WebGPU getting started for game developers
WebGPU is the successor to WebGL. It's lower-level, more explicit, and designed for modern GPUs. If you're starting a new 3D project in 2026, WebGPU is worth learning.
WebGPU Tutorial: 10 projects covering setup through 3D rendering with lighting and animation
1) Check browser support
js
if (!navigator.gpu) {
console.error('WebGPU not supported')
}As of 2026, WebGPU is available in Chrome, Edge, Firefox, and Safari.
2) Get a device
js
const adapter = await navigator.gpu.requestAdapter()
const device = await adapter.requestDevice()The adapter represents the physical GPU. The device is your interface to it.
Both calls can fail. requestAdapter() returns null when the system has no usable GPU, and requestDevice() can reject, so guard against that before continuing:
js
const adapter = await navigator.gpu.requestAdapter()
if (!adapter) throw new Error('No suitable GPU adapter found')
const device = await adapter.requestDevice()The adapter is also consumed once you create a device from it, so request a fresh adapter if you need another device.
3) Configure the canvas
js
const canvas = document.getElementById('game')
const context = canvas.getContext('webgpu')
const format = navigator.gpu.getPreferredCanvasFormat()
context.configure({
device,
format,
alphaMode: 'premultiplied',
})4) Write shaders in WGSL
WebGPU uses WGSL (WebGPU Shading Language), not GLSL.
wgsl
@vertex
fn vs_main(@builtin(vertex_index) idx: u32) -> @builtin(position) vec4f {
var pos = array<vec2f, 3>(
vec2f( 0.0, 0.5),
vec2f(-0.5, -0.5),
vec2f( 0.5, -0.5),
);
return vec4f(pos[idx], 0.0, 1.0);
}
@fragment
fn fs_main() -> @location(0) vec4f {
return vec4f(1.0, 0.5, 0.2, 1.0); // orange
}5) Create a shader module
js
const shaderModule = device.createShaderModule({
code: wgslSource,
})6) Create a render pipeline
js
const pipeline = device.createRenderPipeline({
layout: 'auto',
vertex: {
module: shaderModule,
entryPoint: 'vs_main',
},
fragment: {
module: shaderModule,
entryPoint: 'fs_main',
targets: [{ format }],
},
})7) Render a frame
js
function render() {
const commandEncoder = device.createCommandEncoder()
const textureView = context.getCurrentTexture().createView()
const renderPass = commandEncoder.beginRenderPass({
colorAttachments: [{
view: textureView,
clearValue: { r: 0, g: 0, b: 0, a: 1 },
loadOp: 'clear',
storeOp: 'store',
}],
})
renderPass.setPipeline(pipeline)
renderPass.draw(3)
renderPass.end()
device.queue.submit([commandEncoder.finish()])
requestAnimationFrame(render)
}
render()8) Buffers in WebGPU
js
const vertices = new Float32Array([
-0.5, -0.5,
0.5, -0.5,
0.0, 0.5,
])
const vertexBuffer = device.createBuffer({
size: vertices.byteLength,
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
})
device.queue.writeBuffer(vertexBuffer, 0, vertices)9) Bind groups for uniforms
js
const uniformBuffer = device.createBuffer({
size: 64,
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
})
const bindGroup = device.createBindGroup({
layout: pipeline.getBindGroupLayout(0),
entries: [{
binding: 0,
resource: { buffer: uniformBuffer },
}],
})10) WebGPU vs WebGL
| Aspect | WebGL | WebGPU |
|---|---|---|
| API style | OpenGL-like, stateful | Modern, explicit |
| Shaders | GLSL | WGSL |
| Compute | Limited (extensions) | First-class support |
| Multi-threading | Difficult | Designed for it |
| Browser support | Universal | All major browsers (Chrome, Edge, Safari 26, Firefox) |
When to use WebGPU
- New projects targeting modern browsers
- Compute-heavy workloads (physics, AI, procedural gen)
- When you need fine-grained control over GPU resources
Related
- WebGL fundamentals
- Web Workers for game logic
- Ship a web game that loads fast
- Web Games Tech Stack in 2026 — decision framework for WebGL vs WebGPU vs Wasm
- COOP/COEP and SharedArrayBuffer — required headers for Wasm threading with WebGPU compute
External Resources
- WebGPU specification — W3C spec
- WGSL specification — WebGPU Shading Language spec
- WebGPU Fundamentals — in-depth tutorial series
- Your first WebGPU app — Google Codelab walkthrough