How to Implement Spring Animations with Framer Motion: A Complete Guide
Use the useSpring hook from Framer Motion to transform raw input values into physics-based motion with configurable mass, stiffness, and damping parameters.
To implement spring animations with Framer Motion effectively, the emilkowalski/skills repository provides a comprehensive reference architecture centered on the useSpring hook. This approach replaces static easing curves with simulated physics, creating UI elements that feel natural and responsive to user interactions.
Why Use Spring Animations?
Spring-based animations simulate real-world physics instead of following predetermined curves, giving interfaces an "alive" quality that static transitions cannot match.
Momentum and Interruptibility
Springs retain velocity when animations are interrupted, allowing gestures like drag, hover, or tap to reverse or change direction smoothly. According to the source code in skills/emil-design-eng/SKILL.md, this is the primary advantage over CSS keyframes, which always restart from zero when interrupted.
Decorative Interactions
For mouse-tracking effects and decorative UI elements, springs add subtle bounce and damping that makes motion feel purposeful rather than artificial. The repository emphasizes this pattern for creating premium-feeling interactions without complex manual calculations.
Configurable Physics Parameters
Framer Motion exposes the underlying physics through intuitive configuration options. The emilkowalski/skills repository documents two primary approaches:
- Apple-style preset:
{ type: "spring", duration: 0.5, bounce: 0.2 }for standard UI springs - Full physics model:
{ type: "spring", mass: 1, stiffness: 100, damping: 10 }for fine-tuned control
The useSpring Hook Architecture
The recommended architectural pattern from skills/emil-design-eng/SKILL.md follows four distinct steps:
- Read raw input from events or state (e.g.,
mouseXposition) - Create a spring value using
useSpring(rawValue, config) - Apply the spring to motion props or inline styles (
style={{ rotate: springValue }}) - Customize physics through
stiffness,damping,mass, orbounceparameters
This declarative pattern keeps components focused on UI logic while Framer Motion handles the physics simulation internally.
Implementation Examples
Basic Mouse Rotation with useSpring
This example from the repository demonstrates tracking mouse position with spring-physics interpolation:
import { useSpring, motion } from 'framer-motion';
import { useState } from 'react';
function RotatingBox() {
const [mouseX, setMouseX] = useState(0);
// Spring-interpolated value with physics configuration
const springRotation = useSpring(mouseX * 0.1, {
stiffness: 100,
damping: 10,
});
return (
<div
onMouseMove={e => setMouseX(e.clientX)}
style={{ width: 200, height: 200, background: '#61dafb' }}
>
<motion.div
style={{
width: '100%',
height: '100%',
rotate: springRotation,
originX: 0.5,
originY: 0.5,
}}
/>
</div>
);
}
The springRotation value smoothly follows the mouse coordinates with configurable resistance, defined in skills/emil-design-eng/SKILL.md.
Drag-to-Dismiss Interactions
For gesture-based dismissal patterns, combine useSpring with Framer Motion's drag handlers:
import { motion, useSpring } from 'framer-motion';
import { useState } from 'react';
function DismissableCard() {
const [dragX, setDragX] = useState(0);
const springX = useSpring(dragX, {
type: 'spring',
mass: 0.8,
stiffness: 120,
damping: 12,
});
return (
<motion.div
drag="x"
dragConstraints={{ left: 0, right: 0 }}
onDrag={(e, info) => setDragX(info.point.x)}
style={{ x: springX, width: 300, height: 150, background: '#fff' }}
/>
);
}
This pattern ensures the card maintains momentum when released, creating a tactile feel that static animations cannot replicate.
Reusable Spring Hook Utility
For consistent physics across components, extract the pattern into a custom hook:
import { useSpring } from 'framer-motion';
import { useEffect, useState } from 'react';
export function useResponsiveSpring(
value: number,
config = { stiffness: 100, damping: 10 }
) {
const spring = useSpring(value, config);
const [current, setCurrent] = useState(value);
useEffect(() => {
setCurrent(value);
}, [value]);
return spring;
}
Usage: const ySpring = useResponsiveSpring(scrollY, { stiffness: 80, damping: 15 });
Configuration Presets and Physics Parameters
The emilkowalski/skills repository recommends specific configurations for different interaction types:
- Standard UI springs: Use the Apple-style preset with
durationandbouncefor predictable, polished motion - Physics-heavy interactions: Specify
mass,stiffness, anddampingdirectly when you need precise control over weight and resistance
As documented in skills/review-animations/STANDARDS.md, the design rule "interpolate with useSpring for mouse interactions" should guide architectural decisions when implementing tracking effects.
Summary
- Use
useSpringfrom Framer Motion to implement physics-based animations that feel natural and responsive - Reference
skills/emil-design-eng/SKILL.mdfor the core guide on spring implementation and configuration presets - Leverage interruptibility by using springs for gestures, as springs maintain velocity when interrupted unlike CSS keyframes
- Choose between presets: Use the Apple-style
{ type: "spring", duration: 0.5, bounce: 0.2 }for standard UI, or full physics parameters for custom feel - Apply the 4-step pattern: Read input → Create spring → Apply to styles → Customize physics
Frequently Asked Questions
What is the difference between useSpring and animate props in Framer Motion?
The useSpring hook creates a reactive motion value that continuously interpolates toward its target using physics simulation, while the animate prop applies discrete animations to properties. Use useSpring when you need continuous tracking of changing values (like mouse position), and animate for state-based transitions between discrete values.
When should I use springs instead of CSS transitions?
Use springs when you need interruptibility and momentum preservation during user interactions. According to the repository's analysis in skills/emil-design-eng/SKILL.md, CSS transitions and keyframes always restart from zero when interrupted, creating jarring experiences during drag or hover gestures. Springs maintain velocity and direction changes smoothly.
How do I choose the right stiffness and damping values?
Stiffness controls the spring's tension (higher values = faster movement), while damping controls friction (higher values = quicker settling). The repository recommends starting with { stiffness: 100, damping: 10 } and adjusting: increase stiffness for snappier response, increase damping to reduce oscillation. For most UI elements, the Apple-style preset { type: "spring", duration: 0.5, bounce: 0.2 } provides balanced defaults.
Can useSpring handle interruptible animations during user gestures?
Yes, this is the primary advantage of the useSpring hook. As implemented in the emilkowalski/skills source code, springs retain velocity when interrupted, allowing drag gestures to reverse direction or change target values smoothly without resetting to zero. This creates the "alive" feel characteristic of high-quality interactive interfaces.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →