Local browser sandbox for "duplicate chess" — a four-player coupled-board
chess variant invented by Andrew Freiberg. Scaffold per CREATE_PROJECT.md
plus the approved design spec from this session's brainstorming.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Project-specific decisions. For global/cross-cutting decisions, see `~/bin/DECISIONS.md`.
Format: `YYYY-MM-DD: <decision> — <why>`
## Architecture
2026-05-19: First deliverable is a local single-operator sandbox/visualizer, not a networked game — the inventor's stated need is to *see* a mock game to comprehend the variant; networked four-player play is a separable later project.
2026-05-19: Single Vite + Svelte 5 + TS app, no server — duplicate chess is perfect-information, so the whole engine and all four boards live client-side. No pnpm workspace (unlike blind_chess, which needs a server as its trusted view boundary).
2026-05-19: Engine lives in a pure, DOM-free `src/engine/` tree (vitest-tested); Svelte UI in `src/lib/`. Keeps the coupled-legality logic isolated and portable if a networked version is ever built.
2026-05-19: Engine = 4×`chess.js` + an intersection layer. A player's legal moves = the moves legal on *both* their boards, keyed by `(from,to,promotion)`. Ghost immobility, the synchronized-checkmate definition, and en-passant/castling divergence all fall out of the intersection — no special-case code.
2026-05-19: Authoritative game state is an ordered list of synchronized moves; "replay to ply N" rebuilds all four `chess.js` boards. Powers undo and history scrubbing.
## Implementation
2026-05-19: Compass UI — four boards rendered as 45° diamonds in an X/pinwheel (NW 225°, NE 135°, SW 315°, SE 45°), players seated in the four V-notches, pieces rotate *with* their board so each player's army faces their seat. Confirmed against Andrew's sketch (`USERFILES/4personchess.png` in blind_chess).
2026-05-19: Four player colours (one per player) instead of White/Black fill — makes two-board ownership readable at a glance.
2026-05-19: Intersection highlighting (teaching mode) — grabbing a piece shows playable squares (legal on both boards) AND board-local-only squares, so the coupling is visible.
2026-05-19: Coordinate notation (`e2e4`) for the move log, not SAN — SAN's disambiguation differs between a player's two boards once they diverge, so it cannot be the single identical token.
2026-05-19: Click-to-move, not drag — cleaner on rotated boards.
2026-05-19: Provisional endgame rules picked by Claude, marked PROVISIONAL — Andrew can revise. First terminal event ends the game; any no-synchronized-move stalemate ends the game with all four drawing; threefold/50-move tracked on the whole four-board system; insufficient material not auto-detected.
## Deferred / Rejected
2026-05-19: Networked four-player play — deferred; separable later project, would reuse the `src/engine/` tree.
2026-05-19: AI opponents — deferred; the sandbox is operator-driven.
2026-05-19: Free position editor — rejected for v1; play-from-start + history scrubbing keeps every shown position reachable by legal play, preserving the "every board is real chess" invariant.
2026-05-19: Counter-rotating pieces upright on the diamonds — rejected; pieces rotate with their board so each player's army faces their seat (the point of the compass).
2026-05-19: Deployment behind Caddy — deferred; v1 runs locally, the static build can be hosted later trivially.
2026-05-19: A separate "dual view" of the on-move player's two boards — rejected; the compass is the whole UI, with the triple-highlight happening directly on it.
- **Click-to-move**: click a piece → triple-highlight appears → click a destination.
Click-to-move (not drag) is cleaner on rotated boards.
- **Promotion**: when the chosen move is a pawn reaching the last rank, a dialog
picks the piece; both pawns promote identically.
---
## 6. Provisional endgame rules
The inventor conversation fully specifies the common ending (first checkmate → one
winner, one loser, two draws) but leaves edge cases open. The operator chose to ship
**provisional defaults now**, clearly marked, for Andrew to revise later. These are
**PROVISIONAL — Claude's defaults, not Andrew's rulings**:
| Case | Provisional ruling |
|------|--------------------|
| **Single-player stalemate** (no synchronized move, not in check) | The whole game ends; all four players draw. No frozen-board continuation — this keeps the engine free of multi-player-elimination logic and matches "it is possible for everyone to draw." |
| **Double-board checkmate** (mated while in check on both boards, by both opponents) | Both checking opponents are recorded as winners; the mated player loses; the fourth player draws. Generalizes "the winner is the one who checkmates" without a tiebreak. |
| **Threefold repetition / 50-move** | Evaluated on the whole four-board system (all four positions + side-to-move), not per board. Triggers an all-draw game end. |
| **Insufficient material** | Not auto-detected (rare and hard to define across four coupled boards). The operator may declare a draw manually. |
Each provisional rule must be marked in code (a `PROVISIONAL` comment or constant)
so a future ruling from Andrew can be located and applied cleanly.
---
## 7. Scope
**In scope (v1):**
- Play a full game from the standard start, operator-driving all four players.
- The compass UI with pinwheel boards and four player colours.
- Intersection (teaching-mode) highlighting.
- Ghost detection and rendering.
- Checkmate / stalemate / draw detection with the provisional rules.
- Coordinate-notation move log.
- Undo and history scrubbing.
- Save / load a game to a JSON file.
**Out of scope (v1):**
- Networked four-player play (separable later project; would reuse `src/engine/`).
- AI opponents (the sandbox is operator-driven).
- A free position editor (play-from-start keeps every shown position reachable by
legal play, preserving the "every board is real chess" invariant).
- Insufficient-material auto-detection.
- Deployment behind Caddy (the static build can be hosted later trivially).
- Mobile-specific polish (four boards want a wide screen; desktop-first).
---
## 8. Testing
-`src/engine/` is pure TypeScript with no DOM — covered by **vitest**:
- synchronized-move intersection (including divergence, castling, en passant);
(`layout-v6.html` is the approved compass layout).
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.