The whole game, byte by byte
Each square is one byte of index.html, read live from the page you play.
4085 of 4096 bytes
- decoder
- -
- compressed game
- -
- free
- -
Then and now
Notch's entry for the Java 4K contest, released in December 2009, drew a small world with a CPU raycaster. This one hands both the world and the rays to the GPU.
| 2009 Java 4K | This | |
|---|---|---|
| Size | 2581 B Java applet | 4085 B HTML |
| World | 64 x 64 x 63 | 1024 x 1024 x 128 (128 MiB) |
| Renderer | CPU raycaster at about 214 x 120 | WebGPU compute shader at full window resolution |
| Generation | CPU at load | compute shader at load |
| Placeable | grass | 16: 3 plants, 10 blocks, 3 ores |
| Lighting | face shading | ambient occlusion, sun shadows, day and night |
Controls
Click the page first to lock the pointer.
- W A S D
- Walk. Physical keys, so Z Q S D on AZERTY.
- Left Shift
- Sprint
- Space
- Jump, or swim up
- Mouse
- Look
- Left click
- Break
- Right click
- Place
- 1 - 9 0
- Select a block: grass, dirt, stone, sand, log, leaves, planks, bricks, snow, glass
- Wheel
- Cycle every placeable block, plants and ores included
How it fits
The page is a decoder and a deflate stream. The decoder is all the page can afford, so everything else is squeezed before it gets there.
Source
TypeScript for the game and WGSL for the shader. World constants are shared by name.
Shrink
An in-house minifier rewrites the AST and picks every name by deflate size, the shader's names too.
Deflate
An in-house encoder searches the bit stream for one without the 10 bytes the parser or
l9would change, against zopfli and libdeflate.Page
charset=l9reads each byte as one character. The stream sits raw in<canvas><xmp>.Boot
The browser inflates it with
DecompressionStream('deflate-raw')and evals the result.
<meta charset=l9><body onload='new Response(new Response(Uint8Array.from(c.textContent,c=>c.charCodeAt())).body.pipeThrough(new DecompressionStream("deflate-raw"))).text().then(eval)'><canvas id=c><xmp>
Then the raw deflate stream. No decompressor, no zlib header.
Requirements
Needs WebGPU with immediates, a keyboard and a mouse. Today that means Chrome 150+ on Windows.
| Browser | Runs | Why |
|---|---|---|
| Chrome 150+ on Windows | yes | tested on Chrome 155 |
| Edge 150+, Chrome on Linux, ChromeOS | should | untested, same engine |
| Chrome on macOS | no | the canvas can't be rgba8unorm there yet |
| Firefox 158 | no | no immediates, tested: everything else works |
| Safari 26 | no | no immediates |
| Phones, tablets | no | the controls need a keyboard and a mouse |
Immediates are the tiny per-dispatch uniforms set with setImmediates and read as var<immediate> in WGSL. They save the bytes of a uniform buffer.