Files
music-video-gen/flow-state/src/debug/battery.js
T
Dejvino cc8888077f Fix venue-gallery viz pins that show no viz
Ride + corridor showed no corridor: with a room present the viz plays on its screens (radio/window/wall), so a dark model viz on the Ride's dash radio is invisible, and the shared rig was filming it through the room camera grammar meant for another world (directCamera rooms now keep the subject grammar + viz framing). Battery pins switched to combos that visibly read (Chamber + Kaleido, Stage + Assembly); scenario text states the visibility rule so a dead pin can't hide again.
2026-09-20 17:28:34 +02:00

167 lines
6.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// The vis testing battery as a library.
//
// Every manual testing entry point this project has — bank songs, scenes by
// family, venues, param/scenario combos, the throwaway lab pages and the
// headless CLI runners — collected in one place so debug.html (and anything
// headless later) renders them from the live registries instead of a stale
// hardcoded list. Adding a song, scene or venue updates the battery for free.
//
// Pure URL builders + data: no DOM, no WebGL, no wall-clock. Safe to import
// anywhere, including node (nothing here touches metadata.json, which needs
// Vite's JSON handling — so scene *coverage* is deliberately not imported).
import { SONGS } from '../audio/songbank.js';
import { scenes } from '../scenes/registry.js';
import { venues } from '../venues/registry.js';
const q = (params) => {
const p = new URLSearchParams();
for (const [k, v] of Object.entries(params)) {
if (v === null || v === undefined || v === '') continue;
p.set(k, String(v));
}
const s = p.toString();
return s ? `?${s}` : '';
};
export const songNames = () => SONGS.map((s) => s.name);
export const songCovers = (name) =>
(SONGS.find((s) => s.name === name) || {}).covers || '';
export const sceneNames = () => scenes.map((s) => s.name);
export const venueNames = () => venues.map((v) => v.name);
export const families = () => {
const out = [];
for (const s of scenes) if (!out.includes(s.family)) out.push(s.family);
return out;
};
export const scenesIn = (family) =>
scenes.filter((s) => s.family === family).map((s) => s.name);
/** App links for a bank song: plain, with venue, pinned seeds. */
export const appLinks = (song) => ({
app: `/${q({ song })}`,
venue: `/${q({ song, venue: 1 })}`,
seed1: `/${q({ song, seed: 1 })}`,
seed2: `/${q({ song, seed: 2 })}`,
});
/** Per-scene links: acceptance battery + wide single-scene gallery. */
export const sceneLinks = (name) => ({
gate: `/checks.html${q({ scene: name })}`,
wide: `/gallery.html${q({ scene: name, songs: 6, seeds: 6 })}`,
});
/** Per-venue links: gallery pinned to the venue, app + filmstrip with venue. */
export const venueLinks = (name) => ({
gallery: `/venue-gallery.html${q({ venueSel: name })}`,
app: `/${q({ song: 'centre', venue: 1 })}`,
filmstrip: `/filmstrip.html${q({ song: 'centre,ember', venue: 1, venueSel: name })}`,
});
/**
* Curated param/scenario combos: each is one question with the links that
* answer it. Songs are corners of the feature space (see songbank.js
* `covers`); pairs differ in exactly one control where possible.
*/
export const SCENARIOS = [
{
title: 'venue A/B, same song',
desc: 'Does the room earn its place? Same seed both sides — only the venue differs.',
links: [
['no venue', `/${q({ song: 'centre', seed: 7 })}`],
['venue', `/${q({ song: 'centre', seed: 7, venue: 1 })}`],
],
},
{
title: 'seed reroll, same song',
desc: 'Same music, two draws. Should read as two videos, not two grades of one.',
links: [
['seed 1', `/${q({ song: 'ember', seed: 1 })}`],
['seed 2', `/${q({ song: 'ember', seed: 2 })}`],
],
},
{
title: 'tempo ends',
desc: '62bpm beatless vs 174bpm broken. Motion should follow the song, not the scene.',
links: [
['drone 62', `/${q({ song: 'drone' })}`],
['runner 174', `/${q({ song: 'runner' })}`],
],
},
{
title: 'degenerate case',
desc: 'Two sections. Must not break — still is the regression test for it.',
links: [['still', `/${q({ song: 'still' })}`]],
},
{
title: 'hostile cases',
desc: 'Limitered, noisiest, brightest: the corners that collapse palettes and directors.',
links: [
['slab (flat)', `/${q({ song: 'slab' })}`],
['grit (noise)', `/${q({ song: 'grit' })}`],
['flare (bright)', `/${q({ song: 'flare' })}`],
],
},
{
title: 'most sections',
desc: 'Lattice rotates rosters the hardest. Watch for A/B ping-ponging and repeats.',
links: [['lattice', `/${q({ song: 'lattice' })}`]],
},
{
title: 'venue × viz pins',
desc: 'One room, chosen viz in it: fragment viz play on the room\u2019s screen, model viz stand in the shared world. Combos picked so the viz actually reads — a dark or sparse viz on a small screen is invisible, which is how a dead pin hides. (Ride is excluded: its viz lives on the dash radio, too small to review here.)',
links: [
['Chamber + Kaleido', `/venue-gallery.html${q({ venueSel: 'Chamber', viz: 'Kaleido Tunnel', rows: 2, cols: 3 })}`],
['Stage + Assembly', `/venue-gallery.html${q({ venueSel: 'Stage', viz: 'Assembly', rows: 2, cols: 3 })}`],
],
},
{
title: 'filmstrip with venue',
desc: 'Does the room hold for two minutes, or does it drift, flash, or empty out?',
links: [
['centre + ember', `/filmstrip.html${q({ song: 'centre,ember', venue: 1 })}`],
],
},
{
title: 'fresh scene gates',
desc: 'The per-scene battery for the scenes most recently touched.',
links: [
['Swarm', `/checks.html${q({ scene: 'Swarm' })}`],
['Assembly', `/checks.html${q({ scene: 'Assembly' })}`],
['Pylon Field 3D', `/checks.html${q({ scene: 'Pylon Field 3D' })}`],
],
},
];
/**
* The graduated throwaways: single-purpose lab pages plus the headless
* runners that drive them. Linked, not duplicated — the pages stay where
* the runners expect them.
*/
export const LABS = [
{
title: 'ride lab',
href: '/ride-lab.html',
desc: 'One Ride, four inspection cameras. Settles which way the car faces.',
cli: 'node ride-lab-run.mjs',
},
{
title: 'passerby lab',
href: '/passerby-lab.html',
desc: 'Hunts a seed with a passerby cue on elegy, renders the shot head/mid/tail.',
cli: null,
},
{
title: 'ride closeup',
href: '/venue-gallery.html?rows=1&cols=1&venueSel=Ride',
desc: 'Wheels + beams at 2×. Same framing the closeup runner screenshots.',
cli: 'node ride-closeup.mjs',
},
{
title: 'venue gate loop',
href: null,
desc: 'Headless Chromium against vite dev: phases, filmstrip, gallery, variety. Screenshots to logs/venue/.',
cli: 'node tools/venue-check.js --quick',
},
];