Commit Graph

9 Commits

Author SHA1 Message Date
Kevin 220f70d342 Add the real 211-tile / 5-stat game content
shared/tile-inventory.json + shared/roll-tables.json + shared/GAME-REVIEW.md
+ shared/BRANCHING-TEMPLATE.md were parsed from the design doc in a separate
session and were already sitting untracked in this repo. This is the real,
authoritative game content — 211 tiles across 12 segments, 5 player stats
(cash/love/education/wealth/age), 48 placeholder roll tables — far more
complete than the hand-sketch-inspired board built earlier.

Adds shared/tileInventory.js and shared/rollTables.js: mechanical
`export default {...}` wrappers around the same JSON (kept as-is alongside
them as the raw source reference), so the content is importable both by the
server and by the browser fetching shared/*.js with zero bundler — the same
pattern every other file in shared/ already uses. Avoids relying on JSON
module import-attribute syntax, whose support is uncertain on node:20-alpine
(the Dockerfile's base image).

Also includes assets/colors.json and assets/tile_types.json (an apparently
separate, incomplete transcription of the hand sketch) — not wired into
anything yet, just brought into version control.

Appends integration-gap TODOs to GAME-REVIEW.md: 85 inline_table tiles have
a die size but no table content anywhere in the parsed files; payday/
cash_bonus amounts are undefined everywhere; multi-table roll_table_ref
tiles (2-3 tables at once, 22 of them) have no documented combination rule.
2026-07-28 10:05:55 -07:00
Kevin 70eeb78eaf Give the board an illustrated-map feel instead of a flowchart
Same data-driven layout as before (nothing about computeLayout changed) —
only what gets drawn changed:

- Procedural terrain backdrop: a winding river, a few mountain clusters, and
  denser two-tone trees, scattered deterministically like the existing
  tree-blobs were, so none of it needs hand-alignment to specific tiles and
  it keeps working at any board size.
- The road between spaces is now a wide dashed dirt path with a subtle
  hand-drawn "wobble" (SVG feTurbulence/feDisplacementMap) instead of a
  clean vector line.
- Tiles are beveled: a drawn shadow copy, a gloss gradient, and a few
  degrees of per-tile tilt derived from a hash of the space id (deterministic,
  not random-per-render) so they read as hand-placed rather than
  machine-stamped. Choice diamonds get a small signpost stick underneath.

Prototyped and screenshotted headlessly before committing; user confirmed
this direction over the previous flowchart-style rendering.
2026-07-22 09:17:25 -07:00
Kevin 6aa9769ce5 Expand the board to the full sketch (~107 spaces, three forks)
shared/board.js now transcribes every distinct space label from the
hand-drawn sketch (assets/game_board.png) rather than Phase 1's small
subset. The sketch's arrows get genuinely ambiguous in a few places (it
reads as a mockup, not an engineered spec) and reuses several space names
across zones (Start A Business, Family Reunion, Market Crash, ...) — that
repetition is kept as intentional flavor rather than deduplicated, and the
ambiguous bits are resolved into a clean DAG with the same shape Phase 1
proved out: a fork, a chain() per branch, a convergence — repeated three
times (Career/Education/Gap Year, then Relationship/Investment, then High
Risk/Safe), into a long shared retirement tail. Branches are built with a
small chain() helper that auto-wires each entry's `next` to the following
one, since hand-wiring ~107 ids was too error-prone.

The reducer, SQLite schema, and rooms/WS layer needed zero changes — the
whole point of the pure-reducer/graph-data design from Phase 1. Two things
did need generalizing:
- public/boardRender.js's lane offset was hardcoded to a 2-way fork; the
  new "Which Path?" fork is 3-way (Career/Education/Gap Year), so the
  offset formula is now symmetric for any number of branches.
- shared/game.test.js hardcoded Phase 1's specific space ids. Rewritten to
  be board-structure-agnostic: it always resolves the first offered choice
  and otherwise rolls the max die value, which reliably makes progress
  regardless of board shape (walkForward always stops early at the next
  choice/finish), plus a graph-well-formedness check.

Verified: unit tests green; a full two-player game played headlessly
end-to-end through all three forks to Finish in 38 turns with zero
console/page errors; the rendered board visually confirmed at full scale
(5-row snake layout, 3-way fork fans out correctly, all labels legible).
2026-07-21 18:56:27 -07:00
Kevin 8df4859696 Render the board as SVG, laid out from the graph data
Adds public/boardRender.js: a layout algorithm that derives every space's
position purely from shared/board.js (column = longest-path distance from
Start, lane = branch offset that fans out at a choice space and re-centers
wherever branches rejoin), so it keeps working unmodified as the board data
grows — no hand-placed coordinates to maintain.

Renders spaces as styled SVG nodes (color/shape by type), connects them with
curved path lines, and animates player tokens between positions. Pending
choices glow and are clickable directly on the board, in addition to the
existing text buttons. Game view widens the card on desktop for the board
and scrolls horizontally on narrow viewports.

Also repicks the player color palette (server/index.js) to avoid the board's
own semantic colors (green/gold/red), after a token nearly disappeared into
the same-colored Start space during visual testing.

Verified with a headless-browser run (Playwright, off-screen — not a desktop
screenshot): two players through lobby -> live join update -> board -> a
fork choice, no console errors, reducer tests still green.
2026-07-21 18:12:01 -07:00
Kevin d40bc09867 Phase 1: reducer, SQLite, rooms & invite links
Turns the Phase 0 deployment shell into a playable async multiplayer game:

- shared/game.js + shared/board.js: pure reducer (reduce(state, action) ->
  newState) over a small branching board subset mirroring the sketched
  design (Career/Education fork, Relationship/Investment fork, High-Risk/Safe
  fork, race to Finish). Dice randomness is generated server-side and shipped
  inside the ROLL action payload, so the reducer itself stays fully pure and
  is identically importable by both server and browser.
- server/db.js: SQLite (better-sqlite3) schema for games/players/tokens,
  config and state stored as JSON. tokens covers both room invite links and
  per-player reconnect secrets.
- server/rooms.js: in-memory room registry that is the only place the shared
  reducer is invoked server-side — validates intents, applies actions,
  persists, and broadcasts to every socket in the room.
- server/index.js: REST endpoints to create/join/inspect a game, and a
  room-aware /ws that authenticates via a first {type:'AUTH'} message rather
  than a URL query param (keeps session tokens out of access/proxy logs).
- public/client.js + public/index.html: NetworkTransport wrapping the
  WebSocket, localStorage-backed session persistence so a reload resumes as
  the same player, and a lobby/waiting-room/game-view UI.
- Dockerfile: adds python3/make/g++ so better-sqlite3's node-gyp fallback
  builds on Alpine when a prebuilt binary isn't available for the exact
  Node/musl combo.

Verified: shared/game.test.js (node --test) covers the full rules engine;
a scripted two-client run over real HTTP+WS confirms both clients converge
on identical state through create/join/start/play-to-finish; a server
restart mid-game preserves state and reconnect resumes the same player
without creating a duplicate.
2026-07-21 17:10:56 -07:00
Kevin 1f51c7d541 Remove throwaway board-reading crop images
assets/crops/ was a set of zoomed-in crops generated locally to read the
hand-drawn board sketch's small text — not used by any code, just repo bloat.
2026-07-21 17:09:32 -07:00
Kevin 89159ad5b5 Early version 2026-07-21 16:17:12 -07:00
Kevin 9bd5d5d9ff Remove bundled zip; ignore archives 2026-07-21 14:16:59 -07:00
Kevin b063f3f34b Phase 0: deployment shell 2026-07-21 20:48:28 +00:00