smithery.ai

Create Animations

Create scroll-triggered animations using GSAP and ScrollTrigger in React/TypeScript.

Installation

$ npx skills add https://smithery.ai

Summary

  • Create scroll-triggered animations using GSAP and ScrollTrigger in React/TypeScript.
  • Use this skill when building animated illustrations, scroll-driven animations, SVG animations, or interactive visual components for the portfolio.
  • Triggers on requests to create, modify, or debug animations.

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from smithery.ai · top by installs.

npx skills add https://smithery.ai

Browse all from smithery.ai

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 4,787 B
  • docs SUMMARY.md 317 B

History

  1. First recorded snapshot · 1 installs

SKILL.md

Create Animations

Build scroll-triggered animations using GSAP with ScrollTrigger in React/TypeScript. Animations use SVG for complex illustrations and DOM elements for 3D transforms.

Component Structure

'use client';

import { useEffect, useRef } from 'react';
import gsap from 'gsap';
import { ScrollTrigger } from 'gsap/ScrollTrigger';

gsap.registerPlugin(ScrollTrigger);

const MyAnimation = () => {
  const containerRef = useRef<HTMLDivElement>(null);
  const elementRef = useRef<SVGGElement>(null);

  useEffect(() => {
    const ctx = gsap.context(() => {
      if (!containerRef.current || !elementRef.current) return;

      gsap.set(elementRef.current, { opacity: 0, scale: 0 });

      const tl = gsap.timeline({
        scrollTrigger: {
          trigger: containerRef.current,
          start: 'top bottom',
          end: 'bottom top',
          toggleActions: 'restart none restart reset',
        },
      });

      tl.to(elementRef.current, {
        opacity: 1,
        scale: 1,
        duration: 0.4,
        ease: 'back.out(1.7)',
      });
    }, containerRef);

    return () => ctx.revert();
  }, []);

  return (
    <div ref={containerRef} className="relative flex aspect-square h-96 items-center justify-center">
      <svg viewBox="0 0 320 200" className="relative z-10 h-full w-full" style={{ overflow: 'visible' }}>
        {/* Content */}
      </svg>
    </div>
  );
};

ScrollTrigger

toggleActions format: "onEnter onLeave onEnterBack onLeaveBack"

  • restart none restart reset - Replays on enter, resets when fully leaving viewport
  • play none none none - Plays once only

Markers:

  • start: 'top bottom' - Triggers when element top hits viewport bottom
  • end: 'bottom top' - Ends when element bottom hits viewport top

SVG Patterns

Gradients & Shadows

<defs>
  <linearGradient id="grayGradient" x1="0%" y1="0%" x2="100%" y2="100%">
    <stop offset="0%" stopColor="#525252" />
    <stop offset="100%" stopColor="#3f3f3f" />
  </linearGradient>
  <filter id="shadow" x="-20%" y="-20%" width="140%" height="140%">
    <feDropShadow dx="0" dy="1" stdDeviation="1.5" floodColor="#000" floodOpacity="0.25" />
  </filter>
</defs>

SVG Transform Origin

gsap.set(element, { rotation: 45, svgOrigin: '160 100' }); // x y in viewBox coords

Z-Ordering

SVG: Elements rendered later appear on top. Reorder JSX to control layering.

DOM with 3D transforms: CSS z-index unreliable. Use DOM order instead:

// Interleave for proper merge animations
const panes = [
  { side: 'left', index: 0 },
  { side: 'right', index: 0 },
  { side: 'left', index: 1 },
  // ...
];

GSAP Techniques

Stagger

gsap.to(elements, { opacity: 1, stagger: 0.06 });
gsap.to(elements, { opacity: 1, stagger: { amount: 0.4, from: 'random' } });

Timeline Positioning

tl.to(el1, { x: 0 })           // After previous
  .to(el2, { y: 0 }, '<')      // Same time as previous
  .to(el3, { scale: 1 }, '-=0.1'); // Overlaps by 0.1s

Transform Origin

gsap.set(element, { transformOrigin: 'left center' });
gsap.set(svgElement, { svgOrigin: '160 100' });

Colors

Dark elements: Gray gradients #3f3f3f to #525252

Highlights: CSS variables fill="var(--color-primary-500)"

Light elements: White fill + dark stroke stroke="#525252"

Backgrounds: Very subtle from-gray-200/30 via-transparent to-gray-100/20

Shadows

Keep subtle:

  • SVG: stdDeviation="1.5", floodOpacity="0.25"
  • Tailwind: shadow-sm shadow-black/20

Refs

Array

const elementsRef = useRef<(SVGGElement | null)[]>([]);
{items.map((item, i) => (
  <g ref={(el) => { elementsRef.current[i] = el; }} />
))}

Animation Concepts

Type Description
Merge Elements apart → slide together → transform into unified result
Scatter to Grid Scattered + rotated → snap into organized grid
Stack Collapse 3D stacked panes → collapse → transform to new element
Burst Central element → spawns elements animating outward

Checklist

  • Elements stay within canvas bounds (check scattered positions)
  • Z-order correct (SVG render order, DOM order for 3D)
  • Shadows subtle (not heavy)
  • Primary color highlights in both initial and final states
  • gsap.context() with cleanup ctx.revert()
  • Null checks for all refs