Skip to content

Repository files navigation

Gambit ♞

Play chess in your browser — against Stockfish, a friend on the same device, or online with just a 6-digit PIN. No accounts, no tracking, no build step. Vanilla JavaScript front to back.

CI Live License: MIT Node Dependencies No build step

Gambit — mid-game against the AI

Gambit is a complete, dependency-light chess app: a vanilla-JS client (no framework, no bundler) and a ~350-line Node WebSocket server that is the sole authority on the rules. The AI runs entirely in the visitor's browser via WebAssembly, so the server only ever brokers online games — and the same client ships as two releases: a static single-player build on GitHub Pages and the full online app on any Node host.

Features

  • Three ways to play — Human vs AI, Human vs Human on one device, or Online via a shared 6-digit PIN (with a one-tap invite link).
  • Real chess — castling, en passant, promotion (with a piece picker), check / checkmate / stalemate / all draw types, via chess.js.
  • Stockfish 18, 8 difficulty levels, running locally in WebAssembly — the AI costs the server nothing.
  • Fair, server-authoritative online play — every move is re-validated on the server; reconnect and resume after a reload or dropped connection.
  • Play together — in-game chat (sound + tab-title unread badge), draw offers, and one-click rematch with colors swapped.
  • Polished board — legal-move dots, last-move and in-check highlighting, center-board toasts for check / mate / game events, captured-pieces tray with material score, synthesized move sounds (mutable).
  • Make it yours — 4 themes × 4 piece sets, remembered across visits.
Light · Standard Dark · Medieval Blue · Minimal Sepia · Unicode
Light theme, standard pieces Dark theme, medieval pieces Blue theme, minimal pieces Sepia theme, unicode pieces

How to play

Click a piece, then one of its highlighted destinations. Pick mode, difficulty, theme, and pieces from the header; New game restarts anytime.

Online: choose Online (PIN)Create game, then share the PIN or tap the invite link. Your friend joins and plays Black (their board flips automatically). Accidentally closed the tab? Reload and the game resumes.

Online game — waiting for the opponent with the PIN on screen

Architecture

flowchart LR
    subgraph Browser["Player's browser"]
        UI["Vanilla-JS client<br/>board · themes · pieces"]
        SF["Stockfish 18<br/>(WebAssembly worker)"]
        CJS["chess.js<br/>(local rendering + hints)"]
        UI --- SF
        UI --- CJS
    end

    subgraph Host["Node host (online only)"]
        WS["WebSocket server<br/>matchmaking · relay"]
        GM["Game manager<br/>authoritative chess.js"]
        WS --- GM
    end

    UI -->|"static files (HTTP)"| Host
    UI <-->|"moves / chat / offers (WSS)"| WS
Loading
  • client/ — static frontend, plain ES modules, no build step. Local modes (AI, hot-seat) work fully offline in the browser; Stockfish and chess.js are vendored.
  • server/ — Node.js (≥20, ESM), one runtime dependency (ws). Serves the client and hosts online games, re-validating every move with chess.js — the client is never trusted. Games are in memory; MAX_ACTIVE_GAMES caps parallel games and per-IP limits curb abuse.

The client probes /healthz on load and hides Online mode when no server is present, so a static-only deploy (GitHub Pages) degrades gracefully to single-player.

Run locally

npm install && npm start   # full app (local + online) at http://localhost:8080
npm test                   # protocol, security, social & sound suites

Front-end only (no online): python -m http.server -d client. An HTTP origin is required either way — ES modules and the Stockfish worker don't run from file://.

Deployment

The client is deployed to GitHub Pages (static, single-player) by deploy.yml. The full app runs on any Node host; a one-click Render blueprint is included:

  1. In RenderNew + → Blueprint → pick this repo. It reads render.yaml: build npm install, start npm start, health-check /healthz, TRUST_PROXY=1 preset.
  2. Served at https://<name>.onrender.com over wss:// automatically.

Free-plan trade-off: the service sleeps after ~15 min idle (first visit then wakes in ~30s) and in-memory games are lost on restart. Persistence is on the roadmap.

Every push to main redeploys via deploy-render.yml — set the repo secret RENDER_DEPLOY_HOOK to the service's Deploy Hook URL. Behind any proxy, set TRUST_PROXY=1 so per-IP limits use the real client IP.

Server configuration (environment variables, all optional)
Variable Default Purpose
PORT 8080 HTTP/WebSocket port
MAX_ACTIVE_GAMES 20 Global cap on concurrent online games
MAX_GAMES_PER_IP 3 Live games one client (IP) may own
MAX_CONNECTIONS_PER_IP 20 Concurrent WebSocket connections per IP
JOIN_FAILURE_LIMIT 10 Failed PIN joins per IP per minute before a short lockout
ALLOWED_ORIGINS same-origin Comma-separated origins allowed to open control sockets
HEARTBEAT_MS 30000 WebSocket ping interval (proxy keep-alive + dead-socket detection)
TRUST_PROXY 0 Read the client IP from X-Forwarded-For (set to 1 behind a proxy)

See .env.example. The server shuts down cleanly on SIGTERM/SIGINT.

Project structure

client/            static frontend (deployable on its own)
  index.html
  js/              game.js · board.js · ai.js · online.js · theme.js · pieces.js · sound.js · main.js
  js/vendor/       chess.js, Stockfish (with licenses)
  styles/          main.css + themes/
  assets/          piece sprites, screenshots
server/            server.js (transport + static) · game-manager.js (authoritative state)
test/              protocol · security · social · sound suites (no framework)

Roadmap

Online-game persistence (SQLite/Turso) · accounts & ELO · move replay & PGN import · engine analysis · clocks / blitz · play as Black vs the AI.

Contributing

See CONTRIBUTING.md — adding a theme or a piece set is a one-file change, and npm test runs the full server suite locally.

License & credits

Project code is MIT. Vendored components keep their own licenses: chess.js (BSD-2-Clause), Stockfish.js (GPLv3), and the standard piece set by Cburnett et al. (CC BY-SA 3.0, via cm-chessboard). The medieval and minimal piece sets are original artwork for this project (MIT).

About

Online & offline chess in the browser: play Stockfish, a friend on the same device, or a game via 6-digit PIN

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages