Three.js r160 — WebGPU Renderer, TSL Node Materials & Migration Guide

Three.js r160 is the most significant release in years: the WebGPU renderer graduates to beta, the TSL (Three.js Shading Language) node material system replaces raw GLSL for author-facing material customisation, and several long-standing WebGL quirks get cleaned up. Here's what changed and how to migrate.

Quick Change Summary

Area Change Type
Renderer WebGPURenderer stable beta — polyfill covers WebGL2 fallback new
Materials TSL NodeMaterial API replaces onBeforeCompile for custom shaders new
Materials MeshPhysicalMaterial adds dispersion and iridescence properties improved
Lights RectAreaLight LTC lookup tables updated for better energy conservation improved
Loaders GLTFLoader drops legacy KHR_materials_pbrSpecularGlossiness support breaking
Maths Vector3.applyQuaternion is now 8% faster via optimised formula improved
Geometry BufferGeometry.computeBoundingSphere now handles morph targets correctly improved

1. WebGPU Renderer (Beta)

WebGPURenderer is now the default import from three/webgpu. It automatically falls back to WebGL2 on browsers that don't support WebGPU, so you can adopt it today without gating:

// r160+ — import from the new entry point
import * as THREE from 'three/webgpu';

const renderer = new THREE.WebGPURenderer({ antialias: true });
await renderer.init();    // ← new: must await async init
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

The await renderer.init() step is new and easy to miss. Without it the renderer's GPU device isn't ready and your first draw call will silently produce nothing. Wrap your scene setup in an async function and await init before adding any objects.

2. TSL — Three.js Shading Language

Previously, customising a Three.js material's GLSL required the opaque onBeforeCompile callback — fragile string injection into shader source. TSL replaces this with a composable JavaScript API that generates GLSL or WGSL from a node graph:

import { MeshPhysicalNodeMaterial, texture, uv, vec4, mix } from 'three/nodes';

const mat = new MeshPhysicalNodeMaterial();

// Replace the diffuse colour node with a procedural mixture
const baseColor = vec4(0.2, 0.5, 1.0, 1.0);
const noiseColor = texture(noiseMap, uv().mul(4.0));
mat.colorNode = mix(baseColor, noiseColor, 0.6);

// Works with both WebGL2 and WebGPU renderers —
// TSL compiles to GLSL or WGSL as needed

Key TSL Node types

3. MeshPhysicalMaterial New Properties

const glass = new THREE.MeshPhysicalMaterial({
  transmission: 1,
  roughness: 0,
  thickness: 0.5,
  ior: 1.5,

  // NEW in r160:
  dispersion: 5,           // chromatic aberration (0 = none, 10 = max)
  iridescence: 0.8,        // thin-film iridescence strength
  iridescenceIOR: 1.3,
  iridescenceThicknessRange: [100, 400],   // [min, max] nm
});

4. Breaking: GLTFLoader PBR Specular-Glossiness

The legacy KHR_materials_pbrSpecularGlossiness extension support has been removed from the core GLTFLoader. If you load GLTF files that rely on this extension (common in older assets from Sketchfab), you must now use the explicit extension plugin:

// r160+ migration for specular-glossiness GLTF assets
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { RGBELoader } from 'three/addons/loaders/RGBELoader.js';
// No longer needed — extension removed:
// import { KHR_materials_pbrSpecularGlossiness } from 'three/addons/';

// If you need it, install the separate community package:
// npm install three-gltf-extensions
import { KHRM_specularGlossiness } from 'three-gltf-extensions';
const loader = new GLTFLoader();
loader.register(parser => new KHRM_specularGlossiness(parser));