Introduction

Discrete game world models keep shipping runnable toys, not just papers. Tetris world model (NullandKale / Alec Zinsli) is a ~2M-parameter spatiotemporal MaskGIT that predicts exact NES Tetris palette pixels from prior frames plus the controller — and the step-90,607 export runs entirely in the browser. The public ship landed on GitHub Oct 1 (NullandKale/tetris-world-model); the live player is at nullandkale.github.io/tetris-world-model. Every frame is model-generated; no emulator runs while you play.

What shipped

  • Modality: action-conditioned discrete video world model for NES Tetris (exact palette indices, not a learned tokenizer)
  • Open vs closed: open training + export code; browser ONNX graphs (prefill.onnx ~7 MB, step.onnx ~9 MB) plus start context under web/model/
  • Where to run today: open the GitHub Pages demo (Chrome/Edge WebGPU; WASM fallback elsewhere), or clone and serve web/ locally after scripts/export_onnx.py
  • One hard number: the published browser checkpoint is training step 90,607; on an RTX 3090 Chrome WebGPU path the docs clock a step at 14.4 ms (56 FPS play) after keeping the step graph on-GPU

Why makers should care

This sits in the same discrete-game lane as DashVMC, with a different contract: instead of dream-PPO for a live Geometry Dash agent, you get a playable NES Tetris dream you can drive with arrows / X·Z / Enter on any laptop that can load ONNX Runtime Web.

The recipe is Genie-style dynamics on exact frames:

  1. 16×16 tokens per frame — 256 tokens, palette-index embeddings, spatial then causal temporal blocks
  2. 64-frame window — covers Tetris’s slowest gravity timer (48 frames/drop at level 0)
  3. Controller conditioning — the button byte that produced frame t is embedded into that frame’s tokens
  4. Browser deploy — prefill fills the KV cache from a real start context; step emits the next frame and updated cache (GPU buffers stay on-device)

Training docs call out the usual exposure-bias stack: MaskGIT cosine masking, corrupted context, and scheduled-sampling rollouts so dreams do not melt after a few dozen frames. The Pages build freezes the checkpoint whose long dreams beat a later cooled-down step — a useful maker lesson when you export for demos.

Maker notes

git clone https://github.com/NullandKale/tetris-world-model
cd tetris-world-model
pip install -e '.[onnx]'
# Optional: re-export from a PyTorch checkpoint
# python scripts/export_onnx.py output/world_model_tetris_small/model_latest.pt
python -m http.server 8000 -d web
# then open http://localhost:8000  (or just use the Pages demo)

Controls on the live page: ← → ↓ move/drop, X/Z rotate, Enter Start. Training itself still needs World NES plus your own Tetris (USA).nes ROM (TETRIS_ROM) — neither ships in the repo. The playable surface for readers is the exported ONNX demo, not the training loop.

Scope note: this is one deterministic NES title with a tiny MaskGIT, not an open-world video generator. Steal the exact-pixel + browser ONNX step/prefill pattern; do not expect Matrix-Game fidelity.

Conclusion

NullandKale’s Tetris world model is a same-day, click-to-play discrete world model: open code, shipped ONNX, and a GitHub Pages player that dreams NES Tetris from your buttons alone. For game-gen makers chasing runnable discrete stacks after DashVMC, this is the clean Tetris twin to try tonight.

—Titus