Gsap Web logo

Gsap Web

Organization
iart-ai
gsap-web

This skill should be used when the user asks to "build a scroll animation", "add ScrollTrigger", "pin a section while scrolling", "scrub an animation to scroll", "create a hero timeline", "do a horizontal scroll section", "split text and animate words", "animate a layout change with GSAP Flip", "sync ScrollTrigger with Lenis", "Lenis smooth scroll jittery", "ScrollTrigger markers drift", "ScrollTrigger pins break with Lenis/Locomotive", or "set up smooth scroll with GSAP pinning". Covers GSAP timelines, ScrollTrigger, SplitText, Flip, and Lenis/Locomotive smooth-scroll sync for code-driven web motion.

Overview

Publisheriart-ai
Repositoryweb-animation-skills
Skill namegsap-web
Stars
71
Forks
10
Bundled files
4
LicenseMIT
Links
  • Markdown instructions

    A SKILL.md file the model loads on demand, so it only costs tokens when a request actually matches.

  • Works with any LLM

    AI skills are plain Markdown, not provider-specific code, so this works with GPT, Claude, Gemini, Grok, or a local model.

  • 4 bundled files

    Scripts, templates, and references the model can read while it works. Files are read-only and never executed.

  • Open source

    Published by iart-ai on GitHub. Read the source before you install it.

Installation

Install the Gsap Web AI skill in TypingMind to use it with any LLM, or drop it into another agent that reads SKILL.md.

1

Install in TypingMind

TypingMind installs a skill straight from its GitHub folder — it reads SKILL.md, bundles the resource files, and stores the result locally.

  1. Open the app and go to Plugins → Skills.
  2. Choose "Install from GitHub".
  3. Paste the skill folder URL below and confirm.
    https://github.com/iart-ai/web-animation-skills/tree/main/skills/gsap-web
  4. Enable the skill in any chat where you want it available.
Plugins → Skills → Add skill → From GitHub URL, then paste the folder URL and press Continue.
2

Install in another agent

Any agent that reads the Agent Skills format can use this skill — copy the folder into that agent's skills directory.

Claude Code — .claude/skills
git clone --depth 1 https://github.com/iart-ai/web-animation-skills.git /tmp/web-animation-skills
mkdir -p .claude/skills
cp -r /tmp/web-animation-skills/skills/gsap-web .claude/skills/gsap-web
Restart Claude Code after copying so it picks up the new skill.

Use it in TypingMind

Enable Gsap Web in any TypingMind chat and the model takes it from there. Its name and description sit in the system prompt, and the moment a request matches, the model loads the full instructions itself — you never invoke it by hand, and it costs no tokens until it is actually used.

The model loads Gsap Web on its own as soon as a request matches it.

Works with any AI model

AI skills are plain Markdown instructions rather than provider-specific code, so Gsap Web is not tied to the model it was written for. Install it once in TypingMind and use it with GPT-5, Claude, Gemini, Grok, DeepSeek, Mistral, Llama, or a local model you run yourself — all on your own API keys.

  • Loaded only when it is needed

    The system prompt carries just the name and description. The instructions are fetched on the first matching request, so an idle skill costs nothing.

  • Switch models mid-chat

    Because the skill is instructions rather than code, changing model does not break it — the next model reads the same SKILL.md.

Skill instructions

This is the SKILL.md content the model loads. Read it before installing — a skill is instructions your model will follow.

GSAP for the Web

GSAP (GreenSock Animation Platform) is the workhorse for code-driven web motion: sequenced timelines, scroll-driven storytelling, text reveals, and layout transitions. As of GSAP 3.12+, every plugin (ScrollTrigger, SplitText, Flip, MotionPath, MorphSVG, Draggable, Observer) is 100% free, including for commercial use.

When to use

  • Scroll-driven storytelling: pinned sections, parallax, progress scrubbing, horizontal scroll
  • Sequenced hero animations and complex multi-element timelines with precise overlap control
  • Text reveals split into chars/words/lines (SplitText)
  • Layout transitions where an element changes position/size/parent (Flip)
  • Any motion needing fine timing control, easing precision, or imperative orchestration

Install and register

js
import gsap from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
import { SplitText } from "gsap/SplitText";
import { Flip } from "gsap/Flip";

gsap.registerPlugin(ScrollTrigger, SplitText, Flip);

Plugins MUST be registered before use or they silently no-op. With a bundler, register once at app entry.

Core techniques

Timelines first

Prefer one timeline over many independent tweens — it gives a single playhead, relative positioning, and easy reversal.

js
const tl = gsap.timeline({ defaults: { ease: "power3.out", duration: 0.6 } });
tl.from(".title", { yPercent: 100, opacity: 0 })
  .from(".sub",   { y: 20, opacity: 0 }, "-=0.3")  // start 0.3s before prev ends
  .from(".cta",   { scale: 0.9, opacity: 0 }, "<"); // align to prev tween START

Position parameter cheat sheet:

  • "+=0.5" / "-=0.3" — relative to the end of the timeline (gap / overlap)
  • "<" — start of the previous tween; ">" — end of the previous tween
  • "<0.2" — 0.2s after the previous tween's start
  • "myLabel" — at a named label added via tl.addLabel("myLabel")

Use .from() for entrances (animates FROM the given values TO current CSS), .to() for exits, .fromTo() when both ends must be explicit (most robust against re-runs).

gsap.to vs set vs quickTo

js
gsap.set(el, { autoAlpha: 0 });           // instant, no tween (autoAlpha = opacity + visibility)
const xTo = gsap.quickTo(el, "x", { duration: 0.4, ease: "power3" });
window.addEventListener("pointermove", (e) => xTo(e.clientX)); // fast repeated updates

autoAlpha is preferred over raw opacity because it also toggles visibility:hidden at 0, removing the element from hit-testing.

ScrollTrigger basics

js
gsap.to(".panel", {
  xPercent: -100,
  ease: "none",
  scrollTrigger: {
    trigger: ".wrap",
    start: "top top",      // when trigger top hits viewport top
    end: "+=2000",         // 2000px of scroll distance
    pin: true,             // freeze .wrap while the tween plays
    scrub: 1,              // tie progress to scrollbar (1 = 1s catch-up smoothing)
    markers: true,         // dev-only visual markers — remove for prod
  },
});

Key semantics:

  • start/end take "triggerPos viewportPos" (e.g. "top center") or "+=px".
  • scrub: true locks animation progress to scroll exactly; scrub: <number> adds smoothing lag.
  • toggleActions: "play pause resume reverse" controls onEnter/onLeave/onEnterBack/onLeaveBack for non-scrubbed triggers.
  • Use ease: "none" for scrubbed tweens so motion tracks scroll linearly.

Smooth scroll (Lenis) + ScrollTrigger

Pairing Lenis (or Locomotive) smooth scrolling with ScrollTrigger desyncs unless both run on one loop. Lenis smooths scroll on its own rAF while ScrollTrigger reads scroll on GSAP's ticker; when they tick independently ScrollTrigger samples a stale position. The fix: drive Lenis from GSAP's ticker and update ScrollTrigger on every Lenis scroll.

js
import Lenis from "lenis";

const lenis = new Lenis({ duration: 1.2, smoothWheel: true });

lenis.on("scroll", ScrollTrigger.update);          // 1. update ScrollTrigger on every Lenis scroll
gsap.ticker.add((t) => lenis.raf(t * 1000));       // 2. one loop: ticker drives Lenis (seconds → ms)
gsap.ticker.lagSmoothing(0);                        // 3. stop GSAP catch-up jitter on heavy frames

Critical: gsap.ticker passes time in seconds, lenis.raf() wants milliseconds — multiply by 1000. Do NOT also run a standalone requestAnimationFrame(raf) loop for Lenis; that double-drives it.

Common bugs:

  • Jitter/stutter — a leftover requestAnimationFrame(raf) loop competing with the ticker, or missing lagSmoothing(0). Remove the rogue loop; set lag smoothing to 0.
  • Markers drift from their triggers — ScrollTrigger.update is not subscribed to lenis.on("scroll", …).
  • Pins break — under Lenis do NOT set a scrollerProxy (it scrolls the document). Under Locomotive you MUST wire scrollerProxy + pinType and set scroller: on every trigger.
  • Scroll stuck / flipped direction — missing the * 1000 unit conversion, or two loops out of order.

Cleanup on SPA unmount: gsap.ticker.remove(update) + lenis.destroy(), else loops stack per navigation. Gate behind prefers-reduced-motion (skip Lenis, run native scroll). Full Lenis + Locomotive wiring, anchor-link routing, data-lenis-prevent, React (useGSAP/useEffect), and a symptom→cause table are in references/scrolltrigger-lenis.md.

SplitText (text reveal)

js
const split = SplitText.create(".headline", { type: "lines, words", linesClass: "line" });
gsap.from(split.lines, { yPercent: 100, opacity: 0, stagger: 0.08, duration: 0.7, ease: "power4.out" });

Gotchas:

  • Wrap line-mask reveals: set overflow: hidden on the line wrapper so yPercent: 100 hides cleanly. Add autoSplit: true (GSAP 3.13+) to re-split on font load / resize.
  • Call split.revert() before re-splitting or on unmount to restore original DOM and avoid duplicated nodes.
  • Always split AFTER web fonts load (document.fonts.ready.then(...)) to prevent wrong line breaks.

Flip (layout transitions)

Flip records state, lets the DOM change instantly, then animates the visual difference (FLIP technique). Ideal for grid<->list, expanding cards, and reparenting.

js
const state = Flip.getState(".item");   // 1. capture BEFORE
container.classList.toggle("grid");      // 2. mutate DOM/CSS (instant)
Flip.from(state, {                        // 3. animate the delta
  duration: 0.6, ease: "power2.inOut", stagger: 0.05,
  absolute: true,                         // take items out of flow during move (prevents reflow jitter)
});

Easing quick guide

  • power2/3.out — entrances (fast then settle)
  • power2.inOut — moves between two on-screen states
  • back.out(1.7) — overshoot/pop (number = overshoot amount)
  • elastic.out(1, 0.3) — bouncy, use sparingly
  • none — scrubbed scroll tweens
  • steps(n) — sprite/stepped motion
  • Custom cubic-bezier equivalent: CustomEase.create("x", "M0,0 C0.2,0 0,1 1,1") (CustomEase is free)

Performance and cleanup

  • Animate transform (x/y/xPercent/scale/rotation) and opacity only — they are GPU-composited and skip layout/paint. Avoid animating top/left/width/height.
  • Set will-change: transform on heavy/pinned elements; remove after.
  • Batch many similar scroll reveals with ScrollTrigger.batch() instead of one trigger per element.
  • After a viewport/content change, call ScrollTrigger.refresh().

SPA / framework cleanup is mandatory — orphaned triggers cause memory leaks and ghost pinning. Use gsap.context() (or useGSAP from @gsap/react):

js
useEffect(() => {
  const ctx = gsap.context(() => {
    // all gsap + ScrollTrigger code here
  }, rootRef);
  return () => ctx.revert(); // kills tweens, triggers, and reverts inline styles
}, []);

Deliver & verify (standalone HTML)

Packaged helper (scripts/): scripts/seek-shot.sh anim.html 0 1.5 3 freezes the ?t=N harness and screenshots each moment; scripts/contact-sheet.sh sheet.png frame-*.png tiles them for one-glance review. See scripts/README.md.

For a self-contained animation (hero, reveal, loop, micro-scene) the deliverable is one HTML file that opens directly in a browser — no build step, no framework, no render pipeline. Match the deliverable to the weight of the work: a single file is the right tier for web motion; don't reach for a bundler when one file does the job.

Output contract:

  • One .html file: GSAP + plugins from CDN, your markup, and the animation in one inline <script>.
  • All motion on one master timeline (const tl = gsap.timeline()) — a single playhead you can seek.
  • Include the seek harness below so any moment can be frozen for inspection.

Seek harness — freeze an exact moment for screenshots. The web parallel of a video player's frame-pin: ?t=N seeks the master timeline to N seconds and pauses, so a screenshot lands on a still, deterministic frame.

html
<script>
  // ... build your master timeline as `tl` ...
  const t = new URLSearchParams(location.search).get("t");
  if (t !== null) { tl.pause(); tl.seek(parseFloat(t)); }  // frozen at t seconds
  // no ?t → plays normally
  window.__ready = true;            // ready signal for headless wait
  console.log("duration", tl.duration());
</script>

Verify loop — render → freeze → screenshot → check:

  1. Open the file at three moments across the timeline — start, mid, end: …/anim.html?t=0, ?t=<dur/2>, ?t=<dur>. Read tl.duration() from the console for the end time.
  2. Screenshot each frozen frame.
  3. Check both fidelity (does it match the brief?) and artifacts (clipped text, elements off-canvas, FOUC before fonts load, jank at seams). Output should look intentional and finished.

Any headless screenshot tool works — your agent's browser tool, or Playwright:

bash
npx playwright screenshot --wait-for-timeout=500 "file://$PWD/anim.html?t=1.2" frame-mid.png

Before you finish:

  1. Opens standalone in a browser — no console errors, no missing CDN.
  2. All animation on one master timeline; ?t=N freezes correctly.
  3. Screenshotted at start / mid / end — matches the brief, no artifacts.
  4. prefers-reduced-motion honored (timeline simplified or skipped).
  5. Easing is intentional — no accidental linear on spatial motion.

A complete runnable template with the harness wired in is in examples/standalone-template.html.

Quick reference

GoalAPI
Sequence with overlaptl.from(...).from(..., "-=0.3")
Pin while scrollingscrollTrigger:{ pin:true, end:"+=N" }
Scrub to scrollscrollTrigger:{ scrub:1, ease:"none" }
Reveal lines of textSplitText.create(el,{type:"lines"})
Animate layout changeFlip.getState → mutate → Flip.from
Fast pointer followgsap.quickTo(el,"x",{...})
Kill everythingScrollTrigger.getAll().forEach(t=>t.kill())

Reference files

  • references/scrolltrigger-cookbook.md — pin, scrub, horizontal scroll, snap, ScrollTrigger.batch() reveals, parallax, nested triggers, and SPA cleanup patterns with full code.
  • references/scrolltrigger-lenis.md — full ScrollTrigger + Lenis/Locomotive smooth-scroll sync: canonical wiring, scrollerProxy, anchor links, reduced-motion, React (useGSAP/useEffect), debugging checklist, and symptom→cause table.
  • examples/hero-timeline.js — a complete, runnable hero entrance timeline with SplitText, staggered reveals, and reduced-motion handling.
  • examples/standalone-template.html — the deliverable template: self-contained (CDN GSAP), one master timeline, the ?t=N seek harness for screenshot verification, and reduced-motion handling.

Bundled files

The model reads these on demand while the skill is loaded. They are exposed as readable files and are never executed.

Frequently asked questions

What does the Gsap Web AI skill do?

This skill should be used when the user asks to "build a scroll animation", "add ScrollTrigger", "pin a section while scrolling", "scrub an animation to scroll", "create a hero timeline", "do a horizontal scroll section", "split text and animate words", "animate a layout change with GSAP Flip", "sync ScrollTrigger with Lenis", "Lenis smooth scroll jittery", "ScrollTrigger markers drift", "ScrollTrigger pins break with Lenis/Locomotive", or "set up smooth scroll with GSAP pinning". Covers GSAP timelines, ScrollTrigger, SplitText, Flip, and Lenis/Locomotive smooth-scroll sync for code-driven...

Why use Gsap Web on TypingMind?

Because you install it once and use it with any model. Gsap Web is plain Markdown rather than provider-specific code, so the same skill runs on GPT-5, Claude, Gemini, Grok, or a local model — and you can switch model mid-chat without it breaking. TypingMind runs on your own API keys, so you pay providers directly instead of a per-seat subscription, and your skills and chats stay in your own storage.

How do I install Gsap Web in TypingMind?

Open Plugins → Skills → Install from GitHub in TypingMind and paste https://github.com/iart-ai/web-animation-skills/tree/main/skills/gsap-web. TypingMind reads its SKILL.md and bundles its files and installs it as a skill you can enable per chat.

Which AI models can use Gsap Web?

Any model you connect in TypingMind. AI skills are plain Markdown instructions rather than provider-specific code, so GPT, Claude, Gemini, Grok, and local models can all load this skill when a request matches it.

How many AI models can I use with Gsap Web?

As many as you like. As long as a model supports skills, you can use Gsap Web with it — GPT, Claude, Gemini, Grok, DeepSeek, Mistral, Llama and more — all on TypingMind with your own API keys.

Is the Gsap Web AI skill free?

Yes. It is published on GitHub by iart-ai under the MIT license. You only pay your own AI provider for the tokens you use.

What are AI skills?

An AI skill is a reusable instruction bundle that teaches an AI model how to do one specific task. It follows the open Agent Skills format: a SKILL.md file with a name and description, plus any scripts, templates or reference files the model may need. The model reads the instructions only when your request matches the skill, so an installed skill costs nothing until it is used.

How are AI skills different from plugins or MCP servers?

A plugin or MCP server gives a model new tools to call — code that runs somewhere and returns a result. An AI skill gives the model knowledge and process instead: how to approach a task, which steps to follow, what good output looks like. Skills are plain Markdown, so they need no server, no API key and no runtime, and they work with any model.

View all

Set up your own AI workspace now

Get notified about new features and future giveaways by subscribing to our newsletter 👇