New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Optimised appear animations #1816
Conversation
@@ -56,6 +56,10 @@ const projection = Object.assign({}, config, { | |||
format: "umd", | |||
name: "Projection", | |||
exports: "named", | |||
globals: { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This just removes a warning in the build script
@@ -124,7 +127,7 @@ export function animate<V = number>({ | |||
isComplete = isForwardPlayback ? state.done : elapsed <= 0 | |||
} | |||
|
|||
onUpdate?.(latest) | |||
onUpdate && onUpdate(latest) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A slight aside to this PR but replacing ?.
for foo &&
makes a surprising saving for transpiled bundle sizes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤔 Why?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's just super-exact. onUpdate?.()
becomes:
var _onUpdate;
(_onUpdate = onUpdate) === null || _onUpdate === void 0 ? void 0 : _onUpdate();
??
is also upsettingly large. const a = 0 ?? 1
:
const a = (_ = 0) !== null && _ !== void 0 ? _ : 1;
@@ -109,35 +111,6 @@ export function spring({ | |||
initialDelta * Math.cos(angularFreq * t)) | |||
) | |||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here we're replacing the use of Motion One's spring
function, which only supports under- and critically-dampened springs, with Framer Motion's which supports over-damped springs also.
To help offset the added bundlesize, we're replacing the closed-form velocity calculation with a second sample of the spring calculation. This should actually also be cheaper as the maths is simpler - not sure why we weren't already doing this.
declare global { | ||
interface Window { | ||
MotionAppearAnimations?: MotionAppearAnimations | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need to store these on window? Let's add a comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yeah its so the inline script can communicate with Framer Motion - I've updated with a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Think we should add a comment to the reason for the window globals.
297076c
to
e85e4c6
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code looks good 👏
return useInstantAnimation | ||
? valueTransition.elapsed | ||
? () => delay(set, -valueTransition.elapsed) | ||
: set() | ||
: start() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if we should rename the function (getAnimation
) as now we changed the return type?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This happens in #1818
for (const key in featureTests) { | ||
supports[key] = () => { | ||
if (results[key] === undefined) results[key] = featureTests[key]() | ||
return results[key] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we return the result? 👀
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because otherwise it wouldn't return anything and we couldn't run checks like supports.waapi()
try { | ||
animation.cancel() | ||
MotionAppearAnimations.delete(animationId) | ||
} catch (e) {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we add some logging for the errors?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll add a comment, this is expected behaviour. Animation.cancel()
annoyingly throws, so we have to catch it here.
* 2. As all independent transforms share a single transform animation, stopping | ||
* it synchronously would prevent subsequent transforms from handing off. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't quite understand this comment, could you give an example?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in psuedo code
animate("scale", 2)
-> handoff from "transform" animation
-> cancel "transform" animation
animate("x", 2)
-> no "transform" animation present, start new animation
VS
animate("scale", 2)
-> handoff from "transform" animation
-> schedule cancel "transform" animation
animate("x", 2)
-> handoff from "transform" animation
-> schedule cancel "transform" animation
cancel "transform" animation
9ec28b0
to
bac5a8a
Compare
This PR adds the ability to play optimised appear animations via WAAPI and for Framer Motion to seamlessly take them over once React has loaded.
Animation data is shared via
window
and matching ids, so even if there's a hydration mismatch, the animation will continue unabated.