Threads · note 02 / 4 · by Vorluno · Sep 21, 2026

The dot grid that froze the phone

A canvas effect that runs at 60 fps on a laptop can still hang a phone — not because it draws too often, but because it rebuilds too often, on the one thread the browser cannot spare.

What we built

Team photos rendered as a fine grid of ink dots: one dot per 3 px cell, radius from the pixel's luminance, drawn once into an offscreen canvas as a single Path2D with ~40 000 arcs, then blitted per frame. On a desktop GPU the per-frame cost is one drawImage. Idle: zero writes. Measured.

What the phone saw

Chrome's "This page isn't responding" dialog, and no photo at all. The prebake — building the 40 000-arc path and filling it, twice (ink and colour layers), for three photos — ran on the main thread. On a phone that is one to three seconds per photo. And it ran again on every resize, which on a phone fires every time the address bar shows or hides while you scroll. The photo never got a chance to paint before the next rebuild.

The fix that holds

Split the work by where it can run:


  
  

The browser picks the file; the main thread never hears about it. The photo appears on the phone, every time, with the same look as the canvas.

The rule we kept

An effect's cost is not its frame time. It is frame time × how often you rebuild × where the rebuild runs. If the answer to "where" is "the main thread on a phone", precompute it or do not ship it.

// next noteCloudflare kept the old face