Commit Graph

21 Commits

Author SHA1 Message Date
m3ultra
2f4ab5912f Lane B R26 (v5.0-beta): the stocked shopfront reads from the footpath
Ledger #5 — B's polish pick. A stocked godverse shop now tells you it's
diggable before you reach the door: a crate of seeded spines under the shop
name, and a warm-lamp-over-crates room behind the glass.

Cost: +0 draws / +0 tris. The mark is painted into the chunk's EXISTING
sign-atlas cell; the window cue rides the EXISTING per-shop aTint attribute.
Nothing new is allocated or submitted.

The manifest is the authority, deliberately NOT the godverseShopId key: keyed
means "has a stock identity", the manifest means "a crate is actually here".
Marking keyed-but-unstocked shops would advertise a crate the shop hasn't got
— the street would lie. The mark does not leak tier: "you can dig here" is
equally true of real and mint; provenance belongs on C's price card and in E's
gates. (Second job for ledger #6's manifest, free.)

Measured — true A/B at one pose, manifest 200 vs 404:
  spine-marked sign cells   0 → 3 (18,768 exact-palette px)
  stocked window tint verts 0 → 36
  street_noon               65 draws / 115,502 tris → UNCHANGED
Stocked shopfront (Goulds Books, footpath): 85 draws / 144,730 tris — inside
street law (<=300 / <=200k). Cues agree with ground truth: 3 stocked shops
live → 3 marked cells, 9 stocked window quads.

Covenants re-proved (the prefetch is new code on the boot path), tested with
the manifest present on disk so a stray fetch would 200 and be unmissable:
  ?classic=1        0 keyed, 0 stock fetches, 0 errors  (zero-fetch covenant)
  default synthetic 0 keyed, 0 stock fetches, 0 errors
  manifest 404      18 keyed, fail-soft, 0 page errors

Three traps, self-caught: (1) a module-load fetch would have put a fetch delta
on ?classic=1 — restructured to a lazy reader + plan-driven prefetch, keyed
plans only; (2) the lazy trigger alone raced the first chunk build, so the
first stocked shop you approach built unmarked — prefetch moved to
createChunkManager, before any chunk builds; (3) the first "zero cost" was
VACUOUS (manifest never fetched, so nothing was applied) and the first pixel
detector reported 60 marked cells with no treatment at all — replaced with an
exact-palette signature that reads 0 in control. Vacuous-gate law applies to a
lane's own verification too. Corollary: force-cache serves a deleted file
(transferSize 0, status 200 while disk 404s) — poison the cache or you are
testing your own memory.

B consumes stock_godverse/index.json read-only and emits nothing into it; the
temp manifest used to prove this round was deleted — the directory is G's.
Shape-tolerant + fail-soft, so G's real emission needs no coordination with B.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 09:49:54 +10:00
m3ultra
af8a6db020 Lane B round 22 (v4.0): #3 per-town bookmarks — anchor on the retail heart (Lane G's filed bug) + F's primitive
ROOT CAUSE: every "nearest" resolver in dbg.js sorted by distance from the WORLD ORIGIN. That's the town
centre only on a synthetic plan -- a real OSM town is projected about its cache's bbox centre while its shops
cluster hundreds of metres away, so bookmarks teleported into arbitrary far-flung geometry, exactly as G
reported. Measured origin-pick distance from the retail heart: katoomba 408m, newtown 626m, fremantle 371m.

FIX: resolve bookmarks about the town's DENSEST SHOP CLUSTER (grid-bin shop lots at 120m; heaviest bin's
centroid = the retail heart) instead of the origin -- byDist, lotsByDist, streetViewPose, stopPose, and
crossroadsPose's tie-break.

GATED on the REAL-ROADS signal (edges > 200) -- the same primitive as the R20 tram fence -- so synthetic and
the marched fixtures keep their exact origin-centred behaviour and F's release-tour control shot cannot move.
The gate is load-bearing, not cosmetic: synthetic's anchor is only 117m out but it DOES re-pick (Anglibarn Op
Shop -> Dusty Pages), so an unconditional switch would have silently moved the control. Same reason the new
crossroadsPose tie-break is gated (a degree tie would otherwise resolve differently on synthetic).

Verified across the town set: synthetic(22 edges)/melbourne(15)/katoomba-fixture(15)/silverton(1) -> origin,
UNCHANGED; newtown_godverse(1626) -> anchor(98,-629); katoomba_real(993) -> anchor(-227,-625). G's own town
is fixed.

Result on katoomba: shopfront bookmarks went from ~408m adrift to <=42m of the retail heart (arcade 7m,
milkbar_dusk/patronage_door/shopfront_detail 24m, market_square 26m, dig_real 42m); strip views ~195m on the
high street; venue_night/queue_night ~345m (A's venue placement, not the bookmark). All 19 resolve, 0 errors;
synthetic 19/19 unchanged. warehouse_fringe sits 3,074m out -- correct by design (it's the far:true fringe
shot; on a 5km town the fringe genuinely is 3km away).

-> F (ledger #4, the shared posing primitive): published on the harness as DBG.townAnchor {x,z,n,anchored,ref}
   (the retail heart + whether it's in use) and DBG.clusterPose(kinds) (stand on the road at the densest
   cluster, look along it). Your cluster-pose finding as a dbg.js-consumable -- the tour and the bookmarks now
   resolve through the SAME primitive, so a tour shot and its bookmark can't drift apart.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 22:01:41 +10:00
m3ultra
0c4dad5acc Lane B round 22 (v4.0): #1a venue_night tri diagnosis — the driver is E's four furniture GLBs (91.5%)
BLOCKING-ITEM DIAGNOSIS, filed first so E/A/F aren't waiting. Method: katoomba venue_night, settled, then
hide-a-layer-and-re-measure (frustum-accurate: a layer's cost = the tris that vanish when hidden), then the
same drill inside furniture bucketed by geometry.

VERDICT: the four GLB street-furniture props are 149,161 of 163,015 tris = 91.5% of the stress view.
OWNER: LANE E (asset tris), per the ledger's own rule. Decimation clears the gate with ~120k to spare.

Layer breakdown (baseline 163,015 tris / 88 draws):
  chunk-furniture 151,341 (92.8%) | ground 9,932 | venue-presentation 770 | lighting 624 |
  chunk-buildings 348 (0.2%) | venue-posters 222 | citizens/weather/tram/venue-pools 0

Buildings are 348 tris (the R3 atlas/instancing holds). Posters are 222 -- A's cap already worked and was
never the lever. Pools cost 0.

Inside furniture -- the four GLBs are the whole bill:
  bench 1,942 tris/inst x64 = 60,202 (37%)      <- procity_street_bench_01
  bus_shelter 7,998 x10     = 55,986 (34%)      <- procity_street_bus_shelter_01
  bin 3,000 x19             = 18,000 (11%)      <- procity_street_bin_01
  food_cart 4,991 x8        = 14,973 (9%)       <- procity_street_food_cart_01
  pole/lamp/trees/novelty (primitives) x303 = 2,180 (1.3%)
Identity confirmed by DCC-authored material names (wire_143225087 = a Sketchfab scan, baked_mat,
"2 wood frame ", Material_0) -- E's GLBs, not our procedural materials. Two use MeshPhysicalMaterial.

WHY NOW (and why it is NOT the density widening): shop count doesn't drive this -- ROAD density does. Real
towns put the bench/bin/shelter cadence on a 966-edge graph, so ~100 GLB props land in the streamed set
where synthetic had a handful. A 1.2m bench at 1,942 tris is ~5x the entire building stock in frame. This is
B's own R6 note coming due ("street_bin 3.0k tris... a decimate to ~500 would give back tri headroom if the
combined-lane budget tightens").

-> E, suggested targets: bench 1942->~250, bus_shelter 7998->~600, bin 3000->~200, food_cart 4991->~400.
   149,161 -> ~29,000 (saves ~120k). Projected: my 163k -> ~43k; F's 221,935 -> ~102k. Both far under 200k.
   Cheap extra: drop the two MeshPhysicalMaterials to MeshStandardMaterial.
-> Fable: a B-side fallback exists (furniture.js already has a primitive fallback for every GLB prop via the
   R4 use-if-ready path), so a distance-gated LOD is a contained B change I can land fast. NOT doing it
   unilaterally -- per the ledger this is E's, and source decimation helps every town/view, not just this one.
-> F: my baseline is 163,015 vs your 221,935 on the same view -- my automation's rAF is throttled so the live
   gig crowd never spawns (citizens measured 0). Furniture is still ~68% of your number; decimation clears the
   gate on either baseline. Re-measure against the live crowd, not my figure.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 21:52:43 +10:00
m3ultra
4b0144989b Lane B round 21 (v4.0-beta): town selector reads E's towns index (ledger #2, the missed R20 #5)
Closes the gap Fable caught (hud.js:11 still hardcoded REAL_TOWNS). The real-town list now comes from E's
web/assets/towns/index.json (procity-towns-index/1), so it grows with the town pack instead of being edited
in hud.js. Verified fresh Chromium. Nothing else touched -- tram/ground work is done and verified.

Fail-soft by construction: createHUD is synchronous, so the picker is built immediately from the fallback
literal and UPGRADED IN PLACE when the index resolves -- if the index never arrives, a working list is
already on screen.
- index present -> real names/states/shop counts: "Katoomba, NSW · 80 shops", "Fremantle, WA · 80 shops",
  "Newtown, NSW · 72 shops", "Bendigo, VIC · 36 shops", "Castlemaine, VIC · 24 shops" (roads:false -> "· marched").
- ?noassets -> the fetch is SKIPPED entirely (asset law; the shell doesn't load town caches there either).
  Measured: 0 index fetches, fallback list, 0 errors.
- anything wrong with the index -> the fallback simply stands. Exercised the exact chain: 404, network error,
  malformed JSON, towns:[], towns-not-an-array, junk entries (no key) -> none throws, none rebuilds from junk;
  only a good index rebuilds.

REAL_TOWNS_FALLBACK is retained ONLY as that fallback (comment says so), no longer the source of truth.
Verified live: booting katoomba_real shows "Katoomba, NSW · 80 shops" pre-selected; fits (193px of 230px max);
0 page errors; navigation unchanged (onchange is set once on the <select>, so rebuilding options never clears it).

-> F: unchanged from R19 -- NO shell seam (selector is entirely hud.js, already built by createHUD) and it
   lives inside #pc-hud so setVisible(false) hides it for the beta money shot. The gating call is still yours.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 20:35:47 +10:00
m3ultra
94e56ed5fa Lane B round 20 (v4.0-beta): the tram ruling — route by shop adjacency + per-town fence (ledger #3/#4)
Verified fresh Chromium across 9 town configs (synthetic, 3 fixtures, 5 real).

TRAM RULING (ledger #3): spinePolyline now walks from each main-subgraph dead-end, greedily taking the
unused main edge fronting the most shops (lot.frontEdge), keeping the best-scoring path (ties -> longer).
SYNTHETIC + FIXTURES BYTE-IDENTICAL by construction AND measurement (a synthetic main node has <=2 mains so
there's never a choice; its two dead-ends tie exactly and strict > keeps the pre-R20 start). Old vs new
logic on the same plan = identical polylines (Boolarra: 7 pts, 6 edges, 810m, 172 shops, 2 stops).

The alpha tram fronted 0 shops on 4 of 5 real towns (it was a highway bus). New: katoomba 0->3, newtown
0->8, fremantle 0->2, bendigo 0->1, castlemaine 1->6. Where the best main chain still fronts <5 shops the
tram is FENCED per-town (Fable's fallback). RUNS: synthetic, all fixtures, newtown (8 shops/1924m/16 stops),
castlemaine (6/2184m/10 stops). FENCED: katoomba (3), fremantle (2), bendigo (1) -- highway, not high street.
The fence keys off the REAL-ROADS signal (edges>200), NEVER shop count alone: the marched fixtures front 0
shops on their mains (bare spine, avenues carry shops) so a naive fence would have killed their v2 tram.
routeInfo{fenced,reason,shopsFronted,routeMetres} exposed for F's smoke.

BUG FOUND+FIXED: the stop projection accepted every shelter in the town with no distance gate -- harmless on
synthetic (2 shelters on the spine), nonsense on real graphs: Newtown made 149 phantom stops (~9 min of dwell
at points the tram never passes). Added a 30m gate (a shelter sits halfRoad+1.7 <=~16m off its centreline, so
genuine stops survive): newtown 149->16, castlemaine 37->10; synthetic 2 / fixtures 3 unchanged.

GROUND POLISH (ledger #4): measured, NO fix needed. Real Katoomba has 325 deg-3+ junctions, 28 under 30 deg,
worst 4.3 deg (near-parallel). At grazing eye level the worst reads clean -- no z-fight, no gaps. Layers are
already y-separated (road 0.0/foot 0.02/kerb 0.06) and road-on-road overlap is invisible by design (OVERLAP=1.5
overruns nodes on purpose; one skin, one y, one merged draw on uniform asphalt). Cosmetic only: footpath/kerb
double up on the sliver between <10deg near-parallel roads -- v4.0 candidate, not a defect.

Selector polish (ledger #5): BLOCKED -- E's towns/index.json not landed (build_towns.py WIP); REAL_TOWNS
hardcode stands, one-line swap when E lands.

-> A (finding, measured): only a slice of shops front a MAIN edge on real towns -- katoomba 7/69, fremantle
   4/79, bendigo 7/35, newtown 32/64, castlemaine 11/22. The real high street classifies as 'side', which is
   WHY three towns need the fence. If the main/side classifier promoted shop-dense ways to main, the fence
   would lift. Note onMain also gates gigs.js pickVenues pub placement.
-> F: tram verdict above; selector gating (HUD vs ?dbg) is your call, one line either way.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 19:35:56 +10:00
m3ultra
73694c97aa Lane B round 19 (v4.0-alpha): in-game town selector (ledger #4, beta pull-forward, non-blocking)
Shipped the town picker in hud.js (which already owns its DOM overlay -> NO index.html seam). A compact
<select> in the HUD (top-left, pointer-events:auto), 9 options: synthetic + 3 OSM fixtures (osmTownKeys
minus _real) + 5 real-road caches (Katoomba/Newtown/Fremantle/Bendigo/Castlemaine, hardcoded REAL_TOWNS --
no manifest yet, beta derives it). Selecting navigates: synthetic clears plansrc/town; a town sets
?plansrc=osm&town=<key>, preserving all other params. Current pre-selected; unknown-current still shown.
Verified end-to-end: picked katoomba_real through the dropdown -> booted real Katoomba (966 edges/323
intersections/3 venues), 0 errors. Lives inside #pc-hud so hud.setVisible(false) hides it for money shots.

-> F (B->F seam): NONE -- self-contained in hud.js (already constructed by createHUD). Gate it behind ?dbg
   with one setVisible call if you prefer; left always-in-HUD as a modest debug-grade feature.

Corner-strips spot-check (R18 failure-item #3): ground fills real intersections OK -- degree-4 junction
(58 exist) shows road strips overlap-filling the junction, lane markings + zebra crossing render, no gross
gap. Acceptable for alpha; finer acute-angle pass = beta.

Budget note -> F (measured vs A's UNCOMMITTED WIP -- caveat, not a defect): F's BIG_CITY one-liner is live
(chunks 50->26). But venue block still ~237k tris at night against the current tree, which carries A's
uncommitted R19 finalization (plan_osm modified; graph grew 799->966 edges, junction-joining in but the
far-island CULL not yet). Fable's ruling: the cull is "half of B's tris problem" -> the <=200k gate needs
F's fix AND A's committed cull. Re-measure the busiest real block after A pins (the deferred tris-post-cull
re-measure genuinely waits on A's commit; the dev server serves other lanes' uncommitted edits).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 17:38:59 +10:00
m3ultra
d4fcf68860 Lane B round 18 (v4.0-alpha REAL ROADS): irregular-geometry audit (ledger #4) — the failure list
Audited katoomba_real on E's real roads (schema v2, 484 OSM ways -> 799-edge/872-node graph, 126 real
intersections, edges 3.5m-1303m incl 28 short <12m, ~4x5km span). E's roads landed mid-audit; verified
fresh Chromium, cache-busted. Docs-only (no code change: streetscape is road-agnostic).

VERDICT: Lane B streetscape is ROAD-AGNOSTIC — boots real Katoomba 0-error, every B system builds and
renders on the irregular graph (ground, furniture 39 chunks/148 trees, town-wide pools, tram, chunk
streaming, buildings, wind). Real main street reads well (road+footpath+lamps+working gig poster+citizens).
Like C's interiors, needed no code change to eat real geometry.

FINDING -> F (gate-blocking, PROVEN one-line fix): the BIG_CITY adaptive heuristic misfires on real roads.
index.html BIG_CITY = plan.shops.length>120 -> Katoomba has 20 shops(<120) but 799 edges/5km, so it stays
small-town mode (radius 3 + shadows ON), streams 50-52 chunks -> busiest venue block ~280k tris (clean,
settled) = BREACHES 200k gate (draws 150 <300). Proven fix: ?r=2&shadows=0 (BIG_CITY mode) -> 84k day /
104k night, 20 chunks, 72 draws, well under. Recommend: BIG_CITY = shops>120 || edges>200 (catches
Katoomba's 799, leaves synthetic Boolarra's 22). B's R3 adaptive-streaming concept, edge-count not shop-count.

Tram (Fable's flagged spine risk): degrades gracefully, no crash. spinePolyline runs one main chain =
3527m/49 edges = 21% of 232 mains (longest walkable chain). Arbitrary-but-functional for alpha; smarter
route or hard fence = beta (no plan.mode marker exposed to fence off; didn't add untested fencing).

Furniture/pools scale: town-wide pools ~4989 instances = still ~1 draw; 28 short edges get 0 lamps
(graceful). Correction: the disconnected graph I first saw was a synthetic-fixture DP artifact (junction
vertices dropped on near-collinear ways) — real Katoomba forms 126 intersections correctly; flagged to A.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 16:35:55 +10:00
m3ultra
ee16545941 Lane B round 17 (v3.2): wind sway SHIPS -- weather-driven gum-tree sway (ledger #5, parked since R7)
Verdict: shipped, not killed. The R7 park reason ("touches shared materials") is a non-blocker under
R16's measurement-over-brief standard: the gum-tree billboard material is B-owned (furniture.js), so
this is entirely Lane B -- no C/E material seam. Verified fresh Chromium seed 20261990.

- New web/js/world/wind.js: shared uniforms (uWindTime/uWindAmp) + applyWind(material) (onBeforeCompile
  vertex patch: top-weighted horizontal sway, per-instance world-position phase, USE_INSTANCING-guarded)
  + updateWind(dt,intensity). furniture.js applies it to the tree material; weather.js drives it from
  update(dt) (base breeze 0.05 clear -> 0.05+intensity*0.30 ~0.35 rain gusts).
- Trees only. Awnings excluded by MEASUREMENT: rigid posted-verandah box slabs don't flutter (fabric
  canopy ripple = separate v3.3, shares the rigid awning InstancedMesh today).
- Byte-identical when weather off (the covenant): updateWind runs only inside weather.update, and the
  weather system isn't constructed under ?weather=0 / ?classic=1 -> uWindAmp stays 0 -> sin(...)*0.0==0.0
  -> identical vertices. Proven: amp=0 two times = 0/180000 px differ; ?weather=0 boot = 0 tree-motion px;
  ?classic=1 = amp 0, trees render, 0 errors. No plan/fetch/rng change -> F's classic gate untouched.
- Sway works: rain amp 0.305 moves ~14100/180000 region px over 0.8s (exaggerated 2.5 -> 101k); trees
  render clean, no glitch. ~0 draws (ALU ops in the existing tree InstancedMesh vertex program), 0 errors.

-> Lane F (B->F handshake): SWAY SHIPPED. In old frames under the default boot; ?classic=1/?weather=0
   sway-free + byte-identical. Procedural (no asset -> E has nothing to do).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 14:30:09 +10:00
m3ultra
54a030b38b Lane B round 16 (v3.1 THE FLIP): town-wide streetlamp pools + default-boot budget re-baseline
Ledger #4. Verified fresh Chromium seed 20261990. No new rng, goldens untouched.

- Town-wide pools (venue.js): extended the R13 instanced-pool pass from venue frontages to EVERY
  streetlight + bus shelter. New townPoolSpecs(plan) replicates furniture.js's lamp cadence off the
  plan street graph (lamp every 18m from s=8, alternating sides, off=halfRoad+0.7) and reuses the
  exported busShelterStops(plan) -- read-only, furniture.js untouched (imported one function). All
  pools ride the ONE existing InstancedMesh -> still ~1 draw: 381 instances / 1 draw / ~760 tris.
  Night-driven; fog:true now so distant pools fade into night fog (pools aren't chunk-streamed) instead
  of floating as dots. Gig-gated -> ?classic=1 is pool-free = v2 parity by construction (no always-on
  furniture change, the v3.0 blocker). Deterministic cadence, no seeded draws (release law).

- Default-boot re-baseline: measured the default content (gigs + weather=rain + winmap + tram all
  live), settled. Busiest venue block (pub, NIGHT, rain) ~157 scene / ~170 total draws, 66k tris;
  venue_night 122, queue_night 121, district_posters/street_noon 185 (worst tour shot), market_square
  fresh 97/52k. ALL <=300 draws / <=200k tris. Flip adds ~3 draws (rain 1 + tram 2; winmap 0), pools
  add ~0 (instanced). Daytime dense-citizen ceiling (~275, Lane D, live-walk) unchanged (pools night-only).

- Bookmark spot-check: all 19 resolve, un-letterboxed, 0 errors under the default boot; rain+tram+winmap
  compose cleanly in old frames (street_noon rainy 177/114k, nothing blocked). No pose fixes.

Ran before F's flip landed (out of the stated order): pools are gig-gated so they work under ?gigs now;
re-baseline uses explicit all-flags URLs = post-flip default content. F re-confirms at close.

-> Lane F (B->F handshake): default-boot busiest block ~170 total draws / 66k tris; worst street view
   185 / 131k; densest daytime 97 / 52k. All under budget. Town-wide pools ~1 draw. Pool sprite is
   procedural (E has nothing to do).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 12:21:19 +10:00
m3ultra
a0b578477c Lane B round 15: verify hero after A's poster flip + night poster readability (?gigs=1)
Verified A's ledger-#1 flip (35da83c): the pub's own-frontage poster moved from 15.9m behind the
building to 0.09m from the door on the +Z street face, facing the reader -- no queue_night pose
change needed (R14 prediction held). Gig golden 0x1f636349->0x4f4a549d consumed cleanly.

Fix (John-sanctioned exception to the R14 freeze): posters were unlit MeshStandardMaterial and
rendered pure black at NIGHT (measured frontage poster centre [183,71,59] day -> [4,0,1] night), so
queue_night + district_posters showed no readable bill even after A's flip. venue.js now gives posters
emissiveMap = the poster art, emissiveIntensity ramped in update() by night (0 day -> 0.55 night, same
lerp as glow/pools). Self-lights the bill after dark; daylight byte-identical (verified midday spine
poster pixel-unchanged). No new rng, no plan change, goldens frozen. ?noassets fallback self-lights too.

Verified fresh Chromium seed 20261990: queue_night (seg5, live queue) frames marquee + window glow +
streetlamp pools + a readable red poster by the door + queue punters (90 draws/29k tris);
district_posters night now shows a poster (was black, 180/138k); daylight unregressed.

-> Lane F (B->F handshake): HERO VERIFIED. Shoot queue_night at seg 5 (NIGHT) -- poster now reads there
   and night is needed for pools+glow; drive the queue live (rAF throttled in automation). Poster
   night-emissive rides the shell's per-frame venuePresentation.update(gigState.byVenue).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 10:11:53 +10:00
m3ultra
eee60e05a5 Lane B (Streetscape) round 14: v3.0 release — alpha-alias retirement + tour audit + queue_night hero (?gigs=1)
Release round: no new systems, no rng, goldens frozen (0x3fa36874 / gig 0x1f636349 both unmoved).
Files: audio.js, venue.js, dbg.js (+ LANE_B_NOTES). Verified fresh Chromium, seed 20261990.

- Alpha-alias readers dropped (debt #1, B first): audio.js venueGigState() loses the alias hop
  (g.venueShopId===id -> g.state); byVenue + clock fallback only. venue.js stateGetter() loses the
  bare-string arm (F passes gigState.byVenue since R13, confirmed index.html:379); seed = update(null).
  Verified live: byVenue {116:on,404:on,490:quiet} at NIGHT drives the marquee with no string arm;
  audio resolves gig-<genreKey> per venue with no alias hop. F is UNBLOCKED to delete the getters.
- Bookmark/tour audit under ?gigs=1: all 19 bookmarks resolve, frame un-letterboxed, 0 page errors,
  <=300 draws. District venue-conversions hijacked none (night_neon->Video Regal, dig_real->Retro
  Groove). No pose fixes needed. (Orphan-chunk teleport inflates tris across sequential shots -- fresh
  counts <=153k; tram_stop's real ~293k is close-range Lane D GLB ped rigs, framing fine, not a venue block.)
- queue_night bookmark added (dbg.js): John's release hero -- close 3/4 on the pub door at seg 5
  ('on'), biased to the queue side; new poseForVenueQueue() recomputes venue.js frontage geometry.
  Frames marquee + window glow + streetlamp pools + the queue (spawned live by the shell loop; F's
  gig_shot.py drives it live -- verified by manually spawning D's VenueQueue: 2 punters at the door).
- Poster-repetition call (debt #4): FINE, no ask to E -- 2 gigs tonight => 2 distinct designs
  (screenprint/Screaming Utes x7, xerox/The Dead Ringers x7); variety scales with venues playing.
- Town-wide streetlamp pools: v3.1 candidate per Fable ruling (venue-scoped for v3.0; no code).

-> Lane F: cross-lane alias sweep is CLEAN (no A/C/D/E reads it); only your own 20 tool lines in
   flags_check.py + gig_shot.py remain -- migrate to *Of(id)/venueShopIds[0] when you delete the
   gig_state.js:141-151 getters + the CITY_SPEC alias line (with A).
-> Lane A (now gates John's hero-shot poster): buildPosters item 1 still seats each venue's own
   frontage poster on local -Z (back wall, 15.9m from the +Z street facade). Flip to +sin,+cos and it
   seats by the door -- in the existing queue_night frame, no pose change. Per "don't touch world
   code," B did not work around it. Re-flagged from R13.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 08:43:22 +10:00
m3ultra
46127c7e95 Lane B (Streetscape) round 13: v3.0-beta the district — N-venue frontage + night pass + posters + queue zone (?gigs=1)
Generalises the R12 one-pub slice to all 2-4 venues and lands the night-readability polish. All
gig-gated (flags-off byte-identical, verified in a fresh browser context). Files: venue.js, audio.js, dbg.js.

- venue.js -> N venues: per-venue lit marquee/frontage on B's +Z facade side + window-light spill;
  streetlamp pools on venue blocks (one instanced warm-pool mesh, night-driven -> the Friday-night
  walk reads); town-wide posters instanced per gig (14 posters = 2 draws / 2 textures, band-name
  overprint, flat printed-poster fallback). Town-wide pools deferred (would need always-on
  furniture.js -> breaks flags-off parity).
- Queue-zone marker per venue: venue.queueZone = {x,z,ry,len} for Lane D (head at the door, extends
  along the frontage; queuer faces -ry). queueZones{} + queueZoneFor(id).
- audio.js muffled spill per-genre (debt #1): import gigKeyFor; the nearest venue at doors/on within
  26 m spills its gig-<genreKey> through the 470 Hz lowpass, so pub/band_room/RSL crossfade genre.
  F: delete the GIG_BED bridge.
- update(gigStates) polymorphic: per-venue map {[venueShopId]:state} (F wires PROCITY.gigs.byVenue)
  or alpha-compat bare string (primary pub). Contract documented for F in LANE_B_NOTES.
- ?noassets fetch fix (latent R12 bug): gate the poster JPEG fetch behind !noassets -> 0 gig-layer
  network over the 22-JPEG facade/ground baseline.
- dbg.js: venue_night + district_posters bookmarks (seg 5) so tools/qa/gig_shot.py scripts the
  street money shot; poseForVenue resolves from the live plan.

Budget (fresh Chromium, gigs-on NIGHT, busiest pub block, all frontages lit): worst 154 scene /
~167 total draws, 64k tris -- <=300 / <=200k. 0 console errors (gigs / gigs+noassets / flags-off).
Verified 3 venues seed 20261990: pub->gig-pubrock, RSL->gig-covers, band_room->gig-grunge (all in
E's manifest).

Finding for Lane A: buildPosters item 1 seats each venue-frontage poster on the lot -Z (back wall,
measured 15.9 m from the +Z street facade) -- flip to +sin,+cos. Spine/pole posters render correctly
and face the footpath ("SCREAMING UTES" readable). Non-blocking (marquee + pools carry the shot).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 23:11:10 +10:00
m3ultra
f0a0a99207 Lane B (Streetscape): round-12 v3.0-alpha — venue frontage + posters + muffled-gig spill (?gigs=1)
- web/js/world/venue.js (new): createVenuePresentation — renders E's poster skins at plan.posters with band-name overprint (nameZone, seeded template, flat fallback if JPEG missing); lit pub marquee + bulb row over the door, update(gigState) ramps the glow. Constructed by the shell/F under ?gigs (like weather/tram).
- web/js/world/audio.js: muffled-gig spill — near the venue (<=26m) while a gig is at doors/on, pubrock-live plays through a 470Hz lowpass at low distance-gain. Reads window.PROCITY.gigs (F) with a plan.gigs+clock fallback.
- Prime flag law: inert/absent without the gig layer; goldens frozen (no citygen edits, selfcheck 3074/3074); byte-identical flags-off boot.
- Verified live on a gig plan: THE WOMBATTS posters over band-photo art, The Thornbury Hotel lit at night, spill gain ~0.14. F wiring documented in LANE_B_NOTES; streetlamp-pool stretch deferred.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 20:15:40 +10:00
m3ultra
f7dd44f55a Lane B (Streetscape): round-11 audio — WebAudio engine (street side)
- web/js/world/audio.js: one AudioContext unlocked on first gesture; day/night ambience crossfade, rain (weather.intensity), footsteps, shop-door music spill (nearest open music-shop, distance-gain), tram rumble+bell, enterShop SFX. Consumes Lane E manifest.audio (3x retry). Self-ticks off window.PROCITY.
- House audio law verified live: silent pre-gesture (0 fetches), ?mute=1 silent surface (0 fetches), ?noassets=1 zero audio/manifest fetches, lazy-load (8.7MB<=25MB), no per-frame alloc.
- window.PROCITY.audio for Lane F: playInterior({musicKey,toneKey})/stopInterior (street beds duck while inside), playSfx, setMasterGain, mute, state diag. Confirms Lane C room.audio={musicKey,toneKey} contract.
- Small guarded [Lane B R11 audio] loader in index.html.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 16:00:31 +10:00
m3ultra
16c4450cd9 Lane B round-9: v2 tram (?tram=1) + tour bookmarks + rain-drop polish
- tram.js: 1 small bus, seeded out-and-back loop on the main-street spine,
  door-dwell at each busShelterStops stop, ping-pong at ends. Deterministic,
  exactly 2 draws, night headlights via lighting.isNight(). Flag-off identical.
  Shell wiring (2 lines) documented for F in LANE_B_NOTES.
- dbg.js: 8 v2 tour bookmarks (16 total) incl. rain_verandah hero shot;
  tram_stop now frames the nearest-origin (open) shelter stop.
- weather.js: cap rain gl_PointSize (clamp 2-22px) - near drops are thin
  streaks now, not blobs. Rain smoke still GREEN.
- qa.sh --strict GREEN, golden hash frozen, flags-off byte-identical.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 11:09:41 +10:00
m3ultra
900b274a9a Lane B round-8: weather (?weather=1) — seeded rain/overcast/clear, exposes PROCITY.weather for D
New js/world/weather.js + a one-line lighting.setSky(). Seeded per citySeed (weatherFor):
~57/24/19% clear/overcast/rain over 400 seeds, deterministic. Rain = ONE draw (camera-following
Points + procedural streak/fall/wind shader) + wet ground (roughness/darken on shared ground mats,
restored on dispose) + matching rainy sky dome via lighting.setSky. Fully procedural (0 depot fetch).

- Exposes window.PROCITY.weather = { state:'clear'|'overcast'|'rain', intensity:0..1 } for Lane D's
  weather-reactive crowds (decision #1). Documented the contract + the exact 3-line shell wiring for F
  in LANE_B_NOTES (I don't touch index.html). ?weather=1 seeded (default town rolls clear);
  ?weather=rain|overcast|clear forces a state for demos/smokes.
- Worst view 141 draws day / 126 night (<=300); composes with ?winmap + night (rain outside a lit
  interior-mapped window = the money shot, screenshotted); deterministic; 0 console errors; flag-off
  byte-identical (shell never constructs it). Deferred cut line: vertex-shader wind sway on
  trees/awnings (touches other lanes' materials) — noted, not done. Tram stretch not attempted.

qa.sh --strict GREEN (5/5).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 02:34:14 +10:00
m3ultra
24cef5a7bb Lane B round-6: place street_bin + bus_shelter GLBs (on the street graph, collision-verified)
Consumes the two orphaned street GLBs via the use-if-ready furniture path (fail-soft; ?noassets →
primitives, 0 network).

- Bins: genuinely sparse (~1/block, s+=78m, seeded side), decoupled from benches — country town not
  a mall. GLB on its 0.57x0.68 footprint.
- Bus shelters ON THE STREET GRAPH (future tram/bus stops): deterministic rule = midpoint of every
  MAIN edge with hashEdge(id)%3===0, road-side footpath by the kerb, long axis along the edge, open
  front to road -> 1-3/town (2 in seed 20261990). Solid oriented-rect collider (furniture now returns
  colliders; chunks.js merges them into getColliders) -> walk-into-it is blocked. Exported
  busShelterStops(plan) -> [{edgeId,x,z,yaw}] as the stop-list contract for the vehicle loop.
- Perf: worst view WITH rig-fleet citizens 94k tris / 148 draws (<=200k / <=300, big margin);
  deterministic; all-flags-on (winmap+dig+roster) composes clean, 0 errors. street_bin GLB is 3k tris
  -> flagged to Lane E as a decimation candidate (bounded by the sparse cadence for now).

qa.sh --strict GREEN.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 23:04:14 +10:00
m3ultra
2a923b61e6 Lane B round-5 (v2): parallax interior-mapping window glass behind ?winmap=1
The Vuntra window trick — a passing pedestrian sees a plausible room through the shop glass with real
parallax, no geometry. One shared ShaderMaterial does single-cube interior mapping on the existing
window mesh (back wall + seeded shelves + side walls + floor/ceiling); per-shop variation via
aTangent/aTint/aSeed attributes, still 1 window draw/chunk. §3.5 held via the shared uHour/uNight +
aHours: night → open room glows warm, closed room dark.

v2 prime law: WINMAP is read from the URL in buildings.js (self-contained — no index.html seam; F
just needs a flags-table row). Flag-OFF byte-identical to v1 (windowQuad → v1 hoursQuad, v1
windowMaterial). Proven: flag-off windows MeshStandardMaterial w/ no winmap attrs; flag-on interior
ShaderMaterial; worst view 122-168 draws (<=300); 100% procedural (0 fetch delta vs ?noassets
baseline); 0 console errors; GOLDEN.hash untouched. Screenshots in docs/shots/laneB/winmap_*.

qa.sh --strict GREEN (4/4).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 21:00:57 +10:00
m3ultra
6323d58736 Lane B round-4: closed facades (§3.5) + shot poses/letterbox + furniture GLB + novelty_record
- B1: per-shop closed-facade visuals — dark windows + red CLOSED plate + door tooltip, batched via a
  per-vertex aHours attr + two shared shaders + one uHour/uNight uniform pair on a procity:segment
  event (facade atlas untouched, no per-shop materials, no per-frame poll). 22:00 → only the openLate
  video shop lit, all others CLOSED; ~200 draws worst-view with citizens.
- B2: the shots 'letterbox' was camera-jammed-into-a-wall poses, not a composer bug (composer proven
  correctly sized headless). Reframed street_noon/arcade/warehouse to look down a street
  (streetViewPose), added the 3 missing bookmarks, night_neon now frames the lit video shop amid
  CLOSED neighbours, + a defensive composer resize. shots.py: 10 un-letterboxed shots, 0 errors.
- B3: furniture GLB use-if-ready upgrade (bench + food_cart, sit on their footprints) + novelty_record
  placed at record stores. novelty_record GLB is 26.5k tris (5x glb_law) → stays low-poly primitive
  until Lane E decimates it; ?noassets verified 0 network.

qa.sh --strict GREEN (4/4).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 19:59:27 +10:00
m3ultra
fafd5a700a Lane B (Streetscape): round-3 — scene.environment for PBR peds + budget re-measure with citizens
- lighting.js sets scene.environment (neutral PMREM sky->ground gradient, no asset) in attachRenderer, before CitizenSim constructs; Lane D rig-fleet peds bake their impostor atlas from it and render dark if null. Verified set in street/night/interior + after interior-return.
- Re-measured worst continuous-walk view WITH citizens (pop 140, 125 active peds) via window.DBG: 263 scene / 275 total midday, 275 night -- <=300 everywhere. Radius-2 auto already the spawn default.
- Round-3 task 3 (furniture GLB footprints) standby: Fable s3.4 manifest upgrade not yet landed.
- Docs: LANE_B_NOTES.md + B-progress.md round-3 updates.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 16:00:22 +10:00
m3ultra
5313402e43 Lane B (Streetscape): chunk-streamed walkable town shell
First-person shell: chunk streaming, instanced buildings + facade texture atlas
(22 facade materials -> 1; 5 skin materials city-wide), signs, awnings, furniture,
day/night lighting, minimap, pixel-accurate collision (incl. arbitrary-angle lots),
door raycast -> procity:enterShop, DBG harness, all-fallback mode. Renders Lane A's
full generated town (seed 20261990 'Boolarra Heads', 493 shops); worst continuous-
walk view ~261 draws (<=300 gate). 6 adversarial-review bugs fixed (collision sign,
house doors, awning skin, sign atlas, furniture seed hash, shot-mode restore).

index.html and skins.js include Lane F's inline integration seam edits (marked
'[Lane F integration]'): interior/keeper/citizen wiring + facade filename fix.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 14:28:47 +10:00