Spring Physics — F = -kx - cv

[check: …]
📖 guide (.md) ← react deep dive
📖 Pair this live React playground with the companion guide (.md) — this page is the rendered ground truth. ↗ framer_motion_core uses springs internally — here's the physics underneath (F = -kx - cv).

duration + easing → physics

A tween moves a value from A to B over a fixed duration along an easing curve. A spring has no duration — it simulates a mass on a spring. Each frame the solver computes the restoring force from Hooke's law plus a damper, integrates, and repeats until the system settles. Because it carries velocity, a spring overshoots, settles naturally, and survives interruptions (a new target just re-aims the same moving mass).

F = -k·x - c·v        (Hooke's law + damping force)

  k = stiffness   (spring strength — pull back toward target)
  x = displacement (position - target)
  c = damping     (friction — bleeds energy each frame)
  v = velocity

acceleration = F / mass
velocity    += acceleration · dt     // semi-implicit Euler (stable)
position    += velocity    · dt
repeat until |v| ≈ 0 AND |position - target| ≈ 0
parameterunitraise it →effect
stiffness (k) N/m stronger pull faster, snappier, more oscillation
damping (c) N·s/m more friction less overshoot, settles sooner (c critical = no bounce)
mass (m) kg heavier object slower acceleration, sluggish feel

1 · the spring solver you write (edit me)

2 · Babel compiles JSX → element tree

<SpringDemo/> becomes React.createElement(SpringDemo). The effect's step() loop mutates the ball via ballRef — no React re-render per frame, so 60fps stays cheap.

// (hit "compile & render" to see Babel's output)

3 · live React (the solver, proven)

Drag the sliders, click a preset, or click anywhere on the track to re-aim the target. The gold-check does this automatically: it asserts the ball starts at ~50%, clicks Set Target: 80%, waits for the spring to settle, then asserts the ball landed near 80% — proving F = -kx - cv drives real motion.

ball pos: · gold: start ~50% → click 80% → settle near 80% (moved > 20%)

spring vs tween · presets

intentspringtween (duration + easing)
model physics: F = -kx - cv time-mapped curve (linear/ease-out/cubic-bezier)
duration emergent — settles when |v| ≈ 0 fixed (300ms)
interruption keeps velocity → smooth re-aim restarts from a new curve (can jump)
overshoot physical (underdamped only) only if easing allows
best for gestures, drag, swipe, UI choreographed sequences, loops
presetstiffnessdampingfeel
Gentle10012soft, natural (≈ Framer default)
Wobbly18012playful bounce
Stiff21020snappy
Slow28060heavy, slow
Molasses280120very slow, no overshoot