Help guide

Drag Velocity node

Updated June 21, 2026

Drag Velocity node

Product media placeholder

Replace this area with a screenshot or short walkthrough video during the media sweep.

Passive pointer-drag sensor: cumulative per-axis offset, per-frame raw delta, continuous velocity, optional post-release inertia. Emits px-cumulative offset (`offsetX`/`offsetY`), per-frame raw pointer delta (`frameDeltaX`/`frameDeltaY`), px/sec velocity (`dx`/`dy`), magnitude, and an `isDragging` gate. Never moves the bound element — pure pointer-event integration so the data can be composed into arbitrary downstream graph expressions (carousel pan, parallax pull, scrub-forever timelines, swipe-to-scroll via `scrollPosition`) without hijacking the listen target. After release, velocity decays exponentially over `releaseDecay`; with `inertia: true` that decaying velocity also integrates back into offset (and into `frameDelta*` so an inertia tail can flow into a downstream `scrollPosition`), respecting the optional clamp bounds.

Type dragVelocityCategory inputsContext sharedDynamic ports noCompound no

Inputs

PortTypeDescription
gateInputfloatWhen > 0.5 the node ignores pointer events. Wire from any "busy" signal — e.g. a transitionProgress > 0 expression — to lock drag while another animation is in flight.
clampMinXInputfloatOptional dynamic lower bound on offsetX. When the wired value is finite, it overrides the static `clampMinX` param every frame — the right wiring for carousels/parallax that need bounds tied to a measured runway (e.g. wire from `-scrollTrigger.windowPx` so drag range tracks viewport resize).
clampMaxXInputfloatOptional dynamic upper bound on offsetX. Same semantics as `clampMinXInput`.
clampMinYInputfloatOptional dynamic lower bound on offsetY. Same semantics as `clampMinXInput`.
clampMaxYInputfloatOptional dynamic upper bound on offsetY.

Outputs

PortTypeDescription
offsetXfloatCumulative pointer delta on X integrated across pointermove samples. With `accumulate: true` (default) persists across drag sessions — the typical swipe-pan / scrub-forever idiom. With `accumulate: false` resets to 0 on every pointerdown (slider/knob idiom). Optionally clamped via `clampMinX` / `clampMaxX` (static) or `clampMinXInput` / `clampMaxXInput` (dynamic, wired override).
frameDeltaXfloatRaw cumulative pointer-X delta from this frame's pointer events plus inertia tail (when `inertia` is on). Republished every evaluate(); 0 on frames with no input. The right port to wire into `scrollPosition.addX` / `addY` for swipe-to-scroll, or any consumer that wants per-frame deltas (not the cumulative offset which keeps growing).
frameDeltaYfloatRaw cumulative pointer-Y delta from this frame's pointer events plus inertia tail. Same lifecycle as frameDeltaX.
offsetYfloatCumulative pointer delta on Y. Same semantics as offsetX. Optionally clamped via `clampMinY` / `clampMaxY`.
dxfloatInstantaneous velocity on X. While dragging this updates with each pointermove sample; after release it decays toward 0 over `releaseDecay`.
dyfloatInstantaneous velocity on Y. Same lifecycle as dx.
magnitudefloat`sqrt(dx² + dy²)`. Convenience for "drag speed" driven effects (blur amount, distortion gain).
isDraggingfloat1 while a pointer is down, 0 otherwise. Note: velocity continues to decay after isDragging flips to 0 — wire `magnitude` for a "still moving" signal.

Parameters

ParameterTypeDefaultDescription
selectorelementSelector""Element to listen on. Empty = window-scope (full-page drag, the default for carousel-style use). Set a specific selector to scope to a region.
accumulatebooltrueWhen true (default), `offsetX`/`offsetY` persist across drag sessions — each new drag continues from the previous release position. The right setting for swipe-pan carousels and scrub-forever timelines. Set false for slider/knob idioms where each touch is a fresh delta from origin (offset resets to 0 on pointerdown).
inertiaboolfalseWhen true, post-release velocity also integrates back into `offsetX`/`offsetY` (with the same decay used on velocity), giving a "throw the carousel" feel. Clamp bounds still apply: hitting a wall zeros that-axis velocity. Default false — pure offset, no glide.
sampleSmoothingfloat0.7Per-pointermove retention coefficient on the raw delta/dt computation for VELOCITY only — offset always tracks raw deltas exactly. 0 = no smoothing (very jittery velocity). 0.7 = silky default. Higher = smoother but more lag behind the cursor. min 0; max 0.99; step 0.05
releaseDecayfloat0.85Per-frame retention coefficient on velocity AFTER pointerup. 0 = instant snap to 0 (no inertia tail). 0.85 = smooth fling decay (default). Frame-rate independent. min 0; max 0.99; step 0.05
pointerCapturebooltrueWhen true (default), calls setPointerCapture on pointerdown so move events keep firing even if the cursor leaves the element. Set false for hover-driven UIs that need pointer events to bubble normally. Note: end-of-gesture events (pointermove/up/cancel) are always listened for on `window` so the gesture cleanly terminates regardless of capture.
axisLockstring"free"Gesture-classification mode after movement passes `axisLockThreshold`. `free` (default) = both axes always emit (do your own filtering downstream). `auto` = lock to whichever axis dominated at threshold; the other emits 0 for the rest of the gesture. `x` / `y` = require that axis to dominate; if the other dominates the gesture is REJECTED entirely (zero output for the rest of it). Use `y` on a per-card vertical-rotation sensor so horizontal pan-jitter passing over the card is ignored.
axisLockThresholdfloat6Cumulative |dx|+|dy| (px) before classification fires. Below this no axis is locked and both accumulate normally so taps and tiny initial movements don't pre-lock to noise. 6 px (default) matches the typical OS click-vs-drag threshold.
clampMinXfloat-Lower bound on offsetX. Leave unset for unbounded. Combined with clampMaxX to constrain a carousel to a finite runway.
clampMaxXfloat-Upper bound on offsetX. Leave unset for unbounded.
clampMinYfloat-Lower bound on offsetY. Leave unset for unbounded.
clampMaxYfloat-Upper bound on offsetY. Leave unset for unbounded.

Use cases

  • Swipe-to-scroll carousel — wire `frameDeltaX` (negated) into a `scrollPosition.addY` so horizontal drag advances page scroll directly; pin disengages naturally when scroll reaches the runway end. No need for offset clamps — scroll bounds own the limits.
  • Carousel pan (offset-driven) — wire `offsetX` into a translateX expression on the carousel track. Set `clampMinX`/`clampMaxX` to the runway bounds; enable `inertia` for fling-to-snap.
  • Drag-driven scrub — wire `offsetX` through an expression mapping it to 0..1 (e.g. `Math.max(0, Math.min(1, offsetX / range))`) and feed the progress port of any animation.
  • Per-card rotation / squish — instance the node via forEach scope on each card; wire `dy` into a CSS variable for velocity-gated rotation, or `offsetY` for cumulative rotation.
  • Fluid-carousel drag stretch — wire `dx`/`dy` into `texturedMeshTile.offsetX/offsetY` for velocity-driven mesh translation.
  • Drag-snap navigation — wire `magnitude` through a `thresholdPulse` to fire a snap once velocity crosses a hard threshold (a "fling to next").
  • Velocity-gated wheel — wire `isDragging` into `wheelGesture.gateInput` so wheel events are ignored while the user is actively dragging.

Related nodes

Envelope

Use dragVelocity as the node type inside a graph node envelope. Add id, optional params, optional connections, and optional activeWhen based on the guide context.

Generated source

Registry faster-motion-docs/node-registry.jsonCategory page /help/faster-motion/faster-motion-node-category-inputs/

Was this guide helpful?

Sunny Arora

Written by

Sunny Arora

Get technical deep dives delivered to your inbox

Join creators and developers who get exclusive insights, tutorials, and behind-the-scenes content every week.

No spam. Unsubscribe anytime.

Continue Exploring

You might also enjoy