Files
cycle-atlas/.agents/skills/animation-principles/references/easing-curves.md
T

5.2 KiB

Easing curves, springs, and durations

A reference library of exact values. Copy directly.

Named cubic-bezier library

These are battle-tested curves. The four numbers are (x1, y1, x2, y2) control points.

Ease-out family (use for ENTER / appear / settle)

Name cubic-bezier Feel
easeOutQuad 0.5, 1, 0.89, 1 gentle, subtle
easeOutCubic 0.33, 1, 0.68, 1 balanced, safe default
easeOutQuart 0.25, 1, 0.5, 1 snappy
easeOutQuint 0.22, 1, 0.36, 1 very snappy, decisive
easeOutExpo 0.16, 1, 0.3, 1 dramatic, "premium" arrival
easeOutCirc 0, 0.55, 0.45, 1 strong late deceleration

Ease-in family (use for EXIT / disappear / accelerate away)

Name cubic-bezier Feel
easeInQuad 0.11, 0, 0.5, 0 gentle pull-away
easeInCubic 0.32, 0, 0.67, 0 balanced exit
easeInQuart 0.5, 0, 0.75, 0 sharp exit
easeInExpo 0.7, 0, 0.84, 0 dramatic, fast vanish

Ease-in-out family (use for MOVE / reposition while on screen)

Name cubic-bezier Feel
easeInOutQuad 0.45, 0, 0.55, 1 smooth, neutral
easeInOutCubic 0.65, 0, 0.35, 1 balanced default
easeInOutQuart 0.76, 0, 0.24, 1 punchy in and out
easeInOutExpo 0.87, 0, 0.13, 1 very dramatic, long hold mid

Overshoot / back family (use for PLAYFUL / branded / "weighty")

Name cubic-bezier Notes
easeOutBack 0.34, 1.56, 0.64, 1 overshoots past target then settles
easeInBack 0.36, 0, 0.66, -0.56 dips below before launching (anticipation)
easeInOutBack 0.68, -0.6, 0.32, 1.6 anticipate + overshoot

The y value above 1 (e.g. 1.56) or below 0 (e.g. -0.56) is what creates overshoot/anticipation. Bigger excursion = more bounce.

Material Design standard curves (good for product UI)

Token cubic-bezier Use
Standard 0.2, 0, 0, 1 most transitions
Decelerate (enter) 0, 0, 0, 1 elements entering screen
Accelerate (exit) 0.3, 0, 1, 1 elements leaving screen
Emphasized 0.2, 0, 0, 1 (300-500ms) hero moments

iOS / Apple feel

Apple favors springs, but the closest bezier is 0.25, 0.1, 0.25, 1 (the legacy ease) sharpened toward 0.33, 1, 0.68, 1. For modal presentation Apple uses a spring close to stiffness 280, damping 28.

Spring configurations

Springs are defined by stiffness (tension), damping (friction), and mass. Higher stiffness = faster; higher damping = less bounce; higher mass = more sluggish/heavy.

Framer Motion (type: "spring")

// Snappy default — interactive UI
{ type: "spring", stiffness: 300, damping: 30, mass: 1 }

// Bouncy — playful, branded
{ type: "spring", stiffness: 400, damping: 17, mass: 1 }

// Gentle — large/heavy elements, modals
{ type: "spring", stiffness: 120, damping: 20, mass: 1 }

// Stiff/no bounce — precise, critically damped
{ type: "spring", stiffness: 500, damping: 50, mass: 1 }

// Alternative API: duration-based spring (Framer Motion v10+)
{ type: "spring", duration: 0.5, bounce: 0.25 } // bounce 0 = no overshoot, 0.5 = lively

react-spring presets

import { config } from '@react-spring/web'
config.default   // { tension: 170, friction: 26 }
config.gentle    // { tension: 120, friction: 14 }
config.wobbly    // { tension: 180, friction: 12 }  — visible bounce
config.stiff     // { tension: 210, friction: 20 }
config.slow      // { tension: 280, friction: 60 }  — heavy, no bounce
config.molasses  // { tension: 280, friction: 120 }

SwiftUI / iOS

.spring(response: 0.4, dampingFraction: 0.8)   // response = approx duration, dampingFraction 1.0 = no bounce
.interactiveSpring()                            // for gesture-driven

Duration guidance per element type

Element / event Duration Easing
Hover state, tap highlight 100-150ms easeOutQuad
Toggle, checkbox, switch 150-200ms easeOutCubic
Tooltip, dropdown open 150-250ms easeOutCubic
Button press feedback 80-120ms down / 200ms up easeOut + back on release
Modal / dialog enter 300-400ms easeOutExpo or spring(gentle)
Modal / dialog exit 200-250ms easeInQuart
Page / route region transition 300-500ms easeInOutCubic
Card / list item reveal 400-500ms each easeOutExpo
Hero headline / full-screen 500-800ms easeOutExpo
Cinematic camera push/pan 800-2000ms easeInOutQuad
Loading spinner continuous linear
Number count-up 600-1200ms easeOutExpo

Distance-to-duration scaling

To keep perceived velocity natural, scale duration with travel distance:

duration_ms ≈ base_ms * (distance_px / base_distance_px) ^ 0.5

The ^0.5 (square root) prevents long moves from feeling tediously slow while still granting them more time than short moves. Example: base 300ms at 200px -> a 800px move ≈ 300 * sqrt(4) = 600ms.

Stagger math

total = (count - 1) * offset + per_item_duration

Keep total under ~800ms for group reveals. If it exceeds that, reduce offset or use distance-based staggering (each item's delay proportional to its distance from a focal origin), which keeps a constant feel regardless of count.