gestures
Motion That Follows a Finger
A gesture-driven element is glued to the pointer from the first pixel and stays glued until release, at which point the animation that finishes the job starts at the pointer's exact velocity — so there is no seam between dragging and animating. That is the whole discipline. Benji Taylor's model is the one to hold in your head: "a fluid interface is akin to moving through water — you float rather than walk through it", and the app has "unbreakable physical rules" that every surface obeys. The default tool is therefore a spring, not a curve: { type: "spring", duration: 0.5, bounce: 0 }, dismissing on velocity rather than distance. The dividing line with motion is what drives the clock: a timer means motion, a position means gestures. Hit-target size, tap latency, and hover-on-touch belong to touch-input; whether the app as a whole reads as installed belongs to native-feel.
Adopt the project's gesture layer; do not add a second one. Grep for vaul, @use-gesture, embla, Motion's drag / useDragControls / dragConstraints, a bare pointerdown handler, touch-action, or CSS scroll-snap. Two gesture systems on one surface fight over pointer capture and produce a drag that sometimes scrolls. If the project solves sheets with Vaul, the next sheet is a Vaul sheet — and if the interaction is genuinely a snap carousel, scroll-snap plus overscroll-behavior beats any library.
Quick Reference
| When | Open |
|---|---|
| Choosing spring parameters, or handing a release velocity to the animation that finishes a drag | springs.md |
| Before building a drawer, bottom sheet, swipeable row, or pull-to-refresh — each has thresholds and guards you should not invent | drag-recipes.md |