Configuring a GPUCanvasContext

canvas.getContext('webgpu') returns a context that does nothing until configure() binds it to a device:

The canonical configuration, with every default spelled outJavaScript
context.configure({ device, format: navigator.gpu.getPreferredCanvasFormat(),
  usage: GPUTextureUsage.RENDER_ATTACHMENT, viewFormats: [], colorSpace: 'srgb',
  toneMapping: { mode: 'standard' }, alphaMode: 'opaque' });

Only device and format are required. Each frame, getCurrentTexture() returns the texture to draw into, sized to the canvas's width and height. On this machine it threw InvalidStateError before configure(), returned a 300x150 bgra8unorm texture with usage 16 for a default canvas, returned the same object when called twice in one task and a new one after the next animation frame. So call it inside each frame, never once at startup. You never present explicitly: the browser composites the texture after your task ends. configure() again replaces the configuration; unconfigure() releases the textures.

Two canvases configured with alphaMode 'opaque' and 'premultiplied' over a checkerboard, with what getCurrentTexture() returnsHTMLLive
<!doctype html>
<style>
  body { margin: 0; background: #f7f4ee; font: 13px system-ui, sans-serif; color: #222; }
  .row { display: flex; gap: 12px; max-width: 600px; padding: 8px; box-sizing: border-box; }
  .row div { flex: 1; }
  canvas { display: block; width: 100%; aspect-ratio: 3 / 2; border-radius: 8px;
           background: repeating-conic-gradient(#d9d4ca 0 25%, #fff 0 50%) 0 0 / 24px 24px; }
  pre { margin: 4px 8px; font: 12px ui-monospace, monospace; max-width: 584px; white-space: pre-wrap; }
</style>
<div class="row">
  <div><canvas id="opaque" width="288" height="192"></canvas><b>alphaMode: 'opaque'</b></div>
  <div><canvas id="premul" width="288" height="192"></canvas><b>alphaMode: 'premultiplied'</b></div>
</div>
<pre id="info"></pre>
<script>
function showMessage(text) {                     // 2D fallback when WebGPU is missing
  const c = document.getElementById('opaque'), ctx = c.getContext('2d');
  ctx.fillStyle = '#fbeaea'; ctx.fillRect(0, 0, c.width, c.height);
  ctx.fillStyle = '#8a2b2b'; ctx.font = '15px system-ui, sans-serif'; ctx.textAlign = 'center';
  ctx.fillText(text, c.width / 2, c.height / 2);
}

const code = /* wgsl */ `
@vertex fn vs(@builtin(vertex_index) v: u32) -> @builtin(position) vec4f {
  let p = array(vec2f(-1, -1), vec2f(3, -1), vec2f(-1, 3))[v];
  return vec4f(p, 0, 1);
}
@fragment fn fs(@builtin(position) pos: vec4f) -> @location(0) vec4f {
  let d = length(pos.xy - vec2f(144, 96)) / 80;         // a soft blue disc...
  let alpha = clamp(1.2 - d, 0, 1) * 0.85;
  return vec4f(vec3f(0.08, 0.40, 0.75) * alpha, alpha); // ...in premultiplied alpha
}`;

async function main() {
  const adapter = await navigator.gpu?.requestAdapter();
  if (!adapter) return showMessage('WebGPU is not available in this browser');
  const device = await adapter.requestDevice();
  const format = navigator.gpu.getPreferredCanvasFormat();
  const module = device.createShaderModule({ code });
  const pipeline = device.createRenderPipeline({ layout: 'auto', vertex: { module },
    fragment: { module, targets: [{ format }] } });
  const lines = [];
  const show = () => { document.getElementById('info').textContent = lines.join('\n'); };

  function draw(texture) {
    const encoder = device.createCommandEncoder();
    const pass = encoder.beginRenderPass({ colorAttachments: [{ view: texture.createView(),
      clearValue: [0, 0, 0, 0], loadOp: 'clear', storeOp: 'store' }] });   // transparent clear
    pass.setPipeline(pipeline);
    pass.draw(3);
    pass.end();
    device.queue.submit([encoder.finish()]);       // no present() call: the browser composites
  }

  for (const [id, alphaMode] of [['opaque', 'opaque'], ['premul', 'premultiplied']]) {
    const context = document.getElementById(id).getContext('webgpu');
    let before = 'no error';
    try { context.getCurrentTexture(); } catch (e) { before = e.name; }   // not configured yet
    // The canonical configuration, with every default spelled out (alphaMode varies here)
    context.configure({ device, format, usage: GPUTextureUsage.RENDER_ATTACHMENT, viewFormats: [],
      colorSpace: 'srgb', toneMapping: { mode: 'standard' }, alphaMode });
    const texture = context.getCurrentTexture();
    const same = texture === context.getCurrentTexture();
    draw(texture);
    lines.push(`${alphaMode}: before configure() ${before}; got ${texture.width}x${texture.height} ` +
      `${texture.format}, usage ${texture.usage}; same object twice in one task: ${same}`);
    requestAnimationFrame(() => {                  // one frame later: a new texture to draw into
      const next = context.getCurrentTexture();
      draw(next);
      lines.push(`${alphaMode}: after the next animation frame, a new texture? ${next !== texture}`);
      show();
    });
  }
  show();
}
main();
</script>