├── .yarnrc.yml ├── src ├── assets │ ├── img │ │ ├── logo.png │ │ ├── tfcc.png │ │ ├── webapp.png │ │ ├── favicon.ico │ │ ├── mobileapp.png │ │ └── tfcc-small.png │ ├── data │ │ └── gm2600.bin │ ├── js │ │ └── stockfish.wasm │ └── css │ │ ├── themes │ │ ├── ic.css │ │ ├── gray.css │ │ ├── purple.css │ │ ├── red.css │ │ ├── brown.css │ │ ├── default.css │ │ ├── newspaper.css │ │ ├── yellow.css │ │ └── green.css │ │ ├── images │ │ ├── board │ │ │ ├── 3d │ │ │ │ └── woodi.1024.png │ │ │ ├── red.svg │ │ │ ├── brown.svg │ │ │ ├── ic.svg │ │ │ ├── blue.svg │ │ │ ├── gray.svg │ │ │ ├── green.svg │ │ │ ├── purple.svg │ │ │ ├── yellow.svg │ │ │ └── newspaper.svg │ │ └── pieces │ │ │ ├── staunton │ │ │ └── basic │ │ │ │ ├── Black-King.png │ │ │ │ ├── Black-Pawn.png │ │ │ │ ├── Black-Rook.png │ │ │ │ ├── White-King.png │ │ │ │ ├── White-Pawn.png │ │ │ │ ├── White-Rook.png │ │ │ │ ├── Black-Bishop.png │ │ │ │ ├── Black-Knight.png │ │ │ │ ├── Black-Queen.png │ │ │ │ ├── White-Bishop.png │ │ │ │ ├── White-Knight.png │ │ │ │ ├── White-Queen.png │ │ │ │ ├── Black-Bishop-Flipped.png │ │ │ │ ├── Black-Knight-Flipped.png │ │ │ │ ├── White-Bishop-Flipped.png │ │ │ │ └── White-Knight-Flipped.png │ │ │ ├── alpha │ │ │ ├── bP.svg │ │ │ ├── bR.svg │ │ │ ├── wR.svg │ │ │ ├── bB.svg │ │ │ ├── bN.svg │ │ │ ├── bQ.svg │ │ │ ├── wP.svg │ │ │ ├── wK.svg │ │ │ ├── bK.svg │ │ │ ├── wB.svg │ │ │ ├── wQ.svg │ │ │ └── wN.svg │ │ │ ├── pirouetti │ │ │ ├── bR.svg │ │ │ ├── wR.svg │ │ │ ├── wB.svg │ │ │ ├── bB.svg │ │ │ ├── bP.svg │ │ │ ├── wP.svg │ │ │ ├── wN.svg │ │ │ ├── bN.svg │ │ │ ├── bQ.svg │ │ │ ├── wQ.svg │ │ │ ├── bK.svg │ │ │ └── wK.svg │ │ │ ├── cburnett │ │ │ ├── bP.svg │ │ │ ├── wP.svg │ │ │ ├── wQ.svg │ │ │ ├── wR.svg │ │ │ ├── bB.svg │ │ │ ├── wB.svg │ │ │ ├── wN.svg │ │ │ ├── wK.svg │ │ │ ├── bK.svg │ │ │ ├── bQ.svg │ │ │ ├── bN.svg │ │ │ └── bR.svg │ │ │ ├── leipzig │ │ │ ├── bP.svg │ │ │ └── wP.svg │ │ │ ├── merida │ │ │ ├── wR.svg │ │ │ ├── bP.svg │ │ │ ├── bR.svg │ │ │ ├── wP.svg │ │ │ ├── bQ.svg │ │ │ ├── bN.svg │ │ │ ├── bB.svg │ │ │ ├── wK.svg │ │ │ ├── wN.svg │ │ │ ├── wQ.svg │ │ │ ├── wB.svg │ │ │ └── bK.svg │ │ │ ├── cardinal │ │ │ ├── bR.svg │ │ │ ├── wR.svg │ │ │ ├── bP.svg │ │ │ ├── wP.svg │ │ │ ├── wK.svg │ │ │ ├── bK.svg │ │ │ ├── wB.svg │ │ │ ├── bB.svg │ │ │ ├── wN.svg │ │ │ ├── bN.svg │ │ │ ├── bQ.svg │ │ │ └── wQ.svg │ │ │ ├── spatial │ │ │ ├── bP.svg │ │ │ ├── wP.svg │ │ │ ├── bN.svg │ │ │ ├── wN.svg │ │ │ ├── wQ.svg │ │ │ ├── bQ.svg │ │ │ ├── bK.svg │ │ │ ├── wK.svg │ │ │ ├── wR.svg │ │ │ ├── bR.svg │ │ │ ├── wB.svg │ │ │ └── bB.svg │ │ │ └── maestro │ │ │ ├── wR.svg │ │ │ ├── wP.svg │ │ │ ├── bP.svg │ │ │ └── bR.svg │ │ ├── pieces │ │ ├── alpha.css │ │ ├── default.css │ │ ├── leipzig.css │ │ ├── maestro.css │ │ ├── spatial.css │ │ ├── cardinal.css │ │ ├── cburnett.css │ │ └── pirouetti.css │ │ ├── 3d.css │ │ └── chessground.css ├── icons │ ├── icon-128.webp │ ├── icon-192.webp │ ├── icon-256.webp │ ├── icon-48.webp │ ├── icon-512.webp │ ├── icon-72.webp │ └── icon-96.webp ├── js │ ├── globals.d.ts │ ├── preload.js │ ├── android │ │ └── MainActivity.java │ ├── settings.ts │ └── service-worker.js ├── sitemap.xml └── manifest.json ├── .gitattributes ├── .gitignore ├── .editorconfig ├── capacitor.config.ts ├── scripts ├── inject-sw-manifest.js └── copy-app-files.js ├── .vscode └── launch.json ├── tsconfig.json ├── README.md ├── electron.webpack.js ├── manifest.json ├── .github └── workflows │ └── codeql-analysis.yml ├── package.json └── webpack.config.js /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | nodeLinker: node-modules 2 | 3 | yarnPath: .yarn/releases/yarn-4.9.4.cjs 4 | -------------------------------------------------------------------------------- /src/assets/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freechessclub/freechessclub-app/HEAD/src/assets/img/logo.png -------------------------------------------------------------------------------- /src/assets/img/tfcc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freechessclub/freechessclub-app/HEAD/src/assets/img/tfcc.png -------------------------------------------------------------------------------- /src/icons/icon-128.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freechessclub/freechessclub-app/HEAD/src/icons/icon-128.webp -------------------------------------------------------------------------------- /src/icons/icon-192.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freechessclub/freechessclub-app/HEAD/src/icons/icon-192.webp -------------------------------------------------------------------------------- /src/icons/icon-256.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freechessclub/freechessclub-app/HEAD/src/icons/icon-256.webp -------------------------------------------------------------------------------- /src/icons/icon-48.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freechessclub/freechessclub-app/HEAD/src/icons/icon-48.webp -------------------------------------------------------------------------------- /src/icons/icon-512.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freechessclub/freechessclub-app/HEAD/src/icons/icon-512.webp -------------------------------------------------------------------------------- /src/icons/icon-72.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freechessclub/freechessclub-app/HEAD/src/icons/icon-72.webp -------------------------------------------------------------------------------- /src/icons/icon-96.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freechessclub/freechessclub-app/HEAD/src/icons/icon-96.webp -------------------------------------------------------------------------------- /src/assets/img/webapp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freechessclub/freechessclub-app/HEAD/src/assets/img/webapp.png -------------------------------------------------------------------------------- /src/assets/data/gm2600.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freechessclub/freechessclub-app/HEAD/src/assets/data/gm2600.bin -------------------------------------------------------------------------------- /src/assets/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freechessclub/freechessclub-app/HEAD/src/assets/img/favicon.ico -------------------------------------------------------------------------------- /src/assets/img/mobileapp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freechessclub/freechessclub-app/HEAD/src/assets/img/mobileapp.png -------------------------------------------------------------------------------- /src/assets/js/stockfish.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freechessclub/freechessclub-app/HEAD/src/assets/js/stockfish.wasm -------------------------------------------------------------------------------- /src/assets/img/tfcc-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freechessclub/freechessclub-app/HEAD/src/assets/img/tfcc-small.png -------------------------------------------------------------------------------- /src/assets/css/themes/ic.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --bg-color: #ececec; 3 | } 4 | 5 | cg-board { 6 | background-image: url('../images/board/ic.svg'); 7 | } -------------------------------------------------------------------------------- /src/assets/css/images/board/3d/woodi.1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freechessclub/freechessclub-app/HEAD/src/assets/css/images/board/3d/woodi.1024.png -------------------------------------------------------------------------------- /src/assets/css/themes/gray.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --bg-color: #424242; 3 | } 4 | 5 | cg-board { 6 | background-image: url('../images/board/gray.svg'); 7 | } 8 | -------------------------------------------------------------------------------- /src/assets/css/themes/purple.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --bg-color: #decfef; 3 | } 4 | 5 | cg-board { 6 | background-image: url('../images/board/purple.svg'); 7 | } -------------------------------------------------------------------------------- /src/assets/css/themes/red.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --bg-color: #ffc8c8; 3 | } 4 | 5 | cg-board { 6 | background-image: url('../images/board/red.svg'); 7 | } 8 | -------------------------------------------------------------------------------- /src/assets/css/themes/brown.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --bg-color: #f0d9b5; 3 | } 4 | 5 | cg-board { 6 | background-image: url('../images/board/brown.svg'); 7 | } 8 | -------------------------------------------------------------------------------- /src/assets/css/themes/default.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --bg-color: #dee3e6; 3 | } 4 | 5 | cg-board { 6 | background-image: url('../images/board/blue.svg'); 7 | } 8 | -------------------------------------------------------------------------------- /src/assets/css/themes/newspaper.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --bg-color: #dcdcdc; 3 | } 4 | 5 | cg-board { 6 | background-image: url('../images/board/newspaper.svg'); 7 | } -------------------------------------------------------------------------------- /src/assets/css/themes/yellow.css: -------------------------------------------------------------------------------- 1 | .feature3 { 2 | background-color: #f4ede1; 3 | } 4 | cg-board { 5 | background-image: url('../images/board/yellow.svg'); 6 | } -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | /.yarn/** linguist-vendored 2 | /.yarn/releases/* binary 3 | /.yarn/plugins/**/* binary 4 | /.pnp.* binary linguist-generated 5 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/staunton/basic/Black-King.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freechessclub/freechessclub-app/HEAD/src/assets/css/images/pieces/staunton/basic/Black-King.png -------------------------------------------------------------------------------- /src/assets/css/images/pieces/staunton/basic/Black-Pawn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freechessclub/freechessclub-app/HEAD/src/assets/css/images/pieces/staunton/basic/Black-Pawn.png -------------------------------------------------------------------------------- /src/assets/css/images/pieces/staunton/basic/Black-Rook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freechessclub/freechessclub-app/HEAD/src/assets/css/images/pieces/staunton/basic/Black-Rook.png -------------------------------------------------------------------------------- /src/assets/css/images/pieces/staunton/basic/White-King.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freechessclub/freechessclub-app/HEAD/src/assets/css/images/pieces/staunton/basic/White-King.png -------------------------------------------------------------------------------- /src/assets/css/images/pieces/staunton/basic/White-Pawn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freechessclub/freechessclub-app/HEAD/src/assets/css/images/pieces/staunton/basic/White-Pawn.png -------------------------------------------------------------------------------- /src/assets/css/images/pieces/staunton/basic/White-Rook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freechessclub/freechessclub-app/HEAD/src/assets/css/images/pieces/staunton/basic/White-Rook.png -------------------------------------------------------------------------------- /src/assets/css/images/pieces/staunton/basic/Black-Bishop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freechessclub/freechessclub-app/HEAD/src/assets/css/images/pieces/staunton/basic/Black-Bishop.png -------------------------------------------------------------------------------- /src/assets/css/images/pieces/staunton/basic/Black-Knight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freechessclub/freechessclub-app/HEAD/src/assets/css/images/pieces/staunton/basic/Black-Knight.png -------------------------------------------------------------------------------- /src/assets/css/images/pieces/staunton/basic/Black-Queen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freechessclub/freechessclub-app/HEAD/src/assets/css/images/pieces/staunton/basic/Black-Queen.png -------------------------------------------------------------------------------- /src/assets/css/images/pieces/staunton/basic/White-Bishop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freechessclub/freechessclub-app/HEAD/src/assets/css/images/pieces/staunton/basic/White-Bishop.png -------------------------------------------------------------------------------- /src/assets/css/images/pieces/staunton/basic/White-Knight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freechessclub/freechessclub-app/HEAD/src/assets/css/images/pieces/staunton/basic/White-Knight.png -------------------------------------------------------------------------------- /src/assets/css/images/pieces/staunton/basic/White-Queen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freechessclub/freechessclub-app/HEAD/src/assets/css/images/pieces/staunton/basic/White-Queen.png -------------------------------------------------------------------------------- /src/assets/css/images/pieces/staunton/basic/Black-Bishop-Flipped.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freechessclub/freechessclub-app/HEAD/src/assets/css/images/pieces/staunton/basic/Black-Bishop-Flipped.png -------------------------------------------------------------------------------- /src/assets/css/images/pieces/staunton/basic/Black-Knight-Flipped.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freechessclub/freechessclub-app/HEAD/src/assets/css/images/pieces/staunton/basic/Black-Knight-Flipped.png -------------------------------------------------------------------------------- /src/assets/css/images/pieces/staunton/basic/White-Bishop-Flipped.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freechessclub/freechessclub-app/HEAD/src/assets/css/images/pieces/staunton/basic/White-Bishop-Flipped.png -------------------------------------------------------------------------------- /src/assets/css/images/pieces/staunton/basic/White-Knight-Flipped.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freechessclub/freechessclub-app/HEAD/src/assets/css/images/pieces/staunton/basic/White-Knight-Flipped.png -------------------------------------------------------------------------------- /src/assets/css/themes/green.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --bg-color: #eaffea; 3 | } 4 | 5 | cg-board { 6 | background-image: url('../images/board/green.svg'); 7 | } 8 | 9 | #chat-info { 10 | background-color: rgba(0, 0, 0, 0.025); 11 | } 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | /src/js/app.js 3 | /www 4 | /dev 5 | /app 6 | /dist 7 | platforms 8 | plugins 9 | package-lock.json 10 | yarn-error.log 11 | .idea 12 | /android 13 | /ios 14 | .DS_Store 15 | .pnp.* 16 | .yarn/* 17 | !.yarn/patches 18 | !.yarn/plugins 19 | !.yarn/releases 20 | !.yarn/sdks 21 | !.yarn/versions 22 | -------------------------------------------------------------------------------- /src/js/globals.d.ts: -------------------------------------------------------------------------------- 1 | interface Window { 2 | bootstrap: any; 3 | Popper: any; 4 | d3: any; 5 | Capacitor: any; 6 | electron: any; 7 | } 8 | 9 | declare const bootstrap: any; 10 | declare const Popper: any; 11 | declare const d3: any; 12 | declare const Capacitor: any; 13 | declare const electron: any; 14 | declare module '*.css'; 15 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Unix-style newlines with a newline ending every file 7 | [*] 8 | indent_style = space 9 | tab_width = 2 10 | end_of_line = lf 11 | charset = utf-8 12 | trim_trailing_whitespace = true 13 | insert_final_newline = true 14 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/alpha/bP.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /capacitor.config.ts: -------------------------------------------------------------------------------- 1 | import { CapacitorConfig } from '@capacitor/cli'; 2 | 3 | const config: CapacitorConfig = { 4 | appId: 'club.freechess.FreeChessClub', 5 | appName: 'Free Chess Club', 6 | webDir: 'app', 7 | cordova: { 8 | preferences: { 9 | AppendUserAgent: 'Free Chess Club Mobile' 10 | } 11 | } 12 | }; 13 | 14 | export default config; 15 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/alpha/bR.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/js/preload.js: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Free Chess Club. 2 | // Use of this source code is governed by a GPL-style 3 | // license that can be found in the LICENSE file. 4 | 5 | const { contextBridge, ipcRenderer } = require('electron'); 6 | contextBridge.exposeInMainWorld('electron', { 7 | encrypt: (value) => ipcRenderer.invoke('encrypt', value), 8 | decrypt: (value) => ipcRenderer.invoke('decrypt', value), 9 | }); 10 | -------------------------------------------------------------------------------- /scripts/inject-sw-manifest.js: -------------------------------------------------------------------------------- 1 | const workboxBuild = require("workbox-build"); 2 | const path = require('path'); 3 | 4 | workboxBuild.injectManifest({ 5 | swSrc: "./www/service-worker.js", 6 | swDest: "./www/service-worker.js", 7 | globDirectory: path.resolve(process.cwd(), 'www'), 8 | globPatterns: [ 9 | "play.html", 10 | "assets/**/*.{html,js,wasm,css,png,jpg,svg,json,bin,tsv,ico}", 11 | ], 12 | }); 13 | -------------------------------------------------------------------------------- /scripts/copy-app-files.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs').promises; 2 | 3 | async function copyFiles() { 4 | try { 5 | await fs.mkdir('./app', { recursive: true }); 6 | await fs.copyFile('./www/play.html', './app/index.html'); 7 | await fs.copyFile('./www/service-worker.js', './app/service-worker.js'); 8 | await fs.cp('./www/assets', './app/assets', { recursive: true, force: true }); 9 | await fs.copyFile('./src/js/android/MainActivity.java', './android/app/src/main/java/club/freechess/FreeChessClub/MainActivity.java'); 10 | } catch (err) { 11 | console.error("Error during copy:", err.message); 12 | } 13 | } 14 | 15 | copyFiles(); 16 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible Node.js debug attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "node", 9 | "request": "launch", 10 | "name": "Launch Program", 11 | "program": "${file}" 12 | }, 13 | { 14 | "type": "node", 15 | "request": "attach", 16 | "name": "Attach to Port", 17 | "address": "localhost", 18 | "port": 5858 19 | } 20 | ] 21 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | // "noImplicitAny": true, 4 | // "strictNullChecks": true, 5 | "removeComments": false, // Don't enable this, we need webpack magic comments and comments are later removed by the minimizer 6 | "preserveConstEnums": true, 7 | "sourceMap": true, 8 | "esModuleInterop": true, 9 | "resolveJsonModule": true, 10 | "allowSyntheticDefaultImports": true, 11 | "module": "es2022", 12 | "target": "es2022", 13 | "moduleResolution": "node" 14 | }, 15 | "include": [ 16 | "src/**/*" 17 | ], 18 | "exclude": [ 19 | "node_modules", 20 | "assets", 21 | "app" 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /src/assets/css/images/board/red.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/assets/css/images/board/brown.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/assets/css/images/board/ic.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/pirouetti/bR.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/pirouetti/wR.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/assets/css/images/board/blue.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/assets/css/images/board/gray.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/assets/css/images/board/green.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/assets/css/images/board/purple.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/assets/css/images/board/yellow.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Free Chess Club: A modern web client for FICS. 2 | 3 | Free Chess Club is a modern interface for the [Free Internet Chess Server (FICS)](https://freechess.org/) — one of the oldest internet chess servers with over 800,000 registered accounts. 4 | 5 | You can try out the interface here: [Free Chess Club](http://www.freechess.club/play). 6 | 7 | In addition to the hosted web interface, there are cross-platform [Electron](https://www.electronjs.org/)-based desktop apps (under [Releases](https://github.com/freechessclub/freechessclub-app/releases)) and [Capacitor](https://capacitorjs.com/)-based mobile apps that you can access from the mobile app stores. 8 | 9 | To get started locally, just type: 10 | ```bash 11 | $ yarn start 12 | ``` 13 | and point your browser to http://localhost:8080 14 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/cburnett/bP.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/cburnett/wP.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/alpha/wR.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/alpha/bB.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/leipzig/bP.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/alpha/bN.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/alpha/bQ.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/merida/wR.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/merida/bP.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/pirouetti/wB.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/merida/bR.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/pirouetti/bB.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/pirouetti/bP.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/pirouetti/wP.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/pirouetti/wN.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/alpha/wP.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/pirouetti/bN.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/sitemap.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | http://www.freechess.club/ 11 | 2017-08-12T19:42:12+00:00 12 | monthly 13 | 14 | 15 | http://www.freechess.club/play 16 | 2017-08-12T19:42:12+00:00 17 | monthly 18 | 19 | 20 | http://www.freechess.club/contact 21 | 2017-08-12T19:42:12+00:00 22 | yearly 23 | 24 | 25 | http://www.freechess.club/privacy 26 | 2017-08-12T19:42:12+00:00 27 | yearly 28 | 29 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/pirouetti/bQ.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/pirouetti/wQ.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/js/android/MainActivity.java: -------------------------------------------------------------------------------- 1 | // Custom MainActivity.java for Capacitor Android builds. Allows service worker to work with Android WebView 2 | 3 | package club.freechess.FreeChessClub; 4 | 5 | import android.os.Bundle; 6 | import android.os.Build; 7 | import android.webkit.WebResourceRequest; 8 | import android.webkit.WebResourceResponse; 9 | import android.webkit.ServiceWorkerClient; 10 | import android.webkit.ServiceWorkerController; 11 | import com.getcapacitor.BridgeActivity; 12 | 13 | public class MainActivity extends BridgeActivity { 14 | @Override 15 | public void onCreate(Bundle savedInstanceState) { 16 | super.onCreate(savedInstanceState); 17 | 18 | if(Build.VERSION.SDK_INT >= 24 ){ 19 | ServiceWorkerController swController = ServiceWorkerController.getInstance(); 20 | 21 | swController.setServiceWorkerClient(new ServiceWorkerClient() { 22 | @Override 23 | public WebResourceResponse shouldInterceptRequest(WebResourceRequest request) { 24 | return bridge.getLocalServer().shouldInterceptRequest(request); 25 | } 26 | }); 27 | } 28 | } 29 | } 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/cburnett/wQ.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /electron.webpack.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const path = require('path'); 3 | 4 | const inputDir = 'src'; 5 | const outputDir = 'dist'; 6 | 7 | const electronPreload = { 8 | name: 'electron-preload', 9 | target: 'electron-preload', 10 | mode: 'production', 11 | entry: path.resolve(__dirname, inputDir, 'js/preload.js'), 12 | output: { 13 | filename: 'preload.js', 14 | path: path.resolve(__dirname, outputDir, 'js'), 15 | }, 16 | node: { 17 | __dirname: false, 18 | __filename: false, 19 | }, 20 | } 21 | 22 | const electronApp = { 23 | name: 'electron-app', 24 | target: 'electron-main', 25 | mode: 'production', 26 | entry: path.resolve(__dirname, inputDir, 'js/app.ts'), 27 | output: { 28 | path: path.resolve(__dirname, outputDir, 'js'), 29 | filename: 'app.js', 30 | }, 31 | resolve: { 32 | extensions: ['.ts', '.js'], 33 | }, 34 | module: { 35 | rules: [ 36 | { test: /\.ts$/, exclude: /node_modules/, use: 'ts-loader', }, 37 | ], 38 | }, 39 | node: { 40 | __dirname: false, 41 | __filename: false, 42 | }, 43 | } 44 | 45 | module.exports = [electronPreload, electronApp]; 46 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/alpha/wK.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/css/pieces/alpha.css: -------------------------------------------------------------------------------- 1 | .cg-wrap piece.pawn.white { 2 | background-image: url('../images/pieces/alpha/wP.svg'); 3 | } 4 | .cg-wrap piece.bishop.white { 5 | background-image: url('../images/pieces/alpha/wB.svg'); 6 | } 7 | .cg-wrap piece.knight.white { 8 | background-image: url('../images/pieces/alpha/wN.svg'); 9 | } 10 | .cg-wrap piece.rook.white { 11 | background-image: url('../images/pieces/alpha/wR.svg'); 12 | } 13 | .cg-wrap piece.queen.white { 14 | background-image: url('../images/pieces/alpha/wQ.svg'); 15 | } 16 | .cg-wrap piece.king.white { 17 | background-image: url('../images/pieces/alpha/wK.svg'); 18 | } 19 | .cg-wrap piece.pawn.black { 20 | background-image: url('../images/pieces/alpha/bP.svg'); 21 | } 22 | .cg-wrap piece.bishop.black { 23 | background-image: url('../images/pieces/alpha/bB.svg'); 24 | } 25 | .cg-wrap piece.knight.black { 26 | background-image: url('../images/pieces/alpha/bN.svg'); 27 | } 28 | .cg-wrap piece.rook.black { 29 | background-image: url('../images/pieces/alpha/bR.svg'); 30 | } 31 | .cg-wrap piece.queen.black { 32 | background-image: url('../images/pieces/alpha/bQ.svg'); 33 | } 34 | .cg-wrap piece.king.black { 35 | background-image: url('../images/pieces/alpha/bK.svg'); 36 | } 37 | -------------------------------------------------------------------------------- /src/assets/css/pieces/default.css: -------------------------------------------------------------------------------- 1 | .cg-wrap piece.pawn.white { 2 | background-image: url('../images/pieces/merida/wP.svg'); 3 | } 4 | .cg-wrap piece.bishop.white { 5 | background-image: url('../images/pieces/merida/wB.svg'); 6 | } 7 | .cg-wrap piece.knight.white { 8 | background-image: url('../images/pieces/merida/wN.svg'); 9 | } 10 | .cg-wrap piece.rook.white { 11 | background-image: url('../images/pieces/merida/wR.svg'); 12 | } 13 | .cg-wrap piece.queen.white { 14 | background-image: url('../images/pieces/merida/wQ.svg'); 15 | } 16 | .cg-wrap piece.king.white { 17 | background-image: url('../images/pieces/merida/wK.svg'); 18 | } 19 | .cg-wrap piece.pawn.black { 20 | background-image: url('../images/pieces/merida/bP.svg'); 21 | } 22 | .cg-wrap piece.bishop.black { 23 | background-image: url('../images/pieces/merida/bB.svg'); 24 | } 25 | .cg-wrap piece.knight.black { 26 | background-image: url('../images/pieces/merida/bN.svg'); 27 | } 28 | .cg-wrap piece.rook.black { 29 | background-image: url('../images/pieces/merida/bR.svg'); 30 | } 31 | .cg-wrap piece.queen.black { 32 | background-image: url('../images/pieces/merida/bQ.svg'); 33 | } 34 | .cg-wrap piece.king.black { 35 | background-image: url('../images/pieces/merida/bK.svg'); 36 | } 37 | -------------------------------------------------------------------------------- /src/assets/css/pieces/leipzig.css: -------------------------------------------------------------------------------- 1 | .cg-wrap piece.pawn.white { 2 | background-image: url('../images/pieces/leipzig/wP.svg'); 3 | } 4 | .cg-wrap piece.bishop.white { 5 | background-image: url('../images/pieces/leipzig/wB.svg'); 6 | } 7 | .cg-wrap piece.knight.white { 8 | background-image: url('../images/pieces/leipzig/wN.svg'); 9 | } 10 | .cg-wrap piece.rook.white { 11 | background-image: url('../images/pieces/leipzig/wR.svg'); 12 | } 13 | .cg-wrap piece.queen.white { 14 | background-image: url('../images/pieces/leipzig/wQ.svg'); 15 | } 16 | .cg-wrap piece.king.white { 17 | background-image: url('../images/pieces/leipzig/wK.svg'); 18 | } 19 | .cg-wrap piece.pawn.black { 20 | background-image: url('../images/pieces/leipzig/bP.svg'); 21 | } 22 | .cg-wrap piece.bishop.black { 23 | background-image: url('../images/pieces/leipzig/bB.svg'); 24 | } 25 | .cg-wrap piece.knight.black { 26 | background-image: url('../images/pieces/leipzig/bN.svg'); 27 | } 28 | .cg-wrap piece.rook.black { 29 | background-image: url('../images/pieces/leipzig/bR.svg'); 30 | } 31 | .cg-wrap piece.queen.black { 32 | background-image: url('../images/pieces/leipzig/bQ.svg'); 33 | } 34 | .cg-wrap piece.king.black { 35 | background-image: url('../images/pieces/leipzig/bK.svg'); 36 | } 37 | -------------------------------------------------------------------------------- /src/assets/css/pieces/maestro.css: -------------------------------------------------------------------------------- 1 | .cg-wrap piece.pawn.white { 2 | background-image: url('../images/pieces/maestro/wP.svg'); 3 | } 4 | .cg-wrap piece.bishop.white { 5 | background-image: url('../images/pieces/maestro/wB.svg'); 6 | } 7 | .cg-wrap piece.knight.white { 8 | background-image: url('../images/pieces/maestro/wN.svg'); 9 | } 10 | .cg-wrap piece.rook.white { 11 | background-image: url('../images/pieces/maestro/wR.svg'); 12 | } 13 | .cg-wrap piece.queen.white { 14 | background-image: url('../images/pieces/maestro/wQ.svg'); 15 | } 16 | .cg-wrap piece.king.white { 17 | background-image: url('../images/pieces/maestro/wK.svg'); 18 | } 19 | .cg-wrap piece.pawn.black { 20 | background-image: url('../images/pieces/maestro/bP.svg'); 21 | } 22 | .cg-wrap piece.bishop.black { 23 | background-image: url('../images/pieces/maestro/bB.svg'); 24 | } 25 | .cg-wrap piece.knight.black { 26 | background-image: url('../images/pieces/maestro/bN.svg'); 27 | } 28 | .cg-wrap piece.rook.black { 29 | background-image: url('../images/pieces/maestro/bR.svg'); 30 | } 31 | .cg-wrap piece.queen.black { 32 | background-image: url('../images/pieces/maestro/bQ.svg'); 33 | } 34 | .cg-wrap piece.king.black { 35 | background-image: url('../images/pieces/maestro/bK.svg'); 36 | } 37 | -------------------------------------------------------------------------------- /src/assets/css/pieces/spatial.css: -------------------------------------------------------------------------------- 1 | .cg-wrap piece.pawn.white { 2 | background-image: url('../images/pieces/spatial/wP.svg'); 3 | } 4 | .cg-wrap piece.bishop.white { 5 | background-image: url('../images/pieces/spatial/wB.svg'); 6 | } 7 | .cg-wrap piece.knight.white { 8 | background-image: url('../images/pieces/spatial/wN.svg'); 9 | } 10 | .cg-wrap piece.rook.white { 11 | background-image: url('../images/pieces/spatial/wR.svg'); 12 | } 13 | .cg-wrap piece.queen.white { 14 | background-image: url('../images/pieces/spatial/wQ.svg'); 15 | } 16 | .cg-wrap piece.king.white { 17 | background-image: url('../images/pieces/spatial/wK.svg'); 18 | } 19 | .cg-wrap piece.pawn.black { 20 | background-image: url('../images/pieces/spatial/bP.svg'); 21 | } 22 | .cg-wrap piece.bishop.black { 23 | background-image: url('../images/pieces/spatial/bB.svg'); 24 | } 25 | .cg-wrap piece.knight.black { 26 | background-image: url('../images/pieces/spatial/bN.svg'); 27 | } 28 | .cg-wrap piece.rook.black { 29 | background-image: url('../images/pieces/spatial/bR.svg'); 30 | } 31 | .cg-wrap piece.queen.black { 32 | background-image: url('../images/pieces/spatial/bQ.svg'); 33 | } 34 | .cg-wrap piece.king.black { 35 | background-image: url('../images/pieces/spatial/bK.svg'); 36 | } 37 | -------------------------------------------------------------------------------- /src/assets/css/pieces/cardinal.css: -------------------------------------------------------------------------------- 1 | .cg-wrap piece.pawn.white { 2 | background-image: url('../images/pieces/cardinal/wP.svg'); 3 | } 4 | .cg-wrap piece.bishop.white { 5 | background-image: url('../images/pieces/cardinal/wB.svg'); 6 | } 7 | .cg-wrap piece.knight.white { 8 | background-image: url('../images/pieces/cardinal/wN.svg'); 9 | } 10 | .cg-wrap piece.rook.white { 11 | background-image: url('../images/pieces/cardinal/wR.svg'); 12 | } 13 | .cg-wrap piece.queen.white { 14 | background-image: url('../images/pieces/cardinal/wQ.svg'); 15 | } 16 | .cg-wrap piece.king.white { 17 | background-image: url('../images/pieces/cardinal/wK.svg'); 18 | } 19 | .cg-wrap piece.pawn.black { 20 | background-image: url('../images/pieces/cardinal/bP.svg'); 21 | } 22 | .cg-wrap piece.bishop.black { 23 | background-image: url('../images/pieces/cardinal/bB.svg'); 24 | } 25 | .cg-wrap piece.knight.black { 26 | background-image: url('../images/pieces/cardinal/bN.svg'); 27 | } 28 | .cg-wrap piece.rook.black { 29 | background-image: url('../images/pieces/cardinal/bR.svg'); 30 | } 31 | .cg-wrap piece.queen.black { 32 | background-image: url('../images/pieces/cardinal/bQ.svg'); 33 | } 34 | .cg-wrap piece.king.black { 35 | background-image: url('../images/pieces/cardinal/bK.svg'); 36 | } 37 | -------------------------------------------------------------------------------- /src/assets/css/pieces/cburnett.css: -------------------------------------------------------------------------------- 1 | .cg-wrap piece.pawn.white { 2 | background-image: url('../images/pieces/cburnett/wP.svg'); 3 | } 4 | .cg-wrap piece.bishop.white { 5 | background-image: url('../images/pieces/cburnett/wB.svg'); 6 | } 7 | .cg-wrap piece.knight.white { 8 | background-image: url('../images/pieces/cburnett/wN.svg'); 9 | } 10 | .cg-wrap piece.rook.white { 11 | background-image: url('../images/pieces/cburnett/wR.svg'); 12 | } 13 | .cg-wrap piece.queen.white { 14 | background-image: url('../images/pieces/cburnett/wQ.svg'); 15 | } 16 | .cg-wrap piece.king.white { 17 | background-image: url('../images/pieces/cburnett/wK.svg'); 18 | } 19 | .cg-wrap piece.pawn.black { 20 | background-image: url('../images/pieces/cburnett/bP.svg'); 21 | } 22 | .cg-wrap piece.bishop.black { 23 | background-image: url('../images/pieces/cburnett/bB.svg'); 24 | } 25 | .cg-wrap piece.knight.black { 26 | background-image: url('../images/pieces/cburnett/bN.svg'); 27 | } 28 | .cg-wrap piece.rook.black { 29 | background-image: url('../images/pieces/cburnett/bR.svg'); 30 | } 31 | .cg-wrap piece.queen.black { 32 | background-image: url('../images/pieces/cburnett/bQ.svg'); 33 | } 34 | .cg-wrap piece.king.black { 35 | background-image: url('../images/pieces/cburnett/bK.svg'); 36 | } 37 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/cardinal/bR.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/css/pieces/pirouetti.css: -------------------------------------------------------------------------------- 1 | .cg-wrap piece.pawn.white { 2 | background-image: url('../images/pieces/pirouetti/wP.svg'); 3 | } 4 | .cg-wrap piece.bishop.white { 5 | background-image: url('../images/pieces/pirouetti/wB.svg'); 6 | } 7 | .cg-wrap piece.knight.white { 8 | background-image: url('../images/pieces/pirouetti/wN.svg'); 9 | } 10 | .cg-wrap piece.rook.white { 11 | background-image: url('../images/pieces/pirouetti/wR.svg'); 12 | } 13 | .cg-wrap piece.queen.white { 14 | background-image: url('../images/pieces/pirouetti/wQ.svg'); 15 | } 16 | .cg-wrap piece.king.white { 17 | background-image: url('../images/pieces/pirouetti/wK.svg'); 18 | } 19 | .cg-wrap piece.pawn.black { 20 | background-image: url('../images/pieces/pirouetti/bP.svg'); 21 | } 22 | .cg-wrap piece.bishop.black { 23 | background-image: url('../images/pieces/pirouetti/bB.svg'); 24 | } 25 | .cg-wrap piece.knight.black { 26 | background-image: url('../images/pieces/pirouetti/bN.svg'); 27 | } 28 | .cg-wrap piece.rook.black { 29 | background-image: url('../images/pieces/pirouetti/bR.svg'); 30 | } 31 | .cg-wrap piece.queen.black { 32 | background-image: url('../images/pieces/pirouetti/bQ.svg'); 33 | } 34 | .cg-wrap piece.king.black { 35 | background-image: url('../images/pieces/pirouetti/bK.svg'); 36 | } 37 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/cburnett/wR.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 11 | 14 | 16 | 19 | 21 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/cardinal/wR.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/cburnett/bB.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/cburnett/wB.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | > 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/cardinal/bP.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/cburnett/wN.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 11 | 14 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/cburnett/wK.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/cardinal/wP.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/cburnett/bK.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Free Chess Club", 3 | "short_name": "Free Chess", 4 | "description": "Free Chess Club. Play chess on the Free Internet Chess Server (FICS) using a modern web-based client. No downloads, no hassles—maximum chess guaranteed!", 5 | "start_url": "/play/", 6 | "display": "standalone", 7 | "theme_color": "#000000", 8 | "background_color": "#eeeeee", 9 | "icons": [ 10 | { 11 | "src": "/icons/icon-48.webp", 12 | "type": "image/png", 13 | "sizes": "48x48", 14 | "purpose": "any maskable" 15 | }, 16 | { 17 | "src": "/icons/icon-72.webp", 18 | "type": "image/png", 19 | "sizes": "72x72", 20 | "purpose": "any maskable" 21 | }, 22 | { 23 | "src": "/icons/icon-96.webp", 24 | "type": "image/png", 25 | "sizes": "96x96", 26 | "purpose": "any maskable" 27 | }, 28 | { 29 | "src": "/icons/icon-128.webp", 30 | "type": "image/png", 31 | "sizes": "128x128", 32 | "purpose": "any maskable" 33 | }, 34 | { 35 | "src": "/icons/icon-192.webp", 36 | "type": "image/png", 37 | "sizes": "192x192", 38 | "purpose": "any maskable" 39 | }, 40 | { 41 | "src": "/icons/icon-256.webp", 42 | "type": "image/png", 43 | "sizes": "256x256", 44 | "purpose": "any maskable" 45 | }, 46 | { 47 | "src": "/icons/icon-512.webp", 48 | "type": "image/png", 49 | "sizes": "512x512", 50 | "purpose": "any maskable" 51 | } 52 | ] 53 | } 54 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/alpha/bK.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Free Chess Club", 3 | "short_name": "Free Chess", 4 | "description": "Free Chess Club. Play chess on the Free Internet Chess Server (FICS) using a modern web-based client. No downloads, no hassles—maximum chess guaranteed!", 5 | "start_url": "/play/", 6 | "display": "standalone", 7 | "theme_color": "#000000", 8 | "background_color": "#eeeeee", 9 | "icons": [ 10 | { 11 | "src": "/icons/icon-48.webp", 12 | "type": "image/png", 13 | "sizes": "48x48", 14 | "purpose": "any maskable" 15 | }, 16 | { 17 | "src": "/icons/icon-72.webp", 18 | "type": "image/png", 19 | "sizes": "72x72", 20 | "purpose": "any maskable" 21 | }, 22 | { 23 | "src": "/icons/icon-96.webp", 24 | "type": "image/png", 25 | "sizes": "96x96", 26 | "purpose": "any maskable" 27 | }, 28 | { 29 | "src": "/icons/icon-128.webp", 30 | "type": "image/png", 31 | "sizes": "128x128", 32 | "purpose": "any maskable" 33 | }, 34 | { 35 | "src": "/icons/icon-192.webp", 36 | "type": "image/png", 37 | "sizes": "192x192", 38 | "purpose": "any maskable" 39 | }, 40 | { 41 | "src": "/icons/icon-256.webp", 42 | "type": "image/png", 43 | "sizes": "256x256", 44 | "purpose": "any maskable" 45 | }, 46 | { 47 | "src": "/icons/icon-512.webp", 48 | "type": "image/png", 49 | "sizes": "512x512", 50 | "purpose": "any maskable" 51 | } 52 | ] 53 | } 54 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/pirouetti/bK.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/cburnett/bQ.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/pirouetti/wK.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/js/settings.ts: -------------------------------------------------------------------------------- 1 | export const settings = { 2 | /** Main settings */ 3 | 4 | // toggle game sounds 5 | soundToggle: true, 6 | // toggle for auto-promote to queen 7 | autoPromoteToggle: false, 8 | // toggle for showing Computer opponents in the lobby 9 | lobbyShowComputersToggle: false, 10 | // toggle for showing Rated games in the lobby 11 | lobbyShowUnratedToggle: true, 12 | // toggle for automatically showing new slide-down notifications or notifications in chat channels 13 | notificationsToggle: true, 14 | // toggle for showing highlights/graphics on the board 15 | highlightsToggle: true, 16 | // toggle for showing highlights/graphics on the board 17 | wakelockToggle: true, 18 | // toggle for multi-board mode / single-board mode 19 | multiboardToggle: true, 20 | // toggle for enabling multiple premoves 21 | multiplePremovesToggle: false, 22 | // toggle for enabling smart move 23 | smartmoveToggle: false, 24 | // toggle for remembering user's login and password between sessions 25 | rememberMeToggle: false, 26 | // toggle for showing the eval bar when the engine is running 27 | evalBarToggle: true, 28 | // toggle for showing the best move arrow when the engine is running 29 | bestMoveArrowToggle: true, 30 | 31 | /** Chat settings */ 32 | 33 | // toggle for displaying timestamps on messages 34 | timestampToggle: true, 35 | // toggle for creating separate chat tabs instead of displaying messages in the console 36 | chattabsToggle: true, 37 | 38 | /** History settings */ 39 | 40 | pieceGlyphsToggle: true, 41 | } 42 | 43 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/alpha/wB.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/alpha/wQ.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/cburnett/bN.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 11 | 14 | 18 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/cardinal/wK.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/cardinal/bK.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/cardinal/wB.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/cardinal/bB.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/spatial/bP.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/spatial/wP.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/cburnett/bR.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 11 | 14 | 17 | 20 | 23 | 26 | 29 | 32 | 35 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/merida/wP.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/cardinal/wN.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/cardinal/bN.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/spatial/bN.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/spatial/wN.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/assets/css/images/board/newspaper.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/cardinal/bQ.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/cardinal/wQ.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/alpha/wN.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/js/service-worker.js: -------------------------------------------------------------------------------- 1 | import { precacheAndRoute, cleanupOutdatedCaches } from 'workbox-precaching'; 2 | import { registerRoute } from 'workbox-routing'; 3 | import { StaleWhileRevalidate } from 'workbox-strategies'; 4 | 5 | // pre-cache external resources 6 | const externals = [ 7 | {"url":"https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css", "revision":"1"}, 8 | {"url":"https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/fonts/fontawesome-webfont.woff2?v=4.7.0", "revision":"1"}, 9 | {"url":"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.3.0/css/all.min.css", "revision":"1"}, 10 | {"url":"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.3.0/webfonts/fa-solid-900.woff2", "revision":"1"}, 11 | {"url":"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.3.0/webfonts/fa-regular-400.woff2", "revision":"1"}, 12 | {"url":"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.3.0/webfonts/fa-brands-400.woff2", "revision":"1"}, 13 | {"url":"https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css", "revision":"1"}, 14 | {"url":"https://fonts.googleapis.com/css2?family=Noto+Sans+Math&family=Noto+Sans+Symbols+2&display=swap", "revision":"1"}, 15 | {"url":"https://code.jquery.com/jquery-3.7.0.slim.min.js", "revision":"1"}, 16 | {"url":"https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.6/dist/umd/popper.min.js", "revision":"1"}, 17 | {"url":"https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.min.js", "revision":"1"}, 18 | {"url":"https://cdn.jsdelivr.net/npm/d3@7.8.0/dist/d3.min.js", "revision":"1"}, 19 | {"url":"https://fonts.gstatic.com/s/notosanssymbols2/v24/I_uyMoGduATTei9eI8daxVHDyfisHr71-vrgfE71.woff2","revision":"1"}, 20 | {"url":"https://fonts.gstatic.com/s/notosansmath/v15/7Aump_cpkSecTWaHRlH2hyV5UEl981w.woff2","revision":"1"}, 21 | ]; 22 | 23 | const urlParams = new URLSearchParams(self.location.search); 24 | if(urlParams.get('env') === 'app') // Capacitor or Electron app, don't cache static assets 25 | precacheAndRoute(externals); 26 | else 27 | precacheAndRoute([...self.__WB_MANIFEST, ...externals]); // __WB_MANIFEST is injected by inject-manifest.js 28 | 29 | registerRoute( 30 | ({ url }) => url.origin === 'https://cdn.jsdelivr.net', 31 | new StaleWhileRevalidate({ cacheName: 'stalewhile-cache' }) 32 | ); 33 | 34 | cleanupOutdatedCaches(); 35 | 36 | self.addEventListener('install', (event) => { 37 | self.skipWaiting(); 38 | }); 39 | 40 | self.addEventListener('activate', (event) => { 41 | event.waitUntil(clients.claim()); 42 | }); 43 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/spatial/wQ.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/spatial/bQ.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/spatial/bK.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/spatial/wK.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/merida/bQ.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ master ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ master ] 20 | schedule: 21 | - cron: '44 23 * * 5' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'javascript' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] 37 | # Learn more: 38 | # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed 39 | 40 | steps: 41 | - name: Checkout repository 42 | uses: actions/checkout@v2 43 | 44 | # Initializes the CodeQL tools for scanning. 45 | - name: Initialize CodeQL 46 | uses: github/codeql-action/init@v1 47 | with: 48 | languages: ${{ matrix.language }} 49 | # If you wish to specify custom queries, you can do so here or in a config file. 50 | # By default, queries listed here will override any specified in a config file. 51 | # Prefix the list here with "+" to use these queries and those in the config file. 52 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 53 | 54 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 55 | # If this step fails, then you should remove it and run the build manually (see below) 56 | - name: Autobuild 57 | uses: github/codeql-action/autobuild@v1 58 | 59 | # ℹ️ Command-line programs to run using the OS shell. 60 | # 📚 https://git.io/JvXDl 61 | 62 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 63 | # and modify them (or add more) to build your code if your project 64 | # uses a compiled language 65 | 66 | #- run: | 67 | # make bootstrap 68 | # make release 69 | 70 | - name: Perform CodeQL Analysis 71 | uses: github/codeql-action/analyze@v1 72 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/spatial/wR.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/spatial/bR.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/assets/css/3d.css: -------------------------------------------------------------------------------- 1 | .in3d .cg-wrap { 2 | width: 512px; 3 | height: 464.5px; 4 | } 5 | .in3d .cg-board::before { 6 | position: absolute; 7 | top: -0.730688%; 8 | left: 0; 9 | width: 100%; 10 | height: 103.2%; 11 | content: ''; 12 | background-size: cover; 13 | background-image: url('images/board/3d/woodi.1024.png'); 14 | } 15 | .in3d .ghost, 16 | .in3d .over { 17 | display: none; 18 | } 19 | .in3d square[data-coord-x]::after { 20 | bottom: calc(-10px - 22%); 21 | } 22 | .in3d piece { 23 | /* original size: 24 | width: 140.625%; 25 | height: 179.6875%; */ 26 | /* size on 3D board, with height/width = 90.78571% */ 27 | width: 16.741%; 28 | height: 23.563%; 29 | left: -1.85%; 30 | top: -9.1%; 31 | } 32 | .cg-board piece.dragging { 33 | cursor: move; 34 | z-index: 70!important; 35 | } 36 | .in3d .cg-wrap piece.pawn.white { 37 | background-image: url('images/pieces/staunton/basic/White-Pawn.png'); 38 | } 39 | .in3d .cg-wrap piece.bishop.white { 40 | background-image: url('images/pieces/staunton/basic/White-Bishop.png'); 41 | } 42 | .in3d .cg-wrap.orientation-black div.bishop.white { 43 | background-image: url('images/pieces/staunton/basic/White-Bishop-Flipped.png'); 44 | } 45 | .in3d .cg-wrap piece.knight.white { 46 | background-image: url('images/pieces/staunton/basic/White-Knight.png'); 47 | } 48 | .in3d .cg-wrap.orientation-black div.knight.white { 49 | background-image: url('images/pieces/staunton/basic/White-Knight-Flipped.png'); 50 | } 51 | .in3d .cg-wrap piece.rook.white { 52 | background-image: url('images/pieces/staunton/basic/White-Rook.png'); 53 | } 54 | .in3d .cg-wrap piece.queen.white { 55 | background-image: url('images/pieces/staunton/basic/White-Queen.png'); 56 | } 57 | .in3d .cg-wrap piece.king.white { 58 | background-image: url('images/pieces/staunton/basic/White-King.png'); 59 | } 60 | .in3d .cg-wrap piece.pawn.black { 61 | background-image: url('images/pieces/staunton/basic/Black-Pawn.png'); 62 | } 63 | .in3d .cg-wrap piece.bishop.black { 64 | background-image: url('images/pieces/staunton/basic/Black-Bishop.png'); 65 | } 66 | .in3d .cg-wrap.orientation-white div.bishop.black { 67 | background-image: url('images/pieces/staunton/basic/Black-Bishop-Flipped.png'); 68 | } 69 | .in3d .cg-wrap piece.knight.black { 70 | background-image: url('images/pieces/staunton/basic/Black-Knight.png'); 71 | } 72 | .in3d .cg-wrap.orientation-white div.knight.black { 73 | background-image: url('images/pieces/staunton/basic/Black-Knight-Flipped.png'); 74 | } 75 | .in3d .cg-wrap piece.rook.black { 76 | background-image: url('images/pieces/staunton/basic/Black-Rook.png'); 77 | } 78 | .in3d .cg-wrap piece.queen.black { 79 | background-image: url('images/pieces/staunton/basic/Black-Queen.png'); 80 | } 81 | .in3d .cg-wrap piece.king.black { 82 | background-image: url('images/pieces/staunton/basic/Black-King.png'); 83 | } 84 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/merida/bN.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/leipzig/wP.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/merida/bB.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/maestro/wR.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/merida/wK.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/maestro/wP.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/spatial/wB.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/spatial/bB.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/merida/wN.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "freechessclub", 3 | "version": "4.1.2", 4 | "license": "MIT", 5 | "description": "Free Chess Club: A modern web interface for FICS.", 6 | "main": "./dist/js/app.js", 7 | "scripts": { 8 | "app": "tsc src/js/app.ts && electron src/js/app.js", 9 | "lint": "eslint -c .eslintrc.js --ext .ts src", 10 | "bundle": "webpack --mode production", 11 | "dev": "webpack --mode development", 12 | "pack": "webpack --config electron.webpack.js && electron-builder --dir", 13 | "dist": "webpack --config electron.webpack.js && electron-builder", 14 | "build": "webpack --config electron.webpack.js && electron-builder -mwl --x64 --arm64 -p always", 15 | "release": "yarn build", 16 | "postinstall": "electron-builder install-app-deps", 17 | "android": "node scripts/copy-app-files.js && npx cap run android", 18 | "ios": "node scripts/copy-app-files.js && npx cap run ios", 19 | "start": "webpack-dev-server --config webpack.config.js" 20 | }, 21 | "repository": { 22 | "type": "git", 23 | "url": "https://github.com/freechessclub/freechessclub-app" 24 | }, 25 | "author": { 26 | "name": "Free Chess Club Author(s)", 27 | "email": "support@freechess.club" 28 | }, 29 | "build": { 30 | "appId": "club.freechess.FreeChessClub", 31 | "productName": "Free Chess Club", 32 | "copyright": "Copyright © 2024 Free Chess Club Author(s)", 33 | "publish": [ 34 | "github" 35 | ], 36 | "files": [ 37 | "dist/js/**", 38 | "www/**", 39 | "!node_modules/**" 40 | ], 41 | "mac": { 42 | "category": "public.app-category.board-games", 43 | "identity": "Apple Development: tessellate.ai@gmail.com (W893HC69YA)" 44 | }, 45 | "linux": { 46 | "target": [ 47 | "tar.gz", 48 | "zip" 49 | ], 50 | "category": "Game" 51 | } 52 | }, 53 | "dependencies": { 54 | "@capacitor-community/safe-area": "^7.0.0-alpha.1", 55 | "@capacitor/android": "^7.2.0", 56 | "@capacitor/core": "^7.2.0", 57 | "@capacitor/ios": "^7.2.0", 58 | "@capacitor/preferences": "^7.0.1", 59 | "@mliebelt/pgn-parser": "^1.4.15", 60 | "@popperjs/core": "^2.11.6", 61 | "@uriopass/nosleep.js": "^0.12.2", 62 | "autolink-js": "https://github.com/freechessclub/autolink-js", 63 | "bootstrap": "5.2.3", 64 | "builder-util-runtime": "^9.2.10", 65 | "capacitor-secure-storage-plugin": "^0.11.0", 66 | "chess.js": "^0.12.1", 67 | "chessground": "^9.0.4", 68 | "cm-polyglot": "^1.1.0", 69 | "d3": "^7.8.0", 70 | "electron-updater": "6.6.4", 71 | "emoji-mart": "^5.6.0", 72 | "jquery": "^3.7.0", 73 | "js-cookie": "^3.0.1", 74 | "stockfish.js": "^10.0.2", 75 | "virtual-scroller": "^1.13.1" 76 | }, 77 | "devDependencies": { 78 | "@capacitor/assets": "^3.0.5", 79 | "@capacitor/cli": "^7.2.0", 80 | "@mliebelt/pgn-types": "^1.0.4", 81 | "@types/bootstrap": "5.2.3", 82 | "@types/jquery": "^3.5.16", 83 | "@types/websocket": "^1.0.1", 84 | "@typescript-eslint/eslint-plugin": "^8.17.0", 85 | "@typescript-eslint/parser": "^8.17.0", 86 | "cheerio": "^1.0.0", 87 | "copy-webpack-plugin": "^13.0.0", 88 | "css-loader": "^6.6.0", 89 | "electron": "^36.3.2", 90 | "electron-builder": "26.0.15", 91 | "eslint": "^8.57.1", 92 | "eslint-plugin-jsdoc": "^50.6.0", 93 | "eslint-plugin-prefer-arrow": "^1.2.3", 94 | "exports-loader": "^3.1.0", 95 | "html-webpack-plugin": "^5.6.3", 96 | "mini-css-extract-plugin": "^2.9.2", 97 | "path-browserify": "^1.0.1", 98 | "style-loader": "^3.3.1", 99 | "sync-request": "^6.1.0", 100 | "ts-loader": "^9.3.1", 101 | "typescript": "^5.8.3", 102 | "webpack": "^5.99.9", 103 | "webpack-cli": "^5.0.2", 104 | "webpack-dev-server": "^5.0.2", 105 | "workbox-build": "^7.3.0", 106 | "workbox-core": "^7.3.0", 107 | "workbox-precaching": "^7.3.0", 108 | "workbox-routing": "^7.3.0", 109 | "workbox-strategies": "^7.3.0" 110 | }, 111 | "packageManager": "yarn@4.9.4" 112 | } 113 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/merida/wQ.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/merida/wB.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/merida/bK.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/maestro/bP.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/css/chessground.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Chessground base css properties. 3 | * 4 | * You need to include the css files in themes folder in order to have the 5 | * board and pieces displayed! 6 | */ 7 | 8 | .cg-wrap { 9 | box-sizing: content-box; 10 | position: relative; 11 | display: block; 12 | } 13 | .cg-wrap:after { 14 | content: ""; 15 | display: block; 16 | padding-bottom: 100%; 17 | } 18 | 19 | cg-container { 20 | position: absolute; 21 | width: 100%; 22 | height: 100%; 23 | display: block; 24 | top: 0; 25 | } 26 | 27 | cg-board { 28 | position: absolute; 29 | top: 0; 30 | left: 0; 31 | width: 100%; 32 | height: 100%; 33 | -webkit-user-select: none; 34 | -moz-user-select: none; 35 | -ms-user-select: none; 36 | user-select: none; 37 | line-height: 0; 38 | background-size: cover; 39 | cursor: pointer; 40 | } 41 | cg-board square { 42 | position: absolute; 43 | top: 0; 44 | left: 0; 45 | width: 12.5%; 46 | height: 12.5%; 47 | pointer-events: none; 48 | } 49 | cg-board square.move-dest { 50 | background: radial-gradient(rgba(20, 85, 30, 0.5) 22%, #208530 0, rgba(0, 0, 0, 0.3) 0, rgba(0, 0, 0, 0) 0); 51 | pointer-events: auto; 52 | } 53 | cg-board square.premove-dest { 54 | background: radial-gradient(rgba(20, 30, 85, 0.5) 22%, #203085 0, rgba(0, 0, 0, 0.3) 0, rgba(0, 0, 0, 0) 0); 55 | } 56 | cg-board square.oc.move-dest { 57 | background: radial-gradient(transparent 0%, transparent 80%, rgba(20, 85, 0, 0.3) 80%); 58 | } 59 | cg-board square.oc.premove-dest { 60 | background: radial-gradient(transparent 0%, transparent 80%, rgba(20, 30, 85, 0.2) 80%); 61 | } 62 | cg-board square.move-dest:hover { 63 | background: rgba(20, 85, 30, 0.3); 64 | } 65 | cg-board square.premove-dest:hover { 66 | background: rgba(20, 30, 85, 0.2); 67 | } 68 | cg-board square.last-move { 69 | will-change: transform; 70 | background-color: rgba(155, 199, 0, 0.41); 71 | } 72 | cg-board square.selected { 73 | background-color: rgba(20, 85, 30, 0.5); 74 | } 75 | cg-board square.check { 76 | background: radial-gradient(ellipse at center, rgba(255, 0, 0, 1) 0%, rgba(231, 0, 0, 1) 25%, rgba(169, 0, 0, 0) 89%, rgba(158, 0, 0, 0) 100%); 77 | } 78 | cg-board square.current-premove { 79 | background-color: rgba(20, 30, 85, 0.5); 80 | } 81 | .cg-wrap piece { 82 | position: absolute; 83 | top: 0; 84 | left: 0; 85 | width: 12.5%; 86 | height: 12.5%; 87 | background-size: cover; 88 | z-index: 2; 89 | will-change: transform; 90 | pointer-events: none; 91 | } 92 | cg-board piece.dragging { 93 | cursor: move; 94 | z-index: 10; 95 | } 96 | cg-board piece.anim { 97 | z-index: 8; 98 | } 99 | cg-board piece.fading { 100 | z-index: 1; 101 | opacity: 0.5; 102 | } 103 | .cg-wrap square.move-dest:hover { 104 | background-color: rgba(20, 85, 30, 0.3); 105 | } 106 | .cg-wrap piece.ghost { 107 | opacity: 0.3; 108 | } 109 | .cg-wrap .cg-shapes, .cg-wrap .cg-custom-svgs { 110 | overflow: hidden; 111 | position: absolute; 112 | top: 0px; 113 | left: 0px; 114 | width: 100%; 115 | height: 100%; 116 | pointer-events: none; 117 | } 118 | .cg-wrap .cg-shapes { 119 | opacity: 0.6; 120 | z-index: 2; 121 | } 122 | .cg-wrap .cg-custom-svgs { 123 | /* over piece.anim = 8, but under piece.dragging = 10 */ 124 | z-index: 9; 125 | } 126 | .cg-wrap coords { 127 | position: absolute; 128 | display: flex; 129 | pointer-events: none; 130 | opacity: 0.8; 131 | font-size: 1.2vh; 132 | user-select: none; 133 | } 134 | .cg-wrap coords.ranks { 135 | right: 0; 136 | top: -1.4em; 137 | line-height: 0; 138 | flex-flow: column-reverse; 139 | height: 100%; 140 | width: 0.8em; 141 | } 142 | .cg-wrap coords.ranks.black { 143 | flex-flow: column; 144 | } 145 | .cg-wrap coords.files { 146 | bottom: 0px; 147 | left: 2px; 148 | text-align: left; 149 | flex-flow: row; 150 | width: 100%; 151 | height: 1.4em; 152 | } 153 | .cg-wrap coords.files.black { 154 | flex-flow: row-reverse; 155 | } 156 | .cg-wrap coords.files.coord { 157 | padding-left: 4px; 158 | } 159 | .cg-wrap coords coord { 160 | flex: 1 1 auto; 161 | } 162 | .cg-wrap coords.ranks coord { 163 | transform: translateY(39%); 164 | } 165 | .orientation-white .files coord:nth-child(2n + 1), 166 | .orientation-white .ranks coord:nth-child(2n), 167 | .orientation-black .files coord:nth-child(2n), 168 | .orientation-black .ranks coord:nth-child(2n + 1) { 169 | color: #fff; 170 | } 171 | .orientation-white .files coord:nth-child(2n), 172 | .orientation-white .ranks coord:nth-child(2n + 1), 173 | .orientation-black .files coord:nth-child(2n + 1), 174 | .orientation-black .ranks coord:nth-child(2n) { 175 | color: #000; 176 | } 177 | -------------------------------------------------------------------------------- /src/assets/css/images/pieces/maestro/bR.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const { exec } = require('child_process'); 3 | const path = require('path'); 4 | const HtmlWebpackPlugin = require("html-webpack-plugin"); 5 | const CopyWebpackPlugin = require("copy-webpack-plugin"); 6 | const MiniCssExtractPlugin = require('mini-css-extract-plugin'); 7 | 8 | module.exports = (env, argv) => { 9 | const isProd = argv.mode === 'production'; 10 | const inputDir = 'src'; 11 | const outputDir = isProd ? 'www' : 'dev'; 12 | 13 | const bundle = { 14 | name: 'bundle', 15 | mode: isProd ? 'production' : 'development', 16 | entry: { application: path.resolve(__dirname, inputDir, 'js/index.ts') }, 17 | output: { 18 | path: path.resolve(__dirname, outputDir), 19 | filename: "assets/js/" + (isProd ? "bundle.[contenthash].js" : "bundle.js"), 20 | clean: true, 21 | }, 22 | externals: { 23 | $: 'jquery', 24 | d3: 'd3', 25 | '@popperjs/core': 'Popper', 26 | bootstrap: 'Bootstrap' 27 | }, 28 | resolve: { 29 | // Add '.ts' and '.tsx' as a resolvable extension. 30 | fallback: { 'crypto': false, 'fs': false, 'path': require.resolve('path-browserify') }, 31 | extensions: [".webpack.js", ".web.js", ".ts", ".tsx", ".js"], 32 | alias: { assets: path.resolve(__dirname, inputDir, 'assets') }, 33 | }, 34 | module: { 35 | rules: [ 36 | // all files with a '.ts' or '.tsx' extension will be handled by 'ts-loader' 37 | { test: /\.tsx?$/, use: "ts-loader" }, 38 | { test: /\.(woff|woff2|ttf|eot|svg)$/, type: 'asset', generator: { filename: 'assets/img/[name].[hash][ext][query]' } }, 39 | { test: /\.m?js/, resolve: { fullySpecified: false } }, 40 | { test: /\.wasm$/, type: "asset/resource", generator: { filename: "assets/js/[name][ext]" } }, 41 | { test: /\.css$/, 42 | use: isProd 43 | ? [MiniCssExtractPlugin.loader, { loader: 'css-loader', options: { url: false } }] 44 | : ['style-loader', 'css-loader'], 45 | } 46 | ] 47 | }, 48 | plugins: [ 49 | new webpack.optimize.AggressiveMergingPlugin(), 50 | new HtmlWebpackPlugin({ 51 | template: path.resolve(__dirname, inputDir, 'play.html'), 52 | filename: "play.html", 53 | inject: "body", 54 | minify: isProd, 55 | }), 56 | new CopyWebpackPlugin({ 57 | patterns: [ 58 | { 59 | // copy all static assets 60 | from: path.resolve(__dirname, inputDir), 61 | to: path.resolve(__dirname, outputDir), 62 | globOptions: { 63 | ignore: [ 64 | `${inputDir}/play.html`, 65 | `${inputDir}/js/**`, 66 | `${inputDir}/assets/css/application.css`, 67 | `${inputDir}/assets/css/themes/**` 68 | ], 69 | }, 70 | } 71 | ], 72 | }), 73 | ...(isProd 74 | ? [ 75 | new MiniCssExtractPlugin({ 76 | filename: 'assets/css/[name].[contenthash].css', 77 | chunkFilename: 'assets/css/[name].[contenthash].css', 78 | }), 79 | ] 80 | : []), 81 | ], 82 | optimization: { 83 | minimize: isProd, 84 | }, 85 | experiments: { 86 | asyncWebAssembly: true, 87 | }, 88 | devServer: { 89 | client: { 90 | progress: true, 91 | }, 92 | devMiddleware: { 93 | writeToDisk: false, 94 | }, 95 | static: { 96 | directory: outputDir, 97 | watch: false, 98 | }, 99 | hot: true, 100 | watchFiles: [`${inputDir}/*.html`], 101 | historyApiFallback: { 102 | rewrites: [ 103 | { from: /^\/play/, to: '/play.html' }, 104 | ], 105 | }, 106 | compress: true, 107 | port: 8080, 108 | } 109 | }; 110 | 111 | const serviceWorker = { 112 | name: 'service-worker', 113 | dependencies: ['bundle'], 114 | mode: isProd ? 'production' : 'development', 115 | stats: 'errors-warnings', 116 | entry: path.resolve(__dirname, inputDir, 'js/service-worker.js'), 117 | target: 'webworker', 118 | output: { 119 | filename: 'service-worker.js', 120 | path: path.resolve(__dirname, outputDir), 121 | }, 122 | plugins: [ 123 | { 124 | apply: (compiler) => { 125 | compiler.hooks.done.tap('RunAfterBuildPlugin', () => { 126 | exec(`node "${path.resolve(__dirname, 'scripts/inject-sw-manifest.js')}"`, (err, stdout, stderr) => { 127 | if (stdout) console.log(stdout); 128 | if (stderr) console.error(stderr); 129 | }); 130 | }); 131 | } 132 | } 133 | ] 134 | }; 135 | 136 | return isProd ? [bundle, serviceWorker] : [bundle]; 137 | } 138 | --------------------------------------------------------------------------------