| name | frontend-rive |
| description | State-driven interactive animations with built-in state machines. Use when animations must REACT to user input (hover, click, drag), have multiple states/transitions, or respond to data values (progress bars, counters). Ideal for animated buttons, toggles, checkboxes, characters. For simple play/loop animations use Lottie instead. |
| allowed-tools | Read, Edit, Write, Bash (*) |
Rive
Interactive animations with built-in state machines. Animation logic inside the .riv file.
When to Use
- Animations that REACT to input (hover, click, data)
- Animated buttons, toggles, checkboxes
- Progress indicators driven by values
- Multi-state characters/icons
- Complex state transitions
When NOT to Use
- Simple decorative loops โ Lottie
- Static illustrations โ SVG
- Quick spinners โ CSS/Lottie
Key Concept: State Machines
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Rive State Machine โ
โ โโโโโโโโ hover โโโโโโโโโ โ
โ โ Idle โ โโโโโโโบ โ Hover โ โ
โ โโโโโโโโ โโโโโโโโโ โ
โ โฒ click โ โ
โ โโโโโโโโโโโโโ โโโโ โ
โ โ
โ Inputs: hover (bool), click โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
You control inputs โ Rive handles animations
Process
SETUP โ CONNECT โ CONTROL
- Install:
npm install @rive-app/react-canvas
- Load .riv file with state machine
- Get inputs via
useStateMachineInput
- Connect to UI events
Quick Start
import { useRive, useStateMachineInput } from '@rive-app/react-canvas';
function InteractiveButton() {
const { rive, RiveComponent } = useRive({
src: '/button.riv',
stateMachines: 'ButtonState',
autoplay: true,
});
const hover = useStateMachineInput(rive, 'ButtonState', 'hover');
const press = useStateMachineInput(rive, 'ButtonState', 'pressed');
return (
<RiveComponent
onMouseEnter={() => hover && (hover.value = true)}
onMouseLeave={() => hover && (hover.value = false)}
onMouseDown={() => press && (press.value = true)}
onMouseUp={() => press && (press.value = false)}
/>
);
}
Input Types
Boolean: input.value = true/false
Number: input.value = 75
Trigger: input.fire()
Common Patterns
Toggle:
- Boolean input "isOn"
- onClick: toggle value
Progress:
- Number input "progress" (0-100)
- useEffect: sync with prop
Notification Bell:
- Number input "count"
- Trigger input "ring"
- onClick: fire() trigger
Decision: Rive vs Lottie
| Need | Use |
|---|
| Just plays/loops | Lottie |
| Reacts to hover | Rive |
| Controlled by data | Rive |
| Multiple states | Rive |
| Simple loader | Lottie |
Layout & Sizing
<div className="w-64 h-64">
<RiveComponent />
</div>
<div className="w-full aspect-video max-w-2xl">
<RiveComponent />
</div>
SSR & Hydration
'use client'
const Animation = dynamic(() => import('./RiveAnimation'), { ssr: false })
const [mounted, setMounted] = useState(false)
useEffect(() => setMounted(true), [])
if (!mounted) return <Skeleton />
Performance
const Rive = dynamic(() => import('./RiveComponent'), { ssr: false })
const { ref, inView } = useInView()
useEffect(() => { inView ? rive?.play() : rive?.pause() }, [inView])
Troubleshooting
"Animation not playing":
โ Check autoplay: true
โ Check stateMachines name (case-sensitive)
โ Check .riv path in public/
"Inputs undefined":
โ Always check: if (input) input.value = x
โ Verify input names match Rive editor
"Hydration mismatch":
โ Add 'use client'
โ Use dynamic(() => ..., { ssr: false })
"Wrong size":
โ Container needs explicit width/height
โ Use aspect-ratio utilities
References
- patterns.md โ Toggle, Checkbox, Progress, Like button, Form integration
External Resources