
There is an unwritten law of the internet: if something exists, someone will try to run DOOM on it. Pregnancy tests, tractors, Flipper Zeros, thermostats. The list is long, it is ridiculous, and it never stops growing.
But this week, developer Niels Leenheer took the joke to a place nobody expected. He built a fully playable version of DOOM where every single wall, floor, barrel, and imp is an HTML <div> element, rendered entirely with CSS. No canvas. No WebGL. Just cascading style sheets doing things they were never supposed to do.
You can play it right now in your browser. Yes, it actually works.
How do you even build a 3D shooter in CSS?
The short answer: with a terrifying amount of math and a deep knowledge of modern CSS features that most web developers have never touched.
Leenheer extracted the original map data from the 1993 shareware WAD file (the same data the original DOOM engine used) and translated every vertex, wall segment, and sector into HTML elements. Each wall gets its raw DOOM coordinates as CSS custom properties. Then CSS does the actual geometry: calculating widths with hypot(), rotation angles with atan2(), and positioning everything in 3D space using translate3d() and rotateY().
The game logic runs in JavaScript. But the rendering, all of it, is pure CSS. JavaScript passes four custom properties to the viewport (player X, Y, Z, and angle), and CSS handles the rest. That clean split between logic and visuals is one of the most elegant parts of the whole project.
Moving the world instead of the camera
Here is where things get philosophically interesting (in a nerdy way). CSS does not have a camera. You cannot point a virtual lens at a 3D scene and move it around. So Leenheer used a classic trick from early 3D graphics: instead of moving the camera through the world, you move the entire world around the player.
Step forward? The world shifts backward. Go up the stairs? The stairs move down. Every movement is inverted. It is disorienting to think about, but it works perfectly in practice.
If you have ever dug into the weird history of game development, you know these kinds of hacks are everywhere. The original DOOM itself was full of them. The fact that someone recreated that same spirit of creative problem-solving using CSS in 2026 is, honestly, beautiful.
Floors are just divs tipped sideways
DOM elements are vertical by default. Floors need to be horizontal. So every floor gets a rotateX(90deg) to flip it into the right plane. Leenheer admits he got the sign wrong the first time. The floor was there, just facing the wrong way, invisible to the player. Classic.
For the irregular shapes that DOOM sectors can take (L-shaped rooms, circular-ish curves, platforms with holes), he used clip-path with SVG paths and the evenodd fill rule. The new CSS shape() function made this cleaner than it would have been even a year ago. Modern CSS keeps getting more powerful, and projects like this are proof.
The spritesheet trick and the zombie march
Enemies in DOOM are 2D sprites that always face the camera (a technique called billboarding). Each enemy has sprites for different viewing angles, and the original game stored only 5 unique sets out of 8 rotations, mirroring the rest. Leenheer replicated this with spritesheets, CSS steps() animations, and a scaleX() flip for the mirrored directions.
One unexpected problem: all the enemies were marching in perfect sync. Every zombieman’s left foot hit the ground at the same exact frame. It looked, in Leenheer’s words, “deeply unsettling.” The fix was a random animation-delay set in JavaScript to offset each enemy’s walk cycle. A tiny detail that makes the difference between “tech demo” and “something that feels alive.”
It started with an oscilloscope
The cssDOOM project did not come out of nowhere. Leenheer had previously built a version of DOOM that ran on a 1980s oscilloscope, which gave him the code to extract maps and a solid understanding of the math involved.
For the JavaScript game loop (the part he considered the least interesting), he used Claude to port the original C source code. The original DOOM source has been public for years, and Leenheer wanted to spend his time on the hard part: making CSS do things it was not designed to do. The full source code for cssDOOM is available on GitHub.
Why this matters beyond the meme
“Can it run DOOM?” is a meme, yes. But projects like cssDOOM are more than jokes. They are stress tests for browser technology. They push CSS to its absolute limits and expose what modern browsers can actually handle. Every wall in the game is using hypot(), atan2(), CSS custom properties, clip-path, and @property declarations. These are not obscure features. They are tools that working web developers use every day, just never at this scale.
Keith Clark built a CSS-only FPS demo years ago that proved the concept was possible. Leenheer took it further by rendering a real, complete game with enemies, doors, lifts, and sprite animations. The gap between what CSS could do in 2010 and what it can do now is staggering.
If you have ever watched speedrunners break games apart or followed indie devs build entire worlds from scratch, you know that the most interesting things in tech happen when someone decides to ignore the rules and just try something absurd.
cssDOOM is absurd. It is also brilliant. And you can play it right now at cssdoom.wtf.
Go ahead. Your browser can take it. Probably.
🐾 Visit the Pudgy Cat Shop for prints and cat-approved goodies, or find our illustrated books on Amazon.



