CSS is DOOMed: Developer Builds Classic DOOM Entirely in CSS 3D Transforms
The Achievement
A developer has built a playable version of the classic game DOOM using only CSS 3D transforms for rendering. Every wall, floor, barrel, and imp is a <div>, positioned in 3D space using CSS. You can play it right now at cssdoom.wtf.
How It Works
The project uses the same data as the original DOOM engine — vertices, linedefs, sidedefs, and sectors — extracted from the original 1993 WAD file. The scene is built from thousands of <div> elements.
The Magic of CSS Math
Each wall receives raw DOOM coordinates as CSS custom properties:
.wall {
--delta-x: calc(var(--end-x) - var(--start-x));
--delta-y: calc(var(--end-y) - var(--start-y));
width: calc(hypot(var(--delta-x), var(--delta-y)) * 1px);
height: calc((var(--ceiling-z) - var(--floor-z)) * 1px);
transform:
translate3d(
calc(var(--start-x) * 1px),
calc(var(--ceiling-z) * -1px),
calc(var(--start-y) * -1px)
)
rotateY(atan2(var(--delta-y), var(--delta-x)));
}
Width comes from hypot() (Pythagorean theorem), rotation from atan2() (inverse tangent). All geometry math runs in the browser's CSS engine — not JavaScript.
Architecture Split
- Rendering: Pure CSS 3D transforms
- Game logic: JavaScript (game loop, player movement, collision)
- Map data: Extracted from original DOOM WAD files
The developer used Claude to help port the original C game loop to JavaScript, focusing their own efforts on the CSS rendering — the truly novel part.
Why This Matters
This project demonstrates how far CSS has come in 30 years:
- CSS
hypot()andatan2()enable real geometric calculations - CSS 3D transforms can handle complex scene rendering
- Custom properties (
--vars) make data-driven CSS practical - Modern browsers can handle thousands of 3D-transformed elements
Try It
The demo is live and the source code is on GitHub. The project also spawned from a previous effort to run DOOM on a 1980s oscilloscope.
With 366 points on Hacker News, this is one of the most impressive CSS demonstrations to date — and proof that CSS is not just for styling anymore.