Migrate from GSAP to Motion
GSAP is an incredible animation library. But, you can achieve most of the same effects with Motion, with hardware accelerated performance, often for a far smaller bundlesize.
By the end of this guide we'll have learned the benefits and drawbacks of migrating, and also how to migrate basic animations, timeline sequences, scroll-linked and scroll-triggered animations, and React animations.
Benefits
Motion is built on modern browser APIs like Web Animations API (WAAPI) and Scroll Timeline, which is what enables it to offer hardware acceleration for common animations like transform
, filter
and opacity
.
There are other optimisations, like using the Intersection Observer API for scroll-triggered animations rather than measuring the scroll position every frame (which can trigger style recalculations).
Likewise, when you start an animation with the animate
function and it needs to read initial styles from the DOM, that process is batched and optimised, reducing layout thrashing and style recalculations.
Motion's APIs are generally smaller than GSAP too, with our scroll
function is just 75% the size of its GSAP equivalent, and the mini animate
function 90% smaller. Even the hybrid animate
function, which offers timeline sequencing, independent transform animations, and more, is 18kb, smaller than the GSAP animation functions.
Finally, because Motion is built with ES modules, it is tree-shakable. Which means if you only import the scroll
function, then only this code will end up being delivered to your users. This is an immediate SEO benefit of a few Lighthouse performance points.
Drawbacks
A robust feature comparison with GSAP can be found in our feature comparison guide, but the biggest missing feature from the Motion JavaScript API is layout animations.
Motion for React's layout animations go far beyond traditional "FLIP" techniques, with every animation performed with transforms, full scale correction for children and border-radius
, and more. So if you are a keen user of GSAP's FLIP functionality then Motion doesn't offer a comparable API yet.
GSAP is also geared squarely towards power users, with APIs that we don't believe are used by the majority of users, like the ability to get/set a delay
after an animation has started. Motion's philosophy is to tend towards a more accessible, smaller API, and this is shown in the relative filesizes.
Finally, animate
's onUpdate
callback is currently only available for animating single values, though this will change in the future.
Migrate
For this guide, we're going to take a look at the examples given in the GSAP documentation and see how we'd rewrite them in Motion.
Basic animations
The "Hello world' of JavaScript animations, a rotating box. In GSAP, this would be written with gsap.to
:
Motion's basic animation function is animate
:
You can see here that it looks broadly similar, with a couple of key differences.
rotate
instead ofrotation
repeat: Infinity
instead of-1
for infinitely-repeating animationsease: "linear"
instead ofease: "none"
Something else to note is that in GSAP the options and animating values are all bundled in together. Whereas with Motion, these are separate objects. This isn't of huge practical importance but when animating a plain object it means that object can't have properties with the same name as GSAP options.
GSAP has two other animation methods, fromTo
and from
.
fromTo
allows you to specify start and end keyframes:
With Motion, you just use the keyframe syntax:
This type of syntax (or equivalent also exists in GSAP, but fromTo
is more of a legacy API.
from
allows you to define values to animate from, with the target values being read from the DOM.
Motion doesn't have a comparable API to this, but this is partly because we don't recommend it. Practically what has to happen here is GSAP reads the existing value from the DOM, set this as a target value, then animate from the given value. Unless the user writes their JavaScript to be render-blocking (discouraged), this "incorrect" style will be visible for a frame or more, which is rarely what we want.
Animation controls
Both GSAP and Motion animations return animation controls. GSAP offers far more here. For instance, each animation option gets a method to get/set that option, whereas Motion tends towards the immutability of options.
However, there are some Motion equivalents to know about.
.timeScale()
is.speed
.time()
is.time
.kill()
is.stop()
.revert()
is.cancel()
.progress(1)
is.complete()
.resume()
is.play()
Timeline sequencing
Both Motion and GSAP offer timeline sequencing. The fundamental difference is that GSAP has a more imperative API, with a .timeline()
constructor and .to
, .add()
and .addLabel()
methods used to compose/amend the timeline:
Whereas Motion uses a declarative array syntax:
The benefit of the GSAP approach is it's easier to dynamically change a timeline in progress. Whereas with Motion, it's a little less boilerplate to compose long animations.
Composing multiple timelines is different in each library, much as above:
Scroll-triggered animations
Scroll-triggered animations are normal time-based animations that trigger when an element enters the viewport.
GSAP has the ScrollTrigger
plugin whereas Motion uses inView
function.
There fundamental technical difference between the two is inView
is based on the browser's Intersection Observer API, which is a super-performant way of detecting when elements enter the viewport. Whereas ScrollTrigger
measures the element and then tracks its position relative to scroll every frame. These reads/writes cause style recalculations.
Additionally, as inView
only triggers when the tracked element enters the viewport, it means scroll-triggered animations are lazily initialised. In combination with Motion's deferred keyframe resolution, this can result in drastically shorter startup times when using many scroll-triggered animations.
Scroll-pinning
GSAP has an option called pin
. If set, this will pin
the element to the viewport during the scroll animation. For performance reasons, we recommend using CSS position: sticky
instead.
Scroll-linked animations
By passing scrub: true
to scrollTrigger
, GSAP can create scroll-linked animations. These are fundamentally different in that instead of animations being driven by time, they're being driven by scroll progress instead.
In Motion, these kinds of animations are driven by the scroll
function.
scroll
is different in that, much like animate
can use the Web Animations API for hardware accelerated performance, scroll
can use the Scroll Timeline API for two performance benefits:
Enables hardware accelerated scroll animations
Can measure scroll progress for callbacks without polling scroll position (removing style recalculations)
Instead of start
and end
offset options, scroll
accepts a single offset
array, with options much like those found in GSAP.
You can see here that instead of using "top"
/"bottom"
, or "left"
/"right"
, Motion uses the axis-agnostic "start"
and "end"
keywords.
The benefit of a single offset
option is we can map more than two offsets to more than two animation keyframes. Here's an animation where the element fades in and out of the viewport:
React
Motion began life as a React animation library: Framer Motion. As such, its suite of React APIs goes far beyond GSAP's useGSAP
function.
That said, you can achieve a similar pattern for a smaller bundlesize with Motion's useAnimate
hook.
Take this rotating cube example from the GSAP docs:
We can rewrite this with Motion's mini useAnimate
, which offers a React interface to the 2.5kb animate
function.
Now we're running the same effect with 90% less code included in the bundlesize, plus the animation is running with hardware acceleration, which means fewer stutters (especially during React re-renders.
If you wanted to use { rotate: 360 }
like in the GSAP example then that's also possible by using the hybrid animate
function:
Conclusion
Although Motion and GSAP's feature sets don't fully overlap, thanks to modern practises and new browser APIs we think the majority of users will see better performance and lower filesizes by migrating to Motion.
Are there more GSAP features you'd like to see covered in this guide? Or a GSAP feature you'd like to see in Motion? Let me know!
A Motion+ membership will give you early access to features & content, access to our private Discord, and more.
It's a one-time fee that grants lifetime access. No subscription necessary!