打开网易新闻 查看精彩图片

1993年的游戏数据,2025年的浏览器。一位开发者把两者焊在一起,整出了个让前端圈集体沉默的东西——纯CSS渲染的DOOM。

不是Canvas,不是WebGL,是

。几千个

,每个都是墙、地板、油桶或恶魔。游戏逻辑跑在JavaScript里,但画面全靠CSS变形(CSS transforms)硬算。这事听起来像行为艺术,但代码就躺在GitHub上,点开就能玩。

作者叫Håkon,做过更疯的——把DOOM塞进1980年代的示波器。所以这次他开局就有底:地图提取代码现成的,数学公式高中就学过。真正的未知数是浏览器到底能扛多重的CSS。

第一版原型:想全用CSS,连游戏状态都想塞进去

第一版原型:想全用CSS,连游戏状态都想塞进去

最初的手搓版本试图把游戏状态、逻辑、计算全交给CSS。渲染?没问题。状态?勉强能行。逻辑?彻底崩盘。复杂度爆炸后,Håkon把项目劈成两半:渲染继续死磕CSS,游戏循环交给Claude照着原版C代码生成JavaScript。

「原版DOOM源码公开几十年了,手抄一遍没意思。」他在博客里写。这个决定让项目活了下来——也让他能专心折腾真正想探索的东西。

打开网易新闻 查看精彩图片

技术方案直白到近乎粗暴:从原始WAD文件里抽出顶点、线段、扇区数据,转成几千个带自定义属性的

。每个墙元素挂着原始坐标——起点XY、终点XY、地板和天花板高度。CSS接手后续所有计算:宽度用勾股定理,3D变形矩阵实时生成,浏览器负责最终渲染。

浏览器成了意外之敌

浏览器成了意外之敌

现代CSS确实能打,但Håkon撞上的限制也够写份错题集。最大麻烦是Z轴精度:CSS 3D变形用32位浮点,DOOM的坐标系对这个精度来说太野。近距离墙面开始闪烁、撕裂,经典深度冲突(Z-fighting)在浏览器里复活。

他试了各种hack。把场景切成多个层,每层用不同透视原点——不行,接缝处穿帮。最后妥协方案:把世界坐标压缩到CSS能稳定处理的范围内,牺牲部分精度换画面稳定。

另一个坑是纹理过滤。DOOM原版用最近邻采样,像素边缘锋利。CSS的image-rendering: pixelated理论上支持,但实际渲染时浏览器各显神通,有的模糊有的锐化。Håkon被迫接受「每台电脑看起来略有不同」的现实。

性能:比想象中好,比需求中差

性能:比想象中好,比需求中差

打开网易新闻 查看精彩图片

几千个

同时变形,帧率居然能看。Håkon测下来,现代桌面浏览器能稳30帧,复杂场景掉到20。手机?别想了,「能跑,但不算能玩」。

瓶颈不在CSS本身,在DOM。每个墙、每个精灵都是独立元素,浏览器布局引擎要逐个计算。他试过合并同类项,把相同纹理的墙批处理——但CSS变量系统不支持这种动态分组,只能作罢。

最讽刺的发现:GPU加速在这里成了双刃剑。3D变形确实走GPU,但元素太多时,CPU花在准备渲染指令上的时间反而暴涨。Håkon最后做了视锥剔除(frustum culling),只渲染镜头可见的墙面,帧率才回到舒适区。

这项目到底证明了什么

这项目到底证明了什么

Håkon自己列了三条:浏览器比多数人想象的强;CSS比多数人用的强;以及,「用错工具做对事」有时候值得。

前端社区的反应分裂成两派。一派兴奋于CSS的隐藏技能,开始讨论能不能用同样思路做数据可视化或轻量3D界面。另一派皱眉:这明明是WebGL的活儿,硬拧CSS是技术债务的预演。

Håkon的回应藏在项目文档里——他没打算替代任何现有方案,只想知道边界在哪。30年前DOOM逼出了显卡革命,30年后它还在逼浏览器工程师解释为什么Z轴会闪。

代码开源后,有人提交了PR:给恶魔加了CSS动画关键帧,让它们抽搐得更像原版。Håkon合并了。下一步他还没想好,但有个想法在评论区被顶得很高——用CSS变量实现可交互的关卡编辑器,让用户实时拧参数看墙怎么歪。