threejs-impl-webgpu
EXPERIMENTAL — The WebGPU renderer and TSL are under active development.
API surfaces may change between Three.js releases. Pin your Three.js version.
Quick Reference
WebGPURenderer Setup
import * as THREE from 'three/webgpu';
const renderer = new THREE.WebGPURenderer({ antialias: true });
await renderer.init(); // MUST await before first render
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setAnimationLoop(animate);
document.body.appendChild(renderer.domElement);
ALWAYS call await renderer.init() before the first renderer.render() call.
ALWAYS use renderer.setAnimationLoop(callback) instead of requestAnimationFrame.
NEVER call renderer.render() before init() resolves — this throws a runtime error.
Browser Support
| Browser |
Version |
Status |
| Chrome |
113+ |
Full support |
| Edge |
113+ |
Full support |
| Safari |
18+ |
Supported |
| Firefox |
Experimental |
Behind flag (dom.webgpu.enabled) |
Feature Detection and Fallback
import { WebGPU } from 'three/webgpu';
if (WebGPU.isAvailable()) {
const renderer = new THREE.WebGPURenderer({ antialias: true });
await renderer.init();
} else {
const renderer = new THREE.WebGLRenderer({ antialias: true });
}
ALWAYS check WebGPU.isAvailable() before creating a WebGPURenderer.
ALWAYS provide a WebGLRenderer fallback for unsupported browsers.
Critical Warnings
NEVER write raw GLSL or WGSL strings — ALWAYS use TSL functions. WebGPU compiles TSL to WGSL automatically. GLSL is NOT supported by the WebGPU backend.
NEVER use ShaderMaterial with WebGPURenderer — use NodeMaterial with TSL instead.
NEVER use requestAnimationFrame with WebGPURenderer — ALWAYS use renderer.setAnimationLoop().
NEVER use EffectComposer (three/examples) with WebGPURenderer — use the PostProcessing class with TSL nodes instead.
Node Materials
Every classic Three.js material has a node-based equivalent. Classic materials auto-convert when used with WebGPURenderer, but node materials provide full TSL customization.
Material Mapping
| Classic Material |
Node Material |
MeshBasicMaterial |
MeshBasicNodeMaterial |
MeshStandardMaterial |
MeshStandardNodeMaterial |
MeshPhysicalMaterial |
MeshPhysicalNodeMaterial |
MeshPhongMaterial |
MeshPhongNodeMaterial |
MeshLambertMaterial |
MeshLambertNodeMaterial |
LineBasicMaterial |
LineBasicNodeMaterial |
LineDashedMaterial |
LineDashedNodeMaterial |
PointsMaterial |
PointsNodeMaterial |
SpriteMaterial |
SpriteNodeMaterial |
ALWAYS import node materials from 'three/webgpu', not from 'three'.
NodeMaterial Input Properties
All properties accept TSL node values. All are optional and override defaults.
Common inputs (all node materials):
| Property |
TSL Type |
Purpose |
.colorNode |
vec4 |
Base color |
.opacityNode |
float |
Opacity |
.normalNode |
vec3 |
Normal map replacement |
.emissiveNode |
color |
Emissive output |
.positionNode |
vec3 |
Vertex displacement |
.fragmentNode |
vec4 |
Full fragment shader replacement |
.vertexNode |
vec4 |
Full vertex shader replacement |
.outputNode |
vec4 |
Final output override |
.aoNode |
float |
Ambient occlusion |
.alphaTestNode |
float |
Alpha test threshold |
.depthNode |
float |
Custom depth |
.castShadowNode |
vec4 |
Shadow casting override |
Standard/Physical inputs:
| Property |
TSL Type |
Purpose |
.metalnessNode |
float |
Metalness |
.roughnessNode |
float |
Roughness |
.envNode |
color |
Environment map |
.lightsNode |
— |
Lighting model override |
Physical-only inputs: .clearcoatNode, .clearcoatRoughnessNode, .clearcoatNormalNode, .sheenNode, .iridescenceNode, .iridescenceIORNode, .iridescenceThicknessNode, .specularIntensityNode, .specularColorNode, .iorNode, .transmissionNode, .thicknessNode, .attenuationDistanceNode, .attenuationColorNode, .dispersionNode, .anisotropyNode.
TSL (Three Shading Language)
TSL is a JavaScript-based node graph system that compiles to GLSL (WebGL2) and WGSL (WebGPU). It replaces raw shader strings entirely.
Type System
| Category |
Functions |
| Scalars |
float(), int(), uint(), bool() |
| Vectors |
vec2(), vec3(), vec4(), ivec2(), ivec3(), ivec4(), uvec2(), uvec3(), uvec4() |
| Matrices |
mat2(), mat3(), mat4() |
| Color |
color() |
| Conversion |
.toFloat(), .toVec3(), .toColor() |
Variables and Uniforms
| Function |
Purpose |
uniform(value) |
GPU-side dynamic value |
toVar(node) |
Reusable shader variable |
toConst(node) |
Inline constant |
varying(node) |
Vertex-to-fragment interpolation |
vertexStage(node) |
Force computation in vertex shader |
attribute(name, type) |
Access buffer attributes |
Uniforms support callbacks: .onRenderUpdate(fn), .onFrameUpdate(fn), .onObjectUpdate(fn).
Operators
All operators are chainable on TSL nodes:
- Arithmetic:
.add(), .sub(), .mul(), .div(), .mod()
- Comparison:
.equal(), .notEqual(), .lessThan(), .greaterThan(), .lessThanEqual(), .greaterThanEqual()
- Logical:
.and(), .or(), .not(), .xor()
- Assignment:
.assign(), .addAssign(), .subAssign(), .mulAssign(), .divAssign()
- Bitwise:
.bitAnd(), .bitOr(), .bitXor(), .shiftLeft(), .shiftRight()
Geometry Nodes
| Category |
Nodes |
| Position |
positionGeometry, positionLocal, positionWorld, positionView, positionWorldDirection, positionViewDirection |
| Normal |
normalGeometry, normalLocal, normalView, normalWorld |
| Tangent |
tangentGeometry, tangentLocal, tangentView, tangentWorld |
| UV |
uv(index) |
| Screen |
screenUV, screenCoordinate, screenSize |
| Viewport |
viewportUV, viewportCoordinate, viewportSize |
Camera and Model Nodes
- Camera:
cameraNear, cameraFar, cameraPosition, cameraProjectionMatrix, cameraViewMatrix, cameraWorldMatrix, cameraNormalMatrix
- Model:
modelViewMatrix, modelNormalMatrix, modelWorldMatrix, modelPosition, modelScale, modelDirection
Animation Nodes
| Node |
Purpose |
time |
Elapsed seconds since start |
deltaTime |
Frame delta in seconds |
oscSine(timer) |
Sine oscillator (0-1) |
oscSquare(timer) |
Square wave oscillator |
oscTriangle(timer) |
Triangle wave oscillator |
oscSawtooth(timer) |
Sawtooth oscillator |
Texture Operations
| Function |
Purpose |
texture(tex, uv, level) |
Sample with interpolation |
textureLoad(tex, uv, level) |
Sample without interpolation |
textureStore(tex, uv, value) |
Write to storage texture |
textureSize(tex, level) |
Get texture dimensions |
cubeTexture(tex, uvw, level) |
Sample cube map |
triplanarTexture(texX, texY, texZ, scale, position, normal) |
Triplanar mapping |
Control Flow
ALWAYS use capital If — lowercase if is JavaScript, not TSL.
If(condition, () => {
// true branch
}).ElseIf(otherCondition, () => {
// else-if branch
}).Else(() => {
// false branch
});
select(condition, trueVal, falseVal) — ternary operator
Loop(count, ({ i }) => { }) — GPU loop, supports Break(), Continue()
Switch(value).Case(val, fn).Default(fn) — no fallthrough
Discard() — discard fragment
Return() — early return
Function Definition
const myFn = Fn(([param1, param2]) => {
return param1.add(param2);
});
// Call: myFn(nodeA, nodeB)
Compute Shaders
WebGPU enables general-purpose GPU compute via TSL. Compute shaders are NOT available in WebGL fallback mode.
Setup
import { compute, storage } from 'three/webgpu';
const computeNode = compute(shaderFn, count, workgroupSize);
await renderer.computeAsync(computeNode);
ALWAYS use await renderer.computeAsync() — compute dispatch is asynchronous.
Storage and Atomics
- Storage:
storage(attribute, type, count), storageTexture(texture)
- Atomics:
atomicAdd(), atomicSub(), atomicMax(), atomicMin(), atomicAnd(), atomicOr(), atomicXor(), atomicStore(), atomicLoad()
- Barriers:
workgroupBarrier(), storageBarrier(), textureBarrier()
- Built-in IDs:
workgroupId, localId, globalId, numWorkgroups, subgroupSize
WebGPU Post-Processing
NEVER use the WebGL EffectComposer with WebGPURenderer. Use the PostProcessing class instead.
import { PostProcessing } from 'three/webgpu';
import { bloom, renderOutput } from 'three/tsl';
const postProcessing = new PostProcessing(renderer);
const scenePass = renderOutput(scene, camera);
postProcessing.outputNode = bloom(scenePass);
Available Post-Processing Nodes
bloom(), dof(), fxaa(), smaa(), gaussianBlur(), ssr(), ssgi(), ao(), chromaticAberration(), film(), dotScreen(), sobel(), afterImage(), anamorphic(), denoise(), lut3D(), motionBlur(), outline(), rgbShift(), transition(), traa(), renderOutput()
Color Operations
luminance(), saturation(), vibrance(), hue(), posterize(), grayscale(), sepia()
Blend Modes
blendBurn(), blendDodge(), blendOverlay(), blendScreen(), blendColor()
WebGL to WebGPU Migration
| Step |
Action |
| 1 |
Replace import * as THREE from 'three' with import * as THREE from 'three/webgpu' |
| 2 |
Replace new WebGLRenderer() with new WebGPURenderer() and add await renderer.init() |
| 3 |
Replace classic materials with NodeMaterial equivalents (or keep classic — they auto-convert) |
| 4 |
Replace EffectComposer with PostProcessing class and TSL post-processing nodes |
| 5 |
Replace raw GLSL ShaderMaterial with TSL-based NodeMaterial |
| 6 |
Replace requestAnimationFrame with renderer.setAnimationLoop() |
ALWAYS make the entry point async when using WebGPURenderer — renderer.init() returns a Promise.
Reference Links
- references/methods.md — API signatures for WebGPURenderer, NodeMaterial, TSL, compute
- references/examples.md — Working code examples for WebGPU scenes
- references/anti-patterns.md — Common mistakes and how to avoid them
Official Sources
Source: Impertio-Studio/Three.js-Claude-Skill-Package — distributed by TomeVault.
1---2name: impertio-studio-three-js-claude-skill-package-threejs-impl-w3description: threejs-impl-webgpu4---56# threejs-impl-webgpu78> **EXPERIMENTAL** — The WebGPU renderer and TSL are under active development.9> API surfaces may change between Three.js releases. Pin your Three.js version.1011## Quick Reference1213### WebGPURenderer Setup1415```javascript16import * as THREE from 'three/webgpu';1718const renderer = new THREE.WebGPURenderer({ antialias: true });19await renderer.init(); // MUST await before first render20renderer.setSize(window.innerWidth, window.innerHeight);21renderer.setAnimationLoop(animate);22document.body.appendChild(renderer.domElement);23```2425**ALWAYS** call `await renderer.init()` before the first `renderer.render()` call.26**ALWAYS** use `renderer.setAnimationLoop(callback)` instead of `requestAnimationFrame`.27**NEVER** call `renderer.render()` before `init()` resolves — this throws a runtime error.2829### Browser Support3031| Browser | Version | Status |32|---------|---------|--------|33| Chrome | 113+ | Full support |34| Edge | 113+ | Full support |35| Safari | 18+ | Supported |36| Firefox | Experimental | Behind flag (`dom.webgpu.enabled`) |3738### Feature Detection and Fallback3940```javascript41import { WebGPU } from 'three/webgpu';4243if (WebGPU.isAvailable()) {44 const renderer = new THREE.WebGPURenderer({ antialias: true });45 await renderer.init();46} else {47 const renderer = new THREE.WebGLRenderer({ antialias: true });48}49```5051**ALWAYS** check `WebGPU.isAvailable()` before creating a WebGPURenderer.52**ALWAYS** provide a WebGLRenderer fallback for unsupported browsers.5354### Critical Warnings5556**NEVER** write raw GLSL or WGSL strings — ALWAYS use TSL functions. WebGPU compiles TSL to WGSL automatically. GLSL is NOT supported by the WebGPU backend.5758**NEVER** use `ShaderMaterial` with WebGPURenderer — use `NodeMaterial` with TSL instead.5960**NEVER** use `requestAnimationFrame` with WebGPURenderer — ALWAYS use `renderer.setAnimationLoop()`.6162**NEVER** use `EffectComposer` (three/examples) with WebGPURenderer — use the `PostProcessing` class with TSL nodes instead.6364---6566## Node Materials6768Every classic Three.js material has a node-based equivalent. Classic materials auto-convert when used with WebGPURenderer, but node materials provide full TSL customization.6970### Material Mapping7172| Classic Material | Node Material |73|-----------------|---------------|74| `MeshBasicMaterial` | `MeshBasicNodeMaterial` |75| `MeshStandardMaterial` | `MeshStandardNodeMaterial` |76| `MeshPhysicalMaterial` | `MeshPhysicalNodeMaterial` |77| `MeshPhongMaterial` | `MeshPhongNodeMaterial` |78| `MeshLambertMaterial` | `MeshLambertNodeMaterial` |79| `LineBasicMaterial` | `LineBasicNodeMaterial` |80| `LineDashedMaterial` | `LineDashedNodeMaterial` |81| `PointsMaterial` | `PointsNodeMaterial` |82| `SpriteMaterial` | `SpriteNodeMaterial` |8384**ALWAYS** import node materials from `'three/webgpu'`, not from `'three'`.8586### NodeMaterial Input Properties8788All properties accept TSL node values. All are optional and override defaults.8990**Common inputs (all node materials):**9192| Property | TSL Type | Purpose |93|----------|----------|---------|94| `.colorNode` | `vec4` | Base color |95| `.opacityNode` | `float` | Opacity |96| `.normalNode` | `vec3` | Normal map replacement |97| `.emissiveNode` | `color` | Emissive output |98| `.positionNode` | `vec3` | Vertex displacement |99| `.fragmentNode` | `vec4` | Full fragment shader replacement |100| `.vertexNode` | `vec4` | Full vertex shader replacement |101| `.outputNode` | `vec4` | Final output override |102| `.aoNode` | `float` | Ambient occlusion |103| `.alphaTestNode` | `float` | Alpha test threshold |104| `.depthNode` | `float` | Custom depth |105| `.castShadowNode` | `vec4` | Shadow casting override |106107**Standard/Physical inputs:**108109| Property | TSL Type | Purpose |110|----------|----------|---------|111| `.metalnessNode` | `float` | Metalness |112| `.roughnessNode` | `float` | Roughness |113| `.envNode` | `color` | Environment map |114| `.lightsNode` | — | Lighting model override |115116**Physical-only inputs:** `.clearcoatNode`, `.clearcoatRoughnessNode`, `.clearcoatNormalNode`, `.sheenNode`, `.iridescenceNode`, `.iridescenceIORNode`, `.iridescenceThicknessNode`, `.specularIntensityNode`, `.specularColorNode`, `.iorNode`, `.transmissionNode`, `.thicknessNode`, `.attenuationDistanceNode`, `.attenuationColorNode`, `.dispersionNode`, `.anisotropyNode`.117118---119120## TSL (Three Shading Language)121122TSL is a JavaScript-based node graph system that compiles to GLSL (WebGL2) and WGSL (WebGPU). It replaces raw shader strings entirely.123124### Type System125126| Category | Functions |127|----------|-----------|128| Scalars | `float()`, `int()`, `uint()`, `bool()` |129| Vectors | `vec2()`, `vec3()`, `vec4()`, `ivec2()`, `ivec3()`, `ivec4()`, `uvec2()`, `uvec3()`, `uvec4()` |130| Matrices | `mat2()`, `mat3()`, `mat4()` |131| Color | `color()` |132| Conversion | `.toFloat()`, `.toVec3()`, `.toColor()` |133134### Variables and Uniforms135136| Function | Purpose |137|----------|---------|138| `uniform(value)` | GPU-side dynamic value |139| `toVar(node)` | Reusable shader variable |140| `toConst(node)` | Inline constant |141| `varying(node)` | Vertex-to-fragment interpolation |142| `vertexStage(node)` | Force computation in vertex shader |143| `attribute(name, type)` | Access buffer attributes |144145Uniforms support callbacks: `.onRenderUpdate(fn)`, `.onFrameUpdate(fn)`, `.onObjectUpdate(fn)`.146147### Operators148149All operators are chainable on TSL nodes:150151- **Arithmetic:** `.add()`, `.sub()`, `.mul()`, `.div()`, `.mod()`152- **Comparison:** `.equal()`, `.notEqual()`, `.lessThan()`, `.greaterThan()`, `.lessThanEqual()`, `.greaterThanEqual()`153- **Logical:** `.and()`, `.or()`, `.not()`, `.xor()`154- **Assignment:** `.assign()`, `.addAssign()`, `.subAssign()`, `.mulAssign()`, `.divAssign()`155- **Bitwise:** `.bitAnd()`, `.bitOr()`, `.bitXor()`, `.shiftLeft()`, `.shiftRight()`156157### Geometry Nodes158159| Category | Nodes |160|----------|-------|161| Position | `positionGeometry`, `positionLocal`, `positionWorld`, `positionView`, `positionWorldDirection`, `positionViewDirection` |162| Normal | `normalGeometry`, `normalLocal`, `normalView`, `normalWorld` |163| Tangent | `tangentGeometry`, `tangentLocal`, `tangentView`, `tangentWorld` |164| UV | `uv(index)` |165| Screen | `screenUV`, `screenCoordinate`, `screenSize` |166| Viewport | `viewportUV`, `viewportCoordinate`, `viewportSize` |167168### Camera and Model Nodes169170- **Camera:** `cameraNear`, `cameraFar`, `cameraPosition`, `cameraProjectionMatrix`, `cameraViewMatrix`, `cameraWorldMatrix`, `cameraNormalMatrix`171- **Model:** `modelViewMatrix`, `modelNormalMatrix`, `modelWorldMatrix`, `modelPosition`, `modelScale`, `modelDirection`172173### Animation Nodes174175| Node | Purpose |176|------|---------|177| `time` | Elapsed seconds since start |178| `deltaTime` | Frame delta in seconds |179| `oscSine(timer)` | Sine oscillator (0-1) |180| `oscSquare(timer)` | Square wave oscillator |181| `oscTriangle(timer)` | Triangle wave oscillator |182| `oscSawtooth(timer)` | Sawtooth oscillator |183184### Texture Operations185186| Function | Purpose |187|----------|---------|188| `texture(tex, uv, level)` | Sample with interpolation |189| `textureLoad(tex, uv, level)` | Sample without interpolation |190| `textureStore(tex, uv, value)` | Write to storage texture |191| `textureSize(tex, level)` | Get texture dimensions |192| `cubeTexture(tex, uvw, level)` | Sample cube map |193| `triplanarTexture(texX, texY, texZ, scale, position, normal)` | Triplanar mapping |194195### Control Flow196197**ALWAYS** use capital `If` — lowercase `if` is JavaScript, not TSL.198199```javascript200If(condition, () => {201 // true branch202}).ElseIf(otherCondition, () => {203 // else-if branch204}).Else(() => {205 // false branch206});207```208209- `select(condition, trueVal, falseVal)` — ternary operator210- `Loop(count, ({ i }) => { })` — GPU loop, supports `Break()`, `Continue()`211- `Switch(value).Case(val, fn).Default(fn)` — no fallthrough212- `Discard()` — discard fragment213- `Return()` — early return214215### Function Definition216217```javascript218const myFn = Fn(([param1, param2]) => {219 return param1.add(param2);220});221// Call: myFn(nodeA, nodeB)222```223224---225226## Compute Shaders227228WebGPU enables general-purpose GPU compute via TSL. Compute shaders are NOT available in WebGL fallback mode.229230### Setup231232```javascript233import { compute, storage } from 'three/webgpu';234235const computeNode = compute(shaderFn, count, workgroupSize);236await renderer.computeAsync(computeNode);237```238239**ALWAYS** use `await renderer.computeAsync()` — compute dispatch is asynchronous.240241### Storage and Atomics242243- **Storage:** `storage(attribute, type, count)`, `storageTexture(texture)`244- **Atomics:** `atomicAdd()`, `atomicSub()`, `atomicMax()`, `atomicMin()`, `atomicAnd()`, `atomicOr()`, `atomicXor()`, `atomicStore()`, `atomicLoad()`245- **Barriers:** `workgroupBarrier()`, `storageBarrier()`, `textureBarrier()`246- **Built-in IDs:** `workgroupId`, `localId`, `globalId`, `numWorkgroups`, `subgroupSize`247248---249250## WebGPU Post-Processing251252**NEVER** use the WebGL `EffectComposer` with WebGPURenderer. Use the `PostProcessing` class instead.253254```javascript255import { PostProcessing } from 'three/webgpu';256import { bloom, renderOutput } from 'three/tsl';257258const postProcessing = new PostProcessing(renderer);259const scenePass = renderOutput(scene, camera);260postProcessing.outputNode = bloom(scenePass);261```262263### Available Post-Processing Nodes264265`bloom()`, `dof()`, `fxaa()`, `smaa()`, `gaussianBlur()`, `ssr()`, `ssgi()`, `ao()`, `chromaticAberration()`, `film()`, `dotScreen()`, `sobel()`, `afterImage()`, `anamorphic()`, `denoise()`, `lut3D()`, `motionBlur()`, `outline()`, `rgbShift()`, `transition()`, `traa()`, `renderOutput()`266267### Color Operations268269`luminance()`, `saturation()`, `vibrance()`, `hue()`, `posterize()`, `grayscale()`, `sepia()`270271### Blend Modes272273`blendBurn()`, `blendDodge()`, `blendOverlay()`, `blendScreen()`, `blendColor()`274275---276277## WebGL to WebGPU Migration278279| Step | Action |280|------|--------|281| 1 | Replace `import * as THREE from 'three'` with `import * as THREE from 'three/webgpu'` |282| 2 | Replace `new WebGLRenderer()` with `new WebGPURenderer()` and add `await renderer.init()` |283| 3 | Replace classic materials with NodeMaterial equivalents (or keep classic — they auto-convert) |284| 4 | Replace `EffectComposer` with `PostProcessing` class and TSL post-processing nodes |285| 5 | Replace raw GLSL `ShaderMaterial` with TSL-based `NodeMaterial` |286| 6 | Replace `requestAnimationFrame` with `renderer.setAnimationLoop()` |287288**ALWAYS** make the entry point `async` when using WebGPURenderer — `renderer.init()` returns a Promise.289290---291292## Reference Links293294- [references/methods.md](references/methods.md) — API signatures for WebGPURenderer, NodeMaterial, TSL, compute295- [references/examples.md](references/examples.md) — Working code examples for WebGPU scenes296- [references/anti-patterns.md](references/anti-patterns.md) — Common mistakes and how to avoid them297298### Official Sources299300- https://threejs.org/docs/301- https://github.com/mrdoob/three.js/wiki/Three.js-Shading-Language302- https://threejs.org/examples/?q=webgpu303304---305> Source: [Impertio-Studio/Three.js-Claude-Skill-Package](https://github.com/Impertio-Studio/Three.js-Claude-Skill-Package) — distributed by [TomeVault](https://tomevault.io).306<!-- tomevault:4.0:skill_md:2026-05-28 -->