| name | framer-advanced-physics |
| description | This skill should be used when the user needs to tune spring physics for a specific feel, or wants to understand and configure Framer Motion spring parameters. Trigger when the user mentions "spring animation", "stiffness and damping", "Framer Motion spring", "iOS spring feel", "feels too bouncy", "feels too stiff", "feels too slow", "no overshoot", "spring preset", "mass and damping", "inertia animation", "drag spring", "motion values", "useSpring hook", or asks how to replicate the feel of native iOS or Android springs. Also trigger when the user says an animation "doesn't settle right", "oscillates too much", or wants a "snappier" or "smoother" spring. |
Framer Motion Advanced Physics
Spring physics is notoriously difficult to tune from scratch. The stiffness/damping/mass parameter space is three-dimensional, and different products have different physical personalities. This skill provides a systematic way to identify the right preset, understand how parameters interact, and generate production-ready spring configurations.
Understanding Spring Parameters
Spring motion is governed by a damped harmonic oscillator:
F = -kx - cv
k (stiffness) — how aggressively the spring pulls toward rest. High = snappy.
c (damping) — how fast energy is absorbed. High = settles quickly, no bounce.
m (mass) — how much resistance to acceleration. High = heavy, slow to start and stop.
velocity — initial velocity (inherited from gesture or set manually). Non-zero velocity creates momentum continuity.
Critical damping is the threshold where the spring returns in the shortest time without oscillating. Apple uses slightly underdamped springs (a touch of overshoot) for personality, but very close to critical.
Parameter effect guide:
| Parameter | Low value | High value |
|---|
stiffness | Slow, floaty, lazy | Snappy, immediate, tight |
damping | Oscillates, visible bounce | Settles fast, restrained |
mass | Light, fast response | Heavy, deliberate |
velocity | Starts from rest | Continues gesture momentum |
Spring Personality Presets
iOS System UI — stiffness: 400, damping: 40
{ type: "spring", stiffness: 400, damping: 40 }
Near-critically-damped. Crisp, precise, barely any overshoot. This is the signature of hardware-quality system UI. Use for: sheet presentations, drawers, context menus, tooltips.
When to deviate: Scale stiffness and damping proportionally to maintain the personality at different speeds. stiffness: 600, damping: 55 is faster but equally precise.
Snappy Utility — stiffness: 500, damping: 50
{ type: "spring", stiffness: 500, damping: 50 }
Fastest settle, zero overshoot. Use for: utility components, developer tools, anything where speed matters more than feel.
Framer Default — stiffness: 100, damping: 10
{ type: "spring", stiffness: 100, damping: 10 }
Gentle, slight bounce. Framer Motion's built-in default. Soft and approachable. Use for: consumer apps, social products, anything warm and friendly.
Playful Consumer — stiffness: 200, damping: 15
{ type: "spring", stiffness: 200, damping: 15 }
Visible bounce, expressive, energetic. Use for: like animations, badge appearances, success moments, gamification. Do not use for navigation — the oscillation would be distracting.
Heavy Modal — stiffness: 280, damping: 60
{ type: "spring", stiffness: 280, damping: 60 }
Weighted and authoritative. Settles firmly with minimal bounce. Use for: full-screen modals, confirmation dialogs, anything that should feel structural.
Elastic / Back — stiffness: 300, damping: 20
{ type: "spring", stiffness: 300, damping: 20 }
Pronounced overshoot, settles with personality. Use for: tooltip appears from trigger, notification badge, button confirms. Keep displacement small — large movements with elastic springs look broken.
Common Framer Motion Spring Patterns
useSpring — continuously follows a changing value:
import { useSpring, useMotionValue, motion } from "framer-motion";
function SpringFollower() {
const mouseX = useMotionValue(0);
const mouseY = useMotionValue(0);
const springX = useSpring(mouseX, { stiffness: 300, damping: 30 });
const springY = useSpring(mouseY, { stiffness: 300, damping: 30 });
return (
<motion.div
style={{ x: springX, y: springY }}
onMouseMove={(e) => {
mouseX.set(e.clientX);
mouseY.set(e.clientY);
}}
/>
);
}
Layout animation with spring:
<motion.div
layout
transition={{ type: "spring", stiffness: 400, damping: 40 }}
>
{}
</motion.div>
Gesture-driven spring with velocity continuity:
animate(x, 0, {
type: "spring",
stiffness: 500,
damping: 50,
velocity: info.velocity.x,
});
inertia — scroll-like deceleration:
animate(x, 0, {
type: "inertia",
velocity: info.velocity.x,
bounceStiffness: 400,
bounceDamping: 40,
power: 0.8,
timeConstant: 700,
});
Diagnostic: When the Spring Feels Wrong
| Problem | Likely cause | Fix |
|---|
| Too bouncy / oscillates too long | Damping too low | Increase damping |
| Settles too slowly, feels sluggish | Stiffness too low | Increase stiffness, reduce mass |
| Snaps too abruptly, not smooth | Stiffness too high | Reduce stiffness, or add small mass |
| Continues after gesture, feels un-tied | Missing velocity in animate() | Pass gesture info.velocity to spring |
| Overshoot is too large | Damping too low relative to stiffness | Increase damping until satisfied |
| "Pops" at start, no acceleration | Very low initial stiffness | Increase base stiffness (>= 200) |
Additional Resources
references/spring-presets.md — Extended preset catalog, side-by-side comparisons for mobile vs. desktop contexts, React Native spring configs, CSS linear() spring approximations, and a parameter calculator guide