not-tonight/lanes/LANE_FLOOR.md
type-two 5086a325d8 Design docs, build plan, contracts, and lane instructions for NOT TONIGHT
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 15:48:44 +10:00

4.9 KiB
Raw Blame History

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.mdLANEHANDOVER.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.

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 56 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.