gsap-animations
activeCreates and orchestrates high-performance GSAP animation components — page loaders, scroll effects, text reveals, navigation transitions, slideshows, and micro-interactions. Generates production-ready code with state gating, defensive DOM queries, and proper cleanup. Use this skill whenever the user asks to build animations, motion design, page transitions, loading sequences, scroll-triggered effects, parallax, text splitting/revealing, animated navigation menus, slideshows, or any interactive motion component. Also trigger when users mention GSAP, GreenSock, ScrollTrigger, SplitText, Physics2D, Lenis smooth scroll, or want to add "life" or "polish" to a UI. Covers vanilla JS, React, Next.js, and Astro implementations. Do NOT use for CSS-only animations, Framer Motion, or non-animation frontend tasks like routing or state management.
Quality Score Breakdown
Show checks (11)
- ✓ SKILL.md exists with exact casing 3/3
- ✓ Valid YAML frontmatter 3/3
- ✓ No unexpected frontmatter keys 1/1
- ✓ Name field valid (kebab-case) 2/2
- ✓ Name matches folder name 1/1
- ✓ Description field present 2/2
- ✓ No angle brackets in frontmatter 1/1
- ✓ Folder name is kebab-case 1/1
- ✓ No README.md inside skill folder 1/1
- ✓ Test directory with test-cases.yml exists 2/2
- ✓ Status 'active' is valid 1/1
Show checks (7)
- ✓ Contains action verbs: creates, generates, orchestrates 4/4
- ✓ Contains trigger indicators: use for, use this, trigger, asks to 5/5
- ✓ Description is specific and actionable 4/4
- ✓ File types mentioned in description 3/3
- ✓ Description length: 845/1024 chars 2/2
- ✓ Has negative triggers (scope boundaries) 2/2
- ✓ Owner/author specified in metadata 2/2
Show checks (8)
- ✓ Skill body has content 3/3
- ✓ Has step/section structure 4/4
- ✓ Includes examples 5/5
- ✓ Includes error handling 4/4
- ✓ Uses progressive disclosure (references/scripts) 4/4
- ✓ Actionable language: 4/10 verb patterns found 3/3
- ✓ Word count: 1146/5000 2/2
- ✓ All referenced paths exist 3/3
Show checks (10)
- ✓ test-cases.yml exists and parses 3/3
- ✓ 10 should-trigger tests ✓ 4/4
- ✓ 5 should-not-trigger tests ✓ 3/3
- ✓ 7 functional tests ✓ 5/5
- ✓ 2 negative tests ✓ 3/3
- ✓ 2 edge case tests ✓ 3/3
- ✓ Performance baseline documented 2/2
- ✓ All functional tests have ≥2 assertions 2/2
- ✓ All trigger phrases are diverse 2/2
- ✓ All assertions are specific 2/2
Show checks (5)
- ✓ No secrets detected 5/5
- ✓ No injection vectors in frontmatter 3/3
- ✓ Name is not reserved 3/3
- ✓ No suspicious code patterns 2/2
- ✗ 7 external URLs found — verify they're necessary: https://cdn.jsdelivr.net/npm/, https://cdn.jsdelivr.net/npm/, https://cdn.jsdelivr.net/npm/gsap@3.13.0/dist/gsap.min.js 1/2
Test Coverage
GSAP Animations Skill
Create production-grade GSAP animation components that transform static interfaces into memorable, tactile experiences. Every animation should feel intentional, physically grounded, and choreographed — not decorative.
Quick Reference — Read Before Building
Before writing any animation code, read the relevant reference files based on the task:
| Task | Reference File |
|---|---|
| Any GSAP component | references/core-patterns.md ← ALWAYS read this first |
| Page load / intro sequences | references/loading-animations.md |
| Scroll-driven effects | references/scroll-animations.md |
| Page transitions (between pages) | references/page-transitions.md |
| Navigation / menu animations | references/navigation-animations.md |
| Text reveals, splits, loops | references/text-animations.md |
| React / Next.js / Astro setup | references/framework-adapters.md |
| Responsive scaling system | references/scaling-system.md |
Read references/core-patterns.md for EVERY task — it contains the universal rules that all components must follow.
Design Philosophy
These animations work because they follow three principles:
1. Choreography over decoration. Every element enters with purpose. Timelines orchestrate 5-15 elements into a single cohesive motion, not isolated bounces. The "<" position parameter is used extensively to run tweens in parallel with fine-grained offsets — this is what makes complex sequences feel like one fluid gesture.
2. Physical grounding. Motion feels real because it references physics — elastic overshoot on a word carousel, gravity on falling text, parallax depth on slideshows. Easing choices define personality: expo.inOut for dramatic power, expo.out for confident arrivals, elastic.out for playful mechanics, and custom eases for signature motion.
3. Invisible infrastructure. Users never see loading flicker, broken font metrics, or scroll jank. Class-based state gating (is--hidden → is--loading → final) prevents flash. document.fonts.ready protects SplitText measurements. Lenis syncs smooth scroll with ScrollTrigger via a shared ticker. The animation code that users DO see is built on defensive infrastructure they don’t.
Component Architecture
Every GSAP component follows this structure:
1. Register plugins at file top
2. Define custom eases
3. Wrap in an init function
4. Query DOM with defensive null-checks
5. Build timeline(s)
6. Gate initialization (DOMContentLoaded + fonts.ready if text)
gsap.registerPlugin(ScrollTrigger, SplitText, CustomEase);
CustomEase.create("smooth", "0.625, 0.05, 0, 1");
function initMyComponent() {
const container = document.querySelector(".my-component");
if (!container) return;
const elements = container.querySelectorAll(".my-element");
const heading = container.querySelector("h1");
// Timeline with shared defaults
const tl = gsap.timeline({
defaults: { ease: "expo.inOut", duration: 1.2 },
onStart: () => container.classList.remove("is--hidden"),
});
// Defensive checks before each animation block
if (elements.length) {
tl.fromTo(elements,
{ yPercent: 100, opacity: 0 },
{ yPercent: 0, opacity: 1, stagger: 0.05 }
);
}
}
document.addEventListener("DOMContentLoaded", () => {
document.fonts.ready.then(() => initMyComponent());
});
Core Rules
These rules apply to every GSAP component. Violating them produces the jank, flicker, and breakage that separates amateur animations from production ones.
State Management
- Use class-based state gating:
is--hidden(display:none initially) → remove ononStart→is--loadingremoved on complete - Store interactive state on DOM with
data-*attributes (e.g.,data-nav-state="open") - Use
data-*attributes for component targeting — never rely on class names that may change
Timeline Construction
- Use
gsap.timeline()withdefaultsfor shared easing and duration - Position tweens with
"<"(start of previous) and"< 0.2"(offset from previous start) for parallel choreography - Use
fromTofor explicit start states — never assume DOM state - Wrap every animation block in
if (elements.length)guards
Performance
- Use
xPercent/yPercentover pixel values — they’re resolution-independent - Use
autoAlphainstead ofopacity— it togglesvisibility: hiddenat 0, removing elements from accessibility tree - Keep
will-changein CSS for known animated properties, never set it via JS - Use
emunits in CSS for dimensions that should scale responsively
Easing Vocabulary
| Feel | Ease | Use Case |
|---|---|---|
| Dramatic power | expo.inOut | Loading sequences, hero reveals |
| Confident arrival | expo.out | Content entering viewport |
| Snappy interface | CustomEase("0.65, 0.01, 0.05, 0.99") | Nav toggles, UI state changes |
| Playful mechanic | elastic.out(1, 0.85) | Carousels, slot-machine effects |
| Smooth wipe | CustomEase("0.625, 0.05, 0, 1") | Slideshow transitions, panel reveals |
| No ease (physics) | "none" | When Physics2D or real physics handles motion |
Stagger Patterns
| Pattern | Config | Effect |
|---|---|---|
| Cascade | { each: 0.05 } | Sequential wave |
| Spread | { amount: 0.75, from: "random" } | Pixelated / organic |
| Pinch | { each: 0.05, from: "edges" } | Edges-first convergence |
| Reveal | { each: 0.025 } | Fast letter-by-letter |
Plugin Reference
| Plugin | CDN | Purpose |
|---|---|---|
| gsap core | gsap@3.13.0/dist/gsap.min.js | Timeline, tweens, easing |
| ScrollTrigger | gsap@3.13.0/dist/ScrollTrigger.min.js | Scroll-driven animation |
| SplitText | gsap@3.13.0/dist/SplitText.min.js | Text splitting + masked reveals |
| CustomEase | gsap@3.13.0/dist/CustomEase.min.js | Custom easing curves |
| Physics2DPlugin | gsap@3.13.0/dist/Physics2DPlugin.min.js | Gravity, velocity, angle-based motion |
| Lenis | lenis@1.2.3 (separate) | Smooth scroll, syncs with GSAP ticker |
CDN base: https://cdn.jsdelivr.net/npm/
CSS Foundation
Every GSAP component needs these CSS patterns:
/* State gating — prevent flash of unstyled content */
.component.is--hidden { display: none; }
/* Scroll lock during loading */
main:has(.component.is--loading) { height: 100dvh; }
/* Masked reveal containers */
.reveal-container { overflow: hidden; }
/* Animated elements */
.animated-element {
will-change: transform;
}
Error Handling
- Missing DOM elements: Every
querySelectorAllresult must be guarded with.lengthcheck. SinglequerySelectorresults must be checked for truthiness. The timeline should still work when optional elements are absent. - Font loading race condition: SplitText animations must gate on
document.fonts.readyinsideDOMContentLoaded. Without this, character measurements break when web fonts swap in after splitting. - Rapid toggle (nav/modal): Use
tl.clear()on a single reusable timeline instead of creating new timelines. This prevents half-open states when users click open/close rapidly. - Back/forward cache: Page transitions must handle the
pageshowevent withevent.persistedcheck. Without this, browsers restoring from bfcache show a frozen exit-animation state. - Memory leaks: React components must return
ctx.revert()from the cleanup function. Vanilla JS components using ScrollTrigger must kill triggers on teardown. SplitText withautoSplitmust returngsap.context()fromonSplit.
Output Quality Checklist
Before delivering any GSAP component, verify:
- No flash of unstyled content —
is--hiddenclass prevents it - Timeline has
defaultswith easing and duration - Every querySelectorAll result is guarded with
.lengthcheck - Text animations wait for
document.fonts.ready - Uses
xPercent/yPercentinstead of pixel transforms - Stagger values feel natural (0.025-0.1 for letters, 0.05-0.15 for elements)
- Custom eases are registered at file top, not inline
-
data-*attributes used for JS targeting -
emunits used for responsive dimensions in CSS - Cleanup is handled (context return, kill methods, or event removal)