That's cool bro, but can it write Doom ?
ÂI'm not a developer and I've never made a game. I gave a coding agent a 392 character goal: port the Doom engine to TypeScript, unattended. It took 3.5 hours. That was the easy bit.
I'm not a developer and I've never made a game. I gave a coding agent a 392 character goal: port the Doom engine to TypeScript, unattended. It took 3.5 hours. That was the easy bit.
Part 1 of a series in which I ask an AI to rebuild a 1993 video game and then try very hard to leave it alone.
Every piece of hardware ever made gets asked the same question eventually. Pregnancy tests, tractors, a fridge, a calculator powered by potatoes. That's cool bro, but can it run Doom ?
It's the oldest joke in computing. Somebody gets Doom running on something it has no business running on, and the internet nods and moves on. Doom is the benchmark for "does this thing have a processor and a screen". If it can run Doom, it's a computer. Congratulations.

AI coding agents have now had a couple of years of benchmarks, leaderboards and breathless LinkedIn posts. Lately the hype train has switched tracks to reverse engineering: agents rebuilding games and apps like Minecraft meets GTA mash-up, even a whole suite of Adobe products, with the results open sourced for the world to use. Some of those claims will hold up and some won't, but the direction of travel is obvious.
So it felt like a good time to ask the grown-up version of the question. Not can it run Doom. Can it write Doom ?
This is an experiment in how far an AI agent can take you with a bit of creativity and the ability to say clearly what you want. That's the whole skill being tested, and it's mostly mine, not the agent's.
I should be upfront about who's running it. I'm a cloud architect, not a developer. I've never written a game, I have no game development experience, and I couldn't tell you how a 1993 renderer draws a wall. I know what good looks like, I know how to ask awkward questions, and that's about it.
The brief I gave myself: hand an agent a goal, walk away, and come back to a browser-playable port of the original Doom engine that behaves exactly like the real thing. Not "a Doom-like". Not a raycaster with a shotgun sprite. The actual game logic, tic for tic, in TypeScript, running in a browser tab.
And because I can't leave anything alone, that's only the start. The engine is the foundation. What I actually want to find out is how far I can take it afterwards, using other AI tools and a distinct lack of care for how many tokens I burn doing it. More on that at the end.
I set myself a constraint: the goal had to fit in under 400 characters. If you need three pages to explain what you want, you don't know what you want.
My first attempt was roughly "recreate a 1:1 clone of the original Doom, end to end, fully documented, ready to play on the web". Which sounds fine until you ask what any of those words mean to something that follows instructions literally.
What does 1:1 mean ? Looks similar ? Plays similar ? What does "ready to play" mean ? It compiles ? Here's where it landed after a pass through a prompt optimiser:
Goal: a browser-playable TypeScript port of Doom (1993), faithful tic for tic.
References: github.com/id-Software/DOOM (GPL source) and doomwiki.org.
Load a user-supplied WAD (shareware DOOM1.WAD or Freedoom); bundle no id assets.
Done when DEMO1-3 replay in sync, E1 is completable under Playwright, and
README plus docs/ cover build, run, controls and architecture.
Keep working until then.
The clever bit isn't mine, it's thirty years old. Doom's demo files don't store video, they store button presses. Play them back and the game re-simulates everything. If your physics, your random number table or your monster AI is off by a single step, the demo drifts and the player ends up running into a wall while imps wander about unbothered.
So "the demos replay in sync" is a one-line test for "you got the whole engine right". That's "1:1" turned into something a machine can check.
A goal is not a plan. If you give an agent a goal and nothing to measure against, it will tell you it's finished, and it will be very confident about it.
So before kicking anything off, the repo got some scaffolding. Full disclosure: I planned this with Claude, and it wrote the scaffolding. I'm the one who said "go big" and then asked awkward questions.
This is the part that makes the whole thing possible. Chocolate Doom is an existing source port that behaves exactly like the original. The agent's first job is to patch it to run headless and write out the game state on every single tic: the random number indices, where the player is, how many things are alive, a checksum over all of them.
That output gets frozen. From then on, the TypeScript engine has to reproduce it exactly. If tic 4,112 disagrees, the port is wrong, and the agent knows which tic to go and stare at. "Faithful" stops being an opinion and becomes a diff.
The one rule I care most about: once those fixtures are committed, the agent isn't allowed to regenerate them. If the test disagrees with the fixture, fix the port. Else what use is it.
Seven milestones, each with one command that passes or fails:
Notice the game simulation comes before the renderer. That feels backwards, you want to see something. But the simulation has an exact right answer and pictures don't, so it goes first.
The last addition was a journal. The agent keeps a running diary of the build: what broke, what it tried, what it got wrong. It decides what goes in. The only rules are a timestamp on each entry and no editing earlier ones, so the wrong guesses stay on the record.
That's the raw material for the rest of this series. I want to write about what the thing actually went through, not a tidy success story. One caveat I'll keep repeating: the journal is the agent's account of what it did. The git history is what it did. I'll be checking one against the other.
Three jobs, three model setups:
| Stage | Model | Effort |
|---|---|---|
| Planning | Opus 5.5 | Medium |
| Pre-reqs (oracle, scaffolding) | Sonnet 5.5 | Medium |
| Execution | Sonnet 5.5 | X-high, on ultracode, driven by the goal prompt |
Execution ran in a Claude Code cloud session sandbox rather than on my own machine. An agent running with no permission prompts belongs in a box that isn't my laptop, and a cloud session carries on when I shut the lid.
It fell over in the first two minutes. Not on Doom. On apt-get.
The environment has a network setting. The default, Trusted, allows the usual package registries. I'd been advised to switch to Custom and add a couple of extra hosts for a browser download. What nobody clocked is that Custom only includes the defaults if you tick the box that says so. I hadn't. So my allowlist was two hosts long, and neither of them was npm.
The result: no apt, no npm, no PyPI. A build agent with no way to install a build tool.
What the agent did next is the most interesting part of the opening. It worked out the mirrors were blocked by policy rather than broken. It said, in as many words, that it wouldn't bypass that. It checked what was already installed, found it couldn't proceed, and came back with a diagnosis and a proposed fix for me to apply.
The proposed fix was actually wrong, or at least unnecessary. It was patching around a misconfigured sandbox with proxy overrides, when the real answer was "flip the setting back to Trusted and start a fresh session". Which I did.
| Verdict | |
|---|---|
| Hit a wall it wasn't allowed through | Stopped and asked. Good. |
| Diagnosed the wall | Correctly, and quickly |
| Proposed fix | Plausible, but treating the symptom |
| Actual cause | Me, and a tick box |
A junior engineer who stops at a blocked firewall and writes up what they found is doing the job properly. But it's a useful reminder that these things debug the environment they're given. They don't step back and ask whether the environment is daft.
Fair question, and one I asked myself before starting - well writing about it and posting it on linkedin. Short version: no, but only because of what exactly is being ported.
The port is the game engine, and only the game engine. id Software released the Doom engine source under the GPL in the nineties. That's why Doom runs on everything, and it's the whole reason the meme exists. Porting that code is exactly what the licence is for.
(One thing to be clear on: this is a port, not a clean-room rewrite. A clean room means writing from a specification without ever seeing the original code. The agent did the opposite. It read id's GPL source and Chocolate Doom's source and ported the behaviour function by function, fixed-point maths and known quirks included. That was the instruction, and it's why my repo has to be GPL and the source public. My own art and levels aren't affected by that.)
What was never given away is the game itself. The levels, monsters, textures, sounds and music live in a separate file called a WAD, short for "Where's All the Data". Think of the engine as a console and the WAD as the cartridge. Doom the engine is free software. Doom the game is still id's, and later Bethesda's.
That split is the entire design of the project:
| Part | What it is | Status |
|---|---|---|
| Engine | Rules, physics, monster AI, renderer | GPL. My port, public source |
DOOM1.WAD | The shareware episode: freely distributable, still copyrighted | You supply it |
| Full Doom WADs | The commercial game data | You supply it, and you bought it |
| Freedoom | A replacement WAD built from scratch, openly licensed | Fine to test and ship against |
What it means for the project:
DOOM1.WAD, so it's checked against the real thing without redistributing itThat last point matters in the next phase. When the game becomes mine, every character, weapon and level has to be original. Not "the imp, but blue". My own designs, my own art (well AI, i'm not channelling my inner bob ross for this). Which is a better easter egg anyway - nobody visits a cloud architect's blog hoping to find someone else's game.
Yes. The agent took 3.5 hours to do the port, and it works with both Freedoom and the DOOM1.WAD.
That's Freedoom running in a browser tab. Before you ask: that's the agent playing, not me. I drove it through a script because I wanted a clean capture. I'm not much better at Doom than the script is, so you aren't missing anything.
What is that, exactly ? Plain TypeScript, no game framework and no rendering library. The agent wrote a software renderer that fills a 320x200 buffer of palette colours pixel by pixel, the way the original did, and copies it to a 2D canvas. No WebGL, no 3D scene. Sound goes through Web Audio.
The accurate one-liner: a from-source TypeScript port of the original engine, verified tic for tic against a reference implementation, built unattended in about three and a half hours.
"1:1" needs a scope on it. It's faithful in behaviour, and that's measured rather than claimed. Every recorded demo replays tic for tic against a real reference engine, and rendered frames match its output. But the measurement covers episode 1. Code that episode 1 never exercises, later monsters for example, is only checked against the agent's own reading of the source.
For scale, the finished repo is roughly 34,000 lines of source and 16,000 lines of tests, with about 1,180 tests passing. Session start to the last milestone was 21:07 to 00:36, which is the 3.5 hours. A review of a fresh clone in a clean container rebuilt the oracle, ran the whole check suite and got a clean pass. The oracle fixtures it wasn't allowed to touch were untouched, and nothing of id's is in the repo.
One honest caveat: the agent wrote the tests as well as the code. A green test run isn't the same as someone playing it, so the real acceptance test was always going to be playing Freedoom in the browser.
And what it proves: an agent can translate tens of thousands of lines of well-documented C into another language and hold itself to an exact standard. It doesn't prove an agent can design an engine from nothing.
I'll be honest about what that is, though. Getting Doom to play was never the goal. It's the proof that the foundation is sound. The question I actually care about is the one after it: now that an agent can write Doom for the browser, how far can I take it to make it my own ? Using other AI tools, and a claude subscription with a quota to use before Tuesday reset.
That's where this goes next, and it's part 3. The engine supports Dehacked, which lets monster stats, animation frames, sounds and text be redefined from a data lump with no engine changes. So a reskin is mostly a new WAD plus a Dehacked lump, and only genuinely new behaviour needs engine code. That's what makes it feasible for someone who isn't a developer (me). The plan: image models for concept art, then into 3D, then rendered back out as sprites from eight angles so everything stays consistent. Go big or go home.
The enemy list is already written and I'm unreasonably pleased with it. You will be fighting Zombie Processes, an Open Bucket that leaks on you, and a boss called The Bill that gets bigger the longer you leave it. If you've ever run a cloud account, you've met all three.
DOOM1.WAD. Playing Doom was never the goal; making it mine isThink I've got the setup wrong, or know a better way to keep an agent honest ? I'm always happy to be proven wrong if it means a cleaner solution.