GSAP Skill
SkillAI & modelsGreenSock Animation Platform — high-performance JS animation engine with plugin ecosystem.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the GSAP Skill skill
About this capability
Specialized agents, MCP servers, skills, and a visual dashboard for Claude Code. MIT.
What this skill tells your AI
The instructions your AI receives, as published by claude-dev-suite/claude-dev-suite in skills/animation/gsap/SKILL.md and read by ahel’s review.
GreenSock Animation Platform — high-performance JS animation engine with plugin ecosystem.
Install
npm install gsap
# Plugins (ScrollTrigger free, others require club membership):
# ScrollTrigger, Flip, Observer, ScrollSmoother — included in gsap package
Core API
import gsap from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
import { Flip } from "gsap/Flip";
gsap.registerPlugin(ScrollTrigger, Flip);
| Method | Purpose |
|---|---|
gsap.to(target, vars) | Animate FROM current state TO vars |
gsap.from(target, vars) | Animate FROM vars TO current state |
gsap.fromTo(target, from, to) | Explicit start and end |
gsap.set(target, vars) | Instant set, no animation |
gsap.timeline(vars) | Sequence multiple tweens |
gsap.context(fn, scope) | Scope cleanup (React) |
gsap.matchMedia() | Responsive animations |
Tween Properties
gsap.to(".box", {
x: 100, // translateX (px)
y: -50, // translateY
rotation: 360, // degrees
scale: 1.5,
opacity: 0,
duration: 1,
delay: 0.2,
ease: "power2.out",
stagger: 0.1, // when targeting multiple elements
repeat: -1, // -1 = infinite
yoyo: true, // reverse on repeat
onComplete: () => console.log("done"),
});
Easing Reference
| Ease | Character |
|---|---|
power1-4.in/out/inOut | Polynomial — power2.out is the go-to |
elastic.out(1, 0.3) | Springy bounce |
back.out(1.7) | Slight overshoot |
bounce.out | Ball bounce |
circ.out | Circular — sharp deceleration |
expo.out | Dramatic fast-to-slow |
none / linear | Constant speed |
Timeline
const tl = gsap.timeline({ defaults: { ease: "power2.out", duration: 0.5 } });
tl.from(".hero-title", { opacity: 0, y: 60 })
.from(".hero-subtitle", { opacity: 0, y: 40 }, "-=0.3") // 0.3s overlap
.from(".hero-cta", { opacity: 0, scale: 0.9 }, "+=0.1") // 0.1s gap
.from(".hero-image", { opacity: 0, x: 60 }, "<0.2"); // same start as prev + 0.2
// Position parameter:
// "<" = same start as previous
// ">" = end of previous
// "+=n" = n seconds after end
// "-=n" = n seconds before end
// "1.5" = absolute time in timeline
ScrollTrigger
gsap.to(".panel", {
xPercent: -100 * (panels.length - 1),
ease: "none",
scrollTrigger: {
trigger: ".scroll-container",
pin: true, // pins the trigger element during scroll
scrub: 1, // smooth scrubbing (lag in seconds)
snap: 1 / (panels.length - 1),
end: () => `+=${containerRef.current?.offsetWidth}`,
}
});
// Callbacks
ScrollTrigger.create({
trigger: "#section",
start: "top 80%",
end: "bottom 20%",
onEnter: () => console.log("entered"),
onLeave: () => console.log("left"),
onEnterBack: () => console.log("entered back"),
markers: process.env.NODE_ENV === "development", // visual debug markers
});
React Integration — useGSAP hook
import { useGSAP } from "@gsap/react";
import gsap from "gsap";
import { useRef } from "react";
gsap.registerPlugin(useGSAP);
function AnimatedHero() {
const containerRef = useRef<HTMLDivElement>(null);
useGSAP(() => {
// All GSAP code here is automatically cleaned up on unmount
gsap.from(".title", { opacity: 0, y: 60, duration: 0.8, ease: "power3.out" });
}, { scope: containerRef }); // scope = only select within containerRef
return (
<div ref={containerRef}>
<h1 className="title">Hello</h1>
</div>
);
}
Context (manual cleanup without useGSAP)
useEffect(() => {
const ctx = gsap.context(() => {
gsap.from(".item", { opacity: 0, stagger: 0.1 });
}, containerRef);
return () => ctx.revert(); // kills all tweens created in context
}, []);
Stagger
gsap.from(".card", {
opacity: 0, y: 30,
stagger: {
amount: 0.6, // total time spread across all elements
from: "center", // start: "start" | "end" | "center" | "random" | index
ease: "power2.inOut",
grid: [3, 4], // for grid layouts
}
});
SVG Path Draw (manual, no plugin)
function animatePath(el: SVGPathElement) {
const len = el.getTotalLength();
gsap.set(el, { strokeDasharray: len, strokeDashoffset: len });
gsap.to(el, { strokeDashoffset: 0, duration: 2, ease: "power2.inOut" });
}
matchMedia (responsive)
const mm = gsap.matchMedia();
mm.add("(min-width: 768px)", () => {
gsap.from(".title", { x: -100, opacity: 0 });
});
mm.add("(max-width: 767px)", () => {
gsap.from(".title", { y: 40, opacity: 0 });
});
// Cleanup:
return () => mm.revert();
Reduced Motion
const prefersReduced = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
gsap.to(".element", {
x: prefersReduced ? 0 : 200,
duration: prefersReduced ? 0 : 1,
opacity: 1,
});
Pitfalls
- Always
ctx.revert()or useuseGSAPin React — GSAP tweens survive component unmount otherwise scrub: true= hard sync with scroll;scrub: 1= 1s lag (smoother)pin: true— the trigger element must have explicit height for the pinned section to work- Avoid
document.querySelectorinside components — use refs withgsap.context(scope) ScrollTrigger.refresh()after dynamic content loads (images, fonts)
Signals
- GitHub stars
- 33
- Forks
- 6
- Last commit
- Sep 2026
- Hacker News mentions
- 9
Advanced
- Catalog kind
- skill
- Gateway key
gsap-claude-dev-suite- Source
- github.com/claude-dev-suite/claude-dev-suite