Getting started
Installation
npm install gsap
import { gsap } from "gsap";
CDN:
<script src="https://cdn.jsdelivr.net/npm/gsap@3/dist/gsap.min.js"></script>
Register plugins
import { ScrollTrigger } from "gsap/ScrollTrigger";
import { Flip } from "gsap/Flip";
gsap.registerPlugin(ScrollTrigger, Flip);
Plugins must be registered before use.
First animation
// Animate to values
gsap.to(".box", {
x: 200,
rotation: 360,
duration: 1,
ease: "power2.out",
});
Tween methods
gsap.to()
gsap.to(".box", { x: 100, duration: 1 });
Animate to the given values.
gsap.from()
gsap.from(".box", { opacity: 0, y: -50, duration: 1 });
Animate from the given values to current state.
gsap.fromTo()
gsap.fromTo(".box", { opacity: 0, x: -100 }, { opacity: 1, x: 0, duration: 1 });
Define both start and end values.
gsap.set()
gsap.set(".box", { x: 100, y: 50, opacity: 0 });
Immediately set properties (no animation, duration: 0).
Special properties
Tween config
| Property | Description | Default |
|---|---|---|
duration |
Seconds | 0.5 |
delay |
Delay before start | 0 |
ease |
Easing function | "power1.out" |
repeat |
Times to repeat (-1=loop) |
0 |
repeatDelay |
Gap between repeats | 0 |
yoyo |
Reverse on each repeat | false |
stagger |
Offset for multiple targets | - |
paused |
Start paused | false |
overwrite |
true, "auto", false |
false |
immediateRender |
Render on creation | varies |
Callbacks
gsap.to(".box", {
x: 100,
onStart: () => console.log("started"),
onUpdate: () => console.log("updating"),
onComplete: () => console.log("done"),
onRepeat: () => console.log("repeating"),
onReverseComplete: () => console.log("reversed"),
});
Each callback has a Params variant: onCompleteParams: [arg1, arg2].
CSS properties
Transform shortcuts
| GSAP | CSS equivalent |
|---|---|
x: 100 |
translateX(100px) |
y: 100 |
translateY(100px) |
xPercent: 50 |
translateX(50%) |
yPercent: 50 |
translateY(50%) |
rotation: 90 |
rotate(90deg) |
scale: 2 |
scale(2) |
scaleX: 0.5 |
scaleX(0.5) |
skewX: 30 |
skewX(30deg) |
transformOrigin: "center" |
transform-origin |
autoAlpha: 0 |
opacity: 0 + visibility: hidden |
autoAlpha toggles visibility automatically — use instead of opacity for hiding elements.
3D transforms
gsap.to(".box", {
rotationX: 45,
rotationY: 45,
z: 100,
transformPerspective: 500,
force3D: true,
});
| Property | Description |
|---|---|
rotationX |
Rotate around X axis |
rotationY |
Rotate around Y axis |
z |
Translate Z (depth) |
transformPerspective |
Per-element perspective |
force3D |
Force GPU acceleration |
Timelines
Basic timeline
const tl = gsap.timeline({
defaults: {
duration: 1,
ease: "power2.out",
},
});
tl.to(".box1", { x: 100 })
.to(".box2", { y: 100 })
.to(".box3", { rotation: 180 });
Animations play in sequence. defaults apply to all children.
Position parameter
| Value | Description |
|---|---|
1 |
At absolute 1s |
"+=1" |
1s after previous end |
"-=1" |
Overlap by 1s |
"<" |
Start of previous |
">" |
End of previous |
"<+=0.5" |
0.5s after prev start |
"myLabel" |
At named label |
tl.to(".a", { x: 100 })
.to(".b", { y: 100 }, "-=0.5") // overlap
.to(".c", { rotation: 90 }, "<"); // same start
Labels & nesting
// Labels
tl.addLabel("midpoint").to(".box", { x: 100 }, "midpoint");
// Add at label
tl.add(otherTimeline, "midpoint");
// Nested timelines
const master = gsap.timeline();
master.add(introTimeline()).add(mainTimeline(), "-=0.5").add(outroTimeline());
Easing
Core eases
| Ease | Description |
|---|---|
"none" |
Linear (no easing) |
"power1" |
Subtle |
"power2" |
Moderate (default-like) |
"power3" |
Strong |
"power4" |
Extra strong |
"back" |
Overshoot |
"bounce" |
Bouncy |
"circ" |
Circular |
"elastic" |
Springy |
"expo" |
Exponential |
"sine" |
Gentle sinusoidal |
"steps(n)" |
Stepped (n steps) |
Usage
// Each ease has .in, .out, .inOut variants
gsap.to(".box", { ease: "power2.out" }); // default
gsap.to(".box", { ease: "power2.in" }); // start slow
gsap.to(".box", { ease: "power2.inOut" }); // both ends
gsap.to(".box", { ease: "elastic.out(1, 0.3)" });
gsap.to(".box", { ease: "back.out(1.7)" });
gsap.to(".box", { ease: "steps(12)" });
Default is "power1.out". Omitting the variant defaults to .out.
Stagger
Simple stagger
gsap.to(".box", {
x: 100,
stagger: 0.1, // 0.1s between each
});
Advanced stagger
gsap.to(".box", {
x: 100,
stagger: {
each: 0.1, // time between each
from: "center", // "start", "end", "center", "edges", "random", or index
grid: "auto", // auto-detect grid
axis: "x", // "x" or "y" for grid
ease: "power2.inOut",
},
});
Control methods
Playback control
const tween = gsap.to(".box", { x: 100, paused: true });
tween.play(); // play from current
tween.pause(); // pause
tween.resume(); // resume from paused
tween.reverse(); // play backward
tween.restart(); // restart from beginning
tween.seek(0.5); // jump to 0.5s
tween.progress(0.5); // jump to 50%
tween.timeScale(2); // double speed
tween.kill(); // destroy
tween.revert(); // revert to pre-GSAP state
State & promises
tween.isActive(); // currently animating?
tween.progress(); // 0–1 progress
tween.duration(); // total duration
tween.time(); // current time
// Promise-based
tween.then(() => {
console.log("complete");
});
// Or async/await
await gsap.to(".box", { x: 100 });
ScrollTrigger
Basic usage
import { ScrollTrigger } from "gsap/ScrollTrigger";
gsap.registerPlugin(ScrollTrigger);
gsap.to(".box", {
x: 500,
scrollTrigger: {
trigger: ".box",
start: "top center",
end: "bottom top",
scrub: true,
},
});
Full config
scrollTrigger: {
trigger: ".element",
start: "top center", // [trigger] [scroller]
end: "bottom top",
scrub: true, // true, or seconds for smooth
pin: true, // pin trigger element
pinSpacing: true,
markers: true, // debug markers
toggleActions: "play pause resume reset",
toggleClass: "active",
onEnter: () => {},
onLeave: () => {},
onEnterBack: () => {},
onLeaveBack: () => {},
}
Start/end syntax
Format: "[trigger position] [scroller position]"
| Value | Description |
|---|---|
"top center" |
Trigger top at viewport center |
"top 80%" |
Trigger top at 80% from top |
"top top" |
Trigger top at viewport top |
"+=300" |
300px after start |
toggleActions format: "onEnter onLeave onEnterBack onLeaveBack". Values: play, pause, resume, reverse, restart, reset, complete, none.
Utilities & patterns
Utility methods
gsap.utils.toArray(".box");
gsap.utils.clamp(0, 100, value);
gsap.utils.mapRange(0, 100, 0, 1, 50); // 0.5
gsap.utils.normalize(0, 100, 50); // 0.5
gsap.utils.wrap([0, 1, 2], 4); // 1
gsap.utils.snap(5, 13); // 15
gsap.utils.random(0, 100);
gsap.utils.interpolate(0, 100, 0.5); // 50
gsap.utils.shuffle([1, 2, 3]);
gsap.utils.pipe(fn1, fn2, fn3);
gsap.utils.selector(scope);
Function-based values
gsap.to(".box", {
// Per-element values
x: (i, target, targets) => i * 50,
rotation: (i) => i * 90,
});
// Random values
gsap.to(".box", { x: "random(-100, 100)" });
gsap.to(".box", { x: "random(-100, 100, 10)" }); // snapped
// Relative values
gsap.to(".box", { x: "+=20" }); // add 20
gsap.to(".box", { x: "-=20" }); // subtract 20
Context & matchMedia
// Context for cleanup (React, etc.)
const ctx = gsap.context(() => {
gsap.to(".box", { x: 100 });
// all animations auto-cleaned
}, containerRef);
ctx.revert(); // cleanup all
// Responsive animations
const mm = gsap.matchMedia();
mm.add("(min-width: 768px)", () => {
gsap.to(".box", { x: 200 });
return () => {}; // cleanup
});
mm.add("(max-width: 767px)", () => {
gsap.to(".box", { x: 50 });
});
quickTo & quickSetter
// Optimized for rapid updates (mousemove, etc.)
const xTo = gsap.quickTo(".box", "x", {
duration: 0.4,
ease: "power3",
});
window.addEventListener("mousemove", (e) => xTo(e.clientX));
// Even faster (no tween overhead)
const setX = gsap.quickSetter(".box", "x", "px");
setX(100);
Reusable effects
gsap.registerEffect({
name: "fadeIn",
effect: (targets, config) =>
gsap.from(targets, {
opacity: 0,
y: config.y,
duration: config.duration,
}),
defaults: { y: -20, duration: 0.5 },
extendTimeline: true,
});
// Use it
gsap.effects.fadeIn(".box");
tl.fadeIn(".box", { y: -30 });
Plugins
Free plugins
| Plugin | Description |
|---|---|
ScrollTrigger |
Scroll-based animations |
Draggable |
Drag and drop |
Flip |
Layout transition animations |
Observer |
Multi-event listener |
ScrollToPlugin |
Animate scroll position |
TextPlugin |
Animate text content |
MotionPathPlugin |
Animate along SVG paths |
Premium plugins (Club GSAP)
| Plugin | Description |
|---|---|
DrawSVGPlugin |
Animate SVG strokes |
MorphSVGPlugin |
Morph between SVG shapes |
SplitText |
Split text for animation |
ScrambleTextPlugin |
Scramble text effect |
InertiaPlugin |
Momentum-based motion |
GSDevTools |
Visual debugging UI |
Premium plugins are free on CodePen and Stackblitz.
React integration
useGSAP hook
npm install @gsap/react
import { useRef } from "react";
import { useGSAP } from "@gsap/react";
function MyComponent() {
const container = useRef();
useGSAP(
() => {
gsap.to(".box", { x: 100 });
},
{ scope: container },
);
return (
<div ref={container}>
<div className="box" />
</div>
);
}
With dependencies & cleanup
useGSAP(
() => {
gsap.to(".box", {
x: isActive ? 200 : 0,
rotation: isActive ? 360 : 0,
});
},
{ scope: container, dependencies: [isActive] },
);
useGSAP handles cleanup automatically — no manual revert() needed.
Also see
- GSAP documentation (gsap.com)
- GSAP easing visualizer (gsap.com)
- ScrollTrigger docs (gsap.com)
- GSAP cheat sheet (official) (gsap.com)
- useGSAP React hook (npmjs.com)