Two devices that were built, wired up, and doing nothing. OVERLAYS. buildStack gated layering on `surfaceOf(m) === 'composable'`, and no scene in the library declared `surface` — so the only thing that could ever sit on top was the one scene declaring `role: 'accent'`, and the overlay roster excluded accents by construction. Empty intersection, every time: 0/144 stacks carried an overlay. Every layered frame in every song was the same particle field. Labelled the library from the phase 12 coverage gate rather than by eye: the 37 scenes painting under 30% of the frame are composable. Particle Field loses its privileged slot and becomes one of them, keeping only `background: false`, which is the honest part — points in empty space cannot carry a section alone. The reserved accent slot is gone; one roster, two passes at it. 1 distinct overlay scene becomes 27, and the rate lands at 34% of stacks after trimming a base chance that had been tuned while the branch was dead. THE CAMERA. framing.shift moved the frame by a median of 0.029 of a half-frame at a fresh random angle every shot, so successive offsets cancelled and the median jump at a cut was 0.014. Present in every frame, visible in none. look/Camera.js is the director's camera department: the story says tension, order and which act a section is in, and this turns that into where the frame looks and how it travels there. Each director names a camera. Jump distance follows tension and act, speed follows energy, and the curve is one of four. Cuts choose between reframing and matching, so two scenes can still read as one place. Median offset 0.190, median reframe 0.135, and 94% of shots now move during the shot rather than only at the cut. Four new gates, each with a FLOOR — the device this replaces passed every existing check while doing nothing, because the only bound was a ceiling. Also lands the in-progress Epic 4 story layer it builds on: Story.js, phase 13, and the direction statistic. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
197 lines
9.4 KiB
HTML
197 lines
9.4 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<title>flow-state · debug</title>
|
|
<style>
|
|
:root { color-scheme: dark; }
|
|
body {
|
|
margin: 0; padding: 24px 24px 80px;
|
|
background: #0b0d12; color: #d6dae3;
|
|
font: 13px/1.6 ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
}
|
|
h1 { font-size: 15px; letter-spacing: .12em; text-transform: uppercase; color: #7d8698; margin: 0 0 6px; }
|
|
h2 { font-size: 12px; letter-spacing: .1em; text-transform: uppercase; color: #6b7280; margin: 26px 0 10px; font-weight: 600; }
|
|
p.lede { color: #8b94a7; max-width: 80ch; margin: 0 0 8px; }
|
|
a { color: #7dd3fc; text-decoration: none; }
|
|
a:hover { text-decoration: underline; }
|
|
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(330px, 1fr)); gap: 10px; }
|
|
.card {
|
|
background: #11141b; border: 1px solid #1c2030; border-radius: 4px;
|
|
padding: 12px 14px; border-left: 3px solid #2a3040;
|
|
}
|
|
.card.slow { border-left-color: #eab308; }
|
|
.card.fast { border-left-color: #22c55e; }
|
|
.card.cli { border-left-color: #6366f1; }
|
|
.card h3 { margin: 0 0 4px; font-size: 13px; }
|
|
.card p { margin: 0 0 8px; color: #8b94a7; font-size: 12px; }
|
|
.card .meta { color: #565f70; font-size: 11px; }
|
|
code, pre {
|
|
background: #080a0f; border: 1px solid #1a1e28; border-radius: 3px;
|
|
padding: 1px 5px; color: #b8c0d0; font-size: 12px;
|
|
}
|
|
pre { padding: 8px 10px; overflow-x: auto; margin: 6px 0 0; }
|
|
.note { color: #6b7280; font-size: 12px; max-width: 80ch; }
|
|
.warn { color: #eab308; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<h1>flow-state · debug</h1>
|
|
<p class="lede">
|
|
Everything here answers a question the app itself cannot. The app shows you
|
|
one video; these show you whether the generator is doing its job across
|
|
many.
|
|
</p>
|
|
|
|
<h2>Looking at output</h2>
|
|
<div class="grid">
|
|
<div class="card fast">
|
|
<h3><a href="/gallery.html">gallery</a></h3>
|
|
<p>Every visualizer, six times, on six different songs' content — cast,
|
|
ink, lattice, palette and parameters all varying. Sorted least-varied
|
|
first, so the scenes that always look the same come to the top.</p>
|
|
<div class="meta">~3 min · the one to open when a scene feels familiar ·
|
|
<code>HOWTO-variety.md</code> for how to fix what it finds</div>
|
|
</div>
|
|
<div class="card">
|
|
<h3><a href="/filmstrip.html">filmstrip</a></h3>
|
|
<p>Every song in the bank, one frame every 30 seconds, left to right.
|
|
The gallery asks whether a scene looks the same in every song; this
|
|
asks whether a song looks the same as itself four minutes later.
|
|
Scored on <code>direction</code> — whether the distance between two
|
|
frames grows with the time between them — so the videos that are busy
|
|
and going nowhere sort to the top.</p>
|
|
<div class="meta">~6 min, then cached · <a href="/filmstrip.html?every=15">?every=15</a> tighter ·
|
|
<a href="/filmstrip.html?song=centre,ember">?song=</a> just these ·
|
|
<code>EPIC-4.md</code> for the arc it is checking</div>
|
|
</div>
|
|
<div class="card fast">
|
|
<h3><a href="/">the app</a></h3>
|
|
<p>Drop a track and watch it. <code>test/songs/*.wav</code> holds the
|
|
synthetic bank if you want something with known properties.</p>
|
|
<div class="meta">build the bank with <code>npm run build:songs</code></div>
|
|
</div>
|
|
</div>
|
|
|
|
<h2>Is it correct?</h2>
|
|
<div class="grid">
|
|
<div class="card fast">
|
|
<h3><a href="/checks.html">phase gates</a></h3>
|
|
<p>Every acceptance gate in <code>PLAN.md</code>, run for real. This is
|
|
the one to check before committing.</p>
|
|
<div class="meta">
|
|
<a href="/checks.html?slow=1">?slow=1</a> full suite ·
|
|
<a href="/checks.html?phase=12">?phase=12</a> one phase
|
|
</div>
|
|
</div>
|
|
<div class="card fast">
|
|
<h3>single scene</h3>
|
|
<p>The whole per-scene battery for one visualizer: renders, animates,
|
|
deterministic, distinct, param sweep, flash rate, and every declared
|
|
trait and artifact.</p>
|
|
<div class="meta"><code>checks.html?scene=Metaballs</code> — the loop you
|
|
are in while writing or migrating one</div>
|
|
</div>
|
|
</div>
|
|
|
|
<h2>Is it varied?</h2>
|
|
<p class="note">
|
|
These measure whether two videos differ, which no other gate can see — a
|
|
generator that ignores its input passes determinism and liveness perfectly.
|
|
<span class="warn">Read the caution below before trusting a single run.</span>
|
|
</p>
|
|
<div class="grid">
|
|
<div class="card slow">
|
|
<h3><a href="/checks.html?decompose=1">decompose</a></h3>
|
|
<p>Identity against container, measured apart: hold the scene fixed and
|
|
vary the song's content, then the reverse. <strong>The most
|
|
trustworthy number here</strong> — it compares renders directly, and
|
|
its noise floor is exactly zero.</p>
|
|
<div class="meta">~1 min</div>
|
|
</div>
|
|
<div class="card slow">
|
|
<h3><a href="/checks.html?songs=1&count=12">song variety</a></h3>
|
|
<p>Twelve songs from the bank, each with its own audio-derived seed. Also
|
|
reports coupling — whether songs that <em>sound</em> different come
|
|
out <em>looking</em> different, which is still unsolved.</p>
|
|
<div class="meta">~2 min · <a href="/checks.html?variety=1">?variety=1</a>
|
|
for the seed version, one song and many seeds</div>
|
|
</div>
|
|
<div class="card slow">
|
|
<h3><a href="/checks.html?experiment=1&count=12&repeats=3">arms, with error bars</a></h3>
|
|
<p>Three pools compared over repeated runs. The template for any A/B
|
|
here: it prints the difference against its own noise band and says
|
|
outright when the two are indistinguishable.</p>
|
|
<div class="meta">~5 min</div>
|
|
</div>
|
|
<div class="card slow">
|
|
<h3><a href="/checks.html?sweep=1&count=12&sizes=4,8,16,32&repeats=3">pool sweep</a></h3>
|
|
<p>How many scenes a track should draw on. Swept rather than guessed —
|
|
and the answer turned out to be that it does not matter between 4 and
|
|
32.</p>
|
|
<div class="meta">~5 min</div>
|
|
</div>
|
|
</div>
|
|
|
|
<h2>Command line</h2>
|
|
<div class="grid">
|
|
<div class="card cli">
|
|
<h3>migration status</h3>
|
|
<p>Which scenes draw the song's content, which still draw their own, and
|
|
what each remaining one needs. Recipe in <code>MIGRATION.md</code>.</p>
|
|
<pre>node tools/migration-status.js</pre>
|
|
</div>
|
|
<div class="card cli">
|
|
<h3>cast census</h3>
|
|
<p>Which visualizers actually get cast, across songs and seeds — and for
|
|
the ones that do not, which of the four gates killed them.</p>
|
|
<pre>node tools/cast-census.js 12 40</pre>
|
|
</div>
|
|
<div class="card cli">
|
|
<h3>identity census</h3>
|
|
<p>How far apart the songs' identities are before anything is rendered.
|
|
No GPU. Run this before blaming the visualizers.</p>
|
|
<pre>node tools/identity-census.js 12</pre>
|
|
</div>
|
|
<div class="card cli">
|
|
<h3>song bank</h3>
|
|
<p>Rebuild the test songs and verify they still span every feature the
|
|
generator reads. Fails loudly if an axis has collapsed.</p>
|
|
<pre>npm run build:songs
|
|
npm run check:songs</pre>
|
|
</div>
|
|
<div class="card cli">
|
|
<h3>static gates</h3>
|
|
<p>Determinism grep, schema/shader agreement both ways, and the backtick
|
|
check that guards the shader template literals.</p>
|
|
<pre>npm run lint:scenes
|
|
npm test</pre>
|
|
</div>
|
|
</div>
|
|
|
|
<h2>Reading the variety numbers</h2>
|
|
<p class="note">
|
|
This harness has two classes of measurement and only one of them is safe to
|
|
steer by. <strong>Direct render comparisons</strong> — the gallery score,
|
|
<code>decompose</code>, the per-scene gate — have a noise floor of zero and
|
|
mean what they say. <strong>Aggregate ratios</strong> — chiefly
|
|
<code>separation</code>, which divides one small difference by another —
|
|
swing wildly between runs: three runs of the same measurement gave 0.31,
|
|
0.56 and 0.07. Four conclusions were drawn and withdrawn during this epic
|
|
for exactly that reason. Anything under about 0.01 of spread needs
|
|
<code>&repeats=3</code> before it is believed, and a difference that
|
|
changes sign with the sample is not a difference.
|
|
</p>
|
|
|
|
<h2>If a page is dead</h2>
|
|
<p class="note">
|
|
A module that fails to load takes the whole graph with it: the page renders,
|
|
every control is present, and nothing is wired to anything. The app carries a
|
|
boot guard that says so. The usual causes are a content blocker — a file
|
|
named like tracking will be treated as tracking, which cost this project a
|
|
session over a file called <code>clicktrack.js</code> — or a dev server
|
|
caught mid-restart.
|
|
</p>
|
|
</body>
|
|
</html>
|