Play Doom on your GitHub contribution graph — a Chrome extension that compiles DoomGeneric to WebAssembly and renders every frame live onto the real contribution grid.
Install · How it works · Build from source · ABI spec · Privacy
Get it from the Chrome Web Store.
Then on any GitHub profile: open the contribution graph's Contribution settings menu (top right of the graph) and check Doom. The graph expands to a taller grid and a live game starts immediately — no setup, no save file, nothing to configure.
Prefer to run it from source? See Build from source.
- Arrows move and turn, Ctrl fires, Space uses/opens doors, Escape pauses. Standard Doom controls — nothing GitHub-specific.
- The game starts straight into E1M1 with monster respawning turned on, so a long-running tab stays lively instead of running out of demons.
- Every GitHub contribution-graph color level (the 5 shades from "no activity" to "a lot") maps directly to Doom's rendered brightness, dithered to avoid hard banding at this resolution.
- Toggling Doom off restores your actual contribution graph exactly as it was.
| Piece | What it does |
|---|---|
doomgeneric_github.c |
The DoomGeneric backend: owns the framebuffer, downsamples Doom's 320×200 render to the graph's resolution, and exposes a tiny C ABI (see docs/SPECS.md) for the JS host to drive. |
extension/src/doom/worker.js |
Runs the compiled WASM module in a dedicated Web Worker at Doom's native 35Hz tick rate, off the page's main thread. |
extension/src/doom/frame.js + engine.html |
A hidden iframe hosting the worker, relaying input in and frames out via postMessage. |
extension/src/doom/display-driver.js |
Expands the real contribution grid to the taller display size and paints each cell by setting its data-level attribute — the exact mechanism GitHub's own CSS uses to color a real contribution square. |
extension/src/content.js + utils.js |
Finds the contribution graph's settings menu and injects the Doom toggle into it. |
Nothing is downloaded at runtime: the WASM binary, the shareware IWAD, and
the Doom engine are all bundled in the extension. No network requests, no
accounts, no data collected — see PRIVACY.md.
Requires the Emscripten SDK
on PATH.
emsdk_env # or emsdk_env.bat / emsdk_env.ps1, from your emsdk checkout
make -f Makefile.emscripten clean
make -f Makefile.emscriptenThis produces engine.js / engine.wasm at the repo root — copy both into
extension/src/doom/ before loading the extension.
Load the extension locally: chrome://extensions → enable Developer
mode → Load unpacked → select the extension/ folder.
Test the engine without the extension: serve the repo root
(python -m http.server 8080) and open test/pipeline.html, which drives
the exact same worker/iframe/input pipeline the real extension uses.
The C ↔ JS boundary is small and documented in full in
docs/SPECS.md: a handful of exported functions
(DG_Github_Init, DG_Github_Input, DG_GetFramebufferPtr,
doomgeneric_Tick) and one flat framebuffer, one byte per cell, values
0–4 matching GitHub's contribution levels.
- DoomGeneric by ozkl — the portable Doom implementation this is built on.
- id Software — for Doom, and for releasing the source.