houserules/packages/chess/src
Joey Yakimowich-Payne f4e030b8e5
feat(chess): piece-hp mechanic + extensible preset-hook infrastructure
Implements the piece-hp (Hit Points) preset end-to-end and, more
importantly, sets up the infrastructure for rules that need state,
capture interception, or custom UI. Adding a new "guns" rule, a
"poison-cloud" visual, or similar now requires zero changes to
engine.ts, Board.tsx, or protocol.ts.

Engine / preset registry
~~~~~~~~~~~~~~~~~~~~~~~~
PresetDef gains three new optional hooks:

  - onActivate(engine)       \u2014 fires once on active-set transition
                               (inactive \u2192 active). Idempotent by
                               convention so sync paths that re-apply
                               from server state don\`t stomp values.
  - onDeactivate(engine)     \u2014 symmetric cleanup. Also fires when a
                               turn-limited preset expires via
                               tickAfterMove.
  - onBeforeCapture(engine, attacker, target)
      Fires immediately before the engine\`s default capture path.
      Returns `{ consume: true }` to short-circuit: engine skips
      target retraction AND attacker move. Used by piece-hp for
      non-lethal damage; future rules can override however they like.

New ChessEngine.setActivePresets(requests) is the single entry point
that diffs old vs new and fires lifecycle hooks in deterministic
order (deactivate-then-activate). replaceAll stays public for tests
that want to bypass hooks.

ActivePresetSet.tickAfterMove now returns the list of expired ids
so the engine can fire onDeactivate on them.

piece-hp preset
~~~~~~~~~~~~~~~
- onActivate seeds Hp=2 on every piece.
- onDeactivate retracts Hp from all pieces.
- onBeforeCapture decrements Hp; if > 0 consumes the capture (attacker
  stays, target survives, turn advances). At 0, returns without
  consuming so the engine\`s default retract-and-move fires normally.

All capture sites intercepted: regular captures (engine.ts:200) AND
en-passant captures (engine.ts:194). The check-simulation path in
check.ts does NOT fire the hook \u2014 it uses an isolated snapshot
session, so lifecycle side effects don\`t leak into legal-move
filtering.

UI overlay registry
~~~~~~~~~~~~~~~~~~~
New packages/chess/src/ui/preset-overlays.tsx: a module-level registry
mapping preset id \u2192 React component that renders above each piece.
Board.tsx loads the registry via side-effect import and renders any
registered overlays for every active preset.

New packages/chess/src/presets/piece-hp.ui.tsx registers HealthBarPips:
2 pip dots above each piece, filled = remaining HP, empty = lost HP.
Pip color contrasts piece color for readability on either square.

Adding a new visual rule now costs 3 files and zero engine changes:
  presets/foo.ts        (mechanic + lifecycle hooks)
  presets/foo.ui.tsx    (overlay component + registry call)
  presets/ui-overlays-index.ts  (single-line import)

Testing
~~~~~~~
New piece-hp.test.ts: 8 integration tests covering lifecycle (seed,
retract, idempotent re-apply, no-fire on scope-only change) and
capture resolution (non-lethal decrement, lethal retract at HP=0,
HP drain over multiple captures, deactivate mid-game leaves damage
but retracts Hp). Total 861 tests pass (+8), 3/3 E2E green.
2026-04-17 15:54:33 -06:00
..
app fix(chess): wire multiplayer live sync via GameClient + PredictionManager 2026-04-17 13:54:06 -06:00
assets fix(chess): cylindrical board wraps every piece, plus eliminate piece image flash 2026-04-17 15:17:57 -06:00
hooks feat(chess): piece-hp mechanic + extensible preset-hook infrastructure 2026-04-17 15:54:33 -06:00
net feat(chess): per-color preset scope, turn-limited duration, server-authoritative sync 2026-04-17 14:23:37 -06:00
persist feat(chess): add localStorage auto-save and restore (P3.14) 2026-04-16 16:24:49 -06:00
presets feat(chess): piece-hp mechanic + extensible preset-hook infrastructure 2026-04-17 15:54:33 -06:00
rules feat(chess): add checkmate detection (P2.19) 2026-04-16 15:06:27 -06:00
ui feat(chess): piece-hp mechanic + extensible preset-hook infrastructure 2026-04-17 15:54:33 -06:00
audio.ts feat(chess): polish UI with SVG pieces, motion animations, sound, and confetti 2026-04-17 12:04:56 -06:00
coord.test.ts feat(chess): add coordinate + color helpers (P2.7) 2026-04-16 14:47:04 -06:00
coord.ts feat(chess): add coordinate + color helpers (P2.7) 2026-04-16 14:47:04 -06:00
engine-presets.test.ts feat(chess): per-color preset scope, turn-limited duration, server-authoritative sync 2026-04-17 14:23:37 -06:00
engine.ts feat(chess): piece-hp mechanic + extensible preset-hook infrastructure 2026-04-17 15:54:33 -06:00
index.ts fix(chess): real cylindrical-board slide wrap + working check indicator 2026-04-17 15:03:49 -06:00
pgn.ts test(chess): replay 5 classic FIDE games; Phase 2 acceptance gate (P2.23) 2026-04-16 15:18:57 -06:00
schema.test.ts feat(chess): add attribute schema and piece fact shape (P2.5) 2026-04-16 14:46:27 -06:00
schema.ts feat(chess): add attribute schema and piece fact shape (P2.5) 2026-04-16 14:46:27 -06:00
starting-position.test.ts feat(chess): add starting-position fact generator (P2.6) 2026-04-16 14:46:34 -06:00
starting-position.ts feat(chess): add starting-position fact generator (P2.6) 2026-04-16 14:46:34 -06:00
vite-env.d.ts feat(chess): polish UI with SVG pieces, motion animations, sound, and confetti 2026-04-17 12:04:56 -06:00