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. Support still varies by GPU and driver underneath that, so before you debug a blank canvas, confirm what the device reports with the free WebGL and WebGPU checker.

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 ​