From Pixels to Parameters: Doom's Renderer in a Transformer

A recent project, born from a series of posts, has achieved a remarkable feat: porting the iconic Doom rendering algorithm to run entirely within a 21-billion-parameter transformer model. What sets this endeavor apart is its complete bypass of traditional machine learning training. Instead, the creator developed a custom compiler that translates computational graphs into transformer weights. This allowed for Doom's rendering logic to be expressed as a compatible graph, which was then compiled into the transformer's parameters.

The resulting model checkpoints are standard Hugging Face transformers checkpoints, meaning they can be loaded without special `trust_remote_code` flags. The process involves providing the transformer with a prompt that encodes scene data. The model then generates a sequence of tokens. These tokens are not abstract representations of an image but direct, executable pixel drawing commands—instructions to move a cursor, draw a pixel, and so forth. Applying these commands sequentially reconstructs the rendered frame, effectively turning a classic game engine's core logic into a generative sequence.

The technical approach leverages the inherent structure of transformers as sequence generators. By framing the rendering process as a series of discrete operations that build an output frame, the transformer can learn to predict the sequence of these operations. The key innovation lies in the compiler, which bridges the gap between a deterministic, procedural rendering algorithm and the probabilistic, weight-based nature of a transformer. This is akin to teaching a musician to play a symphony not by listening to recordings, but by directly writing the sheet music into their brain, note by note.

Diagram illustrating the compiler's process from Doom's rendering graph to transformer weights

The Compiler and Computational Graphs

At the heart of this project is a custom compiler. This compiler's primary function is to take a computational graph, representing the steps of Doom's renderer, and convert it into the specific format required by a transformer model – the model's weights. A computational graph is a directed acyclic graph where nodes represent operations (like addition, multiplication, or more complex rendering functions) and edges represent the data (tensors) flowing between them. Many modern deep learning frameworks build and optimize computations using these graphs.

The compiler essentially flattens this graph into a sequence of operations that a transformer can represent. For a transformer, this means mapping operations and data transformations onto its attention mechanisms and feed-forward layers. The process is not about the transformer learning to *mimic* rendering through trial and error on image data. Instead, it's about encoding the *exact logic* of the renderer into the transformer's parameters. This is a crucial distinction. It means the transformer becomes a highly specialized execution engine for the Doom rendering algorithm, rather than a general-purpose image generator.

The output of this compilation process is a set of weights. When loaded into a standard transformer architecture, these weights dictate the model's behavior. The prompt acts as an initial state or context for the rendering process. For instance, a prompt might describe the camera position, the level geometry, and the lighting conditions. The transformer then autoregressively generates the token sequence, which, when interpreted, describes the pixel-by-pixel construction of the final image.

Generating Pixel Commands

The output of the transformer is a sequence of tokens, but these tokens are not abstract embeddings. They are designed to be directly translatable into commands that manipulate pixels on a screen. This includes instructions such as moving the drawing cursor to a specific X, Y coordinate, setting the color of a pixel at that coordinate, or perhaps defining a block fill operation for efficiency. This output format is deliberately simple and mechanical, mirroring the low-level operations a graphics card or a software renderer would perform.

The host program, a mere 43 lines of Python, orchestrates this entire process. It loads the compiled transformer model, prepares the input prompt representing the scene, initiates the generation of the token sequence, and then parses this sequence. The parsing stage is critical: it takes the generated commands and applies them to an in-memory frame buffer. When all commands are executed, the frame buffer holds the final rendered image, which can then be displayed.

This approach sidesteps the immense data requirements and computational costs associated with training large language models for image generation tasks. Instead of learning from millions of images, the model is essentially given the explicit rules for creating a specific type of image—in this case, a Doom frame. The