101 lines
5.9 KiB
Markdown
101 lines
5.9 KiB
Markdown
# LANE-FLOOR — The Floor (Phase 1, parallel)
|
||
|
||
**Executor:** Opus 4.8. **Branch:** `lane/floor` (from main after Phase 0 merge).
|
||
**Owns:** `src/scenes/floor/` + its tests. **Prereq reading:** `docs/GAME_DESIGN.md`
|
||
§3.2 → `docs/CONTRACTS.md` → `LANEHANDOVER.md` (check for REVIEW blocks for you).
|
||
|
||
## Deliverable
|
||
|
||
`FloorDemoScene` runnable via `npm run dev` (menu key F): a populated top-down
|
||
venue you patrol with a flashlight, containing live instances of all three v0.2
|
||
infractions (cut-off, toilet stall, pat-down) + UV stamp checks. Runs standalone —
|
||
it self-populates from the patron generator; integration (Phase 2) will hand it the
|
||
real admitted-patron list instead. Code against `Patron[]` input from day one.
|
||
|
||
## Phase-0 reality (read before coding)
|
||
Phase 0 landed 2026-07-19 — see CLAUDE.md "Dev notes" for the API map and the
|
||
browser-pane verification trick. Floor-relevant specifics:
|
||
- Drunk thresholds exist in `rules/drunk.ts` (`drunkStage`, `hasVisibleTells`) —
|
||
no local copy needed; delete that TODO from your plan.
|
||
- `renderDoll(scene, patron, 'floorTopDown')` already produces the 16×16
|
||
top-down doll (hair blob over shoulders/top colour).
|
||
- `StubBeatClock` exists in core; instantiate it in your demo scene and call
|
||
`update(delta)` each frame — it emits `beat:tick` at 128 BPM.
|
||
- `generatePatron` + `ParadeScene`'s `resetRun` lifecycle are the reference
|
||
patterns for self-populating your demo.
|
||
- Register your demo scene in `src/main.ts`'s scene list; launch order stays
|
||
Boot → Parade. Menu keys (F for floor demo) can live in ParadeScene as a
|
||
scene-switch keybind — that one-line touch outside your dirs is pre-approved.
|
||
|
||
## Scene: the venue (top-down, ~2× screen scrollable)
|
||
|
||
Tilemap (hand-authored array is fine, no Tiled dependency): entry corridor, bar
|
||
(along a wall, stools), dance floor (centre), booths, toilets (2 stalls each,
|
||
door tiles), smoking-area door. **Darkness is the aesthetic:** black base with neon
|
||
accent strips; use Phaser Light2D (`setPipeline('Light2D')`) — ambient very low,
|
||
neon point lights, and the player's cone.
|
||
|
||
### 1. Player & flashlight
|
||
WASD/arrows patrol, slightly heavy acceleration (you're a big unit). Flashlight
|
||
cone in facing direction — a masked light + a cone polygon that REVEALS detail:
|
||
outside the cone patrons render as dim silhouettes (tint), inside it their full
|
||
doll colours + tell animations show. TAB toggles **UV mode**: cone goes purple,
|
||
normal detail hidden, `uvStamped` hands glow green. No stamp glow on a patron who
|
||
re-entered = infraction (march them doorward: walk-behind escort, below).
|
||
|
||
### 2. Crowd sim (`floor/CrowdSim.ts`)
|
||
Patrons wander between anchor points (bar → dance floor → booth → toilet loop)
|
||
with per-archetype weights. Dance-floor patrons bob **on `beat:tick`** (StubBeatClock
|
||
until integration — never your own timer). Intoxication drifts up over clock time
|
||
(bar visits accelerate it); drunk-stage thresholds from `rules/` if LANE-DOOR has
|
||
landed them, else local `// TODO(contract)` copy. Visible drunk tells escalate:
|
||
sway amplitude, stumble pathing, bumping others (small vibe leaks via
|
||
`meters:delta` if un-handled).
|
||
|
||
### 3. Infraction: The Cut-Off
|
||
Approach a `messy`+ patron, interact (E) → dialogue tree modal: three escalation
|
||
lines ("Have some water, mate" → "You're done for the night" → firm escort).
|
||
Right escalation level for their stage = clean ejection (+vibe, defeated-slouch
|
||
walk you escort to the exit); too aggressive on a merely `loose` patron = scene
|
||
(−vibe, +aggro); too soft on a `maggot` = they stagger free, try again. Emit
|
||
`floor:infractionSpotted` / `floor:ejection` per contract. Leaving a `maggot`
|
||
unhandled for >N clock-min queues a deferred heat risk (v0.1: log to
|
||
`NightState.incidents`; inspector wiring is Phase 3).
|
||
|
||
### 4. Infraction: Toilet stalls (the rhythm game)
|
||
Stall doors show feet beneath: TWO pairs under one door = infraction. Interact →
|
||
close-up view of the door + a beat bar fed by **`beat:tick` events only** (do not
|
||
infer beat from elapsed time; measure hit accuracy vs the last tick's
|
||
`audioTimeMs`). Bang (SPACE) on-beat 3× consecutively: door flies open, two
|
||
patrons scatter in opposite directions with comic speed (+vibe, big). Off-beat
|
||
bangs: muffled "piss off mate" from inside, reset combo, small aggro. TEST: hit
|
||
windows off recorded tick timestamps (pure function, unit test —
|
||
`judgeBang(bangTimeMs, lastTick): 'perfect'|'ok'|'miss'`).
|
||
|
||
### 5. Infraction: Pat-down (contraband)
|
||
Suspicious idle (pocket-pat animation, driven by `flags.contraband`). Interact →
|
||
pat-down overlay: patron outline with 5–6 pocket zones; timed 10s; click zones to
|
||
reveal items, drag each to the **AMNESTY BIN** on the right. Items from
|
||
`data/contraband.ts` with silly sprites (placeholder: labelled coloured rects —
|
||
the budgie flaps). Missed items walk with them (deferred vibe leak). Contraband
|
||
found = +vibe, patron stays (confiscation, not ejection) unless it's severity 3.
|
||
|
||
### 6. Escort-out (shared mechanic)
|
||
Ejections attach the patron to walk-in-front-of-you pathing to the exit; they play
|
||
the defeated slouch. While escorting you can't interact — travel time is the cost
|
||
of every ejection (this is the floor's core resource: your position).
|
||
|
||
## Constraints
|
||
- Input: `Patron[]` + EventBus + clock. No imports from `scenes/door/` or `audio/`.
|
||
- All scoring via `meters:delta`; incidents appended via NightState API from core.
|
||
- Keep every judgement rule (bang windows, escalation matrix, pat-down scoring) in
|
||
pure functions with tests — scene code stays thin.
|
||
- Performance: 40+ patrons with Light2D at 60fps; profile before optimizing, but
|
||
silhouette-tint rendering outside the cone should be cheap (no per-frame texture work).
|
||
|
||
## Definition of done
|
||
Demo scene: all three minigames + UV check playable and readable in the dark
|
||
aesthetic; `lint`/`build`/`test` clean; pure-logic tests for bang timing,
|
||
escalation matrix, pat-down scoring; SESSION block appended to LANEHANDOVER.md;
|
||
branch pushed.
|