# How to Configure Spring Animations for Drag, Gesture, and Momentum Interactions

> Master spring animations for drag, gesture, and momentum interactions. Achieve natural feel with velocity carry-over and interruptible springs for seamless UI control.

- Repository: [Emil Kowalski/skills](https://github.com/emilkowalski/skills)
- Tags: how-to-guide
- Published: 2026-08-05

---

**Use a spring with velocity carry-over for any gesture-driven UI—the spring retains release velocity for natural momentum and remains interruptible when users change direction mid-gesture.**

The `emilkowalski/skills` repository establishes clear standards for motion design, with spring animations as the core technique for responsive, physical-feeling interfaces. Whether you're building draggable sheets, swipe-to-dismiss toasts, or momentum-based scrolling, spring configuration determines how convincing your interaction feels.

## Why Springs Beat Transitions for Gesture Interactions

Spring physics excel where CSS transitions and keyframes fail. According to [`skills/review-animations/STANDARDS.md`](https://github.com/emilkowalski/skills/blob/main/skills/review-animations/STANDARDS.md), the critical advantage is **velocity carry-over**: when a user releases a drag, the spring seeds from the release velocity instead of restarting from zero.

Key benefits for gesture-based interactions:

- **Interruptibility** – Springs retarget from their current state. If a user reverses direction mid-gesture, the animation continues smoothly rather than snapping.
- **Natural momentum** – Physical objects don't stop abruptly. Feeding release velocity to a spring creates that "thrown" sensation.
- **Continuous responsiveness** – The spring reacts to every frame of input, maintaining connection between finger and UI element.

The repository notes that keyframes feel "brick-wall-like" because they ignore velocity state—springs solve this by design.

## Canonical Spring Configurations

[`skills/review-animations/STANDARDS.md`](https://github.com/emilkowalski/skills/blob/main/skills/review-animations/STANDARDS.md) defines two recommended approaches:

### Apple-Style Config (Recommended Default)

```javascript
{ type: "spring", duration: 0.5, bounce: 0.2 }

```

This produces a **critically-damped spring**—easy to reason about, predictable timing, subtle overshoot. Ideal for most UI work where you want polish without distraction.

### Physics-Based Config (Precise Control)

```javascript
{ type: "spring", mass: 1, stiffness: 100, damping: 10 }

```

Use when you need specific physical characteristics: heavier `mass` for sluggish, substantial feel; higher `stiffness` for snappier response; `damping` tuned to eliminate or emphasize oscillation.

## Spring Setup by Interaction Type

| Interaction | Spring config | Velocity handling |
|-------------|-------------|-------------------|
| **Drag-to-move** (sheets, cards) | `{ type: "spring", duration: 0.5, bounce: 0.2 }` | Pass pointer velocity on `pointerup` |
| **Flick-to-dismiss** (toasts, modals) | Same, or increase `bounce` to 0.3 for playful exit | Compute `distance / elapsedMs`, apply as `velocity` option if threshold exceeded |
| **Continuous decorative motion** | `{ type: "spring", mass: 1, stiffness: 100, damping: 10 }` | No external velocity; natural settle creates subtle "alive" movement |

The repository recommends a velocity threshold of approximately **0.11** (normalized) for momentum-based dismissals, as noted in the design guidelines.

## Implementation with Motion (Framer Motion)

[`skills/pick-ui-library/SKILL.md`](https://github.com/emilkowalski/skills/blob/main/skills/pick-ui-library/SKILL.md) recommends **Motion** (formerly Framer Motion) for React projects. The `useSpring` hook provides direct API access to velocity seeding.

### Drag-to-Move Card

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

export function DraggableCard() {
  const [{ x, y }, api] = useSpring(
    { x: 0, y: 0 },
    { type: "spring", duration: 0.5, bounce: 0.2 }
  );

  const handleDrag = (e: PointerEvent) => {
    api.start({ x: e.clientX, y: e.clientY });
  };

  const handleRelease = (
    e: PointerEvent,
    info: { velocity: { x: number; y: number } }
  ) => {
    api.start({
      x: e.clientX,
      y: e.clientY,
      velocity: Math.hypot(info.velocity.x, info.velocity.y) / 1000,
    });
  };

  return (
    <motion.div
      style={{ x, y, touchAction: "none", cursor: "grab" }}
      onPointerDown={(e) =>
        e.currentTarget.setPointerCapture(e.pointerId)
      }
      onPointerMove={handleDrag}
      onPointerUp={handleRelease}
    >
      {/* Card content */}
    </motion.div>
  );
}

```

### Momentum-Dismiss Toast

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

export function Toast({ onClose }: { onClose: () => void }) {
  const [{ y }, api] = useSpring(
    { y: 0 },
    { type: "spring", duration: 0.5, bounce: 0.2 }
  );

  const handleSwipe = (
    e: PointerEvent,
    info: { velocity: { y: number } }
  ) => {
    const velocity = Math.abs(info.velocity.y) / 1000;

    if (velocity > 0.11) {
      api.start({ y: 200, velocity }).then(onClose);
    } else {
      api.start({ y: 0 });
    }
  };

  return (
    <motion.div
      style={{
        y,
        touchAction: "none",
        background: "#333",
        color: "#fff",
        padding: "8px 16px",
      }}
      onPointerDown={(e) =>
        e.currentTarget.setPointerCapture(e.pointerId)
      }
      onPointerMove={handleSwipe}
    >
      Swipe up to dismiss
    </motion.div>
  );
}

```

Both examples demonstrate the pattern from [`skills/apple-design/SKILL.md`](https://github.com/emilkowalski/skills/blob/main/skills/apple-design/SKILL.md): update spring target during drag, seed with computed velocity on release.

## Velocity Calculation and Thresholds

For momentum interactions, compute velocity as:

```javascript
const velocity = Math.abs(distance) / elapsedMs;

```

The repository suggests normalizing to approximately **0.11** as the threshold for triggering a dismiss action. Below this, the element should spring back to its original position; above it, the momentum carries through to completion.

Normalization (dividing by 1000 in the examples above) converts to units compatible with Motion's spring API.

## Key Source Files

| File | Purpose |
|------|---------|
| [`skills/review-animations/STANDARDS.md`](https://github.com/emilkowalski/skills/blob/main/skills/review-animations/STANDARDS.md) | Canonical spring definitions and configuration standards |
| [`skills/apple-design/SKILL.md`](https://github.com/emilkowalski/skills/blob/main/skills/apple-design/SKILL.md) | Design rationale for gesture-spring pairing, velocity mapping guidelines |
| [`skills/improve-animations/AUDIT.md`](https://github.com/emilkowalski/skills/blob/main/skills/improve-animations/AUDIT.md) | Motion audit criteria emphasizing springs for interruptible gesture UI |
| [`skills/pick-ui-library/SKILL.md`](https://github.com/emilkowalski/skills/blob/main/skills/pick-ui-library/SKILL.md) | Library recommendations, including Motion for spring-based animation |

## Summary

- **Springs preserve velocity** where transitions reset to zero, creating natural momentum for drag and gesture interactions.
- **Apple-style config** (`duration: 0.5, bounce: 0.2`) handles most UI needs; use physics parameters for precise physical feel.
- **Seed release velocity** into the spring via the `velocity` option to maintain continuity when gestures end.
- **Threshold at ~0.11** for momentum-based dismissals, snapping back below and completing above.
- **Motion's `useSpring`** provides the `velocity` API needed to implement these patterns in React.

## Frequently Asked Questions

### What's the difference between `duration`/`bounce` and `mass`/`stiffness`/`damping` springs?

The `duration`/`bounce` shorthand produces the same underlying physics but with intuitive controls: `duration` sets settle time, `bounce` sets overshoot amount (0-1). The physics parameters expose the raw spring model for cases where you need specific mass or stiffness characteristics. [`skills/review-animations/STANDARDS.md`](https://github.com/emilkowalski/skills/blob/main/skills/review-animations/STANDARDS.md) recommends the shorthand as the default.

### Why not use CSS `transition` with `cubic-bezier` for gestures?

CSS transitions restart from zero velocity on every target change, creating that "brick-wall" feel when gestures interrupt. Springs maintain state—their equations incorporate current velocity and position, enabling retargeting continuity essential for responsive drag interactions.

### How do I prevent springs from feeling "bouncy" or unprofessional?

Keep `bounce` between **0.1 and 0.3** for UI realism, per [`skills/apple-design/SKILL.md`](https://github.com/emilkowalski/skills/blob/main/skills/apple-design/SKILL.md). Higher values feel playful or toy-like; 0 produces overdamped motion with no overshoot. Critically-damped springs (bounce ~0.2) balance responsiveness with stability.

### Which library does the repository recommend for spring animations?

Motion (formerly Framer Motion), as documented in [`skills/pick-ui-library/SKILL.md`](https://github.com/emilkowalski/skills/blob/main/skills/pick-ui-library/SKILL.md). Its `useSpring` hook exposes the `velocity` option required for momentum seeding, with React-native integration that matches the repository's implementation patterns.