spud
A Minecraft client for machines that cannot run Minecraft — no JVM, no game engine, and a renderer that needs no graphics card.
Playable on a survival server: walking, mining, placing, fighting, chat, containers, and the health, hunger and effect readouts. Targets protocol 769 (game version 1.21.4), offline-mode and LAN servers.
Why it exists
Vanilla Minecraft wants a couple of gigabytes of memory and a GPU. Plenty of hardware has neither — an old laptop, a router, a single-board computer — and on those the game is not slow, it simply does not run.
spud is a client for that hardware. There is no Java runtime and no game engine underneath it; the network protocol is written out by hand, and a packet whose id it does not implement is discarded exactly, because every frame is length-delimited. A partial client is a legal client, which is what makes a small one possible at all.
Two renderers that have to agree
There are two ways to draw the world: OpenGL, and a rasteriser that runs entirely on the CPU with no window, no context, and no graphics hardware anywhere in the process. The software path is the whole point — it is what makes "a machine that cannot run Minecraft" mean a machine with no GPU rather than merely a slow one.
The CPU path mirrors the two GL shaders stage for stage rather than reinventing them, so a change to one obviously demands a change to the other. It does near-plane clipping, edge-function scan conversion, a depth buffer, perspective-correct interpolation, nearest-neighbour atlas sampling, alpha cutout on the opaque pass and source-alpha blending for water.
The two will never be bit-identical — fill rules, sample rounding and the order floats are summed all differ between a driver and this — so they are compared by distance instead. On the demo scene every single pixel lands within 8/255 of the OpenGL frame, with a mean difference of 0.317. Splitting the work across cores changes nothing: the same scene at 1, 2, 7 and 64 threads is byte-for-byte identical, and a test enforces it.
Facts nobody should be typing by hand
Packet ids, block states, collision shapes, entity sizes, item ids, tool speeds and effect ids are generated from the game's own data rather than transcribed. Every one of them gets reassigned between versions, and a table typed out by hand is a table that is wrong after the next release.
Assets are resolved at build time too — 2,213 model files, their parent chains and blockstate variants flattened into tables the client reads directly. Retargeting to a new game version is running the generators again, plus whatever field layout genuinely moved.
The renderer on this site
The interactive scene on the resume page is this same rasteriser compiled to WebAssembly. It could not ship with the game's textures — those are not mine to redistribute — so the browser build generates its own atlas and its own cube geometry at startup from a hash function, owing nothing to anyone. The Depth control paints the depth buffer directly, which is the clearest look at what the CPU is actually computing.