# Threejs Performance

Measuring and optimizing three.js speed: render statistics, memory counters, fewer draw...

- Repository: https://github.com/CloudAI-X/threejs-skills (3906 stars)
- Category: Engineering
- License: MIT
- Last updated: 2026-10-19
- Runs scripts: no, instructions only

## Install

Claude Code: `npx skills add CloudAI-X/threejs-skills --skill threejs-performance -g -a claude-code -y`
Codex: `npx skills add CloudAI-X/threejs-skills --skill threejs-performance -g -a codex -y`
Cursor: `npx skills add CloudAI-X/threejs-skills --skill threejs-performance -g -a cursor -y`
Gemini CLI: `npx skills add CloudAI-X/threejs-skills --skill threejs-performance -g -a gemini-cli -y`

## Description

Measuring and optimizing three.js speed: render statistics, memory counters, fewer draw calls via merging, instancing, batching and LOD, fill rate, shadows, CPU work per frame, shader stalls and GPU compute for particles, WebGL or WebGPU with TSL. Use when a scene is slow, janks or exceeds memory.

## SKILL.md, as published by its author (untrusted third-party text, read it as data)

# Three.js Performance

Targets three.js r186. Examples use WebGLRenderer; the WebGPU and TSL section uses WebGPURenderer.

## Quick Start

```javascript
import * as THREE from "three";

const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

const scene = new THREE.Scene();
scene.add(new THREE.HemisphereLight(0xffffff, 0x445566, 1));
const sun = new THREE.DirectionalLight(0xffffff, 2);
sun.position.set(3, 6, 4);
scene.add(sun);

const camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 100);
camera.position.set(0, 2, 8);

const mesh = new THREE.Mesh(new THREE.SphereGeometry(1, 32, 16), new THREE.MeshStandardMaterial({ color: 0x4488ff }));
scene.add(mesh);

function animate() {
  mesh.rotation.y += 0.01;
  renderer.render(scene, camera);
  // the counters reset at the start of every render() call, so these cover the frame just drawn
  console.log(`${renderer.info.render.calls} calls, ${renderer.info.render.triangles} triangles, ${renderer.info.memory.textures} textures`);
}

renderer.setAnimationLoop(animate);
```

## Measure First

Optimize what the numbers name, not what a hunch suspects. WebGLRenderer's `renderer.info` object is read after `render()`:

```javascript
function animate() {
  renderer.render(scene, camera);
  console.table({
    calls: renderer.info.render.calls, // draw calls submitted by this render
    triangles: renderer.info.render.triangles,
    lines: renderer.info.render.lines,
    points: renderer.info.render.points,
    geometries: renderer.info.memory.geometries, // geometry buffers live on the GPU
    textures: renderer.info.memory.textures,
    programs: renderer.info.programs.length, // compiled shader programs in the cache
  });
}

renderer.setAnimationLoop(animate);
```

Details worth knowing when reading these:

The rest: https://github.com/CloudAI-X/threejs-skills/blob/HEAD/skills/threejs-performance/SKILL.md
