Motion For The Web
Master the art of modern web animation, from subtle CSS transitions to full-blown JavaScript motion systems. This series starts with the fundamentals of smooth, accessible CSS motion, then builds through keyframes, scroll-linked animations, SVG techniques, and the Web Animations API, finishing with powerhouse libraries like Motion.dev, AnimeJS, and GSAP.

Progress
Series Info
- Episodes
- 43
- Run Time
- 4h 18m
- Difficulty
- Intermediate
- Last Updated
- Nov 27, 2025
- Version
- Latest
Series Episodes
- Introduction (1)
- Never Force Motion Onto Users (3)
Reduced Motion Preference: CSS Media Query
Before we start animating everything in sight, we need to talk about accessibility. Not everyone experiences motion the same way, for many, it can literally cause dizziness or discomfort. In this episode, we explore the prefers-reduced-motion media query, which lets users decide how much movement they see. We'll implement a subtle "pulse" animation as the default and upgrade to a more energetic "party" version only when users haven't opted out. The result: animations that feel alive, but respectful.Motion-Guarded HTML Link Tags
CSS media queries aren't the only way to respect user motion preferences, we can even handle them at the HTML level. Here we conditionally load an entire stylesheet only when motion is allowed, using the media="(prefers-reduced-motion: no-preference)" attribute on a tag. It's a clean and efficient way to manage animation-heavy code, keeping experiences lightweight for users who opt out. By the end, we've built three layers of defense: CSS, HTML, and soon JavaScript.Window: matchMedia() in JavaScript
CSS and HTML can handle motion preferences, but JavaScript can listen to them too. This lesson shows how to use window.matchMedia to detect and respond to a user’s prefers-reduced-motion setting in real time. We add a change event listener that updates behavior dynamically, so your app can adapt without a page reload. With that, we complete the trio, motion preference handling across CSS, HTML, and JS, ensuring your animations always respect the user’s comfort level.
- CSS Transitions (6)
A Quick Word About Animation Performance
Not all CSS properties are created equal when it comes to animation. In this short performance primer, we test how animating transform and opacity gives buttery-smooth, GPU-accelerated motion, while animating layout-affecting properties like width or height can cause jank. Using browser paint flashing tools, we see exactly what gets repainted and why it matters. The rule of thumb: stick to transforms and opacity whenever you can.CSS Transitions 101
Time to get hands-on. We start our first real animations with CSS transitions, smooth, one-line ways to move from one state to another. You’ll learn how to use transition-duration and transition-property to control exactly what animates and for how long. We explore how to combine multiple effects, handle hover states, and understand why defining transitions on the base element (not the hover state) matters. It’s the perfect introduction to motion in CSS.Transition Timing Functions
Between the start and end of a transition lies the magic: easing. This lesson breaks down transition-timing-function and the difference between ease-in, ease-out, and ease-in-out. We visualize these curves through side-by-side box animations, showing how different timing functions change the feel of motion. You’ll also get a glimpse of cubic-bezier functions, the key to crafting completely custom easings for expressive, characterful motion.Combined Timing Functions
When a transition animates multiple properties, each can have its own easing curve, and that's where things get interesting. Here we combine easing functions for rotation, color, and border radius to create playful, layered effects. You'll learn about steps() for stop-motion-style transitions and explore modern easing presets from Adam Argyle's Open Props library. By the end, you'll have a deep feel for how timing curves shape emotion and energy in motion design.Transition Shorthand Syntax
Animations don't always need to start immediately. Using transition-delay, we can introduce rhythm and pacing by staggering property changes. This episode also introduces the powerful transition shorthand, letting you define property, duration, easing, and delay all in a single line. You'll learn how to chain multiple transitions for different properties, control their timing precisely, and understand how browsers interpret multiple time values in one rule.Transitioning on Enter and Leave
CSS has finally caught up with our need for real enter and leave transitions. Using the new transition-behavior and @starting-style features, we bring smooth motion to popovers and other elements that appear and disappear. You'll see how allow-discrete enables transitions even when toggling from display: none, and how @starting-style lets you define true "before" states. It's a modern, declarative way to handle UI entry and exit motion, no JavaScript required.
- CSS Animations (8)
Keyframe Animations 101
CSS keyframes unlock a whole new level of motion control, letting you define exactly what happens between the start and end of an animation. In this lesson, we create our first @keyframes, connect it to an element with the animation property, and experiment with duration, iteration count, and direction. You’ll learn how alternate makes animations play forward and backward seamlessly, and how properties like animation-timing-function shape their personality. It’s your first real taste of how powerful keyframes can be.Keyframe Steps
Moving beyond simple from–to animations, this episode explores intermediate keyframes to choreograph complex motion. We break animations into multiple percentage steps, control timing at each stage, and even create "freeze frames" by repeating keyframe percentages. You'll see how to layer transforms like translate, scale, and rotate for expressive sequences, the kind of fluid, characterful movement impossible with transitions alone. This is where keyframes start feeling like storytelling, not just motion.Animation Fill Mode
If your animations keep snapping back to the start, animation-fill-mode is the fix. Here we learn how to preserve styles before or after an animation using values like forwards, backwards, and both. We also layer in animation-delay for staggered effects, animation-direction for reversing motion, and even step-specific easing for fine-grained control. By the end, you’ll have a rock-solid understanding of how to make animations start, play, and end exactly as you intend, without awkward resets or flickers.Animating Along a Path
In this lesson, we animate elements along custom paths using the offset-path property, no JavaScript required. We start with a simple dome-shaped curve, then pull in a real SVG path from Figma and make our element follow it perfectly. You'll also see how to reuse shapes via CSS variables and even animate polygons and stars using clip-path. This is creative motion design in pure CSS: shapes, paths, and delightful geometry in motion.Animate Elements When In View
Sometimes motion should only happen when users can actually see it. Enter animation-timeline with the view() function, a new CSS feature that ties animation progress to viewport visibility. We use it to fade and scale shapes as they enter the screen, define custom animation-range values for when motion starts and ends, and pair it with fill-mode: both for smooth reversibility. It’s a modern, declarative approach to scroll-triggered animations, no JavaScript needed.Sync Animations With Scroll
Taking animation-timeline even further, we switch from view() to scroll() to sync animations directly with scroll progress. You’ll learn how to animate a progress bar that fills as the page scrolls and link animations to specific scroll containers instead of the entire page. By the end, you’ll understand how CSS can now do what once required JavaScript libraries: fully scroll-driven motion, smooth, performant, and declarative.View (Page) Transitions
The View Transitions API is pure magic, it lets the browser handle animated page changes automatically. Here we start with multi-page navigation and add a single line of CSS: @view-transition navigation: auto;. Instantly, the browser crossfades between pages using snapshots. Then we explore how to assign view-transition-names to matching elements, creating seamless morphs between page components. It’s a powerful, progressive enhancement that makes full-page reloads feel like single-page apps.Dynamic View Transition Names
What if multiple elements share the same view-transition-name? Things break, unless you make them dynamic. In this lesson, we fix that by generating unique transition names for each post, enabling smooth animations between a list view and individual post pages. We even animate a navigation underline between active links for that extra polish. The key takeaway: dynamic naming unlocks incredibly precise, realistic transitions between mismatched DOM elements.
- JavaScript Animations (7)
A Whole New World
CSS can take you far, but eventually, you’ll hit its limits. This lesson marks the bridge into JavaScript animations, where you can respond to user interactions, gestures, and physics-like movement. We explore examples from the web’s most immersive experiences and talk about when to reach for JS libraries like GSAP, Anime.js, or Motion. It’s an invitation to think beyond static transitions and design motion that reacts, feels alive, and tells a story.Animation Loops in JS
Let's start small: animating a single square with plain JavaScript. You'll learn how setInterval can change style properties over time, how to calculate frame rates for smooth 60 FPS motion, and how to stop animations cleanly using clearInterval. It's a foundational peek at how all JS animation works under the hood, manual loops, performance considerations, and the seeds of control that lead to real animation engines.Implicit Animation Framerate
Instead of forcing frame updates manually with setInterval, we can hand timing control back to the browser with requestAnimationFrame. In this lesson, we rewrite our rotation loop so it syncs perfectly with the browser's refresh rate, ensuring silky-smooth motion without wasted CPU cycles. You'll learn why this approach saves battery life, prevents skipped frames, and automatically pauses when tabs are inactive. It's the foundation for performant JavaScript animations.Keyframes Animations in JavaScript (WAAPI)
The Web Animations API (WAPI) bridges the gap between CSS and JavaScript animations, giving you the best of both worlds. We use the .animate() method to define keyframes and options directly in JS, complete with easing, duration, and iteration count. You'll learn how to use the iterations property, offsets, and per-keyframe easing to choreograph complex sequences programmatically. It's a modern, declarative way to animate, without juggling classes or timeouts.Animation Playback Controls
Once you’ve got an animation running with the Web Animations API, you also get something CSS can’t give you: full playback control. Here, we tap into the animation object to pause, play, and even reverse our keyframes. We wire up UI buttons to toggle state and explore how the reverse() method lets animations run backward seamlessly. This lesson is where animations stop being decorative, and start being interactive.Animation Playhead Scrub
Sliders meet animations in this fun, interactive lesson. We replace our play/pause buttons with an input range that lets you "scrub" through an animation's timeline in real time. Using currentTime and getTiming(), we connect the slider's position to the animation's progress, giving users direct control over playback. You'll see how to keep everything in sync, no magic, just clean math and the Web Animations API.Query the Animation Progress
Animations aren't just something you can control, you can also listen to them. Here, we use getComputedTiming() to read the animation's live progress and display it in the UI as a percentage. By wrapping updates in requestAnimationFrame, the progress value stays in perfect sync with the render cycle. This small trick opens the door to reactive motion, analytics, and data-driven UI effects powered by animation state.
- SVG Animations (2)
SVG Line Draw
SVGs aren't static, they can move, morph, and tell stories. In this lesson, we animate an SVG path so it looks like it's being drawn in real time using stroke-dasharray and stroke-dashoffset. You'll learn how to measure path length dynamically, handle rounded line caps, and create elegant reveal animations without JavaScript. It's the perfect blend of geometry, math, and visual delight, all in CSS.Animated Spinner
Building on our SVG skills, we create a dynamic loading spinner with CSS keyframes. Using a rotating circle and animating its stroke-dasharray, we make a shape that stretches, shrinks, and spins in a continuous, organic loop. You'll see how easing and offsets can turn a simple circle into something that feels alive, proving that elegant motion often comes from just a few well-tuned CSS properties.
- JS Animation Libraries (15)
A Tour Of The Landscape
JavaScript animation libraries come with trade-offs, power versus performance. This lesson tours the major players and explains how tools like GSAP, Anime.js, and Motion.dev expand what’s possible. You’ll learn how they differ in syntax, performance, and use cases, and why the Web Animations API still matters. It’s a big-picture look at when and why to reach for a library instead of rolling your own.Motion.dev
Meet Motion.dev, the modern successor to Framer Motion. Lightweight, framework-agnostic, and powered by the Web Animations API, it delivers spring physics, staggered transitions, and composable syntax that feels like magic. We explore how it simplifies animation with readable defaults, smart easing, and hardware-accelerated performance. It's animation made approachable, elegant, and fast.Motion.dev: Animate
Time to get hands-on with Motion.dev. We rebuild a Web Animations API demo using Motion’s terse syntax, one line replaces a dozen. You’ll see how its sensible defaults (like ease-out easing, forward fill, and springy motion) make animations look great instantly. From there, we tweak duration, easing, and sequencing to take it further. The takeaway: Motion.dev makes professional-grade motion design feel effortless.Motion.dev: Springs
Motion.dev supports true physics-based motion using spring animations. In this lesson, we replace default tween easing with spring types and explore parameters like stiffness, damping, and velocity to achieve realistic motion. You’ll see how adjusting these values changes the animation’s energy, from snappy and rigid to soft and floppy, and understand when springs feel most natural. We also discuss their limitation to two-keyframe transitions and preview how to bring spring behavior into more complex sequences.Motion.dev: Sequences
Building on springs, we explore Motion.dev's sequencing API, a clean way to chain multiple animations together. Each step can define its own selector, properties, timing, and easing, giving you granular control over complex multi-stage motion. We add per-step spring settings, experiment with delays, and even use global options to control overall timing. By the end, you'll know how to orchestrate beautifully springy multi-step animations with just a few lines of code.Motion.dev: Hover
Time to make our Motion.dev animations interactive. We use the hover() helper to pause and resume animations on hover, then combine it with new hover-specific animations for scale and rotation. You’ll learn how to elegantly pause motion mid-flight, layer in hover-triggered effects, and cleanly revert them on hover-out. The result feels delightfully tactile, fluid, physics-aware motion that reacts naturally to user interaction.Anime.js
AnimeJS takes everything we’ve learned so far and cranks it up. We tour its stunning documentation and explore how it unifies staggering, SVG animation, scroll effects, and timelines under one expressive API. You’ll see how its live demos make learning fun and discover features like animating CSS variables, shapes, and numbers. It’s a powerful all-in-one engine that still manages to stay approachable, part learning playground, part professional toolkit.Anime.js: Draggable
Let's build something interactive with AnimeJS: a draggable square that snaps to a grid. We start from a simple div and use createDraggable() to make it move, snap to 64-pixel cells, and stay inside its container. You'll see how to tweak drag physics, add springy release easing, and use modifiers to alter motion behavior. It's an impressive mix of simplicity and depth, professional-grade drag physics with just a few lines of code.Anime.js: Draggable Part 2
We extend our draggable example with modifiers and callbacks for richer motion control. You’ll learn how modifiers transform axis values, how to trigger animations on drag release, and how to create relative rotations with the "+=90" syntax. Adding spring easing and subtle delays makes every release feel alive and bouncy. It’s a satisfying deep dive into how AnimeJS blends input, feedback, and animation with remarkable precision.GSAP
Meet GSAP, the GreenSock Animation Platform, the most powerful and battle-tested library in the web animation world. We explore its rich plugin ecosystem, legacy roots from the Flash era, and why it’s still the gold standard for high-end motion. You’ll learn about its core concepts, plugin-based architecture, and professional capabilities like timelines, scroll triggers, and advanced UI animation. GSAP is where creative coding meets motion design.GSAP: Timeline
Time to see why GSAP's timeline system is legendary. We start with a few basic tweens and discover how timelines bring order to chaos, sequencing animations naturally without manual delays. You'll learn how to add, offset, and label steps, how to control progress interactively, and why timelines are essential for orchestrating complex animation flows. It's clean, predictable, and incredibly powerful.GSAP: ScrollTrigger
ScrollTrigger lets you synchronize animations with scroll position effortlessly. We register the plugin, set up triggers, and define when animations should start and stop using viewport markers. You'll see how to configure toggle actions for entering and leaving view, and how to visualize trigger zones for debugging. The result is a scroll-driven sequence that plays forward and backward smoothly, the first taste of cinematic storytelling with GSAP.GSAP: Scroll Scrubbing
Taking ScrollTrigger further, we enable scrub to link animation progress directly to scroll position. You’ll learn how to add easing lag for smooth motion, how scrub values create inertia, and why this approach feels so responsive. By tying motion directly to user scroll, animations become fluid, immersive, and deeply connected to page navigation. It’s the foundation of the modern parallax effect and the hallmark of polished, reactive web motion.GSAP: ScrollSmoother
GSAP’s ScrollSmoother plugin takes scroll-based motion to a new level, adding buttery-smooth inertia without hijacking the browser’s native behavior. In this lesson, we explore how it enhances the scrolling experience safely and accessibly. You’ll learn how to set up the required wrapper and content structure, experiment with smoothing values and easing curves, and understand when moderation is key. ScrollSmoother makes scrolling feel premium, the perfect touch for high-end experiences when used wisely.GSAP: Laughably Easy Parallax
Once ScrollSmoother is running, unlocking parallax effects is effortless. We enable the plugin's effects mode and add simple data-speed and data-lag attributes to elements for depth and weight. You'll see how to build layered motion with different speeds and delays, then recreate the classic "image-behind-a-window" parallax effect with a single attribute or even an automatic data-speed="auto" mode. It's visually rich, silky-smooth, and surprisingly lightweight, a modern parallax that feels natural, not gimmicky.
- Wrap-Up (1)