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>
This commit is contained in:
m3ultra 2026-07-16 10:11:53 +10:00
parent 35da83c347
commit a0b578477c
2 changed files with 52 additions and 1 deletions

View File

@ -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 = <the poster art>` +
`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

View File

@ -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)