Files
station-master/docs/design.md
T
2026-07-31 07:19:57 -04:00

6.3 KiB
Raw Blame History

Station Master — design index

Station Master is a tabletop railroad-operations game set in the era of timetable-and-train-order railroading (18401950), being developed into a multiplayer digital game: players connect from a web browser and an authoritative server manages lobbies and game state.

Source of record

  • StationMasterPrototypeRules.pdf — the original prototype rules
  • StationMaster-PrototypeTurnChart.pdf — the 12-Stage turn chart

These stay as-is. Everything below is derived from them.

Rules

Document What it is
rules/rules-v0.1.md Faithful markdown transcription of the PDFs. No corrections. The baseline everything diffs against.
rules/rules-v0.2.md The working ruleset. v0.1 with all ten gaps resolved, each change marked with its gap number.
rules/card-reference.md What is printed on every card, plus the economy summary. The spec an engine or a print-and-play layout consumes.
rules/glossary.md Every defined term, alphabetized.
rules/open-questions.md All thirteen gaps, each with the options considered, the decision, and the rationale.

Architecture

Target is small self-hosted scale: a handful of concurrent games, hosted on a website or as a StartOS service. Stack is deliberately undecided; these documents describe what any implementation must do.

Document What it is
architecture/components.md The project plan. All 20 buildable pieces — where each runs, when, MVP vs finished size — plus dependency graph and build order.
architecture/overview.md Why the server is authoritative; state/intent/event split; transport; the rules-engine boundary.
architecture/game-state.md The entity model, and the constraints that are easy to lose.
architecture/protocol.md Intents, events, and per-player view redaction.
architecture/lobby-and-sessions.md Create/join, seating, reconnection, persistence.
architecture/deployment.md Plain web host vs StartOS service — and the one constraint that differs.

Current status

Rules formalized, card faces specified, architecture documented, and the rules engine built and simulated. Eleven of thirteen gaps are closed; Gap 12 (balance variance) and Gap 13 (deck scaling) remain open, both with data behind them.

Gaps 813 were all found by working the design forward — building it or simulating it — rather than by reading the PDFs. None arises in tabletop play, where a person simply does the sensible thing.

The economy, in one line: Local Operations actions are the main currency — one per Stage, twelve per Day — but inbound work bypasses them, which is where the game's variance comes from. See card-reference.md §7.

Wanted, not yet designed: post-game replay — watching a finished game back at speed. The architecture already produces what it needs (an ordered append-only event log plus a stored seed), so the note in architecture/overview.md exists to keep the capability from being designed out. It is explicitly not scheduled.

Provisional numbers — the victory targets are now confirmed at the mean by simulation. Still untested by play: Crew Tray count, Laborer counts, and whether the variance in Gap 12 is a flaw.

Next steps. The specification is complete enough to build against or to play on paper.

The build path is laid out in architecture/components.md — 20 components, a dependency graph, and a twelve-step order. Its MVP is solitaire: one Office, a fixed number of Days, a server talking to a single browser, display functional rather than pretty. The milestones worth knowing:

  • Step 4 — a full solitaire game runs to completion headless, proving the rules before a pixel is drawn.
  • Step 6 — the balance harness validates or retunes the provisional numbers, while changing them is still free.
  • Step 10 — MVP complete; a human plays end to end.

Stack: TypeScript, chosen so the engine runs in both the server and the browser — one implementation of the movement rules, and instant affordances without a round-trip. Node 22 runs TypeScript natively, so there is no build step during development.

Steps 16 are done — the rules engine (components 17), heuristic bots (17) and the balance harness (18), with 134 tests passing.

The step 4 milestone is met: a full solitaire game runs to completion, headless. Games are reproducible from a seed, terminate from every seed tried, conserve all 62 rolling stock pieces, and develop properly.

End-of-game statistics (src/sim/stats.ts) report revenue by source, traffic, development, action mix and strategy buckets — plus an anomaly detector that treats "this event never fired" as a finding. It caught two bugs on its first run.

The step 6 milestone is met, with a caveat. The harness found five engine bugs that no test had caught, and once they were fixed the numbers came good: ~35% win rate and 5.0 Revenue/player/Day, matching the Gap 10e prediction of 5-6.

The caveat is large: those numbers were themselves measured against a scoring bug, since fixed. Honest figures are ~0.9 Revenue/Day and a 0% win rate — the targets are currently unreachable. The bot is still the prime suspect (it uses ~10 Laborer actions per game out of ~900 available), so this is Gap 12 and remains open. One genuine signal did emerge: mixed freight/passenger strategies outscore pure ones, with pure freight much the worst.

Gap 11 is decided — track orientation is chosen on placement, settled by measurement. Gap 13 answers the deck-size question: do not double it; scale only the buildable cards with player count.

Next: step 7 begins the server (components 8, 9, 20).

Run the harness with node src/sim/harness.ts [games] [length].

Running alongside, and independent of all of it: print-and-play components. card-reference.md specifies every card face, so layout and art are the only remaining work before a table playtest — which answers the one question simulation cannot, whether it is fun.