Give drags physics

Release drags onto springs, dismiss on velocity, rubber-band edges.

From improve-animations and find-animation-opportunities.

Flick a sheet away

Flick each sheet down fast; only the right one reads speed.

Distance, 300ms tweenBad

Approve 3 bills

0.00 px/ms
Velocity + springGood

Approve 3 bills

0.00 px/ms
import { animate, motionValue } from "motion";

const SPRING = { type: "spring", duration: 0.5, bounce: 0.2 };
const y = motionValue(0);
y.on("change", (v) => { sheet.style.transform = `translateY(${v}px)`; });

function onRelease({ distance, elapsedMs, height }) {
  const velocity = Math.abs(distance) / elapsedMs;
  const dismiss = distance > height / 2 || (distance > 8 && velocity > 0.11);
  animate(y, dismiss ? height : 0, { ...SPRING, velocity: y.getVelocity() });
}

Throw a card

Throw a card, then catch it mid-flight.

Fixed 300ms tween backBad
$4,210.00Drag me
animate(keyframes, 300ms ease)v0 = 0
Spring with velocityGood
$4,210.00Drag me
spring 0.5s, bounce 0.2v0 = 0
const SPRING = { type: "spring", duration: 0.5, bounce: 0.2 };

card.addEventListener("pointerdown", () => { x.stop(); y.stop(); });
card.addEventListener("pointerup", () => {
  animate(x, 0, { ...SPRING, velocity: x.getVelocity() });
  animate(y, 0, { ...SPRING, velocity: y.getVelocity() });
});

Scroll past the end

Drag or fling each list past its edge.

Recommended range 0.1 to 0.3, marked in green.
Hard stopBad
y = clamp(y, min, 0)
Rubber bandGood
spring 0.5s, bounce 0.2
const rubberband = (overshoot, dimension, c = 0.55) =>
  (1 - 1 / ((overshoot * c) / dimension + 1)) * dimension;

const offset =
  raw > 0   ? rubberband(raw, viewHeight) :
  raw < min ? min - rubberband(min - raw, viewHeight) :
  raw;

animate(y, edge, { type: "spring", duration: 0.5, bounce: 0.2, velocity });

Why it matters, pros and cons

Why it matters

A spring continues the finger’s speed. Edges that resist say “end”, not “frozen”.

Pros

  • Short, fast flicks dismiss.
  • Catch mid-flight with no restart.
  • Boundaries explain themselves.

Cons

  • Springs have no fixed end time.
  • Velocity alone dismisses on a twitch; require travel.
  • Native scroll already overscrolls; don't rebuild it.