The roster board and the back office get real rooms
plate:corkboard, plate:backoffice and a TRELLIS'd COIN-U-SORT 400 — the two screens seen every night were pure rectangles. Drawn versions stay as fallbacks. RosterScene gets its own tiny preload because it is scene[0] and runs before the prewarm it starts. Heading moved off the board: real art put it on the light. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
91fe06d023
commit
d10b9a34fd
@ -2496,3 +2496,34 @@ had already split `barServeBreach` out of `barServe` so the RSA question can
|
||||
actually fire. I only had to supply the missing words and the variety rule.
|
||||
`tests/incidentReport.test.ts` now guards the whole class: every loaded kind
|
||||
must have a bespoke prompt, not the generic line.
|
||||
|
||||
## SESSION — FABLE-SOLO-29 · 2026-08-09
|
||||
|
||||
**Branch:** main (solo, Fable) · **Gate:** lint ✓ build ✓ test ✓ (842 tests)
|
||||
|
||||
### The two between-shift screens stop being rectangles
|
||||
The roster board and the back office are seen EVERY night and were both drawn
|
||||
entirely from coloured primitives. Added to `tools/gen/assets.py` in the
|
||||
existing idiom (new `BETWEEN` group):
|
||||
- `plate:corkboard` — a lit cork noticeboard, flat route, keep_bg, no quantise
|
||||
- `plate:backoffice` — a cramped panelled office, one bulb, empty desk
|
||||
- `sorter` — MESH route (rake 58), the COIN-U-SORT itself. `quantise=False`
|
||||
deliberately: it is a ~130px UI hero, not a 16px floor prop, and 16 colours
|
||||
turns a grey machine to porridge.
|
||||
|
||||
Both scenes keep their drawn version as the fallback — a missing plate has
|
||||
always meant placeholders, never a broken screen. The sorter image goes INSIDE
|
||||
the existing container so every shake and bob still works untouched.
|
||||
|
||||
### RosterScene needs its own preload, uniquely
|
||||
It is scene[0]: it runs before anything has loaded, so it cannot rely on the
|
||||
manifest prewarm it goes on to START. `preload()` pulls the corkboard and only
|
||||
the corkboard; the other ~130 sprites still warm in the background behind the
|
||||
board.
|
||||
|
||||
### A legibility regression the plate caused, and the fix
|
||||
Dropping real art behind the roster put the heading directly on the plate's
|
||||
fluorescent tube — light type on the brightest thing in the image. The board
|
||||
moved down to y=194 (258 tall) and the heading moved off it onto the dark wall
|
||||
at y=16/38. Worth remembering: adding a background can break foreground text
|
||||
that was fine over a flat colour.
|
||||
|
||||
@ -70,7 +70,7 @@ furniture (bar, booths, stools) could come straight from its fit pipeline.
|
||||
(794 MB, 26,910 files) — prior AI-gen pools; sweep for club/street/neon/night
|
||||
material before generating fresh.
|
||||
- m4pro SPACEY `MRP PHOTOSHOP FILES` (4.4 GB PSDs) — design-language source
|
||||
(posters/flyers could become in-game wall dressing). m4pro is HANDS-OFF; access
|
||||
(posters/flyers could become in-game wall dressing). m4pro is reachable (HANDS-OFF label retired 2026-08-06 — never true); access
|
||||
via the SMB mount on m3ultra if needed.
|
||||
|
||||
### 4. Generation pipeline (MODELBEAST)
|
||||
|
||||
118
docs/ASSETS.md.bak-20260806
Normal file
118
docs/ASSETS.md.bak-20260806
Normal file
@ -0,0 +1,118 @@
|
||||
# NOT TONIGHT — Fleet Asset Notes
|
||||
|
||||
*What already exists on John's network that this game can reuse, borrow from, or
|
||||
generate with. Sourced from the fleet-wide `ASSET_INVENTORY_2026-07-18.md` and
|
||||
`GAME_ASSET_AUDIT_2026-07-18.md` (both on ultra `~/Documents/`). Compiled
|
||||
2026-07-19.*
|
||||
|
||||
**Context for lanes:** v0.1–0.3 use PROCEDURAL placeholder art (coloured-pixel
|
||||
paper-doll, synthesized audio) — nothing below is needed before the v0.4 art pass.
|
||||
This doc exists so the art pass starts from the library, not from scratch. Nothing
|
||||
here changes the `renderDoll` / layer contracts.
|
||||
|
||||
## Directly relevant (v0.4 art pass)
|
||||
|
||||
### 1. 90sDJsim paper-doll wardrobe — the big one
|
||||
`ultra:~/Documents/90sDJsim/web/world/media/doll/` — **441 authored clothing
|
||||
sprites** across tops/bottoms/shoes/hats/bags, brand-flavoured (coogi, dr_martens,
|
||||
nike_air_max, moschino, quiksilver, kmart, disruptor_ii…), dynamically loaded by
|
||||
`os.listdir` slot convention.
|
||||
- **Reuse the taxonomy**: their slot/brand/type naming should inform
|
||||
`data/outfits.ts` vocabulary (we already have shoes/legs/top/outer/hair/accessory
|
||||
— cross-check their catalog for types we missed, e.g. bucket hats, bumbags).
|
||||
- **Reuse the art via pixelation**: 90s wardrobe reads perfectly as 2026 Valley
|
||||
fashion-in-quotes. A downscale/quantize pass (sprite → 32×48 palette-locked
|
||||
pixel layer) could convert the catalog into real doll layers. Prototype on 10
|
||||
sprites before committing — pixelated photo-sprites can look mushy; may need a
|
||||
cleanup pass or MODELBEAST-assisted redraw per sprite.
|
||||
|
||||
### 2. RIGROOM — the character × animation factory (surveyed 2026-07-19)
|
||||
**This supersedes the old "animation references" note. The fleet has a full
|
||||
character/animation pipeline, live and organised:**
|
||||
- **RIGROOM library** (`ultra:~/meshgod-backups/library`, 2.4 GB): **607
|
||||
animation FBX** in themed packs + 59 character files. Web UI live at
|
||||
`http://100.91.239.7:8010/rigroom` (characters × animations pairing, three.js
|
||||
preview, instant Mixamo-ready FBX download). CLI:
|
||||
`MESHGOD/scripts/rigroom.py classify|sort|scan`.
|
||||
- Clips that read like THIS game's shot list: `Searching_Pockets` (pat-down),
|
||||
`Standing_Arguing` + a full boxing/knockout pack (floor fights),
|
||||
`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
|
||||
- `ultra:~/Documents/90sDJsim/web/world/media/` named scene/venue art — 100 wired
|
||||
widescreen club/venue images. Mood reference for our neon-dark interiors.
|
||||
- `gdrive:ASSETS FROM AI` (2.47 GB, 3,239 files) + `gdrive:IMAGE-DATABASE`
|
||||
(794 MB, 26,910 files) — prior AI-gen pools; sweep for club/street/neon/night
|
||||
material before generating fresh.
|
||||
- m4pro SPACEY `MRP PHOTOSHOP FILES` (4.4 GB PSDs) — design-language source
|
||||
(posters/flyers could become in-game wall dressing). m4pro is HANDS-OFF; access
|
||||
via the SMB mount on m3ultra if needed.
|
||||
|
||||
### 4. Generation pipeline (MODELBEAST)
|
||||
m3ultra central queue :8777 (see fleet skill). For NOT TONIGHT this is an
|
||||
**image generator, not a mesh generator** — we need no GLBs. Useful for: patron
|
||||
face/outfit reference sheets to hand-pixel from, venue backdrop concepts, Dazza's
|
||||
contact photo, joke ID photos. The thriftgod `gen_assets.py` + 640px `sips`
|
||||
convention (m3ultra `~/Documents/thriftgod/`) is a proven prompt→asset-dir pattern
|
||||
worth cloning for an `art_src/` pipeline here.
|
||||
|
||||
## Explicitly NOT for this game
|
||||
|
||||
- **All 3D mesh libraries** (`3D=models`, `3D-STORE`, FBX, femalemeshed,
|
||||
NPCFACTORY, MODELBEAST GLB output) — no 3D in this game; only via the Option-B
|
||||
prerender path above, never at runtime.
|
||||
- **Audio archives** (bandcamp ~1 TB, YT-AUDIO, MONSTER MIXES). The design is
|
||||
locked to a fully synthesized WebAudio techno engine (design §5 / LANE_JUICE) —
|
||||
the low-pass location trick needs a synth we control, and shipping archive audio
|
||||
is a licensing minefield. John's own MONSTER MIXES are legally his — park the
|
||||
idea of a licensed-mix easter egg (jukebox in the kebab shop?) as a someday-note.
|
||||
- **dealgod image pool** (2.4M product photos) + `recordgod_disc_images` — product
|
||||
photography, wrong domain. (One cursed exception: pat-down contraband items
|
||||
could be pixelated from real dealgod product shots. Someday-note.)
|
||||
- **thriftgod 2D dressing** — authored 640px painterly JPGs, wrong style; its
|
||||
*pipeline* is the reusable part (see §4).
|
||||
|
||||
## Ground rules for the eventual art pass
|
||||
|
||||
**Licensing: none needed.** This is a private tailnet sandbox game, never public —
|
||||
John's call (2026-07-19). Anything on the fleet or gdrive is fair game, including
|
||||
the audio archives and MONSTER MIXES. (If that ever changes and the game goes
|
||||
public, this section is the checklist to revisit first.)
|
||||
|
||||
1. Everything funnels through the existing contracts (`renderDoll` poses, outfit
|
||||
slots) — art swaps in behind interfaces, callers never change.
|
||||
2. One palette, one pixel density (32×48 queue dolls at 640×360) decided ONCE
|
||||
before any batch conversion; retrofitting mixed densities is the classic trap.
|
||||
3. Log each imported batch (source → transform → dest) in this file — not for
|
||||
licensing, just so we can regenerate/retrace later.
|
||||
4. Check the MeshGod gallery + MODELBEAST `data/` (m3ultra) before generating
|
||||
anything — the inventory's rule "catalog before regenerating" applies here too.
|
||||
5. The synthesized techno engine stays the core soundtrack (the location-filter
|
||||
trick needs a synth we control), but real archive audio is now allowed as
|
||||
layers/easter eggs — e.g. MONSTER MIXES on a kebab-shop jukebox, real crowd
|
||||
ambience beds under the synth.
|
||||
@ -68,6 +68,8 @@
|
||||
"pillar",
|
||||
"plant",
|
||||
"planter",
|
||||
"plate_backoffice",
|
||||
"plate_corkboard",
|
||||
"plywoodBar",
|
||||
"pokie",
|
||||
"poolTable",
|
||||
@ -88,6 +90,7 @@
|
||||
"sinkRow",
|
||||
"skylineCard",
|
||||
"smokeMachine",
|
||||
"sorter",
|
||||
"speaker",
|
||||
"stackF1",
|
||||
"staffBartender",
|
||||
|
||||
BIN
public/props/plate_backoffice.png
Normal file
BIN
public/props/plate_backoffice.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 186 KiB |
BIN
public/props/plate_corkboard.png
Normal file
BIN
public/props/plate_corkboard.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 271 KiB |
BIN
public/props/sorter.png
Normal file
BIN
public/props/sorter.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
@ -66,11 +66,16 @@ export class HaulDeskScene extends Phaser.Scene {
|
||||
const t = tallyHaul(this.args.haul, this.args.pocketedBaggie);
|
||||
this.lines = t.lines;
|
||||
|
||||
this.add.rectangle(W / 2, H / 2, W, H, 0x14110c);
|
||||
// the desk: a slab of laminate under a single tired bulb
|
||||
this.add.ellipse(W / 2, 96, 460, 220, 0x2a2318, 0.55);
|
||||
this.add.rectangle(W / 2, 250, W, 220, 0x3a2f1e);
|
||||
this.add.rectangle(W / 2, 142, W, 3, 0x241c12);
|
||||
// The room. The drawn version stays as the fallback: a missing plate has
|
||||
// always meant placeholders rather than a broken screen.
|
||||
if (this.textures.exists('gen:prop:plate_backoffice')) {
|
||||
this.add.image(0, 0, 'gen:prop:plate_backoffice').setOrigin(0, 0).setDisplaySize(W, H);
|
||||
} else {
|
||||
this.add.rectangle(W / 2, H / 2, W, H, 0x14110c);
|
||||
this.add.ellipse(W / 2, 96, 460, 220, 0x2a2318, 0.55);
|
||||
this.add.rectangle(W / 2, 250, W, 220, 0x3a2f1e);
|
||||
this.add.rectangle(W / 2, 142, W, 3, 0x241c12);
|
||||
}
|
||||
|
||||
this.add
|
||||
.text(W / 2, 20, HAUL_UI.title, { fontFamily: MONO, fontSize: '15px', color: '#f0e4d0' })
|
||||
@ -85,7 +90,7 @@ export class HaulDeskScene extends Phaser.Scene {
|
||||
.text(W / 2, 60, '', { fontFamily: MONO, fontSize: '9px', color: '#e8dcc4', align: 'center', wordWrap: { width: 420 } })
|
||||
.setOrigin(0.5, 0);
|
||||
this.quipText = this.add
|
||||
.text(W / 2, 300, '', { fontFamily: MONO, fontSize: '8px', color: '#a09070', align: 'center', wordWrap: { width: 460 } })
|
||||
.text(W / 2, 300, '', { fontFamily: MONO, fontSize: '8px', color: '#c0ac84', align: 'center', wordWrap: { width: 460 } })
|
||||
.setOrigin(0.5, 0);
|
||||
this.tallyText = this.add
|
||||
.text(W - 18, 250, '$0', { fontFamily: MONO, fontSize: '26px', color: '#f0d060' })
|
||||
@ -131,16 +136,22 @@ export class HaulDeskScene extends Phaser.Scene {
|
||||
const y = 210;
|
||||
const c = this.add.container(x, y);
|
||||
this.sorter = c;
|
||||
c.add(this.add.rectangle(0, 0, 150, 92, 0x5a5348).setStrokeStyle(2, 0x3a352c));
|
||||
c.add(this.add.rectangle(0, -38, 116, 20, 0x241f18)); // hopper mouth
|
||||
c.add(this.add.rectangle(0, -46, 132, 8, 0x6a6355));
|
||||
for (let i = -2; i <= 2; i++) {
|
||||
c.add(this.add.rectangle(i * 26, 22, 18, 26, 0x2a251c)); // coin channels
|
||||
// The machine goes INSIDE the container so every shake and bob below still
|
||||
// works whether it is real art or the drawn fallback.
|
||||
if (this.textures.exists('gen:prop:sorter')) {
|
||||
c.add(this.add.image(0, 0, 'gen:prop:sorter').setDisplaySize(132, 100));
|
||||
} else {
|
||||
c.add(this.add.rectangle(0, 0, 150, 92, 0x5a5348).setStrokeStyle(2, 0x3a352c));
|
||||
c.add(this.add.rectangle(0, -38, 116, 20, 0x241f18)); // hopper mouth
|
||||
c.add(this.add.rectangle(0, -46, 132, 8, 0x6a6355));
|
||||
for (let i = -2; i <= 2; i++) {
|
||||
c.add(this.add.rectangle(i * 26, 22, 18, 26, 0x2a251c)); // coin channels
|
||||
}
|
||||
c.add(this.add.rectangle(0, 50, 150, 10, 0x46403a)); // the tray
|
||||
}
|
||||
c.add(this.add.rectangle(0, 50, 150, 10, 0x46403a)); // the tray
|
||||
c.add(
|
||||
this.add
|
||||
.text(0, -8, HAUL_UI.machineName, { fontFamily: MONO, fontSize: '7px', color: '#9a9080' })
|
||||
.text(0, 62, HAUL_UI.machineName, { fontFamily: MONO, fontSize: '7px', color: '#8a8070' })
|
||||
.setOrigin(0.5),
|
||||
);
|
||||
}
|
||||
|
||||
@ -39,6 +39,16 @@ export class RosterScene extends Phaser.Scene {
|
||||
this.carried = data ?? {};
|
||||
}
|
||||
|
||||
/**
|
||||
* The board's own plate, and only that. RosterScene is scene[0] — it runs
|
||||
* before anything has loaded, so unlike every other screen it cannot rely on
|
||||
* the manifest prewarm it goes on to start. One small image is worth the
|
||||
* wait; the rest of the art is warmed in the background by prewarmProps().
|
||||
*/
|
||||
preload(): void {
|
||||
this.load.image('gen:prop:plate_corkboard', 'props/plate_corkboard.png');
|
||||
}
|
||||
|
||||
/**
|
||||
* Warm the prop textures while the player reads the board.
|
||||
*
|
||||
@ -89,15 +99,19 @@ export class RosterScene extends Phaser.Scene {
|
||||
|
||||
// the back office: unpainted, honest
|
||||
this.add.rectangle(W / 2, H / 2, W, H, 0x14100c);
|
||||
this.add.rectangle(W / 2, H / 2 - 8, 560, 280, 0x3a2a18).setStrokeStyle(3, 0x241a10);
|
||||
if (this.textures.exists('gen:prop:plate_corkboard')) {
|
||||
this.add.image(W / 2, 194, 'gen:prop:plate_corkboard').setDisplaySize(560, 258);
|
||||
} else {
|
||||
this.add.rectangle(W / 2, 194, 560, 258, 0x3a2a18).setStrokeStyle(3, 0x241a10);
|
||||
}
|
||||
|
||||
this.add
|
||||
.text(W / 2, 42, `${venue.name} — ${NIGHT_NAMES[nightIndex] ?? ''}`, {
|
||||
.text(W / 2, 16, `${venue.name} — ${NIGHT_NAMES[nightIndex] ?? ''}`, {
|
||||
fontFamily: MONO, fontSize: '16px', color: '#f0e4d0',
|
||||
})
|
||||
.setOrigin(0.5);
|
||||
this.add
|
||||
.text(W / 2, 62, 'THE ROSTER · take a shift', {
|
||||
.text(W / 2, 38, 'THE ROSTER · take a shift', {
|
||||
fontFamily: MONO, fontSize: '8px', color: '#a89878',
|
||||
})
|
||||
.setOrigin(0.5);
|
||||
|
||||
@ -346,9 +346,33 @@ DOORSCENE = [
|
||||
],
|
||||
]
|
||||
|
||||
|
||||
# ---- Between-shift screens ---------------------------------------------------
|
||||
# The roster board and the back office are the two screens the player sees EVERY
|
||||
# night that were still drawn entirely from coloured rectangles. Both are plates
|
||||
# (keep_bg, no quantise): they fill their frame and are meant to be opaque.
|
||||
BETWEEN = [
|
||||
F("plate:corkboard", (560, 280), 4600,
|
||||
"a battered cork noticeboard filling the whole frame, pinholes and old staples, "
|
||||
"warm fluorescent light from above, a strip of timber frame at the edge, "
|
||||
"NOTHING pinned to it, no paper, no notes, empty board",
|
||||
gen=(1536, 768), quantise=False, keep_bg=True),
|
||||
F("plate:backoffice", (640, 360), 4601,
|
||||
"a cramped nightclub back office at night seen straight on, cheap laminate desk "
|
||||
"surface across the lower half, dark panelled wall above, a wall calendar, "
|
||||
"a taped-up roster, one tired ceiling bulb, NOTHING on the desk, empty desk",
|
||||
gen=(1536, 864), quantise=False, keep_bg=True),
|
||||
# The sorter is a UI hero at ~150px, not a 16px floor prop, so it keeps its
|
||||
# full palette — quantised to 16 colours a grey machine turns to porridge.
|
||||
Asset("sorter", "mesh", (128, 96),
|
||||
"a battered desktop mechanical coin sorting machine, metal hopper on top, "
|
||||
"five coin channels down the front, output tray at the base, worn enamel, "
|
||||
f"{MESH_TAIL}", 4602, rake=58, quantise=False),
|
||||
]
|
||||
|
||||
ALL: list[Asset] = [
|
||||
*ROYAL, *ELEVATE, *ROOM, *TEXTURES, *WALLS, *STAFF, *FILLER, *STREETS,
|
||||
*DOORSCENE,
|
||||
*DOORSCENE, *BETWEEN,
|
||||
]
|
||||
|
||||
BY_KIND = {a.kind: a for a in ALL}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user