Motion

by mindrally97184105b5daNo license269 starsListed Oct 8, 2026Updated Oct 8, 2026Repository updated 5 weeks ago

Expert guidelines for building performant animations with Motion (formerly Motion One) vanilla JavaScript animation library

AI-generated overview

Guidelines for building performant web animations with the Motion JavaScript library.

What it does
This skill provides expert guidance for creating animations with Motion (formerly Motion One), a vanilla JavaScript animation library. It covers basic animations, keyframes, timelines, scroll-linked effects, in-view triggers, staggering, springs, easing, playback controls, cleanup, and reduced-motion accessibility. It produces code examples and best-practice recommendations rather than executable artifacts.
When to use it
Use it when writing or reviewing JavaScript or TypeScript web animations with Motion. It suits tasks involving scroll effects, viewport-triggered animations, sequenced timelines, or animation performance tuning. It is also relevant when accessibility around reduced-motion preferences matters.
Requirements
Requires the Motion npm package (npm install motion) in a JavaScript or TypeScript project. No scripts ship with the skill; it is instructions and code examples only.

Motion Animation Guidelines

You are an expert in Motion (motion.dev), JavaScript, TypeScript, and web animation performance. Follow these guidelines when creating animations.

Core Principles

About Motion

  • Motion is the JavaScript animation library from the creator of Framer Motion
  • Use motion for vanilla JavaScript/TypeScript projects
  • Use motion/react for React projects (see framer-motion skill)
  • Designed for high performance with minimal bundle size

Installation

bash
npm install motion

Basic Import

javascript
import { animate, scroll, inView, timeline } from "motion";

Basic Animations

Simple Animation

javascript
import { animate } from "motion";
// Animate a single elementanimate(".element", { x: 100, opacity: 1 }, { duration: 0.5 });
// Animate with optionsanimate(  ".element",  { transform: "translateX(100px)" },  {    duration: 0.8,    easing: "ease-out"  });

Keyframes

javascript
animate(  ".element",  {    x: [0, 100, 50],      // Keyframe values    opacity: [0, 1, 0.5]  },  { duration: 1 });

Performance Optimization

Animate Transform Properties

javascript
// Best performance - GPU acceleratedanimate(".element", {  x: 100,           // translateX  y: 50,            // translateY  scale: 1.2,       // scale  rotate: 45,       // rotate  opacity: 0.5      // opacity});
// Avoid when possible - triggers layoutanimate(".element", {  width: 200,       // Causes layout recalculation  height: 150,      // Causes layout recalculation  top: 50,          // Causes layout recalculation  left: 100         // Causes layout recalculation});

Use will-change

javascript
// Add will-change for transform animationsconst element = document.querySelector(".element");element.style.willChange = "transform";
animate(element, { x: 100 }, {  onComplete: () => {    element.style.willChange = "auto"; // Remove after animation  }});

Hardware Acceleration

Motion automatically uses hardware-accelerated properties when possible. For best performance:

  1. Prefer x, y over left, top
  2. Prefer scale over width, height
  3. Use opacity for fade effects
  4. Use rotate over transform: rotate()

Timeline Animations

Create Timelines

javascript
import { timeline } from "motion";
const sequence = [  [".header", { y: ["-100%", 0], opacity: [0, 1] }],  [".content", { y: [50, 0], opacity: [0, 1] }, { at: "-0.3" }],  [".footer", { y: [50, 0], opacity: [0, 1] }, { at: "-0.3" }]];
const controls = timeline(sequence, {  duration: 0.8,  defaultOptions: { easing: "ease-out" }});

Timeline Controls

javascript
const controls = timeline(sequence);
controls.play();controls.pause();controls.reverse();controls.stop();controls.finish();
// Seek to specific timecontrols.currentTime = 0.5;

Scroll Animations

Basic Scroll Animation

javascript
import { scroll, animate } from "motion";
scroll(  animate(".progress-bar", { scaleX: [0, 1] }),  { target: document.querySelector("article") });

Scroll-Linked Animation

javascript
scroll(({ y }) => {  // y.progress is 0 to 1  animate(".element", {    opacity: y.progress,    y: y.progress * 100  }, { duration: 0 });});

Scroll with Container

javascript
scroll(  animate(".parallax", { y: [0, -100] }),  {    target: document.querySelector(".section"),    offset: ["start end", "end start"]  });

In-View Animations

Trigger on Visibility

javascript
import { inView, animate } from "motion";
inView(".card", (info) => {  animate(info.target, { opacity: 1, y: 0 }, { duration: 0.5 });
  // Return cleanup function  return () => {    animate(info.target, { opacity: 0, y: 20 }, { duration: 0.2 });  };});

With Options

javascript
inView(  ".element",  (info) => {    animate(info.target, { scale: [0.8, 1], opacity: [0, 1] });  },  {    margin: "-100px",  // Trigger 100px before entering viewport    amount: 0.5        // Trigger when 50% visible  });

Stagger Animations

Stagger Multiple Elements

javascript
import { stagger, animate } from "motion";
animate(  ".list-item",  { opacity: [0, 1], y: [20, 0] },  { delay: stagger(0.1) });

Stagger from Center

javascript
animate(  ".grid-item",  { scale: [0, 1] },  { delay: stagger(0.05, { from: "center" }) });

Stagger with Easing

javascript
animate(  ".item",  { x: ["-100%", 0] },  {    delay: stagger(0.1, {      easing: "ease-out",      start: 0.2    })  });

Spring Animations

Use Springs for Natural Motion

javascript
animate(  ".element",  { scale: 1.2 },  {    easing: "spring",    // or with custom spring settings    easing: [0.34, 1.56, 0.64, 1] // Custom bezier curve  });

Spring Options

javascript
animate(".element", { x: 100 }, {  type: "spring",  stiffness: 300,  damping: 30});

Easing Functions

Built-in Easings

javascript
// Common easing valuesanimate(".element", { x: 100 }, { easing: "ease" });animate(".element", { x: 100 }, { easing: "ease-in" });animate(".element", { x: 100 }, { easing: "ease-out" });animate(".element", { x: 100 }, { easing: "ease-in-out" });animate(".element", { x: 100 }, { easing: "linear" });
// Cubic bezieranimate(".element", { x: 100 }, {  easing: [0.25, 0.1, 0.25, 1]});

Animation Controls

Control Playback

javascript
const controls = animate(".element", { x: 100 }, { duration: 1 });
// Control methodscontrols.play();controls.pause();controls.stop();controls.finish();controls.reverse();
// Get/set timecontrols.currentTime = 0.5;console.log(controls.duration);
// Cancel animationcontrols.cancel();

Animation Events

javascript
const controls = animate(  ".element",  { x: 100 },  {    duration: 1,    onComplete: () => console.log("Done!")  });
// Promise-basedcontrols.finished.then(() => {  console.log("Animation finished");});

Accessibility

Respect Reduced Motion

javascript
const prefersReducedMotion = window.matchMedia(  "(prefers-reduced-motion: reduce)").matches;
animate(  ".element",  { x: 100, opacity: 1 },  {    duration: prefersReducedMotion ? 0 : 0.5,    easing: prefersReducedMotion ? "linear" : "ease-out"  });

Create Accessible Wrapper

javascript
function safeAnimate(element, keyframes, options = {}) {  const reducedMotion = window.matchMedia(    "(prefers-reduced-motion: reduce)"  ).matches;
  return animate(element, keyframes, {    ...options,    duration: reducedMotion ? 0 : (options.duration ?? 0.3)  });}

Integration with Frameworks

Vanilla JavaScript

javascript
document.addEventListener("DOMContentLoaded", () => {  animate(".hero", { opacity: [0, 1], y: [30, 0] });});

With Event Listeners

javascript
const button = document.querySelector(".button");
button.addEventListener("mouseenter", () => {  animate(button, { scale: 1.05 }, { duration: 0.2 });});
button.addEventListener("mouseleave", () => {  animate(button, { scale: 1 }, { duration: 0.2 });});

Cleanup

Cancel Animations

javascript
const controls = animate(".element", { x: 100 });
// Later, cancel itcontrols.cancel();

Cleanup Pattern

javascript
class AnimatedComponent {  constructor(element) {    this.element = element;    this.animations = [];  }
  animate(keyframes, options) {    const controls = animate(this.element, keyframes, options);    this.animations.push(controls);    return controls;  }
  destroy() {    this.animations.forEach(anim => anim.cancel());    this.animations = [];  }}

Best Practices Summary

  1. Use transform properties (x, y, scale, rotate) for best performance
  2. Add will-change before complex animations, remove after
  3. Use timeline for sequenced animations
  4. Use scroll() for scroll-linked effects
  5. Use inView() for viewport-triggered animations
  6. Use stagger() for animating multiple elements
  7. Prefer springs for interactive/gesture animations
  8. Always respect reduced motion preferences
  9. Cancel animations when no longer needed
  10. Test performance on actual devices

Source and attribution

Source:mindrally/skillsinmotionat commit9718410

License: No license

Content belongs to its original authors. SourceWeft indexes it from a public repository.

Report or request removal