GSAP AI Skills

repository·main·Indexed 12 days ago

https://github.com/greensock/gsap-skills

Specialized knowledge modules designed to teach AI coding agents (such as Claude Code, Cursor, and Copilot) how to correctly implement the GreenSock Animation Platform (GSAP). It provides canonical patterns for the core API, timelines, ScrollTrigger, and framework-specific integrations for React, Vue, and Nuxt, including the use of the @gsap/react package and useGSAP hook.

Tokens
18.5K
Snippets
58
Records
82
Agent score
95%

What's inside GSAP AI Skills

  1. Overview of available GSAP Skills

    main

    The GSAP AI Skills package is divided into several specialized modules that teach agents correct usage of different GSAP features:

    • gsap-core: Core API (gsap.to(), from(), fromTo(), easing, duration, stagger, defaults).
    • gsap-timeline: Sequencing, position parameter, labels, nesting, and playback.
    • gsap-scrolltrigger: Scroll-linked animations, pinning, scrub, triggers, refresh, and cleanup.
    • gsap-plugins: Usage of plugins like ScrollToPlugin, ScrollSmoother, Flip, Draggable, Inertia, Observer, SplitText, ScrambleText, and more.
    • gsap-utils: Helper functions via gsap.utils (clamp, mapRange, normalize, interpolate, random, snap, etc.).
    • gsap-react: React-specific patterns including the useGSAP hook, refs, gsap.context(), cleanup, and SSR.
    • gsap-performance: Best practices for performance (transforms vs layout props, will-change, batching).
    • gsap-frameworks: Lifecycle management and selector scoping for Vue, Svelte, and other frameworks.
  2. Link animation progress to scroll using scrub

    main

    The scrub property ties the progress of an animation directly to the scrollbar position.

    • scrub: true: The animation progress is directly linked to the scroll position.
    • scrub: <number>: The animation follows the scroll position with a delay of <number> seconds, creating a smooth 'catching up' effect.
    gsap.to(".box", {
      x: 500,
      scrollTrigger: {
        trigger: ".box",
        start: "top center",
        end: "bottom center",
        scrub: 1 // smooth lag of 1 second
      }
    });
  3. Configure ScrollTrigger start and end positions

    main

    The start and end properties define when a ScrollTrigger becomes active. They accept strings, numbers, or functions.

    • Format: "triggerPosition viewportPosition" (e.g., "top center", "bottom 80%").
    • Numeric values: A number like 500 represents pixels from the top of the scroller.
    • Relative values: Use "+=300" (300px past start) or "+=100%" (scroller height past start).
    • Clamp: Use clamp() (v3.12+) to keep triggers within page bounds, e.g., start: "clamp(top bottom)".
    • Functions: You can pass a function that receives the ScrollTrigger instance and returns a value. If the layout changes, call ScrollTrigger.refresh() to recalculate positions.
  4. Core Principles for GSAP in Component Frameworks

    main

    When using GSAP with component-based frameworks (Vue, Svelte, etc.), follow these three core principles to prevent memory leaks and selector collisions:

    1. Create after mounting: Always initialize tweens and ScrollTrigger instances inside lifecycle hooks that run after the DOM is available (e.g., onMounted in Vue, onMount in Svelte).
    2. Scope selectors: Use gsap.context(callback, scope) where scope is your component's root element. This ensures selectors like .box only target elements within that specific component instance.
    3. Cleanup on unmount: Always call ctx.revert() in the component's unmount/destroy lifecycle hook. This kills all animations and ScrollTrigger instances tracked by that context and reverts inline styles.
  5. Scope Selectors with gsap.context()

    main

    To prevent GSAP from selecting elements outside your component, always provide a scope to gsap.context().

    • Correct: gsap.context(() => { gsap.to(".box", { ... }) }, containerRef) — The selector .box is restricted to the containerRef subtree.
    • Incorrect: gsap.to(".box", { ... }) — This uses a global selector and may animate elements in other components or elsewhere on the page.
    // Scoped to the container
    ctx = gsap.context(() => {
      gsap.to(".box", { x: 100 });
    }, container.value);
  6. Best practices for managing many elements and animations

    main

    To prevent jank when dealing with large numbers of elements or complex timelines:

    • Staggering: Use the stagger property instead of creating many separate tweens with manual delays when the animation logic is the same.
    • Virtualization: For long lists, consider animating only visible items or using virtualization to avoid creating hundreds of simultaneous tweens.
    • Timeline Reuse: Reuse timelines where possible rather than creating new ones every frame.
    • Cleanup: Always kill or pause off-screen or inactive animations when they are no longer visible to prevent stray tweens from consuming resources.
  7. Nest timelines within other timelines

    main

    Timelines can be treated as single units and added to other timelines using the .add() method. This is useful for building complex, modular animation structures.

    const master = gsap.timeline();
    const child = gsap.timeline();
    
    child.to(".a", { x: 100 }).to(".b", { y: 50 });
    
    // Add the child timeline to the master at time 0
    master.add(child, 0);
    master.to(".c", { opacity: 0 }, "+=0.2");
    const master = gsap.timeline();
    const child = gsap.timeline();
    child.to(".a", { x: 100 }).to(".b", { y: 50 });
    master.add(child, 0);
    master.to(".c", { opacity: 0 }, "+=0.2");
  8. Use the position parameter to control animation timing

    main

    The position parameter is the third argument in a .to() (or similar) call. It allows you to place tweens at specific times, relative to other tweens, or at specific labels.

    Placement Types:

    • Absolute: A number representing seconds (e.g., 1).
    • Relative: A string using += or -= (e.g., "+=0.5" starts 0.5s after the previous animation ends; "-=0.2" starts 0.2s before the previous animation ends).
    • Label: A string matching a label name (e.g., "labelName" or "labelName+=0.3").
    • Relationship (Relative to previous tween):
      • "<": Starts at the same time as the most recently added animation.
      • ">": Starts when the most recently added animation ends (default).
      • "<0.2": Starts 0.2s after the most recently added animation starts.
    tl.to(".a", { x: 100 }, 0);           // at 0 seconds
    tl.to(".b", { y: 50 }, "+=0.5");      // 0.5s after last end
    tl.to(".c", { opacity: 0 }, "<");     // same start as previous
    tl.to(".d", { scale: 2 }, "<0.2");    // 0.2s after previous start
  9. How to use the function form of gsap.utils

    main

    Many gsap.utils methods allow you to create reusable functions by omitting the final value argument. This is highly efficient for high-frequency operations like mousemove handlers or tween callbacks where the configuration (like a range or a snap increment) remains constant while the input value changes.

    Note on random(): Unlike other utilities, random() does not use the omission pattern. To get a reusable function from random(), you must pass true as the last argument (returnFunction).

    // Standard pattern: omit the last argument to get a function
    let c = gsap.utils.clamp(0, 100);
    c(150); // 100
    
    // Exception: random() requires 'true' as the last argument
    let randomFn = gsap.utils.random(-200, 500, 10, true);
    randomFn(); // returns a new random value
  10. Use Function-based and Relative values

    main

    GSAP allows for dynamic values and relative adjustments within the vars object.

    Function-based values

    If a property value is a function, it is called once for each target during the first render. The return value is used for that specific target.

    Relative values

    Use prefixes to indicate relative changes to the current value:

    • +=n: Add n to current value.
    • -=n: Subtract n from current value.
    • *=n: Multiply current value by n.
    • /=n: Divide current value by n.
    // Function-based: each item moves based on its index
    gsap.to(".item", {
      x: (i, target, targetsArray) => i * 50
    });
    
    // Relative: move 20px less than current position
    gsap.to(".class", { x: "-=20" });
  11. Wrap event handlers with contextSafe

    main

    Animations created inside functions that execute after the initial useGSAP run (such as event listeners) are not automatically tracked by the GSAP context. To ensure these animations are cleaned up on unmount, wrap the function in contextSafe provided by the useGSAP hook.

    const container = useRef();
    const goodRef = useRef();
    
    useGSAP((context, contextSafe) => {
      // ✅ safe, created during execution
      gsap.to(goodRef.current, { x: 100 });
    
      // ✅ safe, wrapped in contextSafe() so it's tracked by the context
      const onClickGood = contextSafe(() => {
        gsap.to(goodRef.current, { rotation: 180 });
      });
    
      goodRef.current.addEventListener('click', onClickGood);
    
      // Clean up the listener manually
      return () => {
        goodRef.current.removeEventListener('click', onClickGood);
      };
    }, { scope: container });