Repository navigation
Conversation
getEffectsData() normalized effect.keyframes as soon as it built the effect data, so presets whose keyframes (and ranges) are getters over values set in their dom.measure() callback were read before the measure. The getter returns a new array on each read, so the result was always spread into a copy, which froze every getter at its pre-measure value. Cross loops came out with zero offsets, and BgZoom/BgFake3D scroll ranges ignored the component height. Pass the preset's object through untouched and normalize keyframe names where they are consumed: inside the fastdom.mutate() that sets the WAAPI keyframes, and in getCSSAnimation(). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
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.
Description
Bug fix (motion): presets that compute their keyframes from measured values get keyframes from before the measurement.
Crossloops sit still, and the scroll range ofBgZoomandBgFake3Dignores the component's height.Some presets return
keyframes(andBgZoom/BgFake3DalsoendOffsetAdd) as getters. They read values that the preset'sdom.measure()callback sets in the next fastdom frame.getWebAnimation()already waits for that: it callssetKeyframes()and sets the ranges insidefastdom.mutate().Since #281,
getEffectsData()callsnormalizeKeyframes(effect.keyframes)right away, which runs the getter before the measure. A getter returns a new array on every read, so thekeyframes === effect.keyframescheck always fails, and{ ...effect, keyframes }then copies every getter as the value it has at that moment. The mutate step gets those early values:Crosskeyframe offsets0, 0, 0, 1, 1(the element starts outside its parent and never moves)0, 0.64, 0.64, 1, 1BgZoom(in) range endcalc(100svh + 0px)calc(100svh + 800px)BgFake3Dparallax range endcalc(100svh + 0px)calc(100svh + 800px)These numbers come from the real presets run through
getWebAnimation()in jsdom, with stubbed layout (an 800px tall component for the background presets) and fastdom queued the way a browser frame runs it.Fix:
getEffectsData()passes the preset's object through untouched. Keyframe names are normalized where they're used: inside thefastdom.mutate()inwebAnimations.ts, and ingetCSSAnimation(). The CSS path calls the presets'style(), which doesn't measure, so its output is unchanged.Related Issue
Found in the Wix viewer while moving sites from interact v1 to v2: page-load
Crossloops that ran under v1 never play under v2. In the investigation that found this, patching the same change into the bundle made theCrossloops on two affected sites run again, with offsets of 0.408 and 0.502 instead of 0.Checklist
Tests
Two new specs in
packages/motion/test/motion.spec.ts›getWebAnimation(). Each one registers a preset whose getter depends on a value itsdom.measure()sets, and queues fastdom so the measure runs aftergetWebAnimation()returns:should read lazy keyframes after the preset measured the target:setKeyframes()gets offset0.4. Without the fix, it gets0.should read lazy scrub ranges after the preset measured the target: the range end iscover calc(0% + 200px). Without the fix, it'scover calc(0% + 0px).The existing kebab-case normalization specs still pass.
yarn build,yarn test,yarn lintandyarn format:checkpass.🤖 Generated with Claude Code