useAnimationFrame
Create smooth 60fps animations using requestAnimationFrame. Perfect for games, visualizations, and interactive UI elements.
Live Demo
Watch the animated box move and rotate smoothly. Try pausing and resuming the animation.
📊 Animation Stats
FPS:0
Frames:0
Position X:0px
Rotation:0°
🎮 Controls
🟢 Running
💡 How It Works:
- Uses requestAnimationFrame for smooth 60fps animations
- Provides deltaTime for frame-rate independent movement
- Automatically cleans up on unmount
- Can be paused/resumed without memory leaks
Code Examples
Basic Animation
import { useAnimationFrame } from "@uiblock/hooks";
import { useState } from "react";
export default function BouncingBall() {
const [position, setPosition] = useState({ x: 0, y: 0 });
const [velocity, setVelocity] = useState({ x: 2, y: 2 });
useAnimationFrame((deltaTime) => {
setPosition(prev => {
let newX = prev.x + velocity.x;
let newY = prev.y + velocity.y;
// Bounce off walls
if (newX > 300 || newX < 0) {
setVelocity(v => ({ ...v, x: -v.x }));
}
if (newY > 300 || newY < 0) {
setVelocity(v => ({ ...v, y: -v.y }));
}
return { x: newX, y: newY };
});
});
return (
<div style={{ position: 'relative', width: 300, height: 300 }}>
<div
style={{
position: 'absolute',
left: position.x,
top: position.y,
width: 20,
height: 20,
borderRadius: '50%',
background: 'blue'
}}
/>
</div>
);
}Pausable Animation
import { useAnimationFrame } from "@uiblock/hooks";
import { useState } from "react";
export default function PausableAnimation() {
const [rotation, setRotation] = useState(0);
const [running, setRunning] = useState(true);
useAnimationFrame((deltaTime) => {
setRotation(prev => (prev + 0.1 * deltaTime) % 360);
}, running);
return (
<div>
<div style={{ transform: `rotate(${rotation}deg)` }}>
🎨
</div>
<button onClick={() => setRunning(!running)}>
{running ? 'Pause' : 'Play'}
</button>
</div>
);
}Frame-Rate Independent Movement
import { useAnimationFrame } from "@uiblock/hooks";
import { useState } from "react";
export default function SmoothMovement() {
const [x, setX] = useState(0);
// Speed in pixels per second
const speed = 100;
useAnimationFrame((deltaTime) => {
// deltaTime is in milliseconds
const deltaSeconds = deltaTime / 1000;
setX(prev => (prev + speed * deltaSeconds) % 500);
});
return (
<div style={{ transform: `translateX(${x}px)` }}>
Moving at constant speed regardless of FPS
</div>
);
}How It Works
Here's the implementation:
import { useEffect, useRef } from 'react'
export function useAnimationFrame(
callback: (deltaTime: number) => void,
running: boolean = true
) {
const requestRef = useRef<number>()
const previousTimeRef = useRef<number>()
const callbackRef = useRef(callback)
// Update callback ref
useEffect(() => {
callbackRef.current = callback
}, [callback])
useEffect(() => {
if (!running) {
if (requestRef.current) {
cancelAnimationFrame(requestRef.current)
}
return
}
const animate = (time: number) => {
if (previousTimeRef.current !== undefined) {
const deltaTime = time - previousTimeRef.current
callbackRef.current(deltaTime)
}
previousTimeRef.current = time
requestRef.current = requestAnimationFrame(animate)
}
requestRef.current = requestAnimationFrame(animate)
return () => {
if (requestRef.current) {
cancelAnimationFrame(requestRef.current)
}
}
}, [running])
}Key Features:
- Provides deltaTime for frame-rate independent animations
- Automatically cancels animation frame on unmount
- Can be paused/resumed with the running parameter
- Uses refs to avoid recreating animation loop
API Reference
Parameters
callback: (deltaTime: number) => voidFunction called on each animation frame. Receives deltaTime in milliseconds since last frame.
running?: booleanOptional. Controls whether animation is running. Defaults to true.
Returns
void - The hook manages the animation loop internally
💡 Use Cases
- Game loops and physics simulations
- Smooth UI animations and transitions
- Canvas-based visualizations
- Particle systems and effects
- Progress indicators and loaders
- Interactive data visualizations
- Scroll-based animations
- Real-time charts and graphs