Command Palette

Search for a command to run...

Hectal
Shots in this scene
SHOT 9.3Intermediate ~19 min · shot 3 of 7

Duration-Based Springs

In one line

Designers think in "about a third of a second, a little bounce", not in stiffness and damping. Motion's visualDuration and bounce convert that into real spring physics.

0/7 · 0%

Think of it like this

You book a taxi by saying when you must arrive, not by naming the engine's horsepower. visualDuration and bounce are the arrival time and a taste for how lively the ride is. The horsepower, stiffness and damping, is worked out for you.

Words you'll meet

New words in this topic, in plain English. Come back here whenever one feels fuzzy.

bounce
Motion's dial for liveliness. 0 is critical damping, larger is bouncier, negative is overdamped.
visualDuration
In seconds, the time the movement looks done. The bounce tail can run longer.
duration-based spring
A spring solved to end at a given time, built from duration and bounce.
design token
A named value shared by designers and code, such as a spring called "fast spatial".

Step by step

01Read the three balls

All three springs have visualDuration 0.4 s. Bounce 0, 0.25 and 0.5 overshoot 0.0%, 2.8% and 16.3%.

02Press Go, pause at 400 ms

The balls are at 154.7, 164.1 and 168.7 of 160 px. The timeline shows linear() tracks of 750, 700 and 1050 ms: Motion sampled each spring into a CSS easing.

03Read the option table

Line 4 shows precedence, line 3 the end at exactly the duration, line 5 the negative bounce, line 6 the clamp.

04Take the taste test

Play both drawers of the "Feel it" pair and pick one before the answer opens.

Try it yourself

  1. 1

    Turn the dial to 1

    In "Bounce balls" change the third 0.5 in cases to 1. The console says ζ 0, overshoot 85.4%, at rest after 8159 ms: our 1 - bounce says ζ 0 but Motion clamps it to 0.05, so the ball bobs for 8 s.

  2. 2

    Shorten the duration

    In "What Motion makes of the options" change duration: 500 to 200: overshoot 1.5%, at rest after 200 ms. A duration-based spring ends exactly on time with the same overshoot, only faster.

Code & diagrams

Bounce balls

Motion's `spring()` is a generator: `next(t)` gives the position at t milliseconds. The console loops over it. The balls use `animate()` with the same options.

Press Run to see the page.
00:00.000
animations
0.00s0.10s0.20s0.30s0.40s0.50s0.60s0.70s0.80s0.90s

Nothing is moving yet. Hover, click or scroll the page: every animation it starts shows up here as a track.

frames

Console

Nothing logged yet.

Expected console output

bounce 0: ζ 1, overshoot 0.0%, at rest after 720 ms
bounce 0.25: ζ 0.75, overshoot 2.8%, at rest after 679 ms
bounce 0.5: ζ 0.5, overshoot 16.3%, at rest after 819 ms
What Motion makes of the options

Seven option sets run through the generator.

Press Run to see the page.
00:00.000
animations
0.00s0.10s0.20s0.30s0.40s0.50s0.60s0.70s0.80s0.90s

Nothing is moving yet. Hover, click or scroll the page: every animation it starts shows up here as a track.

frames

Console

Nothing logged yet.

Expected console output

no options (stiffness 100, damping 10)    → overshoot 16.3%, at rest after 1068 ms
visualDuration 0.4, bounce 0.2            → overshoot 1.5%, at rest after 701 ms
duration 500, bounce 0.2                  → overshoot 1.5%, at rest after 500 ms
stiffness 170, damping 26 + bounce 0.9    → overshoot 0.0%, at rest after 718 ms
bounce -0.5, visualDuration 0.4           → overshoot 0.0%, at rest after 787 ms
bounce 1, visualDuration 0.4              → overshoot 85.4%, at rest after 8159 ms
stiffness 170, damping 0                  → overshoot 100.0%, never rests
Feel itA drawer that opens

Open the cart drawer on both sides. Which one would you want on the launch page?

A Bounce 0.5, 0.5 s

Press Run to see the page.

B Bounce 0.1, 0.35 s

Press Run to see the page.
Play both, then choose:

Break it on purpose

Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.

Break #1

Mix physics and time

Read line 4 of "What Motion makes of the options": stiffness and damping together with bounce 0.9 and duration 300.

terminal
$ Read the console
── what you'll see ──
overshoot 0.0%, at rest after 718 ms

Myth vs fact

Myth

Bounce 0 is the fastest way to settle.

Fact

In the example bounce 0.25 was at rest after 679 ms and bounce 0 after 720 ms: a critically damped spring creeps in.

Pro corner

Extra depth for experienced readers. New to this? Skip it for now and come back later.

  • ▸

    For properties the browser can animate on its own, Motion builds a linear() easing from the spring (the tracks above are WAAPI animations with linear() and a generator-measured duration). That is why such a spring has a fixed length and cannot take over an earlier speed (9.4, 9.5).

Remember this

  1. 1

    The problem this solves: stiffness 170 and damping 26 mean nothing to a designer, and Mei's spec says "0.35 s, a light bounce". Motion (14.3 here) takes both descriptions and turns the friendly one into physics.

  2. 2

    **bounce is the damping ratio in disguise.** For bounce 0 to 1, ζ = 1 - bounce: 0 is critical damping, 0.25 is ζ 0.75, 0.5 is ζ 0.5. A negative bounce gives an overdamped spring, ζ = 1 ÷ (1 + bounce). ζ never falls below 0.05, so bounce 1 is not endless: it overshoots 85.4% and rests after 8159 ms.

  3. 3

    **visualDuration is the time the move looks done.** For bounce 0 and up, Motion sets stiffness = (2π ÷ (1.2 × visualDuration))² and damping = 2 × ζ × √stiffness (a negative bounce also rescales the frequency so the move still arrives on time). Its "at rest" thresholds depend on the move: a 0 to 1 value uses 0.005 and 0.01, a move over 5 units uses 0.5 and 2, so the rest times above are for a 0 to 1 move. For 0.4 s and bounce 0.2 that is stiffness 171.3 and damping 20.94. The bounce tail runs past it: rest after 701 ms. At 400 ms a bounce-0 spring is at 96.7%.

  4. 4

    A little bounce settles sooner than none. In the first example bounce 0.25 is at rest after 679 ms, bounce 0 after 720 ms: a critically damped spring creeps into its last pixels. Bounce 0.5 takes 819 ms.

  5. 5

    **The duration option ends on time, with a catch.** duration: 500 rests at exactly 500 ms, but duration-based springs ignore the speed of an interrupted animation. Motion's source says why: inherited velocity "causes massive oscillation on small-range animations". For gestures (9.4, 9.6) use stiffness and damping.

  6. 6

    Precedence and defaults. Give stiffness, damping or mass and the time options are ignored: { stiffness: 170, damping: 26, bounce: 0.9, duration: 300 } behaves as 170 and 26 (rest after 718 ms). With no options Motion 14.3 uses stiffness 100, damping 10, mass 1 (ζ 0.5, 16.3% overshoot, rest after 1068 ms). Read defaults from the installed package: other tables can be older.

  7. 7

    Tokens. Material 3 (since May 2025) names springs by role, such as md.sys.motion.spring.fast.spatial: spatial springs for position and size, effects springs for things like colour and opacity, each fast, default or slow, in an expressive and a standard scheme. Read its spec page for the values. Lumen will use a few named springs, not numbers scattered in the code.

Explain it without notes

01

How do bounce and visualDuration relate to stiffness and damping?

02

When would you use stiffness and damping instead of duration and bounce?

Practice

01

Mei asks for "0.3 s, a hint of bounce". Write the Motion call for an element sliding in 200 px.

02

What damping gives a spring with stiffness 171.3 a ζ of 0.8?

Done when you can

  • You can turn bounce into a damping ratio

  • You can say which option wins when physics and time are mixed

  • You can say why duration-based springs do not suit gestures