Small WebGPU demos break for boring reasons. Most of the time it is not the API that is wrong — it is a missing adapter check, a pipeline misconfiguration, or a render loop that forgets to clear the canvas. This post is a clean fix pass for a broken triangle demo. The goal is to isolate one issue at a time and prove the fix works before moving on.

I cannot verify these steps from this blog repo. Treat this as a lab guide you can run locally.

What this post covers

By the end, you will:

  • fix a broken triangle render,
  • clean up the render loop,
  • verify the output is stable.

“Fix one thing, then verify it, then move on.”

Rendering pipeline checkpoint illustration for this section.

What you need

  • A WebGPU-capable browser.
  • A minimal WebGPU demo project, even if it is currently broken.

If you do not have a project yet, start with a single index.html and a main.js that requests a WebGPU adapter. Everything else in this post builds on that.

Step 1: Confirm the adapter and device

Goal: Ensure WebGPU is available before debugging anything else.

File: main.js

Add:

const adapter = await navigator.gpu.requestAdapter();
if (!adapter) throw new Error("No GPU adapter");
const device = await adapter.requestDevice();

Why: If the adapter is missing, nothing else matters. This is the first hard check. It reduces false debugging. It also tells you whether the browser supports WebGPU.

Verify:

  • Run the demo and check the console.
  • Expected: no "No GPU adapter" error.
  • This confirms WebGPU is available.

If it fails:

  • Symptom: adapter is null.
    Fix: enable WebGPU in the browser flags.

Step 2: Rebuild the pipeline

Goal: Create a minimal pipeline that can draw a triangle.

File: main.js

Add:

const pipeline = device.createRenderPipeline({
layout: "auto",
vertex: { module, entryPoint: "vs_main" },
fragment: { module, entryPoint: "fs_main", targets: [{ format }] },
primitive: { topology: "triangle-list" }
});

Why: If the pipeline is wrong, nothing draws. A minimal pipeline reduces the number of moving parts. This also makes shader issues easier to spot. It is the fastest route back to a working demo.

Verify:

  • Run the demo and look for a triangle.
  • Expected: a triangle appears.
  • This confirms the pipeline works.

If it fails:

  • Symptom: blank canvas.
    Fix: verify shader entry point names.

Step 3: Clean the render loop

Goal: Ensure each frame clears and draws correctly.

File: main.js

Use this loop:

function frame() {
const encoder = device.createCommandEncoder();
const pass = encoder.beginRenderPass({
colorAttachments: [{
view: context.getCurrentTexture().createView(),
clearValue: { r: 0.05, g: 0.05, b: 0.08, a: 1 },
loadOp: "clear",
storeOp: "store"
}]
});
pass.setPipeline(pipeline);
pass.draw(3);
pass.end();
device.queue.submit([encoder.finish()]);
requestAnimationFrame(frame);
}
frame();

Why: A clean render loop removes flicker and blank frames. It also makes the draw call obvious. This is the simplest loop that still updates every frame. It is the most reliable baseline.

Verify:

  • Expected: the triangle stays visible without flicker.
  • This confirms the loop works.

If it fails:

  • Symptom: triangle flickers.
    Fix: ensure you use loadOp: "clear" and submit the command buffer.

Verify it worked

  • A triangle appears.
  • The render loop runs without errors.
  • The output is stable.

Common mistakes

SymptomCauseFix
Nothing rendersShader entry points mismatchAlign entry point names in code and shader
Canvas is blackNo clear color or draw callAdd clearValue and draw(3)
Device lost errorsDriver issuesReload and try again
Graphics systems checkpoint illustration for this section.

What to add next

Once the triangle is stable, the next honest upgrades are:

  • Add resize handling so the canvas stays crisp when the window changes.
  • Add a uniform for color so you can change the triangle without touching the shader source.

Both of those are small, and both are easy to verify visually.

Related links

Closing

Fix one issue at a time and verify after every change. That sounds slow, but it is faster than debugging three broken things at once. A stable triangle is a real foundation. Everything else in WebGPU builds from there.

Keep reading