codify-design-to-code
Codify Dev - 设计转代码
核心原则
截图看布局,骨架定边界,JSON 取样式。三者协同,缺一不可。
结构先行,样式后填。 你看不到渲染结果,所有布局正确性只能靠推理。先用截图和骨架确定正确的 DOM 结构,再用 JSON 填充精确样式值。结构错了,样式再精确也白费。
| 数据源 | 告诉你什么 | 不告诉你什么 |
|---|---|---|
| 截图 | 视觉效果、颜色感知、间距比例、整体氛围 | 精确数值、层级结构、节点 ID |
| 骨架 | 组件边界、布局方向、重复模式、节点层级 | 具体样式、颜色、字体大小 |
| JSON | 精确 CSS 值、节点属性、资源 ID | 视觉上下文、设计意图 |
协同:截图 + 骨架 → 理解意图、确定 DOM 结构;骨架 + JSON → 精确实现;截图 + JSON → 验证还原。
工作流程
准备:设置工作目录
每次任务开始时先执行,用节点 ID 隔离临时文件,避免并发冲突:
SKILL_DIR="/path/to/skill" # 替换为 skill 目录实际路径
NODE_ID="节点ID" # 替换为实际节点 ID
FILE_KEY="文件Key" # 替换为实际文件 Key
WORK_DIR="$TMPDIR/codify-${NODE_ID//:/–}" # 每个节点独立目录
mkdir -p "$WORK_DIR"
SKILL_DIR通常为当前 skill 文件所在目录,如/Users/xxx/project/skill。
Step 0. 获取截图,建立视觉基准
截图是第一步,不可跳过。 在读骨架和 JSON 之前先看截图,用于:
- 识别所有视觉元素(装饰图形、渐变、光晕等)
- 建立视觉基准,后续所有 JSON 解读都以截图为参照
node "$SKILL_DIR/scripts/download-screenshot.cjs" \
--nodeId "$NODE_ID" \
--fileKey "$FILE_KEY" \
--output "$WORK_DIR/screenshot.png"
截图下载后立即读取图片,记录:
- 页面整体布局和层次
- 所有视觉装饰元素(光晕、阴影、渐变、图标)
- 文字样式的视觉重量和颜色
- 哪些元素突出了其父容器的边界(如图标超出卡片顶部、阴影溢出容器等)
Step 1. 获取骨架,理解结构
curl -s -X POST http://127.0.0.1:13580/get_design \
-H "Content-Type: application/json" \
-d "{\"node_id\": \"$NODE_ID\", \"file_key\": \"$FILE_KEY\", \"mode\": \"skeleton\"}"
对照截图阅读骨架,重点关注:
- 整体层级和布局方向
- 与截图对应的视觉元素是否都在骨架中有对应节点
- 组件边界和重复结构
骨架标记见 design-schema.md,拆分规则见 codegen-rules.md。
判断复杂度,选择路径
| 条件 | 路径 | 说明 |
|---|---|---|
| 骨架层级 ≤ 3 层,且带 ID 的子节点 ≤ 3 个 | 快速路径 | 直接获取完整 JSON 一次性生成 |
| 骨架层级 > 3 层,或带 ID 的子节点 > 3 个 | 分块路径 | 按区块逐块实现再组合 |
判断标准不是绝对的:如果骨架虽然层级多但节点重复度高(大量
×N),仍可走快速路径。关键是你能否在一次生成中准确记住所有节点的精确样式值。如果不确定,选分块路径。
Step 2A. 快速路径:一次性获取 JSON + 生成
适用于简单 UI(少量节点、浅层级)。
获取完整 JSON 并保存:
curl -s -X POST http://127.0.0.1:13580/get_design \
-H "Content-Type: application/json" \
-d "{\"node_id\": \"$NODE_ID\", \"file_key\": \"$FILE_KEY\"}" \
> "$WORK_DIR/design.json"
# 读取(小型节点直接格式化输出)
cat "$WORK_DIR/design.json" | python3 -m json.tool
识别并下载所有资源:
JSON 返回的数据中有两类资源需要下载,它们的发现机制不同:
assets数组中列出的矢量资源:JSON 末尾的assets数组明确列出了所有 ICON / VECTOR 类型节点,可直接按nodeId批量下载为 SVG- 主结构中的位图资源:
RECTANGLE/IMAGE类型且带有object-fit属性的节点是位图填充节点,不会出现在assets数组中,需要从主结构中识别后单独下载为 PNG
建立节点→用途的映射:下载前,必须将每个资源节点的 nodeId 映射回主 JSON 结构树中,通过该节点在结构树中的**位置(父子层级、相邻节点)**来确定它的 UI 角色(如关闭按钮、装饰图标等)。不要凭节点的 type 或 name 猜测用途。
node "$SKILL_DIR/scripts/download-assets.cjs" --fileKey "$FILE_KEY" --nodes '[
{"nodeId":"<nodeId>","outputPath":"$WORK_DIR/icon-name.svg","format":"svg"}
]'
⚠️ 关键规则:ICON / IMAGE 节点必须下载实际资源文件,代码中直接引用文件路径。不要跳过下载自己画 SVG,也不要用占位符,也不要用 Unicode 字符近似替代。
然后跳到 Step 4. 生成代码。
Step 2B. 分块路径:制定分块计划
适用于复杂 UI(深层级、多节点)。
根据骨架结构,将设计拆分为 3-6 个独立区块。每个区块对应骨架中一个带 ID 的子树。
分块原则:
- 每块对应截图中一个视觉区域
- 每块的 JSON 数据量在一次上下文中可完整消化
- 块之间通过容器布局关系组合,互不依赖内部细节
记录分块计划(示例):
Block A: 25:05110 → 卡片容器 + 装饰光晕 + 关闭按钮
Block B: 25:05123 → 盾牌图标 + 标题
Block C: 25:05133 → 步骤图标列(左侧)
Block D: 25:05134 → 步骤内容列(右侧)
Step 3. 分块路径:逐块执行
对每个 Block 重复以下三步,完成一个块后再开始下一个:
3.1 获取该块的 JSON
curl -s -X POST http://127.0.0.1:13580/get_design \
-H "Content-Type: application/json" \
-d "{\"node_id\": \"子节点ID\", \"file_key\": \"$FILE_KEY\"}" \
> "$WORK_DIR/block-A.json"
cat "$WORK_DIR/block-A.json" | python3 -m json.tool
读取 JSON 时必须做到:
-
子节点
customStyle全量读取:不只读顶层节点,对每一个子节点都读取customStyle,尤其关注:margin-top/margin-bottom/margin-right/margin-left:决定元素间距,是布局精确度的关键padding:决定容器内边距align-items/justify-content:决定对齐方式
-
布局模式判断:遇到并排/堆叠结构,明确区分:
- 左列是弹性伸缩(
flex:1)还是固定尺寸堆叠(固定height+margin-bottom)? - 判断依据:子节点是否有固定
width/height+margin-bottom,如有则用固定尺寸,不用flex:1估算
- 左列是弹性伸缩(
-
JSON 必须读完:如数据较大需分段读取,须确认读到最后一段才进入下一步
3.2 下载该块涉及的资源
资源的发现和识别规则:
- 矢量资源:从 JSON 末尾的
assets数组中,筛选出nodeId属于当前块子树的条目,批量下载为 SVG - 位图资源:在当前块的 JSON 结构中,查找带
object-fit属性的RECTANGLE/IMAGE节点,单独下载为 PNG
命名依据结构位置而非猜测:资源文件的命名应基于该节点在结构树中的 UI 角色(通过父子层级和相邻节点判断),而不是基于节点的 type 或 name 字段。
node "$SKILL_DIR/scripts/download-assets.cjs" --fileKey "$FILE_KEY" --nodes '[
{"nodeId":"<nodeId>","outputPath":"$WORK_DIR/icon-xxx.svg","format":"svg"}
]'
⚠️ 关键规则:ICON / IMAGE 节点必须下载实际资源文件,代码中直接引用文件路径。不要跳过下载自己画 SVG,也不要用占位符,也不要用 Unicode 字符近似替代。
3.3 记录该块的关键样式
读完 JSON 和下载资源后,在继续下一个块之前,用简要注释记录该块的核心信息:
- 容器布局方式(flex 方向、padding、gap)
- 关键节点的
customStyle摘要(字号、颜色、间距等) - 该块涉及的资源文件列表
目的是确保每块的 JSON 数据被充分消化,而不是在最终生成时回头翻找。
所有块处理完成后,进入 Step 4 生成代码。
Step 4. 生成代码
阅读 codegen-rules.md。
代码生成分两步:先确定结构,再填充样式。
4.1 先写 DOM 结构骨架
基于截图和骨架,先输出纯 DOM 结构(含语义化的 class 名和注释,但不含具体样式值)。这一步只关注:
- 容器嵌套关系是否合理
- 需要绝对定位的元素,其定位参考(
position: relative的祖先)是否正确 - 需要裁切(
overflow: hidden)的容器,其子元素是否都在边界内——如有元素需要突出容器边界,该元素必须放在裁切容器外部 - 重复结构是否使用循环
- 设计稿的层级与 DOM 层级的映射是否合理(设计稿层级不一定要 1:1 映射到 DOM,合理调整以符合 CSS 布局需要)
4.2 再填充精确样式
结构确认后,从 JSON 的 customStyle 中提取所有精确值填充到代码中:
- 所有尺寸、颜色、间距直接来自 JSON,不估算
- ICON / IMAGE 节点直接引用已下载的资源文件路径,不手绘近似 SVG
- 以截图为参照校验每个区块的视觉效果
- 输出格式和资源引用方式遵循项目规范(见 codegen-rules.md)
Step 5. 视觉验证(可选但强烈推荐)
如果生成的是可直接在浏览器运行的代码(HTML 文件、本地可启动的应用等),使用 Playwright 截图与设计稿截图进行对比验证。最多进行 2 轮修正。
5.1 截图渲染结果
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page(viewport={"width": 375, "height": 812})
page.goto('file:///path/to/output.html')
page.wait_for_load_state('networkidle')
page.screenshot(path='$WORK_DIR/render-result.png', full_page=True)
browser.close()
需要 Playwright 环境。如不可用,跳过此步进入完成前回顾。
5.2 逐区域对比
不要泛泛地看"像不像",要逐区域精确对比。 将页面分为 3-5 个视觉区域(与分块计划对应),每个区域单独检查:
- 位置:元素在区域内的水平/垂直位置是否与设计稿一致?居中、偏左、还是固定偏移?
- 尺寸:元素的宽高比例是否正确?有没有被拉伸或压缩?
- 层叠:元素之间的前后遮挡关系是否正确?有没有被裁切、被遮挡?
- 间距:元素之间的间距是否合理?太紧或太松?
5.3 聚焦修正
发现差异后,每次只修一个问题,修完立刻重新截图验证。不要一次改多处——同时改多个地方,无法判断哪个改动造成了新问题。
修正优先级:
- 结构性问题(元素缺失、层级错误、被裁切) → 修 DOM 结构
- 位置问题(偏移、对齐方向错误) → 修定位和布局属性
- 细节问题(间距、字号、颜色微调) → 修具体样式值
完成前回顾
生成代码后(如已做视觉验证则在验证通过后),对照截图逐项检查:
- 截图中的所有视觉元素是否都已实现(包括装饰光晕、阴影等)
- 骨架中的关键节点是否都有对应代码
- JSON 是否已完整读完(包括最后的
assets字段) - 所有资源是否已下载,代码中引用的是已下载的文件路径,无手绘近似、无占位符
- 左右并排结构的对齐是否基于 JSON 的固定尺寸,而非估算
- 动态数据是否通过接口/Props 传入(非硬编码)
- 重复结构是否使用数组循环
- 资源引用方式是否与项目已有代码一致
常见错误
| 错误 | 原因 | 正确做法 |
|---|---|---|
| 资源节点的用途判断错误(如把关闭按钮图标当成装饰图标) | 凭节点的 type 或 name 字段猜测用途,未回溯结构树 |
将资源 nodeId 映射回主 JSON 结构,通过结构位置(父子层级、相邻节点、坐标)确定 UI 角色 |
| 位图资源遗漏未下载 | 只从 assets 数组中查找资源 |
assets 数组仅包含矢量资源;带 object-fit 属性的 RECTANGLE / IMAGE 节点是位图资源,需从主结构中额外识别并下载 |
| 用 Unicode 字符或 HTML 实体代替图标资源 | 认为简单图标(如 ✕ ⓘ ▶)可以用文字近似 | ICON 节点必须使用下载的实际资源文件,文字字符与设计资源在视觉上不等价(大小、粗细、对齐方式均不同) |
| 结构和样式一起写,结构定错后推倒重来 | 边想结构边写样式,注意力分散导致结构性错误 | 先写纯 DOM 结构确认合理,再填充样式值 |
突出元素被 overflow: hidden 裁切 |
元素放在了圆角裁切容器内部,用负偏移试图突出 | 突出元素放在裁切容器外部的 wrapper 上绝对定位 |
| 资源文件内容被内联为 base64 | 读取了已下载的文件内容再转为 data URI | 直接引用文件路径(<img src="path/to/icon.svg">),不读文件内容 |
| 对同一节点多次 curl 分段读取 JSON | 直接 pipe 给 head/tail,每次重新请求 | 先 > design.json 保存,后续 sed -n 分段读文件 |
左右对齐结构用 flex:1 拉伸连接线 |
没有读子节点的 margin-bottom + 固定 height |
读 JSON 中每个子节点的 customStyle,用固定尺寸还原 |
| 跳过截图,直接看骨架和 JSON | 截图当作"可选"步骤 | 截图必须是第一步 |
| 装饰图形(光晕/渐变椭圆)缺失 | 没有下载无 customStyle 的图形节点 |
下载 assets 里的所有资源;如骨架有图形节点但不在 assets 里,单独下载确认 |
| SVG 图标手绘近似路径 | 没下载资源或下载后不用,凭印象自己画 | 下载资源后在代码中直接引用文件路径(如 <img src="icon.svg">) |
| 大 JSON 读到一半就开始写代码 | JSON 分段读取时跳过了后半段 | 必须确认 JSON 完整读取后(含 assets)才进入代码生成 |
| 复杂 UI 一口气生成导致细节丢失 | 上下文窗口无法记住所有节点样式 | 使用分块路径,逐块消化、逐块生成 |
参考文档
| 文档 | 何时读取 |
|---|---|
| codegen-rules.md | 生成代码前必读 |
| design-schema.md | 理解 JSON 结构时 |
| api.md | 调用 API 或下载资源时 |
错误处理
见 api.md 错误格式与错误码。