← Back to all hooks

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) => void

Function called on each animation frame. Receives deltaTime in milliseconds since last frame.

running?: boolean

Optional. 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