DOOM is running in pure CSS. Not Canvas. Not WebGL. Just browser primitives most developers don’t know exist. Developer Niels Leenheer built a fully playable 3D first-person shooter where every wall, floor, and enemy is a <div> element positioned in 3D space using CSS transforms. The project is trending #2 on Hacker News today (225 points), with developers split between impressed (“surprisingly fluid and very playable”) and pragmatic (“don’t do this… that fact that it runs doesn’t make it a good idea”). This isn’t just a technical flex. It reveals how powerful CSS has become—and how few developers realize it.
Seven CSS Features Rendering Real-Time 3D
So how does this work? JavaScript handles game logic, but CSS handles all rendering. Leenheer uses the same DOOM engine data—vertices, linedefs, sidedefs, sectors—stored as custom properties. The implementation showcases seven modern CSS features working together:
@property enables animation of custom properties like player position and lighting. Without registered custom properties, browsers treat them as strings—they can’t animate. 3D transforms position walls with translate3d(), rotate floors 90 degrees with rotateX(90deg), and billboard sprites with rotateY() to always face the camera. Clip-path handles sector boundaries and cutouts for pillars and windows. Background-position uses world coordinates to tile textures across all sectors. SVG filters combine feColorMatrix, feTurbulence, and feDisplacementMap to create the Spectre’s shimmering invisibility effect. Anchor positioning makes the HUD responsive without JavaScript calculations. CSS animations drive doors, lifts, sprite cycling, projectiles, and flickering lights.
The viewport setup moves the entire world in the opposite direction of the player rather than moving a camera. JavaScript frustum culling checks each element’s distance and whether it faces the camera. An experimental CSS-only approach uses animation delay tricks, but waits for CSS if() to gain wider browser support. The browser handles depth sorting automatically thanks to DOOM’s 2.5D geometry—no intersecting planes means no Z-fighting.
Performance reality? “We’re asking the browser’s compositor to deal with thousands of 3D-transformed elements,” Leenheer writes. Large maps crash Safari on iOS. This won’t replace WebGL or WebGPU renderers. But it demonstrates what “production-ready CSS features” can achieve when “used in ways their spec authors probably never imagined.”
CSS Transformed While Developers Weren’t Looking
This level of capability didn’t exist a few years ago. CSS evolved from styling language to legitimate rendering engine—and most developers missed it. One analysis puts it bluntly: “If you have not been paying close attention to CSS since 2024, you are going to be surprised. The language has changed more in the last two years than in the previous decade.”
Container queries now respond to parent container size instead of viewport. A card shows one column in a narrow sidebar and three columns in full-width sections—same component, zero media queries. Native CSS nesting eliminated hundreds of lines of Sass compilation. The @property rule added type checking, defaults, and inheritance for CSS variables, making them reliable for complex animations. CSS gained if statements and math functions like modulo in 2025, evolving toward programming language territory.
The timeline tells the story: 2015 saw developers begging for parent selectors, container queries, and native nesting. By 2024, features shipped in all major browsers. In 2025, math functions arrived. Now in 2026, CSS is a legitimate rendering engine. Yet most developers remain unaware.
Why the gap? Frameworks abstract away browser primitives. JavaScript framework hype drowns out CSS updates—opening Twitter or dev.to feels like everyone is shouting about the “next big thing” in JavaScript. CSS quietly became powerful while developers stopped paying attention. Knowledge gaps lead to suboptimal tool selection. Developers reach for JavaScript solutions when CSS already handles the use case.
Use the Right Tool for the Job
Impressive as this is, it raises an important question: should you actually build games in CSS? The Hacker News community answered decisively: “Don’t do this. That fact that it runs doesn’t make it a good idea.” Better advice? “Use 3D CSS to enhance a 2D page with some flair” rather than building actual 3D games.
CSS 3D works well for UI enhancements—card flips, 3D buttons, layered interfaces. Page transitions and parallax effects. Simple 3D effects like rotating product displays. Progressive enhancement that adds 3D flair to 2D layouts. It excels when accessibility matters, since DOM-based rendering works with screen readers.
CSS 3D is the wrong choice for real-time 3D games. Use WebGL or WebGPU. It struggles with large 3D scenes containing thousands of dynamic objects—Canvas or WebGL perform vastly better. Performance-critical applications need proper 3D engines, not CSS hacks.
The tradeoffs matter. CSS offers advantages: DOM-based semantic HTML, declarative syntax that’s easier to reason about, hardware acceleration, and automatic transition handling without external libraries. But limitations bite hard: DOM manipulation overhead, compositor strain with many elements, O(N²) complexity for intersecting planes, and browser inconsistencies (Safari view transitions completely flatten preserve-3d, Chrome textures occasionally disappear).
Firefox’s WebRender handles CSS 3D better than Chrome thanks to GPU-accelerated rendering. But phones still get “toasty” during gameplay. Canvas renders thousands of objects faster at the bitmap level. WebGL handles tens of thousands of polygons at 60fps with GPU matrix transformations.
The decision framework is straightforward: Simple UI effects with accessibility needs? CSS 3D. Thousands of dynamic 2D elements? Canvas. Complex 3D with real-time rendering? WebGL or WebGPU. Many applications benefit from using each technology where it performs best.
Understanding Capabilities Drives Better Decisions
Understanding these tradeoffs matters. CSS 3D transforms are hardware-accelerated in all major browsers. They can render complex scenes, within performance constraints. Modern features are powerful enough for sophisticated effects. DOM-based rendering offers accessibility advantages Canvas can’t match.
Browsers are more capable than most developers realize. Hardware acceleration makes CSS 3D viable for specific applications. Performance remains limited compared to Canvas and WebGL. Browser inconsistencies persist—Safari and Chrome both have quirks.
Don’t copy CSS DOOM for production games. Do understand the principles for appropriate use cases. Consider accessibility implications—Canvas isn’t screen-reader friendly. Evaluate performance requirements before choosing an approach. Stay informed about CSS evolution, not just JavaScript frameworks. Experiment with modern features. Question assumptions about what browsers can and can’t do.
Has CSS Grown Too Complex?
Which brings us to the bigger question: Has CSS grown too complex, or is it finally powerful enough? Both are true. CSS started as a simple styling language. Now it has nesting, variables, math functions, if statements, 3D transforms, and animations. It’s approaching programming language territory. As one critic noted, “It’s still a language designed for styling webpages with 30 years of added features.”
But developers begged for these features for years. Modern web applications need sophisticated styling capabilities. CSS evolution enables possibilities without JavaScript. Better tools produce better results. The real problem isn’t CSS evolution—it’s the developer education gap. Frameworks abstract away browser capabilities, leaving developers unaware of what’s possible.
The solution? Understand the primitives, not just the abstractions. CSS grew up. Developers need to catch up.











