fdb/docs

[§] /docs/how-to/pick-an-ease

How to pick the right ease (and when to use a spring)

Choose a curve in seconds, with a default set that covers almost every move.

TL;DR

  • Entering or responding: expo.out. Moving between two states: power4.inOut.
  • Retro and pixel pieces: steps(n). Continuous loops: none.
  • Anything people can grab or interrupt: a spring.

Goal: motion that feels intentional, with no time spent guessing curves.

You need

  • GSAP (or CSS cubic-bezier). Motion (motion/react) for springs.
  • The motion tokens, so every component uses the same names.
 expo.out      █▓▒░░···   enter, respond
 power4.inOut  ·░▒██▒░·   between states
 steps(6)      ··██··██   retro, pixel
 none          ▒▒▒▒▒▒▒▒   loops, marquees
 (speed over time: solid is fast)

See them side by side

ease-out

UI enters & responds

ease-in-out

moves across screen

ease-in

exits only

overshoot

playful, use rarely

Time runs left to right, progress bottom to top. A curve that rises fast early (ease-out) feels responsive, because the change is visible immediately.
linear
ease-out-quint
ease-in-out-cubic
ease-in (avoid for UI)
spring-ish overshoot
Same distance, same duration. Only the curve changes. Press play and watch which ones feel like UI.

Steps

1. Ask what the thing is doing

  • Arriving or reacting (menu opens, toast appears, hover): ease-out. It starts fast so it feels instant, then settles.
  • Already on screen and moving (a card to a new slot, a drawer): ease-in-out. It speeds up and brakes like a real object.
  • Leaving for good: ease-in is allowed here, and only here.

2. Use the default set

gsap.defaults({ ease: 'expo.out', duration: 0.6 });
gsap.to(card, { x: 240, ease: 'power4.inOut', duration: 0.8 });   // between states
gsap.to(sprite, { x: 96, ease: 'steps(6)', duration: 0.6 });      // retro
gsap.to(track, { xPercent: -50, ease: 'none', repeat: -1, duration: 20 }); // loop

In CSS, expo.out is close to cubic-bezier(0.16, 1, 0.3, 1) and power4.inOut to cubic-bezier(0.76, 0, 0.24, 1).

3. Keep durations short

Hover and press 100 to 200ms. Menus 150 to 250ms. Modals and sections 250 to 400ms. If you notice the animation itself, it is too long.

4. Reach for a spring when people can interrupt

A curve has a fixed duration. If someone grabs a sheet halfway, a curve has to restart. A spring keeps its current speed and carries on from where it is.

spring
ease-out
settles in
1150ms
overshoot
19.1%
A spring has no duration: stiffness and damping decide how long it takes and whether it overshoots. The bezier gets the same time, so only the feel differs. Low damping wobbles; high damping feels heavy.
<motion.div drag="x" dragConstraints={{ left: 0, right: 0 }}
  transition={{ type: 'spring', stiffness: 400, damping: 36 }} />

Keep bounce off for functional UI. Save a little overshoot for one playful moment.

5. Never use ease-in for a response

It starts slowly, so a click feels laggy. The browser keyword ease has the same problem in a milder form.

Why it works

Real objects never start or stop instantly. Ease-out mimics something thrown into place, ease-in-out mimics something pushed and braked. People read both as physical, so the interface feels solid.

See it live

[ex] in the wild · 14

Sources

On this page