← Back to PopCraft
← THE DAILY POP

How We Render 2 Million Halftone Dots at 120fps

A deep dive into the WGSL shader behind PopCraft's live halftones — and how we turn them into real, editable vector dots.

SDSpace Devin · Founder●August 21, 2026●2 min read

Halftones are the soul of pop art: a photograph dissolved into dots whose size carries the tone. They're also a performance nightmare. A full-bleed poster at print resolution can contain millions of dots, and designers expect to drag a slider and see every one of them update instantly.

Here's how we made that happen.

Step 1: never draw a dot

The live halftone effect doesn't create geometry at all. It's a single fragment shader pass. For each pixel we:

  1. Rotate the pixel's position into the screen angle (the classic 15°, 45°, 75° CMYK angles are presets).
  2. Find which cell of the grid it falls in and sample the source image's tone at the cell center.
  3. Compute the dot radius from the tone, then return ink if the pixel is inside the dot.
let cell = floor(rotated / spacing);
let center = (cell + 0.5) * spacing;
let tone = luminance(textureSample(src, samp, unrotate(center)));
let radius = sqrt(1.0 - tone) * spacing * 0.7071;
let ink = 1.0 - smoothstep(radius - aa, radius + aa, distance(rotated, center));

Because every pixel is independent, the GPU chews through a 4K canvas in well under a millisecond.

Step 2: make it real when you need it

Live effects are great until you want to edit a dot, or send the poster to a print shop as SVG. So we wrote the same math a second time in TypeScript. Convert to vector walks the same cell layout, runs the same tone and band calculations, and emits polygons — real, selectable, exportable vector dots.

Step 3: keep the two in sync forever

The scariest bug in a system like this is drift: the shader and the vector version slowly disagreeing. Our test suite renders both, rasterizes the vector output and diffs it against the GPU image. If they differ by more than a hair, the build fails.

If the preview lies, the tool lies. We don't ship lies. We ship dots.

Space DevinFounder
NEXT ISSUE →Bring Your Procreate Brushes With You