SwiftUI .bouncy
Its base bounce of 0.3 gives a damping fraction of 0.7. Stiffness 157.91, damping 17.59 and mass 1 give a damping ratio of 0.7, so the spring is underdamped. It settles to within 0.1% in 0.82 s. It passes the end value by up to 4.6% at 0.35 s and crosses it 2 times.
Demo
Both boxes take 0.82 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 (820 ms) and a linear() string that follows the spring.
transition: translate 820ms linear(0, 0.0078, 0.0294, 0.0621, 0.1036, 0.1519, 0.2051, 0.2615, 0.3198, 0.3789, 0.4376, 0.4951, 0.5508, 0.6041, 0.6547, 0.7021, 0.7462, 0.7869, 0.8241, 0.8578, 0.8881, 0.9152, 0.939, 0.9598, 0.9779, 0.9932, 1.0062, 1.0169, 1.0256, 1.0324, 1.0377, 1.0415, 1.044, 1.0455, 1.046, 1.0458, 1.0449, 1.0434, 1.0416, 1.0394, 1.037, 1.0344, 1.0317, 1.029, 1.0263, 1.0236, 1.0211, 1.0186, 1.0162, 1.014, 1.012, 1.0101, 1.0083, 1.0068, 1.0053, 1.0041, 1.003, 1.002, 1.0011, 1.0004, 0.9998, 0.9993, 0.9989, 0.9985, 0.9983, 0.9981, 0.998, 0.9979, 0.9979, 0.9979, 0.9979, 0.998, 0.9981, 0.9982, 0.9983, 0.9984, 0.9985, 0.9986, 0.9988, 0.9989, 1);el.animate({ translate: ['0 0', '240px 0'] }, { duration: 820, easing: 'linear(0, 0.0078, 0.0294, 0.0621, 0.1036, 0.1519, 0.2051, 0.2615, 0.3198, 0.3789, 0.4376, 0.4951, 0.5508, 0.6041, 0.6547, 0.7021, 0.7462, 0.7869, 0.8241, 0.8578, 0.8881, 0.9152, 0.939, 0.9598, 0.9779, 0.9932, 1.0062, 1.0169, 1.0256, 1.0324, 1.0377, 1.0415, 1.044, 1.0455, 1.046, 1.0458, 1.0449, 1.0434, 1.0416, 1.0394, 1.037, 1.0344, 1.0317, 1.029, 1.0263, 1.0236, 1.0211, 1.0186, 1.0162, 1.014, 1.012, 1.0101, 1.0083, 1.0068, 1.0053, 1.0041, 1.003, 1.002, 1.0011, 1.0004, 0.9998, 0.9993, 0.9989, 0.9985, 0.9983, 0.9981, 0.998, 0.9979, 0.9979, 0.9979, 0.9979, 0.998, 0.9981, 0.9982, 0.9983, 0.9984, 0.9985, 0.9986, 0.9988, 0.9989, 1)', fill: 'both' });import { spring, springDuration, springLinear } from '../../core/motion/springs.js';
const k = 157.91, d = 17.59;
// 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: 820 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
- 157.91k, with mass 1
- Damping
- 17.59d, with mass 1
- Damping ratio
- 0.7underdamped
- Settle time
- 0.82 swithin 0.1% of the end
- Overshoot
- 4.6%peak at 0.35 s
- Crosses the end
- 2times
- 50% of travel
- 0.114 s14% of the settle time
- 90% of travel
- 0.21 s26% of the settle time
- Natural frequency
- 12.57 rad/ssqrt(k)
- Ring period
- 0.7 sone swing of the overshoot
- Peak speed
- 4.73xtimes the average speed
- linear() points
- 81within 0.19% 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
| SwiftUI | SwiftUI documentation read on 2026-11-03 |
| .bouncy: duration 0.5, base bounce 0.3 (Apple: "higher amount of bounce") | Animation.bouncy(duration:extraBounce:) |
Read it at developer.apple.com/documentation/swiftui/animation/bouncy(duration:extrabounce:).
Conversion: stiffness = (2 pi / response)^2, damping = 4 pi x dampingFraction / response, with mass 1. The duration-and-bounce forms map to response = duration and dampingFraction = 1 - bounce, the same bounce mapping Motion documents "as SwiftUI does". Apple states bounce 0 is critically damped and bounce 1 is undamped.
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.