生成供 AI 编码代理直接实现的设计交接文档,所有值和状态都明确定义。
填写变量
填写后,下方提示词与复制内容会同步替换。
# Design Handoff Notes — AI-First, Human-Readable
### 一份结构化交接文档,专为 AI 实现代理(Claude Code、Cursor、Copilot)优化,同时保持对人类开发者的清晰度
---
## 关于此提示词
**描述:** 生成一份设计交接文档,作为 AI 编码代理的直接实现指令。与传统交接笔记描述设计“应有的感觉”不同,这份文档提供了机器可解析的规范,零歧义。每个值都是明确的,每个状态都有定义,每个边缘情况都有规则。文档的结构使得 AI 代理可以自上而下阅读并实现,无需询问澄清问题 —— 而人类开发者也能自然地阅读。
**核心理念:** 如果 AI 阅读此文档时不得不猜测任何内容,文档就失败了。
**使用时机:** 设计定稿后,实现开始前。这将取代 Figma 交接、设计规范 PDF 和“让它看起来像模型”的对话。
**读者:**
- 主要:AI 编码代理(Claude Code、Cursor、Copilot 等)
- 次要:审查或调试 AI 输出的人类开发者
- 第三:你(设计师),在检查实现是否符合意图时
**与 CLAUDE.md 的关系:** 此文档假设项目根目录中已存在 CLAUDE.md 设计系统文件。交接笔记引用 CLAUDE.md 中的标记,但不重新定义它们。如果不存在 CLAUDE.md,请先运行设计系统提取提示词。
---
## 提示词
```
你是一名设计系统工程师,正在编写实现规范。
你的输出将主要由 AI 编码代理(Claude Code、Cursor)阅读,其次是人类开发者。
你的写作必须遵循一个绝对规则:
**如果读者不得不猜测、推断或假设任何内容,你就失败了。**
每个值都必须是明确的。每个状态都必须有定义。每个边缘情况都必须有规则。没有“酌情”,没有“大致”,没有“类似于”。
## 项目上下文
- **项目:** {{project_name}}
- **框架:** [Next.js 14+ / React / 等]
- **样式:** [Tailwind 3.x / CSS Modules / 等]
- **组件库:** [shadcn/ui / 自定义 / 等]
- **CLAUDE.md 位置:** [路径 — 或“尚未创建”]
- **设计来源:** [上传的代码 / 实时 URL / 截图]
- **要规范的页面:** [全部 / 特定页面]
## 输出格式规则
在编写任何规范之前,请严格遵守以下格式规则:
1. **值始终是代码就绪的。**
错误:“中等间距”
正确:`p-6` (24px)
2. **颜色始终是标记引用 + 备用十六进制值。**
错误:“品牌蓝色”
正确:`text-brand-500` (#2563EB) — 来自 CLAUDE.md 标记
3. **大小始终使用项目的单位系统。**
如果使用 Tailwind:使用 Tailwind 类作为主要单位,px 作为注释
如果使用 CSS:使用 rem 作为主要单位,px 作为注释
错误:“在桌面上放大”
正确:`text-lg` (18px) 在 ≥768px 时,`text-base` (16px) 在以下时
4. **条件句使用明确的 if/else,绝不使用“酌情”。**
错误:“酌情显示加载状态”
正确:“如果数据获取时间 >300ms,显示骨架。如果获取失败,显示错误状态。如果数据返回空数组,显示空状态。”
5. **文件路径是明确的。**
错误:“创建一个按钮组件”
正确:“创建 `src/components/ui/Button.tsx`”
6. **每个视觉属性都明确说明,绝不通过假设继承。**
即使“显而易见” —— 也要说明。AI 代理没有视觉上下文。
---
## 文档结构
生成交接文档时包含以下部分:
### 第 1 部分:实现地图
一个优先级排序的表格,列出所有要构建的内容。
AI 代理应按此顺序实现,以正确解决依赖关系。
| 顺序 | 组件/部分 | 文件路径 | 依赖 | 复杂度 | 备注 |
|-------|------------------|-----------|-------------|-----------|-------|
| 1 | 设计标记设置 | `tailwind.config.ts` | 无 | 低 | 必须首先 —— 所有其他组件都引用这些 |
| 2 | 排版组件 | `src/components/ui/Text.tsx` | 标记 | 低 | 标题、正文、说明、标签变体 |
| 3 | 按钮 | `src/components/ui/Button.tsx` | 标记、排版 | 中 | 3 种变体 × 3 种大小 × 6 种状态 |
| ... | ... | ... | ... | ... | ... |
规则:
- 任何内容都不能引用表格中后面的组件
- 复杂度 = 组件有多少变体 × 状态
- 备注 = 任何关于实现的不明显内容
---
### 第 2 部分:全局规范
这些适用于所有地方。AI 代理应在构建任何组件之前配置这些。
#### 2.1 断点
定义确切的行为边界:
```
BREAKPOINTS {
mobile: 0px — 767px
tablet: 768px — 1023px
desktop: 1024px — 1279px
wide: 1280px — ∞
}
```
对于每个断点,说明:
- 容器最大宽度和内边距
- 基本字体大小
- 全局间距乘数(如果变化)
- 导航模式(汉堡菜单 / 水平 / 等)
#### 2.2 过渡默认值
```
TRANSITIONS {
慢速:duration-300 ease-in-out
弹簧:duration-500 cubic-bezier(0.34, 1.56, 0.64, 1)
无:duration-0
}
规则:除非本文档另有规定,否则每个交互元素都使用 `default`。
规则:过渡效果应用于:background-color、color、border-color、opacity、transform、box-shadow。绝不应用于:width、height、padding、margin(这些会导致布局重新计算)。
#### 2.3 Z-Index 层级
```
Z-INDEX {
base: 0
dropdown: 10
sticky: 20
overlay: 30
modal: 40
toast: 50
tooltip: 60
}
规则:绝不使用此层级之外的 z-index 值。
```
#### 2.4 焦点样式
```
FOCUS {
style: ring-2 ring-offset-2 ring-brand-500
applies-to: 每个交互元素(按钮、链接、输入框、选择框、复选框)
visible: 仅在键盘导航时可见(使用 focus-visible,而非 focus)
}
```
---
### 第 3 部分:页面规范
为每个页面提供完整的实现规范。
#### 页面:${page_name}
**路由:** `/exact-route-path`
**布局:** ${which_layout_wrapper_to_use}
**数据需求:** [此页面需要的数据,来源]
##### 页面结构(从上到下)
```
页面结构:${page_name}
├── 部分:Hero
│ ├── 组件:标题 (h1)
│ ├── 组件:副标题 (p)
│ ├── 组件:CTA 按钮 (primary, lg)
│ └── 组件:HeroImage
├── 部分:Features
│ ├── 组件:SectionHeading (h2)
│ └── 组件:FeatureCard × 3 (grid)
├── 部分:Testimonials
│ └── 组件:TestimonialSlider
└── 部分:CTA
├── 组件:标题 (h2)
└── 组件:CTA 按钮 (primary, lg)
```
##### 逐部分规范
为每个部分提供:
**${section_name}**
```
布局 {
container: max-w-[1280px] mx-auto px-6 (移动端: px-4)
direction: flex-col (移动端) → flex-row (桌面端)
gap: gap-8 (32px)
padding: py-16 (64px) (移动端: py-10)
background: bg-white
}
内容 {
heading {
text: "${exact_heading_text_or_content_source}"
element: h2
class: text-3xl font-bold text-gray-900 (移动端: text-2xl)
max-width: max-w-[640px]
}
body {
text: "${exact_body_text_or_content_source}"
class: text-lg text-gray-600 leading-relaxed (移动端: text-base)
max-width: max-w-[540px]
}
}
网格(如适用) {
columns: grid-cols-3 (平板: grid-cols-2) (移动端: grid-cols-1)
gap: gap-6 (24px)
items: ${what_component_renders_in_each_cell}
alignment: items-start
}
动画(如适用) {
type: fade-up on scroll
trigger: 当部分进入视口时触发(阈值: 0.2)
stagger: 每个子元素在前一个之后延迟 100ms
duration: duration-500
easing: ease-out
runs: 一次(在向上滚动时不重新触发)
}
```
---
### 第 4 部分:组件规范
为每个组件提供完整的实现契约。
#### 组件:${componentname}
**文件:** `src/components/${path}/${componentname}.tsx`
**用途:** [一句话 —— 此组件的作用]
##### Props 接口
```typescript
interface ${componentname}Props {
variant: 'primary' | 'secondary' | 'ghost' // 视觉样式
size: 'sm' | 'md' | 'lg' // 尺寸
disabled?: boolean // 默认: false
loading?: boolean // 默认: false
icon?: React.ReactNode // 可选的前导图标
children: React.ReactNode // 标签内容
onClick?: () => void // 点击处理程序
}
```
##### 变体 × 尺寸矩阵
为每种组合定义确切值:
```
变体:primary
尺寸:sm
height: h-8 (32px)
padding: px-3 (12px)
font: text-sm font-medium (14px)
background: bg-brand-500 (#2563EB)
text: text-white (#FFFFFF)
border: none
border-radius: rounded-md (6px)
shadow: none
尺寸:md
height: h-10 (40px)
padding: px-4 (16px)
font: text-sm font-medium (14px)
background: bg-brand-500 (#2563EB)
text: text-white (#FFFFFF)
border: none
border-radius: rounded-lg (8px)
shadow: shadow-sm
尺寸:lg
height: h-12 (48px)
padding: px-6 (24px)
font: text-base font-semibold (16px)
background: bg-brand-500 (#2563EB)
text: text-white (#FFFFFF)
border: none
border-radius: rounded-lg (8px)
shadow: shadow-sm
变体:secondary
[相同结构,不同值]
变体:ghost
[相同结构,不同值]
```
##### 状态规范
每个变体的每个状态都必须定义:
```
状态(适用于所有变体,除非被覆盖):
hover {
变换: 无(悬停时不缩放/平移)
阴影: ${token_or_none}
光标: 指针
过渡: 默认(duration-200 ease-out)
}
激活状态 {
背景: ${token} — 比默认值加深两级
变换: scale-[0.98]
过渡: duration-75
}
焦点可见状态 {
环: ring-2 ring-offset-2 ring-brand-500
其他: 与默认状态相同
}
禁用状态 {
不透明度: opacity-50
光标: 不允许
指针事件: 无
所有悬停/激活/焦点状态:不适用
}
加载状态 {
内容: 用旋转器替换子元素(16px,animate-spin)
宽度: 保持与非加载状态相同的宽度(防止布局偏移)
指针事件: 无
不透明度: opacity-80
}
```
##### 图标行为
```
图标规则 {
位置: 始终在标签文本左侧
大小: 16px(小),16px(中),20px(大)
间距: gap-1.5(小),gap-2(中),gap-2(大)
颜色: 继承文本颜色(currentColor)
加载时: 图标隐藏,旋转器占据其位置
仅图标: 若无子元素,组件变为正方形(宽度 = 高度)
添加 aria-label 属性要求
}
```
---
### 第 5 部分:交互流程
为每个用户流程提供逐步实现:
#### 流程:[流程名称,例如“用户注册”]
```
触发: 用户点击页头中的“注册”按钮
步骤 1: 模态框打开
动画: 淡入(opacity 0→1,duration-200)
背景: bg-black/50,点击外部关闭模态框
焦点: 将焦点锁定在模态框内,自动聚焦第一个输入框
主体: 滚动锁定(防止背景滚动)
步骤 2: 用户填写表单
字段: ${list_exact_fields_with_validation_rules}
验证: 在失去焦点时(而非变化时 — 减少噪音)
字段:电子邮件 {
类型: email
必填: true
验证: 正则表达式模式 + “必须包含 @ 和域名”
错误: “这看起来不像电子邮件 — 检查是否有拼写错误”
成功: 绿色勾号图标出现(淡入,duration-150)
}
字段:密码 {
类型: 密码(带显示/隐藏切换)
必填: true
验证: 至少 8 个字符,1 个大写字母,1 个数字
错误: 显示需求清单,突出未满足项
强度: 显示强度条(弱/中/强)
}
步骤 3: 用户提交
按钮: 显示加载状态(参见按钮组件规范)
请求: POST /api/auth/signup
持续时间: 预计 1-3 秒
步骤 4a: 成功
模态框: 内容过渡到成功消息(交叉淡入,duration-200)
消息: “账户已创建!请检查您的电子邮件以验证。”
操作: “知道了”按钮关闭模态框
重定向: 关闭后重定向到 /dashboard
提示: 无(模态框本身就是确认)
步骤 4b: 错误 — 电子邮件已存在
字段: 电子邮件输入显示错误状态
消息: “此电子邮件已有账户 — 要登录吗?”
操作: “登录”链接将模态框切换到登录表单
按钮: 返回默认状态(非加载)
步骤 4c: 错误 — 网络故障
显示: 模态框顶部的错误横幅(非提示)
消息: “我们这边出了点问题。再试一次?”
操作: “再试一次”按钮重新提交
按钮: 返回默认状态
步骤 4d: 错误 — 限速
显示: 错误横幅
消息: “尝试次数过多。请等待 60 秒后再试。”
按钮: 禁用 60 秒,并显示倒计时
```
---
### 第 6 部分:响应行为规则
不要描述变化 — 指定确切规则:
```
响应规则:
规则 1:导航
≥1024px: 水平导航,所有项目可见
<1024px: 汉堡图标,从右侧滑入抽屉
抽屉宽度:80vw(max-w-[320px])
动画:translate-x(duration-300 ease-out)
背景:bg-black/50,点击外部关闭
规则 2:网格部分
≥1024px: grid-cols-3
768-1023px:grid-cols-2(如果数量为奇数,最后一项跨满)
<768px: grid-cols-1
规则 3:英雄部分
≥1024px: 两列(文本左,图片右)— 55/45 分割
<1024px: 单列(文本上,图片下)
图片最大高度:400px,object-cover
规则 4:排版缩放
≥1024px: h1=text-5xl, h2=text-3xl, h3=text-xl, body=text-base
<1024px: h1=text-3xl, h2=text-2xl, h3=text-lg, body=text-base
```
≥1024px: section-padding: py-16, container-padding: px-8
768-1023px: section-padding: py-12, container-padding: px-6
<768px: section-padding: py-10, container-padding: px-4
规则 6:触摸目标
<1024px: 所有交互元素的最小点击区域为 44×44px
如果视觉尺寸小于 44px,使用不可见的填充以达到 44px
规则 7:图片
所有图片:使用 next/image 并设置响应式 sizes 属性
首图:sizes="(max-width: 1024px) 100vw, 50vw"
网格项:sizes="(max-width: 768px) 100vw, (max-width: 1024px) 50vw, 33vw"
---
### 第 7 部分:边缘情况与边界条件
本部分旨在防止“但当……时会发生什么”的问题:
```
边缘情况:
文本溢出 {
标题:最多 2 行,超出部分用 text-ellipsis 截断(添加 title 属性显示完整文本)
正文:允许自然换行,不截断
按钮标签:仅单行,最多 30 个字符,不截断(设计约束)
导航项:单行,移动端超过 16 个字符时截断
表格单元格:悬停时显示工具提示并截断
}
空状态 {
列表/网格无项目时:显示 ${emptystate} 组件
- 插图:${describe_or_reference_asset}
- 标题:"${exact_text}"
- 正文:"${exact_text}"
- 行动号召:"${exact_text}" → ${action}
用户头像缺失时:显示彩色背景上的首字母
- 背景:根据用户名哈希生成(确定性)
- 首字母:姓氏和名字的首字母,大写
- 字体:text-sm font-medium text-white
图片加载失败时:显示带图片图标的灰色占位符
- 背景:bg-gray-100
- 图标:来自 lucide-react 的 ImageOff,text-gray-400,24px
}
加载状态 {
页面加载:全页面骨架屏(非旋转图标)
组件加载:与最终尺寸匹配的组件级骨架屏
按钮操作:按钮内的内联旋转图标(参见按钮规范)
无限列表:在获取下一页时底部显示 3 行骨架屏
骨架屏样式:bg-gray-200 rounded animate-pulse
骨架屏规则:骨架屏形状必须与最终内容形状匹配
(文本为矩形,头像为圆形,卡片为 rounded-lg)
}
错误状态 {
API 错误(500):显示带重试按钮的内联错误横幅
网络错误:在顶部显示“您似乎已离线”横幅(重新连接时自动消失)
404 内容:显示自定义 404 组件(非 Next.js 默认)
权限被拒绝:重定向到 /login 并附带返回 URL 参数
表单验证:每个字段内联验证(参见流程规范),不使用 alert()
}
数据极端情况 {
用户名 1 个字符:正常显示
用户名 50 个字符:导航中截断为 20 个字符,个人资料中显示完整
价格 $0.00:显示“免费”
价格 $999,999.99:确保布局不破坏(测试格式化数字)
列表 1 项:与多项目布局相同(无特殊情况)
列表 500 项:每页 20 项分页,显示“加载更多”按钮
日期为今天:显示“今天”而非日期
日期为今年:显示“3 月 13 日”而非“2026 年 3 月 13 日”
日期为其他年份:显示“2025 年 3 月 13 日”
}
```
---
### 第 8 部分:实现验证清单
实现后,AI 代理(或人类开发者)应验证:
```
验证:
□ 每个组件完全匹配变体 × 尺寸矩阵
□ 每个状态(悬停、激活、聚焦、禁用、加载)均正常工作
□ 所有页面的 Tab 顺序遵循视觉顺序
□ 焦点可见环仅在键盘导航时出现,鼠标点击时不出现
□ 所有过渡使用指定的持续时间和缓动(非浏览器默认)
□ 页面加载期间无布局偏移(检查 CLS)
□ 骨架屏状态与最终内容尺寸匹配
□ 第 7 部分的所有边缘情况均已处理
□ 移动断点上的触摸目标 ≥ 44×44px
□ 任何断点下均无水平滚动
□ 所有图片使用 next/image 并设置正确的 sizes 属性
□ Z-index 值仅使用定义的刻度
□ 错误状态正确显示(使用网络节流测试)
□ 空状态正确显示(使用空数据测试)
□ 文本截断在边界长度时正常工作
□ 深色模式令牌(如适用)均已映射
```
---
## AI 代理应如何使用本文档
在生成的交接文档顶部包含此指令,以便实现 AI 知道如何操作:
```
AI 实现代理的指令:
1. 在编写任何代码之前,完整阅读本文档。
2. 按照第 1 部分(实现地图)中指定的顺序实现。
3. 参考 CLAUDE.md 获取令牌值。如果此处引用的令牌不在 CLAUDE.md 中,请标记并使用提供的回退值。
4. 本文档中的每个值都是有意的。不要用“接近”的值替代。`gap-6` 意味着 `gap-6`,而不是 `gap-5`。
5. 必须实现每个状态。如果未为组件指定状态,则这是规范中的空白——请标记,不要猜测。
6. 实现每个组件后,运行其状态矩阵并验证所有状态正常工作,然后再继续下一个组件。
```
7. 遇到歧义时,优先采用更明确的解释。
如果仍有歧义,添加一个 TODO 注释:"// HANDOFF-AMBIGUITY: [描述]"
```
```
---
## 自定义说明
**如果你不使用 Tailwind:** 将提示词中的所有 Tailwind 类引用替换为你系统中的等效项。结构保持不变——仅值格式发生变化。告诉 Claude:"优先使用 CSS 自定义属性,px 值作为注释。"
**如果你要交接给特定的 AI 工具:** 添加工具特定的说明。例如,对于 Cursor:"生成实现时,作为对现有文件的逐步编辑,而不是完整的文件重写。" 对于 Claude Code:"将每个组件创建为一个完整的文件,测试它,然后继续下一个。"
**如果还没有 CLAUDE.md 文件:** 告诉提示词在交接文档顶部生成一个最小的 token 部分,仅涵盖此次特定交接所需的 token。它不会是一个完整的设计系统,但可以防止硬编码值。
**对于多页面项目:** 每页运行一次提示词,但仅在第一次运行时包含第 1 节(实现地图)和第 2 节(全局规范)。后续页面引用相同的全局规范。# Design Handoff Notes — AI-First, Human-Readable
### A structured handoff document optimized for AI implementation agents (Claude Code, Cursor, Copilot) while remaining clear for human developers
---
## About This Prompt
**Description:** Generates a design handoff document that serves as direct implementation instructions for AI coding agents. Unlike traditional handoff notes that describe how a design "should feel," this document provides machine-parseable specifications with zero ambiguity. Every value is explicit, every state is defined, every edge case has a rule. The document is structured so an AI agent can read it top-to-bottom and implement without asking clarifying questions — while a human developer can also read it naturally.
**The core philosophy:** If an AI reads this document and has to guess anything, the document has failed.
**When to use:** After design is finalized, before implementation begins. This replaces Figma handoff, design spec PDFs, and "just make it look like the mockup" conversations.
**Who reads this:**
- Primary: AI coding agents (Claude Code, Cursor, Copilot, etc.)
- Secondary: Human developers reviewing or debugging the AI's output
- Tertiary: You (the designer), when checking if implementation matches intent
**Relationship to CLAUDE.md:** This document assumes a CLAUDE.md design system file already exists in the project root. Handoff Notes reference tokens from CLAUDE.md but don't redefine them. If no CLAUDE.md exists, run the Design System Extraction prompts first.
---
## The Prompt
```
You are a design systems engineer writing implementation specifications.
Your output will be read primarily by AI coding agents (Claude Code, Cursor)
and secondarily by human developers.
Your writing must follow one absolute rule:
**If the reader has to guess, infer, or assume anything, you have failed.**
Every value must be explicit. Every state must be defined. Every edge case
must have a rule. No "as appropriate," no "roughly," no "similar to."
## Project Context
- **Project:** {{project_name}}
- **Framework:** [Next.js 14+ / React / etc.]
- **Styling:** [Tailwind 3.x / CSS Modules / etc.]
- **Component library:** [shadcn/ui / custom / etc.]
- **CLAUDE.md location:** [path — or "not yet created"]
- **Design source:** [uploaded code / live URL / screenshots]
- **Pages to spec:** [all / specific pages]
## Output Format Rules
Before writing any specs, follow these formatting rules exactly:
1. **Values are always code-ready.**
WRONG: "medium spacing"
RIGHT: `p-6` (24px)
2. **Colors are always token references + fallback hex.**
WRONG: "brand blue"
RIGHT: `text-brand-500` (#2563EB) — from CLAUDE.md tokens
3. **Sizes are always in the project's unit system.**
If Tailwind: use Tailwind classes as primary, px as annotation
If CSS: use rem as primary, px as annotation
WRONG: "make it bigger on desktop"
RIGHT: `text-lg` (18px) at ≥768px, `text-base` (16px) below
4. **Conditionals use explicit if/else, never "as needed."**
WRONG: "show loading state as appropriate"
RIGHT: "if data fetch takes >300ms, show skeleton. If fetch fails, show error state. If data returns empty array, show empty state."
5. **File paths are explicit.**
WRONG: "create a button component"
RIGHT: "create `src/components/ui/Button.tsx`"
6. **Every visual property is stated, never inherited by assumption.**
Even if "obvious" — state it. AI agents don't have visual context.
---
## Document Structure
Generate the handoff document with these sections:
### SECTION 1: IMPLEMENTATION MAP
A priority-ordered table of everything to build.
AI agents should implement in this order to resolve dependencies correctly.
| Order | Component/Section | File Path | Dependencies | Complexity | Notes |
|-------|------------------|-----------|-------------|-----------|-------|
| 1 | Design tokens setup | `tailwind.config.ts` | None | Low | Must be first — all other components reference these |
| 2 | Typography components | `src/components/ui/Text.tsx` | Tokens | Low | Heading, Body, Caption, Label variants |
| 3 | Button | `src/components/ui/Button.tsx` | Tokens, Typography | Medium | 3 variants × 3 sizes × 6 states |
| ... | ... | ... | ... | ... | ... |
Rules:
- Nothing can reference a component that comes later in the table
- Complexity = how many variants × states the component has
- Notes = anything non-obvious about implementation
---
### SECTION 2: GLOBAL SPECIFICATIONS
These apply everywhere. AI agent should configure these BEFORE building any components.
#### 2.1 Breakpoints
Define exact behavior boundaries:
```
BREAKPOINTS {
mobile: 0px — 767px
tablet: 768px — 1023px
desktop: 1024px — 1279px
wide: 1280px — ∞
}
```
For each breakpoint, state:
- Container max-width and padding
- Base font size
- Global spacing multiplier (if it changes)
- Navigation mode (hamburger / horizontal / etc.)
#### 2.2 Transition Defaults
```
TRANSITIONS {
default: duration-200 ease-out
slow: duration-300 ease-in-out
spring: duration-500 cubic-bezier(0.34, 1.56, 0.64, 1)
none: duration-0
}
RULE: Every interactive element uses `default` unless
this document specifies otherwise.
RULE: Transitions apply to: background-color, color, border-color,
opacity, transform, box-shadow. Never to: width, height, padding,
margin (these cause layout recalculation).
```
#### 2.3 Z-Index Scale
```
Z-INDEX {
base: 0
dropdown: 10
sticky: 20
overlay: 30
modal: 40
toast: 50
tooltip: 60
}
RULE: No z-index value outside this scale. Ever.
```
#### 2.4 Focus Style
```
FOCUS {
style: ring-2 ring-offset-2 ring-brand-500
applies-to: every interactive element (buttons, links, inputs, selects, checkboxes)
visible: only on keyboard navigation (use focus-visible, not focus)
}
```
---
### SECTION 3: PAGE SPECIFICATIONS
For each page, provide a complete implementation spec.
#### Page: ${page_name}
**Route:** `/exact-route-path`
**Layout:** ${which_layout_wrapper_to_use}
**Data requirements:** [what data this page needs, from where]
##### Page Structure (top to bottom)
```
PAGE STRUCTURE: ${page_name}
├── Section: Hero
│ ├── Component: Heading (h1)
│ ├── Component: Subheading (p)
│ ├── Component: CTA Button (primary, lg)
│ └── Component: HeroImage
├── Section: Features
│ ├── Component: SectionHeading (h2)
│ └── Component: FeatureCard × 3 (grid)
├── Section: Testimonials
│ └── Component: TestimonialSlider
└── Section: CTA
├── Component: Heading (h2)
└── Component: CTA Button (primary, lg)
```
##### Section-by-Section Specs
For each section:
**${section_name}**
```
LAYOUT {
container: max-w-[1280px] mx-auto px-6 (mobile: px-4)
direction: flex-col (mobile) → flex-row (desktop)
gap: gap-8 (32px)
padding: py-16 (64px) (mobile: py-10)
background: bg-white
}
CONTENT {
heading {
text: "${exact_heading_text_or_content_source}"
element: h2
class: text-3xl font-bold text-gray-900 (mobile: text-2xl)
max-width: max-w-[640px]
}
body {
text: "${exact_body_text_or_content_source}"
class: text-lg text-gray-600 leading-relaxed (mobile: text-base)
max-width: max-w-[540px]
}
}
GRID (if applicable) {
columns: grid-cols-3 (tablet: grid-cols-2) (mobile: grid-cols-1)
gap: gap-6 (24px)
items: ${what_component_renders_in_each_cell}
alignment: items-start
}
ANIMATION (if applicable) {
type: fade-up on scroll
trigger: when section enters viewport (threshold: 0.2)
stagger: each child delays 100ms after previous
duration: duration-500
easing: ease-out
runs: once (do not re-trigger on scroll up)
}
```
---
### SECTION 4: COMPONENT SPECIFICATIONS
For each component, provide a complete implementation contract.
#### Component: ${componentname}
**File:** `src/components/${path}/${componentname}.tsx`
**Purpose:** [one sentence — what this component does]
##### Props Interface
```typescript
interface ${componentname}Props {
variant: 'primary' | 'secondary' | 'ghost' // visual style
size: 'sm' | 'md' | 'lg' // dimensions
disabled?: boolean // default: false
loading?: boolean // default: false
icon?: React.ReactNode // optional leading icon
children: React.ReactNode // label content
onClick?: () => void // click handler
}
```
##### Variant × Size Matrix
Define exact values for every combination:
```
VARIANT: primary
SIZE: sm
height: h-8 (32px)
padding: px-3 (12px)
font: text-sm font-medium (14px)
background: bg-brand-500 (#2563EB)
text: text-white (#FFFFFF)
border: none
border-radius: rounded-md (6px)
shadow: none
SIZE: md
height: h-10 (40px)
padding: px-4 (16px)
font: text-sm font-medium (14px)
background: bg-brand-500 (#2563EB)
text: text-white (#FFFFFF)
border: none
border-radius: rounded-lg (8px)
shadow: shadow-sm
SIZE: lg
height: h-12 (48px)
padding: px-6 (24px)
font: text-base font-semibold (16px)
background: bg-brand-500 (#2563EB)
text: text-white (#FFFFFF)
border: none
border-radius: rounded-lg (8px)
shadow: shadow-sm
VARIANT: secondary
[same structure, different values]
VARIANT: ghost
[same structure, different values]
```
##### State Specifications
Every state must be defined for every variant:
```
STATES (apply to ALL variants unless overridden):
hover {
background: ${token} — darken one step from default
transform: none (no scale/translate on hover)
shadow: ${token_or_none}
cursor: pointer
transition: default (duration-200 ease-out)
}
active {
background: ${token} — darken two steps from default
transform: scale-[0.98]
transition: duration-75
}
focus-visible {
ring: ring-2 ring-offset-2 ring-brand-500
all other: same as default state
}
disabled {
opacity: opacity-50
cursor: not-allowed
pointer-events: none
ALL hover/active/focus states: do not apply
}
loading {
content: replace children with spinner (16px, animate-spin)
width: maintain same width as non-loading state (prevent layout shift)
pointer-events: none
opacity: opacity-80
}
```
##### Icon Behavior
```
ICON RULES {
position: left of label text (always)
size: 16px (sm), 16px (md), 20px (lg)
gap: gap-1.5 (sm), gap-2 (md), gap-2 (lg)
color: inherits text color (currentColor)
when loading: icon is hidden, spinner takes its position
icon-only: if no children, component becomes square (width = height)
add aria-label prop requirement
}
```
---
### SECTION 5: INTERACTION FLOWS
For each user flow, provide step-by-step implementation:
#### Flow: [Flow Name, e.g., "User Signs Up"]
```
TRIGGER: user clicks "Sign Up" button in header
STEP 1: Modal opens
animation: fade-in (opacity 0→1, duration-200)
backdrop: bg-black/50, click-outside closes modal
focus: trap focus inside modal, auto-focus first input
body: scroll-lock (prevent background scroll)
STEP 2: User fills form
fields: ${list_exact_fields_with_validation_rules}
validation: on blur (not on change — reduces noise)
field: email {
type: email
required: true
validate: regex pattern + "must contain @ and domain"
error: "That doesn't look like an email — check for typos"
success: green checkmark icon appears (fade-in, duration-150)
}
field: password {
type: password (with show/hide toggle)
required: true
validate: min 8 chars, 1 uppercase, 1 number
error: show checklist of requirements, highlight unmet
strength: show strength bar (weak/medium/strong)
}
STEP 3: User submits
button: shows loading state (see Button component spec)
request: POST /api/auth/signup
duration: expect 1-3 seconds
STEP 4a: Success
modal: content transitions to success message (crossfade, duration-200)
message: "Account created! Check your email to verify."
action: "Got it" button closes modal
redirect: after close, redirect to /dashboard
toast: none (the modal IS the confirmation)
STEP 4b: Error — email exists
field: email input shows error state
message: "This email already has an account — want to log in instead?"
action: "Log in" link switches modal to login form
button: returns to default state (not loading)
STEP 4c: Error — network failure
display: error banner at top of modal (not a toast)
message: "Something went wrong on our end. Try again?"
action: "Try again" button re-submits
button: returns to default state
STEP 4d: Error — rate limited
display: error banner
message: "Too many attempts. Wait 60 seconds and try again."
button: disabled for 60 seconds with countdown visible
```
---
### SECTION 6: RESPONSIVE BEHAVIOR RULES
Don't describe what changes — specify the exact rules:
```
RESPONSIVE RULES:
Rule 1: Navigation
≥1024px: horizontal nav, all items visible
<1024px: hamburger icon, slide-in drawer from right
drawer-width: 80vw (max-w-[320px])
animation: translate-x (duration-300 ease-out)
backdrop: bg-black/50, click-outside closes
Rule 2: Grid Sections
≥1024px: grid-cols-3
768-1023px: grid-cols-2 (last item spans full if odd count)
<768px: grid-cols-1
Rule 3: Hero Section
≥1024px: two-column (text left, image right) — 55/45 split
<1024px: single column (text top, image bottom)
image max-height: 400px, object-cover
Rule 4: Typography Scaling
≥1024px: h1=text-5xl, h2=text-3xl, h3=text-xl, body=text-base
<1024px: h1=text-3xl, h2=text-2xl, h3=text-lg, body=text-base
Rule 5: Spacing Scaling
≥1024px: section-padding: py-16, container-padding: px-8
768-1023px: section-padding: py-12, container-padding: px-6
<768px: section-padding: py-10, container-padding: px-4
Rule 6: Touch Targets
<1024px: all interactive elements minimum 44×44px hit area
if visual size < 44px, use invisible padding to reach 44px
Rule 7: Images
all images: use next/image with responsive sizes prop
hero: sizes="(max-width: 1024px) 100vw, 50vw"
grid items: sizes="(max-width: 768px) 100vw, (max-width: 1024px) 50vw, 33vw"
```
---
### SECTION 7: EDGE CASES & BOUNDARY CONDITIONS
This section prevents the "but what happens when..." problems:
```
EDGE CASES:
Text Overflow {
headings: max 2 lines, then truncate with text-ellipsis (add title attr for full text)
body text: allow natural wrapping, no truncation
button labels: single line only, max 30 characters, no truncation (design constraint)
nav items: single line, truncate if >16 characters on mobile
table cells: truncate with tooltip on hover
}
Empty States {
lists/grids with 0 items: show ${emptystate} component
- illustration: ${describe_or_reference_asset}
- heading: "${exact_text}"
- body: "${exact_text}"
- CTA: "${exact_text}" → ${action}
user avatar missing: show initials on colored background
- background: generate from user name hash (deterministic)
- initials: first letter of first + last name, uppercase
- font: text-sm font-medium text-white
image fails to load: show gray placeholder with image icon
- background: bg-gray-100
- icon: ImageOff from lucide-react, text-gray-400, 24px
}
Loading States {
page load: full-page skeleton (not spinner)
component load: component-level skeleton matching final dimensions
button action: inline spinner in button (see Button spec)
infinite list: skeleton row × 3 at bottom while fetching next page
skeleton style: bg-gray-200 rounded animate-pulse
skeleton rule: skeleton shape must match final content shape
(rectangle for text, circle for avatars, rounded-lg for cards)
}
Error States {
API error (500): show inline error banner with retry button
Network error: show "You seem offline" banner at top (auto-dismiss when reconnected)
404 content: show custom 404 component (not Next.js default)
Permission denied: redirect to /login with return URL param
Form validation: inline per-field (see flow specs), never alert()
}
Data Extremes {
username 1 character: display normally
username 50 characters: truncate at 20 in nav, full in profile
price $0.00: show "Free"
price $999,999.99: ensure layout doesn't break (test with formatted number)
list with 1 item: same layout as multiple (no special case)
list with 500 items: paginate at 20, show "Load more" button
date today: show "Today" not the date
date this year: show "Mar 13" not "Mar 13, 2026"
date other year: show "Mar 13, 2025"
}
```
---
### SECTION 8: IMPLEMENTATION VERIFICATION CHECKLIST
After implementation, the AI agent (or human developer) should verify:
```
VERIFICATION:
□ Every component matches the variant × size matrix exactly
□ Every state (hover, active, focus, disabled, loading) works
□ Tab order follows visual order on all pages
□ Focus-visible ring appears on keyboard nav, not on mouse click
□ All transitions use specified duration and easing (not browser default)
□ No layout shift during page load (check CLS)
□ Skeleton states match final content dimensions
□ All edge cases from Section 7 are handled
□ Touch targets ≥ 44×44px on mobile breakpoints
□ No horizontal scroll at any breakpoint
□ All images use next/image with correct sizes prop
□ Z-index values only use the defined scale
□ Error states display correctly (test with network throttle)
□ Empty states display correctly (test with empty data)
□ Text truncation works at boundary lengths
□ Dark mode tokens (if applicable) are all mapped
```
---
## How the AI Agent Should Use This Document
Include this instruction at the top of the generated handoff document
so the implementing AI knows how to work with it:
```
INSTRUCTIONS FOR AI IMPLEMENTATION AGENT:
1. Read this document fully before writing any code.
2. Implement in the order specified in SECTION 1 (Implementation Map).
3. Reference CLAUDE.md for token values. If a token referenced here
is not in CLAUDE.md, flag it and use the fallback value provided.
4. Every value in this document is intentional. Do not substitute
with "close enough" values. `gap-6` means `gap-6`, not `gap-5`.
5. Every state must be implemented. If a state is not specified for
a component, that is a gap in the spec — flag it, do not guess.
6. After implementing each component, run through its state matrix
and verify all states work before moving to the next component.
7. When encountering ambiguity, prefer the more explicit interpretation.
If still ambiguous, add a TODO comment: "// HANDOFF-AMBIGUITY: [description]"
```
```
---
## Customization Notes
**If you're not using Tailwind:** Replace all Tailwind class references in the prompt with your system's equivalents. The structure stays the same — only the value format changes. Tell Claude: "Use CSS custom properties as primary, px values as annotations."
**If you're handing off to a specific AI tool:** Add tool-specific notes. For example, for Cursor: "Generate implementation as step-by-step edits to existing files, not full file rewrites." For Claude Code: "Create each component as a complete file, test it, then move to the next."
**If no CLAUDE.md exists yet:** Tell the prompt to generate a minimal token section at the top of the handoff document covering only the tokens needed for this specific handoff. It won't be a full design system, but it prevents hardcoded values.
**For multi-page projects:** Run the prompt once per page, but include Section 1 (Implementation Map) and Section 2 (Global Specs) only in the first run. Subsequent pages reference the same globals.