# GSAP (GreenSock Animation Platform) GSAP is a framework-agnostic JavaScript animation library that enables developers to create high-performance animations that work across all major browsers. It can animate CSS properties, SVG elements, canvas, React, Vue, WebGL, colors, strings, motion paths, and virtually any JavaScript-accessible property. GSAP is up to 20x faster than jQuery and includes powerful plugins like ScrollTrigger for scroll-based animations, along with comprehensive utility methods for interpolation, value mapping, and more. The library provides a robust sequencing system through its Timeline feature, allowing complex animation choreography with precise control over timing. With zero dependencies and seamless handling of browser inconsistencies, GSAP delivers reliable animations on millions of websites. Version 3.15.0 introduces all plugins as free (including formerly premium plugins like SplitText and MorphSVG), making the complete animation toolkit accessible to everyone. ## Installation ### CDN Installation ```html ``` ### NPM Installation ```javascript npm install gsap // Import GSAP and plugins import gsap from "gsap"; import ScrollTrigger from "gsap/ScrollTrigger"; import Flip from "gsap/Flip"; import Draggable from "gsap/Draggable"; // Register plugins before use gsap.registerPlugin(ScrollTrigger, Draggable, Flip); ``` ## Core Animation API ### gsap.to() - Animate TO Values Animates target(s) from their current values to the specified end values. This is the most common animation method. ```javascript // Basic animation - move element 100px right over 1 second gsap.to(".box", { x: 100, duration: 1 }); // Multiple properties with easing gsap.to(".box", { x: 200, y: 100, rotation: 360, scale: 1.5, opacity: 0.5, duration: 2, ease: "power2.inOut" }); // With callbacks gsap.to("#element", { x: 100, duration: 1, onStart: () => console.log("Animation started"), onUpdate: () => console.log("Animation updating"), onComplete: () => console.log("Animation complete") }); // Stagger multiple elements gsap.to(".item", { y: -50, opacity: 1, duration: 0.5, stagger: 0.1 // 0.1 second delay between each element }); // Function-based values for dynamic animations gsap.to(".box", { x: (index, target, targets) => index * 100, // Different x for each rotation: (index) => index * 45, duration: 1, stagger: 0.2 }); ``` ### gsap.from() - Animate FROM Values Animates target(s) from the specified values to their current/natural values. ```javascript // Animate FROM these values to current state gsap.from(".box", { x: -200, opacity: 0, duration: 1 }); // Entrance animation with stagger gsap.from(".card", { y: 100, opacity: 0, scale: 0.8, duration: 0.8, ease: "back.out(1.7)", stagger: { amount: 0.5, from: "center" // Stagger from center outward } }); ``` ### gsap.fromTo() - Animate FROM-TO Values Provides explicit control over both starting and ending values. ```javascript // Define both start and end states explicitly gsap.fromTo(".box", { x: -200, opacity: 0 }, // FROM values { x: 200, opacity: 1, duration: 1 } // TO values ); // Complex fromTo with easing gsap.fromTo(".element", { scale: 0, rotation: -180, opacity: 0 }, { scale: 1, rotation: 0, opacity: 1, duration: 1.5, ease: "elastic.out(1, 0.5)" } ); ``` ### gsap.set() - Immediately Set Properties Sets properties instantly without animation, useful for initial states. ```javascript // Set initial state instantly gsap.set(".box", { x: 100, y: 50, opacity: 0.5 }); // Set multiple elements with function-based values gsap.set(".item", { x: (index) => index * 50, rotation: (index) => index * 15 }); ``` ## Timeline API ### Creating and Sequencing Timelines Timelines allow you to sequence multiple animations with precise timing control. ```javascript // Create a timeline const tl = gsap.timeline(); // Chain animations - each starts when previous ends tl.to(".box1", { x: 100, duration: 1 }) .to(".box2", { y: 50, duration: 0.5 }) .to(".box3", { rotation: 360, duration: 1 }); // Timeline with defaults applied to all children const tl = gsap.timeline({ defaults: { duration: 1, ease: "power2.out" } }); tl.to(".a", { x: 100 }) .to(".b", { y: 50 }) .to(".c", { opacity: 0.5 }); // Position parameters for precise timing const tl = gsap.timeline(); tl.to(".a", { x: 100, duration: 1 }) .to(".b", { y: 50, duration: 1 }, "-=0.5") // Start 0.5s before previous ends .to(".c", { rotation: 360, duration: 1 }, "<") // Start at same time as previous .to(".d", { scale: 1.5, duration: 1 }, ">") // Start when previous ends .to(".e", { opacity: 0, duration: 1 }, 2); // Start at absolute time 2s // Using labels for organization const tl = gsap.timeline(); tl.addLabel("intro") .to(".logo", { opacity: 1, duration: 1 }) .addLabel("main", "+=0.5") .to(".content", { y: 0, duration: 1 }, "main") .to(".sidebar", { x: 0, duration: 0.8 }, "main+=0.2"); // Jump to label tl.play("main"); ``` ### Timeline Control Methods ```javascript const tl = gsap.timeline({ paused: true }); tl.to(".box", { x: 100, duration: 1 }) .to(".box", { y: 50, duration: 1 }); // Control methods tl.play(); // Start playing tl.pause(); // Pause at current position tl.resume(); // Resume from paused position tl.reverse(); // Play backwards tl.restart(); // Restart from beginning tl.seek(0.5); // Jump to 0.5 seconds tl.progress(0.5); // Jump to 50% progress tl.timeScale(2); // Double the speed tl.kill(); // Stop and remove // Chaining control tl.pause().progress(0.5).resume(); // Check state console.log(tl.isActive()); // true if playing console.log(tl.paused()); // true if paused console.log(tl.reversed()); // true if reversed console.log(tl.progress()); // Current progress (0-1) console.log(tl.time()); // Current time in seconds ``` ### Repeating Timelines ```javascript // Timeline that repeats forever with yoyo const tl = gsap.timeline({ repeat: -1, // -1 = infinite, or specific number yoyo: true, // Alternate direction each iteration repeatDelay: 0.5 // Delay between repeats }); tl.to(".box", { x: 200, duration: 1 }) .to(".box", { y: 100, duration: 0.5 }); ``` ## ScrollTrigger Plugin ### Basic Scroll-Triggered Animations ScrollTrigger creates animations that respond to scroll position. ```javascript import { gsap } from "gsap"; import { ScrollTrigger } from "gsap/ScrollTrigger"; gsap.registerPlugin(ScrollTrigger); // Basic scroll-triggered animation gsap.to(".box", { x: 500, rotation: 360, duration: 1, scrollTrigger: { trigger: ".box", // Element that triggers start: "top center", // When top of trigger hits center of viewport end: "bottom center", // When bottom of trigger hits center scrub: true, // Link animation progress to scroll markers: true // Debug markers (remove in production) } }); // Scrub with smoothing gsap.to(".parallax-element", { y: -200, scrollTrigger: { trigger: ".section", start: "top bottom", end: "bottom top", scrub: 1 // 1 second of smoothing } }); // Toggle actions (play/pause/reverse on enter/leave) gsap.to(".fade-in", { opacity: 1, y: 0, duration: 1, scrollTrigger: { trigger: ".fade-in", start: "top 80%", toggleActions: "play none none reverse" // Format: onEnter onLeave onEnterBack onLeaveBack // Values: play, pause, resume, reverse, restart, reset, complete, none } }); ``` ### ScrollTrigger with Timeline ```javascript // Create timeline with ScrollTrigger const tl = gsap.timeline({ scrollTrigger: { trigger: ".container", start: "top top", end: "+=3000", // 3000px of scrolling scrub: 1, pin: true // Pin the container during scroll } }); tl.to(".panel-1", { xPercent: -100 }) .to(".panel-2", { xPercent: -100 }) .to(".panel-3", { xPercent: -100 }); // Horizontal scroll section const sections = gsap.utils.toArray(".panel"); gsap.to(sections, { xPercent: -100 * (sections.length - 1), ease: "none", scrollTrigger: { trigger: ".container", pin: true, scrub: 1, snap: 1 / (sections.length - 1), // Snap to each panel end: () => "+=" + document.querySelector(".container").offsetWidth } }); ``` ### ScrollTrigger Standalone ```javascript // Create ScrollTrigger without animation ScrollTrigger.create({ trigger: ".element", start: "top center", end: "bottom center", onEnter: () => console.log("Entered!"), onLeave: () => console.log("Left!"), onEnterBack: () => console.log("Entered from bottom!"), onLeaveBack: () => console.log("Left going up!"), onUpdate: (self) => console.log("Progress:", self.progress) }); // Batch animations for multiple elements ScrollTrigger.batch(".item", { interval: 0.1, batchMax: 3, onEnter: (batch) => gsap.to(batch, { opacity: 1, y: 0, stagger: 0.1 }), onLeave: (batch) => gsap.to(batch, { opacity: 0, y: 100 }) }); ``` ## Draggable Plugin ### Creating Draggable Elements ```javascript import { gsap } from "gsap"; import { Draggable } from "gsap/Draggable"; gsap.registerPlugin(Draggable); // Basic draggable Draggable.create(".box", { type: "x,y" // Allow both directions }); // Constrained dragging Draggable.create(".slider-handle", { type: "x", bounds: ".slider-track", inertia: true // Momentum after release }); // With callbacks Draggable.create(".draggable", { type: "x,y", bounds: "#container", onDragStart: function() { console.log("Started dragging", this.target); }, onDrag: function() { console.log("x:", this.x, "y:", this.y); }, onDragEnd: function() { console.log("Ended at", this.endX, this.endY); } }); // Rotation draggable Draggable.create(".knob", { type: "rotation", bounds: { minRotation: 0, maxRotation: 270 }, onDrag: function() { console.log("Rotation:", this.rotation); } }); // Snap to grid Draggable.create(".box", { type: "x,y", snap: { x: (value) => Math.round(value / 50) * 50, // Snap to 50px grid y: (value) => Math.round(value / 50) * 50 } }); ``` ## Utility Methods ### gsap.utils - Value Manipulation ```javascript // toArray - Convert selector/NodeList to Array const boxes = gsap.utils.toArray(".box"); boxes.forEach((box, i) => { gsap.to(box, { x: i * 100 }); }); // mapRange - Map value from one range to another const mapProgress = gsap.utils.mapRange(0, 100, 0, 1); console.log(mapProgress(50)); // 0.5 // clamp - Constrain value to range const clamped = gsap.utils.clamp(0, 100, 150); // Returns 100 // wrap - Wrap value around range const wrapped = gsap.utils.wrap(0, 360, 450); // Returns 90 // interpolate - Create interpolator function const colorInterpolate = gsap.utils.interpolate("red", "blue"); console.log(colorInterpolate(0.5)); // Purple-ish color // random - Generate random values gsap.to(".box", { x: gsap.utils.random(-200, 200), y: gsap.utils.random(-100, 100), duration: 1 }); // Can be used as array selector gsap.to(".box", { backgroundColor: gsap.utils.random(["red", "green", "blue"]) }); // snap - Snap to nearest value const snapTo10 = gsap.utils.snap(10); console.log(snapTo10(23)); // 20 // distribute - Distribute values across elements gsap.to(".box", { x: gsap.utils.distribute({ base: 0, amount: 500, from: "center", ease: "power2" }), duration: 1 }); // pipe - Combine functions const clampAndRound = gsap.utils.pipe( gsap.utils.clamp(0, 100), Math.round ); console.log(clampAndRound(105.7)); // 100 ``` ### gsap.quickTo() and gsap.quickSetter() High-performance methods for frequently-updated values. ```javascript // quickTo - Optimized for repeated updates const xTo = gsap.quickTo("#cursor", "x", { duration: 0.3, ease: "power3" }); const yTo = gsap.quickTo("#cursor", "y", { duration: 0.3, ease: "power3" }); document.addEventListener("mousemove", (e) => { xTo(e.clientX); yTo(e.clientY); }); // quickSetter - Fastest way to set values (no animation) const setX = gsap.quickSetter("#element", "x", "px"); const setRotation = gsap.quickSetter("#element", "rotation", "deg"); document.addEventListener("scroll", () => { setX(window.scrollY * 0.5); setRotation(window.scrollY * 0.1); }); ``` ## Context and MatchMedia ### gsap.context() - Cleanup Management Automatically handles animation cleanup, essential for React/Vue/frameworks. ```javascript // Create context to track all animations const ctx = gsap.context(() => { gsap.to(".box", { x: 100 }); gsap.to(".circle", { rotation: 360 }); ScrollTrigger.create({ trigger: ".section", // ... }); }); // Later, clean up everything in one call ctx.revert(); // Reverts all animations and ScrollTriggers // Scoped selectors (useful in components) const ctx = gsap.context((self) => { // ".box" will only match elements INSIDE containerRef gsap.to(".box", { x: 100 }); }, containerRef); ctx.revert(); ``` ### gsap.matchMedia() - Responsive Animations ```javascript // Create responsive animations const mm = gsap.matchMedia(); mm.add("(min-width: 800px)", () => { // Desktop animations gsap.to(".box", { x: 500, duration: 1 }); ScrollTrigger.create({ trigger: ".section", pin: true }); // Return cleanup function (optional) return () => { console.log("Desktop breakpoint cleaned up"); }; }); mm.add("(max-width: 799px)", () => { // Mobile animations gsap.to(".box", { x: 100, duration: 0.5 }); }); // Multiple conditions mm.add({ isDesktop: "(min-width: 800px)", isMobile: "(max-width: 799px)", reduceMotion: "(prefers-reduced-motion: reduce)" }, (context) => { const { isDesktop, isMobile, reduceMotion } = context.conditions; if (reduceMotion) { gsap.set(".box", { x: 100 }); // No animation } else if (isDesktop) { gsap.to(".box", { x: 500, duration: 1 }); } else { gsap.to(".box", { x: 100, duration: 0.5 }); } }); ``` ## Easing Functions ### Available Eases ```javascript // Power eases (increase intensity: power1 < power2 < power3 < power4) gsap.to(".box", { x: 100, ease: "power1.out" }); // Gentle gsap.to(".box", { x: 100, ease: "power4.inOut" }); // Strong // Named eases gsap.to(".box", { x: 100, ease: "none" }); // Linear gsap.to(".box", { x: 100, ease: "bounce.out" }); // Bouncy gsap.to(".box", { x: 100, ease: "elastic.out(1, 0.3)" }); // Elastic spring gsap.to(".box", { x: 100, ease: "back.out(1.7)" }); // Overshoot gsap.to(".box", { x: 100, ease: "circ.inOut" }); // Circular gsap.to(".box", { x: 100, ease: "expo.out" }); // Exponential gsap.to(".box", { x: 100, ease: "sine.inOut" }); // Sinusoidal // Stepped ease gsap.to(".box", { x: 100, ease: "steps(5)" }); // 5 discrete steps // Ease directions: .in, .out, .inOut // .out = starts fast, ends slow (most common) // .in = starts slow, ends fast // .inOut = slow-fast-slow ``` ## Callbacks and Events ### Animation Callbacks ```javascript gsap.to(".box", { x: 100, duration: 1, // Lifecycle callbacks onStart: () => console.log("Started"), onUpdate: () => console.log("Updating"), onComplete: () => console.log("Complete"), onReverseComplete: () => console.log("Reverse complete"), onRepeat: () => console.log("Repeating"), onInterrupt: () => console.log("Interrupted"), // With parameters onCompleteParams: ["param1", "param2"], onComplete: (a, b) => console.log(a, b), // Custom scope callbackScope: myObject }); // Promise-based completion gsap.to(".box", { x: 100, duration: 1 }) .then(() => console.log("Animation done!")) .then(() => gsap.to(".box", { y: 50 })); // Async/await async function animate() { await gsap.to(".box", { x: 100, duration: 1 }); await gsap.to(".box", { y: 50, duration: 0.5 }); console.log("All done!"); } ``` ## Keyframes ### Keyframe Animations ```javascript // Array syntax - sequential keyframes gsap.to(".box", { keyframes: [ { x: 100, duration: 1 }, { y: 50, duration: 0.5 }, { rotation: 360, duration: 1 } ] }); // Percentage-based keyframes gsap.to(".box", { keyframes: { "0%": { x: 0, y: 0 }, "50%": { x: 200, y: -100 }, "100%": { x: 400, y: 0 } }, duration: 2, ease: "none" }); // With per-keyframe easing gsap.to(".box", { keyframes: [ { x: 100, ease: "power2.out" }, { y: 50, ease: "bounce.out" }, { rotation: 360, ease: "elastic.out" } ], duration: 3 }); ``` ## React Integration ### Using @gsap/react ```javascript import { useRef } from "react"; import gsap from "gsap"; import { useGSAP } from "@gsap/react"; gsap.registerPlugin(useGSAP); function Component() { const containerRef = useRef(); useGSAP(() => { // Animations are scoped to container and auto-cleaned gsap.to(".box", { x: 100, duration: 1 }); gsap.timeline() .to(".circle", { y: 50 }) .to(".square", { rotation: 360 }); }, { scope: containerRef }); // Scope selector to container return (
Box
Circle
Square
); } // With dependencies (re-run when deps change) useGSAP(() => { gsap.to(".box", { x: position, duration: 0.5 }); }, { dependencies: [position], scope: containerRef }); ``` ## Summary GSAP provides a comprehensive animation toolkit that handles everything from simple property tweens to complex scroll-driven experiences. Its Timeline feature enables precise sequencing of multiple animations with flexible positioning, while plugins like ScrollTrigger and Draggable extend functionality for interactive experiences. The utility methods offer powerful value manipulation, and gsap.context() ensures clean integration with modern frameworks. Key integration patterns include using gsap.context() for automatic cleanup in React/Vue components, gsap.matchMedia() for responsive animations, and ScrollTrigger for scroll-based interactions. For optimal performance, leverage gsap.quickTo() for frequently-updated values and gsap.set() for instant property changes. The library's consistent API across all animation types, combined with its robust easing system and callback architecture, makes it suitable for everything from simple UI transitions to complex web experiences.