Material 3 Expressive slow spatial
It has the same damping ratio as the default spatial spring (0.8). Only the stiffness is lower, 200 against 380. Stiffness 200, damping 22.63 and mass 1 give a damping ratio of 0.8, so the spring is underdamped. It settles to within 0.1% in 0.6 s. It passes the end value by up to 1.5% at 0.37 s and crosses it 1 time.
Demo
Both boxes take 0.6 s. Playing at 0.5× speed.
Your system asks for reduced motion, so nothing plays. The chart shows the whole move.
Code
A spring has no fixed duration, so the CSS takes the settle time (600 ms) and a linear() string that follows the spring.
transition: translate 600ms linear(0, 0.0053, 0.0201, 0.0427, 0.0716, 0.1057, 0.1436, 0.1845, 0.2275, 0.2717, 0.3166, 0.3615, 0.406, 0.4497, 0.4922, 0.5334, 0.573, 0.6108, 0.6467, 0.6807, 0.7126, 0.7426, 0.7705, 0.7965, 0.8205, 0.8426, 0.8629, 0.8814, 0.8983, 0.9135, 0.9273, 0.9397, 0.9508, 0.9607, 0.9694, 0.9771, 0.9838, 0.9896, 0.9947, 0.999, 1.0026, 1.0057, 1.0082, 1.0102, 1.0118, 1.0131, 1.014, 1.0146, 1.015, 1.0151, 1.0151, 1.0149, 1.0146, 1.0142, 1.0137, 1.0132, 1.0126, 1.0119, 1.0113, 1.0106, 1.0099, 1.0092, 1.0086, 1.0079, 1.0073, 1.0067, 1.0061, 1.0056, 1.005, 1.0045, 1.0041, 1.0036, 1.0032, 1.0029, 1.0025, 1.0022, 1.0019, 1.0016, 1.0014, 1.0012, 1);el.animate({ translate: ['0 0', '240px 0'] }, { duration: 600, easing: 'linear(0, 0.0053, 0.0201, 0.0427, 0.0716, 0.1057, 0.1436, 0.1845, 0.2275, 0.2717, 0.3166, 0.3615, 0.406, 0.4497, 0.4922, 0.5334, 0.573, 0.6108, 0.6467, 0.6807, 0.7126, 0.7426, 0.7705, 0.7965, 0.8205, 0.8426, 0.8629, 0.8814, 0.8983, 0.9135, 0.9273, 0.9397, 0.9508, 0.9607, 0.9694, 0.9771, 0.9838, 0.9896, 0.9947, 0.999, 1.0026, 1.0057, 1.0082, 1.0102, 1.0118, 1.0131, 1.014, 1.0146, 1.015, 1.0151, 1.0151, 1.0149, 1.0146, 1.0142, 1.0137, 1.0132, 1.0126, 1.0119, 1.0113, 1.0106, 1.0099, 1.0092, 1.0086, 1.0079, 1.0073, 1.0067, 1.0061, 1.0056, 1.005, 1.0045, 1.0041, 1.0036, 1.0032, 1.0029, 1.0025, 1.0022, 1.0019, 1.0016, 1.0014, 1.0012, 1)', fill: 'both' });import { spring, springDuration, springLinear } from '../../core/motion/springs.js';
const k = 200, d = 22.63;
// per-frame code (window.seek, vawe.onFrame): t is seconds since the move starts
const x = 240 * spring(t, k, d);
// CSS and Web Animations: 600 ms, the linear() string above
el.animate(
{ translate: ['0 0', '240px 0'] },
{ duration: springDuration(k, d) * 1000, easing: springLinear(k, d), fill: 'both' },
);Numbers
- Stiffness
- 200k, with mass 1
- Damping
- 22.63d, with mass 1
- Damping ratio
- 0.8underdamped
- Settle time
- 0.6 swithin 0.1% of the end
- Overshoot
- 1.5%peak at 0.37 s
- Crosses the end
- 1time
- 50% of travel
- 0.107 s18% of the settle time
- 90% of travel
- 0.211 s35% of the settle time
- Natural frequency
- 14.14 rad/ssqrt(k)
- Ring period
- 0.741 sone swing of the overshoot
- Peak speed
- 3.59xtimes the average speed
- linear() points
- 81within 0.13% of travel
Computed with spring() and springDuration() from core/motion/springs.js. The settle time is the last moment the spring is more than 0.1% away from the end value; a library stops its own spring by its own rest thresholds, so its clock can run shorter.
Source of the numbers
| Material 3 | androidx main at 9adbcd8 (compose material3 1.6.0-alpha01) |
| damping ratio 0.8, stiffness 200 (MotionScheme.expressive().slowSpatialSpec()) | ExpressiveMotionTokens.SpringSlowSpatialDamping (0.8) and SpringSlowSpatialStiffness (200) |
Conversion: Stiffness is used as it is with mass 1 (SpringSimulation takes the natural frequency as sqrt(stiffness)). damping = 2 x dampingRatio x sqrt(stiffness), the same c = 2 x naturalFreq x dampingRatio that SpringSimulation.getAcceleration uses.
Related springs
The four closest curves in this set, by the average gap between the two springs over their first seconds. A gap of 0.01 is invisible; 0.1 is a different feel.