Hand off release velocity

Start the spring at the release velocity so drag and settle are one.

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

Throw the sheet

Flick a sheet and let go mid-motion, or press Throw both.

Starts at 0 px/sBad

spring({ from: y, to, velocity: 0 })
Starts at releaseGood

spring({ from: y, to, velocity: v })
sheet.addEventListener("pointerup", (e) => {
  const v = releaseVelocity(history, e.timeStamp);
  spring({ from: y, to, velocity: v, onUpdate: render });
});

Measure the release velocity

Drag the knob and release while moving, then while still.

From pointer historyLive
Last event only
0 px/s
Windowed
0 px/s
Target − current
0 px
Relative velocity
0

v = Δp / Δt over the last window
const recent = history.filter((s) => now - s.t <= 100);
if (recent.length < 2) return 0;

Match the API's velocity units

Edit the values, then press Play.

relativeVelocity = 50 / (150 − 50) = 0.5

Raw px/s as relativeBad

initialSpringVelocity: 50
Normalized by distanceGood

initialSpringVelocity: 0.5
animate(el, { y: 150 }, { type: "spring", velocity: 50 });
const relative = 50 / (150 - 50);

Why it matters, pros and cons

Why it matters

Starting at zero drops the speed for a frame. The eye reads that dip as a seam.

Pros

  • Drag and settle read as one motion.
  • Harder throws land with more energy.
  • Same number picks the snap target.

Cons

  • Last-event velocity is noisy; average over 100 ms.
  • A finger held still must yield zero.
  • Raw px/s into relative APIs overshoots wildly.