Commit graph

69 commits

Author SHA1 Message Date
8b8a5179ec
fix(chess): lift dragged piece above all other pieces
The piece`s own z-index could only stack within its grid cell`s context,
so when translated over neighbouring cells it rendered underneath their
pieces. Promote the hosting cell to z-50 while it holds the dragged
piece so the whole cell (and piece inside) float above the board.
2026-04-17 13:31:44 -06:00
d4622b2cb4
feat(chess): spring-physics drag with cursor-release FLIP animation
Dragging a piece now follows the cursor with spring lag and a subtle tilt,
scales up with a deeper shadow while lifted, and on a valid drop glides
smoothly from the cursor-release position into the destination square.
Invalid drops spring back to the origin. Dragging is disabled entirely
for the non-playing side (no grab cursor, no transforms, no drag events).

Cursor tracking uses a document-level `dragover` listener — the `drag`
event on the source element is throttled by Chromium and reports 0/0 in
Firefox, so is unusable for smooth tracking.

Replaces motion`s `layoutId` FLIP with a manual implementation. Motion
measures layout rects without inline transforms, so `layoutId` always
animated from the source square instead of the cursor position. The new
approach stashes the transformed `getBoundingClientRect` on dragend and
consumes it from a `useLayoutEffect` at mount, jumping the spring to the
delta and letting it animate home — producing a true release-to-target
FLIP.
2026-04-17 13:30:36 -06:00
858d326895
fix(chess): preset toggles refresh engine state immediately; new-game flows reset the board 2026-04-17 12:15:23 -06:00
50fba0bbd7
fix(chess): replace broken black-pawn and black-knight SVGs with valid Cburnett assets 2026-04-17 12:08:13 -06:00
fef8baa9dc
feat(chess): polish UI with SVG pieces, motion animations, sound, and confetti
- Add Cburnett SVG chess pieces from Wikimedia (Lichess set, ~18KB total)
- Add move/capture/check/checkmate/castle/promote sound effects via OGG
- Install motion for layout animations: pieces slide smoothly, captures fade
- Install canvas-confetti: victory celebration on checkmate
- Install sonner: toast notifications
- Install lucide-react: volume icons for mute toggle
- Persist mute state in localStorage
- Animated game-over banner (spring entrance)
- Animated drawer slide-in replacing CSS keyframe
- Lobby and App get polished visual treatment
- Preserve all E2E data-* selectors and drag-drop contract

Co-authored-by: visual-engineering agent
2026-04-17 12:04:56 -06:00
0f1cb4ff34
fix(chess): preserve RulesDrawer scroll position on toggle 2026-04-17 11:44:08 -06:00
7e040c0f27
feat(chess): add in-game RulesDrawer for mid-game preset toggling 2026-04-17 11:41:39 -06:00
51afd9a6f5
feat(chess): wire PRESET_REGISTRY into ChessEngine.getAllLegalMoves 2026-04-17 11:31:07 -06:00
dbf3b4551d
fix(chess): repair lobby create/join flow and connectAndCreate default 2026-04-16 21:32:21 -06:00
ca6a3df500
fix(rete): inject clock into EventLog; use tsc for DTS; fix cycle.test.ts private access; add Playwright worker limit 2026-04-16 18:25:49 -06:00
103f2bd0a6
test(root): E2E multiplayer with reconnect; tag Phase 4 (P4.12) 2026-04-16 18:12:44 -06:00
6fb67c5026
feat(chess): add lobby UI for create/join rooms (P4.11) 2026-04-16 18:01:31 -06:00
721cc5484d
feat(chess): add client prediction + server reconciliation (P4.10) 2026-04-16 17:48:33 -06:00
39d91b6356
feat(chess): add WebSocket client library with reconnect (P4.9)
GameClient provides typed event-driven access to the chess server:

- Envelope management: auto v/seq/ts, token captured from room.created/joined
- Event emitter: on/off for game.state, game.delta, game.end, room.created,
  room.joined, error, connected, disconnected(willReconnect)
- Exponential backoff reconnect: 1s, 2s, 4s, ... capped at 30s, max 10 attempts
- Sequence-ack tracking via currentSeq (highest server seq seen; never regresses)
- Dependency injection for WebSocket ctor and timers enables deterministic tests

packages/chess/src/net/types.ts mirrors the server wire types without importing
from @paratype/chess-server (wrong dependency direction).

21 tests cover connect flow, message dispatch, send semantics, reconnect state
machine, seq tracking, and listener management.
2026-04-16 17:44:13 -06:00
2d0b8399f8
feat(server): add reconnection with 60s grace + snapshot resume (P4.7)
On disconnect, a player's slot is held for 60s via ReconnectManager.
During the grace window, game.delta frames destined for the absent
slot are buffered in order. If the client reconnects with its
original token (envelope-level), the grace timer is cancelled and
the server replays a fresh game.state snapshot plus every buffered
delta. Timer expiry triggers the original "player_left" game.end
cleanup that previously ran immediately on disconnect.

- new packages/server/src/reconnect.ts: ReconnectManager (no WS refs,
  no registry coupling, unref'd timers so tests don't block exit)
- broadcast.ts: unregisterConnection starts grace; handleRoomJoin
  routes reconnect path via envelope token + isPending check;
  handleGameMove buffers deltas for disconnected opponents
- reconnect.test.ts: 9 unit cases (grace/cancel/buffer/expire/reset)
- broadcast.test.ts: end-to-end reconnect scenario + negative case
2026-04-16 17:38:26 -06:00
e420ee18c5
feat(server): add move validation + fact-delta broadcast (P4.6)
Wire the WebSocket message handler to process game.move intents via
GameSession and broadcast game.delta to both room players. Add
broadcast.ts as the message router with handlers for room.create,
room.join (triggers game.state to both players when 2nd player
joins), room.leave, and game.move. Move-intent validation enforces
NOT_YOUR_TURN before applyMove so clients can distinguish turn
errors from illegal moves.

index.ts now extends ClientData with roomCode/token, registers
connections on open and unregisters (+ markDisconnected +
broadcast game.end) on close, and gates inbound frames through
the size cap and rate limiter before dispatch.

broadcast.test.ts drives handleMessage directly with mock
ServerWebSockets (vitest runs on Node, so we can't use Bun.serve)
covering: legal-move broadcast to both players, illegal-move
error-to-sender-only with silent opponent, NOT_YOUR_TURN, malformed
JSON fatal disconnect, VERSION_MISMATCH fatal disconnect,
ROOM_NOT_FOUND, and BAD_TOKEN for unauthenticated game.move.

bun run typecheck, bun run lint, bun run test all pass.
2026-04-16 17:27:00 -06:00
f37c0934aa
feat(server): add authoritative game session per room (P4.5)
Each room owns a ChessEngine wrapped in a GameSession; only the server
calls insert/retract/fireRules and all EntityIds are minted server-side.
GameSessionRegistry keys sessions by room code so two rooms cannot
observe or collide with each other's working-memory state.

GameSession.applyMove validates algebraic inputs, finds the matching
legal move via ChessEngine.findMove, applies it, and returns a fact-
level diff (inserted/retracted) plus the new turn and terminal state.
Terminal states are sticky: further moves after checkmate/draw return
GAME_OVER rather than silently mutating a dead session.

Exposes @paratype/chess's headless surface (ChessEngine, coord helpers,
schema types) via a new package entry point; the React app continues to
import concrete modules directly.
2026-04-16 17:17:42 -06:00
aafc18ef9e
feat(server): add rate-limit, origin allow-list, message-size cap (P4.4) 2026-04-16 17:11:40 -06:00
7d07bb78ba
feat(server): add room registry with codes + tokens (P4.3) 2026-04-16 17:09:43 -06:00
817b4d95f3
feat(server): add protocol schemas + validation (P4.2) 2026-04-16 17:07:21 -06:00
25695d69b2
feat(server): scaffold Bun HTTP+WS server with health + logging (P4.1) 2026-04-16 17:03:42 -06:00
13af8ddab3
test(chess): e2e full-flow scenario; tag Phase 3 (P3.15) 2026-04-16 16:55:28 -06:00
a75b6f041b
feat(chess): add localStorage auto-save and restore (P3.14) 2026-04-16 16:24:49 -06:00
3fdeb5822d
feat(chess): add JSON export/import with validation (P3.13) 2026-04-16 16:14:46 -06:00
bc753aadfd
feat(chess): add Save/Load panel + time-travel undo (P3.12) 2026-04-16 16:12:15 -06:00
116cbb42b5
feat(chess): add rule-toggle UI with compatibility warnings (P3.11) 2026-04-16 16:05:04 -06:00
d367f51171
feat(chess): add interactive Chessboard with drag-drop (P3.10) 2026-04-16 16:01:34 -06:00
0f891fa013
feat(chess): scaffold Vite + React app (P3.9) 2026-04-16 15:54:32 -06:00
8436df7986
feat(chess): add all 15 preset custom rules P3.4-P3.8 2026-04-16 15:32:18 -06:00
cf1a8a3aab
feat(chess): add preset rules 1-3 (P3.4)
Introduces PresetRegistry + three pawn-focused preset rules from
RULES.md (pawns-move-backward, double-pawn-sprint,
pawn-diagonal-no-capture). Presets register themselves via
side-effect imports and expose getExtraMoves/filterMoves hooks for
the ChessEngine to invoke during move generation (engine wiring is
P3.11). Registry enforces incompatibility and requires invariants.
2026-04-16 15:30:14 -06:00
35e270e3b5
feat(rete): add Immer snapshots at tick boundaries (P3.2) 2026-04-16 15:25:35 -06:00
c5c00153ab
feat(rete): add replay engine + state-hash determinism verifier (P3.3) 2026-04-16 15:25:13 -06:00
aa5105d1c7
feat(rete): add append-only event log with monotonic sequence (P3.1) 2026-04-16 15:24:11 -06:00
6baab9f3fd
test(chess): replay 5 classic FIDE games; Phase 2 acceptance gate (P2.23)
- packages/chess/src/engine.ts — ChessEngine integrates all rule modules
  (pawn, knight, sliding, king, castling, en-passant, promotion, check,
  checkmate, stalemate, draws) into a playable game without the Rete
  production network
- packages/chess/src/pgn.ts — minimal SAN/PGN parser with full
  disambiguation support (file/rank hints, full from-square)
- packages/chess/tests/fide-games/classic-games.test.ts — 5 game tests:
  Fool's Mate, Scholar's Mate, Ruy López, Sicilian Defence, Italian Game

All 5 tests green; typecheck clean.
2026-04-16 15:18:57 -06:00
f94ab386a8
feat(chess): add checkmate detection (P2.19) 2026-04-16 15:06:27 -06:00
3f8a38bb41
feat(chess): add insufficient material draw (P2.22) 2026-04-16 15:05:54 -06:00
29ea2136b8
feat(chess): add 50-move and threefold repetition rules (P2.21) 2026-04-16 15:05:33 -06:00
20a18e6c78
feat(chess): add stalemate detection (P2.20) 2026-04-16 15:04:38 -06:00
6b760c9535
feat(chess): add check detection + self-check filter (P2.18) 2026-04-16 15:00:39 -06:00
fbdf10ec51
feat(chess): add pawn promotion rule (P2.17) 2026-04-16 14:58:31 -06:00
6938a2aedb
feat(chess): add en passant rule (P2.16) 2026-04-16 14:57:58 -06:00
f1da22641f
feat(chess): add castling rules (P2.15) 2026-04-16 14:57:39 -06:00
d9eaeb2f06
feat(chess): add turn order + move integration (P2.13) 2026-04-16 14:54:30 -06:00
483e4ef686
feat(chess): add capture resolution (P2.14) 2026-04-16 14:53:37 -06:00
83d99778db
feat(chess): add king basic move rules (P2.12) 2026-04-16 14:52:51 -06:00
1013c40e2a
feat(chess): add bishop/rook/queen sliding rules (P2.11) 2026-04-16 14:52:39 -06:00
6994d5fe55
feat(chess): add knight move rules (P2.10) 2026-04-16 14:51:56 -06:00
9a87e57007
feat(chess): add pawn move/capture rules (P2.9) 2026-04-16 14:51:49 -06:00
eb58441752
feat(chess): add movement primitive rules (P2.8) 2026-04-16 14:49:03 -06:00
d4cee82b20
feat(chess): add coordinate + color helpers (P2.7) 2026-04-16 14:47:04 -06:00