Duration & Delay

Control animation timing with duration in seconds and delay before start.

duration and delay are the two core timing properties in every AnimationConfig. Duration controls how long the animation runs; delay controls when it starts.

Duration

duration sets how many seconds the animation takes to complete. It accepts any positive number, including decimals.

PropertyTypeDefaultDescription
durationnumber0.5Seconds the animation takes to complete
typescript
import { Motion } from "@motion.page/sdk";

// 0.3s — fast UI interaction
Motion("quick-fade", ".button", {
  from: { opacity: 0 },
  duration: 0.3,
}).play();

// 1.2s — slower scroll reveal
Motion("slow-reveal", ".hero", {
  from: { opacity: 0, y: 60 },
  duration: 1.2,
  ease: "power2.out",
}).onScroll({ scrub: false, toggleActions: "play none none none" });

Duration 0 — Instant Snap

Setting duration: 0 makes the animation apply instantly with no transition. This is functionally equivalent to Motion.set().

typescript
// These two are equivalent
Motion("snap", ".box", {
  to: { opacity: 0 },
  duration: 0,
}).play();

Motion.set(".box", { opacity: 0 });

Prefer Motion.set() when the intent is clearly “apply immediately” — it’s more readable. Use duration: 0 when you want snap behaviour inside a multi-step timeline where other entries have duration.

Delay

delay sets how many seconds to wait before the animation begins. The element holds its initial state during the delay period.

PropertyTypeDefaultDescription
delaynumber0Seconds to wait before the animation starts
typescript
Motion("delayed-entry", ".card", {
  from: { opacity: 0, y: 30 },
  duration: 0.6,
  delay: 0.4,
  ease: "power2.out",
}).play();

Combining Duration & Delay

Use both together to fine-tune when and how fast an animation runs:

typescript
Motion("entrance", ".modal", {
  from: { opacity: 0, scale: 0.92 },
  duration: 0.5,
  delay: 0.2,
  ease: "power2.out",
}).onPageLoad();

Delay with Stagger

When stagger is used, the per-element delay is added on top of the base delay. The first element starts at delay, the second at delay + stagger, the third at delay + 2 × stagger, and so on.

typescript
// Element 1 starts at 0.3s
// Element 2 starts at 0.3 + 0.08 = 0.38s
// Element 3 starts at 0.3 + 0.16 = 0.46s
// …and so on
Motion("list-reveal", ".item", {
  from: { opacity: 0, y: 20 },
  duration: 0.5,
  delay: 0.3,
  stagger: 0.08,
  ease: "power2.out",
}).onScroll({ scrub: false, toggleActions: "play none none none" });

delay is useful here as a scene delay — a buffer before the staggered sequence begins, so it doesn’t fire the instant the trigger activates.

See Stagger for the full StaggerVars API and advanced ordering options.

API Reference

typescript
interface AnimationConfig {
  duration?: number;                       // Seconds — how long the animation runs
  delay?: number;                          // Seconds — how long to wait before starting
  stagger?: number | StaggerVars;          // Per-element delay, stacks on top of delay
  // ...other props
}

Timing Tips

UI interactions (hovers, clicks, toggles) — 0.2–0.4s. Fast enough to feel responsive, slow enough to be visible.

Standard transitions (modals, panels, toasts) — 0.4–0.6s. Balanced and polished.

Scroll reveals and entrance animations0.6–1.2s. Longer reads as deliberate and cinematic.

Stagger increments0.02–0.08s per element. Below 0.02s is imperceptible; above 0.12s starts feeling slow for most lists.

Common Mistakes

Using milliseconds instead of seconds. Duration is always in seconds. duration: 500 means 500 seconds, not 500ms. Use duration: 0.5 for half a second.

Forgetting that delay stacks with stagger. With delay: 0.5 and stagger: 0.1, the last element in a 10-item list starts at 0.5 + 0.9 = 1.4s. Factor this in when the animation needs to complete within a tight time window.


Related: Easing · Stagger · Core Concepts