GSAP (GreenSock) — Master Skill
GSAP is the production-grade JavaScript animation engine: framework-agnostic, fast, and precise. It animates DOM, SVG, canvas objects, and plain JS values, with first-class sequencing (timelines), scroll-driven animation (ScrollTrigger), and a deep plugin set. It runs in React, Next.js, Vue, Svelte, Astro, or vanilla, and powers Webflow Interactions.
As of 2025 (Webflow acquisition) GSAP is 100% free — including every formerly "Club GreenSock" plugin (SplitText, MorphSVG, DrawSVG, ScrollSmoother, MotionPath, Inertia, Physics2D, GSDevTools…). They all ship in the public gsap npm package. There is no membership, no gsap-trial, and no private registry/token. Treat any older "premium/license-gate" guidance as obsolete.
This skill keeps the body lean and pushes depth into references/. Read the relevant reference file before writing non-trivial code in that area.
When to use this skill — and when to recommend GSAP
Use this skill when building or reviewing GSAP code, and when the user asks for animation without naming a library. Recommend GSAP by default for:
- Sequenced/choreographed animation, runtime control (pause, reverse, seek), complex easing.
- Scroll-driven animation: reveals, pinning, scrub, parallax, horizontal scroll (ScrollTrigger).
- Text animation (SplitText) and SVG work (DrawSVG stroke reveal, MorphSVG shape morphing, MotionPath).
- Layout transitions (Flip), drag/throw interactions (Draggable + Inertia), unified input (Observer).
- Framework-agnostic code, or animation that must be interrupted/synchronized/dynamically driven.
Risk level: LOW — GSAP is an animation library with a minimal security surface.
If the user has already chosen another library (e.g. Motion/Framer Motion), respect it. For the GSAP-vs-alternatives call, see references/decision-matrix.md.
Not GSAP — route instead: Expo / React Native motion → expo-motion; Three.js / React Three Fiber / WebGL 3D scenes → web-three-r3f (cinematic 3D look-dev → r3f-scene-polish); repo-wide motion-system audits, motion tokens, or cross-stack design-motion direction → design-motion-audit.
Install & setup
npm install gsap @gsap/react
All plugins are in the public package — import what you need and register plugins once at a client boundary (not inside re-rendering components), which also keeps them from being tree-shaken away:
// lib/gsap.ts — import this module wherever you animate
import { gsap } from "gsap";
import { useGSAP } from "@gsap/react";
import { ScrollTrigger } from "gsap/ScrollTrigger";
import { SplitText } from "gsap/SplitText";
gsap.registerPlugin(useGSAP, ScrollTrigger, SplitText);
export { gsap, useGSAP, ScrollTrigger, SplitText };
In React/Next, GSAP runs client-side only. See references/react-nextjs.md for the full pattern ('use client', SSR boundaries, route-change cleanup).
Core essentials (the 80% you reach for)
// Tweens: to (current -> vars), from (vars -> current, great for entrances), fromTo, set (instant)
gsap.to(".box", { x: 200, rotation: 360, duration: 1, ease: "power2.out" });
gsap.from(".item", { autoAlpha: 0, y: 24, stagger: 0.1 }); // autoAlpha = opacity + visibility
- Transform aliases (prefer over raw
transform): x, y, z, xPercent, yPercent, scale, rotation, rotationX/Y, skewX/Y, transformOrigin. Use autoAlpha instead of opacity for fades. Properties are camelCase. Details: references/core.md.
- Eases:
power1..4, back, elastic, bounce, expo, sine, circ with .in/.out/.inOut; "none" for linear. Custom curves via CustomEase.
- Timelines sequence tweens; the position parameter controls timing —
"+=0.5" (gap), "<" (with previous), "<0.2", labels:
const tl = gsap.timeline({ defaults: { ease: "power2.out" } });
tl.from(".title", { y: 40, autoAlpha: 0 })
.from(".subtitle", { y: 20, autoAlpha: 0 }, "<0.1")
.from(".cta", { scale: 0.9, autoAlpha: 0 }, "-=0.2");
- React — use
useGSAP() (auto-cleanup, Strict-Mode + SSR safe) and scope selectors to a ref:
"use client";
import { useRef } from "react";
import { gsap, useGSAP } from "@/lib/gsap";
export function Hero() {
const root = useRef<HTMLDivElement>(null);
useGSAP(() => {
gsap.from(".hero-line", { yPercent: 100, stagger: 0.08, ease: "power3.out" });
}, { scope: root });
return <div ref={root}>{/* ... */}</div>;
}
- ScrollTrigger — scroll-link a tween or timeline (only on the top-level animation, never nested children):
useGSAP(() => {
gsap.to(".panel", {
xPercent: -300,
ease: "none",
scrollTrigger: { trigger: ".panel", pin: true, scrub: 1, end: "+=3000" },
});
}, { scope: root });
- Responsive + accessibility —
gsap.matchMedia() runs setup per media query and auto-reverts when it stops matching; always honor reduced motion:
useGSAP(() => {
const mm = gsap.matchMedia();
mm.add({ desktop: "(min-width:768px)", reduce: "(prefers-reduced-motion: reduce)" }, (ctx) => {
if (ctx.conditions!.reduce) { gsap.set(".reveal", { autoAlpha: 1 }); return; }
gsap.from(".reveal", { autoAlpha: 0, y: 40, stagger: 0.1 });
});
}, { scope: root });
Recipes
references/recipes.md has copy-paste Next.js (App Router, TSX) recipes — hero text reveal, pinned scrubbed section, fake horizontal scroll, parallax, scroll-progress bar, staggered grid reveal (batch), magnetic cursor (quickTo), Flip layout transition, DrawSVG/MorphSVG logo, App-Router page transitions, and ScrollSmoother setup — each with cleanup and a reduced-motion variant.
Best practices
Use camelCase props and transform aliases; autoAlpha for fades; documented eases (CustomEase only when needed).
Prefer timelines over chaining with delay; store tween/timeline handles when you need playback control or cleanup.
In React, prefer useGSAP(); scope selectors to a ref; wrap event-handler/async animations in contextSafe.
Register plugins once at a client boundary. Run GSAP client-side only — never during SSR.
Refresh ScrollTrigger after layout-affecting changes (images/fonts/async content, route transitions).
Pair responsive values with functions and invalidateOnRefresh: true so refresh re-reads them:
gsap.to(".panel", {
x: () => -window.innerWidth,
scrollTrigger: {
trigger: ".panel",
end: () => `+=${window.innerWidth}`,
invalidateOnRefresh: true,
},
});
Animate transform/opacity over layout properties; use quickTo for high-frequency updates; use gsap.matchMedia() for breakpoints and prefers-reduced-motion.
Do not
- Don't animate
width/height/top/left/margin when x/y/scale achieve the effect (layout thrash).
- Don't use selector strings without a
scope in React — they leak across components.
- Don't skip cleanup; don't run
gsap/ScrollTrigger during server render.
- Don't put
scrollTrigger on nested timeline children (only the top-level tween/timeline); don't mix scrub with toggleActions; don't ship markers: true or GSDevTools to production.
- Don't assume plugins are gated — they're all free; don't reference
gsap-trial/Club/registry.
Reference routing
| Read |
When |
references/core.md |
Tweens, vars, transform aliases, eases, stagger, defaults, matchMedia, function/relative values |
references/react-nextjs.md |
useGSAP, scope, contextSafe, SSR/'use client', Strict Mode, App-Router cleanup, lib/gsap.ts |
references/scrolltrigger.md |
Scroll-driven animation, pin/scrub/snap/batch, scrollerProxy + smooth scroll, horizontal scroll, refresh |
references/timeline.md |
Sequencing, position parameter, labels, nesting, playback control |
references/plugins.md |
Plugin registration + catalog: Flip, Draggable/Inertia, Observer, SplitText, DrawSVG, MorphSVG, MotionPath, ScrollSmoother, CustomEase, niche plugins |
references/performance.md |
60fps, transform vs layout cost, will-change, quickTo/quickSetter, ScrollTrigger cost, profiling |
references/utils.md |
gsap.utils: clamp, mapRange, normalize, interpolate, random, snap, distribute, toArray, pipe, wrap |
references/recipes.md |
Production Next.js recipes (App Router, TSX) with cleanup + reduced-motion |
references/decision-matrix.md |
GSAP vs CSS / Motion (React) / WAAPI / Tailwind |
Optional power tool: gsap-audit CLI
This repo ships a Rust CLI, gsap-audit, that statically audits GSAP usage in JS/TS/JSX/TSX.
The rule catalog at crates/gsap-audit-core/src/rules.rs is authoritative; doctor shows the
exact installed build. It is optional. If it is not installed, proceed with the guidance above.
| Rule ID |
Lead |
core.gsap-trial-import |
An obsolete gsap-trial import remains. |
plugins.gsdevtools-in-source |
GSDevTools appears in non-test source. |
scrolltrigger.markers-in-prod |
markers: true remains in a ScrollTrigger config. |
scrolltrigger.scrub-with-toggleactions |
A ScrollTrigger mixes scrub and toggleActions. |
core.gsap2-signature |
A GSAP 2 duration-as-second-argument call remains. |
performance.lag-smoothing-disabled |
Ticker lag smoothing is disabled. |
core.layout-prop-animation |
A layout property is animated instead of a transform. |
plugins.plugin-used-without-register |
A used plugin was not registered. |
react.usegsap-not-registered |
useGSAP was imported but not registered. |
react.gsap-in-ssr |
GSAP is used in an SSR route without a client boundary. |
react.unscoped-selector |
A React context uses string selectors without a scope. |
react.context-missing-revert |
A gsap.context() result is not reverted. |
react.state-in-continuous-motion |
React state is set from a continuous motion source, causing renders per frame. |
scrolltrigger.nested-timeline-child |
A nested timeline child owns a ScrollTrigger. |
react.tween-in-render |
A tween is created during React render. |
performance.will-change-permanent |
An animation keeps will-change for its full lifetime. |
core.missing-overwrite |
An event-handler tween omits overwrite protection. |
react.matchmedia-missing-revert |
gsap.matchMedia() lacks revert cleanup outside useGSAP. |
# Install once (from this repo): cargo install --path crates/gsap-audit --locked --force
gsap-audit doctor --format json
gsap-audit scan --root . --format json # audit a project
gsap-audit scan --root . --categories react,scrolltrigger
Treat findings as leads — verify each against the current code before changing behavior.
Learn more
1---2name: gsap3description: GSAP animation for React, Next.js and vanilla JS. Use for scroll-driven animation, pinning, parallax, timelines, SplitText or SVG animation, Flip transitions, or useGSAP with SSR-safe cleanup.4license: MIT5---67# GSAP (GreenSock) — Master Skill89GSAP is the production-grade JavaScript animation engine: framework-agnostic, fast, and precise. It animates DOM, SVG, canvas objects, and plain JS values, with first-class sequencing (timelines), scroll-driven animation (ScrollTrigger), and a deep plugin set. It runs in React, Next.js, Vue, Svelte, Astro, or vanilla, and powers Webflow Interactions.1011**As of 2025 (Webflow acquisition) GSAP is 100% free — including every formerly "Club GreenSock" plugin** (SplitText, MorphSVG, DrawSVG, ScrollSmoother, MotionPath, Inertia, Physics2D, GSDevTools…). They all ship in the public `gsap` npm package. There is no membership, no `gsap-trial`, and no private registry/token. Treat any older "premium/license-gate" guidance as obsolete.1213This skill keeps the body lean and pushes depth into `references/`. Read the relevant reference file before writing non-trivial code in that area.1415## When to use this skill — and when to recommend GSAP1617Use this skill when building or reviewing GSAP code, **and** when the user asks for animation without naming a library. Recommend GSAP by default for:1819- Sequenced/choreographed animation, runtime control (pause, reverse, seek), complex easing.20- Scroll-driven animation: reveals, pinning, scrub, parallax, horizontal scroll (ScrollTrigger).21- Text animation (SplitText) and SVG work (DrawSVG stroke reveal, MorphSVG shape morphing, MotionPath).22- Layout transitions (Flip), drag/throw interactions (Draggable + Inertia), unified input (Observer).23- Framework-agnostic code, or animation that must be interrupted/synchronized/dynamically driven.2425**Risk level: LOW** — GSAP is an animation library with a minimal security surface.2627If the user has already chosen another library (e.g. Motion/Framer Motion), respect it. For the GSAP-vs-alternatives call, see `references/decision-matrix.md`.2829**Not GSAP — route instead:** Expo / React Native motion → `expo-motion`; Three.js / React Three Fiber / WebGL 3D scenes → `web-three-r3f` (cinematic 3D look-dev → `r3f-scene-polish`); repo-wide motion-system audits, motion tokens, or cross-stack design-motion direction → `design-motion-audit`.3031## Install & setup3233```bash34npm install gsap @gsap/react35```3637All plugins are in the public package — import what you need and **register plugins once** at a client boundary (not inside re-rendering components), which also keeps them from being tree-shaken away:3839```ts40// lib/gsap.ts — import this module wherever you animate41import { gsap } from "gsap";42import { useGSAP } from "@gsap/react";43import { ScrollTrigger } from "gsap/ScrollTrigger";44import { SplitText } from "gsap/SplitText";4546gsap.registerPlugin(useGSAP, ScrollTrigger, SplitText);47export { gsap, useGSAP, ScrollTrigger, SplitText };48```4950In React/Next, GSAP runs **client-side only**. See `references/react-nextjs.md` for the full pattern (`'use client'`, SSR boundaries, route-change cleanup).5152## Core essentials (the 80% you reach for)5354```tsx55// Tweens: to (current -> vars), from (vars -> current, great for entrances), fromTo, set (instant)56gsap.to(".box", { x: 200, rotation: 360, duration: 1, ease: "power2.out" });57gsap.from(".item", { autoAlpha: 0, y: 24, stagger: 0.1 }); // autoAlpha = opacity + visibility58```5960- **Transform aliases** (prefer over raw `transform`): `x, y, z, xPercent, yPercent, scale, rotation, rotationX/Y, skewX/Y, transformOrigin`. Use `autoAlpha` instead of `opacity` for fades. Properties are camelCase. Details: `references/core.md`.61- **Eases**: `power1..4`, `back`, `elastic`, `bounce`, `expo`, `sine`, `circ` with `.in/.out/.inOut`; `"none"` for linear. Custom curves via `CustomEase`.62- **Timelines** sequence tweens; the **position parameter** controls timing — `"+=0.5"` (gap), `"<"` (with previous), `"<0.2"`, labels:6364```tsx65const tl = gsap.timeline({ defaults: { ease: "power2.out" } });66tl.from(".title", { y: 40, autoAlpha: 0 })67 .from(".subtitle", { y: 20, autoAlpha: 0 }, "<0.1")68 .from(".cta", { scale: 0.9, autoAlpha: 0 }, "-=0.2");69```7071- **React** — use `useGSAP()` (auto-cleanup, Strict-Mode + SSR safe) and scope selectors to a ref:7273```tsx74"use client";75import { useRef } from "react";76import { gsap, useGSAP } from "@/lib/gsap";7778export function Hero() {79 const root = useRef<HTMLDivElement>(null);80 useGSAP(() => {81 gsap.from(".hero-line", { yPercent: 100, stagger: 0.08, ease: "power3.out" });82 }, { scope: root });83 return <div ref={root}>{/* ... */}</div>;84}85```8687- **ScrollTrigger** — scroll-link a tween or timeline (only on the top-level animation, never nested children):8889```tsx90useGSAP(() => {91 gsap.to(".panel", {92 xPercent: -300,93 ease: "none",94 scrollTrigger: { trigger: ".panel", pin: true, scrub: 1, end: "+=3000" },95 });96}, { scope: root });97```9899- **Responsive + accessibility** — `gsap.matchMedia()` runs setup per media query and auto-reverts when it stops matching; always honor reduced motion:100101```tsx102useGSAP(() => {103 const mm = gsap.matchMedia();104 mm.add({ desktop: "(min-width:768px)", reduce: "(prefers-reduced-motion: reduce)" }, (ctx) => {105 if (ctx.conditions!.reduce) { gsap.set(".reveal", { autoAlpha: 1 }); return; }106 gsap.from(".reveal", { autoAlpha: 0, y: 40, stagger: 0.1 });107 });108}, { scope: root });109```110111## Recipes112113`references/recipes.md` has copy-paste Next.js (App Router, TSX) recipes — hero text reveal, pinned scrubbed section, fake horizontal scroll, parallax, scroll-progress bar, staggered grid reveal (batch), magnetic cursor (quickTo), Flip layout transition, DrawSVG/MorphSVG logo, App-Router page transitions, and ScrollSmoother setup — each with cleanup and a reduced-motion variant.114115## Best practices116117- Use camelCase props and transform aliases; `autoAlpha` for fades; documented eases (CustomEase only when needed).118- Prefer timelines over chaining with `delay`; store tween/timeline handles when you need playback control or cleanup.119- In React, prefer `useGSAP()`; scope selectors to a ref; wrap event-handler/async animations in `contextSafe`.120- Register plugins once at a client boundary. Run GSAP client-side only — never during SSR.121- Refresh ScrollTrigger after layout-affecting changes (images/fonts/async content, route transitions).122- Pair responsive values with functions and `invalidateOnRefresh: true` so refresh re-reads them:123124 ```ts125 gsap.to(".panel", {126 x: () => -window.innerWidth,127 scrollTrigger: {128 trigger: ".panel",129 end: () => `+=${window.innerWidth}`,130 invalidateOnRefresh: true,131 },132 });133 ```134135- Animate `transform`/`opacity` over layout properties; use `quickTo` for high-frequency updates; use `gsap.matchMedia()` for breakpoints and `prefers-reduced-motion`.136137## Do not138139- Don't animate `width/height/top/left/margin` when `x/y/scale` achieve the effect (layout thrash).140- Don't use selector strings without a `scope` in React — they leak across components.141- Don't skip cleanup; don't run `gsap`/`ScrollTrigger` during server render.142- Don't put `scrollTrigger` on nested timeline children (only the top-level tween/timeline); don't mix `scrub` with `toggleActions`; don't ship `markers: true` or `GSDevTools` to production.143- Don't assume plugins are gated — they're all free; don't reference `gsap-trial`/Club/registry.144145## Reference routing146147| Read | When |148|---|---|149| `references/core.md` | Tweens, vars, transform aliases, eases, stagger, defaults, matchMedia, function/relative values |150| `references/react-nextjs.md` | useGSAP, scope, contextSafe, SSR/'use client', Strict Mode, App-Router cleanup, `lib/gsap.ts` |151| `references/scrolltrigger.md` | Scroll-driven animation, pin/scrub/snap/batch, scrollerProxy + smooth scroll, horizontal scroll, refresh |152| `references/timeline.md` | Sequencing, position parameter, labels, nesting, playback control |153| `references/plugins.md` | Plugin registration + catalog: Flip, Draggable/Inertia, Observer, SplitText, DrawSVG, MorphSVG, MotionPath, ScrollSmoother, CustomEase, niche plugins |154| `references/performance.md` | 60fps, transform vs layout cost, will-change, quickTo/quickSetter, ScrollTrigger cost, profiling |155| `references/utils.md` | gsap.utils: clamp, mapRange, normalize, interpolate, random, snap, distribute, toArray, pipe, wrap |156| `references/recipes.md` | Production Next.js recipes (App Router, TSX) with cleanup + reduced-motion |157| `references/decision-matrix.md` | GSAP vs CSS / Motion (React) / WAAPI / Tailwind |158159## Optional power tool: `gsap-audit` CLI160161This repo ships a Rust CLI, `gsap-audit`, that statically audits GSAP usage in JS/TS/JSX/TSX.162The rule catalog at `crates/gsap-audit-core/src/rules.rs` is authoritative; `doctor` shows the163exact installed build. It is optional. If it is not installed, proceed with the guidance above.164165| Rule ID | Lead |166| --- | --- |167| `core.gsap-trial-import` | An obsolete `gsap-trial` import remains. |168| `plugins.gsdevtools-in-source` | GSDevTools appears in non-test source. |169| `scrolltrigger.markers-in-prod` | `markers: true` remains in a ScrollTrigger config. |170| `scrolltrigger.scrub-with-toggleactions` | A ScrollTrigger mixes `scrub` and `toggleActions`. |171| `core.gsap2-signature` | A GSAP 2 duration-as-second-argument call remains. |172| `performance.lag-smoothing-disabled` | Ticker lag smoothing is disabled. |173| `core.layout-prop-animation` | A layout property is animated instead of a transform. |174| `plugins.plugin-used-without-register` | A used plugin was not registered. |175| `react.usegsap-not-registered` | `useGSAP` was imported but not registered. |176| `react.gsap-in-ssr` | GSAP is used in an SSR route without a client boundary. |177| `react.unscoped-selector` | A React context uses string selectors without a scope. |178| `react.context-missing-revert` | A `gsap.context()` result is not reverted. |179| `react.state-in-continuous-motion` | React state is set from a continuous motion source, causing renders per frame. |180| `scrolltrigger.nested-timeline-child` | A nested timeline child owns a ScrollTrigger. |181| `react.tween-in-render` | A tween is created during React render. |182| `performance.will-change-permanent` | An animation keeps `will-change` for its full lifetime. |183| `core.missing-overwrite` | An event-handler tween omits overwrite protection. |184| `react.matchmedia-missing-revert` | `gsap.matchMedia()` lacks revert cleanup outside `useGSAP`. |185186```bash187# Install once (from this repo): cargo install --path crates/gsap-audit --locked --force188gsap-audit doctor --format json189gsap-audit scan --root . --format json # audit a project190gsap-audit scan --root . --categories react,scrolltrigger191```192193Treat findings as leads — verify each against the current code before changing behavior.194195## Learn more196197- GSAP docs: https://gsap.com/docs/v3/198- React & GSAP: https://gsap.com/resources/React/199- Eases visualizer: https://gsap.com/docs/v3/Eases