fix(studio): compute keyframe percentages in the tween's own time frame

A sub-composition tween's resolvedStart is composition-local, while the timeline
element resolved for it is the sub-comp HOST, whose start is main-timeline
absolute. toClipPercentage subtracted the two frames from each other, so a host
mounted at 1.5s cached its 0s tween at -12% and its last tween's end keyframe at
88% instead of 100%. A clip-relative percentage can never be negative.

resolveClipTimingBasis now returns the clip start in the frame the tween's own
times are measured in: the composition mount (expandedParentStart for an
expanded child, the parent composition clip's start otherwise, 0 for a
root-composition element) is subtracted, and a sub-comp inner element that falls
back to its host's window starts at 0 in that window. It moves to gsapShared so
the post-commit cache writer can share it instead of resolving its own basis,
which also gives that writer the sub-comp host fallback it was missing.
This commit is contained in:
Miguel Angel Simon Sierra
2026-07-28 18:04:37 +02:00
parent 86f633f985
commit 3f0c20f633
5 changed files with 190 additions and 56 deletions
+4 -11
View File
@@ -7,24 +7,17 @@ import {
pruneKeyframeCacheToFiles,
writeGsapAnimationsForElement,
} from "./gsapKeyframeCacheHelpers";
import { toAbsoluteTime, toClipPercentage } from "./gsapShared";
import { resolveClipTimingBasis, toAbsoluteTime, toClipPercentage } from "./gsapShared";
import {
deduplicateKeyframes,
isStaticPositionHold,
synthesizeFlatTweenKeyframes,
} from "./gsapTweenSynth";
import {
fetchParsedAnimations,
populateKeyframeCacheFromAst,
resolveClipTimingBasis,
} from "./keyframeCacheAstLoad";
import { fetchParsedAnimations, populateKeyframeCacheFromAst } from "./keyframeCacheAstLoad";
// Re-exported so callers keep importing the GSAP cache surface from one module.
export {
fetchParsedAnimations,
resolveClipTimingBasis,
resolveSelectorElementIds,
} from "./keyframeCacheAstLoad";
export { resolveClipTimingBasis } from "./gsapShared";
export { fetchParsedAnimations, resolveSelectorElementIds } from "./keyframeCacheAstLoad";
/** The selected element's identity for matching tweens to it. */
export interface GsapElementTarget {