中文译文
设计交接说明 — AI 优先,人类可读
一份结构化交接文档,针对 AI 实现代理(Claude Code、Cursor、Copilot)优化,同时对人类开发者保持清晰
关于此提示词
描述: 生成一份设计交接文档,作为 AI 编码代理的直接实现指令。与描述设计「应该感觉如何」的传统交接说明不同,本文档提供机器可解析、零歧义的规格说明。每个值都是明确的,每个状态都有定义,每个边界情况都有规则。文档的结构使得 AI 代理可以从头到尾阅读并直接实现,无需提出澄清性问题——同时人类开发者也能自然地阅读它。
核心理念: 如果 AI 读完本文档后还需要猜测任何内容,那么本文档就是失败的。
何时使用: 设计定稿之后,实现开始之前。它取代 Figma 交接、设计规格 PDF,以及「就照着稿子做」这类对话。
读者是谁:
- 主要:AI 编码代理(Claude Code、Cursor、Copilot 等)
- 次要:审查或调试 AI 输出的人类开发者
- 第三:你(设计师),在检查实现是否符合意图时
与 CLAUDE.md 的关系: 本文档假定项目根目录中已存在 CLAUDE.md 设计系统文件。交接说明引用 CLAUDE.md 中的 token,但不重新定义它们。如果不存在 CLAUDE.md,请先运行设计系统提取提示词。
提示词
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:** ${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:
断点 { 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
过渡 { 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 }
规则:每个交互元素都使用 default,除非
本文档另有规定。
规则:过渡适用于:background-color、color、border-color、
opacity、transform、box-shadow。绝不适用于:width、height、padding、
margin(这些会导致布局重新计算)。
#### 2.3 Z-Index Scale
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 适用于: 每个交互元素(按钮、链接、输入框、下拉选择框、复选框) 可见性: 仅在键盘导航时(使用 focus-visible,而非 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_name} ├── 区块:Hero │ ├── 组件:标题(h1) │ ├── 组件:副标题(p) │ ├── 组件:CTA 按钮(primary,lg) │ └── 组件:HeroImage ├── 区块:Features │ ├── 组件:区块标题(h2) │ └── 组件:FeatureCard × 3(grid) ├── 区块:Testimonials │ └── 组件:TestimonialSlider └── 区块:CTA ├── 组件:标题(h2) └── 组件:CTA 按钮(primary,lg)
##### Section-by-Section Specs
For each section:
**${section_name}**
LAYOUT { 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 }
CONTENT { 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] } }
GRID(如适用) { columns: grid-cols-3(平板:grid-cols-2)(移动端:grid-cols-1) gap: gap-6(24px) items: ${what_component_renders_in_each_cell} alignment: items-start }
ANIMATION(如适用) { type: 滚动时淡入上移 trigger: 当区块进入视口时(threshold: 0.2) stagger: 每个子元素在前一个之后延迟 100ms duration: duration-500 easing: ease-out runs: 仅一次(向上滚动时不重新触发) }
---
### 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' // 视觉样式
size: 'sm' | 'md' | 'lg' // 尺寸
disabled?: boolean // 默认值:false
loading?: boolean // 默认值:false
icon?: React.ReactNode // 可选的前置图标
children: React.ReactNode // 标签内容
onClick?: () => void // 点击处理函数
}
Variant × Size Matrix
Define exact values for every combination:
变体:primary
尺寸:sm
高度: h-8 (32px)
内边距: px-3 (12px)
字体: text-sm font-medium (14px)
背景: bg-brand-500 (#2563EB)
文字: text-white (#FFFFFF)
边框: 无
圆角: rounded-md (6px)
阴影: 无
尺寸:md
高度: h-10 (40px)
内边距: px-4 (16px)
字体: text-sm font-medium (14px)
背景: bg-brand-500 (#2563EB)
文字: text-white (#FFFFFF)
边框: 无
圆角: rounded-lg (8px)
阴影: shadow-sm
尺寸:lg
高度: h-12 (48px)
内边距: px-6 (24px)
字体: text-base font-semibold (16px)
背景: bg-brand-500 (#2563EB)
文字: text-white (#FFFFFF)
边框: 无
圆角: rounded-lg (8px)
阴影: shadow-sm
变体:secondary
[相同结构,不同取值]
变体:ghost
[相同结构,不同取值]
State Specifications
Every state must be defined for every variant:
状态(除非被覆盖,否则适用于所有变体):
hover {
background: ${token} — 从默认状态加深一级
transform: none(悬停时不缩放/位移)
shadow: ${token_or_none}
cursor: pointer
transition: default(duration-200 ease-out)
}
active {
background: ${token} — 从默认状态加深两级
transform: scale-[0.98]
transition: duration-75
}
focus-visible {
ring: ring-2 ring-offset-2 ring-brand-500
all other: 与默认状态相同
}
disabled {
opacity: opacity-50
cursor: not-allowed
pointer-events: none
ALL hover/active/focus states: 不适用
}
loading {
content: 用 spinner 替换子元素(16px,animate-spin)
width: 保持与非加载状态相同的宽度(防止布局偏移)
pointer-events: none
opacity: opacity-80
}
Icon Behavior
图标规则 {
位置: 标签文本左侧(始终)
尺寸: 16px(sm)、16px(md)、20px(lg)
间距: gap-1.5(sm)、gap-2(md)、gap-2(lg)
颜色: 继承文本颜色(currentColor)
加载时: 图标隐藏,spinner 占据其位置
仅图标: 若无子元素,组件变为正方形(宽度 = 高度)
添加 aria-label 属性要求
}
SECTION 5: INTERACTION FLOWS
For each user flow, provide step-by-step implementation:
Flow: [Flow Name, e.g., "User Signs Up"]
触发条件: 用户点击页眉中的「注册」按钮
步骤 1: 模态框打开
动画: 淡入(不透明度 0→1,时长 200)
背景遮罩: bg-black/50,点击外部关闭模态框
焦点: 将焦点锁定在模态框内,自动聚焦第一个输入框
主体: 滚动锁定(防止背景滚动)
步骤 2: 用户填写表单
字段: ${list_exact_fields_with_validation_rules}
验证: 在失焦时(而非输入时——减少干扰)
字段:email {
类型: email
必填: true
验证: 正则表达式模式 + 「必须包含 @ 和域名」
错误: 「这看起来不像一个邮箱——检查一下是否有拼写错误」
成功: 绿色对勾图标出现(淡入,时长 150)
}
字段:password {
类型: password(带显示/隐藏切换)
必填: true
验证: 最少 8 个字符,1 个大写字母,1 个数字
错误: 显示要求清单,高亮未满足项
强度: 显示强度条(弱/中/强)
}
步骤 3: 用户提交
按钮: 显示加载状态(参见 Button 组件规范)
请求: POST /api/auth/signup
时长: 预计 1-3 秒
步骤 4a: 成功
模态框: 内容过渡为成功消息(交叉淡入淡出,时长 200)
消息: 「账户已创建!请查看你的邮箱进行验证。」
操作: 「知道了」按钮关闭模态框
重定向: 关闭后,重定向到 /dashboard
提示条: 无(模态框本身就是确认)
步骤 4b: 错误——邮箱已存在
字段: email 输入框显示错误状态
消息: 「此邮箱已注册账户——想改为登录吗?」
操作: 「登录」链接将模态框切换为登录表单
按钮: 返回默认状态(非加载中)
步骤 4c: 错误——网络故障
显示: 模态框顶部的错误横幅(不是提示条)
消息: 「我们这边出了点问题。要重试吗?」
操作: 「重试」按钮重新提交
按钮: 返回默认状态
步骤 4d: 错误——触发速率限制
显示: 错误横幅
消息: 「尝试次数过多。请等待 60 秒后重试。」
按钮: 禁用 60 秒,并显示倒计时
SECTION 6: RESPONSIVE BEHAVIOR RULES
Don't describe what changes — specify the exact rules:
响应式规则:
规则 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:Hero 区块
≥1024px: 双列(文字在左,图片在右)—— 55/45 分割
<1024px: 单列(文字在上,图片在下)
图片 max-height: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
规则 5:间距缩放
≥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 属性
hero: sizes="(max-width: 1024px) 100vw, 50vw"
网格项: 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:
边界情况:
文本溢出 {
标题: 最多 2 行,之后用 text-ellipsis 截断(添加 title 属性以显示完整文本)
正文文本: 允许自然换行,不截断
按钮标签: 仅单行,最多 30 个字符,不截断(设计约束)
导航项: 单行,在移动端超过 16 个字符时截断
表格单元格: 截断,悬停时显示 tooltip
}
空状态 {
0 个项目的列表/网格:显示 ${emptystate} 组件
- 插图:${describe_or_reference_asset}
- 标题:"${exact_text}"
- 正文:"${exact_text}"
- CTA:"${exact_text}" → ${action}
用户头像缺失:在彩色背景上显示首字母
- 背景:根据用户名哈希生成(确定性)
- 首字母:名字 + 姓氏的首字母,大写
- 字体:text-sm font-medium text-white
图片加载失败:显示带图片图标的灰色占位符
- 背景:bg-gray-100
- 图标:来自 lucide-react 的 ImageOff,text-gray-400,24px
}
加载状态 {
页面加载: 整页骨架屏(不是 spinner)
组件加载: 与最终尺寸匹配的组件级骨架屏
按钮操作: 按钮内联 spinner(参见 Button 规范)
无限列表: 获取下一页时在底部显示骨架行 × 3
骨架屏样式:bg-gray-200 rounded animate-pulse
骨架屏规则: 骨架屏形状必须匹配最终内容形状
(文本用矩形,头像用圆形,卡片用 rounded-lg)
}
错误状态 {
API 错误(500): 显示带重试按钮的内联错误横幅
网络错误: 在顶部显示 "You seem offline" 横幅(重新连接时自动消失)
404 内容: 显示自定义 404 组件(不是 Next.js 默认组件)
权限被拒绝: 重定向到 /login 并带 return URL 参数
表单验证: 按字段内联显示(参见流程规范),绝不使用 alert()
}
数据极端情况 {
用户名 1 个字符: 正常显示
用户名 50 个字符: 在导航中截断为 20 个字符,在个人资料中显示完整
价格 $0.00: 显示 "Free"
价格 $999,999.99: 确保布局不会破坏(用格式化数字测试)
包含 1 个项目的列表: 与多个项目相同的布局(无特殊情况)
包含 500 个项目的列表: 每 20 个分页,显示 "Load more" 按钮
日期为今天: 显示 "Today" 而不是日期
日期为今年: 显示 "Mar 13" 而不是 "Mar 13, 2026"
日期为其他年份: 显示 "Mar 13, 2025"
}
SECTION 8: IMPLEMENTATION VERIFICATION CHECKLIST
After implementation, the AI agent (or human developer) should verify:
验证:
□ 每个组件都精确匹配变体 × 尺寸矩阵
□ 每个状态(hover、active、focus、disabled、loading)都正常工作
□ 所有页面上的 Tab 顺序都遵循视觉顺序
□ 焦点可见环在键盘导航时出现,在鼠标点击时不出现
□ 所有过渡都使用指定的时长和缓动(而非浏览器默认值)
□ 页面加载期间无布局偏移(检查 CLS)
□ 骨架屏状态与最终内容尺寸一致
□ 第 7 节中的所有边界情况都已处理
□ 移动端断点上的触摸目标 ≥ 44×44px
□ 任何断点下都没有水平滚动
□ 所有图片都使用 next/image 并带有正确的 sizes 属性
□ Z-index 值仅使用已定义的层级
□ 错误状态正确显示(用网络限速测试)
□ 空状态正确显示(用空数据测试)
□ 文本截断在边界长度下正常工作
□ 深色模式令牌(如适用)已全部映射
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:
面向 AI 实现代理的说明:
1. 在编写任何代码之前,完整阅读本文档。
2. 按照第 1 节(实现映射)中指定的顺序进行实现。
3. 参考 CLAUDE.md 获取 token 值。如果此处引用的某个 token
不在 CLAUDE.md 中,请标记它并使用所提供的回退值。
4. 本文档中的每一个值都是有意为之的。不要用“差不多”的值
来替代。`gap-6` 就是 `gap-6`,不是 `gap-5`。
5. 每一个状态都必须实现。如果某个组件未指定某个状态,
那就是规范中的缺口——请标记它,不要猜测。
6. 在实现每个组件之后,运行其状态矩阵
并验证所有状态都能正常工作,然后再继续下一个组件。
7. 遇到歧义时,优先采用更明确的解释。
如果仍然有歧义,添加一条 TODO 注释:"// HANDOFF-AMBIGUITY: [description]"
---
## 自定义说明
**如果你不使用 Tailwind:** 将提示词中所有 Tailwind 类名引用替换为你系统的对应写法。结构保持不变——只有值的格式会变。告诉 Claude:“以 CSS 自定义属性为主,px 值作为注释。”
**如果你要交给某个特定的 AI 工具:** 添加针对该工具的说明。例如,对于 Cursor:“将实现生成为对现有文件的分步编辑,而不是整文件重写。”对于 Claude Code:“将每个组件创建为完整文件,测试它,然后再进行下一个。”
**如果尚不存在 CLAUDE.md:** 让提示词在交接文档顶部生成一个最小化的 token 部分,只涵盖本次交接所需的 token。它不会是完整的设计系统,但能防止硬编码值。
**对于多页面项目:** 每页运行一次提示词,但只在第一次运行时包含第 1 节(实现地图)和第 2 节(全局规格)。后续页面引用相同的全局规格。
English original
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:** ${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.
