Phase 4: arc driver ("C" brain)
Three timescales now stack: per-frame reactivity, per-section seeded LFO drift, and whole-song scene changes with lookahead. Layer instances are cached per section and reused across crossfades — rebuilding them per frame would recompile shaders every transition. Crossfades run forward from a boundary: the outgoing scene holds while the incoming one fades in over it. Three real bugs, each found by a check that had to be rewritten first: 1. A pop exactly at every transition. buildSlope is discontinuous by construction (~1 before a boundary, 0 after), and the outgoing layer is still on screen when it flips — collapsing its lookahead ramp in one frame. It now holds the slope it had entering the boundary. 2. FeatureTrack.at() returns a REUSED row object, and _boundarySlope() called at() again mid-render, rewriting the features the layer was about to read. Symptom: a frame correct on every repeat and wrong the first time — invisible to fresh-vs-fresh comparison, and wrong in every export, since export renders each frame exactly once. Now indexes the typed array directly, with the aliasing hazard documented on at(), and a new check covers the whole bug class. 3. Warm-up converged to 1%, leaving a visible 0.015 difference at heavy feedback settings. Now targets 0.1%. Two checks were themselves wrong and were rebuilt: a raw delta threshold and an outlier-vs-local-median test both flag beat flashes as pops, and a control window taken from a different scene reads an ordinary busy scene as a 9x spike. The working formulation A/Bs each boundary against the interior of the two scenes adjacent to it. PLAN.md §6 corrected: boundary seeks are NOT exact for free. Layer state is re-seeded there but the feedback buffer is global and carries across. Clearing it at boundaries would buy exactness for a visible flash at every transition; warm-up is the better trade and applies everywhere. Gate 9/9. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+17
-8
@@ -266,15 +266,24 @@ Stateful layers — feedback buffers, particle systems — mean frame *N* depend
|
||||
before it. Scrubbing to an arbitrary frame therefore can't be exact for free. Three-part
|
||||
resolution:
|
||||
|
||||
1. **Warm-up.** On seek, render *K* frames (default ≈120, about 2s) as fast as possible
|
||||
off-screen before displaying. Converges feedback state to visually correct.
|
||||
2. **Section-boundary seeks are exact.** Particle systems and layer state are re-seeded
|
||||
deterministically at each section boundary, so jumping to a boundary — the common review
|
||||
action — needs no warm-up and is frame-exact.
|
||||
3. **Export is always sequential**, so it is exact everywhere by construction.
|
||||
1. **Warm-up.** On seek, render *K* frames off-screen before displaying. *K* is computed
|
||||
from the feedback decay rather than fixed — the residual after *n* frames is `decay^n`,
|
||||
so `log(0.001)/log(decay)` frames converges to a tenth of a percent (96 frames at
|
||||
decay 0.93). A light-feedback look seeks almost instantly; a heavy one still lands.
|
||||
2. **Export is always sequential**, so it is exact everywhere by construction.
|
||||
|
||||
Documented consequence: scrubbing to a random mid-section frame shows a *converged*, not
|
||||
bit-exact, image. Reviewing a transition never hits this, because transitions are boundaries.
|
||||
> **Correction, made during Phase 4.** The original plan claimed section-boundary seeks
|
||||
> would be frame-exact with no warm-up, because layer state is re-seeded there. That is
|
||||
> wrong: layer state is only half the story, and the compositor's feedback buffer is
|
||||
> *global* — it carries straight across a boundary like any other frame. Making boundary
|
||||
> seeks exact would mean clearing feedback at every transition, which trades a cheap
|
||||
> warm-up for a visible flash on every scene change. Warm-up is the better trade, and it
|
||||
> applies everywhere rather than only mid-section. Measured: converges to a 0.00000 mean
|
||||
> difference. With feedback disabled, seeks are bit-exact anywhere, which is what proves
|
||||
> nothing *else* in the pipeline is carrying state.
|
||||
|
||||
Documented consequence: scrubbing shows a *converged*, not bit-exact, image whenever
|
||||
feedback is enabled — which is visually indistinguishable, and exact once feedback is off.
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user