Go to file
m3ultra e4d77629c5 Lane A R37 (v8 wave 0 §0.1, ruling-side): the poster gate was VACUOUS — corrected to three arms with a permanent control
The audit's claim against my lane, re-measured and CONFIRMED exactly: on the default
boot (synthetic 20261990, gigs default-ON) there are 14 posters, all 14 stand inside
e.width/2 — the bitumen ground.js paints — and 0 stand inside the ruled kerb
roadWidth/2. One refinement it did not make: 12 are spine posters at poleOffset=6m,
8m inside the paint (genuinely mid-road); 2 are frontage posters clipping the corridor
edge by 0.06m (FACADE_PROUD past their venue's facade plane).

WHY the gate was green: my placer seats posters via poleOffset, which is DERIVED FROM
roadWidth, and my selfcheck asserted clearance against roadWidth/2. Gate and subject
were the same function agreeing with itself — the R27 cross-convention trap recurring
inside the very file whose header explains it. It never read a number that came from
Lane B, so no change to where the road is painted could make it fail.

The correction (selfcheck.js, districtInvariants), three arms:
  1. no poster on a carriageway — measured through vergeBand(e)[0], the published law
     itself, the same call B's ground now consumes, so gate and renderer move together
  2. every SPINE poster stands INSIDE some edge's vergeBand — the outer bound the old
     check never had ("not on the road" also passed for a poster in a paddock).
     Frontage exempt BY MEASUREMENT: 18/108 gig plans have a frontage poster past every
     corridor edge (worst 3.98m, launceston_real) via plan_osm's lot setback.
     Spine violations over the same corpus: 0/108.
  3. THE CONTROL — count posters standing on bitumen under the PRE-RULING ground
     (?verge=0, road quad = full e.width) and assert it is NOT ZERO on every gig plan
     (min 3 / max 212 / never 0 across 510 plans), pinned at EXACTLY 14 on the default
     boot. A control allowed to drift toward zero is how a gate goes vacuous.
     The replica is pinned to B's FLAG, not to a line number that will drift.

FALSIFIABILITY PROVEN. Simulated ?verge=0 honestly — vergeBand switched to the
pre-ruling reading, poleOffset pinned to the true band so the PLACER stays
byte-identical (it is a render flag: paint changes, plan does not; fingerprint and
every gig golden green in both runs, so the gate's reading is the only variable):
  corrected (R37) gate  →  FAIL, 1020 failures (2 arms x 510 plans)
  pre-R37 (HEAD) gate   →  ALL GREEN 156,352/156,352  — structurally blind

GOLDENS: NOTHING MOVED, ZERO RE-PINS. 0x5f76e76, GIG_GOLDEN 0xec7a2d39, 25 base town
goldens and 24 real-town gig goldens all untouched — correct and predicted, since the
only generator-adjacent file changed is the selfcheck, which validates output and never
produces it. 156,352 -> 157,407 checks (+1,055), 10.3s.

Corridor law CONFIRMED for Lane B, semantics unchanged, contract published in full
(LANE_A_NOTES §37) with four hazards flagged loudly while B consumes it in parallel:
roadWidth and edge.width are both FULL widths but one is carriageway and one corridor
(that naming IS why this bug existed); lane's band is NOT the literal [2,2] the round
instructions state (2 synthetic edges are, 56 real lane edges are [4,4] — branch on
outer<=inner); arcade is all footpath with coincident kerbs to skip; the inward
extension never inverts (0 of 31,039 edges). Two charter numbers corrected: the "9m
band / 18m of every main" figures are synthetic-only — on every real town a main is
24m => 7m band, and the corpus's dominant edge is side@12 at 22,415/31,039 (72%) with
a 3m footpath.

FILED, NOT FIXED — v8 debt ledger, four entries (LANE_A_NOTES §37): D1 chunkIndex
(two impls, THREE divergences, header comment promises a swap that would break three
ways — owner B) · D2 isOpen (three impls + an ad-hoc fourth site; A's canonical one has
ZERO importers; the live shell copy treats no-hours as CLOSED where A's law says OPEN —
latent until v8 adds an hours-less lot — owner F) · D3 two shop registries (B's missing
all three venue kinds => buildings.js:344 renders op-shop signage on every gig venue
since R13 — owner B) · D4 NEW, mine: the poster gate's inner bound is NEAREST-EDGE and
an arcade (kerb 0) camouflages a real carriageway — 8 real-town plans hide a spine
poster up to 1.78m inside a main, 0 on synthetic. Cost measured decision-grade:
synthetic 0/4 plans move, 11/26 town gig goldens re-pin, poster counts unchanged.
Deferred to R38 on purpose — it moves plan output for a reason that is NOT the kerb
ruling, and the "did the kerb ruling move a golden?" answer must stay a clean no.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 16:25:04 +10:00
docs Lane A R37 (v8 wave 0 §0.1, ruling-side): the poster gate was VACUOUS — corrected to three arms with a permanent control 2026-08-03 16:25:04 +10:00
pipeline Lane E R36 w1: the 2 a.m. commits regularized — 9 assets (not 7) swept, Rokoko zone correction, depot 44→53 2026-07-25 22:43:17 +10:00
priorwork Fable (integrator): round-3 lane instructions + archive round-1 lane prompts 2026-07-14 14:30:36 +10:00
tools Lane F R36 w2 (v7.0 close): the 2 a.m. assets gated — DJ-body figure-scale leg + smoke_djdance 2026-07-25 23:09:48 +10:00
web Lane A R37 (v8 wave 0 §0.1, ruling-side): the poster gate was VACUOUS — corrected to three arms with a permanent control 2026-08-03 16:25:04 +10:00
.gitignore Fable: R14 kickoff rulings recorded (push done, flag stays opt-in, genres final) + gitignore local session files 2026-07-16 00:59:42 +10:00
B-progress.md Lane B R30 (v7.0-alpha ledger #4): THE COLLECTION UI + SLEEP surface — the crate panel in hud.js (cover thumb = pack-atlas CSS crop off the sku, per-shop/town-wide bases, parody = glyph by design; where+day honest, foreign towns fall back to townKey), game bar day/$/CRATE count + SLEEP on F's §30.1 contract; construction-gated on PROCITY.game itself (classic/game=0 ⇒ zero DOM/listeners, measured); venue.js compat venueShopId = live weekNight getter (F's §30.4 filing, 116→490 across a sleep). Verified vs F's REAL committed core (nothing stubbed) on no-store :8151 snapshot; qa 6/6 2026-07-18 14:37:15 +10:00
C-progress.md Lane C R30 (v7.0-alpha ledger #2, implementation): sell.js — the sell counter lands. E at the bench → the mirrored price sticker; offer strictly below pricePaid by construction (8/8 scripted round trips lose money); type=type fail-closed (untyped item sells nowhere); wallet.sell = the credit mirror; game layer absent → no card, zero errors. Verified on :8144 no-store, stubbed game shape (F's core not landed); soak green avg 3.4ms · leak 0/0 · draws card-open ≡ closed 2026-07-18 14:14:14 +10:00
D-progress.md Lane D round 12: gig band + crowd + patronage surge (?gigs=1) 2026-07-15 19:49:07 +10:00
E-progress.md Lane E R12 (v3.0-alpha gig layer): 5 instruments + 4 posters + 3 gig audio 2026-07-15 19:44:48 +10:00
F-progress.md Lane F R36 w2.5 (v7.0 close, final): the hold RESOLVED — re-gate 0 fails / 0 warns on the true final tree 2026-07-26 00:31:22 +10:00
G-progress.md Lane G R27 (v5.0): tier 2 — the two read endpoints, the three fences, and the gate's missing subject 2026-07-17 13:56:02 +10:00
README.md Lane F R36 w2 (v7.0 close): THE FREEZE — README v7 section, charter risk verdicts, notes §36 2026-07-25 23:10:34 +10:00

PROCITY

A standalone, procedurally generated, fully walkable 90s-Australian shopping town — every building enterable (the Vuntra City trick), every interior seeded and themed: record stores, op shops, toy shops, book barns, video rental, pawnbrokers, milk bars, market stalls. Built on the proven house stack (three.js r175 vendored, plain JS, no build step) and the asset DNA of 90sDJsim + thriftgod. v1 is the system; the GODVERSE/BaseGod real-item content plugs in later.

Run

cd web && python3 -m http.server 8130
# http://localhost:8130            (game shell — Lane B)
# http://localhost:8130/map.html   (2D plan debugger — Lane A)

The manual — how to play (private test)

Click START to lock the mouse. Then:

input does
W A S D + mouse walk / look (first person)
walk into a shop door enter the interior (open shops only — check the hours tooltip)
E (inside a shop) open the crate at a record bin — then it's cursor-driven: click sleeves to riffle, click BUY
E (at the counter) · C (anywhere) · SLEEP (bottom bar) sell a find to the keeper (he pays under the guide band, never over) · open THE CRATE — your collection, in shops too now · sleep = save, the day advances, stock rotates
read the guide stamp on every price card the 90s price-guide band ("guide $824"). An item asking under its band is a gem — buy it, sell it to a keeper, pocket the margin. Bought slots stay gone for the day (the bin remembers)
☆ WANT IT on a pull card start hunting it — keepers gossip ("saw one in Castlemaine"), and buying one clears the hunt. Switching towns costs a day — the 23 towns are a map now, not a dropdown
⚖ LIST in the crate consign a find to GodBay — the auction hammers overnight (sleep or ride somewhere). One hammer per item, ever: keeper cash now, or the gavel tomorrow
wake up (sleep or arrive) the morning paper rides the wake/arrival toast: "⚖ SOLD 'Milk Bar Dreams' — hammer $8, $7 after fees" (or "PASSED IN — it comes home"). The news is a toast, never saved — the ledger is your cash and crate
click a book spine / toy box pull-and-buy card (real price stickers in godverse shops)
walk out the door / Esc leave the shop (Esc also frees the mouse anywhere)
M 2D town map (street only)
[ / ] step time of day back / forward · T pauses the clock
P capture screenshots (street)
HUD dropdown (top-left) switch towns — synthetic, fixtures, 23 real AU towns, godverse

Worth trying: ?classic=1 (the original v2 town, byte-identical forever) · ?noassets=1 (zero-network boot) · ?stock=real in a godverse town (Monster Robot Party's actual crate) · ?seed=<n> (any number = a different town). Night is when the gigs happen — step time with ].

Read first

  • docs/CITY_SPEC.md — the treaty: schema, units, seeds, budgets, file ownership.
  • docs/V7_THE_GAME.md — the CURRENT epoch (ratified): persistence, the collection, the gem thrill. docs/V6_LIVING_STREET.md runs in parallel (mocap NPCs, footpaths, cars).
  • docs/THE_FRONTIER.md — the honest map of what is not figured out yet.
  • docs/RESEARCH.md — what the parent repos already solved, with exact paths to port from.

The lanes (parallel Opus 4.8 sessions)

Each lane is a self-contained prompt. To run one, start an Opus session in this repo and say: "Read docs/LANES/LANE_X_….md and execute it." AE are parallel-safe (disjoint files, standalone test pages); F integrates after they land.

lane mission owns
A — CITYGEN seed → CityPlan data (streets, blocks, lots, shops) + 2D map js/citygen, js/core/registry.js, map.html
B — STREETSCAPE chunk-streamed instanced 3D town + game shell index.html, js/world
C — INTERIORS every door opens: seeded themed shop interiors js/interiors, interior_test.html
D — CITIZENS rigged-near / impostor-far NPCs + shopkeepers js/citizens, citizens_test.html, models/
E — ASSETS audit ultra's library, normalize GLBs, skins, manifest pipeline/, assets/
F — INTEGRATION wire AE into one seed-to-town game + QA gates (after AE)

Already in the repo

  • web/vendor/ — three.js r175 + addons (vendored from 90sDJsim; no CDN at runtime).
  • web/assets/gen/ — 69 generated texture skins (25 shopfront facades, 10 skies, 10 grounds, 8 wallpapers, 16 interior surfaces) inherited from thriftgod + 90sDJsim, style-locked.
  • web/js/core/ — frozen shared modules: prng.js (seeded-everything law), loaders.js (fail-soft promise-cached GLB/texture + 3GOD depot), canvas.js (text planes).

House laws (short form — CITY_SPEC has the fine print)

Seeded everything, Math.random banned in gen code · the game must run with zero assets · instancing from day one · canvas text, no font files · characters = shared base rigs + one clip bank, canonical sources live outside this repo · 🟢 web-ok licensing only.

v3.1 — THE FLIP: the town shows its best by default

The Friday-night layer soaked through alpha, beta, and the v3.0 release — so v3.1 flips it on by default, and the mature v2 flags flip with it. Boot the plain URL and each town seeds 24 venues (pub, band room, RSL) with a full seeded week of gigs, town-wide posters, and a Friday night that reads: a 4-piece band (trio + a seated drummer) with real instruments, a mixed crowd, an outdoor queue, a per-venue cover charge, muffled gig spill + walla and applause, town-wide streetlamp pools, and identity continuity — the ped you followed in is in the crowd. Plus weather, the tram, and the parallax interior-window shader, all live by default.

The covenant moved, it didn't disappear. ?classic=1 boots the exact v2 town — byte-identical forever (synthetic golden 0x3fa36874, zero gig layer, zero fetch delta). That is the new frozen regression target; the default boot is deterministic to the gig golden 0xb1d48ea1. Asset-free (?noassets=1) composes with the default boot and stays silent-and-fine.

Flags — the four headliners are ON by default, each with a =0 opt-out; ?classic=1 is the master off:

flag default what
?classic=1 off the exact v2 boot — all four below off, byte-identical to the frozen baseline
?gigs=0 on the gig district — venues, week schedule, band/crowd/queue, cover, posters, night pass
?weather=0 · ?tram=0 · ?winmap=0 on seeded weather · the tram loop · the parallax interior-window shader
?roster=v1 · ?pop=N stream chunk-streamed citizen density is the baseline; ?roster=v1 restores the fixed roster
?dig=0 · ?stock=real dig on crate-riffle on record bins · real GODVERSE sleeves in the stock
?live=1 · ?live=<url> off tier 2 — live stock from the GODVERSE server (sold-in-the-real-shop means gone in the game). Opt-in by design: absent ⇒ byte-identical to tier 1, and the game never asks a question it has no reason to expect an answer to
?noassets=1 · ?plansrc=osm · ?mute=1 · ?dbg=1 off asset-free (zero network) · OSM plan source · silence · the window.DBG capture/soak harness
?plansrc=osm&town=<key> boot a real Australian town: fixtures melbourne/katoomba/silverton, or a real OSM cache bendigo_real/castlemaine_real/fremantle_real/katoomba_real/newtown_real (ODbL, web/assets/towns/SOURCES.md). REAL ROADS: a cache with roads[] (schema v2) builds the CityPlan street graph from the town's actual OSM streets; without roads[] a cache marches onto synthetic avenues. Or just pick a town from the HUD selector — no URL needed

v4.0 — THE REAL MAP: the towns are the product

23 real Australian towns — 1,210 real shops, every state and territory — on their actual streets. Not "inspired by": Fitzroy's shops sit on Fitzroy's roads, at their real positions, because the pipeline eats OpenStreetMap and marches it through the same CityPlan contract the procedural town uses. Pick one from the in-HUD selector and walk it. Everything built across v1v3 comes along unchanged — the venues and their seeded week of gigs, the 4-piece band with the seated drummer, the crowd that follows you into the pub, the interiors behind every door, weather, the tram — because they all hang off the plan contract and never had to know the geography got real.

The towns run from meccas (Fitzroy, 160 shops) to the thin tail (12), at real retail density: the secondhand heroes keep their footfall while the street around them gets ~4× busier — texture, never a takeover. Venues bias to the retail heart. The tram only runs where it fronts a real high street (elsewhere it was honestly "a highway bus", so it's fenced). Everything stays deterministic from the seed, silent under ?noassets=1, and ?classic=1 still boots the exact v2 town, byte-identical forever (0x3fa36874).

The tour: docs/shots/release_v4/contact.html — the Fremantle hero, the Fitzroy mecca, the thin tail (labelled honestly: the floor is shops-per-street-metre, and Toowoomba is below it), the synthetic control, and the ?classic=1 covenant made visible. Charter: docs/V4_REAL_MAP.md · data + licences (ODbL): web/assets/towns/SOURCES.md.

v5.0-alpha — THE FIRST REAL CRATE: the shops get real too

v4 made the towns real. v5 makes the shops real — and the first one is standing.

Boot ?plansrc=osm&town=redhill_godverse&stock=real, walk down Musgrave Road into Monster Robot Party (147 Musgrave Rd, Red Hill, Brisbane — a real record shop), and riffle its crate. The records in it are that shop's real stock: 120 real records off its real point-of-sale, real covers, real titles, real prices. Buy one and the wallet debits what the sticker says. It's gone for the session and back next boot — because until the live tier lands, the crate is a file, not a shop's ledger.

Stock is a data tier now, exactly like assets — each rung fully playable, each degrading softly to the one below, so the game never depends on a server to be a game:

tier what deterministic?
0 · parody seeded canvas sleeves (v1) — any boot, always works yes — the QA baseline
1 · static real per-shop atlases baked from the shop's own POS yes — atlases are files
2 · live GODVERSE ?live=1 — live stock off the real till: sell a record in the shop and it's gone from the game crate no — by design

The offline law: the server enriches, never gates. ?noassets=1 still fetches zero bytes and plays silent-and-fine; a shop whose atlas is missing falls soft to parody rather than borrowing someone else's crate; and ?classic=1 still boots the exact v2 town, byte-identical forever (0x3fa36874). The world stays seeded and golden-gated — only the stock inside it is data.

Provenance: item photos are each shop's own product shots, 🟢 in-house — flagged before any public or commercial release, and every atlas carries that flag where the QA gate must print it. Real titles and artists are an in-house amendment to the no-real-trademarks law, on the same footing. Nothing an in-game purchase does touches real inventory — v5.0 ships sell-sandboxed by ruling; a real reservation tier is chartered for v5.x, not assumed. Charter: docs/V5_REAL_SHOP.md · economy design: docs/G3_ECONOMY_DESIGN.md. | ?seed=N | 20261990 | town seed |

Release tour: docs/shots/release_v3_1/contact.html — the money shots on the default boot, plus a ?classic=1 before/after. QA: tools/qa.sh --strict (classic regression + default-boot gate + smokes + no-giants) --soak (the full-week soak); the seated drummer passes the no-giants gate at the seated stature band [0.9,1.5] m.

v7.0 — THE GAME: you're a crate-digger in 90s Australia

v4 made the towns real, v5 made the shops real — v7 makes it a game. Boot the plain URL on a fresh browser and you arrive HUNTING: the splash names a seeded first want and your pocket money ("You're hunting HILLS HOIST — $191 in your pocket"), three toast-beats walk you through the first dig, and from there the loop is live:

dig (E at a record bin — the crate riffle) → read the guide (every price card carries a 90s price-guide band; an item asking under its band is a gem, and spotting one is the whole skill) → ☆ WANT what you're hunting (keepers gossip seeded rumors — "saw one in Castlemaine") → travel (switching towns costs a day; the 23 towns are a strategy map) → sell to the keeper (instant cash, always under guide — the no-pump law) or ⚖ LIST on GodBay (a seeded offline auction that hammers overnight; one hammer per item, ever — no retry farm) → SLEEP (= save; the day advances, parody/mint stock rotates per (shop, day), bought slots come back) → wake to the morning paper ("⚖ SOLD — hammer $22, $19 after fees"). Repeat, richer and one gem wiser.

The machinery under it: a versioned localStorage save carrying THE DELTA ONLY (cash · collection · day · town · wants · pulls · listings — the world always regenerates from seed, so a corrupt save can cost you your stuff, never the town), JSON export/import for moving machines, and an economy fenced by gates: sell < guide-band structurally, auction EV ≈ 0.8×mid (random flips bleed; only finds profit), save/load byte-determinism, rotation seeded by (citySeed, shop, day).

?classic=1 still boots the pure v2 town — zero save, zero game DOM, zero Storage calls, instrumented every run — and ?game=0 opts out of the layer on any boot. Charter: docs/V7_THE_GAME.md (ratified 2026-07-17, risk verdicts appended at the close) · economy: docs/G3_ECONOMY_DESIGN.md · the tour (day one to first gem, 6 frames, no staging): docs/shots/v7_tour/.