# Momentum

> Finish the throw people started.

- Section: Motion
- URL: https://critly.vercel.app/momentum
- Published: 2026-10-08
- Source: https://github.com/kausthubh-coder/critly/blob/main/content/motion/momentum.mdx

When you let go of something you're dragging, it's still moving. Whatever
animation takes over has to start at that speed, or there's a seam: the
object brakes to a stop the instant you let go, then starts moving again on
its own.

Throw each knob to the other end, hard.

> **Interactive demo: Velocity Handoff.** Open https://critly.vercel.app/momentum to try it.

The top knob finishes with a curve. Curves start from zero speed, so a fast
throw hits a wall at the moment of release. The bottom one finishes with a
[spring](https://critly.vercel.app/springs) that's given the release velocity, so the throw just
continues and settles.

**Hand the release velocity to the animation that finishes the gesture, and
aim for where the throw was going, not where it was let go.**

## Aim where it was going

A quick flick toward a corner is usually released closer to where it
started. Snap to the nearest corner from there and the window goes back.
Flick both windows.

> **Interactive demo: Projection.** Open https://critly.vercel.app/momentum to try it.

The right one projects the throw forward first. The dot shows where the
flick would have come to rest if it coasted like a scroll view, and the
window snaps to the corner nearest that point. Apple's projection uses
the scroll deceleration rate of 0.998 per millisecond, which works out to
about half a second of travel at the release speed: a 1000px/s flick
projects about 500px. Use 0.99 for a precise, less throwy feel, about a
tenth of a second.

## Velocity or distance

To dismiss a sheet or a toast, accept a short fast flick or a long slow
drag. Vaul dismisses a drawer at 0.4px/ms, or once it's dragged a quarter of
its height. Sonner dismisses a toast at 0.11px/ms or 45px. Requiring distance
alone makes things feel heavy.

## Give at the edges

Past a boundary, don't stop dead. Let the content follow less and less, then
spring back. The common iOS-style curve moves at 55% of the finger's speed at
first and never passes the container's own size.

> **Interactive demo: Rubber Band.** Open https://critly.vercel.app/momentum to try it.

## Usage

**Motion**

```tsx
import { animate, motion, useMotionValue } from "motion/react";

// Where a flick would come to rest (px/s in, px out).
const project = (velocity: number, rate = 0.998) =>
  ((velocity / 1000) * rate) / (1 - rate);

const x = useMotionValue(0);

<motion.div
  drag="x"
  dragMomentum={false} // the release is ours
  style={{ x }}
  onDragEnd={(_, info) => {
    const aim = x.get() + project(info.velocity.x);
    const target = aim > 160 ? 320 : 0;
    // A physics spring keeps the velocity it's given.
    animate(x, target, {
      type: "spring",
      stiffness: 247,
      damping: 31.4,
      velocity: info.velocity.x,
    });
  }}
/>
```

**Rubber band**

```ts
// How far content moves when pulled `over` px past an edge.
// `size` is the container's size; c = 0.55 is the iOS-like feel.
function rubberBand(over: number, size: number, c = 0.55) {
  return (1 - 1 / ((Math.abs(over) * c) / size + 1)) * size * Math.sign(over);
}
```

Animate x and y as two springs, each with its own velocity, so a diagonal
throw curves naturally. Pass `stiffness` and `damping`, not `duration` and
`bounce`: Motion drops the velocity of springs defined by time. Under
[reduced motion](https://critly.vercel.app/reduced-motion), keep dragging one-to-one with the finger,
and settle the release with no bounce and no long coast.

## Resources

- [Designing Fluid Interfaces](https://developer.apple.com/videos/play/wwdc2018/803/): Apple's WWDC18 talk on velocity handoff, momentum projection and rubber banding.
- [Fluid interfaces sample code](https://github.com/nathangitter/fluid-interfaces): Nathan Gitter's open-source recreation of the WWDC18 examples, including the projection function.
- [Building a drawer component](https://emilkowal.ski/ui/building-a-drawer-component): Emil Kowalski on Vaul's velocity-based dismissal and damped over-drag.
- [Drag in Motion](https://motion.dev/docs/react-drag): Drag gestures, release velocity, momentum and elastic constraints.
