From a0b578477c22317906677a246afaf2736aa6c315 Mon Sep 17 00:00:00 2001 From: m3ultra Date: Thu, 16 Jul 2026 10:11:53 +1000 Subject: [PATCH] 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 --- docs/LANES/LANE_B_NOTES.md | 38 ++++++++++++++++++++++++++++++++++++++ web/js/world/venue.js | 15 ++++++++++++++- 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/docs/LANES/LANE_B_NOTES.md b/docs/LANES/LANE_B_NOTES.md index 414ac09..917f173 100644 --- a/docs/LANES/LANE_B_NOTES.md +++ b/docs/LANES/LANE_B_NOTES.md @@ -1,5 +1,43 @@ # LANE B — NOTES (measured) +## Round 15 (Fable's ROUND15 → Lane B) — verify the hero after A's poster flip (v3.0 release) + +Task: re-verify `queue_night` after A's ledger-#1 flip (`35da83c`: `buildPosters` item 1 → `+sin,+cos` +street face, `ry = lot.ry + π`; gig golden re-pinned `0x1f636349 → 0x4f4a549d`, synthetic frozen). + +**A's placement is correct — verified.** The pub's own-frontage poster moved from **15.9 m behind the +building** (R13/R14) to **0.09 m from the door on the +Z street face**, facing the reader (A's `ry+π` +composes with venue.js's `+π` render → the printed face points along the street outward normal, name +not mirrored). No pose change needed — my R14 prediction held. + +**But a night-lighting gap surfaced (and John sanctioned the fix).** Posters are unlit +`MeshStandardMaterial` (emissive `000000`); nothing illuminates them at night (marquee/pools/glow are +emissive *materials*, not lights). Measured the frontage poster centre pixel: **DAY `[183,71,59]` +(vivid) → NIGHT `[4,0,1]` (pure black)** — so `queue_night` (seg 5) still framed no readable bill, the +very thing A's golden move was for; `district_posters` was dark for the same reason. **Fix (venue.js, +John-sanctioned exception to the R14 freeze):** posters get `emissiveMap = ` + +`emissive = white`, `emissiveIntensity` **ramped in `update()` by night** (0 by day → 0.55 at night, +same lerp as the glow/pools). Self-lights the bill after dark; **daylight stays byte-identical** +(emissive 0 → verified the midday SCREAMING UTES spine poster is pixel-unchanged, no glow/wash). No new +rng, no plan change, goldens untouched (`0x3fa36874` / `0x4f4a549d` both frozen). `?noassets` fallback +poster self-lights too (its canvas exists, zero fetch). + +Verified fresh Chromium, seed 20261990: +- **`queue_night`** (seg 5, live queue spawned): marquee + window glow + streetlamp pools + **readable + red poster by the door** + queue punters + dark CLOSED neighbours. 90 draws / 29k tris. +- **`district_posters`** (seg 5): a venue poster now reads on the spine (was black). 180 draws / 138k tris. +- **Daylight** spine poster: byte-identical to R13/R14 (day emissive ramps to ~0). `venue_night` reads. +- Spine posters face the street everywhere (A's flip only moved item-1 frontage posters; item-2 pole + posters unchanged, still readable). + +**→ Lane F (B→F handshake): HERO VERIFIED.** `queue_night` frames queue + marquee + A's now-visible +poster; drive the queue live in `tour_shots.py` (the rAF is throttled in automation — I spawn D's +`VenueQueue` manually to preview). Shoot at **seg 5 (NIGHT)** — the poster now reads there (fix above), +and night is required for the pools + window glow. Poster night-readability is on venue.js's `update()` +ramp, so the shell's per-frame `venuePresentation.update(gigState.byVenue)` already drives it. + +--- + ## Round 14 (Fable's ROUND14 → Lane B) — v3.0 RELEASE: alias retirement + the tour audit Release round — no new systems. Three B files touched (`audio.js`, `venue.js`, `dbg.js`); no world diff --git a/web/js/world/venue.js b/web/js/world/venue.js index 0abda2a..978b8f0 100644 --- a/web/js/world/venue.js +++ b/web/js/world/venue.js @@ -50,6 +50,7 @@ export function createVenuePresentation(plan, skins, scene, { assetBase = 'asset // pick ONE seeded skin per gig, and render each group as a single InstancedMesh. Town-wide the whole // poster layer is ≤ (tonight's playing venues) draws instead of one mesh + one canvas per bill. let posterDraws = 0; + const posterMats = []; // ramped emissive at night (R15 ledger #1 completion) so posters read after dark { const byGig = new Map(); for (const p of posters) { @@ -63,7 +64,11 @@ export function createVenuePresentation(plan, skins, scene, { assetBase = 'asset const band = gig ? gig.bandName : 'LIVE TONIGHT'; const skin = POSTER_SKINS[(((gid | 0) + (plan.citySeed >>> 0)) % POSTER_SKINS.length + POSTER_SKINS.length) % POSTER_SKINS.length]; const tex = posterTexture(assetBase, skin, band, NOASSETS); disposables.push(tex); - const mat = new THREE.MeshStandardMaterial({ map: tex, roughness: 0.92, metalness: 0, side: THREE.DoubleSide }); + // emissiveMap = the poster art, ramped 0 (day) → ~0.55 (night) in update(): posters are otherwise + // unlit MeshStandard and render pure black at NIGHT (measured [4,0,1]), so the queue_night hero and + // district_posters showed no readable bill after A's +Z flip. Day stays byte-identical (emissive 0). + const mat = new THREE.MeshStandardMaterial({ map: tex, emissive: new THREE.Color(0xffffff), emissiveMap: tex, emissiveIntensity: 0, roughness: 0.92, metalness: 0, side: THREE.DoubleSide }); + posterMats.push(mat); const geo = new THREE.PlaneGeometry(POSTER_W, POSTER_H); disposables.push(mat, geo); const inst = new THREE.InstancedMesh(geo, mat, list.length); @@ -224,6 +229,14 @@ export function createVenuePresentation(plan, skins, scene, { assetBase = 'asset if (Math.abs(poolT - poolMat.opacity) < 0.004) poolMat.opacity = poolT; if (poolMesh) poolMesh.visible = poolMat.opacity > 0.01; } + // posters self-light at night so the bill reads (unlit MeshStandard → black after dark). Day = 0, + // so daylight tour shots stay byte-identical; the ramp lifts every poster (frontage + spine) at night. + const posterT = night ? 0.55 : 0; + for (let i = 0; i < posterMats.length; i++) { + const pm = posterMats[i]; + pm.emissiveIntensity += (posterT - pm.emissiveIntensity) * 0.1; + if (Math.abs(posterT - pm.emissiveIntensity) < 0.004) pm.emissiveIntensity = posterT; + } } update(null); // seed: no gig states yet → every venue quiet (frontage dark, pools follow night)