Command Palette

Search for a command to run...

Hectal
Scene
08
Take
01
Level
Intermediate
Runtime
~3 h

JavaScript Animation

Drive motion from code: a shared requestAnimationFrame loop, then the Web Animations API in depth: playback, keeping the end state, promises, getAnimations and composite.

6 shots14 live examples4 dailies
0/6 · 0%

CSS is the right tool for a state that changes (hover, open, closed). But some motion starts in code: a dot that flies from a product to the cart, a list that animates after a fetch, a bump that must restart on every click. For those you need JavaScript to start, steer and stop animations.

This phase has two tools. The first is the requestAnimationFrame loop, done properly: time-based, shared by many animations, safe after a tab switch, and stopped when nothing needs it. The second, and the one you will use most, is the Web Animations API: element.animate() gives you the same engine as CSS animations, but with a handle you can play, pause, reverse, seek, await and cancel.

Its traps come with real output: fill: "forwards" that piles up and overrides your styles, a finished promise that rejects on cancel, and one that never settles. The build gives the launch page a cart bump and a dot that flies to the cart.

▶ Roll: 8.1

Scene 08 · the brief from Lumen

Lena, QA at Lumen Bikes

“I pressed Add three times in a row and could not tell which press counted. The toast is nice, but the cart itself still does not react.”

Since the toast arrived (Phase 4), people know an accessory was added. But Mei's storyboard has a second beat: the item should travel to the cart, so the eye follows it there, and the count should bump when it lands. Ama calls this the moment the page becomes a shop.

Kofi tried it with a CSS class. The bump worked once. On the second quick click the class was already on, so nothing replayed. He tried removing and re-adding it in the same frame, and that did nothing either. The flying dot needs numbers that only exist at click time (where the card is, where the cart is), and CSS cannot hold those.

Both problems are the same shape: motion that starts in JavaScript, with measured numbers, and must survive a second click. Lena's rule for this phase: press Add ten times as fast as you can. Nothing may get stuck, and no dot may stay on the page.

In this scene

You will learn

  • Write a requestAnimationFrame loop that is time-based, shared, clamped and stoppable
  • Start, steer, reverse and seek animations with element.animate()
  • Keep an animation's end state without piling up animations or blocking your styles
  • Await animations, handle cancel, and list every animation with getAnimations()
  • Add a cart bump and a fly-to-cart dot to the launch page

You write code in

In your lumen-motion project (npm run dev) and in the editor on this page

Files you touch

  • src/js/components/cart.js
  • src/js/motion/loop.js
  • src/js/main.js
  • src/styles/components.css

Shot list · 6 shots, widths by reading time

  1. 8.1The requestAnimationFrame Loop Done RightA hand-written animation loop needs four habits: add up elapsed time instead of counting frames, share one loop between all animations, clamp the gap after a tab switch, and stop when nothing is left to move. 25 min 2 live
  2. 8.2The Web Animations APIelement.animate(keyframes, options) starts a CSS-quality animation from JavaScript and hands you an Animation object to steer it. It uses the same engine as CSS animations, with a few different defaults and some silent failures worth knowing. 21 min 2 live
  3. 8.3Playback ControlAn Animation is a small video player: play(), pause(), reverse(), finish() and cancel() steer it, currentTime seeks it and playbackRate changes its speed. Each has an edge case that the remote below lets you hit on purpose. 21 min 2 live
  4. 8.4Keeping the End StateWhen a Web Animations API animation ends, the element jumps back to its own style. fill: "forwards" stops that, but it holds the value above your CSS and piles up. The better pattern is commitStyles() then cancel(). 23 min 3 live
  5. 8.5Promises, Events and getAnimationsEvery Animation has a ready and a finished promise, so motion can be sequenced with await. cancel() rejects the promise, getAnimations() lists every animation including CSS ones, and composite: "add" lets two animations share one property. 23 min 3 live
  6. 8.6Build: The Cart Bump and the Fly-to-Cart AnimationbuildGive the Add buttons their payoff: a dot flies from the product to the cart on an arc, the cart count bumps when it lands, two quick clicks both work, and reduced motion gets a fade instead of a flight. 56 min 2 live

Dailies · 4 checked exercises

A film crew watches the day's shots every evening. Build each one yourself and press Check: the page freezes its clock and checks your motion at exact moments, its cost, and its reduced-motion version.