Skip to content

HKTITAN/FediChess

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

20 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

FediChess

GitHub version

Decentralized peer-to-peer chess in the browser — the fediverse of chess. Play with anyone over the web without a central game server, or nearby over BLE with no internet. Same open wire protocol over WebRTC (online) and BLE (local); build your own client and interoperate. Matchmaking uses public WebTorrent trackers for online play; moves and chat go directly between peers.

Version: 0.3.0 — see CHANGELOG for release history.

Deploy

Deploy with Vercel Deploy to Netlify Deploy to Render
Deploy on Railway Deploy to Koyeb Deploy to Heroku
Deploy to DO Cloudflare Pages Azure Static Web Apps
Firebase Hosting AWS Amplify Fly.io
Google Cloud Run Deno Deploy Platform.sh

Open in / Build with

Open in Cursor GitHub Codespaces Open in GitPod
Open in CodeSandbox Open in StackBlitz Open in Replit
Open in Glitch GitHub Copilot v0
Codeium Windsurf Bolt.new
VS Code Codeium IDE Cursor Rules

Table of contents


Why FediChess?

  • No central server. Games run between browsers. No company owns your games or ELO; everything can stay on your device.
  • Open protocol. The wire protocol is documented so anyone can build a compatible client (web, mobile, CLI) and play with this app and others.
  • Self-hostable and federated. Use default public trackers or run your own. Point your instance at community trackers to grow the pool. Optional ranking API allows voluntary, user-consent leaderboards.
  • Censorship-resistant. As long as peers can reach trackers and each other (or a TURN server), games work. No single point of control.

Features

Gameplay

  • P2P multiplayer — No game server. Peers discover each other via WebTorrent trackers and connect over WebRTC. Moves and chat go directly between players.
  • Lobby + ELO matchmaking — Default ELO range ±200; optional “Show all peers” to challenge anyone in the lobby. Set a username (e.g. HKTITAN) visible to others.
  • Full game flow — 5 min + 30s increment clocks, in-game chat, resign, draw offer/accept. Spectators can join and watch; only the two players send moves.
  • PGN export & analysis — Copy FEN/PGN from the result dialog. One-click link to analyze on Lichess (or paste into Chess.com).
  • Account backup — Export progress (ELO, game history, name) to a file and restore on another device. Backups are signed (password-protected HMAC) so they cannot be edited for fair play. Use Backup account from the lobby or home.

Technical

  • Open wire protocolProtocol spec: rooms, action types (≤12 bytes), JSON payloads. Any client that implements it can interoperate.
  • Self-hosted trackers — Override NEXT_PUBLIC_P2P_TRACKERS to use your own or community WebTorrent trackers. Same protocol across instances.
  • Optional STUN/TURN — Configure NAT traversal so connections work behind strict firewalls or symmetric NAT (see Configuration).
  • Static export — Next.js builds to static files (out/). No Node server required in production; host on Vercel, Netlify, or any static host.

UX

  • Classic and Neon themes — Toggle board/UI themes. Mobile-responsive layout, 44px touch targets, safe-area padding.
  • Local AI — Play vs a simple built-in engine (random legal moves) from the home page. For strong engine play, you can integrate e.g. Stockfish.wasm in a Web Worker.

How it works

  1. Discovery — Your browser connects to one or more WebTorrent-compatible WSS trackers and joins a lobby room (e.g. p2p-chess-global) with a shared app ID (p2p-chess-v1).
  2. Lobby — The app sends periodic heartbeats (ELO, username) and receives others’ heartbeats. You see a list of peers; you can challenge one (and choose your color). They accept or decline.
  3. Game room — On accept, both clients join a game room p2p-chess-{gameId} over the same P2P layer. Each move and game event is broadcast as a shared event log; board state is derived by replaying the log so spectators and late joiners see the same position.
  4. WebRTC — After discovery, peers connect directly (or via TURN if configured). All game data (moves, chat, sync) flows over WebRTC data channels — no server in the middle.

Dual transport: The same protocol also runs over BLE (Web Bluetooth) for nearby play — see Transports and Protocol (BLE). Architecture has diagrams, data flow, and stability (disconnect, refresh).


Tech stack

Layer Technology Notes
UI Next.js 15, React 19, TailwindCSS App Router, static export; responsive, touch-friendly.
P2P Trystero (torrent), WebTorrent trackers, WebRTC; BLE (Web Bluetooth) Online: discovery/signaling via trackers, data over WebRTC. Nearby: BLE GATT (see lib/ble-transport.ts). Shared Room interface in lib/transport-types.ts.
Game chess.js, react-chessboard Rules, FEN, move validation; board component.
State Zustand User, lobby, game, UI state; peers tagged by transport (webrtc/ble).
Persistence IndexedDB (idb-keyval) ELO, peak ELO, game history. Optional localStorage for name and preferences.
  • Package name: fedichess (npm/repo). Product name: FediChess. Version: 0.3.0.

Prerequisites

  • Node.js 18+ (or 20+ recommended)
  • npm or pnpm
  • Modern browser with WebRTC support (Chrome, Firefox, Safari, Edge)

Installation & quick start

Clone and install

git clone https://github.com/HKTITAN/fedichess.git
cd fedichess
npm install

Run locally

npm run dev

Open http://localhost:3000. Use Play Random to join the lobby, or Copy Link to share the lobby URL with a friend.

Scripts

Command Description
npm run dev Start Next.js dev server (default port 3000).
npm run build Production build; outputs static export to out/.
npm run start Serve the built app (after npm run build).
npm run lint Run ESLint.

Configuration

All configuration is via environment variables. For Next.js, use NEXT_PUBLIC_* for values needed in the browser.

Variable Description Default
NEXT_PUBLIC_P2P_TRACKERS Comma-separated WSS tracker URLs. Override to use your own or extra trackers. wss://tracker.webtorrent.dev, wss://tracker.openwebtorrent.com, wss://tracker.btorrent.xyz
NEXT_PUBLIC_STUN_URL STUN server for NAT traversal (e.g. stun:stun.l.google.com:19302). (browser default)
NEXT_PUBLIC_TURN_URL TURN server URL (optional).
NEXT_PUBLIC_TURN_USERNAME TURN username (if required).
NEXT_PUBLIC_TURN_CREDENTIAL TURN credential (if required).

Create a .env.local in the project root (do not commit secrets). Example:

# Optional: use your own trackers
NEXT_PUBLIC_P2P_TRACKERS=wss://your-tracker.example.com,wss://another.example.com

# Optional: STUN/TURN for strict NATs
NEXT_PUBLIC_STUN_URL=stun:stun.l.google.com:19302
# NEXT_PUBLIC_TURN_URL=turn:turn.example.com:3478
# NEXT_PUBLIC_TURN_USERNAME=user
# NEXT_PUBLIC_TURN_CREDENTIAL=pass

Playing and testing

Two tabs (same machine)

  1. Tab 1: Open the app, click Play Random (or go to /lobby).
  2. Tab 2: Open the app, click Play Random.
  3. Both join the same lobby. Optionally set usernames. From Tab 1, click Challenge next to Tab 2’s peer.
  4. In Tab 2, click Accept. Both tabs navigate to the game; play as usual.

Share link (two devices or friends)

  1. In the lobby, click Copy Link and send the URL (e.g. via chat or email).
  2. The other person opens the link in their browser and joins the same lobby.
  3. Challenge and accept as above.

Nearby (BLE)

  1. Lobby: Click Connect via BLE (Chrome or Edge; HTTPS or localhost). Select a FediChess BLE device when the picker appears.
  2. The other device appears as a Nearby peer. Challenge and accept as usual; the game runs over the same BLE connection.
  3. Note: The browser can only act as a central (client). The other side must advertise the FediChess GATT service (e.g. a native app or a separate BLE peripheral). Two browser tabs cannot connect to each other via BLE alone.

Local AI

Click Local AI on the home page to play vs a simple engine (random legal moves). No P2P involved.


Deployment

FediChess builds to a static export (out/). No Node server is required in production.

Build configuration (Vercel, Netlify, Render, etc.)

The repo is set up for one-click and Git-based deploys:

File Purpose
package.json engines.node: >=18.17.0; scripts: build = next build, dev = next dev.
.nvmrc Node 20 (used by many platforms and locally with nvm use).
vercel.json Framework: nextjs (Vercel runs next build and serves the static export).
netlify.toml Build: npm run build, publish: out, NODE_VERSION: 20.
render.yaml Blueprint: static site, buildCommand: npm ci && npm run build, staticPublishPath: out.

Other hosts: use build command npm run build (or npm ci && npm run build) and publish directory out. Optional env: NEXT_PUBLIC_P2P_TRACKERS, NEXT_PUBLIC_STUN_URL, etc. (see Configuration).

Vercel (recommended)

  1. Push the repo to GitHub.
  2. In Vercel, import the repository.
  3. Deploy. The default Next.js preset works; build command next build produces the static export.
  4. (Optional) Add environment variables under Project Settings → Environment Variables (e.g. NEXT_PUBLIC_P2P_TRACKERS).

Other hosts

  • Run npm run build and upload the contents of the out/ directory to any static host (Netlify, Cloudflare Pages, GitHub Pages, etc.).
  • Ensure the host supports client-side routing (SPA fallback to index.html for /lobby, /game, etc.) if you use paths other than /.

PWA icons

The manifest uses the favicon as a fallback. For a better "Add to home screen" experience, add icon-192.png and icon-512.png to public/ and update the icons array in public/manifest.webmanifest.

Deployment checks (CI)

The repo runs GitHub Actions CI (lint + build) on every push and pull request to the default branch. You can require this check to pass before Vercel promotes a deployment to Production, so only passing builds go live.

  • Workflow: .github/workflows/ci.yml — installs dependencies, runs npm run lint, then npm run build.
  • Enable in Vercel: Project → SettingsGitDeployment Checks → require the CI (or "Build and lint") check before deploying. See documentation/deployment-checks.md for step-by-step instructions and troubleshooting.

Project structure

Path Purpose
app/ Next.js App Router: page.tsx (home), lobby/page.tsx, game/page.tsx, local/page.tsx, layout.tsx, globals.css.
components/ React components: game/ (board, chat, timer, move history), landing/hero.tsx, ui/ (button, card, dialog, input), theme-provider.tsx, error-boundary.tsx.
lib/ Core logic: chess-engine.ts (rules, FEN), p2p.ts (Trystero + BLE helpers), ble-transport.ts (BLE GATT room), transport-types.ts (Room interface), store.ts, elo.ts, pgn.ts, constants.ts, clipboard.ts.
types/ TypeScript: web-bluetooth.d.ts (Web Bluetooth API for BLE).
documentation/ Index, architecture, protocol, SDK guide, ranking API.
public/ Static assets and manifest.webmanifest.

Full “where to find what” map: documentation/README.md.


Documentation

Document Description
documentation/README.md Index — quick links and map of the codebase.
Architecture High-level design, transports (WebRTC + BLE), diagrams, data flow, state, discovery/NAT, stability (disconnect, refresh), security.
Protocol Wire protocol — transports (WebRTC, BLE), rooms, action types (≤12 bytes), JSON payloads, lobby and game flows. Required for building other clients.
SDK guide How to build FediChess clients in other languages (JS/TS, Python, Go, Rust) and interoperate with this app.
Ranking API Optional voluntary ranking service: submit results, leaderboard. User consent and configurable.
CHANGELOG Version history and release notes (current: 0.3.0).
Releases How to cut a release; tag-triggered GitHub Releases with notes from CHANGELOG.
Deployment checks Require CI to pass before production deploys (Vercel).

All of the above live in the documentation/ folder; documentation/README.md is the index.


Architecture at a glance

FediChess has no central game server. All gameplay (moves, chat, sync) happens directly between peers. The app uses two transports that share the same wire protocol (rooms, action names, JSON payloads):

  1. WebRTC (online) — Browsers connect to public WebTorrent-compatible WSS trackers to discover each other, then form peer-to-peer WebRTC data channels. The trackers are used only for discovery and signaling; once connected, game data flows only between the two players (and any spectators). Lobby room: p2p-chess-global; each game gets a room p2p-chess-{gameId}.
  2. BLE (nearby) — For local play without internet, the same protocol runs over Web Bluetooth (GATT). One device acts as a peripheral advertising the FediChess GATT service; the browser connects as central. Messages are length-prefixed actionName + JSON, same payloads as WebRTC.

Lobby and game UI are transport-agnostic: they use a single Room interface (makeAction, getPeers, onPeerJoin, onPeerLeave, leave) implemented by both Trystero (WebRTC) and the BLE layer. State (user, lobby, game) lives in Zustand; persistence (ELO, game history) is IndexedDB and optional account backup (HMAC-signed export). For full diagrams, data flow, and edge cases (disconnect, refresh, NAT), see Architecture.


Transports

Transport Discovery Data Scope Use case
WebRTC WebTorrent trackers (WSS), Trystero WebRTC data channels Many peers per room; lobby + game rooms Online play, spectators
BLE Web Bluetooth device picker (FediChess GATT service) GATT characteristic (length-prefixed actionName + JSON) 1:1 per connection Nearby play, no internet

Same protocol: rooms, action names, JSON payloads. Only the wire and discovery differ. Peers discovered over WebRTC are challenged over WebRTC; peers discovered over BLE are challenged over BLE. The game page uses the same Room interface for both.


Security and privacy

  • No server-side game logic. Moves and chat are sent peer-to-peer. We do not log or store game content. ELO and game history are stored only in your browser (IndexedDB) and, if you use it, in your own backup file.
  • Identity. There is no account system. You choose a display name (e.g. a username); it is not verified. Anyone who can join the same lobby room can see that name and your ELO (from heartbeats). For strong authentication you would need a separate mechanism (e.g. signed credentials) not provided by this app.
  • Trust. Peers can send arbitrary JSON. The app validates FEN and game events and ignores invalid data. Only the two players designated via role messages may send moves and game events; spectators cannot.
  • Trackers. Default trackers are public WebTorrent WSS servers. They see room IDs and peer presence (for signaling); they do not see move or chat content. To reduce exposure you can run your own tracker and set NEXT_PUBLIC_P2P_TRACKERS.
  • Account backup. Exports are signed with HMAC (key derived from your password) so tampering is detectable. Backups are intended for personal restore; do not share backup files if they contain data you care about.

Building other clients

The wire protocol is the source of truth. Any client that implements the same rooms, app ID, action names, and JSON payloads can discover peers, send challenges, and play games with this web app and other compatible clients.

  • JavaScript/TypeScript: This repo is the reference. WebRTC: Use Trystero (torrent strategy), same trackers and app ID. BLE: Implement the FediChess GATT service (see protocol doc for UUIDs and message format) or use lib/ble-transport.ts as reference. See SDK guide.
  • Python, Rust, C++: Official SDKs and examples live in sdks/; they use a shared Node bridge and the same protocol.
  • Other languages: Use the bridge from a client (see sdks/) or a WebRTC + WebTorrent library; protocol and payload shapes are in protocol.md.

Community clients that implement the protocol can be listed in this README (open an issue or PR).


FAQ

Do I need an account?
No. You set a display name in the app; it is stored locally and sent in lobby heartbeats. There is no login or password for the game server (there is no game server). Account backup is optional and password-protected for your own restore.

Why can’t I see any peers in the lobby?
You and others must be in the same lobby room (default: p2p-chess-global) and use the same app ID and trackers. If you changed NEXT_PUBLIC_P2P_TRACKERS, you’ll only see peers using the same trackers. Firewall or NAT can block WebRTC; try enabling STUN/TURN (see Configuration).

Does BLE work between two browsers?
No. The browser is always the central (client). The other side must be a peripheral advertising the FediChess GATT service (e.g. a native app or a BLE board). Two browser tabs cannot connect to each other via BLE.

Where is my ELO stored?
Locally in your browser (IndexedDB). Optional “Backup account” exports it to a file; you can restore on another device. Optional ranking API can submit results to a third-party leaderboard with your consent.

Can I self-host?
Yes. Build with npm run build and serve the out/ directory. You can point the app at your own WebTorrent trackers via NEXT_PUBLIC_P2P_TRACKERS. There is no backend to host; it’s a static site.

How do I add a new SDK (e.g. Go)?
Implement a client that spawns the Node bridge and speaks the same stdio JSON-lines protocol, or implement WebRTC + tracker discovery in your language. See sdks/ and SDK guide.


Ranking and federation

  • Local ELO — Computed and stored on device; updated after each game. No server required.
  • Voluntary ranking — The optional ranking API lets clients submit game results (with user consent) to a central or federated service for a global leaderboard. Anyone can run a compatible ranking server.
  • Federation — Using the same protocol and trackers across instances, communities can share a player pool; optional ranking services can aggregate across instances.

Contributing

Contributions are welcome: bug reports, feature ideas, code, and documentation.

  • Issues: Open a GitHub Issue to report bugs or suggest features.
  • Pull requests: Open a PR with your changes. Keep PRs focused; run npm run lint before submitting.
  • Documentation: Improvements to documentation/ and this README are welcome.
  • Protocol: The protocol is the source of truth. Client implementations in other languages that follow it can be proposed for listing as community SDKs.

See CONTRIBUTING.md for a short guide. By contributing, you agree that your contributions will be licensed under the MIT License.


License

MIT. See LICENSE.


Star History

Star History Chart