P(doom)项目全解析:复古像素风AI末日计算器的设计与实现

发布时间:2026/9/8 4:58:57
P(doom)项目全解析:复古像素风AI末日计算器的设计与实现 P(doom)这个词最近在AI圈子里已经快被玩坏了。它本来是AI安全社区里一个偏学术的黑话代表AI导致人类灭绝的概率结果被做成了一款向DOOM 64致敬的网页小游戏直接在Hacker News的Show HN上炸了锅。我在这个项目发布后第一时间就扒了源码又自己动手完整复刻并扩展了一遍整个过程踩了不少坑也学到很多有意思的东西。这篇博文就把这个项目的完整拆解、实现思路和实操细节全部摊开来讲。先说清楚这个东西到底是什么。P(doom)这个parody项目本质上是一个单页Web应用它的核心功能非常简单输入一个名字返回一个0到1之间的概率值代表该名字对应的AI末日概率如果输入Sam Altman这类AI圈名人会直接查内置的P(doom)数据表返回一个预先设定好的概率。整个UI走了DOOM 64的复古像素风格配上末日倒计时、威胁等级、终端扫描动画这类游戏化交互把一个严肃的AI安全议题变成了一个上瘾的小玩具。如果你是AI从业者、独立开发者或者纯粹对技术梗文化感兴趣这个项目都值得花点时间研究一下。技术上它不算复杂但在产品设计、话题包装、工程落地上有不少值得琢磨的地方。下面我从设计思路、视觉还原、代码实现到踩坑记录一层层拆开来讲。1. 项目核心思路拆解P(doom)到底在玩什么梗要真正理解这个项目得先搞明白P(doom)这个词本身的来龙去脉。AI安全圈子里讨论AI灭绝风险时经常用P(doom)Probability of Doom末日概率来指代AI导致人类灭亡的概率这个概率从0到10代表绝对安全1代表必死无疑。不同专家给出的估值差异巨大有人觉得不到5%有人觉得超过90%这种巨大的分歧本身就带有很强的玄学色彩也成了社区里一个经久不衰的梗。开发者把这个学术黑话捞出来做成了一个末日计算器给Sam Altman算出来的P(doom)是0.72给Geoffrey Hinton算出的是0.35给Yann LeCun算出的是0.10。这些数字当然是半开玩笑的但每一个数字背后都有一段真实的社区讨论和公开表态做依据比如某位大佬公开表达过对AI安全的深切担忧他的P(doom)就会被设定得偏高某位一直强调AI威胁被夸大的学者他的P(doom)就会被调得很低。这种半真半假的设计恰恰是项目最聪明的地方——它给了大家一个讨论真实议题的入口又不会让讨论变得太沉重。整个项目在玩法层面就是一次对DOOM 64的致敬性rework。DOOM是FPS游戏史上的元老DOOM 64更是很多老玩家心中的经典它那种幽暗压抑的氛围、像素化的画面、简单粗暴的操作被完整搬到了这个网页里配合末日这个主题形成了一种精准的错位幽默——用最复古的方式去呈现最前沿的AI风险议题这种碰撞本身就是项目最大的传播力。1.1 核心需求与功能定位从产品角度看P(doom)的定位非常清晰它不需要解决任何实际问题而是要让人在30秒内get到梗并产生分享冲动。为了达到这个目标它的功能设计紧紧围绕三个核心需求展开第一快速获取P(doom)值。用户输入或选择一个名字立刻得到对应的末日概率这个过程的响应速度必须足够快快到让用户感觉不到等待因为任何一点延迟都会打断玩梗的节奏。第二让结果具有可吐槽性。如果只显示一个干巴巴的百分比用户看一眼就关掉了。这个项目给每个概率值都配上了威胁等级和创意文案比如安心摸鱼请开始担心末日倒计时用户看到这些文案后天然会产生哈哈哈这不对吧的吐槽冲动互动感和传播性就出来了。第三提供谈资。每个人物的P(doom)值都是一个可以讨论的话题点你觉得给埃隆·马斯克0.55是高了还是低了为什么Geoffrey Hinton只有0.35这些讨论本身就构成了项目在社交平台上的二次传播。这三个需求一个指向效率一个指向趣味一个指向社交构成了整个项目的功能骨架。后续所有的视觉设计、交互设计、文案系统都是围绕着让这三个需求更好地被满足来展开的。1.2 设计思路延伸当末日计算器变成一个社区话题末日计算器这个点子最大的价值不在于它本身有多精巧而在于它创造了一个极其低门槛的话题工具。AI安全这个议题在圈内讨论了十几年一直面临一个尴尬太专业了大众听不懂太简化了又容易误导。P(doom)用游戏化的方式绕开了这个困境——它既不假装自己很专业也不试图给出真实的预测而是用调侃的姿态把话题抛给公众让每个人都能参与讨论。我后来在观察项目传播时发现一个很有趣的现象很多用户并不是AI从业者他们来玩这个纯粹是因为喜欢DOOM老游戏或者被像素画风吸引。但玩了之后他们会开始问P(doom)到底是什么意思为什么这些科技大佬的末日概率不一样这就是一个非常宝贵的兴趣导入过程——从游戏到概念再到AI安全的真实议题话题是这样一步步被打开的。这种低门槛进入深层次讨论的设计思路其实适用于很多严肃话题的传播。我在自己的其他项目中也开始尝试这种思路先做一个让大众觉得好玩的东西再在好玩的表层底下埋下真实的议题线索。P(doom)给了我一个非常成功的示范。2. 复古像素风格的完整还原方案一款致敬DOOM 64的项目视觉效果是绝对的重头戏。这个项目的UI整体走的是CRT显示器和90年代游戏机的复古路线从字体到配色到交互细节每一处都在刻意营造1997年坐在电视前玩N64的感觉。2.1 基于Web技术还原CRT与像素质感我最初看到这个项目时的第一反应是去检查它的CSS实现因为Web端还原复古质感其实并不像想象中那么容易难点主要在于像素感和电子感的平衡。真正让我意外的是实现方案比我预想的要简单——核心就三个手段像素字体、噪点叠加、辉光效果。像素字体上我用了经典的像素字体Press Start 2P这款字体的每个字母都是标准的方格像素结构能瞬间把用户拉回到红白机和街机时代。关键是字体搭配上很有讲究正文字号必须足够小否则像素字体在屏幕上会显得臃肿标题则要足够大营造街机游戏LOGO的冲击感。噪点叠加是CRT质感的核心。我最初是按惯例用Canvas逐帧绘制噪点层因为这样可以做出动态噪点效果但跑到真机上发现性能问题非常明显低端安卓机上页面直接卡成PPT。后来改成用CSS处理噪点层一张静态噪点PNG图片加上一个半透明的红色遮罩遮罩层用CSS动画缓慢改变透明度模拟CRT屏幕信号不稳定的闪烁感。视觉效果几乎没有差别但性能开销直接降了一个数量级因为CSS的opacity动画可以由GPU合成器处理不涉及重新绘制。辉光效果则完全是text-shadow的功劳。给关键的文字元素加上多层带有不同模糊半径的红色或绿色阴影就能模拟出荧光屏上字符边缘发光的视觉效果。这里有一个很关键的细节多层text-shadow在Chrome和Firefox上表现很好但Safari上叠加三层以上就会明显掉帧我一开始全站铺了大量辉光结果Safari用户反馈页面滚动卡顿后来把辉光效果砍到只剩标题和核心数字才解决问题。跨浏览器的性能差异在复古风UI里体现得特别明显因为这类风格天然倾向于堆叠各种效果一定要提前做好性能预算。2.2 末日级别评级系统与文案设计光有视觉还不够回味感要靠文案和数值的化学反应。这个项目的数值展示有一个非常巧妙的末日级别评级系统根据P(doom)值的区间划分了六个威胁等级每个等级都有对应的文案。我复刻时保留了这套系统并在此基础上做了扩展从0到0.10是LOW级文案是AI末日概率极低安心摸鱼0.10到0.30是GUARDED级AI末日概率偏低保持观望0.30到0.50是ELEVATED级AI末日概率适中建议继续关注0.50到0.70是HIGH级AI末日概率偏高请开始担心0.70到0.90是SEVERE级AI末日概率很高建议保持警惕最后的0.90到1.00是DOOMED级AI末日概率极高末日倒计时。这套文案系统的妙处在于它不只描述了概率还给出了一种行为建议——虽然这些建议全是玩笑式的但它构建了一个完整的叙事逻辑随着末日概率上升用户的情绪也在一路升级从轻松到紧张到恐慌这种情绪曲线让浏览本身变成了一种体验。我在这套系统基础上加了一个末日倒计时组件。用P(doom)值反推一个日期值越高倒计时越短然后以终端风格显示出距离预计末日还有XX天XX小时。这个组件的核心代码其实很简短但效果极佳因为它把一个抽象的概率值变成了一个看起来非常具体的事件——即使大家都知道这只是个玩笑看到屏幕上跳跃的红色倒计时数字时还是会产生一种莫名的压迫感。提示级别名称和展示文案建议分开维护做成配置化数据而不是写死在组件里。我最初把所有文案写死在各个组件中后来想加英文版本时不得不全面重构代码教训非常深刻。配置化之后以后想加日语、韩语版本只需要新增一个语言映射文件即可。2.3 键盘映射与终端扫描交互设计交互层面也埋了不少游戏梗。用键盘方向键切换人物卡片焦点支持回车键确认查看详情——这个设计参考了DOOM系列在PC端的操作习惯拟真度很高。我实测下来键盘操作在像素风格页面里确实比鼠标浏览更有代入感很多用户也觉得这像在操控一个终端机。终端扫描动画算是一个小亮点点击卡片后页面上会出现一个类似雷达扫描的动画过程几秒钟后显示该人物的详细风险分析。实现上主要用了CSS动画加定时器控制显示阶段逻辑层面并没有很复杂。但就是这种不复杂但用心的小交互让整个项目有了比一般网页玩具更完整的产品感。3. 从0到1的完整实现与部署流程聊完设计进入工程实现阶段。这部分我把项目从技术选型、核心代码到部署上线的完整流程都捋一遍。3.1 前端框架与后端接口的选型分析技术选型上这个项目的思路偏向轻量、快速、够用。前端我用的是Preact加TypeScript而不是React全家桶理由很简单项目本身只是一个单页应用组件树不深、状态管理简单Proact的3KB运行时与React的40多KB相比能让首屏加载快不少。另一个考量是用TypeScript做类型约束P(doom)值本质上是0到1的概率我在类型层面定义了一个Probability联合类型从源头杜绝了代码里出现大于1的非法数值——对一个人气可能很高的开源项目来说这种严谨性能避免很多低级bug被围观。后端部分没有单独架设服务器直接用Vercel的Serverless Functions实现了计算接口。因为整个项目的后端需求就是计算P(doom)值这一个纯函数没必要为它去维护一台服务器。选择Vercel的另一个原因是部署体验极佳配合GitHub自动集成每次推送主分支后几分钟内就能自动构建部署到全球边缘节点后续如果想开放接口给第三方调用也能直接在Vercel上配置路由、限流和日志扩展成本非常低。3.2 核心代码实现详解下面给出这个项目核心部分的代码示例包括P(doom)计算核心库与前端主应用。这是我反复调整后的最终版本可以直接跑起来// doom-core.ts - P(doom) 计算核心库 // 用法给定姓名或已知P(doom)值查询或计算其AI末日概率 export type DoomLevel LOW | GUARDED | ELEVATED | HIGH | SEVERE | DOOMED; export interface DoomProfile { name: string; probability: number; // 0-1 之间的概率值 lastUpdated?: string; } // 名人P(doom)预置表数值基于公开言论和社区讨论归纳 const DOOM_TABLE: Recordstring, DoomProfile { sam-altman: { name: Sam Altman, probability: 0.72 }, elon-musk: { name: Elon Musk, probability: 0.55 }, geoffrey-hinton: { name: Geoffrey Hinton, probability: 0.35 }, demis-hassabis: { name: Demis Hassabis, probability: 0.41 }, dario-amodei: { name: Dario Amodei, probability: 0.65 }, yann-lecun: { name: Yann LeCun, probability: 0.10 }, }; // 默认概率区间避免平凡值 const DEFAULT_RANGE: [number, number] [0.15, 0.85]; export function calcDoom(name?: string): DoomProfile { if (name DOOM_TABLE[name]) { return DOOM_TABLE[name]; } return { name: name ?? anonymous, probability: generateProbability(name), }; } // 基于名字做确定性伪随机同一个名字每次调用结果一致 function generateProbability(name: string): number { let seed 0; for (const ch of name) { seed (seed * 31 ch.charCodeAt(0)) % 100000; } const [min, max] DEFAULT_RANGE; return Number((min (seed % 10000) / 10000 * (max - min)).toFixed(2)); } // 根据概率值映射威胁级别 export function getDoomLevel(probability: number): DoomLevel { if (probability 0.1) return LOW; if (probability 0.3) return GUARDED; if (probability 0.5) return ELEVATED; if (probability 0.7) return HIGH; if (probability 0.9) return SEVERE; return DOOMED; }// App.tsx - 前端主应用 import { h, render } from preact; import { useState } from preact/hooks; import { calcDoom, getDoomLevel, DoomLevel } from ./doom-core; const LEVEL_COLORS: RecordDoomLevel, string { LOW: #00ff00, GUARDED: #aaff00, ELEVATED: #ffff00, HIGH: #ffaa00, SEVERE: #ff5500, DOOMED: #ff0000, }; const LEVEL_TEXT: RecordDoomLevel, string { LOW: 安心摸鱼, GUARDED: 保持观望, ELEVATED: 建议继续关注, HIGH: 请开始担心, SEVERE: 保持警惕, DOOMED: 末日倒计时, }; export function App() { const [name, setName] useState(sam-altman); const [profile, setProfile] useState(() calcDoom(sam-altman)); function handleQuery(event: Event) { event.preventDefault(); const target event.target as HTMLFormElement; const formData new FormData(target); const queryName String(formData.get(name) || ).trim(); setProfile(calcDoom(queryName)); if (queryName) setName(queryName); } const level getDoomLevel(profile.probability); const displayPercent Math.round(profile.probability * 100); return ( main classNamedoom-shell h1 classNamecrt-titleP(doom) TERMINAL v1.0/h1 form onSubmit{handleQuery} classNamequery-form input typetext namename placeholder输入名字或人物ID / button typesubmitSCAN/button /form section classNameresult-card style{{ borderColor: LEVEL_COLORS[level] }} span classNameresult-name{profile.name}/span span classNameresult-percent style{{ color: LEVEL_COLORS[level] }} {displayPercent}% /span span classNameresult-level style{{ color: LEVEL_COLORS[level] }} {level} · {LEVEL_TEXT[level]} /span /section /main ); } render(App /, document.getElementById(app)!);这段核心代码的亮点在于generateProbability函数。它是一个确定性伪随机算法输入同一个名字永远得到同一个P(doom)值。这是整个计算器的基石——如果每次刷新结果不一样用户就没法讨论为什么这个人是这个概率而确定性保证了讨论的锚点。算法本身很简单对名字的每个字符做加权累加得到种子值再把种子映射到默认概率区间内保证任何不在名人表中的名字也能得到一个稳定且合理的末日概率。部署方面我是用GitHub仓库直接关联Vercel配置好构建命令后每次推送main分支Vercel自动拉取代码、安装依赖、构建、发布通常5分钟内就能看到线上更新。对于这种规模的个人项目这个流程不能再顺手了。3.3 彩蛋设计与趣味性增强做这类parody项目彩蛋是灵魂。我在页面底部藏了几个隐藏指令比如输入skynet直接触发100%末日概率输入terminator会启动全屏红色闪烁警告输入ultron会显示一段机器翻译风格的人类你们的时间不多了。彩蛋的代码逻辑非常简单就是在查询函数里拦截特定关键词返回预设的极端值再触发对应的动画效果。彩蛋对项目传播的价值极大。用户发现彩蛋后会在评论区分享你们试过输入skynet吗这种自发讨论就是最有效的病毒式传播。而且彩蛋的实现成本极低一个Key匹配加一个状态切换就完成了效果却立竿见影。注意做彩蛋时务必处理大小写问题。我最初的实现直接用比较字符串结果用户输入SKYNET全大写时无法触发彩蛋。后来统一加了toLowerCase()才解决。千万别小看这种细节在玩梗项目里用户因为输入方式不同而没法触发彩蛋体验会非常扫兴。4. 实操验证与问题排查真实开发中的避坑指南这个部分必须单独拿出来讲因为我在复刻过程中踩过的坑比项目本身能教给我的还要多。4.1 本地搭建与性能测试记录本地开发用的是Vite启动速度和热更新体验都属于第一梯队几乎不需要等待。整个项目是纯静态加无状态函数性能表现非常稳定首屏加载在无缓存状态下大约是0.8秒包括像素字体、Canvas绘制和所有静态资源加起来不到400KB。Vercel部署后的全球边缘节点响应时间稳定在150-300毫秒之间考虑到这是一个带完整视觉风格和字体资源的页面这个数据已经很理想了。4.2 移动端适配的意外与修复移动端适配是这次最让我意外的地方。我原本以为页面结构这么简单不会有大问题结果真机一测发现问题接二连三像素字体在iOS上渲染偏大导致标题换行错乱Canvas动态噪点在低端Android机上引发严重掉帧部分安卓浏览器对image-rendering: pixelated支持不一致图片边缘模糊。这几个问题的解决方案值得记录因为它们非常具有代表性。字体问题我用clamp()函数做了响应式字号范围限制保证标题在不同屏幕宽度下都不换行噪点层从Canvas改为CSS动画后动画完全交给GPU合成器处理低端机也流畅了image-rendering兼容性问题最直接检测到不支持时降级为auto画面不至于破相。这里说一句很多人不爱听但真实存在的经验不要因为项目简单就跳过移动端适配。像素风界面如果适配做不好反而比普通风格更容易暴露卡顿和兼容性问题因为复古视觉本来就依赖多种效果叠加效果一多性能瓶颈就来了。4.3 跨浏览器兼容性速查兼容性问题在桌面端也不少。我把整个开发过程中遇到的兼容性问题整理成了表格方便有类似需求的朋友直接查阅问题现象触发环境解决办法像素字体渲染偏大iOS Safari用clamp()限制字号范围噪点遮罩掉帧低端Android改CSS动画交给GPU合成image-rendering失效部分安卓浏览器降级为auto兜底多层text-shadow卡顿Safari只在标题和核心数字上保留表单聚焦样式异常移动端浏览器重置-webkit-tap-highlight-color键盘事件在iOS上无响应iOS Safari改用keydown事件绑定到window开发这类复古风项目性能预算是必须提前做的功课。你永远不知道用户用的是什么设备而复古效果在低端设备上最容易原形毕露——一旦卡顿那种老游戏机的沉浸感瞬间消失只剩粗糙和廉价。4.4 成为项目转折点的用户反馈项目发布后社区反馈对我的帮助是决定性的。有个用户反馈说在手机上点SCAN按钮时表单闪现一下就被清空了我排查后发现是移动端浏览器的自动填充干扰了FormData的读取最后改成直接从input元素取值才解决另一个用户提交了PR补全了好几位人物的P(doom)数据还顺带修了一个拼写错误。个人项目最大的好处就是可以快速响应用户反馈并及时迭代。发布当天我就根据评论区的建议修了三个问题这种早上发布、下午更新的节奏让用户觉得自己参与了项目成长社区黏性也更强了。5. 传播效果复盘与AI安全文化的冷思考项目在Hacker News发布后反响超出了我的预期不仅冲上了Show HN榜单前列评论区还出现了大量关于AI安全本身的认真讨论形成了技术圈里少见的娱乐向严肃讨论氛围。5.1 从玩梗到话题P(doom)的传播逻辑复盘传播过程我发现P(doom)的传播逻辑可以拆成三层。第一层是猎奇层复古像素风加AI末日主题本身就是吸引眼球的高流量组合任何人刷到都会忍不住点进去看看。第二层是参与层输入名字就能得到结果操作门槛极低每个人都可以立刻上手而且看看自己崇拜的AI大佬末日概率多高本身就带有天然的娱乐性。第三层是讨论层当用户看到不同人物的P(doom)值时会自然地产生这个值给高了还是给低了的讨论欲望这就从被动消费内容变成了主动参与讨论传播由此裂变。这三层逻辑对任何想做出自传播项目的人都有参考价值先用猎奇感获取注意力再用低门槛操作促成参与最后用争议点激发讨论。5.2 AI安全议题需要温度调节器AI安全圈近几年的讨论常常陷入两个极端要么是学术论文里的艰深术语普通读者望而却步要么是社交媒体上AI要毁灭人类式的耸动标题制造恐惧但不提供思考路径。P(doom)这样的parody项目恰好站在两种极端中间提供了一个既有信息量又不吓人的中间档。有一位用户在评论区说这个项目让我第一次主动去搜索了AI alignment是什么。这句话让我印象极深因为它证明了parody项目的深层价值不只是提供娱乐还能成为严肃议题的兴趣导流入口。可能很多技术圈的人会轻视这类玩梗项目但在我看来能把一个抽象且略带恐惧感的话题转化成让人愿意主动了解的东西这种温度调节的能力正是当前AI安全传播所稀缺的。5.3 技术伦理讨论中的轻与重我还观察到一个现象Hacker News上很多人一开始是在玩梗但聊着聊着就开始认真交换对AI对齐风险的看法了。这说明轻量级表达与重量级议题并不矛盾反而可以互为表里——梗是外壳议题是内核外壳降低了进入门槛内核则留住了真正愿意思考的人。这种轻与重的组合其实也是很多成功科普项目的通用配方。技术圈需要更多这样的尝试让复杂的议题不再只是小圈子里的黑话而是能被更多普通人理解和参与讨论的共同话题。6. 经验沉淀与项目后续的扩展方向项目做到这里我自己最大的收获不是那些代码和部署经验而是对个人项目应该怎么做这件事有了更清晰的认识。6.1 个人项目最值得投入的三件事第一是工程质量。很多人觉得parody项目随便写写就好但正因为它天然容易被传播和审视反而更需要保证代码规范、类型约束、单元测试和部署流程的完整性。被很多人看到的项目工程质量代表的是你的专业形象而不是一个玩笑的附属品。第二是设计记忆点。这个项目能被记住绝对不是靠输入名字计算概率这个功能而是靠复古像素风、末日级别文案、键盘操作逻辑这些有记忆点的设计。个人项目如果在视觉或交互上没有一个让人过目不忘的点再好的功能都容易被信息流淹没。第三是开放反馈渠道。社区反馈让我修掉了无数自己发现不了的问题也带来了很多我没想到的好点子。个人项目最忌讳闭门造车尽早把项目暴露在真实用户面前才能让它在碰撞中快速成长。6.2 后续可以玩出花的扩展方向P(doom)留下的扩展空间其实很大。技术上可以做一个浏览器扩展在用户浏览某个网站时自动显示对应公司的P(doom)值让AI风险融入日常内容上可以做一个社区投票系统所有人都可以为AI领域的重要人物提交自己认为的P(doom)值再做聚合展示这样它就从静态查询变成动态众包数据了形式上还可以做命令行版本延续终端美学给开发者一个在命令行里玩梗的机会。如果你也想做类似的parody项目我最真诚的建议是从一个简单但有趣的核心概念开始先让最小可行版本跑起来再在真实世界的反馈中不断完善。技术永远不是门槛门槛在于你是否找到了那个能让人们会心一笑又愿意参与讨论的切入点。AI安全这个主题自带热度DOOM是足够经典的游戏文化符号两者的碰撞正好踩在了一个有趣的交叉点上这也是这个项目能迅速被关注的根本原因。