Why easing makes animation feel alive

September 24, 2026 · 4 min read · by Nobody

Move a box from left to right at a constant speed and it looks mechanical, like a machine part. Let it start quickly and settle gently into place and it suddenly feels like an object with weight. The only thing that changed is the easing curve: how progress is spread out over time.

Progress versus time

Every animation has a progress value that goes from 0 (start) to 1 (end). Easing is a function that takes linear time and returns how far along the motion should be.

linearease inease outease in-out
Horizontal axis: time. Vertical axis: how far the motion has progressed. The dashed line is constant speed. Exact curves, plotted from the formulas below.
Curve Formula (p = time from 0 to 1) Feels like
Linear p A machine. Constant speed, abrupt start and stop
Ease in Something gathering speed, like falling
Ease out 1 - (1 - p)³ Something arriving and settling
Ease in-out 4p³ for the first half, then 1 - (-2p + 2)³ / 2 A deliberate move from A to B

Which one to use

Timing matters as much as the curve

The same curve feels different depending on how long it lasts and how elements are staggered:

Titlefade in + riseIllustrationslide inArrowdrawLabelpop in0.0s0.5s1.0s1.5s2.0s2.5s
Staggered entrances in one scene: each element starts when the previous one is nearly done, in reading order.

A few rules of thumb from building animated explainers:

  1. Stagger entrances by 150 to 400 ms, in reading order. Everything appearing at once reads as a flash; one thing at a time reads as a story.
  2. Keep small entrances short, around 300 to 600 ms. Longer feels sluggish.
  3. Time motion to speech. In a narrated video, an element should appear just as the narrator mentions it.
  4. Combine properties. A fade plus a small 20 to 40 pixel rise looks far more polished than a fade alone.

In code

const EASING = {
  linear: (p: number) => p,
  easeIn: (p: number) => p * p * p,
  easeOut: (p: number) => 1 - (1 - p) ** 3,
  easeInOut: (p: number) => (p < 0.5 ? 4 * p * p * p : 1 - (-2 * p + 2) ** 3 / 2),
};

// Where an element is at time t, for a move from `from` to `to`:
const value = from + (to - from) * EASING.easeOut(progress);

These are cubic curves. CSS offers similar built-in curves (ease-in, ease-out, ease-in-out) defined with cubic-bezier(), whose exact shapes differ slightly but follow the same idea.

Earlier in this series: how a video editor works and rendering MP4 video in the browser.

Nobody