Dynamics · 19
Snap
吸附 · snapChoose a target from the current or projected landing point, then arrive with a spring.
Nearest makes sense once motion has stopped. During a fast throw, the user expects to pass the closest card. Choosing the card nearest the projected landing respects that direction. Pulling toward a changing nearest card each frame can make the final decision feel late and mushy.
Formula
probe = projected ? value + velocity·τ : value target = argmin(point: |point − probe|) spring(value, target, velocity)
Parameters
| This page | Mature libraries | |
|---|---|---|
| mode | projected | GSAP Inertia end / Motion modifyTarget |
| spacing | card pitch | — |
| timeConstant | 0.35 s | Motion 325 ms |
Doing it well
- For a throw, select the snap point at the projected landing, not only at release position. GSAP Inertia applies
endto its natural landing.GSAP src/InertiaPlugin.js:87–97,132 - Fix the chosen target and pass release velocity to the spring; avoid picking a new nearest card every frame.
- Nearest snapping works for a slow drag; once the strip is stopped, projected and nearest generally converge.
In our cases
15 studies use snapping. The quality notes for momentum-slider, drag-gallery and riffle flag per-frame pulling toward nearby cards; this page separates choosing a target at release from arriving there.
Used in 15 cases
Reference implementation · basics.js
/**
* Pick where a thrown value should settle.
* nearest — closest point to where it is now (fine once it has stopped)
* projected — closest point to where it WOULD land: respects the throw (iOS, GSAP Inertia, Motion)
* Then hand { target, velocity } to a Spring so the arrival carries the throw's momentum.
*/
export function snapTarget({ value, velocity = 0, spacing, points, mode = 'projected', timeConstant = 0.35 }) {
const probe = mode === 'projected' ? value + velocity * timeConstant : value;
if (points && points.length) return points.reduce((a, b) => (Math.abs(b - probe) < Math.abs(a - probe) ? b : a));
return Math.round(probe / spacing) * spacing;
}