Spring Physics

typescript
1import { useSpring } from '@flint-ui/core'
2
3function BouncyCard({ active }: { active: boolean }) {
4 const style = useSpring({
5 to: active
6 ? { scale: 1.05, shadow: 12 }
7 : { scale: 1, shadow: 2 },
8 config: {
9 tension: 300, // stiffness
10 friction: 20, // damping
11 mass: 1, // weight feel
12 },
13 })
14
15 return (
16 <div
17 style={{
18 transform: `scale(${style.scale})`,
19 boxShadow: `0 ${style.shadow}px ${style.shadow * 2}px rgba(0,0,0,0.1)`,
20 }}
21 >
22 <Card>Hover me</Card>
23 </div>
24 )
25}
26
27// Preset spring configs
28import { springPresets } from '@flint-ui/core'
29// springPresets.gentle — { tension: 120, friction: 14 }
30// springPresets.wobbly — { tension: 180, friction: 12 }
31// springPresets.stiff — { tension: 400, friction: 30 }
32// springPresets.molasses — { tension: 60, friction: 26 }

Spring-based animations with configurable tension, friction, and mass

Overview

Spring physics create natural-feeling animations that respond to velocity and mass rather than fixed durations. Flint UI's animation utilities use spring dynamics for transitions that feel alive.

Why Springs Over Duration

CSS transitions use fixed timing functions (ease, linear, cubic-bezier). They always take the same amount of time regardless of distance. Springs adapt — a small change feels quick, a large change feels weighty.

typescript
1import { useSpring, animated } from '@flint-ui/motion'
2
3function SpringButton() {
4 const [pressed, setPressed] = useState(false)
5
6 const style = useSpring({
7 scale: pressed ? 0.95 : 1,
8 config: { tension: 300, friction: 10 }
9 })
10
11 return (
12 <animated.button
13 style={style}
14 onPointerDown={() => setPressed(true)}
15 onPointerUp={() => setPressed(false)}
16 >
17 Press me
18 </animated.button>
19 )
20}

Spring Configuration

ParameterEffectDefault
tensionStiffness — higher = snappier170
frictionDamping — higher = less bounce26
massWeight — higher = slower start1

Common Presets

typescript
1const presets = {
2 gentle: { tension: 120, friction: 14 },
3 wobbly: { tension: 180, friction: 12 },
4 stiff: { tension: 210, friction: 20 },
5 slow: { tension: 280, friction: 60 },
6 molasses: { tension: 280, friction: 120 },
7}

Reduced Motion Support

Always respect prefers-reduced-motion. Flint UI's motion utilities automatically disable springs when the user prefers reduced motion.

typescript
1const style = useSpring({
2 opacity: visible ? 1 : 0,
3 transform: visible ? 'translateY(0)' : 'translateY(20px)',
4 config: { tension: 200, friction: 20 },
5 immediate: prefersReducedMotion, // skip animation entirely
6})