mcpField
T
threejs-impl-webgpu

threejs-impl-webgpu

github.com/impertio-studioDevelopment23134 installsUpdated 30w ago
Repository

About threejs-impl-webgpu

threejs-impl-webgpu is a WebGPU implementation reference for Three.js developers, covering WebGPURenderer, TSL, node materials, compute shaders, and post-processing. It notes that the APIs are experimental.

Key features

  1. 01Initialize WebGPURenderer and check availability
  2. 02Build node materials with TSL
  3. 03Run GPU computation with compute shaders
  4. 04Configure WebGPU post-processing
  5. 05Describe WebGL migration steps
  6. 06Outline a WebGL fallback

Use cases

  1. 01Set up WebGPU rendering for a Three.js scene
  2. 02Write materials and shading logic with TSL
  3. 03Migrate a WebGL rendering workflow to WebGPU

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/impertio-studio/three.js-claude-skill-package --skill threejs-impl-webgpu

After installing, type/threejs-impl-webgpuin Claude Code to confirm it loaded.

Bundled files

References and scripts installed along with SKILL.md.

.gitkeep
references/
anti-patterns.md
examples.md
methods.md

Details

From the project README

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
BrowserVersionStatus
Chrome113+Full support
Edge113+Full support
Safari18+Supported
FirefoxExperimentalBehind 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 MaterialNode Material
MeshBasicMaterialMeshBasicNodeMaterial
MeshStandardMaterialMeshStandardNodeMaterial
MeshPhysicalMaterialMeshPhysicalNodeMaterial
MeshPhongMaterialMeshPhongNodeMaterial
MeshLambertMaterialMeshLambertNodeMaterial
LineBasicMaterialLineBasicNodeMaterial
LineDashedMaterialLineDashedNodeMaterial
PointsMaterialPointsNodeMaterial
SpriteMaterialSpriteNodeMaterial

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):

PropertyTSL TypePurpose
.colorNodevec4Base color
.opacityNodefloatOpacity
.normalNodevec3Normal map replacement
.emissiveNodecolorEmissive output
.positionNodevec3Vertex displacement
.fragmentNodevec4Full fragment shader replacement
.vertexNodevec4Full vertex shader replacement
.outputNodevec4Final output override
.aoNodefloatAmbient occlusion
.alphaTestNodefloatAlpha test threshold
.depthNodefloatCustom depth
.castShadowNodevec4Shadow casting override

Standard/Physical inputs:

PropertyTSL TypePurpose
.metalnessNodefloatMetalness
.roughnessNodefloatRoughness
.envNodecolorEnvironment 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
CategoryFunctions
Scalarsfloat(), int(), uint(), bool()
Vectorsvec2(), vec3(), vec4(), ivec2(), ivec3(), ivec4(), uvec2(), uvec3(), uvec4()
Matricesmat2(), mat3(), mat4()
Colorcolor()
Conversion.toFloat(), .toVec3(), .toColor()
Variables and Uniforms
FunctionPurpose
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
CategoryNodes
PositionpositionGeometry, positionLocal, positionWorld, positionView, positionWorldDirection, positionViewDirection
NormalnormalGeometry, normalLocal, normalView, normalWorld
TangenttangentGeometry, tangentLocal, tangentView, tangentWorld
UVuv(index)
ScreenscreenUV, screenCoordinate, screenSize
ViewportviewportUV, viewportCoordinate, viewportSize
Camera and Model Nodes
  • Camera: cameraNear, cameraFar, cameraPosition, cameraProjectionMatrix, cameraViewMatrix, cameraWorldMatrix, cameraNormalMatrix
  • Model: modelViewMatrix, modelNormalMatrix, modelWorldMatrix, modelPosition, modelScale, modelDirection
Animation Nodes
NodePurpose
timeElapsed seconds since start
deltaTimeFrame 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
FunctionPurpose
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

StepAction
1Replace import * as THREE from 'three' with import * as THREE from 'three/webgpu'
2Replace new WebGLRenderer() with new WebGPURenderer() and add await renderer.init()
3Replace classic materials with NodeMaterial equivalents (or keep classic — they auto-convert)
4Replace EffectComposer with PostProcessing class and TSL post-processing nodes
5Replace raw GLSL ShaderMaterial with TSL-based NodeMaterial
6Replace requestAnimationFrame with renderer.setAnimationLoop()

ALWAYS make the entry point async when using WebGPURenderer — renderer.init() returns a Promise.


Reference Links

Official Sources

Comments

Markdown supported