Show HN:把《雷神之锤》移植到安全 Rust,可直接在浏览器里玩
文章摘要
quake-srp 是一个可以直接在浏览器里打开就玩的《雷神之锤》(Quake,id Software 1996 年作品)。项目名里的 SRP 是作者自嘲的「slop rust port」,即「AI 糊出来的 Rust 移植版」。网页本身只是一个游戏外壳:点击开始、捕获鼠标后就能用 WASD + 鼠标玩 id 免费发布的共享版第一章(E1M1–E1M8),页面上附有按键说明、控制台作弊指令(god、noclip、give 等)以及「拖入你自己的 pak1.pak 即可玩完整版和资料片」的提示。真正的技术内容在 GitHub 仓库的 README 和 STATUS 文档以及一段六分钟的讲解视频里。
它是什么。 这是从 id 以 GPL 开源的 WinQuake C 源码逐文件翻译成 Rust 的单人版本:文件格式与 QuakeC 虚拟机、服务端物理、怪物与战斗、基于边排序的软件渲染器、状态栏、菜单、控制台、混音器都包括在内,没有多人模式。作者给自己定了按优先级排列的几条规则:零依赖(只用 Rust 标准库)、不写一行 unsafe(每个 crate 都加了 #![forbid(unsafe_code)])、「经典模式」必须被证明与 id 原版一致,以及代码质量要达到「可展示」的水准。
怎么证明「一模一样」。 这是项目最有意思的部分。作者把 id 的 C 源码无界面地编译出来作为「神谕」(oracle),然后让移植版与它逐项对拍:3D 视图在数千个视角下逐像素比对(包括怪物醒着、正在攻击的场景),状态栏/菜单/控制台的 2D 画面、混音器逐采样比对,演示录像回放时逐帧比对摄像机、所有实体与动态光源。一条命令 classic_check.py 就能跑完十项检查并输出 ALL PASS。README 还专门讨论了「到底和哪个 C 比」:gcc 默认的 x87 浮点会把部分变量留在 80 位寄存器里,结果取决于寄存器分配而非源码本身;而 1996 年玩家实际看到的画面又是 FPU 设为 24 位精度、向零舍入的第三种算术。因此像素检查以 SSE2 构建(严格按 C 声明的类型舍入)为目标,在所有试过的视角下做到零像素差异。
「slop」选项。 除了忠实还原的 Classic 预设,默认的 slop 预设展示「如果硬件不再是瓶颈,软件渲染的 Quake 会是什么样」:按窗口原生分辨率整数倍渲染、宽屏更大视野、取消 72 fps 帧率上限(同时把跳跃、升降机、闪光等按 72 Hz 的手感步进)、怪物在 id 原本 0.1 秒一跳的位置之间平滑插值、火把轻微闪烁、透视校正从每 16 像素一次提高到每 8 像素,以及修了混音器的四个 bug。画面仍然是 8 位调色板、纹理不做滤波。所有与原版的差异都是可单独开关的命名设置。
浏览器里怎么跑。 引擎是一个库,每帧输入玩家操作、输出一张 8 位图像、调色板偏移和声音调用。浏览器版是一个普通的 WASI main 程序,跑在 Web Worker 里:输入事件从 stdin 进入,画面和 PCM 音频通过共享内存交还给页面,用 WebGL2 着色器像 VGA DAC 一样查调色板,AudioWorklet 播放 id 原版混音器的输出,存档和配置以真实文件形式保存在 IndexedDB。渲染器在完成单线程的 BSP 遍历和边扫描后,把画面切成行带分给所有 CPU 核心,且任意线程数下输出逐字节一致。它还支持手柄(带震动)、手机触屏(只能横屏)、离线安装为 PWA。
怎么做出来的。 README 坦白写明:代码和文档全部由 Anthropic 的 Claude 在 Claude Code 中写成,人类负责定规则、试玩和报告问题。大部分工作由「智能体舰队」完成,每个智能体在自己的 git 分支上按书面任务说明工作,再由一个「主持」智能体在完整检查通过后才合并。作者在 HN 上补充说,这是一个历时约四个月的业余项目,「说不清多少时间是在干活,多少时间是在等下一个模型」。
HN 评论精华
这个帖子拿到 236 分、178 条评论,但需要先说明:讨论的大部分篇幅并不在 Quake 本身,而是围绕「这是 LLM 生成的项目,值不值得发到 HN」以及由此延伸出的「AI 克隆/逆向软件的安全隐患」两场争论。技术层面的高质量讨论主要集中在视觉回归测试上。
作者自述与「LLM 是否该被嘲讽」
- airesQ(作者,帖子由他人提交)贴出了六分钟讲解视频,说项目做了约四个月,并直言觉得围绕 LLM 的舆论「出奇地令人难过」:它们烦人、每小时都在犯错,但也很神奇,和它们协作是他多年来最有成就感的事之一。「我们玩了一辈子乐高,现在乐高能听懂我们并帮我们搭建了。」ashkankiani 反驳说「随证据改变观点是美德」这种说法暗含了自己已站在正确答案一边;Palomides 则调侃:喜欢玩乐高的人为什么会乐于把玩乐高自动化?
- onion2k 指出 SRP 就是「slop rust port」,并认为这更像「站在巨人肩膀上」:浏览器渲染、WASM、Rust 几十年的人类积累铺好了路,LLM 只是在最后一刻进场「领奖」。pixelpoet 补刀:其实可以直接把 C 编到 wasm,转 Rust 纯属多余,只是为了能喊「Rust Rust Rust」。
- 质疑派声音不少:IshKebab 认为这对 LLM 来说是小菜一碟,「一年前不可能,半年前有难度,今天微不足道」,因为它可以自己写测试保证逐位一致然后一直跑到通过;flohofwoe 指出所有提交都来自 Claude,并纠正有人说「Quake C++ 代码」的错误——Quake 是 C 写的,id 第一款 C++ 游戏是 2004 年的 Doom 3,另外 C 版本编到 WebAssembly 跑在浏览器里同样「安全」;hn_submit 认为 LLM 移植只是基线,不重构成地道 Rust 就别发出来。
- 支持派则有 davesque、orangedog、psychoslave 等人,认为这只是个有趣的副业项目,没必要苛责;airesQ 回应说如果真那么容易,早该有一堆完整的 Rust 版 Quake 了,但并没有;TeMPOraL 用「你周末做柜子用了工厂木板和电动工具,算不算项目」来反讽这种门槛论。
- dwroberts 从语言角度指出,「safe Rust」只意味着没有
unsafe,C 移植很可能用向量下标绕开借用检查器实现内部可变性,并不等于地道的安全设计。
视觉回归测试:本帖最有干货的分支
- aroman 对仓库里的
oracle目录(用 id 原版 C 做逐像素对比)大为赞叹,称其为「我们集体的新超能力」。ChickeNES 和 Keyframe 说这在 LLM 之前就是常见做法,Dolphin 模拟器的视觉 CI 系统就是典范。 - koito17、tnolet、ffsm8 讨论了网页视觉 diff 的老问题:操作系统和浏览器差异会让像素对比很脆,Playwright 允许设阈值,但 ffsm8 认为这只是缓解而非解决。haukebri 分享经验:不要截全页(滚动条、懒加载、字体时序都会造成抖动),只 diff 小而稳定的区域,并在视觉检查前加一层 DOM 断言。malkia 推荐了 NVIDIA 的 FLIP、SSIM、perceptualdiff 等感知差异算法。
- magicalhippo 说 Claude 最近为他另一个 Quake 项目自发做了同样的事:回放 demo、定期截图逐像素比较,还自己打补丁让游戏完全确定性,并让他录一段含爆炸、水下场景的 demo 来校验,「只用了 20 美元套餐每周额度的 1%」。TeMPOraL 也说在修复一款 1997 年游戏时,Claude 自动产出了无头执行、反编译器、资源浏览器、CRT 模拟器等一整套工具。
安全与「AI 克隆一切」的延伸争论
- King-Aaron 担心同样的手段很快会被用来克隆银行后台、交易系统乃至工业 HMI,从而伪造 API 调用、破坏供应链信任;chii 认为这只是戳破「靠隐蔽求安全」,痛苦越早来越好。hylaride 讲述了与半退休 COBOL 程序员的交谈:金融系统是「分布式单体」,很多 bug 被下游各方以各自的特例处理,根本没法单方面修,重写也解决不了意大利面式的耦合。konart 自称在银行工作,认为某些子系统「已经」或「3–5 年内」就会被这样重写。
- 话题还岔到近期 AI 克隆 Adobe 全家桶的事件:knorker 和 llm_nerd 称这些克隆已能满足日常需求,hypfer 则形容其为「用 vibe coding Rust 写的柏拉图洞穴寓言」;nananana9 半开玩笑地描述了如何「装傻」诱导模型去逆向;TeMPOraL 则说 Claude 在他的游戏修复项目里会主动确保原版资源不进入仓库,「不需要任何花招」。
轻松一面
- CBLT 在源码里搜不到
0x5f3759df,airesQ 指出快速平方根倒数是 Quake 3 才有的;NSUserDefaults 打趣「安全的火箭跳?不太可能」,vintermann 回忆 QuakeC 里把自伤减半的那行代码。koala_man 感叹 1996 年玩 Quake、在 Netscape 2.0 里试 JS 鼠标悬停特效时,绝想不到有一天手机浏览器能跑这个。 - aizk 担心全用 Rust 写的游戏会失去 bug 带来的趣味,kibwen 说 Rust 拦不住物理引擎抽风,马里奥 64 的「平行宇宙」照样存在,随后与 anonymous908213 就 MissingNo 是否源于数组越界展开了一段考据。
- parasti 吐槽自己花五年业余时间手工把 Neverball 移植到网页,一直等最佳时机发布,「结果错过了」。pornel 回应「浏览器玩不了复杂游戏」的说法:WASM 约为原生速度的 50%–70%,对 1996 年的游戏绰绰有余。