agentsclimarketplace

Gsap

Skill AThevon/genjutsu/skills/_jutsu/gsap

Creative coding skills for Claude: animations, 3D, design systems, motion principles

Install
npx -y skills add AThevon/genjutsu --skill gsap

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

What its author says it does

Copied from the file, not written here

GSAP animation engine sub-skill - core, timeline, ScrollTrigger, plugins.

SKILL.md

5.2 KB, as published. Nobody here has run it

GSAP — Animation Engine

When to use GSAP

CriteriaCSS TransitionsFramer MotionGSAP
Hover / simple toggleYesYesOverkill
Sequenced timelineNoLimitedYes
Scroll-drivenscroll-timelineLimitedScrollTrigger
Complex staggerNoBasicDistribution
Mobile perf (60fps)GoodAverageExcellent
Text splittingNoNoSplitText
SVG morph / drawNoNoMorphSVG
Bundle size concern0kb~30kb~25kb + plugins

Rule: if the animation needs timeline, scroll-link, or distributed stagger, use GSAP. Otherwise CSS first.

Setup

// Always register plugins at the top level
import gsap from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
import { SplitText } from "gsap/SplitText";

gsap.registerPlugin(ScrollTrigger, SplitText);

React: use useGSAP() from the @gsap/react package instead of useEffect + manual cleanup.

import { useGSAP } from "@gsap/react";

useGSAP(() => {
  gsap.to(".box", { x: 200 });
}, { scope: containerRef }); // auto-cleanup, auto-revert

Core Patterns

defaults{} to avoid repetition

const tl = gsap.timeline({
  defaults: { duration: 0.8, ease: "power2.out" },
});
tl.to(".a", { y: -20 })
  .to(".b", { y: -20 }, "<0.1")
  .to(".c", { y: -20 }, "<0.1");

fromTo for full control

gsap.fromTo(".card", { y: 40, opacity: 0 }, { y: 0, opacity: 1, stagger: 0.15 });

Stagger with distribution

gsap.to(".grid-item", {
  scale: 0,
  stagger: {
    each: 0.05,
    from: "center",   // "start" | "end" | "center" | "edges" | "random" | index
    grid: "auto",      // auto-detects the grid
    axis: "x",         // "x" | "y" | null (both)
  },
});

ScrollTrigger Patterns

Basic Pin + Scrub

gsap.to(".panel", {
  x: "-300%",
  ease: "none",
  scrollTrigger: {
    trigger: ".container",
    pin: true,
    scrub: 1,
    end: () => "+=" + document.querySelector(".container").scrollWidth,
  },
});

Batch for mass reveal

ScrollTrigger.batch(".card", {
  onEnter: (elements) => gsap.to(elements, { opacity: 1, y: 0, stagger: 0.1 }),
  start: "top 85%",
});

Horizontal scroll with containerAnimation

const scrollTween = gsap.to(".panels", {
  x: () => -(document.querySelector(".panels").scrollWidth - window.innerWidth),
  ease: "none",
  scrollTrigger: { trigger: ".wrapper", pin: true, scrub: 1 },
});

// Animate elements INSIDE the horizontal scroll
gsap.to(".panel-content", {
  scale: 1.2,
  scrollTrigger: {
    trigger: ".panel-content",
    containerAnimation: scrollTween, // linked to horizontal scroll
    start: "left center",
    end: "right center",
    scrub: true,
  },
});

DO NOT — Critical mistakes

1. Ease on containerAnimation

// BAD — ease breaks the scroll mapping
scrollTrigger: { containerAnimation: scrollTween, scrub: 1, ease: "power2.out" }

// GOOD — always ease: "none" on the parent tween
const scrollTween = gsap.to(".panels", { x: ..., ease: "none", scrollTrigger: { scrub: 1 } });

2. ScrollTrigger on a child tween in a timeline

// BAD — ScrollTrigger ignores child tweens of a timeline that has its own ScrollTrigger
const tl = gsap.timeline({ scrollTrigger: { trigger: ".section" } });
tl.to(".box", { x: 100, scrollTrigger: { trigger: ".box" } }); // IGNORE

// GOOD — one ScrollTrigger per timeline OR standalone tweens
gsap.to(".box", { x: 100, scrollTrigger: { trigger: ".box" } }); // tween standalone

3. setState in onUpdate

// BAD — setState 60x/s = re-render hell
scrollTrigger: { onUpdate: (self) => setProgress(self.progress) }

// GOOD — mutate a ref or DOM element directly
const progressRef = useRef(0);
scrollTrigger: { onUpdate: (self) => { progressRef.current = self.progress; } }
// Or better: gsap.quickSetter to mutate the DOM without React

4. immediateRender on from() in a timeline

// BAD — from() has immediateRender: true by default, breaks sequencing
tl.to(".box", { x: 100 });
tl.from(".box", { y: 50 }); // visually jumps to the start

// GOOD — disable immediateRender when from() follows another tween
tl.to(".box", { x: 100 });
tl.from(".box", { y: 50, immediateRender: false });

5. Animating non-transform properties

// BAD — width/height/top/left trigger layout reflow
gsap.to(".box", { width: 200, height: 200 });

// GOOD — use transforms (GPU-accelerated, composited)
gsap.to(".box", { scaleX: 1.5, scaleY: 1.5 });
// If actual size needed: use Flip plugin for layout transition

Refs

  • references/core.md — Complete gsap.to/from/fromTo/set API, options
  • references/timeline.md — Timeline, position parameter, nesting
  • references/scrolltrigger.md — Full ScrollTrigger reference
  • references/plugins.md — SplitText, Flip, MorphSVG, DrawSVG, MotionPath, Observer

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.