Compare commits
No commits in common. "main" and "lane/door" have entirely different histories.
@ -1,15 +1,6 @@
|
|||||||
{
|
{
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"configurations": [
|
"configurations": [
|
||||||
{
|
{ "name": "not-tonight", "runtimeExecutable": "npm", "runtimeArgs": ["run", "dev"], "port": 5199 }
|
||||||
"name": "not-tonight",
|
|
||||||
"runtimeExecutable": "npm",
|
|
||||||
"runtimeArgs": [
|
|
||||||
"run",
|
|
||||||
"dev"
|
|
||||||
],
|
|
||||||
"port": 5199,
|
|
||||||
"autoPort": true
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
6
.gitignore
vendored
@ -1,6 +1,2 @@
|
|||||||
node_modules
|
node_modules/
|
||||||
dist/
|
dist/
|
||||||
art_incoming/
|
|
||||||
public/props/manifest.lock
|
|
||||||
__pycache__/
|
|
||||||
*.pyc
|
|
||||||
|
|||||||
51
CLAUDE.md
@ -29,46 +29,7 @@ by parallel "lanes" coordinated through files, reviewed by Fable.
|
|||||||
branch. An unpushed session didn't happen.
|
branch. An unpushed session didn't happen.
|
||||||
- Remote is Gitea: `ssh://git@100.71.119.27:222/monster/not-tonight.git`.
|
- Remote is Gitea: `ssh://git@100.71.119.27:222/monster/not-tonight.git`.
|
||||||
|
|
||||||
## Dev notes (venue expansion landed 2026-07-28)
|
## Dev notes (Phase 0 landed 2026-07-19)
|
||||||
- **The ladder's four venues now have four different rooms** (`docs/VENUES.md`).
|
|
||||||
Layouts live in `src/scenes/floor/layouts/` (`theRoyal`, `elevate`, `room`);
|
|
||||||
**Voltage stays in `venueMap.ts`** so the others can import primitives from it
|
|
||||||
without an import cycle. A night picks its room from `NightContext.venue.id`.
|
|
||||||
- Nothing about a room may be a module singleton any more. Props, lights, posts,
|
|
||||||
probes and the tile palette all hang off `FloorLayout`. `venueMap.VENUE/PROPS/
|
|
||||||
LIGHTS` still exist and are still Voltage's — they are the reference room, not
|
|
||||||
"the venue".
|
|
||||||
- **Dev route `#floor:<venueId>`** boots the floor demo straight into one room
|
|
||||||
(`#floor:room`, `#floor:theRoyal`, `#floor:elevate`). Plain `#floor`/F = Voltage.
|
|
||||||
- `tests/floor/layoutInvariants.ts` is the executable rulebook every layout runs:
|
|
||||||
perimeter, reachability, anchors on walkable tiles, posts not sealed, probes
|
|
||||||
reachable, props on-grid. Add a room, add it to `LAYOUTS`, it gets checked.
|
|
||||||
- Asset generation is `tools/gen/` — `assets.py` is the manifest (one entry per
|
|
||||||
sprite), `run_batch.py` walks it, resumable, `--workers N`. **Cloudflare Workers
|
|
||||||
AI first** (10k free neurons/day, resets 00:00 UTC), falling back to MODELBEAST
|
|
||||||
`flux_local` automatically when the day's allocation is spent. Meshes use the
|
|
||||||
**512 tier + vertex baker** (`mb.FAST_MESH`): ~90s vs ~6min, and the difference
|
|
||||||
does not survive the downscale to 32px. Heartbeat: `~/.jobs/not-tonight-assets.json`.
|
|
||||||
- `props_import.py` takes its sizes FROM `tools/gen/assets.py`, so sizes cannot
|
|
||||||
drift between the farm and the game. It locks `manifest.json` — parallel imports
|
|
||||||
used to lose entries to a read-modify-write race, which shows up as a prop that
|
|
||||||
is on disk but renders as a placeholder. `tools/gen/rebuild_manifest.py` repairs.
|
|
||||||
|
|
||||||
## 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) · M toggles the MIX DESK overlay anywhere (ear-pass rig).
|
|
||||||
`localStorage.removeItem('not-tonight-save')` for a clean run.
|
|
||||||
- Audio unlocks on first click (TechnoEngine + location filter). Before that a
|
|
||||||
StubBeatClock keeps `beat:tick` honest.
|
|
||||||
- Venue spaces/props/lights are DATA (`venueMap.PROPS`/`LIGHTS`, plan in
|
|
||||||
docs/SPACES.md). Generated art drops into `public/props/` via
|
|
||||||
`tools/props_import.py` + manifest — placeholders render until then.
|
|
||||||
|
|
||||||
## Dev notes (Phase 0, still true)
|
|
||||||
- Gate: `npm run lint && npm run build && npm test` — all three must pass before
|
- 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`).
|
any push. Dev server: `npm run dev` (port 5199, config in `.claude/launch.json`).
|
||||||
- Key APIs (read the source, it's short): `core/EventBus` (`on` returns an
|
- Key APIs (read the source, it's short): `core/EventBus` (`on` returns an
|
||||||
@ -90,13 +51,3 @@ by parallel "lanes" coordinated through files, reviewed by Fable.
|
|||||||
The game is Aussie hospitality satire — affectionate, funny, with a moral undertow
|
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
|
(design doc §4.3). If content you're writing reads as mean-spirited rather than
|
||||||
absurd, soften toward absurd.
|
absurd, soften toward absurd.
|
||||||
|
|
||||||
## Deploy (live since 2026-07-19)
|
|
||||||
- Live at **https://monsterrobot.games/not-tonight/** (botchat VPS, forum-nginx
|
|
||||||
bind mount — host path `/home/humanjing/monsterrobot.games/games/not-tonight/`,
|
|
||||||
`/not-tonight` is a symlink to it; landing tile in `../index.html`).
|
|
||||||
- Ship: `npm run build && rsync -az --delete dist/ humanjing@100.71.119.27:/home/humanjing/monsterrobot.games/games/not-tonight/`
|
|
||||||
then cache-busted curl to verify. Hashed asset names make CF cache a non-issue;
|
|
||||||
index.html is text/html (uncached by CF default).
|
|
||||||
- Cover art: `covers/nottonight.jpg` + `_riso.jpg` (MODELBEAST flux_local seed
|
|
||||||
4208 + PIL stamp text/riso pass — recipe in LANEHANDOVER Phase-3 deploy note).
|
|
||||||
|
|||||||
2009
LANEHANDOVER.md
@ -1 +0,0 @@
|
|||||||
raw drops go here; process with tools/props_import.py
|
|
||||||
|
Before Width: | Height: | Size: 132 KiB |
|
Before Width: | Height: | Size: 106 KiB |
|
Before Width: | Height: | Size: 202 KiB |
|
Before Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 92 KiB |
|
Before Width: | Height: | Size: 363 KiB |
|
Before Width: | Height: | Size: 225 KiB |
|
Before Width: | Height: | Size: 180 KiB |
|
Before Width: | Height: | Size: 116 KiB |
|
Before Width: | Height: | Size: 141 KiB |
|
Before Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 823 KiB |
|
Before Width: | Height: | Size: 337 KiB |
|
Before Width: | Height: | Size: 562 KiB |
|
Before Width: | Height: | Size: 152 KiB |
|
Before Width: | Height: | Size: 169 KiB |
|
Before Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 944 KiB |
|
Before Width: | Height: | Size: 71 KiB |
|
Before Width: | Height: | Size: 46 KiB |
@ -26,42 +26,16 @@ nike_air_max, moschino, quiksilver, kmart, disruptor_ii…), dynamically loaded
|
|||||||
sprites before committing — pixelated photo-sprites can look mushy; may need a
|
sprites before committing — pixelated photo-sprites can look mushy; may need a
|
||||||
cleanup pass or MODELBEAST-assisted redraw per sprite.
|
cleanup pass or MODELBEAST-assisted redraw per sprite.
|
||||||
|
|
||||||
### 2. RIGROOM — the character × animation factory (surveyed 2026-07-19)
|
### 2. Drunk/idle/dance animation references
|
||||||
**This supersedes the old "animation references" note. The fleet has a full
|
`ultra:~/Documents/90sDJsim/web/world/models/` — 22 ped GLBs + **9 anim clip GLBs
|
||||||
character/animation pipeline, live and organised:**
|
incl. `walk_drunk`, idle, sit** (from the shared `character_kit` rig). Plus
|
||||||
- **RIGROOM library** (`ultra:~/meshgod-backups/library`, 2.4 GB): **607
|
`ultra:~/Documents/MOTIONLIB/` — 2,703 motion/anim FBX.
|
||||||
animation FBX** in themed packs + 59 character files. Web UI live at
|
- Option A (cheap): use `walk_drunk` etc. as *visual reference* for hand-animating
|
||||||
`http://100.91.239.7:8010/rigroom` (characters × animations pairing, three.js
|
the pixel sway/stumble frames.
|
||||||
preview, instant Mixamo-ready FBX download). CLI:
|
- Option B (pipeline): pre-render `character_kit` characters + MOTIONLIB clips to
|
||||||
`MESHGOD/scripts/rigroom.py classify|sort|scan`.
|
top-down sprite-sheet rotations for the Floor scene (Blender orthographic cam →
|
||||||
- Clips that read like THIS game's shot list: `Searching_Pockets` (pat-down),
|
pixelate). Heavier, but gives unlimited consistent NPC animation. Decide at v0.4;
|
||||||
`Standing_Arguing` + a full boxing/knockout pack (floor fights),
|
the doll contract's `floorTopDown` pose doesn't care which path wins.
|
||||||
`Shaking_Head_No` (the deny), `Inspecting`/`Looking_Around` (ID check),
|
|
||||||
`Leaning_Idle02_Smoking` (smoking area), dozens of idles/sits, dance packs,
|
|
||||||
`Brutal To Happy Walking`, zombie stagger (maggot walk), 12 DJ motions.
|
|
||||||
Raw source: `m3ultra:~/Documents/Rokoko_Free_Mocap_FBX_263` (606 FBX).
|
|
||||||
- **Modular character kit** (`m3ultra:~/Documents/character_kit_modular`,
|
|
||||||
canonical `ultra:~/Documents/character_kit/modular/`): GODVERSE socket
|
|
||||||
standard — head/hands/feet/torso swap on one shared 65-bone `mixamorig:`
|
|
||||||
skeleton, 40 embedded actions, every library clip retargets for free.
|
|
||||||
- **repose** (`m3ultra:~/Documents/repose`): photo → T-pose views (SD1.5 +
|
|
||||||
ControlNet, all-local) → MeshGod multi-view → autorig. A face becomes a
|
|
||||||
rigged character without leaving the tailnet.
|
|
||||||
- **For NOT TONIGHT (v0.4 art pass), the pre-render path is now fully paved:**
|
|
||||||
modular kit character + RIGROOM clip → Blender orthographic top-down/front →
|
|
||||||
pixelate → sprite sheets behind the existing `renderDoll` poses. The outfit
|
|
||||||
variety could even come from kit part swaps. Same pipeline, one venue's
|
|
||||||
worth of NPC animation for free. Decide at v0.4; contracts don't move.
|
|
||||||
- Also present, unsurveyed depth: `MOCAPGOD` (empty queue — service scaffold),
|
|
||||||
`mixamo_upload` staging, `MOTIONLIB` (2,703 FBX, ultra) still the deep pool.
|
|
||||||
|
|
||||||
### 2b. procity (m3ultra) — the 90s-Aussie town sim
|
|
||||||
Walkable procedural shopping town (three.js, no build step), built by lanes
|
|
||||||
like ours. Pipeline: 186 GLB/FBX with fit/normalize/decimate tooling
|
|
||||||
(`procity_fit_*` props: arcade cabinet, clothes racks, shelving), 21 peds.
|
|
||||||
The **prop pipeline conventions** (batch manifests, decimation results JSON)
|
|
||||||
are the pattern to copy if NOT TONIGHT ever goes 3D-prop-assisted; the venue
|
|
||||||
furniture (bar, booths, stools) could come straight from its fit pipeline.
|
|
||||||
|
|
||||||
### 3. Venue / street reference art
|
### 3. Venue / street reference art
|
||||||
- `ultra:~/Documents/90sDJsim/web/world/media/` named scene/venue art — 100 wired
|
- `ultra:~/Documents/90sDJsim/web/world/media/` named scene/venue art — 100 wired
|
||||||
|
|||||||
@ -68,20 +68,15 @@ scene code. Beat sync example: audio engine emits `beat:tick` on the bus; the to
|
|||||||
rhythm game consumes `beat:tick`; until integration, LANE-FLOOR uses the
|
rhythm game consumes `beat:tick`; until integration, LANE-FLOOR uses the
|
||||||
`StubBeatClock` from core (same event, fixed 128 BPM).
|
`StubBeatClock` from core (same event, fixed 128 BPM).
|
||||||
|
|
||||||
### Phase 2 — Integration — ✅ DONE 2026-07-19 (executed by Fable)
|
### Phase 2 — Integration (ONE lane, sequential)
|
||||||
Night flow machine: Door and Floor run concurrently all night, player toggles
|
Night flow state machine (Door ⇄ Floor interleave, radio pulls, Last Drinks,
|
||||||
via the doorway / floor exit; Kayden rules the real queue while you're inside
|
Summary), real audio engine replaces stubs, save/progression, Kayden-at-door
|
||||||
(80% admit, 1-in-7 unstamped); TechnoEngine + location filter + SFX live in the
|
simulation while player is on Floor. Playtest pass: one full night start→summary.
|
||||||
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)
|
### Phase 3 — Content & polish (parallelizable again)
|
||||||
`lanes/LANE_CONTENT.md` (guest list, moral encounters, inspector, incident
|
Archetypes, scripted moral encounters, inspector, incident report memory, regulars,
|
||||||
report), `lanes/LANE_FLOOR2.md` (fights, smoking area, aggro decay),
|
venues 2–4, real pixel art swapped into the paper-doll layer slots, MODELBEAST-
|
||||||
`lanes/LANE_JUICE2.md` (ear pass, ambience, night arc). Later in this phase:
|
assisted art generation if useful.
|
||||||
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)
|
### Phase 4 — The role ladder (design §6; future, do not start)
|
||||||
Glassie, bartender, DJ roles + roster board. Not scoped yet — but it imposes ONE
|
Glassie, bartender, DJ roles + roster board. Not scoped yet — but it imposes ONE
|
||||||
|
|||||||
@ -120,18 +120,9 @@ export interface EventMap {
|
|||||||
'meters:delta': { vibe?: number; aggro?: number; hype?: number };
|
'meters:delta': { vibe?: number; aggro?: number; hype?: number };
|
||||||
'meters:changed': { vibe: number; aggro: number; hype: number };
|
'meters:changed': { vibe: number; aggro: number; hype: number };
|
||||||
'heat:strike': HeatStrike;
|
'heat:strike': HeatStrike;
|
||||||
// folded in at the Phase-1 review (2026-07-19):
|
|
||||||
'incident:log': IncidentRecord; // single writer: core/meters.ts appends to NightState.incidents
|
|
||||||
'door:phoneTheatre': { durationMs: number };
|
|
||||||
'audio:unlocked': { atMs: number };
|
|
||||||
'beat:bar': { barIndex: number; beatIndex: number; audioTimeMs: number };
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Phase-1 review also added: `PatronFlags.handHolding?` (CCR-1),
|
|
||||||
`VerdictOutcome.hypeDelta?` (CCR-2), `DressCodeRule.short?` (CCR-4).
|
|
||||||
`src/data/types.ts` remains the source of truth where this doc lags.
|
|
||||||
|
|
||||||
**Bus discipline:** scenes emit `meters:delta`; only `core/meters.ts` mutates state
|
**Bus discipline:** scenes emit `meters:delta`; only `core/meters.ts` mutates state
|
||||||
and emits `meters:changed`. HUD listens to `meters:changed` only. This keeps three
|
and emits `meters:changed`. HUD listens to `meters:changed` only. This keeps three
|
||||||
lanes from fighting over the same numbers.
|
lanes from fighting over the same numbers.
|
||||||
|
|||||||
@ -1,91 +0,0 @@
|
|||||||
# NOT TONIGHT — Character, Scenario & Interaction Backlog
|
|
||||||
|
|
||||||
*The idea shelf. Everything here obeys §4.3: choices cost something real, the
|
|
||||||
game never grades them, and the humane option is never secretly optimal.
|
|
||||||
Status: ✅ implemented · 🔜 next nibbles · 💡 backlog.*
|
|
||||||
|
|
||||||
## Interactions & mini-systems
|
|
||||||
|
|
||||||
- ✅ **The joint bust** (smoking yard). E on a smoker who smells herbal → three
|
|
||||||
verbs, none of them clean: **BIN IT** (by the book — write-up in the truth
|
|
||||||
log, smoker's night dampened), **POCKET IT** (the game's first corruption
|
|
||||||
verb — nothing happens now; maybe a Dazza sting later; and it sits in the
|
|
||||||
incident log waiting for the report form, where your account of it can be a
|
|
||||||
lie the audit remembers), **DIDN'T SEE IT** (the yard relaxes, vibe drifts
|
|
||||||
up… and it's still on the record as ignored). 'joint' is real contraband, so
|
|
||||||
it also turns up in pat-downs at the rope.
|
|
||||||
- ✅ **The glassie run** (the glassie role's fantasy, previewed as a floor
|
|
||||||
task). A wire rack of glasses appears at the bar's east end; carry it the
|
|
||||||
length of the venue to the kitchen dishwasher. Crowd bumps and sharp turns
|
|
||||||
build WOBBLE; wobble breaks glasses one smash at a time. Deliver what
|
|
||||||
survives for vibe. Racks keep coming. The door is unattended while you do it
|
|
||||||
— Kayden is thrilled.
|
|
||||||
- ✅ **ID passback detection** (2026-07-20): the same card twice in one night — the name on
|
|
||||||
the guest-list clipboard you already checked; second appearance of an
|
|
||||||
identical card = passback. Needs a "cards seen tonight" memory at the desk.
|
|
||||||
- ✅ **Regular step-up lines** (2026-07-20) keyed off timesDeniedBefore ("back again. new
|
|
||||||
moustache. no hard feelings").
|
|
||||||
- ✅ **Smoking-door slip-in** (2026-07-20) (FLOOR2 §2's second noStamp source).
|
|
||||||
- ✅ **The 1:30 lockout** (2026-07-20) (deeply Queensland): after 1:30 AM, admissions are
|
|
||||||
ILLEGAL. The queue still forms; Dazza still wants bodies; every post-lockout
|
|
||||||
admit is a guaranteed strike risk vs a rioting line. A whole late-game phase
|
|
||||||
in one law.
|
|
||||||
- ✅ **Vomit protocol** (2026-07-20): someone redecorates the dance floor → deploy the wet
|
|
||||||
floor sign (we own the prop) → slips if you dawdle; the glassie mop loop.
|
|
||||||
- ✅ **Phone confiscation** (2026-07-20): someone filming on the dance floor — the
|
|
||||||
influencer's revenge arc.
|
|
||||||
- ✅ **Water station duty** (2026-07-20) (RSA): press a cup on a `loose` patron; done right
|
|
||||||
it de-escalates the ripen timer. The humane tool that costs time.
|
|
||||||
- ✅ **First aid** (2026-07-20): a fainter. Recovery position via a QTE that is deliberately
|
|
||||||
NOT funny; the room hushes; the night resumes changed.
|
|
||||||
- ✅ **Kebab run** (2026-07-20): Dazza demands a kebab mid-slam. The shop is right there.
|
|
||||||
The queue can see you. The whole game in one errand.
|
|
||||||
|
|
||||||
## Characters (door archetypes & scripted people)
|
|
||||||
|
|
||||||
- ✅ **The off-duty cop** (2026-07-20) — flashes a badge at the rope. Real cop (deny freely,
|
|
||||||
he respects it; admit and he quietly reports the venue's breaches — a
|
|
||||||
walking inspector) or a $30 costume badge (the tells: hat, confidence,
|
|
||||||
wrong lanyard). The ID game's scariest bluff.
|
|
||||||
- ✅ **The celebrity incognito** (2026-07-20) — cap + sunnies (two live rule breaches!).
|
|
||||||
Deny: nothing happens, ever, and Dazza never finds out who. Admit: vibe
|
|
||||||
rocket OR pap swarm outside (aggro storm). You cannot know which.
|
|
||||||
- ✅ **The twins** (2026-07-20) — two people, one face, different names. Not a fake:
|
|
||||||
genuinely twins. Everything about the photo check is suddenly on trial.
|
|
||||||
- ✅ **The sovereign citizen** (2026-07-20) — "I don't recognise your dress code as having
|
|
||||||
authority over my person." Aggro engine in a polo. His ID is a laminated
|
|
||||||
business card.
|
|
||||||
- ✅ **The delivery rider** (2026-07-20) — insists the DJ ordered food. The DJ did not
|
|
||||||
order food. OR DID HE. (The booth lamp flickers hungrily.)
|
|
||||||
- ✅ **The promoter** (2026-07-20) — arrives with a roll of wristbands and 'his' guest list
|
|
||||||
that doesn't match yours. Two clipboards enter, one leaves.
|
|
||||||
- ✅ **The noise-complaint neighbour** (2026-07-20) — pyjamas, at the rope, at 1 AM, not
|
|
||||||
trying to get in: trying to get it turned DOWN. The only patron who wants
|
|
||||||
less club. Handle him badly and the inspector hears about it.
|
|
||||||
- ✅ **The hen's party, lost** (2026-07-20) — seven matching sashes, wrong venue, right
|
|
||||||
energy. Admitting them is a vibe grenade with a random timer.
|
|
||||||
- ✅ **The ex-doorman** (2026-07-20) — watches you work a patron, then tells you what you
|
|
||||||
missed (a live tutorial character; his tips are right ~80% of the time,
|
|
||||||
which is the joke).
|
|
||||||
|
|
||||||
## Systems worth a whole phase
|
|
||||||
|
|
||||||
- ✅ **Venue 4 / ROOM boss week** (2026-07-21, first cut): fourth rung on the
|
|
||||||
ladder (promotes from Elevate). No Dazza rule chronology — the board IS the
|
|
||||||
law and re-randomises every 15 in-game minutes (3 rules per window, seeded,
|
|
||||||
with a toast on the turn); every rope line renders as bracketed lip-read
|
|
||||||
guesses (`[FIST? LIST?]`) because the techno ate the dialogue. 60 licensed,
|
|
||||||
1.2 arrival scale, inspector working, crowd of heads and VIP-claimers.
|
|
||||||
- ✅ **The DJ shift** (2026-07-20, first cut): E at the booth hands you the decks
|
|
||||||
while the resident steps out. B pulls the bass (the room leans in); SPACE
|
|
||||||
drops, judged against the LIVE bar line (clean/late/clang — early and late
|
|
||||||
are the same offence); requests arrive at the booth glass with per-request
|
|
||||||
odds ("got any dnb", nan's song, the DUN DUN one) and three answers that all
|
|
||||||
cost something. A build held too long runs out of stairs. Movement locks
|
|
||||||
while you hold them; the floor and the door keep happening without you.
|
|
||||||
- ✅ **Bartender shift** (2026-07-21, first cut): E at the till hands you the
|
|
||||||
taps (movement locks; the floor keeps happening). Orders arrive as choices —
|
|
||||||
the order line degrades with the patron's stage (the spelling IS the sobriety
|
|
||||||
test) — SERVE / WATER / CUT OFF all legal, all priced. Serving messy/maggot
|
|
||||||
is the RSA breach: the vibe pays up front, and 35% of the time somebody with
|
|
||||||
a lanyard saw it (ONE deferred write-up per night, deduped by reason).
|
|
||||||
162
docs/SPACES.md
@ -1,162 +0,0 @@
|
|||||||
# NOT TONIGHT — Spaces Plan
|
|
||||||
|
|
||||||
*How the game's two spaces grow from readable-but-abstract into places, using the
|
|
||||||
fleet's asset factories. Written 2026-07-20. Code contract: everything lands
|
|
||||||
behind data tables (`venueMap.PROPS` / `LIGHTS`) and a sprite drop-in convention —
|
|
||||||
generated art replaces placeholders with zero code changes.*
|
|
||||||
|
|
||||||
> **Superseded in part, 2026-07-28 — see [VENUES.md](VENUES.md).** This document
|
|
||||||
> describes ONE venue floor, which is what the game had when it was written. The
|
|
||||||
> venue ladder now has four distinct rooms, and props/lights/posts/probes hang
|
|
||||||
> off a per-venue `FloorLayout` rather than the module singletons named below.
|
|
||||||
> The pipeline sections (§4 sprite drop-in, and the settled prop pipeline at the
|
|
||||||
> foot of this file) are still exactly right and still the house rules — only
|
|
||||||
> "the venue floor" in §2 is now specifically *Voltage's* floor.
|
|
||||||
|
|
||||||
## 1. Design principles
|
|
||||||
|
|
||||||
1. **Darkness stays the mechanic.** Props read as silhouettes in ambient dark and
|
|
||||||
resolve under the torch. Nothing may make the room bright enough to scan from
|
|
||||||
the doorway.
|
|
||||||
2. **Navigate by light signature.** Each zone owns a colour of light, so the
|
|
||||||
player orients by glow before geometry: bar = warm amber · dance floor =
|
|
||||||
pulsing pink (on the actual beat) · DJ booth = deep blue · toilets =
|
|
||||||
flickering green fluoro · smoking yard = cool rain-blue spill · entry/exit =
|
|
||||||
venue pink. The torch is white; UV is purple. No other light sources.
|
|
||||||
3. **Props are data.** `PropDef { kind, tile pos, footprint, emissive? }` — the
|
|
||||||
renderer prefers a generated texture (`gen:prop:<kind>`) and falls back to a
|
|
||||||
procedural placeholder, so the game is complete TONIGHT and gets prettier as
|
|
||||||
art lands.
|
|
||||||
4. **Spaces anticipate the role ladder** (design §6): the bar interior is laid
|
|
||||||
out for a future bartender shift, the DJ booth for the DJ shift, the glassie
|
|
||||||
station and smoking yard for floor loops that already have lanes speccing them.
|
|
||||||
|
|
||||||
## 2. The venue floor (80×45 tiles, one room + pockets)
|
|
||||||
|
|
||||||
```
|
|
||||||
┌──────────────────────────────────────────────────────────────────┐
|
|
||||||
│ N ═ BAR ══════════ back-shelf glow ┌─ DUNNIES ────────┐│
|
|
||||||
│ taps · till · glasses │ s1 s2 s3 s4 ││
|
|
||||||
│ ○○○○○○ stools │ sinks + mirror ││
|
|
||||||
│ └───door───────────┘│
|
|
||||||
│ W │
|
|
||||||
│ ┈entry┈ ┌ DANCE FLOOR (pulsing grid) ┐ ╔═ DJ BOOTH ╗ booths│
|
|
||||||
│ corridor │ speaker · · · · · speaker │ ║ decks+mixer║ E│
|
|
||||||
│ posters │ · · · disco ball · · · │ ║ (sealed) ║ booths│
|
|
||||||
│ cloak │ speaker · · · · · speaker │ ╚════════════╝ │
|
|
||||||
│ glassie └───────────────────────────┘ booths│
|
|
||||||
│ station │
|
|
||||||
│ ▓ SMOKING YARD (open sky, rain) ▓ tables+candles S │
|
|
||||||
└────────▓ fence · butt bin ▓──────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
Zone-by-zone (tile coords in `venueMap.ts`):
|
|
||||||
|
|
||||||
| Zone | What's there (props) | Light signature | Future role hook |
|
|
||||||
|---|---|---|---|
|
|
||||||
| **Bar** (north run) | back-bar shelf (emissive), 3 beer taps, till, glass stacks | steady amber pools along the shelf | Bartender shift: the serving lane between bar tiles and shelf is already unwalkable-to-patrons |
|
|
||||||
| **Dance floor** (centre) | 4 corner speaker stacks, disco ball (centre), floor grid cells | pink grid cells pulse ON `beat:tick`; ball throws a slow-rotating glint | DJ role reads crowd here |
|
|
||||||
| **DJ booth** (east of dance, sealed box facing the floor) | 2 decks + mixer (from the 90sDJsim gear GLBs!), booth monitor, lamp | deep blue wash + VU flicker | The DJ shift's playable pocket |
|
|
||||||
| **Booths** (south + east walls) | table per booth pair, candle | tiny warm candle pools | — |
|
|
||||||
| **Dunnies** (NE walled room) | sink row + mirror on west wall, hand dryer | green fluoro, FLICKERS (torch almost redundant inside — deliberate) | — |
|
|
||||||
| **Smoking yard** (SW walled pocket, open sky) | butt bin, milk crate seats, fence | cool blue outdoor spill + rain particles INSIDE the yard | FLOOR2's smoking loop (specced) |
|
|
||||||
| **Entry corridor** (west) | poster wall (3 art slots — MODELBEAST posters!), cloakroom window, stamp podium | venue-pink spill from the door | UV re-entry checks happen here |
|
|
||||||
| **Glassie station** (bar's west end alcove) | glass racks, tub trolley | dim amber | Glassie role's home base |
|
|
||||||
|
|
||||||
Sim impact: walkability only changes where NEW walls go (DJ booth box, yard
|
|
||||||
fence, sink row). All existing anchors keep working; reachability is asserted in
|
|
||||||
tests. The yard gets a `smoke` anchor upgrade so wanderers actually go out for one.
|
|
||||||
|
|
||||||
## 3. The door street (640×360 tableau)
|
|
||||||
|
|
||||||
Already reads well. Two upgrades, both drop-in images (no layout change):
|
|
||||||
1. **Backdrop plate** behind the existing rects: one wide pixel-art street wall
|
|
||||||
(brick, posters, grime) — swaps in as `gen:street:backdrop` when generated.
|
|
||||||
2. **Kebab shop interior glow card** in its window + rotating poster art in two
|
|
||||||
street frames (same poster slots as the entry corridor).
|
|
||||||
|
|
||||||
## 4. The sprite drop-in contract (how John's art lands)
|
|
||||||
|
|
||||||
- Drop processed PNGs in **`public/props/`** named `<kind>.png` and list them in
|
|
||||||
**`public/props/manifest.json`** (`{"props": ["deck", "speaker", ...]}`).
|
|
||||||
- The floor loads the manifest at boot; anything listed replaces its placeholder
|
|
||||||
(texture key `gen:prop:<kind>`). Missing = placeholder. No code changes.
|
|
||||||
- **`tools/props_import.py`** (PIL, runs anywhere with python3+PIL — ultra has it)
|
|
||||||
takes raw generated images → target pixel size + palette quantise + transparent
|
|
||||||
background → writes `public/props/` + updates the manifest:
|
|
||||||
`python3 tools/props_import.py incoming/deck_raw.png deck`
|
|
||||||
- Target sizes are in the script (`TARGETS`): hero props 48–64 px, furniture
|
|
||||||
24–32 px, small items 16 px. It refuses unknown kinds so typos can't ship.
|
|
||||||
|
|
||||||
## 5. GENERATION QUEUE — John's list (in priority order)
|
|
||||||
|
|
||||||
Pipelines: **[MB]** = MODELBEAST `flux_local` (params given) → drop raw output in
|
|
||||||
`art_incoming/`, run the import script (or hand me the raws — either works).
|
|
||||||
**[GLB]** = Blender ortho prerender of an existing fleet mesh (camera: orthographic,
|
|
||||||
top-down 90° for floor props / front 0° for the street, transparent film, ~512px,
|
|
||||||
neutral even lighting) → same import path.
|
|
||||||
|
|
||||||
| # | Item (kind) | Pipeline & source | Notes |
|
|
||||||
|---|---|---|---|
|
|
||||||
| 1 | `deck` | [GLB] `ultra:~/Documents/90sDJsim/web/world/models/gear/deck_t3_technics_sl_1200mk2.glb`, top-down | The hero. One render serves both booth decks |
|
|
||||||
| 2 | `mixer` | [GLB] same dir, `mixer.glb` (or the urei once landed), top-down | Sits between the decks |
|
|
||||||
| 3 | `speaker` | [GLB] 90sDJsim `models/props/` has boombox/speaker meshes; else [MB] prompt: "top-down view of a large black PA speaker stack, pixel art game sprite, dark background, viewed directly from above" 512×512 seed 4210 | 4 placements |
|
|
||||||
| 4 | `discoball` | [MB] "mirrored disco ball seen directly from above, glinting, pixel art sprite, black background" 512×512 seed 4211 | Centre of dance floor |
|
|
||||||
| 5 | `barShelf` | [MB] "top-down bar back-shelf with glowing bottles rows, amber light, pixel art sprite, dark" 1024×256 seed 4212 | Emissive — the amber source |
|
|
||||||
| 6 | `taps` | [MB] "row of three beer taps on a bar counter viewed from above, pixel art, dark bg" 256×256 seed 4213 | |
|
|
||||||
| 7 | `boothTable` | [MB] "small round pub table with two drinks seen from directly above, pixel art, dark bg" 256×256 seed 4214 | 6 placements |
|
|
||||||
| 8 | `sink` | [MB] "public bathroom sink row with mirror viewed from above, green fluorescent light, pixel art, dark" 512×256 seed 4215 | |
|
|
||||||
| 9 | `buttBin` + `crate` | [MB] one sheet: "outdoor smoking area props: cigarette butt bin and milk crate, top-down pixel art, dark bg" 512×256 seed 4216 | Yard dressing |
|
|
||||||
| 10 | `poster1..3` | [MB] three runs: "grimy nightclub gig poster, 90s Australian pub rock / techno rave / missing cat, pixel art, portrait" 256×384 seeds 4217-19 | FRONT view (posters hang on walls) — used at door + corridor |
|
|
||||||
| 11 | `street:backdrop` | [MB] "wide pixel art night street wall: dark brick, torn posters, graffiti, neon reflections, rain, front-on orthographic, game background" 1600×440 seed 4220 | The door scene plate. Biggest single visual win |
|
|
||||||
| 12 | `cloak` / `glassRack` | [MB] "cloakroom window with hanging jackets / metal glass rack with stacked pint glasses, top-down pixel art, dark" 256×256 seeds 4221-22 | Corridor + glassie station |
|
|
||||||
| 13 | `arcade` | [GLB] `m3ultra:~/Documents/procity/pipeline/_normalized/procity_fit_arcade_cabinet_01.glb`, top-down | Corner easter egg near entry |
|
|
||||||
|
|
||||||
**Ambition tier (later, not blocking):** pre-rendered patron sprite sheets from
|
|
||||||
the modular character kit + RIGROOM clips (`Searching_Pockets`, boxing pack,
|
|
||||||
`Leaning_Idle02_Smoking`, zombie stagger for maggots) — replaces the procedural
|
|
||||||
dolls entirely per docs/ASSETS.md §2. Wants its own session to set the
|
|
||||||
palette/density once.
|
|
||||||
|
|
||||||
*(flux params for all [MB] jobs: `model flux2-klein-4b, steps 4`; put "no text,
|
|
||||||
no lettering" in every prompt EXCEPT the posters, where mangled text reads as
|
|
||||||
authentic gig-poster grot.)*
|
|
||||||
|
|
||||||
|
|
||||||
## Prop pipeline — settled 2026-07-22 (A/B'd, not guessed)
|
|
||||||
|
|
||||||
Two routes, both free and unlimited on MODELBEAST. Pick by object, not by habit.
|
|
||||||
|
|
||||||
**[MB] flux direct** — `flux_local` → `tools/props_import.py`. Fast (~9s).
|
|
||||||
Use for FLAT things: posters, decals, graffiti, signage, floor markings.
|
|
||||||
|
|
||||||
**[GLB] TRELLIS → Blender** — `flux_local` (product shot) → `trellis2_mlx`
|
|
||||||
(`asset_id` is a TOP-LEVEL job field, NOT inside `params`) →
|
|
||||||
`tools/glb_to_sprite.py <mesh.glb> <kind>` → sprite + manifest, headless, no
|
|
||||||
GUI. Use for objects with real VOLUME: tables, fridges, machines, furniture.
|
|
||||||
|
|
||||||
Why the split, from the A/B (same pool table, both routes): flux picks its own
|
|
||||||
camera every generation — the same prompt style gave a perfectly top-down
|
|
||||||
urinal and a front-on fridge in one batch, and mismatched camera angles never
|
|
||||||
read as one room. The mesh route renders every prop from one fixed ortho
|
|
||||||
camera, and TRELLIS carries detail flux flattens: worn felt, real pockets,
|
|
||||||
rails and legs, clean alpha.
|
|
||||||
|
|
||||||
**RAKE by object HEIGHT — and I had this backwards first time.**
|
|
||||||
Low and wide (pool table, booth table, crate): **60°**. Tall (arcade, fridge,
|
|
||||||
speaker, anything standing): **~76°**. The instinct to *lower* the rake for tall
|
|
||||||
objects "so you see more face" is wrong — a tall object already shows nothing
|
|
||||||
but face; it needs to be steeper to read as a floor prop at all. A speaker at
|
|
||||||
55° is a featureless black slab.
|
|
||||||
|
|
||||||
**Judge sprites at SHIP size, not render size.** A 512px render of a fridge from
|
|
||||||
above looks ambiguous; the same sprite at 32x32 under the game's own point light
|
|
||||||
reads fine, because the venue's LIGHTS do half the identifying work (the fridges
|
|
||||||
carry a cyan glow, the arcade a flickering blue). Do not re-roll a prop off the
|
|
||||||
back of the big preview.
|
|
||||||
|
|
||||||
**The old guidance, kept because it is still true for low objects:** The venue's props are
|
|
||||||
three-quarter top-down, not straight down. Re-rolled from directly overhead, a
|
|
||||||
bar fridge is a grey rectangle — physically correct and visually dead, because
|
|
||||||
the glowing bottles that say "fridge" are on its front. 60° keeps the top
|
|
||||||
surface dominant while leaving enough face to identify the object at 32px.
|
|
||||||
150
docs/VENUES.md
@ -1,150 +0,0 @@
|
|||||||
# NOT TONIGHT — the four venues
|
|
||||||
|
|
||||||
*Written 2026-07-28. The venue ladder in `src/data/venues.ts` has always been
|
|
||||||
four venues; up to now they shared ONE floor map and differed only by difficulty
|
|
||||||
knobs. This document is the design contract for giving each its own room.*
|
|
||||||
|
|
||||||
## 0. Why bother
|
|
||||||
|
|
||||||
Design §6 sells the ladder as *promotion* — survive a week, get a better door.
|
|
||||||
But a promotion you cannot see is a number, not a reward. Walking into Elevate
|
|
||||||
and finding The Royal's carpet under your feet undoes the fiction the whole run
|
|
||||||
is built on. Each venue now has its own bar layout, its own dunnies, its own
|
|
||||||
smoking area and its own DJ booth, because those four things are exactly what a
|
|
||||||
bouncer actually learns about a room.
|
|
||||||
|
|
||||||
## 1. Shared contract (all four)
|
|
||||||
|
|
||||||
- **Grid is fixed at 80×45 tiles.** Venues differ by ARRANGEMENT, not extent —
|
|
||||||
the camera, minimap and bounds maths all key off `MAP_W`/`MAP_H`, and a
|
|
||||||
per-venue grid size would be a refactor with no visible payoff. A small venue
|
|
||||||
reads small by walling its unused grid to `void`, not by shrinking the array.
|
|
||||||
- **Every layout exports a `FloorLayout`**: `{ id, map, props, lights, posts,
|
|
||||||
probes }`. Nothing else may be a module singleton — that was the old shape and
|
|
||||||
it is what made four venues impossible.
|
|
||||||
- **Every layout must satisfy the same invariants** (`tests/floor/layouts.test.ts`):
|
|
||||||
1. every `AnchorKind` has ≥1 anchor, and every anchor is walkable;
|
|
||||||
2. all walkable tiles are mutually reachable (flood fill), except sealed
|
|
||||||
cubicle interiors, which must be reachable from their `StallDef.door`;
|
|
||||||
3. every `POSTS` entry is walkable and has a walkable neighbour (a post on a
|
|
||||||
sealed tile freezes the player for the night — this has shipped twice);
|
|
||||||
4. every `PROBES` entry has a walkable tile within reach;
|
|
||||||
5. no prop hangs off the grid.
|
|
||||||
- **Materials are grain, the palette is hue.** `FloorLayout.materials` names a
|
|
||||||
generated plate per tile kind (`tex_carpet`, `tex_concrete`, …) and the baker
|
|
||||||
stamps it **tinted to the palette colour**. That is deliberate: an untinted
|
|
||||||
photo-real plate blows straight past the brightness band everything else was
|
|
||||||
tuned in, and the room stops being dark. Plates are 16×16 — the game's tile —
|
|
||||||
because at that size "carpet" is structured noise, which is also what pub
|
|
||||||
carpet looks like from head height. No plate named, or art not landed: flat
|
|
||||||
palette colour, exactly as before.
|
|
||||||
- **The baked floor is keyed per venue** (`floor:tiles:<id>`). Textures outlive a
|
|
||||||
scene, so a single global key meant the first venue you played baked the floor
|
|
||||||
for every venue after it — you would survive a week at The Royal, get promoted,
|
|
||||||
and walk into Voltage still standing on the pub's carpet. It only shows on
|
|
||||||
promotion, which is precisely when the ladder is supposed to pay off.
|
|
||||||
- **Light signatures survive** (SPACES.md §1): bar = amber, dance = pulsing
|
|
||||||
pink on the real beat, DJ = deep blue, toilets = flickering green, smoking =
|
|
||||||
cool blue, entry = venue pink. A venue may add ONE signature colour of its
|
|
||||||
own — Elevate's skyline gold, ROOM's sodium orange — and no more, or the
|
|
||||||
navigate-by-glow rule stops working.
|
|
||||||
- **Darkness stays the mechanic.** No venue may be bright enough to scan from
|
|
||||||
the doorway.
|
|
||||||
|
|
||||||
## 2. The Royal — "a dive with a dance floor"
|
|
||||||
|
|
||||||
Licensed 80 · regulars and punters · nobody checks anything.
|
|
||||||
|
|
||||||
A suburban Australian pub that had a dance floor bolted on in about 2004 and has
|
|
||||||
not redecorated since. Patterned carpet, a horseshoe public bar, and the dance
|
|
||||||
floor is plainly the least important thing in the building.
|
|
||||||
|
|
||||||
| Space | What's in it |
|
|
||||||
|---|---|
|
|
||||||
| **Public bar** (horseshoe, west) | the long counter, taps, till, keg stack, a TV showing the footy, bar fridges |
|
|
||||||
| **Pool room** (north-west) | two pool tables, cue rack, a dartboard on the wall |
|
|
||||||
| **TAB / pokies corner** (north-east) | bank of poker machines, TAB screens, stools, its own miserable light |
|
|
||||||
| **Bistro** (centre-north) | bistro tables, bain-marie counter, the meat-raffle drum |
|
|
||||||
| **Dance floor** (south-east) | small, an afterthought, one mirror ball, a jukebox on the wall |
|
|
||||||
| **DJ corner** | not a booth — a folding table with a controller, beside the dance floor |
|
|
||||||
| **Dunnies** (east) | a stainless TROUGH, two cubicles (one out of order), one basin |
|
|
||||||
| **Beer garden** (south, open sky) | picnic tables, umbrellas, patio heater, butt bin — the smoking area, and the nicest room in the pub |
|
|
||||||
|
|
||||||
Light: warm amber everywhere, green cone over each pool table, the pokies' own
|
|
||||||
sickly blue, and the beer garden cool blue. No pink except the dance corner.
|
|
||||||
|
|
||||||
## 3. Voltage — "valley institution"
|
|
||||||
|
|
||||||
Licensed 110 · the tuning baseline · the inspector drinks here.
|
|
||||||
|
|
||||||
**This is the existing map and it does not change.** It is tuned under the
|
|
||||||
darkness sheet, its reachability is asserted, and every existing floor test
|
|
||||||
targets it. It stays the default layout and the reference for the other three.
|
|
||||||
|
|
||||||
## 4. Elevate — "rooftop, small room, big opinions"
|
|
||||||
|
|
||||||
Licensed 70 · influencers and owner's mates · every second person is a VIP.
|
|
||||||
|
|
||||||
The whole venue is outdoors, which makes the rain a design element rather than a
|
|
||||||
yard-only effect. Small footprint — a third of the grid is sky. You arrive by
|
|
||||||
lift, not off the street, so the entry is a lobby.
|
|
||||||
|
|
||||||
| Space | What's in it |
|
|
||||||
|---|---|
|
|
||||||
| **Lift lobby** (west) | lift doors, a rope line, the stamp podium, one mirror |
|
|
||||||
| **Cocktail bar** (north) | short backlit bar, no taps — bottles and a champagne bucket |
|
|
||||||
| **VIP booths** (east) | banquettes behind velvet rope posts, low tables |
|
|
||||||
| **Dance floor** (centre, small) | it is a terrace with a dance floor, not a club |
|
|
||||||
| **DJ plinth** | raised, open, no booth walls — the DJ is on display |
|
|
||||||
| **Toilets** (north-east) | two unisex cubicles, marble basin, enormous mirror |
|
|
||||||
| **Terrace edge** (south + east) | glass balustrade, planters, the city skyline beyond |
|
|
||||||
| **Smoking** | the whole roof is open air; a designated corner with a standing ash urn and heat lamps |
|
|
||||||
|
|
||||||
Light: warm amber bar, cool blue-white terrace, deep blue DJ, and the venue's
|
|
||||||
own signature — **skyline gold** spilling from the city card beyond the glass.
|
|
||||||
|
|
||||||
## 5. ROOM — "no sign, no socials"
|
|
||||||
|
|
||||||
Licensed 60 · heads and chancers · the board is the law.
|
|
||||||
|
|
||||||
A concrete warehouse. No branding anywhere, because branding is how you get
|
|
||||||
found. The sound system is the most expensive thing in the building by an order
|
|
||||||
of magnitude and everything else is borrowed.
|
|
||||||
|
|
||||||
| Space | What's in it |
|
|
||||||
|---|---|
|
|
||||||
| **Main floor** | concrete pillars, no booths, the crowd is the furniture |
|
|
||||||
| **The stacks** | Funktion-One-style speaker towers + subs — huge, four corners |
|
|
||||||
| **DJ booth** | low, central, facing the floor, no barrier — CDJs not turntables |
|
|
||||||
| **Bar** (west) | a plywood plank on scaffolding, cans only, no taps, no till |
|
|
||||||
| **Toilets** (north-east) | industrial, graffiti on every surface, three cubicles of which one works, a cracked basin, no mirror |
|
|
||||||
| **Loading dock** (south, open sky) | roller door, pallets, a wheelie bin — this is the smoking area |
|
|
||||||
| **Chill-out** (north-west) | two ruined couches under a single bulb |
|
|
||||||
| **The board** | the rule board that rewrites itself (`shuffleDressCode`) — a physical prop by the entry |
|
|
||||||
|
|
||||||
Light: almost none. Sodium orange over the loading dock (ROOM's signature),
|
|
||||||
one flickering green fluoro in the dunnies, strobes on the floor, and the
|
|
||||||
stacks' own power LEDs. This is the darkest venue in the game on purpose.
|
|
||||||
|
|
||||||
## 6. Prop vocabulary added for these rooms
|
|
||||||
|
|
||||||
Route per SPACES.md §"Prop pipeline": **[F]** = flux direct (flat things —
|
|
||||||
signage, boards, screens, backdrops); **[M]** = product shot → TRELLIS.2 →
|
|
||||||
Blender ortho render (things with volume). Rake follows the house rule —
|
|
||||||
**60° low and wide, ~76° tall**.
|
|
||||||
|
|
||||||
| Venue | Kinds |
|
|
||||||
|---|---|
|
|
||||||
| The Royal | `pokie`[M76] `tabBoard`[F] `bistroTable`[M60] `picnicTable`[M60] `trough`[M70] `keg`[M76] `dartboard`[F] `jukebox`[M76] `raffleDrum`[M60] `bainMarie`[M60] `tvSport`[F] `beerUmbrella`[M80] `ashtray`[M60] |
|
|
||||||
| Elevate | `cocktailBar`[M60] `banquette`[M60] `ropePost`[M76] `planter`[M60] `balustrade`[M76] `djPlinth`[M60] `marbleSink`[M70] `ashUrn`[M76] `champBucket`[M60] `loungeChair`[M60] `liftDoor`[F] `skylineCard`[F] |
|
|
||||||
| ROOM | `stackF1`[M76] `subBass`[M60] `plywoodBar`[M60] `rollerDoor`[F] `pallet`[M60] `wheelieBin`[M76] `oldCouch`[M60] `pillar`[M76] `ruleBoard`[F] `strobe`[M76] `smokeMachine`[M60] `cableSnake`[M60] `brokenBasin`[M70] `canStack`[M60] `cdj`[M60] |
|
|
||||||
| Staff (set dressing, all venues) | `staffBartender` `staffDj` `staffGlassie` `staffSecurity` — all [M76] |
|
|
||||||
|
|
||||||
Staff figures are PROPS, not patrons. The procedural dolls stay exactly as they
|
|
||||||
are: `dollPlan` draws the specific items the dress code convicts on, so
|
|
||||||
replacing patrons with pre-rendered art would make the convictions invisible
|
|
||||||
(recorded in LANEHANDOVER, FABLE-SOLO-23). A bartender who never moves is set
|
|
||||||
dressing and carries no mechanical weight, which is why she can be a sprite.
|
|
||||||
|
|
||||||
Street plates (door scene, one per venue, [F], 640×176):
|
|
||||||
`street:royal` `street:elevate` `street:room` — `street:backdrop` stays Voltage's.
|
|
||||||
@ -1,74 +0,0 @@
|
|||||||
# LANE-CONTENT — Door depth & the moral layer (Phase 3, parallel)
|
|
||||||
|
|
||||||
**Executor:** Opus 4.8. **Branch:** `lane/content` (from main after Phase 2).
|
|
||||||
**Owns:** `src/scenes/door/`, `src/rules/`, `src/data/strings/` (door-related
|
|
||||||
files), tests. **Prereq reading:** CLAUDE.md → `docs/GAME_DESIGN.md` §3.1/§4 →
|
|
||||||
the Phase-2 REVIEW block in `LANEHANDOVER.md`.
|
|
||||||
|
|
||||||
## Phase-2 reality (read before coding)
|
|
||||||
- The night is now a real flow: `NightScene` owns clock/meters/audio/save and a
|
|
||||||
`NightContext` (see its interface — `sfx`, `requestLocation`, `beatIntervalMs`
|
|
||||||
are new since Phase 1). Door and Floor run concurrently ALL night; the player
|
|
||||||
toggles via the doorway ("step inside") and the floor's entry exit.
|
|
||||||
- While the player is on the floor, **Kayden rules the real queue** in
|
|
||||||
`DoorScene.kaydenRule()` (admit 80%, same `judge()`, no UV stamp 1-in-7 —
|
|
||||||
stamp accuracy is decided in `NightScene.onVerdict`).
|
|
||||||
- Heat is run-scoped and saved; 3rd strike ends the night AND the run
|
|
||||||
immediately (`endReason: 'licence'`). Nights chain Thu→Fri→Sat via
|
|
||||||
`NightSummaryScene.nextAction()`; `save.ts` carries `GameState`.
|
|
||||||
- `ui/Stamp` + sfx are live in the deny path; `data/strings/door.ts` has
|
|
||||||
`FAIL_TEXT.licence`.
|
|
||||||
|
|
||||||
## Deliverables (in priority order)
|
|
||||||
|
|
||||||
### 1. The Guest List clipboard (design §3.1 — specced, never built)
|
|
||||||
A desk clipboard panel: tonight's list (generated, 8–14 names, some misspelled
|
|
||||||
versions of real patron names). Patrons with `claimsGuestList` get a "'m on the
|
|
||||||
list" line when they step up; player cross-checks. `knowsOwner` patrons who are
|
|
||||||
DENIED trigger the existing furious-Dazza path (judge already scores this —
|
|
||||||
surface it: their step-up line should drop hints ("Terry said swing by"), and
|
|
||||||
`data/strings/dazza.ts` has the `owner-scare` text to foreshadow).
|
|
||||||
Misspelling rule: a name that ALMOST matches is usually legit (bad handwriting);
|
|
||||||
an exact-match name on a confident patron is sometimes a lift. Tells, not
|
|
||||||
certainty. Pure logic in `rules/guestList.ts` + tests.
|
|
||||||
|
|
||||||
### 2. Scripted moral encounters (design §4.3 — the heart)
|
|
||||||
2–3 scripted patrons injected per night by the generator override hook
|
|
||||||
(`generatePatron(ctx, clockMin, archetypeOverride)` + a new scripted-encounter
|
|
||||||
scheduler in `rules/` or `data/`): the girl who needs back in to grab her mate
|
|
||||||
(no stamp, over capacity), the freshly-dumped regular who just wants one quiet
|
|
||||||
beer (already `loose`). Multi-beat dialogue via the existing toast/dialogue
|
|
||||||
patterns. Doing the human thing costs Vibe or risks Heat; the game never says
|
|
||||||
which choice was right. NO achievement chimes, no morality meter — the design
|
|
||||||
doc is explicit that this stays unscored.
|
|
||||||
|
|
||||||
### 3. The Inspector (archetype exists, does nothing yet)
|
|
||||||
Activate `inspector`: reads as a boring `punter` at the rope (their doll is
|
|
||||||
deliberately unremarkable). If admitted, they observe for ~30 clock-min:
|
|
||||||
any live breach in that window (capacity over licensed, a `maggot` on the floor,
|
|
||||||
underage inside) converts its deferred strike to IMMEDIATE. Then they leave and
|
|
||||||
Dazza texts "that was the INSPECTOR you muppet". If denied — nothing happens,
|
|
||||||
ever (they were just a quiet person; paranoia is the tax). Pure logic
|
|
||||||
`rules/inspector.ts` + tests; wiring via bus events only.
|
|
||||||
|
|
||||||
### 4. The Incident Report (design §3.3 — lying groundwork)
|
|
||||||
On the Night Summary: a short form (3–4 incidents sampled from
|
|
||||||
`NightState.incidents`) where the player picks a written account per incident —
|
|
||||||
truthful or flattering. Store both truth and account in
|
|
||||||
`GameState.pastReports`. Cross-night audit (contradictions → strikes) is
|
|
||||||
Phase 4; THIS lane only builds the form + storage + one taste: a lie about a
|
|
||||||
`kayden` incident can be contradicted by Kayden's own log line next morning
|
|
||||||
(Dazza text). Keep the form fast — 20 seconds, not homework.
|
|
||||||
|
|
||||||
### 5. Sobriety line-walk (stretch)
|
|
||||||
The third challenge: cursor-follow line at the desk. Only if 1–4 land clean.
|
|
||||||
|
|
||||||
## Constraints
|
|
||||||
- All scoring through `judge()`/`meters:delta`/`heat:strike` — no new direct
|
|
||||||
meter paths. New events need a CONTRACT CHANGE REQUEST (declaration-merge
|
|
||||||
bridges are BANNED now — request and wait for the fold).
|
|
||||||
- Kayden must interact sanely with everything you add (e.g. he auto-admits
|
|
||||||
guest-list liars — that's fine and funny; make sure it can't crash).
|
|
||||||
- Every pure module tested; play a full 3-night run before your handover and
|
|
||||||
report what the run FELT like — the economy findings from Phase 1 are still
|
|
||||||
open and your content changes the mix.
|
|
||||||
@ -1,62 +0,0 @@
|
|||||||
# LANE-FLOOR2 — Floor completion & aggro physiology (Phase 3, parallel)
|
|
||||||
|
|
||||||
**Executor:** Opus 4.8. **Branch:** `lane/floor2` (from main after Phase 2).
|
|
||||||
**Owns:** `src/scenes/floor/`, `src/data/strings/floor.ts`, tests. **Prereq
|
|
||||||
reading:** CLAUDE.md → `docs/GAME_DESIGN.md` §3.2 → Phase-2 REVIEW block in
|
|
||||||
`LANEHANDOVER.md`.
|
|
||||||
|
|
||||||
## Phase-2 reality (read before coding)
|
|
||||||
- `FloorDemoScene` now runs in TWO modes: standalone `'FloorDemo'` (key F,
|
|
||||||
unchanged) and night mode `'Floor'` (launched by NightScene with a
|
|
||||||
`NightContext`; see `bindNight()`). Night mode: shared bus/clock/state, fed by
|
|
||||||
real door admissions (`door:verdict` → delayed `crowd.spawn`), `MeterHud` for
|
|
||||||
HUD, exit via E at the entry anchor, sim keeps running while the player is at
|
|
||||||
the door (`present === false` path in `update()`).
|
|
||||||
- Incidents flow through `incident:log` (single writer in core/meters).
|
|
||||||
- `NightContext.sfx` exists (SFX handle, always crisp past the location filter).
|
|
||||||
- Kayden's unstamped admits (1 in 7) are your `noStamp` supply in night mode.
|
|
||||||
|
|
||||||
## Deliverables (in priority order)
|
|
||||||
|
|
||||||
### 1. Fight brewing (design §3.2 — the last missing v0.2 infraction)
|
|
||||||
Two agents in escalating shove animation (crowd sim picks pairs with rising
|
|
||||||
aggro contribution when they collide repeatedly). A swing timer (~8s from first
|
|
||||||
shove): player must physically walk BETWEEN them before it ends. Interposed =
|
|
||||||
defused (+vibe, both marked handled); missed = fight (big −vibe, +aggro, both
|
|
||||||
auto-ejected, `incident:log` kind `fight`, and if the inspector is inside —
|
|
||||||
LANE-CONTENT's problem — it's a heat risk). Pure pair-selection + timer logic
|
|
||||||
in `floor/fights.ts`, tested. While the player is at the door, fights still
|
|
||||||
happen (that's radio-pull pressure — emit a `radio:call` urgency 3 via the
|
|
||||||
night's existing pattern: log the incident, NightScene already radios on
|
|
||||||
`maggotUnhandled`; add `fight` to that trigger via CONTRACT CHANGE REQUEST or
|
|
||||||
ask the reviewer to widen the trigger — one-line, will be approved).
|
|
||||||
|
|
||||||
### 2. Smoking area & pass-outs (closes the UV loop from the door side)
|
|
||||||
The smoking-area door becomes live: patrons drift out for a smoke (activity
|
|
||||||
'smoking' exists) and BACK IN through the entry. Re-entering smokers keep their
|
|
||||||
stamp — but a small % of NEW patrons try to slip in through the smoking door
|
|
||||||
(no stamp, never saw the front door). That's the noStamp mechanic getting a
|
|
||||||
source that isn't only Kayden. Numbers small (2–3 a night), tells readable
|
|
||||||
(they enter from the wrong door if you're watching).
|
|
||||||
|
|
||||||
### 3. Aggro physiology (FLOOR-2 CCR, deferred at Phase-1 review — now approved)
|
|
||||||
Implement slow aggro decay on a calm floor: when no unhandled infraction exists
|
|
||||||
and no fight is brewing, drift aggro down ~0.3/clock-min (numbers yours to
|
|
||||||
tune, state the final value in the handover). Implementation note: this is a
|
|
||||||
sim-level `meters:delta` emit from the floor's update, gated on `present`
|
|
||||||
being EITHER value (a calm floor calms the night whether you're watching it or
|
|
||||||
not). Add tests for the gating logic.
|
|
||||||
|
|
||||||
### 4. Night-mode polish
|
|
||||||
- Stall bangs and pat-down bin drops should hit `NightContext.sfx`
|
|
||||||
(`doorBang`, plus pick something for the bin thunk) — overlays take an
|
|
||||||
optional sfx handle via their constructors.
|
|
||||||
- Escorted patrons should exit via the ENTRY in night mode (they're being
|
|
||||||
walked out the front, past the queue — future door-side schadenfreude hook).
|
|
||||||
- Perf check at 44 agents + fights + smokers in night mode; report frame times.
|
|
||||||
|
|
||||||
## Constraints
|
|
||||||
- Demo mode must stay working and identical-feeling (it's the tuning harness).
|
|
||||||
- No imports from `scenes/door/`; the night talks to you via bus + context.
|
|
||||||
- Pure logic tested; verify each mechanic by playing BOTH modes; handover per
|
|
||||||
protocol.
|
|
||||||
@ -1,59 +0,0 @@
|
|||||||
# LANE-JUICE2 — The night has a sound (Phase 3, parallel)
|
|
||||||
|
|
||||||
**Executor:** Opus 4.8. **Branch:** `lane/juice2` (from main after Phase 2).
|
|
||||||
**Owns:** `src/audio/`, `src/ui/`, tests. **Prereq reading:** CLAUDE.md →
|
|
||||||
LANE_JUICE.md (your Phase-1 spec) → Phase-2 REVIEW block in `LANEHANDOVER.md`.
|
|
||||||
|
|
||||||
## Phase-2 reality (read before coding)
|
|
||||||
- `TechnoEngine` + `Sfx` now live inside the actual night (`NightScene` creates
|
|
||||||
them; unlock on first pointerdown; `StubBeatClock` hands over on
|
|
||||||
`audio:unlocked`). The location filter sweeps on every doorway/exit toggle.
|
|
||||||
- `audio:unlocked.atMs` now carries the ANCHORED beat-0 origin (your open
|
|
||||||
question, ruled and implemented).
|
|
||||||
- `MeterHud` has `initialHeat` (ruled: read run-scoped strikes at construction —
|
|
||||||
wired in the floor's night mode).
|
|
||||||
- `ui/Stamp` is the door's stamp, with `stampSlam`/`stampInk` wired. The decal
|
|
||||||
is destroyed ~900ms post-slam by DoorScene.
|
|
||||||
- Your `ui/juiceEvents.ts` was deleted at review — its events live in
|
|
||||||
`data/types.ts` now. Extensions go via CONTRACT CHANGE REQUEST only.
|
|
||||||
|
|
||||||
## Deliverables (in priority order)
|
|
||||||
|
|
||||||
### 1. Ear pass with John (the debt from Phase 1: "verified by ear: NOTHING")
|
|
||||||
Sit a human in front of the JuiceDemo AND a real night. Tune: does the kick
|
|
||||||
read as a kick, is the bassline musical, `typeTick` level (it fires per
|
|
||||||
character), stamp slam vs music balance, the door→floor sweep (does it feel
|
|
||||||
like a door opening). Document every constant you change and why. This is THE
|
|
||||||
deliverable — everything below is secondary.
|
|
||||||
|
|
||||||
### 2. Ambience layer
|
|
||||||
- `rainLoop` at the door (start/stop on `audio:location` — rain is outside).
|
|
||||||
- A crowd-murmur bed INSIDE (filtered noise, level follows
|
|
||||||
`NightState.capacity.inside` — read via a bus listener on `meters:changed`?
|
|
||||||
No — capacity isn't in that payload; request what you need or derive from
|
|
||||||
`door:clicker`/`door:verdict` counting. State your approach in the handover).
|
|
||||||
- The kebab-shop fluoro hum if you're feeling artistic (tiny, dry, mono).
|
|
||||||
|
|
||||||
### 3. The night has an arc
|
|
||||||
Track intensity should rise across the night: thin kick+hat at 9 PM, bassline
|
|
||||||
enters ~10, pads and full mix by midnight, strip back at Last Drinks. Drive it
|
|
||||||
from `clock:tick` (you know the clock minute). Keep every parameter externally
|
|
||||||
settable — this surface IS the future DJ role's control panel (BUILD_PLAN
|
|
||||||
Phase 4 rule).
|
|
||||||
|
|
||||||
### 4. Widget debts
|
|
||||||
- `Phone` thread: scroll instead of truncating the newest over-tall message.
|
|
||||||
- `DialogueBox` drunk-typo mode: wire into the floor cut-off overlay (it
|
|
||||||
currently renders plain text — coordinate via handover, LANE-FLOOR2 owns the
|
|
||||||
call site; you own the widget).
|
|
||||||
- Optional: `MeterHud` variant sized for the door's top bar, so DoorScene can
|
|
||||||
drop its bespoke `MeterBar`s (currently duplicated look). Only if clean —
|
|
||||||
the door HUD works and this is cosmetic unification, not a rescue.
|
|
||||||
|
|
||||||
## Constraints
|
|
||||||
- Location filter architecture is non-negotiable: music through the lowpass,
|
|
||||||
SFX and ambience around it (rain is OUTSIDE — it belongs on the sfx bus but
|
|
||||||
only audible at the door; that's a routing decision, justify yours).
|
|
||||||
- No imports from door/floor scenes. Bus + constructor config only.
|
|
||||||
- Pure-testable math tested; everything else honestly listed as ear-checked or
|
|
||||||
not, per your own Phase-1 standard.
|
|
||||||
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 609 B |
|
Before Width: | Height: | Size: 608 B |
|
Before Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 878 B |
|
Before Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 628 B |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 457 B |
|
Before Width: | Height: | Size: 417 B |
|
Before Width: | Height: | Size: 424 B |
|
Before Width: | Height: | Size: 781 B |
|
Before Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 571 B |
|
Before Width: | Height: | Size: 981 B |
|
Before Width: | Height: | Size: 611 B |
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 524 B |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 670 B |
|
Before Width: | Height: | Size: 691 B |
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 746 B |
|
Before Width: | Height: | Size: 379 B |
|
Before Width: | Height: | Size: 438 B |
|
Before Width: | Height: | Size: 592 B |
|
Before Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 832 B |
|
Before Width: | Height: | Size: 396 B |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 424 B |
|
Before Width: | Height: | Size: 523 B |
|
Before Width: | Height: | Size: 478 B |
|
Before Width: | Height: | Size: 930 B |
|
Before Width: | Height: | Size: 796 B |
|
Before Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 853 B |
|
Before Width: | Height: | Size: 425 B |
|
Before Width: | Height: | Size: 223 B |
|
Before Width: | Height: | Size: 699 B |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 668 B |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 611 B |
@ -1,131 +0,0 @@
|
|||||||
{
|
|
||||||
"props": [
|
|
||||||
"arcade",
|
|
||||||
"ashUrn",
|
|
||||||
"ashtray",
|
|
||||||
"bainMarie",
|
|
||||||
"balustrade",
|
|
||||||
"banquette",
|
|
||||||
"barFridge",
|
|
||||||
"barShelf",
|
|
||||||
"barrier",
|
|
||||||
"beerUmbrella",
|
|
||||||
"binRound",
|
|
||||||
"bistroTable",
|
|
||||||
"boothLamp",
|
|
||||||
"boothTable",
|
|
||||||
"brokenBasin",
|
|
||||||
"buttBin",
|
|
||||||
"cableSnake",
|
|
||||||
"canStack",
|
|
||||||
"carpet",
|
|
||||||
"cctv",
|
|
||||||
"cdj",
|
|
||||||
"ceilingFan",
|
|
||||||
"champBucket",
|
|
||||||
"cloak",
|
|
||||||
"cocktailBar",
|
|
||||||
"crate",
|
|
||||||
"cubicleDoor",
|
|
||||||
"cueRack",
|
|
||||||
"dartboard",
|
|
||||||
"deck",
|
|
||||||
"discoball",
|
|
||||||
"dishwasher",
|
|
||||||
"distroBox",
|
|
||||||
"djPlinth",
|
|
||||||
"exitSign",
|
|
||||||
"fireExt",
|
|
||||||
"fireHose",
|
|
||||||
"firepit",
|
|
||||||
"flightCase",
|
|
||||||
"front_elevate",
|
|
||||||
"front_room",
|
|
||||||
"front_theRoyal",
|
|
||||||
"front_voltage",
|
|
||||||
"glassRack",
|
|
||||||
"glassStack",
|
|
||||||
"graffiti",
|
|
||||||
"handDryer",
|
|
||||||
"highTable",
|
|
||||||
"iceWell",
|
|
||||||
"jukebox",
|
|
||||||
"kebabShop",
|
|
||||||
"keg",
|
|
||||||
"liftDoor",
|
|
||||||
"loungeChair",
|
|
||||||
"marbleSink",
|
|
||||||
"mirror",
|
|
||||||
"mixer",
|
|
||||||
"monitor",
|
|
||||||
"mopBucket",
|
|
||||||
"noticeBoard",
|
|
||||||
"oldCouch",
|
|
||||||
"pallet",
|
|
||||||
"patioHeater",
|
|
||||||
"picnicTable",
|
|
||||||
"pieWarmer",
|
|
||||||
"pillar",
|
|
||||||
"plant",
|
|
||||||
"planter",
|
|
||||||
"plywoodBar",
|
|
||||||
"pokie",
|
|
||||||
"poolTable",
|
|
||||||
"poster1",
|
|
||||||
"poster2",
|
|
||||||
"poster3",
|
|
||||||
"poster4",
|
|
||||||
"poster5",
|
|
||||||
"poster6",
|
|
||||||
"poster7",
|
|
||||||
"poster8",
|
|
||||||
"poster9",
|
|
||||||
"raffleDrum",
|
|
||||||
"rollerDoor",
|
|
||||||
"ropePost",
|
|
||||||
"ruleBoard",
|
|
||||||
"sandwichBoard",
|
|
||||||
"sinkRow",
|
|
||||||
"skylineCard",
|
|
||||||
"smokeMachine",
|
|
||||||
"speaker",
|
|
||||||
"stackF1",
|
|
||||||
"staffBartender",
|
|
||||||
"staffChef",
|
|
||||||
"staffCleaner",
|
|
||||||
"staffDj",
|
|
||||||
"staffGlassie",
|
|
||||||
"staffSecurity",
|
|
||||||
"stampPodium",
|
|
||||||
"stanchion",
|
|
||||||
"streetBin",
|
|
||||||
"streetLamp",
|
|
||||||
"street_backdrop",
|
|
||||||
"street_elevate",
|
|
||||||
"street_room",
|
|
||||||
"street_theRoyal",
|
|
||||||
"strobe",
|
|
||||||
"subBass",
|
|
||||||
"tabBoard",
|
|
||||||
"taps",
|
|
||||||
"taxi",
|
|
||||||
"tex_brick",
|
|
||||||
"tex_carpet",
|
|
||||||
"tex_concrete",
|
|
||||||
"tex_deck",
|
|
||||||
"tex_looTile",
|
|
||||||
"tex_parquet",
|
|
||||||
"tex_paving",
|
|
||||||
"tex_plaster",
|
|
||||||
"tex_steel",
|
|
||||||
"tex_timber",
|
|
||||||
"till",
|
|
||||||
"topiary",
|
|
||||||
"trough",
|
|
||||||
"truss",
|
|
||||||
"tvSport",
|
|
||||||
"urinal",
|
|
||||||
"wetFloor",
|
|
||||||
"wheelieBin"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 893 B |
|
Before Width: | Height: | Size: 918 B |
|
Before Width: | Height: | Size: 351 B |
|
Before Width: | Height: | Size: 432 B |
|
Before Width: | Height: | Size: 884 B |
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 888 B |
|
Before Width: | Height: | Size: 619 B |
|
Before Width: | Height: | Size: 948 B |
|
Before Width: | Height: | Size: 778 B |