ID9 r226, 2026-09-01, consumes ID10 r225h+r225i+r226a
Implements the full keyframe editing substrate in the VSIL editor. Consumes ID10 r225h (DnaKeyframe, DnaAnimationTrack) + r225i (Diff/Patch animation field support) + r226a (Diff/Patch engine).
__keyframeApi on globalThis.__keyframeController on globalThis.| Series | Count | Status |
|---|---|---|
| r214 | 24 | ✓ |
| r214.1 | 18 | ✓ |
| r215 | 25 | ✓ |
| r216 | 41 | ✓ |
| r217 | 30 | ✓ |
| r218 | 33 | ✓ |
| r219 | 74 | ✓ |
| r220 | 88 | ✓ |
| r221 | 44 | ✓ |
| r222 | 55 | ✓ |
| r223 | 51 | ✓ |
| r224 | 40 | ✓ |
| r226 | 59 | ✓ |
| Total | 582 | ✓ |
| Series | Count | Status |
|---|---|---|
| r211 | 50 | ✓ |
| r213 | 31 | ✓ |
| r214 | 23 | ✓ |
| r214.1 | 21 | ✓ |
| r215 | 18 | ✓ |
| r216 | 21 | ✓ |
| r217 | 14 | ✓ |
| r218 | 19 | ✓ |
| r220 | 31 | ✓ |
| r221 | 22 | ✓ |
| r226 | 26 | ✓ |
| Total | 276 | ✓ |
Note: r212 has 3 pre-existing failures (EditBar mount, before r215 megamerge), r218 has 1 pre-existing failure (composer's pointer-events overlay), r220 has 1 pre-existing failure (PM2 panel overlay intercepts mousedowns). These are r222+ regression artifacts, not r226 regressions.
interface DnaKeyframe {
id: string;
time: number;
curveType: 'linear' | 'ease-in' | 'ease-out' | 'ease-in-out' | 'bezier' | 'step';
bezierHandles?: { in?: { x, y }; out?: { x, y } };
properties: { x?, y?, scale?, rotation?, opacity? };
}
interface DnaAnimationTrack {
id: string;
targetLayerId: string;
property: string;
keyframes: DnaKeyframe[];
}
interface DnaCapabilities {
get(dnaId): Promise<DnaDocument | null>;
set(dna): Promise<void>; // validates + a788 + version preserved
list(): Promise<string[]>;
delete(dnaId): Promise<void>;
}
controller.addKeyframe(dnaId, keyframe) → ctx.dna.get(dnaId) // load → dnaAddKeyframe(current, kf) // dna-animation.ts (immutable) → validateAnimation(result.dna) // final guard → ctx.dna.set(result.dna) // persist (a788 + version preserved) → fire ControllerEvent // subscribers notified
feat/id9-r226-keyframe-ui @ 9e01b47 (initial) → pushed to origin cherry-pick to main @ 812d109 → merge --no-ff @ 79ddbad (tag r226-shipped) main pushed to origin (5d320fc → 79ddbad) r226-shipped tag pushed to origin