Zhang(张)的,Agent 协作打造的个人作品集网站 —— 一名大学生开发者用于记录和分享个人 Agent 使用经历和经验的实操集合。它基于我对 Agent 能力的好奇与探索,在探索过程中点滴积累,汇集成了网站各部分设计,它源自“一个身为开发者怎能不打造一个个人网站”的想法,后把想法交由 Agent 加工、处理得到。全过程,我负责统筹设计开发,设计提示词,检查验收,优化交互体验,打磨细节;Agent 全程辅助配合完成任务,并接管全部代码开发。一起看看我与 Agent 协作实践流程。
技术选型
| 层 | 技术 |
|---|---|
| 框架 | Next.js 16(App Router) |
| UI | React 19 + TypeScript |
| 样式 | Tailwind CSS v4 |
| 动画 | motion(motion/react) |
| 内容 | MDX + @next/mdx(mdxRs 编译器) |
| 图标 | lucide-react |
内容设计:目标定位与内容设计
核心说明:明确目标与定位,向 Agent 点明网站的核心定位,以及我对这个网站的功能需求,这样便在上下文中加入了终极目标说明,Agent 如有需求,可在每步后都对照总目标进行修正,微调。同时,可以使用 Harness 提供的 goal (目标模式),实现和上述提示词设计思路一样的效果。随后是主体内容设计,主要是 Agent 使用记录,包括编程,创作,自动化等场景,然后总结记录经验分享。再者便是浅浅介绍自己。Agent 瞄准目标设计多种方案给我拍板,不满意则可与其交谈微调方向,直至拍板实施。
内容系统设计:MDX 驱动的数据流引擎
内容引擎要支撑长期、增量、多形态的内容产出。本项目用同一个静态站点同时承担这两种角色,核心课题是——如何在单一路由下把两者统一,而不牺牲其中任何一方的体验。全站内容收敛在 content/ 目录的 MDX 文件里。构建前由 generate-content-data.js 把每个文件拆成三层,各司其职:
| 产物 | 内容 | 职责 |
|---|---|---|
content-data.json | frontmatter 元信息 | 驱动首页、列表与"精选" |
lib/generated/*.mdx | 剥离 frontmatter 的中文正文 | 编译为正文组件 |
lib/generated/*.en.mdx | 剥离 frontmatter 的英文 sidecar 正文 | 编译为英文正文组件 |
mdx-registry.ts | slug → 中英文 Component 映射 | 按语言取用正文组件,英文缺失时回退中文 |
import Practice0 from '@/lib/generated/practice/zhang.log.mdx';
export const practiceComponents: Record<string, ComponentType> = {
'zhang.log': Practice0,
};
三层拆分的价值在于内容与结构的解耦:元数据与正文各自独立编译,正文组件化让每篇文章可被单独注册与替换——增删一篇内容,只需维护一个 MDX 文件。
内容渲染策略
与 Agent 讨论建议静态生成的确定性。元信息来自构建期静态数据,正文来自编译期注册组件,路由以 generateStaticParams 预生成。整站几乎没有客户端数据请求:首屏确定、构建产物可预期、部署无运行时依赖。这种"用构建确定性换取运行灵活性"的模式,与内容更新频率不高的个人站场景高度契合。
国际化
路径段驱动的词典 app/[lang] 用路径段承载语言,getDictionary(lang) 返回 UI 词典。文章与提示词采用同一思路:content/{collection}/{slug}.en.mdx 是中文主稿旁的英文 sidecar,global-agents.en.md 是全局提示词的英文版本。生成器只读取 sidecar 中需要翻译的元信息字段,日期、封面、标签等共享字段仍以主稿为准,并分别生成 blogComponentsEn / practiceComponentsEn 供英文正文使用。getDisplayTag 负责标签本地化。语言被建模为一个路由参数加一次查表动作,没有引入重型 i18n 框架,轻量且与静态渲染天然兼容。
结构设计
目录结构,经过与 Agent 多轮讨论与修订得出:
zhang.log/
├── app/ # App Router 路由与页面
│ ├── [lang]/ # 语言段(cn / en),所有页面按语言静态预渲染
│ │ ├── layout.tsx # 根布局、字体、导航、页脚与全局 Provider
│ │ ├── not-found.tsx # 语言段内 notFound() 的本地化 404
│ │ ├── [...rest]/page.tsx # 未匹配路径进入 notFound(),交给语言段 404
│ │ ├── page.tsx # 首页数据装配
│ │ ├── HomeClient.tsx # 首页视觉、轨道图和客户端交互
│ │ ├── about/ # 关于页
│ │ │ ├── page.tsx
│ │ │ └── AboutClient.tsx
│ │ ├── agents/page.tsx # 兼容入口:重定向到首页 #agent-experience
│ │ ├── blogs/ # 博客页面路由
│ │ │ ├── page.tsx
│ │ │ ├── BlogClient.tsx
│ │ │ └── [slug]/page.tsx # 文章详情(generateStaticParams)
│ │ ├── practice/ # 实践列表页路由
│ │ │ ├── page.tsx
│ │ │ ├── PracticeClient.tsx
│ │ │ └── [slug]/page.tsx # 实践详情(generateStaticParams)
│ │ └── openclaw/ # OpenClaw 网关文档页
│ │ ├── page.tsx
│ │ ├── OpenClawClient.tsx
│ │ └── sections/ # 蓝图、结构、快速开始、配置、经验、场景与维护
│ ├── globals.css # 全局样式与 Tailwind v4 主题色
│ ├── mdx.d.ts # MDX 模块类型声明
│ └── icon.png # 站点图标
├── components/ # 核心共享组件
│ ├── AgentExperience.tsx # 首页 Agent 方法、工具与经验展示
│ ├── AutoHideScrollbar.tsx # 滚动时显现、静止时隐藏的自定义滚动条
│ ├── BackToTop.tsx # 回到顶部按钮
│ ├── CodeBlock.tsx # 代码语言标签、复制与横向滚动
│ ├── Footer.tsx # 全站页脚与社交入口
│ ├── ImageLightbox.tsx # 图片灯箱
│ ├── ListFilters.tsx # 列表搜索、筛选和排序控件
│ ├── Navbar.tsx # 桌面 / 移动导航与语言切换
│ ├── NotFoundView.tsx # notFound() 回退共用的 404 内容
│ ├── Pagination.tsx # 列表分页
│ ├── ParallaxImage.tsx # 图片视差与渐进加载封装
│ ├── ParallaxSection.tsx # 页面区块视差
│ ├── PracticeIcon.tsx # 实践图标映射
│ ├── PracticeTableOfContents.tsx # 长文目录:桌面侧栏 + 小屏抽屉
│ ├── ProgressiveImage.tsx # 本地封面渐进加载
│ ├── SmoothScroll.tsx # Lenis 惯性滚动
│ ├── useSectionScrollSpy.ts # 章节滚动高亮
│ ├── WorkspaceFileMap.tsx # OpenClaw Workspace 文件关系图
│ └── ZoomableImage.tsx # 正文图片灯箱与缩放
├── content/ # 内容源(MDX / Markdown,唯一内容入口)
│ ├── agents/ # 全局 Agent 提示词(中文主稿 + 英文 sidecar)
│ ├── blog/ # 博客文章(主稿 + .en.mdx sidecar)
│ ├── openclaw/workspace/ # OpenClaw 六份工作区 Markdown 源
│ └── practice/ # 实践(主稿 + .en.mdx sidecar,受约束 frontmatter 驱动)
├── docs/ # 项目规范
│ └── mdx-spec.md # MDX 编写规范
├── lib/ # 数据与业务逻辑
│ ├── agent-content.ts # 首页 Agent 精选工具数据
│ ├── content.ts # 内容读取接口(导入 content-data.json)
│ ├── i18n.ts # 中英文案(cnContent / enContent)
│ ├── i18n-context.tsx # 共享组件的客户端语言上下文
│ ├── mdx-registry.ts # 生成:中英文 MDX 正文静态导入注册表
│ ├── scenarios.ts # 实践场景 key 的唯一来源
│ ├── tag-display.ts # 标签展示语言映射
│ ├── utils.ts # cn() 工具(clsx + tailwind-merge)
│ ├── data/content-data.json # 生成:内容元数据
│ └── generated/ # 生成:去除 frontmatter 的中英文 MDX 正文副本
├── scripts/generate-content-data.js # 生成 JSON、registry 与无 frontmatter 正文
├── public/images/ # 头像、站点图标、博客 / 实践封面与 OpenClaw 素材
├── README.md # 项目入口、开发流程与内容约定
├── DESIGN.md # 视觉设计系统规范(Google Stitch design.md 格式)
├── edgeone.json # EdgeOne 缓存与部署配置
├── AGENTS.md / CLAUDE.md # 给编码 Agent 的行为准则
├── proxy.ts # 路由中间件(非语言路径重定向到 /cn)
├── mdx-components.tsx # MDX 渲染组件映射
├── next.config.ts # Next.js 配置(mdxRs、本地图片)
├── postcss.config.mjs
├── tsconfig.json / next-env.d.ts
└── package.json / package-lock.json
样式与交互设计
设计 DESIGN.md 以统一页面风格。DESIGN.md 是由 Google Stitch 团队开源的一套设计系统规范格式。用于向编码代理描述视觉标识的格式规范。它使代理能够持久、结构化地理解设计系统。通过编写一套网站视觉设计规则,来统一全站设计语言。以下摘要与仓库根目录的 DESIGN.md 同步维护;若两者出现差异,以根目录文件为准。本站视觉语言如下:
---
version: alpha
name: ZHANG.LOG
description: 暗色编辑式个人实践站——近黑底、纸白大字、细规则线与克制的龙虾橙状态强调。
colors:
ink: "#050505"
surface: "#0b0b0b"
paper: "#f1f1ee"
fog: "#9b9b96"
rule: "#262624"
signal: "#ff5a24"
secondary: "#2dd4bf"
typography:
sans:
fontFamily: Geist
roles: body, headings, controls
mono:
fontFamily: Geist Mono
roles: metadata, indexes, paths, code
display:
fontFamily: Geist
fontSize: clamp(3.2rem, 7.2vw, 6.35rem)
fontWeight: 500
lineHeight: 0.94
letterSpacing: -0.07em
body:
fontSize: 1rem
lineHeight: 1.75
label:
fontSize: 0.625rem
lineHeight: 1.4
letterSpacing: 0.12em
rounded:
panel: 8px
sheet: 16px
stage: 32px
pill: 9999px
spacing:
xs: 4px
sm: 8px
md: 16px
lg: 24px
xl: 32px
layout:
contentMaxWidth: 1120px
mobileGutter: 20px
desktopGutter: 24px
navHeight: 64px
navHeightDesktop: 80px
components:
navbar:
backgroundColor: "rgba(5,5,5,0.88)"
borderColor: "{colors.rule}"
height: "{layout.navHeight}"
button-primary:
backgroundColor: "{colors.paper}"
textColor: "{colors.ink}"
rounded: "{rounded.pill}"
button-secondary:
backgroundColor: transparent
borderColor: "{colors.rule}"
rounded: "{rounded.pill}"
index-row:
borderColor: "{colors.rule}"
backgroundColor: transparent
code-block:
backgroundColor: "{colors.surface}"
textColor: "{colors.paper}"
rounded: "{rounded.panel}"
typography: "{typography.mono}"
---
## Overview
ZHANG.LOG 是一份持续维护的个人实践日志,而不是套用作品集模板的营销页。视觉方向是“暗色编辑式工作台”:近黑画布承载纸白大字,细规则线组织信息,等宽字体标记时间、编号与路径,少量龙虾橙只在状态、强调和交互反馈中出现。
页面先讲正在做的事,再给出实践、方法、验证和文章。层级应来自留白、字号、字重和规则线,而不是大量玻璃卡片、渐变标题或装饰性图标。整体感觉应当冷静、直接、可检查,像一份被认真编排的工程记录。
首页用“想法 → Agent → 现实”的轨道图建立整站隐喻;实践与博客使用索引行而非同质卡片墙;详情页把长文、图片和目录组织成可持续阅读的坐标系。动效服务于叙事和反馈,不替代信息。
## Colors
- **Ink(#050505):** 页面与导航的主背景,也是纸白组件上的反白文字色。
- **Surface(#0b0b0b):** 代码块、媒体占位和信息面板的次级底色,与 Ink 只拉开一档。
- **Paper(#f1f1ee):** 主标题、关键正文、主按钮底色和当前导航态。避免使用刺眼的纯白。
- **Fog(#9b9b96):** 说明文字、元信息、未激活导航和次要操作。
- **Rule(#262624):** 分隔线、描边、输入框边界和低层级容器。结构主要靠线,不靠重阴影。
- **Signal(#ff5a24):** 错误、当前章节、编号、状态点和 hover 强调。它是定位色,不是大面积底色。
- **Secondary(#2dd4bf):** 极少量状态或校验节点;不得与 Signal 争抢主次。
颜色优先级固定为 Ink / Paper / Fog / Rule,Signal 只占很小面积。渐变仅用于抽象轨道、图片遮罩和场景化动效,不用于普通文字卡片。
## Typography
- **正文 Sans:** Geist。正文常用 16px / 1.75,长文在桌面可放大到 `lg:prose-lg`;描述性文字用 Fog。
- **标题 Sans:** 仍使用 Geist,以 `font-medium` 和紧凑字距建立层级。首页主标题使用 `clamp(3.2rem, 7.2vw, 6.35rem)`、`line-height: 0.94`、`letter-spacing: -0.07em`。
- **Mono:** Geist Mono。用于日期、序号、路径、代码、状态和章节编号;不用于长段正文。
- **Label:** 10–12px 等宽大写或中文小标签,字距约 `0.12em`–`0.16em`,承担“记录数据”的异质感。
- **长文:** 标题最高 6 个字号层级;正文段落默认首行缩进 2 字符,列表项、表格单元格不缩进。可用 `<Indent n={N}>` / `<NoIndent>` 逐段覆盖。
- **小屏字级:** 依靠 `clamp()` 和 `md:` / `lg:` 断点调整,不缩放根字号。正文表格与代码块在小屏降到 12px。
## Layout
- **内容宽度:** 主内容最大宽度 `1120px`,左右留白移动端 20px、`sm:` 起 24px;长文正文列再收窄,避免宽幅直排。
- **导航:** 固定顶栏高 64px,`sm:` 起 80px。桌面链接居中,语言切换与 OpenClaw 入口靠右;移动端使用汉堡菜单。
- **首页:** 主标题与说明采用不对称 12 栏布局;板块垂直间距以 `py-16 md:py-24` 为主,局部叙事区可扩展到 `py-20 md:py-32`。
- **列表:** 实践和博客以规则线分隔的索引行呈现,不使用统一圆角卡片。实践桌面为 4/8 分栏图文行,博客为 2/7/2/1 的日期、标题、阅读时间和箭头结构。
- **详情:** OpenClaw 与实践详情在 `lg:` 使用 8/4 分栏:左侧正文,右侧 sticky 导航与相关内容;列表与首页封面按 16:9 裁切,详情头图以 `fit="contain"` 完整显示。新源图优先使用 16:9;`zhang.log.png` 是既有兼容特例。
- **断点:** 小屏基础值优先,`md = 768px`,`lg = 1024px`。移动端验收以 `360×800`、DPR 2 为硬性下限。
- **间距:** 4px 基础刻度;常用 `gap-4 md:gap-6`、`p-4 md:p-6`、`pt-28 sm:pt-36 lg:pt-40`。
## Components
- **navbar:** 全宽近黑半透明栏,底部一条 Rule;滚动向下隐藏、向上恢复。当前项用 Paper 与 Signal 小点表示,不使用大型悬浮胶囊。
- **button-primary:** Paper 实底胶囊 + Ink 文字,用于“查看实践”等高优先级入口;hover 变亮,不使用橙色铺底。
- **button-secondary:** 透明底 + Rule 描边胶囊,用于次级入口;hover 只提高边框和文字层级。
- **index-row:** 项目、博客和归档的主要列表单元。以 `border-t border-rule` 分隔,hover 让标题、箭头和局部底纹向 Signal 过渡;触屏使用 `:active` 提供即时按压反馈。
- **article-prose:** 实践与博客详情共用。H2 带章节编号和底部分隔线,H3 使用 Signal 左线;正文最大可读宽度随详情分栏收敛。
- **longform-nav:** 桌面显示完整 sticky 目录;小屏右侧显示刻度入口,点击后拉起底部抽屉。目录通过 portal 挂到 `body`,避免视差容器改变 fixed 定位参照。
- **code-block:** Geist Mono、Surface 底、语言标签与复制按钮;长行横向滚动,不手工折行。触屏设备让复制按钮常显。
- **media:** 本地资源优先,封面使用渐进模糊加载,正文图片支持灯箱与缩放。图片替代文本必须描述内容,不写文件名。
- **not-found:** 语言段内的未知路径与不存在的内容 slug 共用标题、说明、首页 / 实践 / 博客入口,并沿用 Navbar、Footer 与同一套暗色设计令牌。
## Motion
- 滚动惯性由 Lenis 提供;章节跳转需要立即打断惯性滚动,并保留可回访的 hash 锚点。
- 首屏轨道图表达“想法 → Agent → 现实”,底部 CTA 可在指针悬停或键盘聚焦时展开工作台场景。
- hover 只做小位移、边框提亮或颜色过渡;触屏通过 `:active` / `data-pressed` 给出反馈。
- 所有装饰动效必须支持 `prefers-reduced-motion: reduce`。动画不得遮挡正文、阻塞点击或改变布局尺寸。
## Quality Bar
- `360×800`、DPR 2 下页面 `scrollWidth ≤ 360`;宽表和长代码只在自身容器内横向滚动。
- 桌面与移动端都必须验证导航、列表筛选、分页、详情跳转、目录锚点、图片灯箱和回到顶部。
- 站内链接必须指向存在的路由、语言段和锚点;站外链接不得为空,必须指向有效目标,并明确是否新开窗口。
- 所有可交互元素要有可见焦点、可读标签和键盘操作;外链新开窗口时使用安全的 `rel`。
- 发布前执行内容生成、类型检查与生产构建,并同时检查中文与英文路由是否存在 404 或错误回退。
## Do's and Don'ts
**Do**
- 先用规则线、留白和字级建立结构,再考虑是否真的需要容器或阴影。
- 用 Signal 标记当前态、编号、状态点和少量关键动作。
- 优先使用真实内容密度组织页面;列表、表格和代码应能直接扫描。
- 保持移动端基础尺寸,再用 `md:` / `lg:` 恢复桌面尺度。
- 每次修改 UI 后同时检查桌面和小屏,至少覆盖 `360×800`。
**Don't**
- 不要把 Signal 铺成大面积背景,也不要用多套高饱和色并置。
- 不要恢复已淘汰的 Playfair Display、Inter、JetBrains Mono 字体组合描述。
- 不要把每个板块都包装成玻璃卡片;编辑式页面以规则线和非对称布局为主。
- 不要给纯展示面板添加橙色光晕、箭头或 hover 抬升,制造可点击错觉。
- 不要用缩放根字号实现小屏适配,也不要让页面主体产生横向溢出。
设计规范落地后,站点又做了一轮小屏(小于 768px)打磨:间距、内边距与圆角以移动端为基准值,用 md: 断点恢复桌面尺度;表格与代码块在小屏降到 12px,宽表与长代码行只在各自容器内横向滚动;正文段落默认首行缩进 2 字符,需要时可逐段覆盖。长文目录在小屏收敛为右侧刻度条,点击展开底部抽屉;因为目录节点挂在 body 上,它不会被视差容器的 transform 影响定位。
设计语言统一后,提示 Agent 每完成一部分实现,便可调用 playwright MCP 提供的网页访问和网页截图等工具,通过视觉能力查看截图,对比实际实现与预期实现效果,来修正代码,以达到预期实现。同时 Agent 可以参考优秀网页作品截图来实时回调我们的网页呈现效果,以及组件优化等。如此,不断的人与人工智能双方共同提示,设计,审核,验收,最后完成网站呈现效果的开发。
其他流程
除了上面提到的设计、结构与交互打磨,整个开发过程还有一些贯穿始终的流程,它们保证了与 Agent 协作的产出质量。
调用 GitNexus
Agent 使用 GitNexus 看懂代码库
这个项目的代码量会让"直接改"变得有风险,GitNexus 在"理解"和"修改"之间补了一层上下文。它把代码库索引成知识图谱,再通过 CLI 和 MCP 把调用关系、依赖链、执行流程交给 Agent 查询。
- 建立索引:
node .gitnexus/run.cjs analyze,让项目结构、符号关系和执行流程进入可查询状态。 - 理解代码:用
query找涉及的执行流程、context看某个符号的调用者与被调用者,代替在陌生代码里盲搜。 - 评估影响:改一个函数前先跑
impact看 upstream 依赖,判断直接调用者与风险范围;遇到 HIGH / CRITICAL 风险先停下确认。 - 检查变更:改完用
detect_changes核对影响范围有没有偏离预期,再做最终验收。git 提交前使用,作用非凡。
这些动作被写进了项目的 AGENTS.md / CLAUDE.md,形成强制习惯:编辑符号前必跑 impact,提交前后必跑 detect_changes,探索路径用 query 而不是 grep。
技能调用:工具的说明书
本项目用的是 gitnexus 系列技能:exploring、impact-analysis、debugging、refactoring、guide、cli,这些技能详细描述了 gitnexus 的使用技巧,Agent 可以高效使用工具。遇到符合技能触发场景的任务,先加载技能再动手,避免每一次都重新交代一遍上下文。
总结
本次网站开发,我主要负责管理、监控,而 Agent 则是任务的直接执行人。这次任务 Agent 表现出的是出色的编程,设计能力,而我则是全局统筹能力、 Prompt 设计能力和结果验收能力(测试能力)。总之,Agent 的出现,使得人在编程场景的身份正在由编码者转向管理者。人只需在统筹阶段、任务制定阶段、关键走向定夺阶段和最后的验收阶段出手,其余交给长出手脚的 AI —— Agent 来完成。
本次实践仓库链接:Y-King666/zhang.log