Skip to main content
motion

Easing Curves Are Product Voice

Linear feels mechanical, ease-in-out feels natural, spring feels alive. The easing curves you ship are a product personality decision, conscious or not.


5 min read

Every animation your product ships communicates something. Not a message, exactly — more of a physical character. Linear animation feels like a machine. A heavy ease-in-out feels natural. A spring that overshoots slightly feels playful and alive. These aren't aesthetic choices in a vacuum. They're product voice decisions that accumulate across every interaction into an impression users carry.

Most teams make this decision implicitly, by accepting whatever the CSS default is or copying a spring config from a Stack Overflow answer. That's a personality shipped by accident.


What Different Easing Families Communicate

Linear (transition-timing-function: linear) — constant velocity from start to end. No acceleration, no deceleration. It reads as mechanical, robotic, digital-in-the-bad-way. The only place linear easing belongs is in continuous spinning indicators and color transitions where perceptual uniformity matters more than feel.

Ease-in — slow start, fast end. Objects feel like they're launching. Good for elements exiting the screen (they accelerate away), wrong for entrances. An element that eases in to its final position feels like it's arriving too fast and then stopping abruptly.

Ease-out — fast start, slow end. This is the most natural feeling for most UI motion because it mimics physical deceleration. Elements entering a screen should ease-out. They arrive quickly and settle. This matches how a drawer being pulled open feels in the physical world.

Ease-in-out — slow start, fast middle, slow end. Symmetrical. Balanced. Used for elements that move through the viewport (a toast sliding in and then out, a carousel advance). Reads as polished, intentional, calm.

Spring — physically simulated. Overshoots slightly, oscillates, settles. The overshoot is what makes it feel alive. Something with mass just moved into position and is reacting to its own momentum.

/* These four feel entirely different for the same property change */
.mechanical { transition: transform 300ms linear; }
.polished   { transition: transform 300ms cubic-bezier(0.4, 0, 0.2, 1); } /* Material's standard */
.natural    { transition: transform 300ms cubic-bezier(0.34, 1.56, 0.64, 1); } /* Slight overshoot */
.premium    { transition: transform 500ms cubic-bezier(0.16, 1, 0.3, 1); } /* Expo out — fast then long settle */

Spring Configuration as Personality

CSS cubic-bezier curves are approximations of spring motion. Motion for React (and Framer Motion before it was rebranded) lets you configure actual springs: stiffness, damping, and mass.

import { motion } from "motion/react";

// Financial product: controlled, precise, no overshoot
const bankingSpring = { type: "spring", stiffness: 400, damping: 40, mass: 1 };

// Consumer app: bouncy, playful, obvious overshoot
const consumerSpring = { type: "spring", stiffness: 300, damping: 20, mass: 0.8 };

// Design tool: fast response, minimal bounce — feels like direct manipulation
const toolSpring = { type: "spring", stiffness: 600, damping: 35, mass: 0.5 };

<motion.div animate={{ x: 100 }} transition={bankingSpring} />

High damping (≥40) kills the oscillation. The element moves and stops — controlled. Low damping (under 25) lets it oscillate — alive, bouncy. A trading dashboard and a fitness app both have animations. They should feel nothing alike.

The Financial vs Consumer Distinction

A fintech product with a playful spring on its transaction list feels wrong. The interaction communicates something — and "bouncy" isn't what you want near someone's savings balance. Users don't consciously notice the spring config, but they notice the feeling, and that feeling shapes trust.

A consumer app — a social tool, a creative product, something for play — benefits from the overshoot. It signals that the product has energy, that interactions have weight and response. The app feels fun to use, partly because of spring physics, whether or not anyone on the team thought about it that way.

Easing as a Design Token

Easing decisions made once, inconsistently, scattered across components, drift. The practical solution is treating easing curves as design tokens — defined once, referenced everywhere:

// motion-tokens.ts
export const ease = {
  standard: [0.4, 0, 0.2, 1] as const,       // enter/exit, general transitions
  enter:    [0, 0, 0.2, 1] as const,           // elements entering the screen
  exit:     [0.4, 0, 1, 1] as const,           // elements leaving the screen
  expressive: [0.34, 1.56, 0.64, 1] as const, // interactive elements, playful
} as const;

export const duration = {
  fast:     150,
  standard: 250,
  slow:     400,
} as const;

When you define these tokens and enforce their use in your component library, a brand decision — "this product feels precise and controlled" — becomes a code constraint. New components inherit the personality by default. Developers stop making easing decisions accidentally.

The easing you ship is a form of writing. Make it say something you meant.