9/9 through flux product shot -> trellis2_mlx -> glb_to_sprite, unattended. Rake corrected after the first pass: tall objects need a STEEPER angle (76), not a shallower one — an arcade at 55 is a front-on slab. Re-angled from the meshes already on disk, no re-generation, which is the point of keeping the GLB. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
11 KiB
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.
1. Design principles
- 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.
- 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.
- 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. - 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):
- Backdrop plate behind the existing rects: one wide pixel-art street wall
(brick, posters, grime) — swaps in as
gen:street:backdropwhen generated. - 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>.pngand list them inpublic/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 → writespublic/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.