GSAP and ScrollTrigger
to/from/fromTo, timelines and the position parameter, ScrollTrigger, useGSAP in React.
Updated
What GSAP is
GSAP (the GreenSock Animation Platform) is the animation library used on most award-winning sites (Awwwards): agencies, product launches, scroll storytelling. It animates any numeric value — CSS, SVG, canvas, JS objects — with very fine control over time. Since 2025, GSAP and all its plugins (ScrollTrigger, SplitText, MorphSVG) are free.
npm i gsap @gsap/reactThe three basic methods
gsap.to('.box', { x: 200, rotation: 90, duration: 1, ease: 'power3.out' }) // from the current state to
gsap.from('.title', { y: 40, opacity: 0, duration: 0.6 }) // from the given values to the current state
gsap.fromTo('.bar', { scaleX: 0 }, { scaleX: 1, duration: 0.8 }) // both ends explicitly| Option | Role |
|---|---|
duration |
seconds (not milliseconds!) |
ease |
'power1.out' … 'power4.out', 'back.out(1.7)', 'elastic.out', 'none' |
delay |
a delay |
stagger |
the offset between the selected elements: stagger: 0.08 |
repeat, yoyo |
repeating, back and forth |
x, y, rotation, scale are shorthands for transform — performant.
Timelines — sequences
GSAP's strength: you orchestrate dozens of animations on a time axis, without hand-calculated delays.
const tl = gsap.timeline({ defaults: { duration: 0.6, ease: 'power3.out' } })
tl.from('.logo', { y: -20, opacity: 0 })
.from('.title', { y: 40, opacity: 0 }, '-=0.3') // starts 0.3s before the previous one ends
.from('.cta', { scale: 0.8, opacity: 0 }, '<') // at the same time as the previous one
.from('.card', { y: 30, opacity: 0, stagger: 0.1 }, '+=0.2')| Position | Means |
|---|---|
| (missing) | after the previous one |
'<' |
at the same moment the previous one starts |
'+=0.2' / '-=0.3' |
0.2s after / 0.3s before the previous one ends |
1.5 |
at second 1.5, absolutely |
The timeline can be controlled: tl.pause(), tl.reverse(), tl.progress(0.5).
ScrollTrigger — animations tied to scrolling
gsap.registerPlugin(ScrollTrigger)
gsap.from('.feature', {
y: 60,
opacity: 0,
stagger: 0.15,
scrollTrigger: { trigger: '.features', start: 'top 80%' }, // starts when the section reaches 80% of the screen
})
gsap.to('.hero-image', {
scale: 1.3,
scrollTrigger: { trigger: '.hero', start: 'top top', end: 'bottom top', scrub: true }, // tied to the scroll position
})| Option | Effect |
|---|---|
start / end |
'top 80%' = when the trigger's top reaches 80% of the screen's height |
scrub: true |
the animation follows the scroll, forward and backward |
pin: true |
the section stays fixed while the animation runs — scroll storytelling |
markers: true |
shows the start / end lines — for debugging only |
GSAP in React / Next: useGSAP
'use client'
import { useRef } from 'react'
import gsap from 'gsap'
import { ScrollTrigger } from 'gsap/ScrollTrigger'
import { useGSAP } from '@gsap/react'
gsap.registerPlugin(useGSAP, ScrollTrigger)
export function Hero() {
const container = useRef<HTMLElement>(null)
useGSAP(
() => {
gsap.from('.word', { y: '100%', opacity: 0, stagger: 0.05, ease: 'power4.out' })
},
{ scope: container }, // the selectors search only inside the container
)
const { contextSafe } = useGSAP({ scope: container })
const spin = contextSafe(() => gsap.to('.logo', { rotation: '+=360' })) // animations from event handlers
return <section ref={container}>...</section>
}useGSAP automatically cleans up on unmount (and in Strict Mode) — without it, animations and ScrollTriggers stay hanging around between pages.
Motion or GSAP?
| Motion | GSAP | |
|---|---|---|
| Style | declarative, in JSX | imperative, timelines |
| Strengths | enter / exit, layout, gestures, app UI | long sequences, scroll storytelling, text, SVG |
Exit animations, layoutId |
yes, natively | by hand |
| Fine control over time | good | excellent |
| When | apps, UI components | landing pages, showcase sites, experiences |
You don't have to choose: many projects use Motion for the UI and GSAP for the showcase page.
Summary
gsap.to / from / fromTowithdurationin seconds,ease,stagger.- A timeline + the position parameter (
'<','-=0.3') for sequences. - ScrollTrigger for scrolling (
start,scrub,pin); in React alwaysuseGSAPwith ascope.