Make animation interruptible

Never lock input; start each animation from the live value.

From apple-design, §3, after Designing Fluid Interfaces ↗.

Grab the sheet mid-flight

Press Toggle, then grab the sheet while it moves.

Locked until doneBad
Share

Closed

if (animating) return;
Grab any timeGood
Share

Closed

spring.stop(); y = live

Toggle rapidly

Press Toggle both quickly. Cliffs are jumps.

From the logical valueBad
Panel

jump 0 px

animate([closed, open])
From the live valueGood
Panel

jump 0 px

animate([live, open])
const live = new DOMMatrixReadOnly(getComputedStyle(panel).transform).m41;
anim?.cancel();
anim = panel.animate([{ transform: `translateX(${live}px)` }, { transform: `translateX(${to}px)` }], opts);

Spam left and right

Alternate Left and Right fast, or press Spam.

@keyframes restartBad

At rest

animation: go-right 700ms
Spring re-targetGood

At rest

spring({ from: x, velocity: v })

Why it matters, pros and cons

Why it matters

Intent changes mid-motion. Lockouts make users wait; restarts teleport the object.

Pros

  • Every press and grab lands instantly.
  • Position stays continuous; no teleports.
  • Springs keep velocity through re-targets.

Cons

  • Grabbable motion needs JS; CSS alone can't be caught.
  • Springs have no fixed duration for choreography.
  • Reversing motion must not imply an undone commit.