GSAP (GreenSock) — Web Animation Skill
When to use
- High-quality UI/motion design: entrances, micro-interactions, page transitions
- Timeline-based sequences (vs. scattered CSS transitions)
- Scroll-driven storytelling (with ScrollTrigger)
- Complex easing, staggering, orchestration across many elements
Key concepts & APIs
- Tweens:
gsap.to(targets, vars)
gsap.from(targets, vars)
gsap.fromTo(targets, fromVars, toVars)
- Timelines:
const tl = gsap.timeline({ defaults, repeat, yoyo, paused })
- Chain:
tl.to(...).from(...).addLabel('x').add(() => ...)
- Position parameter: absolute
1.2, relative "+=0.5", overlap "-=0.3", label "intro"
- Eases:
ease: "power2.out", "expo.inOut", "elastic.out(1, 0.3)"
- Staggers:
stagger: 0.05 or { each, from: "start|center|end|random", grid }
- Performance-friendly properties:
- Prefer transforms (
x, y, scale, rotation) and opacity (autoAlpha)
- ScrollTrigger (plugin):
gsap.registerPlugin(ScrollTrigger)
- Inline:
gsap.to(".box", { scrollTrigger: ".box", x: 500 })
- Advanced:
scrollTrigger: { trigger, start, end, scrub, pin, snap, markers }
- Standalone:
ScrollTrigger.create({ trigger, start, end, onUpdate, onToggle })
Common pitfalls (and fixes)
- Animating layout properties (top/left/width/height) → jank
- Use transforms, add
will-change: transform, avoid forced reflow.
- ScrollTrigger “not firing” due to wrong trigger sizing/overflow containers
- Ensure trigger exists, has height, and check scroll container (nested scrolling needs config).
- Not cleaning up in SPA/React
- Use
gsap.context() and revert on unmount; kill triggers (ScrollTrigger.getAll().forEach(t => t.kill())) if needed.
- FOUC / measuring before fonts/images load
- Initialize after layout is stable; run
ScrollTrigger.refresh() after images load.
Quick recipes
1) Hero entrance (stagger)
gsap.from(".hero [data-anim]", {
y: 24,
autoAlpha: 0,
duration: 0.8,
ease: "power2.out",
stagger: 0.06,
});
2) Sequenced timeline
const tl = gsap.timeline({ defaults: { ease: "power2.out", duration: 0.6 } });
tl.from(".nav", { y: -20, autoAlpha: 0 })
.from(".hero-title", { y: 30, autoAlpha: 0 }, "-=0.2")
.from(".hero-cta", { scale: 0.95, autoAlpha: 0 }, "-=0.2");
3) Scroll-scrub pinned section
gsap.registerPlugin(ScrollTrigger);
gsap.timeline({
scrollTrigger: {
trigger: ".story",
start: "top top",
end: "+=800",
scrub: 1,
pin: true,
},
}).to(".story .panel", { xPercent: -200 });
What to ask the user (if requirements unclear)
- Is this a static site or SPA (React/Next/Vue)? Any page transitions?
- Do we need scroll-driven sections (pin/scrub/snap)?
- Performance constraints (mobile support, reduced motion)?
1---2name: gsap3description: Use when you need to add or debug professional web animations with GSAP (timelines, ScrollTrigger, stagger, transforms) in HTML/CSS/JS/React. Includes patterns for smooth motion, performance, and common pitfalls.4---5
6# GSAP (GreenSock) — Web Animation Skill
7
8## When to use
9- High-quality UI/motion design: entrances, micro-interactions, page transitions
10- Timeline-based sequences (vs. scattered CSS transitions)
11- Scroll-driven storytelling (with ScrollTrigger)
12- Complex easing, staggering, orchestration across many elements
13
14## Key concepts & APIs
15- Tweens:
16 - `gsap.to(targets, vars)`
17 - `gsap.from(targets, vars)`
18 - `gsap.fromTo(targets, fromVars, toVars)`
19- Timelines:
20 - `const tl = gsap.timeline({ defaults, repeat, yoyo, paused })`
21 - Chain: `tl.to(...).from(...).addLabel('x').add(() => ...)`
22 - Position parameter: absolute `1.2`, relative `"+=0.5"`, overlap `"-=0.3"`, label `"intro"`
23- Eases: `ease: "power2.out"`, `"expo.inOut"`, `"elastic.out(1, 0.3)"`
24- Staggers: `stagger: 0.05` or `{ each, from: "start|center|end|random", grid }`
25- Performance-friendly properties:
26 - Prefer transforms (`x`, `y`, `scale`, `rotation`) and opacity (`autoAlpha`)
27- ScrollTrigger (plugin):
28 - `gsap.registerPlugin(ScrollTrigger)`
29 - Inline: `gsap.to(".box", { scrollTrigger: ".box", x: 500 })`
30 - Advanced: `scrollTrigger: { trigger, start, end, scrub, pin, snap, markers }`
31 - Standalone: `ScrollTrigger.create({ trigger, start, end, onUpdate, onToggle })`
32
33## Common pitfalls (and fixes)
34- Animating layout properties (top/left/width/height) → jank
35 - Use transforms, add `will-change: transform`, avoid forced reflow.
36- ScrollTrigger “not firing” due to wrong trigger sizing/overflow containers
37 - Ensure trigger exists, has height, and check scroll container (nested scrolling needs config).
38- Not cleaning up in SPA/React
39 - Use `gsap.context()` and revert on unmount; kill triggers (`ScrollTrigger.getAll().forEach(t => t.kill())`) if needed.
40- FOUC / measuring before fonts/images load
41 - Initialize after layout is stable; run `ScrollTrigger.refresh()` after images load.
42
43## Quick recipes
44
45### 1) Hero entrance (stagger)
46```js
47gsap.from(".hero [data-anim]", {
48 y: 24,
49 autoAlpha: 0,
50 duration: 0.8,
51 ease: "power2.out",
52 stagger: 0.06,
53});
54```
55
56### 2) Sequenced timeline
57```js
58const tl = gsap.timeline({ defaults: { ease: "power2.out", duration: 0.6 } });
59tl.from(".nav", { y: -20, autoAlpha: 0 })
60 .from(".hero-title", { y: 30, autoAlpha: 0 }, "-=0.2")
61 .from(".hero-cta", { scale: 0.95, autoAlpha: 0 }, "-=0.2");
62```
63
64### 3) Scroll-scrub pinned section
65```js
66gsap.registerPlugin(ScrollTrigger);
67
68gsap.timeline({
69 scrollTrigger: {
70 trigger: ".story",
71 start: "top top",
72 end: "+=800",
73 scrub: 1,
74 pin: true,
75 },
76}).to(".story .panel", { xPercent: -200 });
77```
78
79## What to ask the user (if requirements unclear)
80- Is this a static site or SPA (React/Next/Vue)? Any page transitions?
81- Do we need scroll-driven sections (pin/scrub/snap)?
82- Performance constraints (mobile support, reduced motion)?