Skip to content

UI Physics

Spring physics playground

Tune a spring by feel, then export it to Motion, React Spring, CSS linear(), SwiftUI and more.

Spring curve
Damping ratio
0.45
Settles in
1170 ms
Peak
1.208
Regime
underdamped

Overshoots and rings before settling

Card

Modal

Button press

Press

Tab indicator

OneTwoThree
transition={{
  type: "spring",
  stiffness: 180,
  damping: 12,
  mass: 1,
}}

How it works

  1. Tune

    Stiffness, damping, mass and initial velocity.

  2. Solve

    Three closed forms, chosen by damping ratio.

  3. Check

    Curve, overshoot peak and the millisecond it settles.

  4. Export

    Eight targets, each marked exact or approximate.

Why UI Physics

Spring tools are tied to one framework, and the CSS ones quietly hand you a curve that cannot match what you just previewed.

Almost every spring playground belongs to one library. You tune a feel in a React Spring visualiser and then re-guess it by hand in Motion, or in CSS, or in SwiftUI, because the numbers do not carry across. The thing you actually tuned was a feel, and the feel is portable even when the config is not.

The CSS side has a sharper problem. A cubic-bezier can overshoot its target once. It cannot come back and overshoot again, which is exactly what a bouncy spring does. Tools that offer a bezier for any spring are giving you a curve that does not match their own preview, and you will not notice until the motion looks wrong in the build.

There is also a number nobody shows. When you budget an interaction, what you need is how long the motion takes to stop — not to look roughly finished, but to stay within a fraction of a percent of target. Without that readout, the sliders cannot tell you whether you built something responsive or something that drags.

It refuses to lie about cubic-bezier

When no bezier can match your spring, it says so and points at linear(), instead of emitting a curve that disagrees with the preview above it.

Compared withFramer Motion docs · react-spring visualiser · cubic-bezier.com · linear() easing generator
CapabilityElsewhereHere
Exports to more than one frameworkNo:Playgrounds are usually tied to their own libraryYes:Motion, React Spring, CSS, SwiftUI, Flutter
Correct past critical dampingPartly:A single underdamped formula breaks above itYes:Three closed forms, tested against numerical integration
Honest about cubic-bezierNo:A bezier is offered even for curves it cannot expressYes:Refused for ringing springs, error stated otherwise
CSS linear() outputPartly:Available in dedicated generators, rarely elsewhereYes:Primary CSS output, simplified to stay pasteable
Settle time in millisecondsNo:Seldom shownYes:Solved in closed form, not eyeballed
Shareable linkPartly:SometimesYes:Every parameter lives in the URL

What it does

Drag three sliders until the motion feels right, then copy the config for whichever framework you are in. The same spring is translated to Motion, React Spring, CSS, SwiftUI and Flutter, so a feel you tuned once travels between platforms instead of being re-guessed on each.

The three numbers

Stiffness is how hard the spring pulls toward its target. Raise it and everything happens sooner. Damping is the resistance that bleeds energy out. Too little and the element rings like a plucked string; too much and it crawls. Mass is how much inertia there is to overcome — heavier elements start later and take longer to stop.

What actually determines the character of the motion is the ratio between them, called the damping ratio. Below one the spring overshoots and oscillates. At exactly one it reaches the target as fast as possible without ever passing it. Above one it eases in slowly and never overshoots at all.

Why a bouncy spring cannot be a cubic-bezier

A cubic-bezier easing curve can overshoot its endpoint once. It cannot come back and overshoot again, which is exactly what a bouncy spring does. So for any spring with real bounce, no cubic-bezier exists that matches it, and any tool that hands you one is giving you a curve that does not match its own preview.

The honest answer in CSS is linear(), which takes a list of sampled points and can therefore describe an oscillating curve exactly. It is supported across current browsers. Where a bezier genuinely does fit, this tool will give you one and show you the measured error; where it does not, it will say so instead of guessing.

Settle time

The number most worth knowing when budgeting an interaction is how long the motion takes to stop — not how long it takes to look roughly finished, but the point past which it stays within a fraction of a percent of its target. A transition that settles in four hundred milliseconds feels responsive. The same spring at nine hundred feels broken, and the sliders will not tell you which one you have built without that readout.