- 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.
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.
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
- 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
- 8.2The Web Animations API
element.animate(keyframes, options)starts a CSS-quality animation from JavaScript and hands you anAnimationobject 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 - 8.3Playback ControlAn
Animationis a small video player:play(),pause(),reverse(),finish()andcancel()steer it,currentTimeseeks it andplaybackRatechanges its speed. Each has an edge case that the remote below lets you hit on purpose. 21 min 2 live - 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 iscommitStyles()thencancel(). 23 min 3 live - 8.5Promises, Events and getAnimationsEvery
Animationhas areadyand afinishedpromise, so motion can be sequenced withawait.cancel()rejects the promise,getAnimations()lists every animation including CSS ones, andcomposite: "add"lets two animations share one property. 23 min 3 live - 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.
ease-out, using animate().BeginnerD02Keep the end, drop the animationPressing Slide moves the panel 120 px to the right and it stays there, but it does it with fill: "forwards": when the slide is over, the finished animation is still attached to the panel and still wins over your styles.IntermediateD03Steps that wait for each otherGo slides the box, then fades it, then logs done. The starter guesses each duration with setTimeout, and the second step starts too early.IntermediateD04Fly the dot to the cartPressing Add only changes the number. Make a small dot (div.fly-dot) fly from the button to the cart with animate() over 500 ms, then remove it. When it lands, show the new number.Advanced