DEV Community

Jian Tang
Jian Tang

Posted on

I built a browser tool that turns any image into Minecraft pixel art

I play a lot of Minecraft, and every time I wanted to build pixel art from an image I hit the same wall: manually matching each pixel to the closest block color, then counting how many of each block I'd need. For a 64×64 build that's 4,000+ blocks to plan by hand. So I built a tool to do it in a second — BlockMosaic.

It converts any image into Minecraft blocks right in the browser. No upload, no signup. Here's what went into it and a few things I learned.

Everything runs client-side

The whole pipeline is in-browser — your image never touches a server. That's a privacy win and it means zero server cost, but it also forced some interesting constraints.

The image→blocks conversion runs in a Web Worker so the UI stays responsive, and the heavy code is lazy-loaded with a dynamic import so it never bloats the first paint. The page content itself is server-rendered (static export) for SEO, while the interactive tool hydrates separately.

Matching colors to blocks

The core is simple: downsample the image to a grid, then match each cell to the nearest block by squared RGB distance. The fun part was the palette.

I needed accurate average colors for ~160 blocks. Instead of eyeballing them, I extracted the official block textures from the Minecraft client jar and computed the average color of each texture programmatically (averaging only non-transparent pixels, and the first frame of animated textures). Biome-tinted textures like grass are grayscale in the file, so those got a manual override.

I also added dithering (Floyd–Steinberg and ordered) — when you reduce to a limited block palette, error diffusion makes gradients read way smoother than nearest-match alone.

Exporting builds

Previewing is nice, but the real value is not placing 4,000 blocks by hand. So the tool exports:

  • .litematic for the Litematica mod
  • .schem for WorldEdit
  • .mcfunction as setblock commands

Both schematic formats are NBT under the hood. There's no NBT library small enough that I wanted to ship, so I wrote a tiny big-endian NBT writer and used the browser's built-in CompressionStream for gzip. The trickiest bit was Litematica's bit-packed block-state array (palette indices packed across 64-bit longs) — BigInt made that bearable.

As a bonus I added a Litematica → Schematic file converter (reads a .litematic, re-emits a .schem), which meant writing the NBT reader too.

Things I'd tell my past self

  • Web Workers + dynamic import are the cheap way to keep a heavy client tool from wrecking your load time.
  • CompressionStream/DecompressionStream are in every modern browser now — you rarely need a gzip dependency anymore.
  • Computing palette colors from real assets beats hand-tuning every time, and it's a 50-line script.

Try it

If you build in Minecraft (or just want to pixelate an image), give it a go:

It's free and runs entirely in your browser. I'd love feedback — especially on color accuracy and which export formats you'd want next. What would you build first?

Top comments (0)