Vis testing battery: library + debug page sections

Collects every manual testing entry point into one library (src/debug/battery.js) rendered from the live registries: all 17 bank songs with app/+venue/strip links, all 70 scenes grouped by family with gate/wide links, all 3 venues, 9 curated param and scenario combos, and the graduated lab pages with their headless runners. debug.html renders it; new songs/scenes/venues join free.
This commit is contained in:
Dejvino
2026-09-20 16:54:39 +02:00
parent a99a7cbe49
commit cd7dfcd63d
2 changed files with 329 additions and 0 deletions
+162
View File
@@ -33,6 +33,22 @@
pre { padding: 8px 10px; overflow-x: auto; margin: 6px 0 0; }
.note { color: #6b7280; font-size: 12px; max-width: 80ch; }
.warn { color: #eab308; }
.chips { display: flex; flex-wrap: wrap; gap: 6px; margin: 8px 0 2px; }
.chips a {
background: #080a0f; border: 1px solid #1a1e28; border-radius: 3px;
padding: 1px 7px; font-size: 12px; white-space: nowrap;
}
.chips a:hover { border-color: #7dd3fc; text-decoration: none; }
.chips .fam { width: 100%; color: #565f70; font-size: 11px; letter-spacing: .08em;
text-transform: uppercase; margin-top: 6px; }
.chips .fam:first-child { margin-top: 0; }
.links { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.links a {
background: #080a0f; border: 1px solid #1a1e28; border-radius: 3px;
padding: 1px 7px; font-size: 12px;
}
.links a:hover { border-color: #7dd3fc; text-decoration: none; }
.links .lbl { color: #565f70; font-size: 12px; align-self: center; }
</style>
</head>
<body>
@@ -43,6 +59,48 @@
many.
</p>
<h2>Vis testing battery</h2>
<p class="lede">
The testing library: every bank song, every scene, every venue, the
param/scenario combos worth re-running, and the lab pages. Rendered
from the live registries (<code>src/debug/battery.js</code>), so a new
song, scene or venue joins the battery for free.
</p>
<div class="grid">
<div class="card fast">
<h3>songs — the bank, one click each</h3>
<p>Each song holds a corner of the feature space (<code>covers</code>).
App loads the song; +venue adds the room; strip is one frame per
30 s across the whole song.</p>
<div id="battery-songs" class="chips"><span class="note">loading…</span></div>
</div>
<div class="card fast">
<h3>venues — every room</h3>
<p>Pinned gallery first (fastest way to review a venue change), then
the app and the filmstrip with the room on.</p>
<div id="battery-venues"><span class="note">loading…</span></div>
</div>
</div>
<h2>Scenes — every visualizer</h2>
<p class="note">
Gate is the per-scene acceptance battery (renders, animates,
deterministic, distinct, sweep, flash, traits); wide is the scene on
six songs × six seeds.
</p>
<div class="grid">
<div class="card fast">
<h3>by family</h3>
<div id="battery-scenes" class="chips"><span class="note">loading…</span></div>
</div>
</div>
<h2>Scenarios — params and combos</h2>
<div class="grid" id="battery-scenarios"></div>
<h2>Lab pages + headless runners</h2>
<div class="grid" id="battery-labs"></div>
<h2>Looking at output</h2>
<div class="grid">
<div class="card fast">
@@ -212,5 +270,109 @@ npm test</pre>
session over a file called <code>clicktrack.js</code> — or a dev server
caught mid-restart.
</p>
<script type="module">
import {
songNames, songCovers, families, scenesIn,
venueNames, appLinks, sceneLinks, venueLinks,
SCENARIOS, LABS,
} from '/src/debug/battery.js';
const el = (tag, cls, text) => {
const e = document.createElement(tag);
if (cls) e.className = cls;
if (text !== undefined) e.textContent = text;
return e;
};
const link = (href, text) => {
const a = document.createElement('a');
a.href = href;
a.textContent = text;
return a;
};
// Songs: one row per bank song — name, corner it holds, app / +venue / strip.
{
const host = document.getElementById('battery-songs');
host.replaceChildren();
for (const name of songNames()) {
const covers = songCovers(name);
const L = appLinks(name);
const row = el('span', 'fam', `${name} — ${covers} `);
host.appendChild(row);
host.appendChild(link(L.app, 'app'));
host.appendChild(link(L.venue, '+venue'));
host.appendChild(link(`/filmstrip.html?song=${encodeURIComponent(name)}`, 'strip'));
}
}
// Venues: pinned gallery + app + filmstrip per room.
{
const host = document.getElementById('battery-venues');
host.replaceChildren();
for (const name of venueNames()) {
const L = venueLinks(name);
const card = el('div', null);
card.appendChild(el('p', null, name));
const row = el('div', 'links');
row.appendChild(link(L.gallery, 'gallery'));
row.appendChild(link(L.app, 'app +venue'));
row.appendChild(link(L.filmstrip, 'strip'));
card.appendChild(row);
host.appendChild(card);
}
}
// Scenes: one chip per visualizer (→ gate), ◈ per scene (→ wide gallery).
{
const host = document.getElementById('battery-scenes');
host.replaceChildren();
for (const fam of families()) {
host.appendChild(el('span', 'fam', fam));
for (const name of scenesIn(fam)) {
const L = sceneLinks(name);
host.appendChild(link(L.gate, name));
const w = link(L.wide, '◈');
w.title = `${name} — wide gallery (6 songs × 6 seeds)`;
host.appendChild(w);
}
}
}
// Scenarios: curated cards from the library.
{
const host = document.getElementById('battery-scenarios');
host.replaceChildren();
for (const s of SCENARIOS) {
const card = el('div', 'card');
card.appendChild(el('h3', null, s.title));
card.appendChild(el('p', null, s.desc));
const row = el('div', 'links');
for (const [label, href] of s.links) row.appendChild(link(href, label));
card.appendChild(row);
host.appendChild(card);
}
}
// Labs: pages + the CLI that drives them.
{
const host = document.getElementById('battery-labs');
host.replaceChildren();
for (const lab of LABS) {
const card = el('div', 'card cli');
card.appendChild(el('h3', null, lab.title));
card.appendChild(el('p', null, lab.desc));
if (lab.href) {
const row = el('div', 'links');
row.appendChild(link(lab.href, 'open'));
card.appendChild(row);
}
if (lab.cli) {
const pre = el('pre', null, lab.cli);
card.appendChild(pre);
}
host.appendChild(card);
}
}
</script>
</body>
</html>