How to Use GSAP: The Beginner's Guide (Script Tag, First Tween, Timelines)
CodexFuse Team · 2026-10-31T14:06:56.749Z · 13 min read
A beginner's guide to using GSAP: the CDN script tag, your first gsap.to() tween, the from-vs-to rule, easing, timelines, stagger, and ScrollTrigger.
How to Use GSAP: The Beginner's Guide (Script Tag, First Tween, Timelines)
Learning how to use GSAP is the fastest way to add professional, JavaScript-driven motion to a website. GSAP — the GreenSock Animation Platform — is a free JavaScript animation library that animates HTML elements, SVGs, and even plain JavaScript objects with smooth, high-performance tweens. This GSAP tutorial takes you from an empty HTML file to your GSAP first animation, then on to the to/from rule, easing, timelines, and scroll-triggered reveals — all with a single CDN script tag and no build step. If you like the no-build philosophy of the HTMX beginner guide, you will feel right at home.
What is GSAP?
GSAP (GreenSock Animation Platform) is a JavaScript animation library for creating robust, high-performance animations on the web. It works by tweening — interpolating a value between a start point and an end point over a set duration — and it can animate almost any CSS property, SVG attribute, color, or numeric JavaScript value. Professional sites reach for it once plain CSS transitions stop being enough: when motion needs to play, pause, reverse, or restart on demand, when several animations must be choreographed into one sequence, or when animations should trigger off scroll position. Unlike CSS keyframes, everything is controlled from JavaScript, so your animation responds to real code running on the page.
How do you add GSAP to a page?
You add GSAP with one script tag — there is no installation, no build step, and no account to create. The current version line is 3.15.0 (verified on jsDelivr's package registry on 2026-10-31). Follow these seven steps and you will have your first animation running in under five minutes.
- Create an HTML file. A plain
index.htmlon your desktop is enough — you do not need a server for the first run. - Add the GSAP CDN script tag. Paste this just before your own scripts, near the bottom of the page:
The file is only 28 KB compressed with gzip, so it loads fast on any page (per ICS MEDIA's 2026 GSAP walkthrough).<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/gsap.min.js"></script> - Add your own script tag after it. The GSAP script must load first, so your code can access the global
gsapobject. Placing both tags at the end of<body>also means the page's elements exist before your code runs. - Give an element something to animate. Add a box to your page:
<div id="box"></div>with a width, height, and background color in CSS. - Write your first tween. In your script, add:
gsap.to("#box", { x: 160, rotation: 360, duration: 1.2, ease: "power2.out" }); - Open the file in a browser. The box slides right, spins a full turn, and eases to a stop — that is your first GSAP animation, and you already understand most of what real GSAP code looks like.
- Tweak the numbers. Change the duration, swap the ease, and reload. Seeing the change instantly is the fastest way to build intuition. When the page is ready for a real host, serve it from a container with the Docker beginner guide or a live server from the what is VPS hosting guide.
Your first tween: what does gsap.to() do?
gsap.to() animates an element toward the values you give it, starting from wherever the element already is right now. It is the single most-used line in all of GSAP, and its grammar is three parts: the method (to), the target (a CSS selector, an element, or an array — it behaves like querySelectorAll, so a class selector animates every match), and the vars object (the properties to change, plus configuration like duration).
gsap.to(".card", {
y: -8,
opacity: 1,
duration: 0.6,
ease: "power2.out"
});
Notice x and y instead of raw CSS transform strings. GSAP handles combining transforms under the hood, which is genuinely fiddly to get right by hand once translation and rotation animate at the same time. duration is always in seconds. If you leave ease out, GSAP defaults to a gentle power1.out rather than the linear motion most beginners expect — so your first tweens already look smoother than raw CSS.
What is the difference between gsap.to() and gsap.from()?
gsap.to() animates toward the values you give it; gsap.from() animates from the values you give it back to the element's real, current CSS state. That one sentence is the whole GSAP from vs to rule — and it decides which method you reach for.
| Method | What the values mean | Best for |
|---|---|---|
gsap.to() | The end state. Starts from wherever the element is right now. | Most one-off animations: moving, fading, or recoloring in response to code. |
gsap.from() | The start state. Ends at the element's normal CSS. | Entrance animations: a card fading and sliding into its resting position on load. |
gsap.fromTo() | Both ends spelled out explicitly. | Animations that replay identically, like toggles or progress bars. |
The classic gsap.from() entrance looks like this — and it powers almost every "fade in on load" effect on real websites:
gsap.from(".card", {
opacity: 0,
y: 40,
scale: 0.95,
duration: 0.8,
ease: "back.out(1.7)"
});
The card's actual layout position never changes — only the starting point of its animation does. Because the destination is "whatever the CSS already says," redesigning the element's final look later needs zero changes to this tween. One caution, though: the flash-of-content trap. GSAP applies the from values the moment the tween is created, so an element can flash in its final state for a frame before the animation kicks in. Keep your script at the end of <body> (or wrap it in DOMContentLoaded) and the flash disappears.
When should you use gsap.fromTo() instead?
Use gsap.fromTo() whenever an animation must replay identically from a predictable state. gsap.to() depends on wherever the element happens to be, and gsap.from() depends on whatever its final CSS says — gsap.fromTo() depends on neither, because both objects are spelled out.
gsap.fromTo(".dot",
{ x: 0, opacity: 0.3, scale: 1 },
{ x: 260, opacity: 1, scale: 1.15, duration: 1, ease: "power1.inOut" }
);
If an animation ever looks "off" the second time it plays but fine the first time, that is usually the sign it should have been a fromTo() instead of a to() or from(). Toggles, progress indicators, and anything triggered repeatedly by user interaction are the natural home for this method.
What does ease do in GSAP?
Ease shapes the rate of change over the duration — the same distance over the same time reads as completely different motion depending on this one string. A linear tween ("none") moves at constant speed and reads as mechanical; a power ease accelerates or decelerates smoothly, which is what almost all natural-feeling UI motion uses.
| Ease family | Feel | When to use it |
|---|---|---|
power1 – power4 (alias quad – quint) with .in, .out, .inOut | Smooth acceleration/deceleration | Almost everything; power2.out or power3.out is a safe, professional default for UI motion. |
none (alias linear) | Constant speed | Mechanical motion, marquee loops, anything deliberately robotic. |
back.out() | Overshoots past the target, then springs back | Playful entrances — try "back.out(1.7)". |
elastic.out() | Springy wobble | Bouncy attention-getters — try "elastic.out(1, 0.3)". |
bounce.out() | Dropped-ball bounce | Literal bounces, falling objects. |
The .in / .out / .inOut suffixes control the character of the curve: in starts slow and accelerates, out starts fast and decelerates, inOut does both. Getting comfortable naming a handful of these by ear is one of the highest-value things to learn early, because identical tween code reads as completely different quality of motion with only the ease changed.
How do you chain animations with gsap.timeline()?
A GSAP timeline is a container that plays multiple tweens in order automatically — no hand-calculated delays required. This is the single biggest reason real GSAP code reaches for timelines almost immediately: any animation with more than one meaningful step benefits from one.
const tl = gsap.timeline();
tl.to(".box", { x: 120, duration: 0.6 })
.to(".box", { y: 60, duration: 0.6 })
.to(".box", { rotation: 180, duration: 0.6 });
Chaining .to() calls onto the timeline means each step starts exactly when the previous one finishes — add a sixth step or reorder two of them and nothing else needs recalculating. Timelines also support position parameters for overlap: passing "-=0.2" as the second argument to a .to() starts that step 0.2 seconds before the previous one ends, which is how professionals make choreography feel fluid instead of robotic. And a timeline itself can be paused, reversed, or replayed as a single unit, exactly like an individual tween — build an intro sequence once, then control the whole thing with tl.play(), tl.reverse(), or tl.pause().
How do you animate many elements at once with stagger?
Add stagger to any tween and GSAP offsets each target's start time automatically — one call, ten targets, zero per-element delay math. Pass a CSS selector matching multiple elements and a number of seconds:
gsap.from(".col", {
scaleY: 0,
duration: 0.5,
stagger: 0.07
});
The first bar starts immediately, the second 0.07 seconds later, the third 0.07 after that — a natural cascade instead of everything popping in at once. A stagger between roughly 0.05 and 0.1 seconds reads as snappy for most UI lists; much larger starts to feel slow and deliberate. Rule of thumb: once you find yourself hand-calculating more than two or three different delay values for similar elements, that is the signal to reach for stagger instead.
How do you loop an animation with repeat and yoyo?
Two properties handle looping: repeat controls how many extra times a tween plays, and yoyo controls whether each repeat reverses direction instead of snapping back to the start. The combination builds most looping attention-getters on the web — pulsing notification dots, breathing buttons, subtle loading cues.
gsap.to(".pulse", {
scale: 1.5,
duration: 0.6,
repeat: -1,
yoyo: true
});
repeat: -1 is GSAP's convention for "loop forever." Without yoyo: true, each repeat snaps instantly back to the starting values before playing forward again, which usually reads as a visible jump; with it, the tween plays forward, genuinely reverses, then plays forward again. One discipline note: always give yourself a way to stop an infinite tween — tween.kill() — because a repeat: -1 with no way to end it is easy to leave running accidentally.
How do you trigger GSAP animations with user events?
There is nothing GSAP-specific about the event listeners — mouseenter, click, and scroll are plain DOM events. The GSAP part is only what happens inside the handler: a fresh gsap.to() call with the values for that state. And calling gsap.to() again mid-animation does not cause a jarring jump — the new tween starts from the element's current values, not the interrupted animation's original starting point.
card.addEventListener("mouseenter", () => {
gsap.to(card, { y: -8, duration: 0.3, ease: "power2.out" });
});
card.addEventListener("mouseleave", () => {
gsap.to(card, { y: 0, duration: 0.3, overwrite: "auto" });
});
GSAP 3 does not kill the older tween by default (overwrite is false); adding overwrite: "auto" removes the conflicting parts of the old tween outright, which keeps busy hover effects tidy when the cursor flicks in and out quickly.
How do you animate on scroll with ScrollTrigger?
ScrollTrigger is GSAP's free scroll-animation plugin, and using it is two lines: load its script tag, then register it before your first tween. Take the exact same gsap.from() entrance from earlier and hand it a scrollTrigger option instead of firing it immediately:
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/ScrollTrigger.min.js"></script>
gsap.registerPlugin(ScrollTrigger);
gsap.from(".reveal", {
opacity: 0,
y: 60,
duration: 0.9,
ease: "power2.out",
scrollTrigger: {
trigger: ".reveal",
start: "top 85%"
}
});
The section now fades and slides in when it scrolls to 85% of the viewport height. ScrollTrigger also supports pinning sections, scrubbing a timeline against scroll position, and toggle actions — the full system that would take real effort to build by hand. When you are ready to experiment visually, the Scrollytelling Studio tool lets you simulate GSAP ScrollTrigger tweens, pins, and staggers, then copies the real scene code into your project.
What mistakes do GSAP beginners make?
Most early GSAP frustration comes from a short list of predictable traps. Recognize them now and you will skip weeks of confusion.
| Mistake | Why it hurts | The fix |
|---|---|---|
Animating left/top instead of x/y | Layout properties force the browser to recalculate layout every frame — janky motion. | Use GSAP's x and y shorthands; they map to GPU-friendly transforms. |
The from() flash | The element shows its final state for a frame before the tween applies the starting values. | Put scripts at the end of <body> or wrap them in DOMContentLoaded. |
Forgetting gsap.registerPlugin(ScrollTrigger) | ScrollTrigger tweens silently do nothing. | Register the plugin once, before any tween that uses it. |
Replaying a to() that worked once | The element is already at the end values, so the second run looks broken. | Switch to fromTo() so both ends are explicit. |
| Hand-calculating delays for a list | Brittle, tedious, and breaks when the list length changes. | Use stagger instead of per-element delay. |
Leaving repeat: -1 tweens unmanaged | Infinite tweens keep running and stacking. | Keep a reference and call .kill() when it should stop. |
What should you build after your first animation?
Pick one small, real page element and animate it end to end: a hero section that staggers in on load (timeline + stagger), a card grid that cascades on scroll (ScrollTrigger + gsap.from()), or a button that pulses gently until clicked (repeat: -1 with yoyo, killed on click). Each of these uses only the ideas in this guide — no plugin beyond ScrollTrigger, no build tool, no framework. When those feel easy, the official GSAP docs and the free in-browser GSAP Playground (55 lessons across 18 chapters, per webdevpuneet's 2026 guide) are the natural next steps. You now own the whole beginner arc: script tag, first tween, the to/from rule, easing, timelines, and scroll — everything else in GSAP is a variation on these ideas.
Sources
- jsDelivr package registry — [email protected] current version, fetched 2026-10-31
- ICS MEDIA, "Getting started with GSAP, part 1" (updated 2026-08-14) — CDN tag [email protected], 28 KB gzipped, duration/ease defaults (power1.out), transform shorthands, power1–power4 easing aliases
- webdevpuneet.com, "GSAP Tutorial for Beginners" (2026-10-15) — gsap.to() as the core unit, from/fromTo rules, registerPlugin(ScrollTrigger), timelines with position parameters, stagger 0.05–0.1, repeat -1 with yoyo, .kill(), overwrite: "auto"
- bomberbot.com, "The Beginner's Guide to the GreenSock Animation Platform (GSAP)" — from/to/fromTo recap, CDN + npm install arcs
- gsap.com/resources/get-started — the method/target/vars grammar (to/from/fromTo/set, querySelectorAll targeting)
Frequently asked questions
Is GSAP free to use?
Yes — the core GSAP library and its plugins, including ScrollTrigger, are free and load from a public CDN with no account or API key. The beginner arc in this guide (tweens, timelines, stagger, easing, ScrollTrigger) uses only the free build.
Do I need npm or a build tool to learn GSAP?
No. A single <script> tag pointing at the jsDelivr CDN (currently [email protected]) gives you the full library in a plain HTML file. Install via npm install gsap only when you move to a project that already has a build step, and then import it with import { gsap } from "gsap";.
What is the difference between gsap.to() and gsap.from()?
gsap.to() animates toward the values you give it, starting from the element's current state. gsap.from() animates from the values you give it back to the element's normal CSS state — it is the standard tool for entrance animations. gsap.fromTo() sets both ends explicitly, so replays are always identical.
Why is my GSAP animation flashing before it starts?
That is the gsap.from() flash-of-content trap: the element renders in its final state for a frame before the tween applies the starting values. Put your script at the end of <body> or wrap it in DOMContentLoaded so the starting values are applied before the first paint.
Do I have to register the ScrollTrigger plugin?
Yes — one line, gsap.registerPlugin(ScrollTrigger);, run once before any tween that uses the scrollTrigger option. Without it, scroll-triggered tweens silently do nothing. Load the plugin's own script tag (ScrollTrigger.min.js) after the core GSAP tag.