Keeping AI on the pixel grid
Ask an image model for pixel art with 8 pixel blocks and you'll get something that looks right at a glance. Zoom in and the grid has drifted. This is the story of how I stopped asking the model nicely and started measuring what came back.
The problem
- Image models don't draw on a grid. They paint something that looks like pixel art, at whatever block size feels right to them.
- On one scene I asked for 8 pixel blocks and got a perfectly even 5.12 pixel grid. On another, 10.24. On a 2x2 sheet, the sample in one cell came back at exactly 8 pixels while the three buildings next to it came back at 9.31.
- If you read that art on the grid you asked for, rows and columns get doubled or dropped. The sprite looks stretched, misaligned, a little bit wrong. MagicPixel's public gallery showed it: imperfect pixels in real users' work.
Step one: show the model the grid
Words aren't enough. Every grid-locked generation now includes a pixel grid ruler, a checker image where one square equals one pixel, and every reference image is sent on the same fixed 1024 output grid. When a code path skipped the ruler, the model drifted immediately: a Convert to Pixel Art run came back at roughly 4 pixel blocks with ragged edges. The rule now is simple. If the grid is locked, the ruler goes with it.
Step two: read the grid the model actually drew
Even with a ruler, models wander. So instead of trusting the requested size, MagicPixel measures the lattice in the output:
- Measure edge energy along each axis and find the repeating pattern with a Fourier comb.
- Rank the candidates so the true block size beats its half and its double.
- Snap one color per cell by majority vote, so nothing is blended or redrawn.
The approach builds on Sprite Fusion's open source Pixel Snapper (MIT), adapted for MagicPixel's sheets. Each snap takes about 300 ms.
Step three: know when not to snap
Snapping the wrong art is worse than not snapping. A cell is only re-read on the model's grid when the evidence is clear: a strong lattice on both axes, square blocks, a real drift from the requested size, and a read that is meaningfully more accurate. Everything else keeps the requested grid, byte for byte. A user's own sprite always keeps its own scale, and the board never grows.
What I learned
- Making a non-deterministic tool feel predictable is mostly about measuring what came back, not writing a better prompt.
- The gallery is my best bug tracker. I saw the imperfect pixels in users' work, shipped the grid fix the same day, and shared it on X.
- The best AI features don't feel like AI. They feel like the tool simply works.