3.6 KiB
3.6 KiB
NOT TONIGHT — instructions for Claude sessions in this repo
Papers, Please-style bouncer sim. Browser game: Phaser 3 + TypeScript (strict) + Vite + Vitest. You are probably an Opus 4.8 lane executor — this repo is built by parallel "lanes" coordinated through files, reviewed by Fable.
Before writing any code
- Read
LANEHANDOVER.md— find the latest REVIEW block and any block for your lane. Review instructions override lane files. - Read your lane file in
lanes/(John/Fable will tell you which lane you are; if not stated, ask — do not guess). - Skim
docs/GAME_DESIGN.md,docs/BUILD_PLAN.md, and readdocs/CONTRACTS.mdfully. Contracts are law.
Hard rules
- Work ONLY on your lane branch (
lane/<name>), only in your owned directories (BUILD_PLAN.md §2) + your tests + LANEHANDOVER.md. Never merge or push main. - Parallel lanes on one machine: use a git worktree
(
git worktree add ../not-tonight-<lane> lane/<lane>), don't switch branches in a shared checkout. - Don't modify
docs/CONTRACTS.md,src/core/, orsrc/data/types.tsafter Phase 0 — file a CONTRACT CHANGE REQUEST in the handover instead, stub locally with// TODO(contract):, keep working. - No
Math.random()— SeededRNG streams only. No cross-lane scene imports. Game logic in pure tested functions (src/rules/, per-lane logic modules); scenes stay thin. - End EVERY session:
npm run lint && npm run build && npm testclean, append a SESSION block toLANEHANDOVER.md(template in that file), commit, push your branch. An unpushed session didn't happen. - Remote is Gitea:
ssh://git@100.71.119.27:222/monster/not-tonight.git.
Dev notes (Phase 2 landed 2026-07-19)
- The game boots into the NIGHT (Thu→Fri→Sat run, saved). Controls: click the rope/verdicts at the door; click the venue doorway to step inside; on the floor WASD + E (E at the entry exits back to the door). While you're inside, Kayden works the door — badly, on purpose.
- Dev routes: N night · P parade · F floor demo · J juice demo (+ same-named
URL hashes).
localStorage.removeItem('not-tonight-save')for a clean run. - Audio unlocks on first click (TechnoEngine + location filter). Before that a
StubBeatClock keeps
beat:tickhonest.
Dev notes (Phase 0, still true)
- Gate:
npm run lint && npm run build && npm test— all three must pass before any push. Dev server:npm run dev(port 5199, config in.claude/launch.json). - Key APIs (read the source, it's short):
core/EventBus(onreturns an unsubscribe fn),core/SeededRNG(rng.stream(name)— NEVERMath.random, eslint blocks it),core/GameClock(feed real ms viaupdate(delta)from your scene;ageOn(dob, nightDate)is the ID math),core/meters(emitmeters:delta, never mutate NightState),patrons/generator(generatePatron(ctx, clockMin, override?)),patrons/dollPlan(pure, testable) +patrons/doll(renderDoll(scene, patron, pose)→ texture key),rules/drunk(drunkStage).StubBeatClockneeds an owning scene callingupdate(delta)each frame. - Verifying in Claude's browser preview pane: the pane tab reports
document.hidden = true, so Chrome suspends rAF and the Phaser loop freezes at frame 0. Drive frames manually via the exposed debug handle:const b = performance.now(); for (let i = 1; i <= 900; i++) window.game.loop.step(b + i * 16.67)then screenshot/inspect. In a normal browser the game runs fine.
Tone guard
The game is Aussie hospitality satire — affectionate, funny, with a moral undertow (design doc §4.3). If content you're writing reads as mean-spirited rather than absurd, soften toward absurd.