How to control fps with requestAnimationFrame?

The fps (frames per second) is crucial for animations and games, determining how many times the screen updates per second. JavaScript's requestAnimationFrame() typically runs at 60fps, but we can control this rate using different approaches.

For example, a video is a continuous sequence of images shown at short intervals. Higher fps provides smoother animations, while lower fps can create choppy effects. Understanding fps control helps optimize performance and create desired visual effects.

Using setTimeout() with requestAnimationFrame

The setTimeout() function can delay requestAnimationFrame() calls to control fps. We calculate the interval as 1000/fps milliseconds.

Syntax

setTimeout(() => {
   requestAnimationFrame(animate);
}, interval);

Example: Basic FPS Control

<html>
<body>
   <h3>Using <i>setTimeout()</i> to control fps with requestAnimationFrame</h3>
   <div id="output"></div>
   <script>
      let output = document.getElementById("output");
      let totalFrames = 0;
      let current, consumedTime;
      
      // Set fps to 3 (slow animation)
      let fps = 3;
      let intervalOffps = 1000 / fps;
      let startTime = Date.now();
      
      animate();
      
      function animate() {
         setTimeout(() => {
            requestAnimationFrame(animate);
            
            current = Date.now();
            let elapsed = current - startTime;
            
            // Calculate current fps
            let currentFps = Math.round((1000 / (elapsed / ++totalFrames)) * 100) / 100;
            
            output.innerHTML = "Elapsed time: " + Math.round((elapsed / 1000) * 100) / 100 + 
                              " seconds @ " + currentFps + " fps";
         }, intervalOffps);
      }
   </script>
</body>
</html>

Using Time Comparison Method

This approach checks if enough time has passed since the last frame before rendering. We only update when the time difference exceeds our target interval.

Syntax

let consumedTime = current - lastFrameTime;
if (consumedTime > intervalOffps) {
   // Render frame
}

Example: Time-Based FPS Control

<html>
<body>
   <h3>Using <i>Date() object</i> to control fps with requestAnimationFrame</h3>
   <div id="output"></div>
   <script>
      let output = document.getElementById("output");
      let totalFrames = 0;
      let current, consumedTime;
      
      // Set fps to 30
      let fps = 30;
      let intervalOffps = 1000 / fps;
      let lastFrameTime = Date.now();
      let startTime = lastFrameTime;
      
      animate();
      
      function animate() {
         requestAnimationFrame(animate);
         current = Date.now();
         consumedTime = current - lastFrameTime;
         
         // Only render if enough time has passed
         if (consumedTime > intervalOffps) {
            lastFrameTime = current - (consumedTime % intervalOffps);
            
            let elapsed = current - startTime;
            let currentFps = Math.round((1000 / (elapsed / ++totalFrames)) * 100) / 100;
            
            output.innerHTML = "Elapsed time: " + Math.round((elapsed / 1000) * 100) / 100 + 
                              " seconds @ " + currentFps + " fps";
         }
      }
   </script>
</body>
</html>

Example: Interactive Canvas Animation

This example demonstrates fps control with a visual canvas animation. Use the range slider to adjust fps and observe the animation speed difference.

<html>
<body>
   <h3>Interactive FPS Control with Canvas Animation</h3>
   <label>FPS: </label>
   <input type="range" min="1" max="60" value="10" id="fps">
   <button onclick="startAnimation()">Start Animation</button>
   <button onclick="stopAnimation()">Stop</button>
   <br><br>
   <canvas id="canvas" width="300" height="300" style="border:1px solid #000;"></canvas>
   
   <script>
      let canvas = document.getElementById("canvas");
      let context = canvas.getContext("2d");
      let animation;
      let intervalOffps, current, lastFrameTime, elapsed;
      let angle = 0;
      let isAnimating = false;
      
      function drawShape() {
         // Clear canvas
         context.clearRect(0, 0, canvas.width, canvas.height);
         
         context.save();
         context.translate(150, 150);
         context.rotate(Math.PI / 180 * (angle += 5));
         
         // Draw rotating rectangle
         context.fillStyle = "#007acc";
         context.fillRect(-25, -25, 50, 50);
         context.restore();
         
         // Reset angle after full rotation
         if (angle >= 360) angle = 0;
      }
      
      function animate() {
         if (!isAnimating) return;
         
         animation = requestAnimationFrame(animate);
         current = Date.now();
         elapsed = current - lastFrameTime;
         
         // Only draw if enough time has passed
         if (elapsed > intervalOffps) {
            lastFrameTime = current - (elapsed % intervalOffps);
            drawShape();
         }
      }
      
      function startAnimation() {
         if (isAnimating) stopAnimation();
         
         let fpsInput = document.getElementById("fps");
         let fps = fpsInput.value;
         
         intervalOffps = 1000 / fps;
         lastFrameTime = Date.now();
         isAnimating = true;
         
         animate();
      }
      
      function stopAnimation() {
         isAnimating = false;
         if (animation) {
            cancelAnimationFrame(animation);
         }
      }
   </script>
</body>
</html>

Comparison of Methods

Method Precision Performance Use Case
setTimeout() Good Lower Simple animations
Time Comparison High Better Smooth animations, games

Conclusion

Both methods effectively control fps with requestAnimationFrame(). The time comparison method offers better performance and precision, making it ideal for games and complex animations where smooth frame control is crucial.

Updated on: 2026-03-15T23:19:01+05:30

1K+ Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements