BEHIND THE CARTRIDGE
How 5,629 objects fit in a Game Boy Color cartridge.
Every object in CRUCIBLE.EXE turns, idles, glows or burns, in colour, on hardware that shows three colours per tile. This is how it was made: one description per object, one engine, and a lot of measuring.
- 5,629
- OBJECTS ON THE CARTRIDGE
- 19
- FRAMES EACH (12 VIEWS + 8 POSES)
- ~1.3 KB
- PER OBJECT, BOTH COLOUR LAYERS
- 455
- 16 KiB ROM BANKS OF ART
01 / KEEL
One description, every target.
KEEL is the engine. Each object is written down once: its parts, materials, joints, motion and effects. The same generator renders that description for every target, from the room on this page to the 8 MiB cartridge. It is deterministic: the same seed gives the same pixels everywhere, so a frame made on a laptop is byte-for-byte the frame the cartridge stores.
02 / THREE COLOURS
The machine allows very little colour. So the colour is solved.
A Game Boy Color background tile has three colours plus the background, and the screen has eight background palettes for everything at once. So each object gets its own palette, solved from its own materials. A search tries the object's material colours (every region's dark, mid and light, plus the outline) and keeps the three that minimise perceptual error in OKLab, weighted by how many pixels use each colour across all of its frames. Every tone is drawn as one entry or as an ordered dither of two.





Honestly: three colours are not always enough for every material to keep its own. Across the catalogue, 2,167 objects give every region its own entry; 2,406 borrow a colour from another region. The solver reports the error it leaves instead of hiding it: a median of 3.2 and a worst case of 11.9 (OKLab distance ×100).
03 / DITHER
Shading out of a 4×4 grid of thresholds.
Between two palette entries the shading is an ordered 4×4 Bayer dither: a fixed map of thresholds, so the pattern never shimmers or crawls between frames. The solver tries mixes at 4/16, 8/16 and 12/16 and penalises noisy, high-contrast pairs.
04 / A SECOND LAYER
Sprites painted over the tiles, only where they help.
The Game Boy Color also has sprites with their own palettes. CRUCIBLE.EXE uses them as a second three-colour layer over the base tiles, placed where they reduce the colour error the most: up to 6 colours plus sky per object. On average an object uses 6.6 sprites per frame, and the mean error drops from 3.28 to 0.83.
The trade-off: full colour for everything did not fit. The authored catalogue has 8,637 objects; the cartridge carries the 5,629 that fit with both colour layers.
05 / COMPRESSION
Nineteen frames in about a kilobyte.
Every object has a 12-view turntable and 8 rest poses: 19 frames of 32×32 pixels. A keyframe is stored, then each next frame is coded against the last with a context-modelled binary arithmetic coder (multiply-free, so it suits the CPU). On average that is 799 bytes for the base frames and 512 for the colour layer: about 1.3 KB per object, 7,408,944 bytes of art in 455 banks of 16 KiB.
OBJECT ART · 455 BANKS · 7,408,944 BYTES (+45,776 PADDING) EVERYTHING ELSE · 57 BANKS
06 / AT RUNTIME
Decoding a few rows at a time, so input never waits.
- Frames decode a few rows per tick (the colour layer: eight rows a tick), between everything else the game does, on a CPU of about 4 MHz.
- A new view decodes into the hidden VRAM bank a third per frame, then swaps in; decoded frames are cached in work-RAM banks.
- Palettes are uploaded only in vertical blanking, when the screen is not being drawn.
- Builds were profiled in an emulator, counting instructions and emulated cycles, before a ROM was accepted.
07 / THE STRANGE PARTS
Rooms that live, a clock that isn't there, pieces that get lost.
- Living rooms. The bench and reveal backdrops are composed per save, place and time from a small grammar; they flash at a find, dim at a miss, turn hostile in a fight, and hide rare glitch rooms.
- A clock with no clock chip. The cartridge is MBC5 (no real-time clock), so on its own it asks the date once; on this site the emulator writes the browser's local time into a small block of save memory before every power-on, so it never has to ask. Then it counts VBlanks: 70,224 cycles each, about 59.7275 per second, keeping the remainder so no time is lost. Time away changes things, quietly.
- Lost pieces. A piece you lose cools down for a number of other successful mixes (the same number for the same loss in the same save) before it can form again.
- Dialogue that leans. What you make and say moves two hidden axes. Nobody ever tells you where you are on them.
08 / WHY GENERATE IT
Why this was made with AI-assisted generation.
For this project, describing objects and letting one engine draw them fitted better than drawing each frame by hand in a pixel-art editor. One description became thousands of consistent objects, in every pose and view, inside every colour budget, and could be re-rendered whenever a rule changed, which happened often. Every change was measured (bytes, colour error, cycles) rather than judged by eye alone. That is this project's experience with these constraints, not a statement about artists or other tools; hand-drawn pixel art is a craft this game borrows from everywhere.
