fully on-chain · Cardano preprod
FreeDoom
on Chain
fully decentralized on the Cardano UTXO blockchain

The engine, the WAD and the loader all live as inline datums on the Cardano ledger — no server, no IPFS, no Arweave. A tiny bootstrap in the NFT reads every byte back from the chain, hash-verifies it, and boots the game in your browser. The NFT is the game.

▶ Play the games Proof on chain → Source on GitHub

Why this exists

You've seen the videos — Doom running on a pregnancy test, on a custom CPU, on anything with a handful of pixels. It's a genre at this point. I watched a few too many and thought: why not put it on Cardano as a real game? Not a screenshot, not a link to a hosted build — the actual playable bytes, living on the ledger itself.

So I worked out what protocol that would take: how to chop a WebAssembly game into UTXO-sized pieces, store them as inline datums, and read them back at play time with integrity you can verify. That protocol is what this project is. I plan to write it up as a CIP / CPS when I get the time.

The three games

FreeDoom · Episode 1

The real Doom engine (doomgeneric) + the free Freedoom WAD — all nine E1 maps, mouse-look, and saves.

ProtoDoom

A custom Rust raycaster written from scratch — 3 enemy types, mouse-look. The proof-of-concept that started it.

ProtoDoom (simple)

The very first, bare-bones raycaster build — the smallest thing that proved a game could live in a datum.

All three boot straight from the chain. Open the game center →

How it works

  1. Compress & chunk. The game (engine + WAD) is deflate-compressed and sliced into 14 KB pieces.
  2. Store on-chain. Each piece becomes an inline datum on its own UTXO; a manifest lists them all, hash-pinned by SHA-256.
  3. Mint the NFT. A CIP-68 token carries a tiny two-stage bootstrap — the whole loader is itself stored on-chain too.
  4. Play. The bootstrap reads the loader back from the ledger, the loader reads every chunk, verifies each hash, decompresses, and boots the game in an iframe.
Reading the chain uses a transport, not a source of truth — a wallet bridge or the public Koios API — but the bytes are pinned by hash no matter who serves them. In this preprod build the chunks sit at a recoverable address so the ADA can be reclaimed; locking them permanently would make the game live on-chain forever.

Want to see it for yourself? Browse the mint transaction and every on-chain UTXO →

Dev log · how it evolved

first — a raycaster
A hand-written Rust raycaster, small enough to fit in a single datum. It worked. A game really could live on-chain.
then — the real engine
Swapped in doomgeneric + the Freedoom WAD. First it was a 3-map shareware cut to keep it small.
then — the full episode
Dropped the shareware limit and put the full nine E1 levels on-chain, with a custom level-select menu.
then — smaller
Tuned the Emscripten build (size flags, dead-code) to trim the on-chain footprint.
then — saves
Wired the engine's Save/Load into the browser's storage (IndexedDB), so your progress survives a reload — a proper little developer story.
last — reclaimable
Chose to store the chunks at a spendable address on purpose, so the ledger space can be reclaimed rather than locked forever.

A hobby project

This is a hobby project — I hope you have fun with the concept. I don't plan to extend it much further; I do plan to submit a CIP / CPS for the protocol, and the source is open. Built for the joy of seeing Doom run somewhere new.