Venues: persistent room, motivated camera, ride; drop Pylon Grid

- Venue as one continuous place: persistent per-song layer, interpolated
  venueState, story jumps (one re-hang max + recap) with camera cuts
- Room camera shot plan (venueShots.js): per-section size/target, monotonic
  look sweep, traverse glide body, room-side alternation
- New Ride venue: generated vehicle + actor passengers, radio RTT screen,
  chase/stationary modes, ride archetype across generator/camera/staging
- Flora cost trim (5x(12+6+6) -> 4x(8+4+4) SDF evals, 204ms -> 140ms worst)
- Delete Pylon Grid shader (2.5s/frame SwiftShader); drop its metadata row
- tools/venue-check.js headless gate harness + venue-gallery explorer
This commit is contained in:
Dejvino
2026-09-17 19:35:26 +02:00
parent b1b6431eeb
commit 46fab512df
31 changed files with 3684 additions and 358 deletions
+32 -1
View File
@@ -52,8 +52,37 @@ const dom = {
exportWarnDontAsk: document.getElementById('ew-dontask'),
};
// Show owns the single WebGL2 context. three@0.181 throws when the browser
// blocks context creation (WebGL2 disabled, headless shell without
// SwiftShader) — historically a blank page, since this runs at module scope.
// Fail loudly into the boot-error box instead, with the cause and the fix.
function showBootError(detail) {
const box = document.getElementById('boot-error');
const pre = document.getElementById('be-detail');
if (pre) pre.textContent = detail;
if (box) box.hidden = false;
}
function bootShow() {
try {
return new Show({ canvas: dom.canvas, width: 1280, height: 720 });
} catch (err) {
const msg = err && err.message ? err.message : String(err);
showBootError(
'The WebGL renderer could not start, so nothing on this page can run — ' +
'every preview, gallery and check renders through the same context.\n\n' +
msg,
);
// Tell the boot guard the startup story is over (it would otherwise
// report its own generic text, clobbering the specific cause above),
// then stop: a half-running app with no renderer is worse than none.
window.__FLOW_STATE_READY__ = 'failed';
throw err;
}
}
const state = {
show: new Show({ canvas: dom.canvas, width: 1280, height: 720 }),
show: bootShow(),
playing: false,
quality: 'full',
loopSection: -1,
@@ -376,6 +405,7 @@ function renderPanel() {
<div class="kv"><span>tempo conf.</span><b>${show.track.tempo.confidence.toFixed(2)}</b></div>
<div class="kv"><span>duration</span><b>${formatTime(show.duration)}</b></div>
<div class="kv"><span>sections</span><b>${show.track.sections.length}</b></div>
<div class="kv"><span>venue</span><b>${show.look.venue ? `${show.look.venue.name} (${show.look.venue.archetype})${show.look.venueEnabled ? '' : ' · off'}` : 'off'}${show.arc && show.arc.state && show.arc.state.venueState ? ` · light ${show.arc.state.venueState.light.toFixed(2)} fog ${show.arc.state.venueState.fog.toFixed(2)} pop ${show.arc.state.venueState.popMul.toFixed(2)}` : ''}</b> <a href="#" id="link-venue-toggle" title="Toggle venue (ground) — ?venue=1 enables for this page">${show.look.venueEnabled ? 'disable' : 'enable'}</a> · <a href="/venue-gallery.html" target="_blank">gallery</a></div>
<div class="kv"><span>director</span><b>${show.look.director}${plan ? ` · ${plan.progression}` : ''}</b></div>
<div class="kv"><span>built on</span><b>${personality.signature.join(' + ') || 'nothing'}</b></div>
<div class="kv"><span>form</span><b>${personality.shape.sides || 'round'}${
@@ -413,6 +443,7 @@ function renderPanel() {
<div class="hint">Mixes clicks onto the detected beat grid. If they don't sit on
the beat, tempo detection is wrong and everything downstream inherits it.</div>`;
document.getElementById('btn-metronome').addEventListener('click', downloadClickTrack);
document.getElementById('link-venue-toggle')?.addEventListener('click', (e)=>{ e.preventDefault(); show.setVenueEnabled(!show.look.venueEnabled); renderPanel(); show.seek(show.timeline.frame, {warmup:false}); });
return;
}