Monitor Three.js Performance with stats.js

Maintaining a smooth 60 frames per second (FPS) is crucial for WebGL applications. This article provides a direct, step-by-step guide on how to integrate the popular utility library stats.js into your Three.js project. You will learn how to initialize the performance monitor, display default panels like framerate and render time, and create a custom panel to track real-time WebGL draw calls directly from the Three.js renderer.

Step 1: Install and Import stats.js

First, add stats.js to your project. If you are using a package manager like npm, install it using the following command:

npm install stats.js

Next, import the library into your JavaScript or TypeScript file alongside Three.js:

import * as THREE from 'three';
import Stats from 'stats.js';

(If you are not using a bundler, you can include it via a CDN link like https://cdnjs.cloudflare.com/ajax/libs/stats.js/r17/Stats.min.js using a standard <script> tag).

Step 2: Initialize Stats and Add it to the DOM

Create an instance of Stats, configure which panel to show by default, and append its DOM element to your document container.

// Initialize Stats
const stats = new Stats();

// Choose default panel: 0: fps, 1: ms, 2: mb, 3+: custom
stats.showPanel(0); 

// Position the panel in the top-left corner
stats.dom.style.position = 'absolute';
stats.dom.style.left = '0px';
stats.dom.style.top = '0px';

document.body.appendChild(stats.dom);

Step 3: Monitor Framerate in the Animation Loop

To track your framerate (FPS) and render time (MS), you must update the stats object inside your active requestAnimationFrame loop. You can do this by wrapping your rendering logic with stats.begin() and stats.end().

function animate() {
    // Start tracking performance for this frame
    stats.begin();

    // Your Three.js rendering logic
    cube.rotation.x += 0.01;
    cube.rotation.y += 0.01;
    renderer.render(scene, camera);

    // End tracking and update the panel
    stats.end();

    requestAnimationFrame(animate);
}

requestAnimationFrame(animate);

Step 4: Monitor Draw Calls with a Custom Panel

While stats.js tracks FPS and render times natively, Three.js developers also need to monitor draw calls to prevent CPU bottlenecks. You can query the current draw calls using renderer.info.render.calls and display them inside a custom stats.js panel.

Here is how to set up a custom panel specifically for draw calls:

// 1. Create a custom panel: (Label, Foreground Color, Background Color)
const drawCallsPanel = new Stats.Panel('Draws', '#ff8', '#221');
stats.addPanel(drawCallsPanel);

// Show the custom panel (index 3, since 0, 1, and 2 are pre-defined)
stats.showPanel(3); 

function animate() {
    stats.begin();

    // Render your Three.js scene
    renderer.render(scene, camera);

    // 2. Query Three.js renderer info and update the custom panel
    // The second parameter is the estimated maximum value for the graph scale
    drawCallsPanel.update(renderer.info.render.calls, 200); 

    stats.end();
    requestAnimationFrame(animate);
}

By implementing this setup, you gain an instantaneous, visual representation of both your rendering speed (framerate) and your scene complexity (draw calls), allowing you to optimize your Three.js application efficiently.