Since I've been playing a lot of Minecraft lately as my son is really into it, I wanted to create something related to it. Some kind of tool, to do... something. What exactly? Well, maybe it would be fun to be able to have something that generates Minecraft designs that could be pasted into your world easily.
This was supposed to be a short side project, but that was three weeks ago.
At first I thought I'd make something to allow pasting in entire full-color images that would then be rendered as Minecraft blocks. But the only way I could find to copy & paste things into a Minecraft world without editing files (which I figured would be impractical for active multiplayer servers), was to copy & paste commands. But I discovered you can only paste in 64kB of text.
That's a lot of text, but not a lot of data when creating large images, especially since setting just one block takes more than 150 characters of Minecraft commands! However besides a "set" command, there is also a "fill" command that can fill in rectangular areas. Maybe that could somehow be used if I could reduce an image into the minimal amount of rectangles?
That turned out to be a rabbit hole that had me browsing Cormen's "Introduction to Algorithms". I came up with an approach based on two existing algorithms that significantly reduced the amount of Minecraft commands necessary.
Rabbit hole deepens
I started off implementing the thing in Python, and could confirm that it works, but for even small images it was taking way too long to run. Happily I know some C, so I created a Python extension in C to run it, and got something like a 10x speed boost. This made it tolerably fast for small images, taking up about a second to compute the commands necessary to render an image using Minecraft fill commands.
For a bit larger ones it could still take minutes, as the time taken is proportional to the cube of the dimension of the image, multiplied by the number of colors. Since I wanted to put this online for anyone to access, I didn't want users maxing out my server CPU and also having a poor user experience, so I started thinking how to compute it on the client instead. I could just release it as an app, but first of all I wanted to see it running in a browser.
Then I remembered the fastest possible thing there is to run something in a browser right now: WebAssembly, something I'd never used before.
I read a few tutorials, and while I eventually did get my C code compiled into WebAssembly, it wasn't a very pleasant experience. It felt very brittle. Slight changes could abruptly make my code not work. At one point I was in a situation where just adding a function that printed "hello world" caused my code not to run — even though I wasn't even calling that function from anywhere! Similarly when I changed some compiler options that should have had no effect, such as increasing the amount of debug logging or optimization level, suddenly made my WASM file not even load.
Let it go
In my years as a developer I've learned that any time something seemingly goes wrong with a programming language or tool, it's without exception always been my own fault. And I'm sure here too it was me that was doing something wrong that caused the problems above, but I ran out of ideas of what it could be, and decided to just use the WASM code I'd already written that happened to work. That code only supported black & white images (not even grayscale).
Besides, when experimenting with larger images with more colors, I realized that the algorithm was still way too slow for them. You could produce an output, but you'd have to wait longer than most users would probably have patience for. Besides that the amounf of copy & pasting necessary to then move the result into Minecraft would have been too annoying for color images.
After testing the code with a few more black and white images and admiring them in my Minecraft realm, I realized that there really weren't many good examples available, and the result didn't look that great. So perhaps I should just drop this whole idea. It did seem a shame that all this work and learning would now amount to nothing.
But then I recalled that one time I was playing around with the code and as a test generated a bunch of random black and white blocks. Those blocks reminded me of something... they kind of looked like a QR code. Now that's something that could be potentially useful. Admins who run their own Minecraft servers or realms could paste in QR codes to promote their websites for example.
So I pivoted this side-project into a simpler tool. You can't generate any image you want, but you can make QR codes that can be copied into Minecraft. I just finished polishing it up today (it's easy to forget how many little details there are when launching anything new online, no matter how small!). Thanks for reading this post, and here is the tool: Craft QR.