Skip to content

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

AspectWebGLWebGPU
API styleOpenGL-like, statefulModern, explicit
ShadersGLSLWGSL
ComputeLimited (extensions)First-class support
Multi-threadingDifficultDesigned for it
Browser supportUniversalAll 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

External Resources