Why animation matters for builders
Most B2B tools ship static. A button that just changes color on click, a modal that appears with no transition, a loading state that’s a spinner and nothing else. It’s defensible — animation is easy to do badly, and bad animation actively makes a product feel cheap. So teams skip it.
But motion is how interfaces communicate feedback. When you drag a card, the card should follow your finger. When you delete a row, the row should collapse instead of teleporting away. These aren’t decorations — they’re how users know their input did something. We spent a long time thinking the VORLUX dashboard was fast; it wasn’t until we animated state transitions that it started feeling fast.
The playground above runs anime.js v4, which is the sweet spot between “just do it with CSS” and “build a full motion system.” It’s ~10 KB gzipped, tree-shakable, and the new v4 API leans hard on the parts of the Web Animations API browsers already do well.
Three core concepts in three snippets
1. animate() — one element, one property
const { animate } = animejs_esm_js;
animate('#canvas rect:first-child', {
translateX: 200,
duration: 800,
ease: 'out(3)',
});
Target a CSS selector (or a DOM element / array of elements), pass a property keyed to its final value, specify duration and easing. That’s it. ease: 'out(3)' is a cubic-out curve — anime.js v4 shipped a new easing syntax that reads much cleaner than the v3 string form.
2. Timelines — chain, offset, overlap
const { createTimeline } = animejs_esm_js;
const tl = createTimeline();
tl.add('#canvas rect:nth-child(1)', { translateX: 100 })
.add('#canvas rect:nth-child(2)', { translateX: 100 }, '-=300') // overlap 300ms
.add('#canvas rect:nth-child(3)', { translateX: 100 });
The -=300 offset overlaps the second animation into the first. Timelines are the right abstraction for anything more than two animations — once you’re past two, cascading setTimeouts get ugly fast.
3. Stagger — the trick that sells animation
const { animate, stagger } = animejs_esm_js;
animate('#canvas rect', {
translateY: -30,
duration: 600,
delay: stagger(80), // each rect starts 80ms after the previous
});
Stagger takes any animation that targets many elements and spreads their start times. It’s the single most-used technique in good product motion — search result reveals, list animations, skeleton loading shimmers all use it.
Pitfalls we hit building the VORLUX hero
Animating opacity is free; animating width is expensive. The browser repaints on every frame for width, but composites opacity on the GPU. If you’re seeing jank, check whether you’re animating something layout-bound.
will-change is a promise, not a hint. It tells the browser “I’m about to animate this, please promote it to its own compositor layer.” If you leave it on forever, you leak memory. Add it just before the animation, remove it in the complete callback.
prefers-reduced-motion: reduce is not optional. About 1% of users have this set, and they’re likely the users who’ll get seasick from your hero parallax. Wrap any animation longer than 150ms:
const reduced = matchMedia('(prefers-reduced-motion: reduce)').matches;
if (!reduced) {
animate('#hero', { translateY: -40, duration: 1200 });
}
A 60-second challenge
In the playground, change the starter code so one rectangle (your pick) chases the others with a 200ms delay — it should look like the other four are leading and the fifth is trying to catch up.
Solution
const { animate, stagger } = animejs_esm_js;
// Leaders: rects 1-4
animate('#canvas rect:nth-child(-n+4)', {
translateX: 100,
duration: 800,
loop: true,
alternate: true,
delay: stagger(80),
});
// Chaser: rect 5, starts 200ms later
animate('#canvas rect:nth-child(5)', {
translateX: 100,
duration: 800,
loop: true,
alternate: true,
delay: 200,
ease: 'inOut(3)',
});Where to go next
- anime.js v4 docs — especially the “Advanced” section on scopes and drivers.
- Motion — what you want if you’re in React. More declarative, similar performance posture.
- GSAP — the industry heavyweight. Paid license for a few advanced features but free for 99% of cases. Reach for it when anime isn’t enough.
- Rive — designer-authored animations you drop into an app as
.rivfiles. Best when your design partner is doing the animation work.
You don’t need to pick one. We use anime.js for UI motion and Rive for the onboarding hero — they coexist fine.