真正开始写网站的时候,我反而希望 Agent 稳一点。先把静态站这件事跑通,再谈风格和表达。

在 Idea2Site 里,真正负责生成网站的主要是两个 skill:

make-personal-site
copy-website-style

这两个 skill 都会产出 HTML/CSS/JS 静态站,但它们解决的是两类完全不同的问题。这个地方如果不拆,后面会非常乱。

make-personal-site 解决的是:

我已经有了一个方向,现在帮我原创一个个人网站。

copy-website-style 解决的是:

我有一个具体网站/截图/模板,帮我做一个气质和结构接近的静态版本。

看起来都是建站,但它们的目标、风险和检查点都不一样。一个是原创,一个是复刻,这两个任务要分开处理。

1. 为什么建站执行层要分成两个 skill?

一开始我也想过,是否可以只写一个 make-site,既能原创,又能参考,又能复刻。

后来发现这样很容易混乱,而且混乱得很具体。

因为“松散参考”和“高保真复刻”完全是两种任务。

比如用户说:

我喜欢这个网站的感觉,帮我做一个类似的个人主页。

这可能只是风格参考。我们可以借它的布局节奏、配色克制、文章列表方式,但内容和结构可以重新组织。

但如果用户说:

就照这个网站来,布局、动效、交互都尽量像。

那就完全不一样了。这时候需要:

  • 打开目标网站观察;
  • 记录第一屏布局;
  • 分析滚动和 hover;
  • 看移动端断点;
  • 映射内部页面;
  • 把 framework route 转成静态路径;
  • 清掉原站身份和资产;
  • 和目标做浏览器对比。

如果用一个 skill 同时处理这两类任务,它很容易复刻不够像,原创时又过度贴近某个参考,两个方向都做得不干净。

所以拆成:

make-personal-site:原创静态站
copy-website-style:具体参考站风格复刻

这两个 skill 的共同底座是静态交付,但工作方式不同。

2. make-personal-site:从方向生成可用静态站

make-personal-site 是最核心的建站实现 skill。它负责把前面已经确定的方向真正变成文件。

它的目标非常明确,而且很朴素:

用纯 HTML / CSS / 可选 vanilla JS 创建一个个人网站。
零框架。
零构建步骤。
零 package install。
零运行时依赖。
直接打开 index.html 能预览。
部署到静态托管也能工作。

我觉得这个约束很重要,甚至可以说是这个项目能跑起来的基础。

因为 Agent 做网站最容易被复杂工具链拖走。用户只是想要一个个人博客,结果它给你生成 Next.js、Tailwind、npm、build script、配置文件,最后依赖装不上,页面都看不到。这种情况真的很常见。

make-personal-site 的思路是先收住:

先把最小可用静态站做好。
结构清楚。
路径清楚。
页面完整。
后续好改。

2.1 默认站点结构

对于一个新站,它推荐的结构大概是:

site/
  index.html
  EDITING.md
  about.html
  blog.html
  projects.html
  posts/
    first-post.html
  assets/
    style.css
    script.js
    images/
  data/
    posts.json
    profile.json

这个结构的目的很直接:让未来 Agent 能读懂。因为我们要同时考虑这一轮生成和下一轮用户继续改时是否接得住。

index.html 是首页。 about.html 是身份和背景。 blog.html 是文章列表。 projects.html 是项目页。 posts/ 里放文章详情。 assets/ 放样式、脚本和图片。 data/ 可以放重复内容数据。 EDITING.md 记录以后怎么改。

我觉得 EDITING.md 是这个 skill 里很关键的设计。

因为一个站点生成完只是开始。未来用户会继续说:

把首页第二块改一下。
再加一篇文章。
项目页换成我的真实项目。
颜色太冷了,改暖一点。

有了 editing guide,未来的 Agent 可以直接理解整个结构。

有了 EDITING.md,它能知道:

  • 哪个文件对应哪个页面;
  • 首页每个 section 在哪里;
  • 文章怎么加;
  • 项目列表存在哪里;
  • 颜色变量在哪;
  • 哪些内容还是 placeholder。

这其实是给未来协作留的接口。

2.2 页面要超过首页

make-personal-site 里明确要求:完整个人站需要超过一个 homepage。

如果是博客,就至少要有文章详情页和列表页。

如果有项目,就要有项目页。

如果首页链接了关于页,那关于页必须存在。

这点很小,但非常容易被普通生成忽略。

很多模型会写:

<a href="blog.html">Writing</a>

然后根本没有 blog.html

或者首页展示文章卡片,但点击进去没有文章页。

这对于 demo 截图没关系,但对于真实网站是硬伤。

所以 make-personal-site 的 success gate 里有一个核心要求:

Required page types exist and navigation points to real relative paths.

也就是说,导航要真的能点。

它真的要能点。

2.3 纯静态路径规则

这个 skill 最重视的工程细节之一是路径。

生成静态站时,默认必须使用 page-relative path。

比如 root 页面里:

<link rel="stylesheet" href="assets/style.css">
<a href="about.html">About</a>
<a href="posts/example.html">Post</a>

文章页在 posts/example.html,就要写:

<link rel="stylesheet" href="../assets/style.css">
<a href="../index.html">Home</a>
<a href="../blog.html">Blog</a>

这里要避免随手写:

<link rel="stylesheet" href="/assets/style.css">

为什么?

因为 /assets/style.css 在本地 HTTP 根目录下可能能工作,但在这些场景会坏:

  • 用户双击 index.html
  • GitHub Pages 项目页部署在 /repo-name/ 子路径;
  • 站点被放到某个子目录;
  • 文章页和首页路径深度不同。

静态站最难受的很多 bug 都是路径 bug。

所以 Idea2Site 选择了一个保守策略:

默认全部页面相对路径。
除非用户明确接受 server-root-only。

这件事看起来不起眼,但它决定了生成站点是否能被普通用户直接打开。

2.4 交互只用 vanilla JS

make-personal-site 允许有明确价值的轻交互。

比如:

  • 移动端导航;
  • 主题切换;
  • 标签过滤;
  • 复制按钮;
  • 轻微 hover 效果;
  • 小的 progressive enhancement。

但是它避免:

  • 重动画框架;
  • 必须 dev server 才能运行的效果;
  • canvas 大装饰;
  • 影响阅读的闪烁、glitch、复杂滚动。

个人博客的第一优先级还是阅读和维护。

如果一个动效让文章页变得难读,那它就不该存在。

2.5 它的失败模式

make-personal-site 常见 badcase 大概有几类:

第一类是页面范围不完整。

比如只有首页,文章详情和项目页都缺位。

第二类是路径不兼容。

比如 nested page 里仍然引用 assets/style.css,导致文章页没有样式。

第三类是 placeholder 不清楚。

模型随手写了一个虚构身份:

Hi, I'm Alex, a full-stack engineer from San Francisco...

这看起来完整,但对用户来说是假的。

更好的做法是使用清晰可替换 placeholder,避免编造详细事实。

第四类是过度 landing page。

个人博客被写成了产品官网,第一屏是一句大 slogan 和 CTA,但没有任何真实内容入口。

所以这个 skill 一直强调:

个人站要避开营销 landing page 的写法。
第一屏要有用。

3. copy-website-style:从具体参考站重建风格

copy-website-style 是另一个复杂得多的 skill。它处理的是“我就喜欢这个网站,你帮我做一个像的”这种需求。

它处理的是用户给出具体目标的场景:

参考这个 URL。
复制这个网站风格。
做一个像这个截图一样的网站。
这个模板很好看,帮我做一个静态版。

这个 skill 的核心原则是:

复制风格和交互模式。
代码、资产、个人身份和私有内容默认留在原站。
用干净的 HTML/CSS/JS 重新实现。

3.1 为什么避免直接扒源码?

从工程上说,直接下载目标网站源码当然可能更快,但这条路很危险。

但是这个项目不希望这么做,原因有几个。

第一,版权和许可不清楚。

公共网站的 HTML/CSS/JS 可以作为研究材料,别人的代码、图片、字体、文章、头像、统计 ID、社交链接默认留在原站。

第二,原站实现未必适合静态交付。

目标站可能是 Next.js、Astro、React、Tailwind、Framer Motion、CMS、路由系统、构建产物混在一起。直接搬回来,用户后续很难维护。

第三,用户想要的是自己的站。

如果保留了原作者名字、文章标题、友链、域名,整个任务就会滑向内容复制,偏离风格复刻。

所以 copy-website-style 的策略是:

源站作为研究对象。
实现重新写。
内容替换成用户自己的或 placeholder。

3.2 浏览器探索是第一步

高保真复刻需要浏览器观察。光看 HTML 或截图,很容易漏掉真正有辨识度的东西。

这个 skill 要先在浏览器里观察目标网站。

观察内容包括:

  • 桌面第一屏结构;
  • 移动端第一屏;
  • 导航和内部页面;
  • opening animation;
  • scroll behavior;
  • hover/click 状态;
  • 键盘交互;
  • 图片和字体;
  • DOM 和 CSS 变量线索;
  • console/network 状态。

如果目标站是动效驱动的,截图会漏掉很多东西。

比如有的网站第一屏很普通,但滚动时会横向推进; 有的网站 hover 会触发 mask; 有的网站文章列表和侧栏有很强的布局节奏; 有的网站移动端 nav 是整个体验的一部分。

这些都需要浏览器观察。

3.3 Signature Inventory

我觉得 copy-website-style 里最有意思的是它要求建立 signature inventory。这个其实就是先搞清楚目标站最像自己的地方在哪里。

也就是在写代码前,先记录目标站的几个“签名特征”:

signature layout
signature motion
signature interactions
signature visuals

比如:

  • layout:页面结构、导航位置、列宽、断点、重复 motif;
  • motion:首屏进入、滚动联动、hover、loading;
  • interaction:点击、复制、键盘、移动端菜单、active state;
  • visuals:颜色、字体、边框、阴影、mask、混合模式、背景。

为什么要这样做?

因为复刻最容易出现的问题是“结构像,但气质不像”。你看着它好像有 header、有 card、有文章列表,但是一眼就知道不对。

比如目标站的核心是低密度排版和大留白,但 Agent 只复制了卡片; 目标站的核心是滚动节奏,但 Agent 只复制了颜色; 目标站的核心是字体和行距,但 Agent 只复制了布局。

signature inventory 的作用就是提醒 Agent:先抓住最有辨识度的东西。

3.4 全站范围规则

这个 skill 默认不只复刻首页。

除非用户明确说 homepage only,否则它应该根据目标站导航生成可浏览的静态结构:

  • 主导航页面;
  • 文章详情页;
  • archive/category/tag;
  • links/theme/search/settings;
  • 移动端菜单里才能看到的页面;
  • 分页或列表页。

当然目标是生成代表性页面类型,避免复制目标站所有真实文章。

比如:

posts/sample-post.html
archive/index.html
category/index.html
links/index.html

这样用户拿到的是一个可以继续填内容的网站壳,首页只是其中一部分。

3.5 框架和动效翻译

目标站可能用了各种现代前端技术,但输出仍然要是纯静态。

所以这个 skill 里有一套翻译规则:

源站实现静态翻译
React/Next/Astro components重复 HTML section + CSS class
Tailwind utility普通 CSS
framework route.html 静态页面
content collection静态列表或本地 JS data
Framer Motion springCSS easing 或 requestAnimationFrame
scroll-linked transformscroll progress + CSS custom properties
copy-to-clipboard animation两状态文字切换
minimap trackeractive state + transform

这里的重点在于复现用户感受到的行为,技术栈完整复现放在次要位置。

如果一个复杂 WebGL 没有处在核心体验里,可以降级成静态 topic map; 如果一个物理动效太重,可以用近似 easing; 但核心特征要先保住,再考虑降级方案。

3.6 内容和资产安全

复刻类任务最容易遗留别人的信息。

所以 copy-website-style 有专门的 residual source audit。

要检查:

  • 原作者名字;
  • nickname/handle;
  • 原域名;
  • 原文章标题和正文;
  • 邮箱和社交链接;
  • 友链;
  • analytics ID;
  • 私有 URL;
  • license/statistics 文本;
  • 头像、封面、图标、截图、字体资产。

默认做法是:

保留视觉结构。
替换内容身份。
原站资产留在原处。

这对一个“给用户做自己的网站”的工具来说非常重要。

4. 两个建站 skill 的共同原则

虽然 make-personal-sitecopy-website-style 处理场景不同,但它们共享几条底层原则。

4.1 纯静态优先

输出应该能直接部署,不依赖框架。

4.2 页面相对路径

不默认使用 /assets/... 这种根路径。

4.3 UTF-8 源码可读

中文、日文、英文混排都必须在源码里可读,浏览器显示和源码都要正常。

4.4 需要 editing guide

新站或复刻站都应该有 EDITING.md,帮助未来继续修改。

4.5 浏览器验证

文件生成之后,还要打开本地 HTTP,看页面、交互、移动端和 console。

4.6 不编造用户身份

用户没给的信息,用 placeholder,具体学校、公司、奖项、城市、年份都来自用户材料。

5. 一个完整例子

假设用户说:

我喜欢某个个人博客的侧栏和文章列表,但是内容要换成我的。

如果用户喜欢的是整体感觉,对高度一致要求较低,可以走:

find-style-references -> make-personal-site -> personalize-site -> review-static-site

如果用户明确说:

布局和交互尽量像这个网站。

那就走:

copy-website-style -> personalize-site -> review-static-site

其中 copy-website-style 会先观察目标站,建立 signature inventory,然后重建:

  • 首页;
  • 文章列表;
  • 文章详情;
  • 侧栏;
  • 移动端导航;
  • 核心 hover/scroll/click 交互。

但最终内容会被替换为用户自己的或 placeholder。

这就是它和“复制网站”的区别。

它复制的是体验语言,避开别人的网站本体。

6. 小结

建站执行层其实承担了整个项目最容易被用户感知的部分。

但我觉得它真正重要的是这些更基础的交付能力:

  • 页面结构是否完整;
  • 静态路径是否可靠;
  • 未来是否好改;
  • 参考站是否被正确抽象;
  • 用户身份是否被保护;
  • 生成结果是否能通过 review。

make-personal-sitecopy-website-style 的拆分,让原创和复刻这两类任务各自有了清晰边界。

前者追求从方向到原创站的稳定落地。

后者追求从具体目标到静态重建的高保真和安全替换。

这两个 skill 合在一起,构成了 Idea2Site 的建站执行核心。