Skip to content

fix(core): keep from-state when a render crosses tween starts - #5188

Open
rumi7911 wants to merge 1 commit into
heygen-com:mainfrom
rumi7911:codex/fix-from-state-follow-up
Open

rumi7911 wants to merge 1 commit into
heygen-com:mainfrom
rumi7911:codex/fix-from-state-follow-up

Conversation

@rumi7911

@rumi7911 rumi7911 commented Oct 7, 2026

Copy link
Copy Markdown

What

Keep initialized fromTo() / startAt values when a render refresh rewinds across a tween's start between output frames, including very short tweens that have ended inside the 0.001s rewind window. Restore those values in authored order: earlier same-time writers cannot override from-only properties, while later writers still win.

For a 30fps composition whose scale tween starts at 0.0995s, transformOrigin: 0% 0% remains applied from frame 3. Current main loses that origin and exports the box around its center.

Why

The exact-start priming merged in #5125 fixes the original reproduction. It misses a start between output frames, and replaying from-state between the two timeline passes permits an earlier writer to override it during the final pass.

Related work

Refs #5122. Follow-up to merged #5125, retaining its keyframe and stagger priming and all its tests. This patch is based on upstream 21d14b25b3b3530da60ccbc9ad58788398b797c0, with only three files changed. The earlier-writer case is explicitly deferred in #5125's description.

Uninitialized nested/stagger openings and the existing zero-duration callback guard remain outside this change. This does not claim every GSAP edge case is resolved.

How

Collect already initialized, forward-playing tweens crossed by the artificial rewind, using their local clocks. Temporarily replay cached from-state immediately before each tween's own nonnegative render, preserving writer order without initializing unrelated animations or mutating tween vars.

Restore the original render property descriptor or inherited status, parent metadata, and landing marks in finally. If a property setter reenters the refresh and changes the tween's rendered time, force interpolation to finish; ordinary renders retain their force flag and repeat-refresh evaluation behavior. No public API, dependency, or render-default changes.

Test plan

  • Add 17 tests: 16 adapter cases and one production renderSeek integration. Cover off-grid starts, short ended tweens, writer order, nested speeds, cached function values, backward seeks, unrelated uninitialized animations, error/descriptor restoration, same-time reentry, and short repeatRefresh evaluation.
  • Current-main RED: six symptom regressions fail; 283 tests pass and one reentry guard is skipped. Patched GREEN: all 290 targeted tests pass, including the guard and existing peer tests.
  • Frozen Bun install, all-workspace build and package/script typechecks pass. Runtime CI passes built-artifact, behavior/seek/parity/security/linter checks and coverage thresholds.
  • Changed-file lint/format, comment citations/ratchet, Fallow, tracked-artifact/large-file checks, conventional commit validation, and normal Git hooks pass.
  • Actual CLI exports from clean current main and the patch, with GSAP 3.14.2, Chrome headless shell 154.0.8037.57, 30fps, screenshot capture, and one worker. Synthetic fixture lint has zero errors/warnings; browser check passes nine samples.
  • Independent final code review reports no actionable findings; 5,184 comparisons cover keyframes/staggers, nested speeds, repeats, relative values, tiny durations, and writer order.
  • Entire core suite green: patched 4,296 pass / 4,297 total; clean current-main baseline 4,279 pass / 4,280 total. Both have the same existing 5000ms font timeout: deterministicFonts-googleSubsets.test.ts, “still embeds a local file when the page has no Google link.” No font files were changed.

Decoded white box bounds from the actual off-grid MP4 exports:

Source Frame 3 Frame 4 Frame 5
Main 21d14b2 x50–349 / y270–449 x54–345 / y273–446 x58–341 / y275–444
This patch x100–399 / y300–479 x100–391 / y300–474 x100–384 / y300–470

These are automated encoded-frame measurements. Manual visual/participant validation, yellow-control pixel identity, arbitrary third-party plugins, and exhaustive browser compatibility are not claimed. Documentation changes are not applicable.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant