Remotion Code Analysis — spring() Physics Engine Internals
The math and code of spring() simulating damped spring differential equations in JavaScript
GitHub: remotion-dev/remotion/packages/core/src/spring
The secret behind spring()'s smooth bounce is the damped harmonic oscillator equation: m*x'' + c*x' + k*x = 0.
The discriminant D=c²-4mk determines 3 solution types: overdamped (no bounce), critically damped (fastest convergence), underdamped (bounce). The zeta ratio damping/(2*sqrt(stiffness*mass)) selects which path.
measureSpring() pre-calculates how many frames the spring animation lasts by iterating until the value is within threshold of 1.
How It Works
spring({frame, fps}) calculates time (seconds) from frame/fps
Calculate damping ratio: zeta = damping / (2 * sqrt(stiffness * mass))
If zeta < 1, underdamped: exp(-ζω₀t) * cos(ωDt) solution → bounce animation
If zeta ≥ 1, overdamped/critically damped: converges to 1 without bounce
measureSpring() finds the frame where |1-value| < 0.001 to determine durationInFrames
Pros
- ✓ Real physics: natural motion based on physics laws, not arbitrary curves like CSS ease-in-out
- ✓ Deterministic: same frame always same value, 100% reproducible as it is a math formula
- ✓ measureSpring() auto-calculates duration → determines appropriate length without hardcoding
Cons
- ✗ Mathematical understanding needed: config tuning is trial-and-error without understanding damping ratio/natural frequency