Skip to content
Development
Skill

/gsap-animation

GSAP + Remotion integration for professional motion graphics video production. Timeline orchestration, text splitting, SVG morphing, advanced easing, and reusable effect presets.

BOOST
From plugin
happy-skills
33912 skills
Install
$ npx -y skills add notedit/happy-skills --skill gsap-animation --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/gsap-animation

Context preview

The summary Claude sees to decide when to auto-load this skill.

GSAP + Remotion integration for professional motion graphics video production. Timeline orchestration, text splitting, SVG morphing, advanced easing, and reusable effect presets.

SKILL.md

gsap-animation.SKILL.md
name: gsap-animation
description: GSAP + Remotion integration for professional motion graphics video production. Timeline orchestration, text splitting, SVG morphing, advanced easing, and reusable effect presets.
metadata:
  tags: gsap, remotion, motion-graphics, animation, video, text-animation, svg, timeline, easing

When to use

Use this skill when creating Remotion video compositions that need **GSAP's advanced animation capabilities** beyond Remotion's built-in `interpolate()` and `spring()`.

**Use GSAP when you need:**

  • Complex timeline orchestration (nesting, labels, position parameters like `"-=0.5"`)
  • Text splitting animation (SplitText: chars/words/lines with mask reveals)
  • SVG shape morphing (MorphSVG), stroke drawing (DrawSVG), path-following (MotionPath)
  • Advanced easing (CustomEase from SVG paths, RoughEase, SlowMo, CustomBounce, CustomWiggle)
  • Stagger with grid, center/edges distribution
  • Character scramble/decode effects (ScrambleText)
  • Reusable named effects via `gsap.registerEffect()`

**Use Remotion native `interpolate()` when:**

  • Simple single-property animations (fade, slide, scale) -- do NOT use GSAP for these
  • Numeric counters/progress bars -- pure math, no timeline needed
  • Standard easing curves
  • Spring physics (`spring()`)

**GSAP Licensing:** All plugins are **100% free** since Webflow's 2024 acquisition (SplitText, MorphSVG, DrawSVG, etc.).

---

Setup

# In a Remotion project
npm install gsap
// src/gsap-setup.ts -- import once at entry point
import gsap from 'gsap';
import { SplitText } from 'gsap/SplitText';
import { MorphSVGPlugin } from 'gsap/MorphSVGPlugin';
import { DrawSVGPlugin } from 'gsap/DrawSVGPlugin';
import { MotionPathPlugin } from 'gsap/MotionPathPlugin';
import { ScrambleTextPlugin } from 'gsap/ScrambleTextPlugin';
import { CustomEase } from 'gsap/CustomEase';
import { CustomBounce } from 'gsap/CustomBounce';
import { CustomWiggle } from 'gsap/CustomWiggle';

gsap.registerPlugin(
  SplitText, MorphSVGPlugin, DrawSVGPlugin, MotionPathPlugin,
  ScrambleTextPlugin, CustomEase, CustomBounce, CustomWiggle,
);

export { gsap };

---

Core Hook: useGSAPTimeline

The bridge between GSAP and Remotion. Creates a paused timeline, seeks it to `frame / fps` every frame.

import { useCurrentFrame, useVideoConfig } from 'remotion';
import gsap from 'gsap';
import { useRef, useEffect } from 'react';

function useGSAPTimeline(
  buildTimeline: (tl: gsap.core.Timeline, container: HTMLDivElement) => void
) {
  const frame = useCurrentFrame();
  const { fps } = useVideoConfig();
  const containerRef = useRef<HTMLDivElement>(null);
  const tlRef = useRef<gsap.core.Timeline | null>(null);

  useEffect(() => {
    if (!containerRef.current) return;
    const ctx = gsap.context(() => {
      const tl = gsap.timeline({ paused: true });
      buildTimeline(tl, containerRef.current!);
      tlRef.current = tl;
    }, containerRef);
    return () => { ctx.revert(); tlRef.current = null; };
  }, []);

  useEffect(() => {
    if (tlRef.current) tlRef.current.seek(frame / fps);
  }, [frame, fps]);

  return containerRef;
}

**For SplitText (needs font loading):**

import { delayRender, continueRender } from 'remotion';

function useGSAPWithFonts(
  buildTimeline: (tl: gsap.core.Timeline, container: HTMLDivElement) => void
) {
  const frame = useCurrentFrame();
  const { fps } = useVideoConfig();
  const containerRef = useRef<HTMLDivElement>(null);
  const tlRef = useRef<gsap.core.Timeline | null>(null);
  const [handle] = useState(() => delayRender());

  useEffect(() => {
    document.fonts.ready.then(() => {
      if (!containerRef.current) return;
      const ctx = gsap.context(() => {
        const tl = gsap.timeline({ paused: true });
        buildTimeline(tl, containerRef.current!);
        tlRef.current = tl;
      }, containerRef);
      continueRender(handle);
      return () => { ctx.revert(); };
    });
  }, []);

  useEffect(() => {
    if (tlRef.current) tlRef.current.seek(frame / fps);
  }, [frame, fps]);

  return containerRef;
}

---

1. Text Animations

SplitText Reveal (chars/words/lines)

const TextReveal: React.FC<{ text: string }> = ({ text }) => {
  const containerRef = useGSAPWithFonts((tl, container) => {
    const split = SplitText.create(container.querySelector('.heading')!, {
      type: 'chars,words,lines', mask: 'lines',
    });
    tl.from(split.chars, {
      y: 100, opacity: 0, duration: 0.6, stagger: 0.03, ease: 'power2.out',
    });
  });

  return (
    <AbsoluteFill style={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
      <div ref={containerRef}>
        <h1 className="heading" style={{ fontSize: 80, fontWeight: 'bold' }}>{text}</h1>
      </div>
    </AbsoluteFill>
  );
};

**Patterns:** | Pattern | SplitText Config | Animation | |---------|-----------------|-----------| | Line reveal | `type: "lines", mask: "lines"` | `from lines: { y: "100%" }` | | Char cascade | `type: "chars"` | `from chars: { y: 50, opacity: 0, rotationX: -90 }` | | Word scale | `type: "words"` | `from words: { scale: 0, opacity: 0 }` | | Char + color | `type: "chars"` | `.from(chars, { y: 50 }).to(chars, { color: "#f00" })` |

ScrambleText (decode effect)

> **Determinism warning:** ScrambleText uses internal random character selection. Use `--concurrency=1` when rendering to guarantee frame-perfect reproducibility across renders.

const containerRef = useGSAPTimeline((tl, container) => {
  tl.to(container.querySelector('.text')!, {
    duration: 2,
    scrambleText: { text: 'DECODED', chars: '01', revealDelay: 0.5, speed: 0.3 },
  });
});

**Char sets:** `"upperCase"`, `"lowerCase"`, `"upperAndLowerCase"`, `"01"`, or custom string.

Text Highlight Box

Colored rectangles scale in behind specific words. Uses SplitText for word-level positioning, then absolutely-positioned `<div>` boxes at lower z-index.

const TextHighligh
Read more
Ships withhappy-skills

happy skills

Get the whole plugin

Other skills on happy-skills.