fix(adapter-hyperframes): record real animation, not static end-state#60
Open
liyizhouAI wants to merge 1 commit into
Open
fix(adapter-hyperframes): record real animation, not static end-state#60liyizhouAI wants to merge 1 commit into
liyizhouAI wants to merge 1 commit into
Conversation
Under recordVideo's continuous capture the CSS freeze doesn't hold through the ~2-3s font wait: paused drifts on a font-display swap relayout, and single-file GSAP timelines (e.g. agent-generated frames) auto-play entirely outside the CSS freeze and finish during the wait. The -ss lead-in trim then slices the motion off, yielding a static end-state clip. - freeze: animation-play-state:paused -> animation:none (paused drifts on font-display swap relayout) - after goto: pause gsap.globalTimeline so single-file GSAP rests at frame 0 through the font wait (no-op without GSAP) - __hvUnfreeze: play(0) to release GSAP in sync with recording start (NOT seek(0); a completed tween ignores seek and never re-renders) - ffmpeg seek: probe the webm pixels (signalstats YMIN) for the real motion start -- recordVideo compresses the timeline (~0.7x), so a wall-clock leadInMs maps to the wrong spot Verified end-to-end: a 4-frame agent-generated vignelli video went from all-static (YMIN flat ~20) to each frame opening at frame 0 (YMIN ~210) and animating in.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
recordVideoproduced clips frozen on the animation's static end-state instead of the animation playing. Two distinct root causes:CSS-only freeze used
animation-play-state: paused. This drifts across the font-wait: a font-display swap triggers relayout mid-wait, the paused timeline drifts, and the animation actually plays during the font wait. The later lead-in trim (-ss seekSec) then slices it off -> static end-state clip.Single-file GSAP frames (e.g. agent-generated templates) bypass
__hvPlayAll. Theirgsap.timeline()auto-plays onDOMContentLoadedand is never registered paused, so the CSS freeze doesn't touch GSAP's rAF. The timeline plays out during the ~2-3s font wait and the recording captures only the end-state.Fix
4 changes in
packages/adapter-hyperframes/src/render.ts(+82 / -7):animation-play-state: paused->animation: nonenonefully removes the animation so elements rest at base (frame-0) style; no drift under font swapgoto: pausegsap.globalTimeline__hvUnfreeze: addgsap.globalTimeline.play(0)play(0)NOTseek(0)-- a completed tween ignoresseek(0)and never re-renderssignalstatsYMIN) instead of wall-clockleadInMsrecordVideocompresses the webm timeline (~0.7x), so a wall-clock-derivedseekSeclands at the wrong spot; reading pixels finds the real animation startVerification
Quantified with
ffmpeg signalstats YMIN(frame-darkest pixel; white bg ~210, ink ~20) on a 4-frame single-file-GSAP vertical (1080x1920) sequence:Notes / scope
render.tstouched; no public API change.__hvPlayAll) were not re-tested in this pass -- they were already on a working path; the freeze change is strictly safer for them too.detectMotionStartreturnsnullon any ffmpeg failure -> falls back to the existing wall-clock estimate, so behavior never regresses ifsignalstatsis unavailable.Test plan