Easing Functions

All easing curves — power, sine, expo, circ, back, elastic, bounce — with visual reference.

Easing shapes the acceleration curve of an animation — whether it glides smoothly, snaps sharply, overshoots, or bounces. Every AnimationConfig accepts an ease string.

Basic Usage

typescript
import { Motion } from "@motion.page/sdk";

Motion("reveal", ".card", {
  from: { opacity: 0, y: 40 },
  duration: 0.6,
  ease: "power2.out",
}).onScroll({ scrub: false, toggleActions: "play none none none" });

The ease Property

Property Type Default Description
ease string "power1.inOut" Easing curve — lowercase family name + direction suffix

The format is "family.direction" in lowercase: "power2.out", "elastic.inOut", "back.in". Two values skip the direction suffix: "none" (linear, constant speed) and omitting ease entirely (uses the SDK default, equivalent to "power1.inOut").

Directions

All families except none accept three direction suffixes:

Suffix Meaning Use when
.in Accelerates — slow start, fast end Exits, elements leaving the screen
.out Decelerates — fast start, slow end Entrances, reveals — most natural direction
.inOut Slow start, fast middle, slow end Repositioning, looping, symmetric transitions
typescript
ease: "power2.out"   // fast to slow — standard reveal ease
ease: "power2.in"    // slow to fast — exits and aggressive enters
ease: "power2.inOut" // symmetric — good for repositioning and loops

All Easing Families

Family Feel Best for
power1 Gentle — closest to CSS ease Subtle UI motion, body text reveals
power2 Moderate — the everyday workhorse Scroll reveals, card entrances, most animations
power3 Strong — punchy, confident Hero sections, modals, bold entrances
power4 Very strong — dramatic onset/cutoff Cinematic moments, high-impact exits
sine Smooth sinusoidal — lightest of all Delicate fades, floating loops
expo Extreme — near-instant snap Drawers, command palettes, high-contrast UIs
circ Circular arc — mechanical, abrupt Sorting animations, precise layout changes
back Slight overshoot then settles Playful cards, buttons, landing animations
elastic Multi-oscillation spring Badges, tooltips, success states
bounce Discrete ball-drop bounces Game UI, mascots, high-energy moments
rough Jitter/shaking motion Glitch effects, error shakes, organic feel
slow Pauses mid-range — emphasis beat Dramatic pauses, attention-drawing loops
none Linear — constant speed Scrub animations, progress bars

Visual Comparison

Code Examples by Family

Power1–4

The power family covers the vast majority of UI animations. Strength scales with the number — power1 is barely perceptible, power4 has an almost instant onset or cutoff.

typescript
import { Motion } from "@motion.page/sdk";

// power2.out — the default choice for scroll reveals
Motion("reveal", ".section", {
from: { opacity: 0, y: 30 },
duration: 0.6,
ease: "power2.out",
}).onScroll({ scrub: false, toggleActions: "play none none none" });

// power3.out — punchy hero entrance
Motion("hero", ".headline", {
from: { opacity: 0, y: 60 },
duration: 0.8,
ease: "power3.out",
}).onPageLoad();

// power4.in — aggressive exit for page transitions
Motion("exit", "body", {
to: { opacity: 0, y: -20 },
duration: 0.4,
ease: "power4.in",
}).onPageExit({ skipHref: ["anchor", "mailto"] });

Sine & Expo

sine is the gentlest curve of all families — nearly imperceptible at short durations. expo is the sharpest, producing a near-instant snap quality.

typescript
// sine.out — light, airy entrance for delicate elements
Motion("float", ".caption", {
from: { opacity: 0, y: 12 },
duration: 0.9,
ease: "sine.out",
}).play();

// expo.out — snappy drawer or panel that pops open
Motion("drawer", ".sidebar", {
from: { x: -320 },
duration: 0.5,
ease: "expo.out",
}).play();

Circ

circ follows a circular arc — sharper than power curves and more mechanical in feel.

typescript
// circ.inOut — list reordering with a crisp pivot
Motion("sort", ".item", {
to: { y: 80 },
duration: 0.45,
ease: "circ.inOut",
}).play();

Back — Overshoot

back.out travels slightly past the destination, then snaps back to rest. Creates a satisfying landing or pop effect.

typescript
// Pop-in with overshoot — modal or badge appears with snap
Motion("pop", ".badge", {
from: { opacity: 0, scale: 0.82 },
duration: 0.5,
ease: "back.out",
}).play();

// Hover lift with overshoot — cards feel springy on enter
Motion("lift", ".card", {
to: { y: -8 },
duration: 0.35,
ease: "back.out",
}).onHover({ each: true, onLeave: "reverse" });

Elastic — Spring

elastic.out oscillates multiple times before settling. Draws significant attention — use it for moments that deserve a spotlight.

typescript
// Notification badge springs into view
Motion("ping", ".notification-badge", {
from: { scale: 0, opacity: 0 },
duration: 0.7,
ease: "elastic.out",
}).play();

// Tooltip pops in with a spring
Motion("tooltip", ".tooltip", {
from: { opacity: 0, scale: 0.88 },
duration: 0.6,
ease: "elastic.out",
}).play();

Bounce — Ball Drop

bounce.out simulates discrete ball-bouncing steps. More mechanical and playful than elastic.

typescript
// Icon drops in with a bounce
Motion("drop", ".icon", {
from: { y: -60, opacity: 0 },
duration: 0.8,
ease: "bounce.out",
}).play();

Rough & Slow

rough adds jitter — useful for shaky, glitchy, or organic motion. slow decelerates strongly through the middle of its range, creating a natural pause for emphasis.

typescript
// Error shake — rough jitter on validation failure
Motion("shake", ".form-field", {
from: { x: -5 },
to: { x: 5 },
duration: 0.06,
ease: "rough",
repeat: { times: 8, yoyo: true },
}).play();

// Slow pulse — emphasis beat that draws the eye
Motion("pulse", ".cta-button", {
from: { scale: 1 },
to: { scale: 1.06 },
duration: 0.8,
ease: "slow.inOut",
repeat: { times: -1, yoyo: true },
}).play();

None — Linear

"none" moves at constant speed with no acceleration. The right choice for scrub animations and any motion where the position should map directly to a value without distortion.

typescript
// Scrubbed parallax — scroll position maps 1:1
Motion("parallax", ".bg-layer", {
from: { y: -80 },
to: { y: 80 },
ease: "none",
}).onScroll({ scrub: true });

// Progress bar — constant speed is the point
Motion("progress", ".bar", {
from: { width: "0%" },
to: { width: "100%" },
duration: 3,
ease: "none",
}).play();

When to Use Which Ease

Scroll reveals and entrances → power2.out or power3.out. A decelerating ease reads as the element arriving and coming to rest naturally.

Exits and page transitions → power2.in or power3.in. An accelerating ease looks like the element flying away rather than disappearing mid-movement.

Hover effects → power2.out on enter, power1.inOut or power2.in on leave. Keep hover duration short: 0.2–0.35s.

Looping and yoyo animations → sine.inOut or power2.inOut. Symmetric curves restart without a jarring speed discontinuity.

Scrub / scroll-driven → none. Any other ease creates uneven, rubber-banding scrubbing.

Playful moments → back.out for mild snap, elastic.out for spring energy. Reserve these for moments that genuinely deserve attention.

Dramatic and cinematic → expo.out or power4.out. High-contrast onset/cutoff creates energy and intentionality.

Mechanical / precision UI → circ.inOut or expo.out. These feel direct and purposeful rather than casual.

API Reference

typescript
interface AnimationConfig {
  ease?: string;
  // "power1.out" | "power2.out" | "power3.out" | "power4.out"
  // "power1.in"  | "power2.in"  | "power3.in"  | "power4.in"
  // "power1.inOut" | "power2.inOut" | "power3.inOut" | "power4.inOut"
  // "sine.in"  | "sine.out"  | "sine.inOut"
  // "expo.in"  | "expo.out"  | "expo.inOut"
  // "circ.in"  | "circ.out"  | "circ.inOut"
  // "back.in"  | "back.out"  | "back.inOut"
  // "elastic.in" | "elastic.out" | "elastic.inOut"
  // "bounce.in"  | "bounce.out"  | "bounce.inOut"
  // "rough.in"   | "rough.out"   | "rough.inOut"
  // "slow.in"    | "slow.out"    | "slow.inOut"
  // "none"
}

Omitting ease uses the SDK default: equivalent to "power1.inOut".


Related: Duration & Delay · Stagger · Repeat & Yoyo