vaweGitHub

SpringsJetpack Compose

Compose HighBouncy with StiffnessMediumLow

DampingRatioHighBouncy, 0.2, is the lowest damping ratio constant in the Spring object. Stiffness 400, damping 8 and mass 1 give a damping ratio of 0.2, so the spring is underdamped. It settles to within 0.1% in 1.655 s. It passes the end value by up to 52.7% at 0.16 s and crosses it 10 times.

Demo

Progress against time. The time axis runs 0 to 1.655 s, the settle time.0100.51progress50%90%
Dashed: a straight line. The dot and the line move with the box on the right.
Compose HighBouncy with StiffnessMediumLow
linear

Both boxes take 1.655 s. This is real time.

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 (1655 ms) and a linear() string that follows the spring.

css linear()
transition: translate 1655ms linear(0, 0.0093, 0.0365, 0.0799, 0.1381, 0.209, 0.2908, 0.3812, 0.4783, 0.5798, 0.6836, 0.7876, 0.89, 0.989, 1.0828, 1.1701, 1.2495, 1.3201, 1.381, 1.4315, 1.4714, 1.5004, 1.5186, 1.5263, 1.5238, 1.5118, 1.491, 1.4622, 1.4264, 1.3847, 1.3381, 1.2877, 1.2348, 1.1803, 1.1254, 1.0712, 1.0185, 0.9684, 0.9215, 0.8786, 0.8402, 0.8068, 0.7788, 0.7564, 0.7397, 0.7287, 0.7233, 0.7233, 0.7284, 0.7383, 0.7525, 0.7704, 0.7917, 0.8157, 0.8417, 0.8693, 0.8979, 0.9268, 0.9555, 0.9834, 1.0102, 1.0354, 1.0585, 1.0794, 1.0976, 1.1131, 1.1256, 1.1352, 1.1417, 1.1453, 1.146, 1.1439, 1.1393, 1.1324, 1.1234, 1.1126, 1.1003, 1.0868, 1.0725, 1.0575, 1.0423, 1.0272, 1.0123, 0.998, 0.9846, 0.9721, 0.9608, 0.9509, 0.9423, 0.9353, 0.9299, 0.9261, 0.9238, 0.9231, 0.9238, 0.9259, 0.9293, 0.9337, 0.9392, 0.9455, 0.9524, 0.9599, 0.9677, 0.9757, 0.9837, 0.9916, 0.9992, 1.0064, 1.0131, 1.0192, 1.0246, 1.0293, 1.0332, 1.0363, 1.0385, 1.0399, 1.0405, 1.0403, 1.0394, 1.0378, 1.0355, 1.0328, 1.0296, 1.026, 1.0221, 1.018, 1.0138, 1.0096, 1.0055, 1.0014, 0.9975, 0.9939, 0.9906, 0.9877, 0.9851, 0.983, 0.9813, 0.98, 0.9791, 0.9787, 0.9787, 0.9791, 0.9799, 0.981, 0.9824, 0.984, 0.9858, 0.9878, 0.99, 0.9922, 0.9944, 0.9966, 0.9987, 1.0008, 1.0027, 1.0045, 1.0061, 1.0075, 1.0087, 1.0097, 1.0104, 1.0109, 1.0112, 1.0112, 1.0111, 1.0107, 1.0102, 1.0095, 1.0087, 1.0077, 1.0067, 1.0056, 1.0044, 1.0033, 1.0021, 1.0009, 0.9998, 0.9988, 0.9978, 0.997, 0.9962, 0.9956, 0.995, 0.9946, 0.9943, 0.9941, 0.9941, 0.9941, 0.9943, 0.9946, 0.9949, 0.9953, 0.9958, 0.9963, 0.9969, 0.9975, 0.9981, 0.9988, 0.9994, 0.9999, 1.0005, 1.001, 1.0015, 1.0019, 1.0023, 1.0026, 1.0028, 1.003, 1.0031, 1.0031, 1.0031, 1.003, 1.0029, 1.0027, 1.0025, 1.0023, 1.002, 1.0017, 1.0014, 1.0011, 1.0007, 1.0004, 1.0001, 0.9998, 0.9995, 0.9993, 0.9991, 0.9989, 0.9987, 0.9986, 0.9985, 0.9984, 0.9984, 0.9984, 0.9984, 0.9985, 0.9985, 0.9986, 0.9988, 0.9989, 1);
web animations api
el.animate({ translate: ['0 0', '240px 0'] }, { duration: 1655, easing: 'linear(0, 0.0093, 0.0365, 0.0799, 0.1381, 0.209, 0.2908, 0.3812, 0.4783, 0.5798, 0.6836, 0.7876, 0.89, 0.989, 1.0828, 1.1701, 1.2495, 1.3201, 1.381, 1.4315, 1.4714, 1.5004, 1.5186, 1.5263, 1.5238, 1.5118, 1.491, 1.4622, 1.4264, 1.3847, 1.3381, 1.2877, 1.2348, 1.1803, 1.1254, 1.0712, 1.0185, 0.9684, 0.9215, 0.8786, 0.8402, 0.8068, 0.7788, 0.7564, 0.7397, 0.7287, 0.7233, 0.7233, 0.7284, 0.7383, 0.7525, 0.7704, 0.7917, 0.8157, 0.8417, 0.8693, 0.8979, 0.9268, 0.9555, 0.9834, 1.0102, 1.0354, 1.0585, 1.0794, 1.0976, 1.1131, 1.1256, 1.1352, 1.1417, 1.1453, 1.146, 1.1439, 1.1393, 1.1324, 1.1234, 1.1126, 1.1003, 1.0868, 1.0725, 1.0575, 1.0423, 1.0272, 1.0123, 0.998, 0.9846, 0.9721, 0.9608, 0.9509, 0.9423, 0.9353, 0.9299, 0.9261, 0.9238, 0.9231, 0.9238, 0.9259, 0.9293, 0.9337, 0.9392, 0.9455, 0.9524, 0.9599, 0.9677, 0.9757, 0.9837, 0.9916, 0.9992, 1.0064, 1.0131, 1.0192, 1.0246, 1.0293, 1.0332, 1.0363, 1.0385, 1.0399, 1.0405, 1.0403, 1.0394, 1.0378, 1.0355, 1.0328, 1.0296, 1.026, 1.0221, 1.018, 1.0138, 1.0096, 1.0055, 1.0014, 0.9975, 0.9939, 0.9906, 0.9877, 0.9851, 0.983, 0.9813, 0.98, 0.9791, 0.9787, 0.9787, 0.9791, 0.9799, 0.981, 0.9824, 0.984, 0.9858, 0.9878, 0.99, 0.9922, 0.9944, 0.9966, 0.9987, 1.0008, 1.0027, 1.0045, 1.0061, 1.0075, 1.0087, 1.0097, 1.0104, 1.0109, 1.0112, 1.0112, 1.0111, 1.0107, 1.0102, 1.0095, 1.0087, 1.0077, 1.0067, 1.0056, 1.0044, 1.0033, 1.0021, 1.0009, 0.9998, 0.9988, 0.9978, 0.997, 0.9962, 0.9956, 0.995, 0.9946, 0.9943, 0.9941, 0.9941, 0.9941, 0.9943, 0.9946, 0.9949, 0.9953, 0.9958, 0.9963, 0.9969, 0.9975, 0.9981, 0.9988, 0.9994, 0.9999, 1.0005, 1.001, 1.0015, 1.0019, 1.0023, 1.0026, 1.0028, 1.003, 1.0031, 1.0031, 1.0031, 1.003, 1.0029, 1.0027, 1.0025, 1.0023, 1.002, 1.0017, 1.0014, 1.0011, 1.0007, 1.0004, 1.0001, 0.9998, 0.9995, 0.9993, 0.9991, 0.9989, 0.9987, 0.9986, 0.9985, 0.9984, 0.9984, 0.9984, 0.9984, 0.9985, 0.9985, 0.9986, 0.9988, 0.9989, 1)', fill: 'both' });
vawe
import { spring, springDuration, springLinear } from '../../core/motion/springs.js';

const k = 400, d = 8;

// 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: 1655 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
400k, with mass 1
Damping
8d, with mass 1
Damping ratio
0.2underdamped
Settle time
1.655 swithin 0.1% of the end
Overshoot
52.7%peak at 0.16 s
Crosses the end
10times
50% of travel
0.057 s3% of the settle time
90% of travel
0.084 s5% of the settle time
Natural frequency
20 rad/ssqrt(k)
Ring period
0.321 sone swing of the overshoot
Peak speed
24.81xtimes the average speed
linear() points
241within 0.23% 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

Jetpack Composeandroidx main at 9adbcd8 (compose animation-core 1.14.0-alpha01)
spring(dampingRatio = Spring.DampingRatioHighBouncy (0.2), stiffness = Spring.StiffnessMediumLow (400))Spring.DampingRatioHighBouncy, Spring.StiffnessMediumLow

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.

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.

More springs