117 lines
6.8 KiB
Markdown
117 lines
6.8 KiB
Markdown
# NOT TONIGHT — Build Plan & Technical Architecture
|
||
|
||
*Read [GAME_DESIGN.md](GAME_DESIGN.md) first. This doc is the engineering plan the
|
||
lanes execute. Contract details live in [CONTRACTS.md](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 (ONE lane, sequential)
|
||
Night flow state machine (Door ⇄ Floor interleave, radio pulls, Last Drinks,
|
||
Summary), real audio engine replaces stubs, save/progression, Kayden-at-door
|
||
simulation while player is on Floor. Playtest pass: one full night start→summary.
|
||
|
||
### Phase 3 — Content & polish (parallelizable again)
|
||
Archetypes, scripted moral encounters, inspector, incident report memory, regulars,
|
||
venues 2–4, real pixel art swapped into the paper-doll layer slots, MODELBEAST-
|
||
assisted art generation if useful.
|
||
|
||
### 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)
|
||
|
||
1. **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`.
|
||
2. **Handover:** every work session APPENDS a session block to `LANEHANDOVER.md`
|
||
(template inside it) and pushes. This is how the reviewer (Fable) sees state.
|
||
3. **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.
|
||
4. **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.
|
||
5. **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 dev` shows 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.
|