Phase 10: variety, twelve scenes, and tooling to write the next one

Watching several finished tracks side by side turned up the problem neither
Phase 8 (too few cuts) nor Phase 9 (no through-line) addressed: the same
scene cast in two different videos looked like the same footage twice.
Section bias is nearly identical between two tracks' drops, so both sampled
their parameters around the same centre, and the library's own averageness
did the rest.

Three answers, none of them a new scene:

  Temperament — a per-track hand on every parameter dial: intensity, pace,
  detail, and an extremity that decides how far toward the ends of a range
  the track is willing to sample. Bias comes from the section and is shared
  between tracks; temperament comes from the track and is not.

  Overlays — sometimes a second full scene composited over the shot, from a
  different family, in a blend that preserves what is underneath and never
  above 0.6 opacity. Not always: a stack that always doubled up would read
  as permanently cluttered rather than as occasionally layered.

  A wider palette — hue now derives from SPECTRAL TILT, the log ratio of
  treble to body. The centroid is a number most masters sit in the middle
  of, and the plain body/(body+treble) fraction is worse: low frequencies
  carry most of the energy in all music, so it read 0.98-1.00 for
  everything and four different battery tracks came out within 0.02 of
  each other. The ratio is multiplicative, so its logarithm is what
  spreads — the same four measure -9.3, -5.0, -4.1, -3.8. Also both ways
  round the wheel (violet, magenta and pink were unreachable by
  construction), four new schemes, and seeded chroma profile and lightness
  curve. Closest battery pair went from 0.005 to 0.113.

Twelve scenes take the library to 36, six per family: Aurora Veil, Vortex
Drift, Tide Rings, Ink Bleed, Dust Chamber, Salt Flat, Cargo Belt, Gate
Corridor, Circuit Bloom, Truchet Fold, Signal Decay, Storm Rift. Weighted
toward the 'space' and 'shape' traits, which were thinnest and so the
signatures most likely to run a track out of cast — the Phase 9 casting
rule means the pool a track draws from is smaller than the library.

Also fixes a real one in shots.js: heavy LRU weighting was not enough to
make a section reach its whole roster, and a five-shot section still came
out 0,2,0,2,0 about a fifth of the time. An unseen companion now wins
outright; which one is still free, so only the coverage is guaranteed.

Block Mosh declared the camera trait, assigned sigCamera(p) to a p it then
never read, and passed the lint's evidence grep. The Phase 9 render gate
measured its response to the camera at exactly zero.

--- tooling ---

Adding a scene was mostly boilerplate and round-trips, which is expensive
in both senses. The irreducible cost is the shader body; everything around
it is now mechanical:

  npm run new:scene -- "Name" --family=... --traits=...

writes the module, registers it, and leaves a skeleton that already passes
every gate, with name-derived constants so two skeletons are not twins.

The lint grew the rules that previously needed a GPU to catch: the dead
camera above, prev() with no base image, and large loops with no early
break (with a `// lint: fixed-cost` opt-out for a genuinely fixed-cost
sampling loop). checks.html?scene=Name runs the per-scene acceptance
battery for one scene — ten lines and a verdict instead of rendering the
whole library to find out whether one shader is alive. The same procedure
is a repo skill under .claude/skills/build-visualizer/.

--- checks changed, with the measurements ---

P5 determinism compared two WebGL CONTEXTS, which is not what it is for.
Measured: one context is bit-exact over 40 frames with feedback at 0.6;
two contexts disagree by up to 2/255 whether feedback is on or off. It now
asserts generation is byte-identical (hard) and rendering within 2/255,
since feedback compounds single-level variance.

P10's cross-track comparison measures distance RELATIVE to how much image
there is. Most scenes are mostly dark, so two genuinely different renders
— 25 bars against 53 — scored under 0.02 absolute purely because the black
background agrees with itself.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Dejvino
2026-08-05 23:59:20 +02:00
co-authored by Claude Opus 5
parent 0ee7a6a3b3
commit 2806ef1386
31 changed files with 2275 additions and 76 deletions
+51
View File
@@ -528,6 +528,57 @@ to draw a hexagon should not appear in the hexagon video.
- **Watch the battery.** The target is that a viewer could name the through-line on a second
viewing — not the first. No metric expresses that.
### Phase 10 — variety
The third finding from watching real tracks, after Phase 8 (too few cuts) and Phase 9 (no
through-line): **the same scene cast in two different videos looked like the same footage
twice.** Section bias is nearly identical between two tracks' drops, so both sampled their
parameters around the same centre, and the library's own averageness did the rest.
Three answers, none of them a new scene:
- **Temperament.** A per-track hand on every parameter dial — intensity, pace, detail, and an
*extremity* that decides how far toward the ends of a range the track is willing to sample.
Bias comes from the section and is shared; temperament comes from the track and is not.
- **Overlays.** Sometimes a second full scene is composited over the shot at partial opacity,
from a different family, in a blend that preserves what is underneath. Not always — a stack
that always doubled up would read as permanently cluttered rather than as occasionally
layered.
- **A wider palette.** Hue derives from **spectral tilt** — the log ratio of treble to body —
rather than the centroid or a plain body fraction. Both of those collapse: the centroid is a
number most masters sit in the middle of, and low frequencies carry most of the energy in
all music, so the plain fraction read 0.98-1.00 for everything and four different battery
tracks came out within 0.02 of each other. The ratio is multiplicative, so its logarithm is
what spreads. Plus: both ways round the wheel (violet, magenta and pink were previously
unreachable by construction), four new schemes, and seeded chroma profile and lightness
curve.
The library also grew to **36 scenes, six per family** — depth matters more than it looks,
because the Phase 9 casting rule means the pool a given track draws from is smaller than the
library.
**Gate:**
- Temperaments spread across a battery rather than collapsing to one value.
- One scene rendered under two tracks' parameters differs — measured RELATIVE to how much
image there is, because most scenes are mostly dark and an absolute frame distance scores
two genuinely different sparse renders as nearly identical.
- Overlays occur on 5-55% of stacks, never at `normal` blend, never above 0.6 opacity.
- Every sixth of the colour wheel is reachable across a sampled population, and two tracks
that sound different do not get the same palette.
### Tooling, added with Phase 10
Adding a scene was mostly boilerplate and round-trips, which is expensive in both senses.
- `npm run new:scene -- "Name" --family=… --traits=…` writes the module, registers it, and
leaves a skeleton that already passes every gate (with name-derived constants, so two
skeletons are not identical to each other).
- The lint grew the rules that used to need a GPU to catch: a **dead camera**
(`p = sigCamera(p)` and then nothing reads `p` — a real scene shipped like that and the
Phase 9 render gate measured its response at exactly zero), `prev()` with no base image, and
large loops with no early break (with a `// lint: fixed-cost` opt-out).
- `checks.html?scene=Name` runs the per-scene acceptance battery for ONE scene: ten lines and
a verdict, instead of rendering the whole library to find out whether one shader is alive.
- `.claude/skills/build-visualizer/` is the same procedure as a repo skill.
---
## 10. Detachment from `party-stage`