7.2 KiB
NOT TONIGHT — Build Plan & Technical Architecture
Read GAME_DESIGN.md first. This doc is the engineering plan the lanes execute. Contract details live in CONTRACTS.md.
1. Stack (decided — don't relitigate)
| Choice | What | Why |
|---|---|---|
| Engine | Phaser 3 (latest 3.x) | Scenes map 1:1 to game phases; tweens, input, Light2D for the flashlight cone; huge ecosystem |
| Language | TypeScript, strict | Multiple parallel lanes NEED typed contracts; the rules engine is pure typed functions |
| Build | Vite | Instant dev server, static build output |
| Tests | Vitest | Rules engine, patron generator, ID validity, clock — all pure logic, all unit-testable |
| Audio | Raw WebAudio (no Howler) | The low-pass-filter-as-location trick and the beat-clock need direct node graph access |
| Saves | localStorage | No backend. Ever. |
| Art (v0.x) | Runtime paper-doll renderer | Patrons are layered data (see design §4.1); placeholder layers are coloured-pixel shapes drawn to a texture. Real pixel-art layers swap in later behind the SAME layer contract |
| Deploy | Static dist/ |
Eventually → partly.party games VPS. Not a v0.1 concern |
2. Repo layout (ownership boundaries = merge-conflict avoidance)
src/
core/ # LANE-0 then frozen: EventBus, GameClock, SeededRNG, GameState, save
data/ # LANE-0 then frozen-ish: types + static config (venues, nights, rules, archetypes)
patrons/ # LANE-0: generator, paper-doll renderer, memory/regulars
rules/ # dress-code engine, ID validator, sobriety logic (pure functions ONLY)
scenes/
door/ # LANE-DOOR owns
floor/ # LANE-FLOOR owns
shared/ # Boot, Menu, NightSummary, HUD — LANE-0 stubs, integration fills
audio/ # LANE-JUICE owns: techno engine, sfx synth
ui/ # LANE-JUICE owns: stamp, phone, dialogue box, clicker widgets
tests/ # mirrors src/; every lane adds tests for its pure logic
docs/ # design + this plan + CONTRACTS.md
lanes/ # lane instruction files
LANEHANDOVER.md
Rule: a lane commits only inside its owned directories + its tests + LANEHANDOVER.md.
Changes to core/, data/ types, or CONTRACTS.md after Phase 0 require a
CONTRACT CHANGE REQUEST in the handover file and reviewer sign-off — never just do it.
3. Phases
Phase 0 — Scaffold & Contracts — ✅ DONE 2026-07-19 (executed by Fable)
lanes/LANE0_SCAFFOLD.md. Delivered: strict-TS Vite+Phaser scaffold, all
CONTRACTS.md types in src/data/types.ts, core systems (SeededRNG, EventBus,
GameClock+ageOn, Meters, StubBeatClock, save), patron generator +
paper-doll renderer (pure dollPlan + Phaser renderDoll), 49 unit tests, and
the Patron Parade demo verified in-browser. See the LANE-0 SESSION block in
LANEHANDOVER.md for API notes Phase-1 lanes must read.
Phase 1 — Parallel lanes (after Phase 0 review passes)
Three lanes run concurrently on separate branches/worktrees:
- LANE-DOOR (
lanes/LANE_DOOR.md) — the Door scene, full v0.1 loop: queue, ID minigame, dress-code stamps, clicker, Dazza texts, verdicts, Vibe/Aggro wiring. This is the v0.1 critical path — the game is shippable with only this lane done. - LANE-FLOOR (
lanes/LANE_FLOOR.md) — top-down Floor scene: patrol movement, flashlight/UV cone, drunk detection, Cut-Off dialogue, pat-down minigame, toilet rhythm game (against a stub beat clock until integration). - LANE-JUICE (
lanes/LANE_JUICE.md) — WebAudio techno engine + low-pass location filter + beat clock; SFX synth (stamp, thud, static, clicker); reusable UI widgets (stamp, phone, dialogue). Develops against its own demo scenes.
Lanes talk ONLY through the event bus + contracts. No lane imports another lane's
scene code. Beat sync example: audio engine emits beat:tick on the bus; the toilet
rhythm game consumes beat:tick; until integration, LANE-FLOOR uses the
StubBeatClock from core (same event, fixed 128 BPM).
Phase 2 — Integration — ✅ DONE 2026-07-19 (executed by Fable)
Night flow machine: Door and Floor run concurrently all night, player toggles via the doorway / floor exit; Kayden rules the real queue while you're inside (80% admit, 1-in-7 unstamped); TechnoEngine + location filter + SFX live in the night; ui/Stamp + MeterHud swapped in; Thu→Fri→Sat run with saved run-scoped heat; 3rd strike = immediate LICENCE PULLED, run over. See the Phase-2 SESSION block in LANEHANDOVER.md.
Phase 3 — Content & polish (parallel lanes OPEN)
lanes/LANE_CONTENT.md (guest list, moral encounters, inspector, incident
report), lanes/LANE_FLOOR2.md (fights, smoking area, aggro decay),
lanes/LANE_JUICE2.md (ear pass, ambience, night arc). Later in this phase:
venues 2–4, real pixel art into the paper-doll slots (ASSETS.md), regulars'
cross-night memory, the economy tuning pass (John + reviewer, NOT a lane).
Phase 4 — The role ladder (design §6; future, do not start)
Glassie, bartender, DJ roles + roster board. Not scoped yet — but it imposes ONE rule on every earlier phase: the simulation is role-agnostic. Crowd sim, patron state, meters, and incidents must never assume the player is security — the player is just an entity with a verb-set reading shared state. If you're about to hard-code "the player" into a sim system (e.g. "patrons only get cut off by the player"), model it as an actor capability instead (NPC staff already need this — Kayden works the door while you're on the floor). The DJ role will drive the TechnoEngine directly, so LANE-JUICE keeps track parameters (BPM, layer intensities) externally settable rather than hard-coded.
4. Coordination protocol (all lanes)
- Branches: each lane works on
lane/<name>(e.g.lane/door), pushed to origin (ssh://git@100.71.119.27:222/monster/not-tonight.git). Never push main. On one machine, use worktrees:git worktree add ../not-tonight-door lane/door. - Handover: every work session APPENDS a session block to
LANEHANDOVER.md(template inside it) and pushes. This is how the reviewer (Fable) sees state. - Review gate: reviewer reads handovers + diffs, replies with a REVIEW block in the same file (or a fresh lane instruction file), merges approved lanes to main.
- Contract changes: request-only via handover. If blocked >30 min on a contract
ambiguity, write the question in the handover, make the smallest local stub that
unblocks you, mark it
// TODO(contract):, and continue. - Definition of done for any session: compiles (
npm run build), tests green (npm test), demo scene for your lane runs (npm run dev), handover written.
5. Milestone acceptance
- M0 (Phase 0):
npm run devshows Patron Parade; ≥25 unit tests green covering RNG determinism (same seed → same patrons), ID validity math, layer rendering data. - M1 (v0.1): One full Door-only night playable start→summary; a stranger can understand it with no explanation; fail states (Vibe 0, Aggro 100) both reachable.
- M2 (v0.2): Full night with ≥2 forced Floor interludes; toilet game verifiably on-beat (log beat timestamps vs hit timestamps in tests).
- M3 (v0.3): 3-night run with persistence; an incident-report lie can bite you a night later.