ef1d24e692
5 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
89277705c4 |
Nothing is held for two minutes, not even one visual
planShots skipped cut planning entirely when a section had a single visual to show — "nothing to cut to" — and the exemption swallowed the ceiling with it. Adding a scene shifted the casting enough to land a 150 BPM track in that case, and it held one image for 151.98 seconds against a 22-second limit. Any new scene could have exposed it; the shot-length gate had simply never met a single-visual section before. The premise was wrong rather than the arithmetic. A shot boundary changes the FRAMING as well as the image, so the same visual filmed again at another size is a shot, and the ceiling is about how long one image is held rather than about how many images a section has. Single-visual sections now plan shots like any other. What the single case still suppresses is the hard cut: cutting straight between two framings of one image is a jump cut, so those boundaries always dissolve. Two intermediate versions were wrong in ways worth not repeating: splitting the section into equal spans put a 23.5s shot past the ceiling once the cuts snapped to downbeats, and read as a metronome (cv 0.048) to the rhythm check. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
1ca9fa2f1f |
Let scenes layer on each other, and give the camera somewhere to look
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> |
||
|
|
f050eaaad1 |
Epic 2.1: cut on a phrase, not on a metronome
planShots picked a bar count once per section and then divided the section into that many equal pieces. Measured, a five-minute track at 90 BPM came out as sixteen shots of 19.3, 18.7, 18.7, 18.7 ... 18.7, 19.3 seconds — every cut for five minutes landing on the same pulse. No amount of variety in what the shots contain fixes that, because the fatigue is in the timing. A section now carries a repeating RHYTHM PATTERN in bars — [8,8,16], [4,4,4,8] and friends, picked by energy — walked in order and repeated. The same track now cuts 10.7, 10.7, 21.3, 10.7, 10.7, 21.3: two quick shots answered by a hold. At 150 BPM the louder second section moves to 6.4, 6.4, 6.4, 12.8. Repeating rather than random is the whole point, and it is why the gate comes in two halves. Random shot lengths would satisfy "lengths must vary" and look worse than a metronome, because the ear is following an eight-bar structure and the eye would not be. So one check demands spread and a second demands that the lengths come from a small recurring set. The ceiling is applied by scaling the whole pattern rather than clamping each entry: at 90 BPM a 16-bar hold is 42s and a 4-bar one is 10s, and clamping both to 22 restores the metronome the pattern exists to break. Downbeat snapping is now bounded to cuts that keep the shot legal — snapping to the merely-nearest line pushed a 22s shot to 22.75s, over the ceiling the pattern was fitted to respect. 366 of 370 cuts still land within three quarters of a beat of a downbeat. New Phase 11 gate (EPIC-2.md §4): metronome, phrasing, floor/ceiling, grid. 97/97 checks pass including the slow set. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
2806ef1386 |
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> |
||
|
|
ca5a68eb84 |
Phases 8 and 9: shots, and a production design per track
Both phases come out of the manual gate — watching whole tracks — and both
fix something no automated check was looking for.
Phase 8: shots. A section is a STAGE of the song and can run ninety
seconds; one scene held that long reads as a still image with a wobble on
it. Each section kind now gets a roster of three or four stage visuals
instead of one scene, and each section is cut into shots that rotate
between them on phrase lines, never holding past 22s. The roster stays per
kind, so a track's drops still cut between the same images and the video
keeps its identity; the anchor opens each section and the rotation returns
to it, and when a companion is due it is the least recently shown one.
The arc driver stopped working in sections and started working in cues, one
per shot, so a shot cut and a section change take the same code path and
differ only in transition length. The default transition is a slow
dissolve — two bars calm, one loud; a straight cut is reserved for
sections above the energy threshold, because on calm material a cut reads
as a glitch rather than as an edit.
Phase 9: production design. With cuts every fifteen seconds the next
problem was that the images being cut between shared nothing but the
palette. What a music video actually shares across shots is a location, a
cast, a camera operator and an art direction, so each track now generates a
personality in four traits (shape, camera, space, style) off the look seed.
The traits reach shaders as uniforms plus four helpers in the contract, and
each scene expresses them its own way: Classic Wave's rings take the
signature polygon, Metaballs merge as one, Floating Geometry no longer
picks between a box and a circle because the production already decided.
The part that makes it a design rather than a filter: scenes DECLARE which
traits they honour, a track is built on one or two, and a scene that does
not honour all of them is not cast in that track. The library shrinks per
track on purpose.
Two gates keep the declaration honest — lint greps each shader for evidence
of every trait it claims, and a render check measures that each declared
trait actually moves the image (41 scene/trait pairs, weakest response 64
of 255). A layer with no personality renders bit-identically to before,
which is what keeps every earlier sweep and regression valid.
Checks changed rather than added:
- P4 scene-change and drift checks now measure per shot, not per section;
the crossfade check reads its length off the cue.
- P5 flash sweep runs per shot, so the visuals that only appear
mid-section are measured too.
- P6 preview/export parity primes first (as both real paths do) and
compares at the one-LSB tolerance Phase 7 already uses. Measured over
four consecutive shows: 3 frames at delta 1, then bit-exact — GPU
variance on first render, not a divergence.
- P2's contract-uniform list is derived from the contract instead of
retyped, so the signature uniforms cannot fall out of sync.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|