How I built a live halftone portrait in React with just Canvas 2D
My portfolio is set like a newspaper, so my photo couldn't just be a photo. I wanted it to look like a printed halftone: a grid of dots, bigger where the picture is dark and smaller where it's light. And I wanted it to be alive, so the dots swell and get pushed away when you move the cursor over them. It turned out to be about 150 lines of React and plain Canvas 2D, with no dependencies. Here's…
The author wanted their portfolio's photo to resemble a halftone print, featuring a grid of dots that vary in size based on lightness and darkness. They achieved this using just 150 lines of React and the Canvas 2D API without any dependencies. The process is broken down into four steps.
First, the image is transformed into a grid of samples, essentially creating a low-resolution version of the picture made of dots. This is done by drawing the image onto a small offscreen canvas and reading the pixels back using getImageData. The browser handles the downscaling by averaging the source pixels for each sample, which provides the color and darkness needed for each dot.
Next, a dot is drawn for each sample. The radius of each dot is determined by the sample's darkness, with darker samples resulting in larger dots. A tone curve is applied to the darkness value to prevent midtones from appearing too light. Additionally, an elliptical vignette is used to give the portrait a soft edge instead of a hard rectangle.
To add a sense of life to the portrait, a small sine wave is introduced, causing each dot to ripple slightly based on its position. This ripple effect is relatively slow, making the portrait appear to breathe.
Finally, the portrait reacts to the cursor. The cursor's position is smoothed out and targeted, causing the dots to grow or shrink as the cursor moves around them. This creates an interactive experience where the dots appear to swell and recede as the cursor moves over them.
Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.