Impact: HIGH - Creates natural, organic motion instead of mechanical animations
This skill covers using Remotion’s spring() function to create physics-based animations that feel organic and alive, rather than robotic and linear.
Prefer spring() Over interpolate()
Use spring() for natural motion, interpolate() only for linear progress.
Incorrect (mechanical motion)
Correct (organic spring motion)
const scale = interpolate ( frame , [ 0 , 30 ], [ 0 , 1 ], {
extrapolateRight: "clamp" ,
});
Springs create subtle overshoot and settling that makes animations feel more natural and less “computed”. This small detail makes a huge difference in perceived quality.
Spring Config Parameters
spring ({
frame ,
fps ,
config: {
damping: 10 , // Higher = less bounce (10-200)
stiffness: 100 , // Higher = faster snap (50-200)
mass: 1 , // Higher = more inertia (0.5-3)
},
});
Controls how quickly the spring settles.
Low (8-12): Bouncy, playful, overshoots significantly
Medium (15-20): Balanced, subtle bounce
High (100-200): Smooth, minimal overshoot
damping : 12 // Playful bounce
damping : 200 // Almost no bounce
Controls how quickly the spring accelerates.
Low (50-80): Slow, gentle acceleration
Medium (100-150): Balanced snap
High (170-200): Fast, snappy motion
stiffness : 80 // Gentle
stiffness : 200 // Snappy
Controls the “weight” of the animated object.
Low (0.5-1): Light, responsive
Medium (1-1.5): Natural weight
High (2-3): Heavy, sluggish
mass : 0.5 // Light object
mass : 2 // Heavy object
Common Spring Presets
// Snappy, minimal bounce (UI elements)
const snappy = { damping: 20 , stiffness: 200 };
// Bouncy entrance (playful animations)
const bouncy = { damping: 8 , stiffness: 100 };
// Smooth, no bounce (subtle reveals)
const smooth = { damping: 200 , stiffness: 100 };
// Heavy, slow (large objects)
const heavy = { damping: 15 , stiffness: 80 , mass: 2 };
Snappy
Bouncy
Smooth
Heavy
config : { damping : 20 , stiffness : 200 }
Best for: UI elements, buttons, toggles, quick interactionsFast and responsive with minimal overshoot. config : { damping : 8 , stiffness : 100 }
Best for: Playful animations, attention-grabbing elements, celebrationsSignificant overshoot creates energetic feeling. config : { damping : 200 , stiffness : 100 }
Best for: Subtle reveals, professional content, elegant transitionsAlmost no bounce, smooth deceleration. config : { damping : 15 , stiffness : 80 , mass : 2 }
Best for: Large objects, weighty elements, dramatic entrancesSlow to start and stop, feels substantial.
Delayed Spring Start
Offset the frame for delayed spring animations:
Incorrect (spring starts immediately)
Correct (spring starts after delay)
const entrance = spring ({ frame , fps , config: { damping: 12 } });
When frame - ENTRANCE_DELAY is negative, spring() automatically returns 0. This makes delayed starts very simple.
Spring for Scale with Overshoot
For bouncy scale animations that overshoot:
const bounce = spring ({
frame ,
fps ,
config: { damping: 8 , stiffness: 150 },
});
// Will overshoot past 1.0 before settling
< div style = { { transform: `scale( ${ bounce } )` } } > { content } </ div > ;
Low damping (8-12) creates overshoot above 1.0. Be aware that elements may temporarily grow larger than their final size.
Combining Spring with Interpolate
Map spring output (0-1) to custom ranges:
const springProgress = spring ({ frame , fps , config: { damping: 15 } });
// Map to rotation
const rotation = interpolate ( springProgress , [ 0 , 1 ], [ 0 , 360 ]);
// Map to position
const translateY = interpolate ( springProgress , [ 0 , 1 ], [ 50 , 0 ]);
< div style = { { transform: `translateY( ${ translateY } px) rotate( ${ rotation } deg)` } } >
This pattern is powerful: use spring for the timing/easing, then map its output to whatever range you need.
Chained Springs for Sequential Motion
const PHASE_1_END = 30 ;
const PHASE_2_START = 25 ; // Slight overlap
const phase1 = spring ({ frame , fps , config: { damping: 15 } });
const phase2 = spring ({
frame: frame - PHASE_2_START ,
fps ,
config: { damping: 12 },
});
// phase1 controls entrance, phase2 controls secondary motion
Starting phase 2 before phase 1 completes creates fluid, continuous motion rather than start-stop-start animation.
Key Patterns
Choose Spring Config
Match the config to the desired feel:
Playful: Low damping (8-12)
Professional: Medium damping (15-20)
Elegant: High damping (100-200)
Delay with Frame Offset
spring ({ frame: frame - delay , fps })
Automatically handles negative values.
Map to Custom Range
const s = spring ({ frame , fps });
const custom = interpolate ( s , [ 0 , 1 ], [ start , end ]);
Spring vs Interpolate Decision Tree
Common Mistakes to Avoid
Don’t use interpolate for organic animations - Linear motion looks robotic. Use spring() instead.
Don’t use extreme config values - Damping over 300 or under 5 creates unnatural motion.
Don’t forget to delay springs - For staggered animations, offset the frame: frame - delay
Don’t mix presets inconsistently - Stick to one “feel” throughout a video (all bouncy OR all smooth).
Visualizing Spring Behavior
Sequencing Delay spring animations
Charts Use springs in bar animations
Messaging Bounce chat bubbles