关于 clone-website
Clone Website 是一项技能,用于检查网站并协调其在 Next.js 项目中的视觉重建。它会将页面外观、素材、响应式布局和交互记录到组件规格中,供构建 Agent 使用。
主要功能
- 01通过浏览器自动化检查网站
- 02捕获桌面和移动端截图
- 03提取样式、文本与素材
- 04记录交互状态和行为
- 05为构建 Agent 编写组件规格
- 06验证 TypeScript 和项目构建
适用场景
- 01根据线上 URL 重建页面
- 02记录响应式布局与交互
- 03准备可审查的组件实现说明
MCP 相关
该技能要求通过 Chrome MCP 或 Playwright MCP 等浏览器 MCP 工具检查目标页面。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ julianromli/ ai-skills --skill clone-website安装后在 Claude Code 中输入/clone-website确认已加载。
详细介绍
克隆网站
你即将对 $ARGUMENTS 进行逆向工程,并将其重建为像素级精确的克隆。
提供多个 URL 时,请分别处理,并尽可能并行执行,同时将每个网站的提取产物隔离在专属文件夹中(例如 docs/research/<hostname>/)。
这不是一个分为两个阶段(检查后再构建)的流程。你是一名在施工现场巡视的工头——检查页面的每个版块时,都要将详细规格写入文件,然后将该文件交给专业构建 Agent,并提供其所需的一切。提取与构建并行进行,但提取必须一丝不苟,并生成可审查的产物。
默认范围
目标是 $ARGUMENTS 所指向的页面。请精确克隆该 URL 上可见的内容。除非用户另有说明,否则采用以下默认设置:
- 还原级别: 像素级精确——颜色、间距、排版和动画均需准确匹配
- 范围内: 视觉布局与样式、组件结构与交互、响应式设计、用于演示的模拟数据
- 范围外: 真实后端/数据库、身份验证、实时功能、SEO 优化、无障碍审查
- 自定义: 无——纯粹仿制
如果用户提供了额外说明(特定还原级别、自定义要求、补充背景),请优先遵循这些说明,而非默认设置。
前置检查
- 必须使用浏览器自动化。 检查可用的浏览器 MCP 工具(Chrome MCP、Playwright MCP、Browserbase MCP、Puppeteer MCP 等)。使用任一可用工具——如果有多个,优先使用 Chrome MCP。如果没有检测到任何工具,请询问用户有哪些浏览器工具,以及如何连接。这项技能离不开浏览器自动化。
- 将
$ARGUMENTS解析为一个或多个 URL。规范化并验证每个 URL;如有无效 URL,请先让用户更正。对于每个有效 URL,使用浏览器 MCP 工具确认其可访问。 - 确认基础项目可以构建:
npm run build。Next.js + shadcn/ui + Tailwind v4 脚手架应已就绪。如果尚未就绪,请告知用户先完成设置。 - 如果输出目录不存在,则创建它们:
docs/research/、docs/research/components/、docs/design-references/、scripts/。若需克隆多个网站,也要准备各网站专属文件夹,例如docs/research/<hostname>/和docs/design-references/<hostname>/。 - 在一条命令中处理多个网站时,可先确认是并行执行(若资源允许,推荐采用)还是顺序执行,以避免资源过载。
指导原则
以下原则能让成功克隆与“差不多就行”的拼凑品区分开来。请牢记这些原则,并以此指导每一个决策。
1. 完整性胜过速度
每个构建 Agent 都必须获得完美完成任务所需的一切:截图、精确的 CSS 值、附带本地路径的下载资源、真实文本内容、组件结构。如果构建 Agent 还需要猜测任何内容——颜色、字号、内边距数值——就说明提取工作没有做好。多花一分钟再提取一个属性,也不要交付不完整的任务说明。
2. 小任务,完美结果
当 Agent 收到“构建整个功能区”的任务时,往往会忽略细节——大致估算间距、猜测字号,最后做出的东西“差不多”,但显然不对。如果它只收到一个专注的组件,并拿到精确的 CSS 值,每次都能完美完成。
逐个查看区块并判断其复杂度。一个包含标题和按钮的简单横幅?一个 Agent。一个包含 3 种不同卡片样式、每种都有独特悬停状态和内部布局的复杂区块?每种卡片样式分配一个 Agent,再为区块外层分配一个 Agent。拿不准时,就拆得更小。
**复杂度预算规则:**如果构建器提示词中的规格内容超过约 150 行,这个区块对单个 Agent 来说就太复杂了。将其拆成更小的部分。这是一项机械检查——不要以“但这些内容都相关”为由忽略它。
3. 真实内容,真实素材
从线上网站提取实际文本、图像、视频和 SVG。这是一个克隆,不是模型图。使用 element.textContent,下载每个 <img> 和 <video>,将内联 <svg> 提取为 React 组件。只有当内容明显由服务器生成且每个会话都不同时,才生成内容。
**分层素材很重要。**看起来像一张图片的区块,往往由多个图层组成——背景水彩效果/渐变、前景 UI 模型 PNG、叠加图标。检查每个容器的完整 DOM 树,并列出其中所有 <img> 元素和背景图片,包括绝对定位的叠加元素。即使背景正确,漏掉一张叠加图片也会让克隆看起来空荡荡的。
4. 先打好基础
基础就绪之前,什么都无法构建:需要包含目标网站设计令牌(颜色、字体、间距)的全局 CSS、内容结构的 TypeScript 类型,以及全局素材(字体、favicon)。这一过程必须按顺序进行,不容妥协。之后的工作都可以并行处理。
5. 提取外观和行为
网站不是一张截图,而是一个鲜活的整体。元素会响应滚动、悬停、点击、调整大小和时间而移动、变化、出现和消失。如果你只提取每个元素的静态 CSS,那么克隆在截图中看起来可能正确,但实际使用起来会死气沉沉。
对每个元素,都要提取它的外观(通过 getComputedStyle() 获取精确的计算后 CSS)和行为(什么会发生变化、什么会触发变化,以及变化如何过渡)。不要说“看起来像 16px”——要提取实际的计算值。不要说“导航栏会在滚动时变化”——要记录精确的触发条件(滚动位置、IntersectionObserver 阈值、视口相交情况)、变化前后的状态(两组 CSS 值),以及过渡方式(时长、缓动、CSS transition、JS 驱动还是 CSS animation-timeline)。
以下是需要留意的行为示例——仅供说明,并非穷举。页面可能还会出现列表中没有的行为,你也必须捕捉到:
- 导航栏在滚过某个阈值后缩小、改变背景或增加阴影
- 元素进入视口时以动画方式显现(向上淡入、滑入、错开延迟)
- 区块在滚动时吸附到位(
scroll-snap-type) - 视差图层以不同于滚动的速度移动
- 会产生动画的悬停状态(不只是变化——过渡时长和缓动方式也很重要)
- 带有进入/退出动画的下拉菜单、模态框、手风琴
- 滚动驱动的进度指示器或透明度过渡
- 自动播放的轮播或循环切换的内容
- 页面区块之间从深色到浅色(或任何主题)的过渡
- 循环切换的标签页/胶囊式内容——通过过渡切换可见卡片组的按钮
- 滚动驱动的标签页/手风琴切换——侧边栏中的活动项会随着内容滚过而自动变化(通过 IntersectionObserver,而非点击处理程序)
- 平滑滚动库(Lenis、Locomotive Scroll)——检查是否存在
.lenis类或滚动容器包装元素
6. 构建前先识别交互模式
克隆时最容易造成高昂代价的错误,就是原页面由滚动驱动,你却构建了基于点击的 UI,反之亦然。在为交互式区块编写任何构建提示词之前,你必须明确回答:此区块是由点击、滚动、悬停、时间驱动,还是由其中多种方式共同驱动?
确定方法:
- 不要先点击。 缓慢滚动浏览该区块,观察内容是否会随着滚动自行变化。
- 如果会,它就是由滚动驱动的。提取其机制:
IntersectionObserver、scroll-snap、position: sticky、animation-timeline或 JS 滚动监听器。 - 如果滚动时没有任何变化,再通过点击或悬停测试交互是否由点击或悬停驱动。
- 在组件规范中明确记录交互模式:“交互模式:由
IntersectionObserver驱动的滚动交互”或“交互模式:点击切换,并使用不透明度过渡”。
带有粘性侧边栏和滚动内容面板的区块,与点击切换内容的选项卡界面有本质区别。弄错就意味着必须彻底重写,而不是微调 CSS。
7. 提取所有状态,而不只是默认状态
许多组件有多种视觉状态——选项卡栏会根据当前选项卡显示不同的卡片,页头在滚动位置为 0 和 100 时外观不同,卡片也可能带有悬停效果。你必须提取所有状态,而不只是页面加载时可见的状态。
对于选项卡式/有状态的内容:
- 通过浏览器 MCP 点击每个选项卡/按钮
- 提取每个状态对应的内容、图片和卡片数据
- 记录每项内容所属的状态
- 记录状态之间的过渡动画(不透明度、滑动、淡入淡出等)
对于依赖滚动的元素:
- 捕获滚动位置为 0 时的计算样式(初始状态)
- 滚过触发阈值后,再次捕获计算样式(滚动后状态)
- 对比两者,准确找出发生变化的 CSS 属性
- 记录过渡 CSS(时长、缓动、属性)
- 记录确切的触发阈值(以 px 表示的滚动位置,或视口交叉比例)
8. 规范文件是唯一事实来源
在分派任何构建 Agent 之前,每个组件都必须先在 docs/research/components/ 中创建一份规范文件。此文件是提取工作与构建 Agent 之间的约定。构建 Agent 会在提示词中收到规范文件的内联内容;该文件也会作为可审计的产物保留下来,供用户(或你)在发现问题时审查。
规范文件不是可选项,也不是锦上添花。如果你没有先编写规范文件就分派构建 Agent,就等于根据自己对浏览器 MCP 会话的记忆来提交不完整的说明,构建 Agent 只能自行猜测并填补遗漏。
9. 构建必须始终通过编译
每个构建 Agent 在结束前都必须验证 npx tsc --noEmit 能够通过。合并工作树后,你必须验证 npm run build 能够通过。绝不能接受构建失败,哪怕只是暂时的。
阶段 1:侦察
使用浏览器 MCP 导航至目标 URL。
截图
- 在桌面端(1440px)和移动端(390px)视口下拍摄整页截图
- 使用描述性名称保存到
docs/design-references/ - 这些截图是主要参考;之后构建 Agent 会收到按区块截取的截图
全局提取
在进行任何操作之前,先从页面中提取以下信息:
字体 — 检查 <link> 标签,查找 Google Fonts 或自托管字体。检查关键元素(标题、正文、代码、标签)的计算后 font-family。记录实际使用的每种字体系列、字重和样式。使用 next/font/google 或 next/font/local 在 src/app/layout.tsx 中配置。
颜色 — 从页面各处的计算样式中提取网站的调色板。使用目标网站的实际颜色更新 src/app/globals.css 中的 :root 和 .dark CSS 变量块。将颜色映射到 shadcn 的令牌名称(background、foreground、primary、muted 等)。对于无法映射到 shadcn 令牌的颜色,添加自定义属性。
Favicon 和元数据 — 将 favicon、apple-touch-icon、OG 图片和 webmanifest 下载到 public/seo/。更新 layout.tsx 中的元数据。
全局 UI 模式 — 识别全站通用的 CSS 或 JS:自定义滚动条隐藏、页面容器上的 scroll-snap、全局关键帧动画、背景滤镜、用作叠加层的渐变、平滑滚动库(Lenis、Locomotive Scroll——检查 .lenis、.locomotive-scroll 或自定义滚动容器类)。将这些添加到 globals.css,并注明需要安装的库。
强制交互检查
这是一个专门的检查环节,必须在截图之后、其他操作之前进行。目的是发现页面上的所有行为——其中许多在静态截图中不可见。
滚动检查: 通过浏览器 MCP 从页面顶部缓慢滚动到底部。在每个区块暂停并观察:
- 页眉的外观会改变吗?记录触发时的滚动位置。
- 元素会在进入视口时播放动画吗?记录具体元素和动画类型。
- 侧边栏或标签指示器会随滚动自动切换吗?记录其机制。
- 是否存在滚动吸附点?记录所在容器。
- 是否启用了平滑滚动库?检查是否存在非原生滚动行为。
点击检查: 点击所有看起来可交互的元素:
- 每个按钮、标签、胶囊、链接和卡片
- 记录发生的变化:内容会改变吗?会打开模态框吗?会显示下拉菜单吗?
- 对于标签/胶囊:逐个点击并记录每种状态下显示的内容
悬停检查: 将指针悬停在所有可能带有悬停状态的元素上:
- 按钮、卡片、链接、图片、导航项
- 记录发生的变化:颜色、缩放、阴影、下划线、不透明度
响应式检查: 通过浏览器 MCP 测试 3 种视口宽度:
- 桌面端:1440px
- 平板端:768px
- 移动端:390px
- 在每种宽度下,记录布局发生变化的区块(单列变为堆叠、侧边栏消失等),以及大致的断点位置。
将所有发现保存到 docs/research/BEHAVIORS.md。这是行为参考手册;编写每个组件规范时都要参考它。
页面结构
从上到下梳理页面上每个独立区块,并为每个区块取一个临时名称。记录:
- 区块的视觉顺序
- 哪些是固定/粘性叠加层,哪些是流式内容
- 页面整体布局(滚动容器、列结构、z-index 层级)
- 区块之间的依赖关系(例如,覆盖所有内容的浮动导航)
- 每个区块的交互模型(静态、点击驱动、滚动驱动、时间驱动)
将其保存为 docs/research/PAGE_TOPOLOGY.md,作为页面组装蓝图。
第 2 阶段:基础搭建
这是一个顺序执行的阶段。请亲自完成(不要委派给 Agent),因为这会涉及许多文件:
- 更新
layout.tsx中的字体,使其与目标网站实际使用的字体一致 - 更新
globals.css,加入目标网站的颜色令牌、间距值、关键帧动画、工具类,以及所有全局滚动行为(Lenis、平滑滚动 CSS、body 上的 scroll-snap) - 在
src/types/中为你观察到的内容结构创建 TypeScript 接口 - 提取 SVG 图标——找出页面上所有内联的
<svg>元素,去重后将其保存为src/components/icons.tsx中带名称的 React 组件。根据视觉功能命名(例如SearchIcon、ArrowRightIcon、LogoIcon)。 - 下载全局资源——编写并运行 Node.js 脚本(
scripts/download-assets.mjs),将页面中的所有图片、视频及其他二进制资源下载到public/。保留有意义的目录结构。 - 验证:
npm run build能够通过
资源发现脚本模式
使用浏览器 MCP 枚举页面上的所有资源:
// Run this via browser MCP to discover all assets
JSON.stringify({
images: [...document.querySelectorAll('img')].map(img => ({
src: img.src || img.currentSrc,
alt: img.alt,
width: img.naturalWidth,
height: img.naturalHeight,
// Include parent info to detect layered compositions
parentClasses: img.parentElement?.className,
siblings: img.parentElement ? [...img.parentElement.querySelectorAll('img')].length : 0,
position: getComputedStyle(img).position,
zIndex: getComputedStyle(img).zIndex
})),
videos: [...document.querySelectorAll('video')].map(v => ({
src: v.src || v.querySelector('source')?.src,
poster: v.poster,
autoplay: v.autoplay,
loop: v.loop,
muted: v.muted
})),
backgroundImages: [...document.querySelectorAll('*')].filter(el => {
const bg = getComputedStyle(el).backgroundImage;
return bg && bg !== 'none';
}).map(el => ({
url: getComputedStyle(el).backgroundImage,
element: el.tagName + '.' + el.className?.split(' ')[0]
})),
svgCount: document.querySelectorAll('svg').length,
fonts: [...new Set([...document.querySelectorAll('*')].slice(0, 200).map(el => getComputedStyle(el).fontFamily))],
favicons: [...document.querySelectorAll('link[rel*="icon"]')].map(l => ({ href: l.href, sizes: l.sizes?.toString() }))
});
然后编写下载脚本,将所有资源抓取到 public/。采用分批并行下载(每次 4 个),并妥善处理错误。
第 3 阶段:组件规格说明与分派
这是核心工作循环。对于页面拓扑中的每个区块(从上到下),你要做三件事:提取、编写规格说明文件,然后分派构建者。
第 1 步:提取
对于每个区块,使用浏览器 MCP 提取所有内容:
-
截取该区块的独立截图(滚动到该区块,并截取视口)。保存到
docs/design-references/。 -
提取区块中每个元素的 CSS。使用下面的提取脚本——不要手动测量单个属性。每个组件容器运行一次,并记录完整输出:
// Per-component extraction — run via browser MCP
// Replace SELECTOR with the actual CSS selector for the component
(function(selector) {
const el = document.querySelector(selector);
if (!el) return JSON.stringify({ error: 'Element not found: ' + selector });
const props = [
'fontSize','fontWeight','fontFamily','lineHeight','letterSpacing','color',
'textTransform','textDecoration','backgroundColor','background',
'padding','paddingTop','paddingRight','paddingBottom','paddingLeft',
'margin','marginTop','marginRight','marginBottom','marginLeft',
'width','height','maxWidth','minWidth','maxHeight','minHeight',
'display','flexDirection','justifyContent','alignItems','gap',
'gridTemplateColumns','gridTemplateRows',
'borderRadius','border','borderTop','borderBottom','borderLeft','borderRight',
'boxShadow','overflow','overflowX','overflowY',
'position','top','right','bottom','left','zIndex',
'opacity','transform','transition','cursor',
'objectFit','objectPosition','mixBlendMode','filter','backdropFilter',
'whiteSpace','textOverflow','WebkitLineClamp'
];
function extractStyles(element) {
const cs = getComputedStyle(element);
const styles = {};
props.forEach(p => { const v = cs[p]; if (v && v !== 'none' && v !== 'normal' && v !== 'auto' && v !== '0px' && v !== 'rgba(0, 0, 0, 0)') styles[p] = v; });
return styles;
}
function walk(element, depth) {
if (depth > 4) return null;
const children = [...element.children];
return {
tag: element.tagName.toLowerCase(),
classes: element.className?.toString().split(' ').slice(0, 5).join(' '),
text: element.childNodes.length === 1 && element.childNodes[0].nodeType === 3 ? element.textContent.trim().slice(0, 200) : null,
styles: extractStyles(element),
images: element.tagName === 'IMG' ? { src: element.src, alt: element.alt, naturalWidth: element.naturalWidth, naturalHeight: element.naturalHeight } : null,
childCount: children.length,
children: children.slice(0, 20).map(c => walk(c, depth + 1)).filter(Boolean)
};
}
return JSON.stringify(walk(el, 0), null, 2);
})('SELECTOR');
- 提取多状态样式——对于具有多个状态的元素(滚动触发、悬停、活动标签页),同时捕获两种状态:
// State A: capture styles at current state (e.g., scroll position 0)
// Then trigger the state change (scroll, click, hover via browser MCP)
// State B: re-run the extraction script on the same element
// The diff between A and B IS the behavior specification
明确记录差异:“属性 X 从 VALUE_A 变为 VALUE_B,由 TRIGGER 触发,过渡效果为 TRANSITION_CSS。”
-
提取真实内容——包括所有文本、alt 属性、aria 标签和占位文本。对每个文本节点使用
element.textContent。对于带标签页或具有状态的内容,点击每个标签页,并提取各状态下的内容。 -
识别该区块使用的资源——包括
public/中下载的图片/视频,以及icons.tsx中的图标组件。检查是否存在分层图片(同一容器中堆叠的多个<img>或背景图片)。 -
评估复杂度——该区块包含多少个不同的子组件?不同的子组件指拥有独特样式、结构和行为的元素(例如卡片、导航项、搜索面板)。
第 2 步:编写组件规格说明文件
为每个区块(或子组件,如果你将其拆分)在 docs/research/components/ 中创建规格说明文件。这是必需的——每个构建者都必须有对应的规格说明文件。
文件路径: docs/research/components/<component-name>.spec.md
模板:
# <ComponentName> Specification
## Overview
- **Target file:** `src/components/<ComponentName>.tsx`
- **Screenshot:** `docs/design-references/<screenshot-name>.png`
- **Interaction model:** <static | click-driven | scroll-driven | time-driven>
## DOM Structure
<Describe the element hierarchy — what contains what>
## Computed Styles (exact values from getComputedStyle)
### Container
- display: ...
- padding: ...
- maxWidth: ...
- (every relevant property with exact values)
### <Child element 1>
- fontSize: ...
- color: ...
- (every relevant property)
### <Child element N>
...
## States & Behaviors
### <Behavior name, e.g., "Scroll-triggered floating mode">
- **Trigger:** <exact mechanism — scroll position 50px, IntersectionObserver rootMargin "-30% 0px", click on .tab-button, hover>
- **State A (before):** maxWidth: 100vw, boxShadow: none, borderRadius: 0
- **State B (after):** maxWidth: 1200px, boxShadow: 0 4px 20px rgba(0,0,0,0.1), borderRadius: 16px
- **Transition:** transition: all 0.3s ease
- **Implementation approach:** <CSS transition + scroll listener | IntersectionObserver | CSS animation-timeline | etc.>
### Hover states
- **<Element>:** <property>: <before> → <after>, transition: <value>
## Per-State Content (if applicable)
### State: "Featured"
- Title: "..."
- Subtitle: "..."
- Cards: [{ title, description, image, link }, ...]
### State: "Productivity"
- Title: "..."
- Cards: [...]
## Assets
- Background image: `public/images/<file>.webp`
- Overlay image: `public/images/<file>.png`
- Icons used: <ArrowIcon>, <SearchIcon> from icons.tsx
## Text Content (verbatim)
<All text content, copy-pasted from the live site>
## Responsive Behavior
- **Desktop (1440px):** <layout description>
- **Tablet (768px):** <what changes — e.g., "maintains 2-column, gap reduces to 16px">
- **Mobile (390px):** <what changes — e.g., "stacks to single column, images full-width">
- **Breakpoint:** layout switches at ~<N>px
填写每个部分。如果某个部分不适用(例如静态页脚没有状态),请写“N/A”——但在将“状态与行为”标为 N/A 前请再三考虑。即使是页脚,链接也可能有悬停状态。
第 3 步:分派构建者
根据复杂度,在 worktree 中分派构建者 Agent:
简单区块(1–2 个子组件):由一个构建者 Agent 负责整个区块。
复杂区块(3 个或更多不同子组件):拆分任务。每个子组件分配一个 Agent,另外安排一个 Agent 负责导入这些子组件的区块外层组件。先由子组件构建者开始,因为外层组件依赖它们。
每个构建者 Agent 都会收到:
- 组件规范文件的完整内容(直接放在提示词中,不要说“去读取规范文件”)
docs/design-references/中区块截图的路径- 需要导入的共享组件(
icons.tsx、cn()、shadcn 原语) - 目标文件路径(例如
src/components/HeroSection.tsx) - 完成前使用
npx tsc --noEmit验证的指示 - 关于响应式行为的信息:具体断点值以及对应的变化
不要等待。 为一个区块分派构建者后,立即开始提取下一个区块。构建者在各自的 worktree 中并行工作,你则继续提取。
第 4 步:合并
构建者 Agent 完成工作后:
- 将其 worktree 分支合并到 main
- 你充分了解每个 Agent 构建的内容,因此要妥善解决冲突
- 每次合并后,验证构建仍然通过:
npm run build - 如果合并引入了类型错误,立即修复
持续执行“提取 → 编写规范 → 分派 → 合并”循环,直到所有区块都构建完成。
第 4 阶段:页面组装
所有区块构建并合并后,在 src/app/page.tsx 中将它们连接起来:
- 导入所有区块组件
- 根据拓扑文档实现页面级布局(滚动容器、列结构、粘性定位、z-index 层叠)
- 将实际内容连接到组件属性
- 实现页面级行为:滚动吸附、滚动驱动动画、深色到浅色的过渡、交叉观察器、平滑滚动(Lenis 等)
- 验证:
npm run build顺利通过
第 5 阶段:视觉 QA 对比
组装完成后,不要宣布克隆完成。并排截取对比截图:
- 并排打开原网站和克隆版本(或在相同视口宽度下截图)
- 在桌面端(1440px)从上到下逐个区块进行比较
- 在移动端(390px)再次比较
- 对发现的每处差异:
- 检查组件规范文件——提取的值是否正确?
- 如果规范有误:通过浏览器 MCP 重新提取,更新规范并修复组件
- 如果规范正确但构建者实现有误:修复组件,使其符合规范
- 测试所有交互行为:滚动浏览页面、点击每个按钮和选项卡、将鼠标悬停在交互元素上
- 确认平滑滚动效果合适、页眉过渡正常、选项卡切换正常、动画能够播放
只有完成这轮视觉 QA 后,克隆才算完成。
分派前检查清单
分派任何构建者 Agent 前,确认每项都能勾选。如果不能,就返回继续提取信息。
- 规范文件已写入
docs/research/components/<name>.spec.md,且所有部分均已填写 - 规范中的每个 CSS 值均来自
getComputedStyle(),而非估算 - 已识别并记录交互模型(静态 / 点击 / 滚动 / 时间)
- 对于有状态的组件,已捕获每种状态的内容和样式
- 对于滚动驱动的组件,已记录触发阈值、前后样式和过渡效果
- 对于悬停状态,已记录前后取值和过渡时间
- 已识别区块中的所有图片(包括叠加图层和分层组合)
- 已记录至少桌面端和移动端的响应式行为
- 文本内容与网站完全一致,未进行改写
- 构建者提示词中的规范内容少于约 150 行;如果超出,则需要拆分区块
不要做的事
以下是之前克隆失败的教训——每一项都导致数小时的返工:
- 原站由滚动驱动时,不要做基于点击的标签页(反之亦然)。 先滚动,再点击,以确定交互模式。这是代价最高的错误,必须彻底重写,不能只靠调整 CSS 修复。
- 不要只提取默认状态。 如果加载时标签页显示“Featured”,请点击 Productivity、Creative、Lifestyle,并提取每个标签页的卡片和内容。如果页眉会在滚动时变化,请记录滚动位置为 0 和 100+ 时的样式。
- 不要遗漏叠加/分层图片。 水彩背景 + 前景 UI 模型 = 2 张图片。检查每个容器的 DOM 树,确认是否包含多个
<img>元素和定位叠加层。 - 不要为实际是视频/动画的内容制作模型组件。 在制作复杂的 HTML 模型来复现视频内容前,先检查该区块是否使用了
<video>、Lottie 或 canvas。 - 不要估算 CSS 类。 “看起来像
text-lg”是不对的:计算值可能是18px,而text-lg是18px/28px,但实际行高却是24px。请提取精确值。 - 不要把所有内容都塞进一个大型提交。 这套流程的核心就是逐步推进,并在每一步验证构建结果。
- 不要在构建者的提示词中引用文档。 每位构建者都会在提示词中直接获得 CSS 规范——不要写“颜色请参阅 DESIGN_TOKENS.md”。构建者不应需要阅读外部文档。
- 不要跳过资源提取。 没有真实图片、视频和字体,无论 CSS 多么完美,克隆看起来都会很假。
- 不要给构建 Agent 太大的任务范围。 如果你编写的构建提示词因为区块复杂而变得很长,这就说明应该把任务拆分成更小的部分。
- 不要把无关区块交给同一个 Agent。 CTA 区块和页脚是设计不同的独立组件——不要把它们都交给同一个 Agent 并寄希望于结果。
- 不要跳过响应式提取。 如果只在桌面宽度下检查,克隆在平板和手机上就会出问题。提取时请在 1440、768 和 390 的宽度下测试。
- 不要忘记平滑滚动库。 检查是否使用了 Lenis(
.lenis类)、Locomotive Scroll 或类似库。浏览器默认滚动的感觉明显不同,用户会立刻发现。 - 没有规范文件,不要派发构建者。 规范文件能确保彻底提取信息,并生成可审计的产物。跳过它,就意味着构建者只能获得你凭记忆塞进提示词里的内容。
完成
完成后,请报告:
- 构建的区块总数
- 创建的组件总数
- 编写的规范文件总数(应与组件数一致)
- 下载的资源总数(图片、视频、SVG、字体)
- 构建状态(
npm run build的结果) - 视觉 QA 结果(剩余的差异)
- 已知的缺失项或限制