Skip to content
← writing

An image pixelator in two drawImage calls

canvas
image
tool
frontend

I saw @rauchg share a little "Pixelate Me" app (built in v0, designed by Taras Donchenko) and wanted to rebuild the core. It's a satisfying one, because the effect that looks like it needs a shader is really just two drawImage calls. Drop something in:

The whole trick

To pixelate, shrink then grow. Draw the image into a tiny canvas (say a sixteenth of the size) with smoothing on, so each block averages to one color. Then draw that tiny canvas back to full size with smoothing off, so every sample becomes a hard square instead of a blurry gradient:

const sw = Math.round(w / block);   // 1/16th the width
const sh = Math.round(h / block);
 
const tmp = document.createElement("canvas");
tmp.width = sw; tmp.height = sh;
tmp.getContext("2d").drawImage(img, 0, 0, sw, sh);  // shrink (smooth)
 
ctx.imageSmoothingEnabled = false;                   // the whole trick
ctx.drawImage(tmp, 0, 0, sw, sh, 0, 0, w, h);        // blow it back up

That one flag, imageSmoothingEnabled = false, is the difference between a blurry upscale and crisp pixel art. The block size is just the divisor: bigger divisor, chunkier pixels.

Keep it full resolution

It's tempting to do all this at display size, but then your export is basically a screenshot. Run it at the image's native dimensions instead and the PNG you download is sharp at full size. Transparency rides along for free, so a cut-out subject stays cut out against whatever you drop it onto.

Recreated from Pixelate Me by @rauchg, designed by Taras Donchenko. Grab the component on the Image Pixelator page.

Ask your agent to implement this

Read the full writeup at https://seangeng.com/writing/an-image-pixelator.md and implement it in my project.

It covers: An image pixelator in two drawImage calls — Drop a picture, pick a block size, export a pixel-art PNG. The whole effect is drawing the image tiny, then scaling it back up with image smoothing turned off.

Requirements:
- Follow the technique/approach exactly as described in the writeup.
- Adapt names, colors, and styling to my project's existing conventions.
- If it's a component, make it reusable with sensible props and TypeScript types.
- Keep it accessible: semantic HTML, keyboard support, and respect prefers-reduced-motion.
- When done, tell me which files you created or changed and how to use it.

Paste into Claude Code, Codex, Cursor, or any agent. view raw .md download source .zip