$DOOM

DOOMon Robinhood Chain

The whole 1993 game, byte for byte, in 20 Robinhood Chain transactions. Solana needs 588 for the same bytes. No server, no IPFS, no contract. Your browser pulls them off the chain and runs the game. Right here.

Contract
pons.family

E1M1 is 20 transactions away

Reading the transaction0 bytes

              

The chain didn't answer

Sourcenot loaded
Transactions20
Calldata1.72 MB
Hashnot verified
ExplorerBlockscout

Arrows move · Ctrl fires · Space opens doors · Alt + arrows strafe · Enter picks · Esc menu

Waiting for the chain

One more transaction. The Slayer and the riff.

A second transaction carries the Doom Slayer in full resolution and the first 45 seconds of At Doom's Gate. Your browser reads it off Robinhood Chain, splits the bytes and plays them.

Transaction
0xe855…34b4
Image
WebP, 236 × 423, 27,504 bytes
Sound
Opus, 45 s, 66,402 bytes
Read from
not loaded yet

Not a link to DOOM. DOOM.

Most "on-chain" games store a URL. This stores the game. Every byte of the engine, the shareware levels, the boot script and even the decompressor sits in the calldata of 19 Robinhood Chain transactions, settled to Ethereum. One more transaction lists them all.

20 tx for the entire game. Solana caps a transaction at 4 KB and needs 588 of them. Robinhood Chain takes up to 95 KB per transaction.
1.72 MB of calldata, LZMA-compressed from 6.84 MB. Your browser decompresses it with a decoder that ships inside the same data.
0 servers between you and the game. The page asks a Robinhood Chain node for 20 transactions, checks the SHA-256, unpacks them and boots the WebAssembly.
Verify it yourself
// node 20 or newer, npm i lzma
const RPC = 'https://rpc.mainnet.chain.robinhood.com';
const ROOT = '0x…';
const input = async h => Buffer.from((await (await fetch(RPC, { method: 'POST', headers: { 'content-type': 'application/json' },
  body: JSON.stringify({ jsonrpc: '2.0', id: 1, method: 'eth_getTransactionByHash', params: [h] }) })).json()).result.input.slice(2), 'hex');
const { blob } = JSON.parse((await input(ROOT)).subarray(5));      // root: "DOOM" | 0x03 | JSON
const game = Buffer.alloc(blob.size);
for (const [i, h] of blob.chunks.entries()) {                         // chunk: "DOOM" | 0x01 | u16 | u32 index | bytes
  (await input(h)).subarray(blob.header).copy(game, i * (blob.chunkSize - blob.header));
}
// sha256(game) equals blob.sha256. game = "DOOM" | 0x05 | u32 len | manifest | boot.js | decoder | doom.wasm (LZMA)