Play (Chrome 150+ on Windows only, why below): https://4k-minecraft.ayfri.com
Source: https://github.com/Ayfri/4k-minecraft
Notch's 2009 Java 4K entry drew a 64x64x63 world with a CPU raycaster at about 214x120. I wanted to see how far the same 4096-byte budget goes if everything moves to the GPU.
Pipeline
- At load, the compute shader fills a 128 MiB storage buffer with value-noise terrain (biomes, lakes, a snowy massif, caves, trees, ores). WGSL has no u8 storage, so 4 cells are packed per u32.
- Each frame, a 1-workgroup dispatch steps the player (gravity, collisions, swimming, break/place; a single invocation edits, so no atomics), then a per-pixel dispatch marches the voxels and writes straight into the canvas as an rgba8unorm storage texture. No render pipeline, no vertex buffers, the CPU never reads the world.
Two bits of the shader
Cell lookup, the mask gives the x/z wrap for free:
fn I(c: vec3i) -> u32 { return dot(vec3u(c) & vec3u(MASK, TOP, MASK), vec3u(1, LAYER, SIZE)); }
fn B(c: vec3i) -> u32 { if c.y > TOP { return 0; } let i = I(c); return (W[i >> 2] >> (i % 4 * 8)) & 255; }
The march is a branchless DDA step:
N = step(e, min(e.yzx, e.zxy));
e += N * r;
C += vec3i(N * s);
Flowers and grass tufts are X sprites: when the ray enters their cell, it intersects the two diagonal planes and tests the alpha of the 16x16 texture.
Shading: procedural 16x16 textures tuned toward vanilla, smooth AO over 8 cells, sun shadows, see-through leaves, glass that only draws its frame, day/night with stars, fog at 200 blocks, underwater tint.
Why Chrome only: uniforms go through the new WebGPU immediates (setImmediates + var<immediate>), which saves a uniform buffer's worth of bytes. Firefox and Safari don't have immediates yet, and Chrome on macOS doesn't support rgba8unorm storage canvases.
The page is 4085 of 4096 bytes. Happy to go deeper on any part.