关于 web-clone
Web Clone 是已弃用的技能,原用于从实时 URL 复刻单页,并通过浏览器提取信息和进行视觉检查。README 要求不要调用它;实时 URL 视觉实现请改用 `$visual-ralph`。
主要功能
- 01已弃用,不要调用
- 02范围限于单页 URL 复刻
- 03提取页面结构与样式
- 04实现核心界面交互
- 05使用 Playwright MCP 进行浏览器操作
适用场景
- 01不再用于新任务
- 02实时 URL 实现请改用 `$visual-ralph`
MCP 相关
它需要配置 Playwright MCP 服务来执行浏览器自动化,包括页面导航、快照、截图和 DOM 检查。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ yeachan-heo/ oh-my-codex --skill web-clone安装后在 Claude Code 中输入/web-clone确认已加载。
详细介绍
Web Clone 已弃用
已强制弃用。不要调用或路由此技能。对于实时 URL 的视觉实现和视觉 QA 工作流,请直接使用 $visual-ralph。
<Do_Not_Use_When>
- 用户只有截图参考而没有实时 URL — 直接使用
$visual-verdict - 用户想要修改、重新设计或"改进"该网站 — 使用标准实现流程
- 目标需要身份验证、支付流程或后端 API 对齐 — 超出 v1 范围
- 多页面 / 多路由深度克隆 — v1 仅处理单页面范围 </Do_Not_Use_When>
<Scope_Limits> v1 范围:对提供的 URL 进行单页面克隆。
包含:
- 布局结构(页眉、导航、内容区域、侧边栏、页脚)
- 排版(字体族、字号、字重、行高)
- 颜色、间距、边框、圆角
- 核心交互:导航链接、按钮、表单元素、下拉菜单、模态框、开关
- 从提取的布局中获得的响应式提示(flexbox/grid 模式)
不包含:
- 后端 API 集成或数据获取
- 身份验证流程或受保护内容
- 动态 / 个性化内容(用户特定数据)
- 多页面爬取或路由图克隆
- 第三方小部件功能(地图、嵌入、聊天小部件)
- 图片 / 资源复制(对外部图片使用占位符)
法律声明:仅克隆你拥有或获得明确许可复制的网站。尊重版权和商标。 </Scope_Limits>
必须提供 Playwright MCP 服务以进行浏览器自动化。- 如果未找到浏览器工具,请指示用户:
Playwright MCP is required. Configure it: codex mcp add playwright npx "@playwright/mcp@latest" - 必需工具:
browser_navigate、browser_snapshot、browser_take_screenshot、browser_evaluate、browser_wait_for。可选:browser_click、browser_network_requests。
<Tool_Usage>
- 如果未找到浏览器工具,请立即停止并指示用户配置 Playwright MCP。
- 使用
browser_snapshot(无障碍树)进行结构理解 — 它比截图在 token 上高效得多。 - 仅在需要视觉验证时使用
browser_take_screenshot(第 1 遍基线、第 4 遍对比)。 - 使用
browser_evaluate进行 DOM / 样式提取 — 完全按照本技能中写的那样传入脚本(不要修改它们)。 - 如果在 ralph 中运行,使用
state_write/state_read在迭代之间持久化 web-clone 状态。 - 对于简单的提取跳过 Codex 咨询;仅当验证在同一问题上反复失败时才使用它。 </Tool_Usage>
<State_Management> 持久化提取和进度数据,以便流水线在中断时可以恢复。
- 第 1 遍完成后:将提取摘要写入
.omx/state/{scope}/web-clone-extraction.json,包含:target_url、extracted_at时间戳screenshot_path(指向target-full.png的路径)landmark_count(nav、main、footer、form 元素的数量)interactive_count(检测到的交互元素数量)extraction_size_kb(DOM 提取数据的近似大小)
- 每次第 4 遍验证后:将综合判定追加到
.omx/state/{scope}/web-clone-verdicts.json。 - 在 ralph 中运行时:同时将综合判定中的
visual部分持久化到.omx/state/{scope}/ralph-progress.json以兼容 ralph,将visual.score映射到顶层score,将visual.verdict映射到顶层verdict。 - 完成或失败时:写入带
completed_at或failed_at时间戳的最终状态。 </State_Management>
<Context_Budget> 第 1 遍提取可能产生非常大的数据。请主动应用以下限制:
- DOM 树:如果序列化后的 JSON 超过约 30KB,将
depth参数从 8 降到 4 并重新提取。重点关注顶层结构。 - 可访问性快照:如果超过约 20KB,对于复杂页面来说这是正常的。总结关键地标,而不是保留完整的树。
- 交互元素:上限为 50 个元素。如果存在更多,只保留可见的(
isVisible: true)。 - 总提取上下文:目标控制在合计 60KB 以内。如果超出,优先级为:截图 > 可访问性快照 > 交互元素 > DOM 样式。
- 图像 token:整页截图开销较大。在 Pass 1 中拍摄一张基线图,在 Pass 4 中拍摄一张对比图。除非调试特定区域,否则不要在迭代之间拍摄截图。 </Context_Budget>
Pass 1 — 提取
捕获目标页面的结构、样式、交互和视觉基线。
- 导航:使用
browser_navigate访问target_url。 - 等待渲染:使用
browser_wait_for并设置合适的条件(network idle 或 5s 超时),以确保完整渲染,包括懒加载内容。 - 可访问性快照:
browser_snapshot— 捕获语义树(角色、名称、值、交互状态)。这是你的主要结构参考。 - 整页截图:使用
browser_take_screenshot并设置fullPage: true— 保存为参考基线target-full.png。 - DOM + 计算样式:使用以下脚本执行
browser_evaluate。严格照抄此脚本 — 不要修改它:(() => { const walk = (el, depth = 0) => { if (depth > 8 || !el.tagName) return null; const cs = window.getComputedStyle(el); return { tag: el.tagName.toLowerCase(), id: el.id || undefined, classes: [...el.classList].slice(0, 5), styles: { display: cs.display, position: cs.position, width: cs.width, height: cs.height, padding: cs.padding, margin: cs.margin, fontSize: cs.fontSize, fontFamily: cs.fontFamily, fontWeight: cs.fontWeight, lineHeight: cs.lineHeight, color: cs.color, backgroundColor: cs.backgroundColor, border: cs.border, borderRadius: cs.borderRadius, flexDirection: cs.flexDirection, justifyContent: cs.justifyContent, alignItems: cs.alignItems, gap: cs.gap, gridTemplateColumns: cs.gridTemplateColumns, }, text: el.childNodes.length === 1 && el.childNodes[0].nodeType === 3 ? el.textContent?.trim().slice(0, 100) : undefined, children: [...el.children].map(c => walk(c, depth + 1)).filter(Boolean), }; }; return walk(document.body); })() - 交互元素:使用
browser_evaluate编目所有可交互元素。严格照抄此脚本 — 不要修改它:(() => { const results = []; document.querySelectorAll( 'button, a[href], input, select, textarea, [role="button"], ' + '[onclick], [aria-haspopup], [aria-expanded], details, dialog' ).forEach(el => { results.push({ tag: el.tagName.toLowerCase(), type: el.type || el.getAttribute('role') || 'interactive', text: (el.textContent || '').trim().slice(0, 80), href: el.href || undefined, ariaLabel: el.getAttribute('aria-label') || undefined, isVisible: el.offsetParent !== null, }); }); return results; })() - 网络模式(可选):
browser_network_requests— 记录 XHR/fetch 调用以供参考。不要尝试复制后端。
将所有提取结果保留在工作内存中,以供 Pass 2 使用。
Pass 2 — 构建计划
分析提取结果并分解为组件计划。
-
识别页面区域:根据 DOM 树 + 可访问性快照,识别主要区块:
- 导航栏 / 页眉
- Hero / 横幅区块
- 主要内容区域
- 侧边栏(如果存在)
- 页脚
- 覆盖层元素(模态框、抽屉)
-
映射组件:对于每个区域,定义:
- 组件名称和职责
- 关键样式属性(来自计算样式)
- 内容摘要(标题、文本、图像)
- 子组件(如果嵌套)
-
创建交互映射:根据交互元素列表:
- 导航链接 → 带
href的锚点标签 - 表单元素 → 带有输入框、标签、验证的适当
<form> - 按钮 → 点击处理器(切换、提交、导航)
- 下拉菜单/模态框 → 带过渡的显示/隐藏切换
- 手风琴/选项卡 → 基于状态的可见性
- 导航链接 → 带
-
提取设计 token:识别重复出现的值:
- 调色板(主色、辅助色、背景色、文本颜色)
- 字体栈(字体系列、字号比例、字重比例)
- 间距比例(内边距/外边距模式)
- 边框圆角值
-
定义文件结构:
{output_dir}/ ├── index.html (or App.tsx / App.vue) ├── styles/ │ ├── globals.css (reset + tokens) │ └── components.css (or scoped styles) ├── scripts/ │ └── interactions.js (toggle, modal, dropdown logic) └── assets/ (placeholder images)如果指定了
tech_stack(React 组件、Vue SFC 等),则进行适配。
第 3 遍 — 生成克隆
根据计划实现克隆。逐组件进行。
- 脚手架:创建目录结构和基础文件。
- 先处理设计令牌:基于提取的令牌实现 CSS 自定义属性或 Tailwind 配置。
- 布局外壳:构建与原始页面 flexbox/grid 结构一致的页面级布局。
- 组件:自上而下实现每个区域:
- 匹配提取的 DOM 结构(语义标签、landmark 角色)
- 应用计算样式 — 优先布局属性,其次排版,最后装饰
- 使用实际提取的文本内容;外部图片使用占位符
<img>
- 交互:接好检测到的行为:
- 导航:可用的
<a>标签(指向#锚点或 v1 的占位桩) - 表单:使用
<label>、输入类型、占位符文本的正确结构 - 切换:为下拉菜单、模态框、手风琴添加 JavaScript
- 悬停/聚焦状态:与原始行为一致的 CSS 过渡
- 导航:可用的
- 响应式:如果原始页面使用了响应式断点(可从计算样式中的媒体查询或视口行为检测到),则添加基本的响应式规则。
第 4 遍 — 验证
从三个维度将克隆与原始页面进行对比。
-
启动克隆:为生成的项目启动本地服务器:
npx serve {output_dir} -l 3456 --no-clipboard如果
npx serve不可用,则回退到:python3 -m http.server 3456 -d {output_dir}。 克隆可通过http://localhost:3456访问。 -
视觉验证:
- 使用 Playwright 导航到克隆:用
browser_navigate打开克隆 URL。 - 对克隆进行整页截图。
- 运行
$visual-verdict,参数为:reference_images=["target-full.png"]、generated_screenshot="clone-full.png"、category_hint="web-clone"。 - 判定中的视觉部分直接汇入下方的综合判定。
- 视觉通过阈值:score >= 85。
- 使用 Playwright 导航到克隆:用
-
结构验证:对比 landmark 数量:
- 统计原始页面和克隆中的
<nav>、<main>、<footer>、<form>、<button>、<a>数量。 - 当所有主要 landmark 都存在时结构通过(缺失 landmark = 失败)。
- 统计原始页面和克隆中的
-
功能抽查:通过 Playwright 测试 2–3 个检测到的交互:
- 点击导航链接 → 验证 URL 变化或滚动行为
- 切换下拉菜单/模态框 → 验证可见性变化
- 与表单字段交互 → 验证其可接受输入
- 使用
browser_click和browser_snapshot验证状态变化。
-
输出综合判定:
{
"visual": {
"score": 82,
"verdict": "revise",
"category_match": true,
"differences": ["Header spacing tighter than original"],
"suggestions": ["Increase nav gap to 24px"]
},
"functional": {
"tested": 3,
"passed": 2,
"failures": ["Dropdown does not open on click"]
},
"structure": {
"landmark_match": true,
"missing": [],
"extra": []
},
"overall_verdict": "revise",
"priority_fixes": [
"Fix dropdown toggle interaction",
"Increase header nav spacing"
]
}
第 5 轮 — 迭代
修复影响最大的问题并重新验证。
- 按影响确定修复优先级:布局 > 交互 > 间距 > 字体排版 > 颜色。
- 应用针对性编辑:只修复
priority_fixes中列出的问题。不要重构正常工作的代码。 - 重新验证:重复第 4 轮。
- 循环:持续进行,直到
overall_verdict为pass或达到最多 5 次迭代。 - 最终报告:总结成功克隆的内容、任何剩余差异,以及无法复制的元素。
<Output_Contract> 每轮验证通过后,输出一个 复合网页克隆判定 JSON:
{
"visual": {
"score": 0,
"verdict": "revise",
"category_match": false,
"differences": ["..."],
"suggestions": ["..."],
"reasoning": "short explanation"
},
"functional": {
"tested": 0,
"passed": 0,
"failures": ["..."]
},
"structure": {
"landmark_match": false,
"missing": ["..."],
"extra": ["..."]
},
"overall_verdict": "revise",
"priority_fixes": ["..."]
}
规则:
visual遵循$visual-verdict中的VisualVerdict结构functional.tested/passed为计数;failures列出具体的交互失败项- 当所有主要 HTML 地标(nav、main、footer、forms)都存在时,
structure.landmark_match为true overall_verdict:当 visual.score >= 85 且 functional.failures 为空且 structure.landmark_match 为 true 时为passpriority_fixes:按影响排序,驱动下一轮迭代 </Output_Contract>
<Iteration_Thresholds>
- 视觉通过:score >= 85
- 功能通过:已测试交互零失败
- 结构通过:所有主要地标均存在
- 整体通过:三个维度全部通过
- 最大迭代次数:5(若未达到阈值,报告已取得的最佳结果) </Iteration_Thresholds>
<Error_Handling>
- Playwright MCP 不可用:停止。指示用户进行配置。不要在没有浏览器工具的情况下尝试克隆。
- 页面加载失败:报告 URL 和 HTTP 状态。建议用户确认该 URL 可访问。
- browser_evaluate 返回为空:页面可能使用了大量客户端渲染。延长等待时间(使用带扩展超时的
browser_wait_for)并重试一次。 - 视觉评分在 3 次迭代后仍低于阈值:将当前状态作为尽力而为的结果报告。向用户列出未解决的差异。
- 提取数据过大超出上下文:截断较深的 DOM 分支(深度 > 6)。聚焦顶层结构,将嵌套细节推迟到迭代修复中处理。 </Error_Handling>
第 1 轮:导航到 HN。提取:基于表格的布局、橙色(#ff6600)导航栏、包含链接 + 积分 + 评论的帖子列表、页脚。已保存截图。
第 2 轮:区域:导航栏(logo + 链接)、帖子表格(30 行 × 标题 + 元信息)、页脚。Token:橙色 #ff6600、灰色 #828282、Verdana 字体、基准 10pt。交互映射:帖子链接(外部)、评论链接、"more" 分页。
第 3 轮:生成 index.html,采用 HN 风格的表格布局、匹配提取颜色/字体的 CSS、可用于帖子的 <a> 标签。
第 4 轮:视觉评分=78(字号不对,帖子间距过紧)。功能 2/2(链接可用)。结构匹配=true。
第 5 轮迭代 1:将字体修复为 Verdana 10pt,增加行内边距 → score=88。功能 2/2。结构匹配。→ overall_verdict: pass。完成。
<Final_Checklist>
- 第 1 轮提取已完成并总结(截图 + 无障碍树 + DOM 样式 + 交互)
- 第 2 轮组件规划已创建,包含文件结构
- 第 3 轮克隆已生成,文件已写入
output_dir - 克隆可在本地无错误运行
- 第 4 轮已输出包含全部三个维度的复合判定
-
overall_verdict为pass,或已达到最多 5 次迭代并给出尽力而为的报告 - 在 ralph 中时:视觉判定已持久化到
ralph-progress.json - 提取摘要已持久化到
web-clone-extraction.json</Final_Checklist>