Chapter 5

JS Libraries & Orchestration

The same scene in GSAP vs Motion vs Anime.js.

GSAPMotionAnime.js v4
Timelines, staggering, choreography, interruption. GSAP is free-but-proprietary; Motion and Anime.js are MIT.

At some point hand-rolled requestAnimationFrame loops stop scaling. You need to sequence a dozen elements, stagger them, interrupt mid-flight and have the new motion inherit velocity. That is what an animation library buys you — a timeline, a stagger primitive, and a composition model. This chapter compares the three that define the 2025 landscape, running the identical scene in each.

What a library actually gives you

Strip away the marketing and every serious motion library is three ideas stacked on top of the Web Animations API (or its own ticker):

Timeline

A container that places tweens on a shared playhead. You append with relative offsets ("<", "+=0.2") instead of juggling setTimeout.

Stagger

A function that turns one target list into N delayed starts — by index, by grid distance, or from a chosen origin. The single most-used choreography tool.

Composition & interruption

When a new animation hits a moving element, does it restart, blend, or inherit velocity? This is what makes gestures feel alive — and where springs (Ch.4) meet libraries.

The same scene, three ways

Below: a row of six bars rising and fading in with a stagger, implemented in GSAP, Motion (vanilla motion package), and Anime.js v4 — each in its own component, each reading the same stagger value from the slider. Hit replay all to fire all three at once and compare the feel. Note how the API shapes differ while the result converges.

GSAP vs Motion vs Anime.js — identical stagger live demo
GSAP v3.13+
~23 kB core free, proprietary
Motion pkg motion
~18 kB (hybrid) MIT
Anime.js v4
~10 kB ESM MIT

GSAP & Motion take seconds; Anime.js takes ms — here 80ms.

…and the source behind each panel

GSAP
import { gsap } from 'gsap';

const tl = gsap.timeline();
tl.fromTo(bars,
  { opacity: 0, y: 28, scaleY: 0.3 },
  { opacity: 1, y: 0, scaleY: 1,
    duration: 0.6, ease: 'power3.out',
    stagger: 0.08 }            // seconds
);
Motion
import { animate, stagger } from 'motion';

animate(bars,
  { opacity: [0, 1],
    transform: ['translateY(28px) scaleY(.3)',
                'translateY(0px) scaleY(1)'] },
  { duration: 0.6,
    ease: [0.16, 1, 0.3, 1],
    delay: stagger(0.08) }     // seconds
);
Anime.js
import { createTimeline, stagger } from 'animejs';

const tl = createTimeline();
tl.add(bars, {
  opacity:    [0, 1],
  translateY: [28, 0],
  scaleY:     [0.3, 1],
  duration: 600,
  ease: 'out(3)',
  delay: stagger(80)           // milliseconds
});

Stagger & ease playground

Choreography lives in two knobs: how far apart the starts are (stagger) and what curve each element travels (ease). Drive an Anime.js timeline live — the bars re-run on every change.

Tune the timeline live demo

These map directly onto Anime.js's stagger() and ease params.

Edit it live: a grid stagger

The playground below loads Anime.js v4 straight from a CDN into the sandbox. Change the stagger() origin ('center''first' / 'last'), the grid dimensions, or the ease and watch the ripple change. This is the real library, running in an iframe — break it freely.