Skip to content
Back to skills

Motion

ASecurity

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

  • 248 stars
  • 0 votes
  • 5 copies
  • 35 views
  • Added February 10, 2026
developmentjavascripttypescriptjavabashreactspringperformance

Security analysis

A96/100
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro shows the line behind each finding and how to fix it

Scanned February 12, 2026

npx -y skills add Mindrally/skills --skill motion --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Motion?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Motion
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/mindrally-motion/badge)](https://www.skillsdirectory.com/skills/mindrally-motion)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: motion
description: Expert guidelines for building performant animations with Motion (formerly Motion One) vanilla JavaScript animation library
---

# 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 element
animate(".element", { x: 100, opacity: 1 }, { duration: 0.5 });

// Animate with options
animate(
  ".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 accelerated
animate(".element", {
  x: 100,           // translateX
  y: 50,            // translateY
  scale: 1.2,       // scale
  rotate: 45,       // rotate
  opacity: 0.5      // opacity
});

// Avoid when possible - triggers layout
animate(".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 animations
const 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 time
controls.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 values
animate(".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 bezier
animate(".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 methods
controls.play();
controls.pause();
controls.stop();
controls.finish();
controls.reverse();

// Get/set time
controls.currentTime = 0.5;
console.log(controls.duration);

// Cancel animation
controls.cancel();
```

### Animation Events
```javascript
const controls = animate(
  ".element",
  { x: 100 },
  {
    duration: 1,
    onComplete: () => console.log("Done!")
  }
);

// Promise-based
controls.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 it
controls.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

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.