9.4 KiB
PROCITY — Round 39 instructions (from Fable, integrator)
Date: 2026-07-26 · R38 closed green — v8 wave 1 shipped and the town is inhabited (21 palettes, 36 backyards, the magpie, six panning ambient layers; budget held at 292/300, eight draws of margin, because the worst frame is a night frame and both new layers are zero at night).
JOHN HAS RULED: do the street names. "yes do street names for sure and what else can we get on with? just keep it going." Round 39 opens v9 — THE CITY IS THE GAME with its two zero-draw keystones, and keeps every other lane busy on work that needs no ruling.
Charters: V9_THE_CITY_IS_THE_GAME.md (the hunt; read Fable's verification header first) · SALE_RED_TICKET_DAY.md (the round and the Band Floor Law) · V8_SOMEONE_LIVES_HERE.md (in flight; wave 2 later).
THE BINDING FACTS (verified by Fable — do not re-derive, do not contradict without numbers)
- 17,835 of 19,132 road ways in the shipped caches carry a
name— 93.2%. Counted independently.plan_osm.js:363builds each way asrawWays.push({ kind: roadEdgeKind(rd.kind), pl })— it keeps the kind and the geometry and discardsrd.name. Every real street in 23 Australian towns is in this repo and the game has never said one out loud. - The names are recoverable without touching citygen's output. Plan nodes ARE snapped
projected way points (
plan_osm.js:361-372,SNAP=3), so plan edges lie ON the named ways: median distance from a plan-edge midpoint to its nearest named way is 0.03–0.90 m (worst town katoomba), and 97.8% of corpus shops (1,192/1,219) resolve to a street name. THE INTERIOR MARGIN IS SIX DRAWS, NOT 191.CORRECTED IN-ROUND BY LANE C — the margin was 31, and is 21 after C's bin. The direction was right (index.html:349shipsuseGLB: !NOASSETS, so the default boot IS the GLB path — that part stands and matters). The number was stale:C-progress.md:841's "GLB-on 344" is R9-era. C measured today's tree before touching anything: GLB-off 156 · GLB-on 319, bothopshop/hall. Fable's error, owned: I verified the claim's provenance (the doc does say 344) and not the measurement (the tree says 319). A document is not a tree. The house rule stands and I broke it: measure the thing, not the note about the thing. And the real finding is bigger than the correction — see the transmission entry in the close.- Vertical movement is fiction.
player.js:64andinterior_mode.js:485both writey = EYEunconditionally every frame on every path — no gravity, no floor query, no storey state, no floor height in any data structure. Nothing this round proposes stairs. - Only record shops and market stalls have a diggable crate —
kind:'bin'is minted atfittings.js:60/:75(recordBin,crate) and used by exactly two recipes (theme.js:38-39record,:196stall). The op shop'scrateStackis labelled "back-room dressing" in its own comment. You cannot dig in an op shop, in a game built on op-shop DNA.
The ledger
39.1 — THE ADDRESS LAYER (Lane A — the approved thing, and the prerequisite for everything else)
Recover the names and publish the vocabulary. A new pure module (no THREE, no fetch, no plan
mutation): createAddresses(plan, cache|null) → streetOf(edgeId) · localityOf(shopId) →
{street, district, block, side, label} · cohort(predicate) → shopId[].
- Real towns: street name by nearest named way to the edge midpoint (≤8 m tolerance).
- Synthetic: no roads cache and only 22 edges → the label comes from
district.kind+ block: "the market end", "the arcade", "the backstreets". Same field, different supplier, one consumer contract — this matters, because consumers must not branch on town type. - The synthesis proposes a one-line upgrade: write
norm.shift = {shx, shz}atplan_osm.js:510into the caller-suppliedopts.reportsink, never onto the plan object, so it moves no golden and breaks no classic byte. Take it if it is genuinely that clean; measure and report if it is not. - Goldens must not move. State it plainly with your selfcheck numbers. If one moves, stop.
- Publish the contract in LANE_A_NOTES §39 in your FIRST commit — B and C both consume it.
39.2 — THE FOG (Lane B — the keystone, zero draws)
minimap.js:52-63 draws every lot in the plan from the first frame, ungated: one M keypress
hands over all 493 synthetic shops. Measured cost of earning that yourself: 5,330 m synthetic /
9,622 m fitzroy / 5,797 m northbridge of walking — 4.8 / 8.7 / 5.3 game-days at WALK 4.6 m/s
against the 240-second day.
- Gate the map to shops the player has walked past; discovery is player state, saved under the delta law (size it: 24 towns × N shops, bounded, and prove export/import + corrupt-reject).
- Frame the map to what you know. The payoff is the reason to do it: a shop rectangle goes from 0.8×1.1 px to 29×39 px on bowral — a 35× legibility gain (21× katoomba, 17× adelaide, 11× fitzroy). The map is currently useless on the 21 towns that are supposed to be 21 mental maps.
- BINDING corrections from the judges: discovery is a proximity probe, not
chunks.onChunkBuilt(real towns are all BIG_CITY ⇒ R=2, so the outermost live chunk centre is 128 m out and its far corner 181 m — chunk-built discovery would hand you shops you never saw). And classic-gate it by construction:createMinimap(plan)becomescreateMinimap(plan, game ? knownProvider : null), where a null provider is today's exact behaviour — the same patternground.jsalready uses, sominimap.jsneeds no flag test at all. - Consume A's
localityOffor street labels on the map once A publishes.
39.3 — THE OP SHOP CAN'T BE DUG (Lane C — the game's namesake activity)
PROCITY is built on thriftgod's op-shop DNA and an op shop has no diggable bin. Its recipe is
clothes racks, metal shelves, a bookshelf, a trestle table and a crateStack its own comment calls
back-room dressing. Meanwhile the dig — the crown jewel, soaked since v2 — fires only in record
shops and market stalls.
- Measure first: what can a player actually DO in each of the 12 shop types today? Enumerate it honestly (dig / pull-and-buy / nothing) and put the table in your notes. That table is the deliverable even if nothing else lands.
- Then the mechanism: give the op shop a diggable bin (a bric-a-brac tub, a $2 book crate, a rummage bin — you own the fitting and the recipe). The mechanism is uncontroversial and yours.
- FLAG, do not decide: what is IN it. Records mixed in? Books and toys through the existing pull-and-buy pack? Its own item class? That is a John taste call and it is the difference between "op shops now dig" and "op shops now dig records", which changes the game's economy. Propose, measure the options, and hold.
- Spend against SIX draws (fact 3). Say what your bin costs and prove it.
39.4 — TWO MAGPIES, AND THE ARCADE'S ASSETS (Lane E)
- Settle the magpie (filed from R38): B ships a 182-tri procedural bird with vertex-colour white; E published an 894-tri tinted GLB that reads properly. Render them side by side at the size the bird is actually seen (64/48/32 px, the same sheet form as your tint render) and recommend. Fable rules on the picture, not the prose.
- The arcade is a real 42 m covered lane with 17 shops and it is dressed as nothing — no
props, no signage, no roof texture, no reverb. Generate its kit for a later round: a two-dollar-
shop A-frame, a key-cutter sign, hanging shopfront signage, a tiled arcade floor skin. Same laws:
$0, on-device, 🟢, provenance rows, and size every asset by
tris × the instance count the consuming lane implies— the law your ownpaling_fencebought us. - Correct
magpie.js's two stale tri comments (154 vs measured 182) — that is Lane B's file, so write the ask, do not edit it.
39.5 — THE GATES AND THE CLOSE (Lane F, last)
Gate 39.1–39.3 with falsifiability controls; full qa.sh --strict --matrix; round close. No tag.
Specifically: prove the address layer resolves ≥97% of corpus shops and fails loudly on a town
with no roads cache; prove the fog hides what has not been walked and reveals what has (both
arms, or it is vacuous); prove classic and ?noassets untouched; and re-measure the interior
budget against fact 3 if C's bin lands.
Laws
Everything standing. This round: zero draws is the requirement for 39.1 and 39.2 — they are information design and must cost nothing on the street · the interior margin is six · pathspec-atomic commits (four lanes share the tree) · no pushes, no tags — Fable pushes at close · every gate ships its control demonstrated.
⚠️ Tree note: a background session may still be editing web/js/world/venue.js. No lane touches
it this round.
Order
- Parallel: A (39.1, contract in the first commit) · B (39.2) · C (39.3) · E (39.4).
- Then F (39.5).
Standing — for John, when he wants them
The op-shop bin's contents (39.3) · whether the fog is default-on or a mode · and the v9 shape itself: the address layer and the fog are its first two layers, and the third (the unmarked door / semi-hidden retail) waits on how these two feel.