规范示意图
本技能说明如何绘制。lw-spec-write 说明规范的存放位置以及页面如何渲染。
产品事实
适配器文件夹来自配置。首先读取它:
ah config get harness.adapterDir
然后读取 <adapterDir>/spec-mockup/。项目拥有它。它命名了:
| 事实 | 示例 |
|---|---|
| 每个应用的令牌文件(按顺序) | apps/console/src/styles/tokens.css |
| 亮色和暗色值的选择器 | :root, .dark |
| lucide 图标文件夹 | node_modules/lucide-react/dist/esm/icons |
| 每个带有侧边栏的应用的导航,以及它的来源 | 控制台的路由表 |
| 真实文案的来源 | 应用的 i18n 目录 |
当适配器缺失时,在绘制前向用户索要令牌文件。绝不要凭空发明一种 颜色。
格式
生成的 SVG,使用单一库绘制:此文件旁的 boards.py。每个规范都有
一个脚本 docs/specs/assets/<date>-<topic>-boards.py。它导入该库并写入
docs/specs/assets/<date>-<topic>/。绝不要手动编辑生成的 SVG:修改脚本并重新
运行它。当库缺少某个组件时,将其添加到项目脚本旁边的自有辅助模块中,
以便下一个规范也能使用它。
example.py 是一个示例看板:包含桌面端和手机端的页面,带有图钉和 图例。运行它以查看形状:
python3 .claude/skills/lw-spec-mockup/example.py <scratchpad>/mock --render
一个规范脚本像这样开始:
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[3]
sys.path.insert(0, str(ROOT / ".claude/skills/lw-spec-mockup"))
from boards import GUTTER, Board, render, tokens
t = tokens("apps/console/src/styles/tokens.css", "light")
b = Board(1440 + 2 * GUTTER, 1200, icons="node_modules/lucide-react/dist/esm/icons")
b.title("Dashboard: the empty state")
f = b.sidebar_app(
GUTTER,
160,
t["bg"],
t["sidebar"],
t["ink"],
t["muted"],
t["active"],
["Dashboard"],
"Dashboard",
"Console",
)
b.pin(f.x + f.left + 24, f.top + 30, 1)
b.legend(
GUTTER, 1100, [(1, "The empty state", "No widget until the product names one.", "R1")], 1440
)
b.save("docs/specs/assets/<date>-<topic>/desktop-empty.svg")
| 调用 | 绘制内容 |
|---|---|
tokens(files, theme, base=, dark=, overlay=) | 令牌文件的已解析 --* 值。t["accent"]。缺失的令牌会引发错误。overlay 是提议的重新样式 |
phone(x, y, bg, ink, surface, url), desktop(x, y, bg, url) | 手机(web 或 app),浏览器窗口 |
sidebar_app(x, y, ...) | 带有左侧边栏的应用,例如控制台。从应用的路由表复制 nav |
screenshot(path, x, y), crop(path, ...) | 已发布屏幕的真实截图,或其区域,用于“现状”列 |
icon(name, x, y, size, color) | 来自看板 icons 文件夹的 lucide 字形 |
image(path, ...), embed_font(family, path) | 来自仓库的真实艺术作品和品牌字体 |
pin, legend, caption, column_head, row_label, title | 注释。超过两行的图例注释会引发错误 |
render(svg, png, w, h) | 下方检查所需的无头 Chrome 截图 |
保真度
- 颜色来自令牌,通过
tokens()。规范脚本中的十六进制值是错误的,除非是 令牌文件中不包含的艺术作品颜色。 - 文案是真实的。 使用应用目录中的字符串(如果存在)。新字符串要简短: 标签、值、空状态、错误或单行提示。
- 数据是现实的。 使用合理的值,并在可能出现长数据的地方使用一个长值。
画布
| 表面 | 框架 |
|---|---|
| 手机 | 390 x 844,48 px 间距 |
| 桌面 | 1440 x 900 |
| 看板 | 宽度与框架相同,高度根据行数需要 |
规范绘制的内容
- 现状,然后是目标。 “现状”是已发布屏幕的真实截图 (
today-*.png)。 “目标”是 SVG。在 Markdown 表格中并排放置它们。 - 每个适用的状态占一行: 默认、空、加载、错误、长文本、最小 和最大内容。
- 图钉和图例。 在每个发生变化的元素上放置一个带编号的图钉。在框架下,放置一个 带编号的图例:一个粗体标题,最多两行,以及它服务的规范 ID。
- 规范中的组件列表 在看板旁边:每个元素、它复用的组件、 以及每个新组件及其原因。
命名
docs/specs/assets/<YYYY-MM-DD>-<topic>-boards.py
docs/specs/assets/<YYYY-MM-DD>-<topic>/<surface>-<state>.svg
docs/specs/assets/<YYYY-MM-DD>-<topic>/today-<surface>-<state>.png
规范命名其包含在 assets/ 中的每个文件的基本名称。
在提交每个看板之前检查它
看板的缺陷在源代码中不可见,但在图片中清晰可见。渲染每个看板并使用
读取工具读取 PNG。将 PNG 写入暂存区,而不是 docs/。
- 没有文本超出其框架,没有图钉覆盖值。
- 绘制 UI 中的每个字符串都是标签、值、空状态、错误或提示。
- 没有占位艺术作品,没有凭肉眼选择的颜色。
- 规范涉及的每个状态和表面都有其框架。
- 现状和目标并排放置。
render 需要在 PATH 上有 google-chrome 或 chromium。
构建之后
构建必须匹配已批准的看板。截取构建后的屏幕并将其放在看板旁边。 差异是构建的缺陷,而不是重新绘制看板的理由。