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", "syn

By iart-ai · 885 installs

npx skills add iart-ai/web-animation-skills --skill gsap-web

Source repository · Upstream listing

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 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. 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 autoAlpha is preferred over raw opacity because it also toggles visibility:hidden at 0, removing the element from hit testing. ScrollTrigger basics 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. 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) 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. 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 ): 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. 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: 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 Goal API Sequence with overlap tl.from(...).from(..., " =0.3") Pin while scrolling scrollTrigger:{ pin:true, end:"+=N" } Scrub to scroll scrollTrigger:{ scrub:1, ease:"none" } Reveal lines of text SplitText.create(el,{type:"lines"}) Animate layout change Flip.getState → mutate → Flip.from Fast pointer follow gsap.quickTo(el,"x",{...}) Kill everything ScrollTrigger.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.