The project's README from github.com/boyang-hu/website-rebuild-skill. As one markdown file: README.md.
中文 | English
给一个网址,让你的 AI agent 把那个网站逐行复刻出来,并且能证明复刻得对。
它不是"做一个看起来很像的页面"。它把源站的实现当作规格书:先把整站抓成只读证据,再从压缩过的代码里逐行还原逻辑,最后用一整套自动验收门证明"复刻侧和源站在做同一件事"——包括逐像素比对。
遵循 Agent Skills 开放规范,为任何支持 skills 的智能体设计。跨运行时不是口号而是实测:验证清单里既有 Claude Code 跑完的目标,也有 Codex 全程跑完的目标(Hashgraph VC,166/166 响应字节一致)——同一份 skill 目录,放进哪个 runtime 都能走完整条管线。
每张图左半是源站的只读镜像,右半是复刻侧,均取自各项目验收时的对拍截图:同视口、同滚动位置、同动画时刻。除注明者外,所示帧均为逐像素一致(meanAbsDiff 0.00)。
lusion.co —— 1.25 MB 自研 WebGL 引擎 + 156 个 shader。3D 物理堆叠的姿态来自模拟本身,钉死模拟随机态后两侧逐像素一致。
apple.com/airpods-pro —— 565 个 webpack 模块逐字移植,9 个滚动检查点逐像素一致,此为首屏。
hubtown.co.in —— Theatre.js 驱动的全屏 WebGL 长镜头(Nuxt 3 + three.js)。实时渲染帧,像素差落在同侧噪声带内(meanAbsDiff 0.96)。
samsy.ninja —— 赛博朋克 WebGPU 实时场景,238 MB 重资产。两侧各自实时渲染同一时刻,胶片颗粒噪声为场景自带。
www.on.energy —— Nuxt 3 + WebGL GLB 场景 + Storyblok headless CMS。页顶视频两侧钉到同一帧后,逐像素一致。
raycast.com/keyboard —— 判级到源码化单次会话跑完。注意键盘上方那条未加载的懒加载占位条:两侧一模一样——bug 与怪状态照抄不修,这正是纪律第 4 条。
| 依赖 | 版本 / 说明 |
|---|---|
| Node.js | ≥ 22(内置 fetch / WebSocket 直连 CDP) |
| Chrome / Chromium | 本机安装,无头对比用 |
npx |
个别工序 spawn 钉死版本的外部工具(从不 import) |
两种方式都行,装的是同一份目录。
方式一:npx(一条命令,不用克隆仓库)
npx website-rebuild-skill # → ~/.claude/skills/website-rebuild
npx website-rebuild-skill --project # → ./.claude/skills/website-rebuild
npx website-rebuild-skill --dir <skills 目录> # 其他 runtime,目录名 website-rebuild 会自动追加
安装器只拷文件——不跑 skill、不开浏览器、不联网,本身零依赖。拷完按 sha256 逐文件双向校验,全部匹配才算成功;目标已存在会打印在装的版本并拒绝,要 --force 才替换。--dry-run 可以先看它打算写什么。
方式二:手动拷贝(已经克隆了仓库)
把 skills/website-rebuild/ 整个目录放进你的 agent 的 skills 目录。以 Claude Code 为例:
# 用户级(或项目级 .claude/skills/)
cp -R skills/website-rebuild ~/.claude/skills/website-rebuild
其他支持 Agent Skills 规范的 runtime,按其各自的目录约定放置同一份目录即可。
给你的 agent 一个网址,说"复刻这个站"或"1:1 rebuild 这个网站"。
过程中它会来问你:复刻范围(整站还是指定页面)、做到哪一级(L1 镜像存档 / L2 工程化复刻 / L3 源码化——梯子单调,选低不亏,以后随时续跑升级)、外部依赖怎么处置、以及所有涉及"能不能公开"的判断。这些是你的决定,agent 不会替你做。
大概要多久:工期随版本一路收敛——早期项目按周计,现在中小型站(几十条路由以内)一次会话内无人值守跑完判级到源码化全程,重 WebGL / 自研引擎的站约 1–3 天。agent 会在开工前给出难度评级与预估。
你给一个网址,agent 会自己走完这条链路:
| 阶段 | 它做什么 | 你会看到 |
|---|---|---|
| 判级 | 先探测这个站属于哪一类,能不能做 | 判级结论与依据;不能做会直接说明原因,不会硬跑产出垃圾;已消失但有存档的站转入 Wayback 抢救 |
| 镜像取证 | 把整站抓成只读快照,断网也能跑起来 | 一份逐文件带校验和的镜像与账本 |
| 逆向 | 把压缩过的代码展开,让复刻里的每一行都能指回源站的哪一行 | 一份逆向笔记,说明这个站是怎么实现的 |
| 移植 | 逐行还原到你自己的工程里,每处改动都标注源码出处 | 可运行的复刻工程 + 逐条登记的差异表 |
| 验收 | 自动比对两侧:控制台、网络、DOM、几何、像素 | 量化报告;差异要么被修掉,要么被登记,不许糊过去 |
| 收口 | 逐模块清点有无遗漏,并整理版权事实 | 审计记录 + 一份待你裁定的部署评估 |
| 源码化 | 把逐字移植的产物变成人能读的工程:拆模块、给变量命名、补注释、复制资产(无模块容器的产物走拼接式分解——切成语义命名的部件,按序拼回逐字节等于原件) | 一个可以复制到任何地方独立运行的源码工程,且每次启动前自动做逐文件字节自证 |
它盯着的是"对不对",不是"像不像"。一个自研 WebGL 引擎站的复刻,三条路由做到了跨侧逐像素一致(meanAbsDiff 0.00),最终产出 389 个源码模块、中位数 18 行;一个 44.9 万行的 Nuxt/Vite 站,拆成 2,043 个语义命名部件、按域折进 scene/camera/wave 等目录后,逐字节重拼一致。
⭐ 最后一步是"源码化",而它必须排在最后。 重构最怕改完不知道有没有坏;这里在动手之前已经有了一个逐像素精确的裁判,所以每一次拆分、每一次改名都能被证死。没有裁判的重构是盲改。
⭐ skill 的终点也在这里:到"人能读懂的真实"为止。 拿产出去做你自己的项目(脚手架、fork、二次创作)是你的工程,不是它的阶段——它不替你起名字、写故事、换内容,因为那些决定只有你自己能做。但它留了一样别处没有的东西:交付物自带的字节清单与重拼门,让你 fork 之后精确地知道自己每一步偏离了源站什么。交接指南见 beyond-the-rebuild.md。
它们不是风格偏好。这六条是从实践里挨个撞出来的,违反任何一条都会在后面的阶段以 bug 的形式偿还:
⚠ 第 3 条在最后的源码化阶段有一条明确边界:在人写的那份源码里重命名、拆模块、补注释不算"发明"——那一份是显式登记的衍生物,不是对源站的断言。但两条硬线不动:不许顺手重构(合并重复、提取公共函数、改算法都会让"等价"变得无法判定),以及注释里的推测必须标注成推测。
| 场景 | 覆盖情况 | 实测规模 |
|---|---|---|
| 命令式 WebGL / Canvas 场景 | three.js、自研引擎、GLSL/TSL 逐字提取 | 1.25 MB 单 bundle + 156 个 shader;另一站 47,224 行 three 引擎 |
| GSAP 时间轴 / 滚动叙事 | 时间轴、ScrollTrigger、自研输入状态机 | 多个获奖作品集站 |
| 烘焙动画与私有二进制格式 | GLB / .buf / .riv / KTX2,反解成可校验的数值 |
53 个几何文件、170,289 顶点,格式从代码里逆出 |
| 静态构建器产物 | Astro / Nuxt SSG / Webflow 导出壳 / Vite / webpack | 单页站、SSG 站、导出壳站各若干 |
| 各种代码形态 | 压缩、混淆、未混淆都可以 | 全混淆 47k 行;未混淆 974 行;还有完全没有 bundle、逻辑写在模板内联块里的站 |
| 多语言 / RTL 站 | 双语路由成对对账、dir=rtl 布局、PJAX 转场 |
一个 en/ar 122 路由站(首个 RTL 样本) |
| 音频行为站 | 声音作为验收面:音频引擎池普查(全量 loaded、零音频 404、零外联)、运行时拼 URL 的音频族"池子即账本"采集 | 一个 98 音效池的游戏音频工作室站(主题音乐 + 逐控件交互音效,双编码) |
| B 类:平台层剥离 | Shopify(平台 / 应用 / 上游主题 / 站点自研四层分离) | 两个 Shopify 店铺,其一是主题 fork 的定制店 |
| B 类:第三方资产桶 / headless CMS | Storyblok(/m/ 变换接口)、Strapi 上传桶全量镜像 |
一个 ~1,800 图的 CMS 桶 + 一个 864 MB 的 Strapi 桶 |
| B 类:序列化数据块展开 | Nuxt 等 SSG 把数据编码进页面的形态 | 一个 63.5 KB 的数据块(占文档 54%),展开为 566 KB 结构化数据并逐项比对 |
| X 类:失效站存档抢救 | Wayback CDX 枚举 → 锚点+时间窗选连贯捕获 → id_ 原始字节 → 标准镜像;永久洞如实登记,别名回填单列,停车页验尸挡 200 型夺舍 |
五次抢救、五种形态实测:域名易主(8/15 路由)、平台回收(9/9 全清)、原地停车替换(0 洞 0/0/0)、DNS 消亡+停车夺舍(first-launch,走完 L3 全程)、清单驱动站画面层全失(mustachelab,引擎救回+失败形态入册) |
| C2 类:声明式组织的现代全栈站 | Next.js App Router(webpack / Turbopack)、Nuxt 3 + Vite、R3F、Theatre.js——RSC flight 与 devalue 载荷、服务端图片端点、会话态预取、编译组件的逐字图内嵌(转写微运行时)都有对应处理 | 七个 C2 目标:115 路由全站(115/115 跨侧一致)、Three r182 WebGPU/TSL 站、Theatre.js WebGL 长镜头站、产品页(4 检查点像素全零)、重 WebGL 工作室站(C1+C2 混合,144 路由)等 |
| 类 | 类型 | 原因 |
|---|---|---|
| C1 | 服务端组件站(RSC / Next.js App Router) | 服务端组件源不下发,但它的完整输出(flight 流)内联在每页 HTML 里就是规格书。⭐ v0.3 起可做:重构式逆向——重构一个可构建的 Next 工程,flight 语义门收口(实测 rauchg.com 18/18、basement.studio 144/144 路由一致)。没有逐字 port,产物是"人写的源码 + 门证明的等价" |
| D | 服务端行为站 | 行为主体在服务端(CMS、电商库存、A/B 分桶、个性化),客户端没有可移植的目标,也没有确定性的验收基准 |
| X(无存档) | 已消失且 Wayback 无覆盖的站 | 彻底没有可镜像的对象。⭐ 有存档的 X 站可以抢救(见上表);历年获奖站实测消失率约 29%——这也是"第一时间镜像"成为第一条纪律的原因 |
三类各自的实测样本见下文已验证过的网站。
用 wget、HTTrack、SingleFile 之类的工具把网站抓到本地,也能双击打开、也能离线跑。如果你只是想留个存档或本地看看,那些工具就够了,不必用这个。
区别在于:扒站回答"它长什么样",复刻回答"它是怎么做到的"。
| 扒站 / 镜像 | 工程化复刻 | |
|---|---|---|
| 你拿到的 JS | 压缩混淆后的产物,一行几十万字符 | 模块树:389 个文件、中位数 18 行,每个文件头标注它来自源站的哪几行 |
| 变量名 | e、t、r——压缩器抹掉的信息回不来 |
有证据可依的逐个还原;⛔ 没有证据的宁可不改——错的名字比 e 更有害 |
| 第三方库 | 和业务代码糅在同一个文件里 | 剥离出来,按源站声明的版本从 npm 装回(版本号是从代码里取证的,不是猜的) |
| 能不能改 | 能改,但你不知道改了什么、也不知道会坏什么 | 能改,而且一整套自动检查会告诉你坏没坏 |
| 怎么知道对不对 | 打开看一眼,觉得像 | 控制台 / 网络 / DOM / 几何 / 逐像素五层自动比对,差异要么修掉要么登记 |
| 学得到东西吗 | 学不到——你没有读懂任何一行 | 产出里包含一份逆向笔记:这个站的动画怎么编排、场景怎么组织、数据怎么烘焙 |
| 能不能带走 | 能,但它只是那堆文件 | 复制到任何地方、断网安装、直接跑——资产、构建配置、开发服务器都在里面 |
| 典型产物 | 一堆文件 | 可运行工程 + 逆向笔记 + 差异登记表 + 验收报告 + 版权评估 |
镜像是这套流程的起点,不是终点。 第一步照样把整站抓成只读快照——但那份快照在这里的用途是当裁判:后面每一次"复刻侧对不对"的判断,都是拿它当标尺量出来的。扒站到此为止,复刻从这里开始。
方法论的来源与试炼场——更新记录里的每一条,都来自其中某一个项目。
| 站名 | 网址 | 一句话 |
|---|---|---|
| Rogier de Boeve | rogierdeboeve.com | 摄影师作品集,GLB 模型 + 滚动叙事,方法论的第一个原型 |
| ORYZO | oryzo.ai | 产品站,自研 WebGL 场景;移动端纹理的命名规则要从代码里逆出来,不能猜 |
| Samsy | samsy.ninja | 创意开发者作品集,238 MB 重资产,确立了"镜像是唯一资产库、绝不复制第二份" |
| Kimi Careers | careers.kimi.com | 招聘站,4.8 MB 中文点阵字体"拒绝优化"的五条理由,成了差异登记的范本 |
| Noomo Storytelling | storytelling.noomoagency.com | Nuxt SSR + GLB 烘焙滚动叙事,确立了服务端渲染产物的逐字节比对 |
| Lando Norris | landonorris.com | 车手官网,资产分散在多个外部 CDN,确立了统一收编外部资源的做法 |
| Racing.shop | racing.shop | 第一个实战项目,Shopify 店铺,催生了平台层剥离指南与流媒体补录 |
| Shopify Editions Design | shopify.design | 47,224 行命令式 three.js 引擎单页,本系列难度最高的一次逆向 |
| Object & Archive | objectandarchive.com | Shopify 主题 fork 定制店,逻辑住在模板内联块里;催生了"无 bundle"分支与整个版权取证流程 |
| AIM Services 50th | aimservices.co.jp/50th | 日文企业周年微站,第一次全程无人介入的实测目标 |
| ChungiYoo | chungiyoo.com | 设计师作品集,Nuxt 2 SSG,页面里的数据块占文档 54%、展开后膨胀 8.9 倍 |
| Apple AirPods Pro | apple.com/airpods-pro | 判级的基准物种,第一个 webpack 模块容器目标;565 个模块逐字移植,9 个滚动检查点逐像素一致,仓库外断网重建仍是 0.00 |
| Optimus(v0 生成) | v0-optimus-delta.vercel.app | Next.js + Turbopack 容器,第二种模块打包形态;⭐ 打包器自带导出名,命名从推断变成转写(16/20 tier-1) |
| Lusion | lusion.co | 创意工作室官网,1.25 MB 自研 WebGL 引擎 + 156 个 shader;三条路由**逐像� |