primitive.topology decides how vertices group: point-list, line-list, line-strip, triangle-list (the default) or triangle-strip. The same six zig-zag vertices, one pipeline per topology:
<canvas id="gpu" width="600" height="100"></canvas>
<div id="names" style="display: flex; width: 600px; font: 13px Arial"></div>
<script type="module">
const code = /* wgsl */ `
struct Out { @builtin(position) pos: vec4f, @location(0) @interpolate(flat) panel: u32 }
@vertex fn vs(@builtin(vertex_index) v: u32, @builtin(instance_index) panel: u32) -> Out {
let zigzag = vec2f(f32(v / 2) * 0.13, f32(v % 2) * 0.7); // 6 vertices: 3 low, 3 high
return Out(vec4f(-0.93 + f32(panel) * 0.4 + zigzag.x, -0.8 + zigzag.y + f32(v / 2) * 0.1,
0, 1), panel);
}
const colors = array(vec3f(.08, .40, .75), vec3f(.18, .49, .20), vec3f(.94, .42, 0),
vec3f(.42, .11, .60), vec3f(.78, .16, .16));
@fragment fn fs(in: Out) -> @location(0) vec4f { return vec4f(colors[in.panel], 1); }`;
const device = await (await navigator.gpu.requestAdapter()).requestDevice();
const context = gpu.getContext('webgpu'), format = navigator.gpu.getPreferredCanvasFormat();
context.configure({ device, format });
const module = device.createShaderModule({ code });
const topologies = ['point-list', 'line-list', 'line-strip', 'triangle-list',
'triangle-strip'];
names.innerHTML = topologies.map((t) =>
`<span style="flex: 1; text-align: center">${t}</span>`).join('');
const pipelines = await Promise.all(topologies.map((topology) =>
device.createRenderPipelineAsync({ layout: 'auto', primitive: { topology },
vertex: { module }, fragment: { module, targets: [{ format }] } })));
const encoder = device.createCommandEncoder();
const pass = encoder.beginRenderPass({ colorAttachments: [{ loadOp: 'clear', storeOp: 'store',
view: context.getCurrentTexture().createView(), clearValue: [0.96, 0.94, 0.90, 1] }] });
pipelines.forEach((pipeline, i) => {
pass.setPipeline(pipeline);
pass.draw(6, 1, 0, i); // the same 6 vertices, panel i
});
pass.end();
device.queue.submit([encoder.finish()]);
await device.queue.onSubmittedWorkDone();
window.__done = true;
</script>
Points and lines are always one pixel wide (there is no lineWidth or point size), so thick lines and sprites are quads (Particles and Culling). Strips reuse vertices (four triangles from six vertices here, against two for the list), and alternate triangles are flipped so the strip keeps one winding order. With indexed strips set stripIndexFormat to use primitive restart (index 0xFFFF or 0xFFFFFFFF starts a new strip).