关于 directions-lab
directions-lab 是用于在代码库中搭建设计探索页面的 skill,生成 Today 与多个方向的对照视图,并提供统一控件、注册表配置和 Storybook 条目。
主要功能
- 01搭建 Vite 设计方向页面
- 02对照 Today 与两个或三个方向
- 03通过注册表配置方向和界面
- 04生成 Storybook 提案故事
- 05运行脚手架检查与测试
适用场景
- 01为产品功能创建设计探索
- 02将备选设计与已发布组件对照
- 03向 Storybook 设计目录添加提案
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ paperclipai/ paperclip --skill directions-lab安装后在 Claude Code 中输入/directions-lab确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
agents/openai.yamlassets/PRECEDENTassets/motion/v1-mvp-motion.cssassets/templates/api-routes.ts.mjsapi-stub.ts.mjsbuild-info.ts.mjsdefine-lab.ts.mjsentry.html.mjsfixtures.ts.mjskit.ts.mjslab-state.ts.mjslab.css.mjslaunch-entries.json.mjsmain.tsx.mjsproviders.tsx.mjsregistry.ts.mjsshot.cjs.mjsassets/templates/direction/index.tsx.mjsMotionSpecimen.tsx.mjsSlotBody.tsx.mjstokens.css.mjsassets/templates/frames/AppShell.tsx.mjsBoard.tsx.mjsLabToolbar.tsx.mjsSlot.tsx.mjsSurfaceFrame.tsx.mjsSurfaceView.tsx.mjsassets/templates/stories/compare.stories.tsx.mjsassets/templates/tests/api-stub.test.ts.mjslab-state.test.ts.mjs详细介绍
方向实验室
方向实验室是本仓库进行设计探索的方式:一个页面、一个功能、Today 加上两个或三个方向、该功能出现的每个界面,以及每次都相同的控件,这样共享链接对所有人来说显示一致。artifact 方向实验室(ui/src/artifact-directions)是先例,并保持为冻结的参考;此技能会以相同的结构生成新的实验室,无需手动重画基础设施。
要创建的内容
- 页面。
ui/<slug>-directions.html加上ui/src/<slug>-directions/,这是一个没有后端的 Vite 第二入口。所有状态都保存在 URL 中(?d=&s=&theme=&chrome=&anim=,提案调色板则加上proposal=1)。注册表模块是方向 ID、数字键、标签、界面、默认视图和故事 ID 的唯一数据源;工具栏、键盘、概览板和截图脚本会在运行时读取它,而add-direction会同步更新故事中各方向的导出,因此添加一个方向只需添加一条注册表记录和一个目录。 - 工具栏。 第 1 行是方向行:先显示编号方向,再将
0.Today放在最后,以分段控件呈现;Theme 和 Animation 靠右对齐。第 2 行是界面行:Overview 加上每个界面的一个标签页。只有在实验室脚手架包含多个界面时才会写入第 2 行(单界面实验室后续添加界面时,需要手动添加第 2 行,见references/lab-anatomy.md第 8 节);只有一个界面时,键盘图例会并入第 1 行。页眉中不得放入其他内容。 - Today。 始终存在,始终为
0.Today,始终通过小型适配器和 fetch 存根,将已发布组件挂载到实验室的固定数据上。它是评判每个方向的基准,因此绝不重绘。 - 方向。 两个或三个,编号排列;每个都是自包含的套件目录,并拥有自己的作用域
tokens.css。每个方向都必须原样包含 V1 MVP 动效代码块,并附带一个证明该代码块的测试,这样悬停效果在各实验室中都保持一致。动手前请阅读references/motion-spec.md。 - 目录条目。 在
ui/storybook/stories/design-proposals/下放置一个带稳定 ID 的故事文件,并将其编入提案目录。design-proposals Storybook 正在成为设计系统的规范目录;实验室从首次提交起就应在其中可见。
硬性规则,因为仓库的检查会强制执行,评审者也会据此检查:
提交的任何内容中都不得包含代码注释;实验室中不得有 600 行或更多的文件(check 会在达到 600 行时拒绝);不得修改 package.json 脚本;不得更改 lockfile;不得在仓库中加入截图或生成的目录文件。
开始之前
从仓库根目录在自己的分支上运行(分支名为 claude/<slug>-directions,基于 origin/master)。检查 ui/node_modules/.bin/vite 是否存在;如果不存在,运行 pnpm install --frozen-lockfile。然后运行生成器自己的测试:
node --test .agents/skills/directions-lab/scripts/scaffold.test.mjs
这里失败通常说明模板或动效资源已偏离先例(ui/src/artifact-directions/directions/d5-v1-mvp/tokens.css);其中有两个用例还会读取实际功能映射和目录脚本,因此功能映射中的行或目录消息发生变化时,也会在这里显示。先修复生成器,再搭建脚手架;基于过时模板构建的实验室会在之后失败,而且失败的表现看起来像是你画错了。
阅读需求说明,再深入了解主题
从 Tonio 的说明中提取四项内容:主题(其 slug 和标题)、出现的位置(每个位置对应一个界面)、明确给出的方向数量或名称,以及任何标志或组件名称。然后,在提出任何问题前先查看代码:
rg -l "<Subject>" ui/src/components ui/src/pages
rg -n "<subject word>" maps/feature-map/*.md
第一条 grep 会给出组件文件和标志钩子(use<Feature>Enabled),并通过追踪 useQuery/queryFn 到 ui/src/api/*,找到 Today 必须响应的 /api/ 路由。第二条会给出故事引用的能力 ID。通过这番了解,才能提出针对具体界面的提问,而不是泛泛而谈。完整的提取和推导表见 references/questions-and-defaults.md。
一次询问
最多提出两个问题,并在一次 AskUserQuestion 调用中询问;简述中已回答的问题则跳过:
- 需要多少个方向? 选项为
2和3。在问题中说明,三个未命名方向会依次搭建为1.Refine(调整 token 和间距,结构不变)、2.Rework(使用新组件,布局不变)和3.Rethink(使用新布局);两个方向则搭建为1.Refine和2.Rethink,之后会重命名。简述已说明数量或命名方向时跳过。 - 需要哪些界面? 从 grep 找到的使用位置中多选,并提供“仅一个位置”选项。选择两个或更多位置时才会生成界面行。简述已命名位置时跳过。
绝不要询问主题、动画、Today、端口、slug 或落地视图;这些由技能固定。当无法提出问题时(无头运行),先写下这句话,然后继续:“由于无法提问,默认使用三个方向和一个界面();之后可通过 scaffold.mjs add-direction 更改。”
说明推导结果,然后搭建
运行生成器前,在回复中说明所有推导出的值:slug 和标题、每个界面的 id:Label:width@nav 格式及宽度来源所在行、方向数量和名称、分组、能力及其 feature-map 行(或 [] 和例外说明)、flag hook,以及 Today 需要的 /api/ 路径。此时发现 slug 或能力有误,修正成本很低;等文件生成后再发现,代价就很高。然后:
node .agents/skills/directions-lab/scripts/scaffold.mjs new \
--slug composer --title "Composer" \
--surfaces thread:Task-thread:960@tasks,panel:Right-panel:434@tasks \
--directions 3 --dry-run
读取计划(路径、端口、单元格、故事),移除 --dry-run 并运行。new 会在内存中渲染所有内容,拒绝使用已存在的路径,写入实验室、html 入口、Vite 配置、故事文件、两个 .claude/launch.json 条目和一行 .gitignore 内容,然后执行验证:Storybook 目录检查、实验室自身的 Vitest 文件检查,以及 Vite 构建。如有任何步骤失败,它会删除已写入的内容并还原两个共享文件,因此未完成的实验室不会导致整个仓库的 pnpm test 或 tsc -b 失败(ui/vitest.config.ts 没有 include 过滤器,而 ui/tsconfig.json 包含了整个 src)。在回复中引用 --json 输出。
--surfaces 对每个位置接收 id:Label:width@nav,其中 nav 是 shell 高亮显示的侧边栏项目(tasks、artifacts 或 other),而 width 是该位置在产品中使用的常量(参见 references/questions-and-defaults.md)。可用标志:已指定名称时使用 --names a,b,c;使用 --group Components|Pages|Layouts|Patterns(grep 命中 ui/src/components 时使用 Components);使用 --capabilities area/key,...(根据 maps/feature-map 验证;省略时使用 [] 并附上例外说明);使用 --company name:PREFIX(默认值为 acmehats:ACM);使用 --landing auto|all|today|<id>;使用 --ports dev,preview(生成器会选择空闲端口);使用 --keep-on-failure 检查搭建失败的实验室。
查看效果
启动生成器添加的 dev 入口,运行 preview_start {name: "<slug>-directions-dev"},并打开三个 URL:/(落地页)、/?d=today&s=<first surface> 和 /?d=<first direction id>&s=<first surface>(方向未命名时使用 d1-refine)。确认 document.documentElement.dataset.labAnim === "1",将鼠标悬停在一个动效样例上,观察正面升起、两页翻转;按下 a,再次悬停,确认只有填充发生变化。检查控制台中是否有 [<slug>-directions] unhandled 行:每一行都代表 Today 需要的一个路由。概览板和截图脚本都无法呈现运动效果(iframe 不接收指针;静态图会启用减少动态效果;--hover 只会记录一帧悬停画面,而不是过渡过程),因此只能通过这种方式验证过渡效果。
提交脚手架,然后绘制
先将未经修改的脚手架提交为 feat(ui): scaffold the <title> directions lab。这样,审查者就能将重绘作为独立差异查看,而不是让它埋在基础设施代码里。按以下顺序绘制;references/drawing-phases.md 中列出了每个阶段的完成标准:
- 框架。 将每个
data-lab-stub="frame-<surface>"区域替换为该位置周围的产品界面框架:复制产品的类名字符串,固定注册表宽度,复用展示用基础组件,不要让任何内容在内部滚动。参考框架展示了具体做法(ThreadFrame、PanelFrame、GalleryFrame、AppShell)。 - 固定数据和 Today。 在
kit.ts中重新定义各位置的数据类型,使其符合每个位置接收的 props;填充fixtures.ts;通过adapters.ts,在directions/today/<Pascal>Body.tsx中挂载随产品发布的组件(使用位置 ID 的 PascalCase,因此thread对应ThreadBody.tsx);并在api-routes.ts的registerFeatureRoutes()中,仅注册它实际获取数据所需的路由。当 Today 使用相同数据后与产品一致,且测试通过真实组件运行时,此阶段即完成。 - 方向稿。 每次处理一个方向:将动态效果示例替换为绘图,保留钩子名称(每个处理分支都要有
data-front,data-rotate和data-spread要包含行内基础角度),将每个原始值放入该方向的tokens.css(浅色基础值、.dark覆盖值),并保持动态效果区块不变。每个阶段完成后运行scaffold.mjs check --slug <slug>。
阶段 2 必须先于阶段 3,因为第 2 阶段会改变插槽 props 的结构,而所有 kit 都遵循该类型。
截图
node ui/src/<slug>-directions/shot.cjs --port <dev> --d all --out <scratch dir>
截图应为 1440×900、DPR 2 下的静止状态,包含两种主题;将 PNG 附加到 PR,绝不要放入代码仓库。--hover 会从允许运行动效的第二个浏览器上下文中,为每个方向额外生成一组静止/悬停截图;要判断动态效果本身,仍只能在开启 Animation 切换开关的浏览器面板中查看。
交接
node .agents/skills/directions-lab/scripts/scaffold.mjs check --slug <slug> --strict --run
--strict 会拒绝任何残留的 data-lab-stub 标记;--run 会运行实验室测试、目录检查、令牌门禁、实验室的 Vite 构建以及 cd ui && pnpm typecheck,遇到首个失败即停止,并输出 ## Verification 区块,其中 Not run: 行会列出仍需手动运行的项目(pnpm build-storybook、全仓库类型检查);--json 会以数据形式返回相同结果,并将这些项目列在 notRun 下。创建 PR 时,.github/PULL_REQUEST_TEMPLATE.md 的每个部分都要填写;使用关联问题路径 B,填写三个功能请求标签、故事 ID、启动条目,以及已部署时的 Vercel 别名。在 PR 正文中以文本形式提供 DESIGN.md 目录行;不要在实验室 PR 中应用它。
如果技能本身包含在你的差异中,请强制添加:/.agents/ 被 git 忽略,而仓库中已跟踪的技能是通过 git add -f 添加的。
Storybook 和 design 目录
new 会写入 ui/storybook/stories/design-proposals/<slug>-directions.stories.tsx,
其中包含 meta id design-<slug>-directions、标题 Design proposals/<Group>/<Title> directions/Compare、字面量 parameters.paperclip 块(status: "proposed"、home: "design-proposals"、implementation: "prototype"、
boundary: "fixtures"、capabilities、exception、notes),以及 Compare、
Today、每个方向各一个故事,还有 TodayProductionPalette(装饰器会用提案调色板为
整个 iframe 设置主题;此项会退出主题设置,因此 Today 显示的是已发布版本)。页面本身
默认渲染生产调色板;?proposal=1 会为其套上提案主题,以便与入口并排比较。
catalog 脚本会在 Storybook 启动时、执行
cd ui && pnpm typecheck 时以及 CI 中验证所有内容。
方向经历的生命周期,以及每个阶段需要手动编辑的内容,见
references/lifecycle.md:proposed(new 写入的内容)、adopted(产品代码置于实验性设置
之后,并带有功能主页故事)、current(移除标记)、historical(退役并注明
replacement,移出 proposals 文件夹但保留其 id)。目前 catalog 会强制 proposals
文件夹中的所有条目保持 proposed;允许目录收录 current 条目的治理变更已整理成可直接粘贴的
差异,见 references/canonical-directory.md。只有 Tonio 同意后,才单独提交一次该变更的 PR。
后续请求
- 添加方向:
scaffold.mjs add-direction --slug <slug> --name <Name>(下一个数字、registry 条目、包含 motion 块和样例的 kit 目录、故事的D<N>导出,然后执行check,失败时回滚)。 工具栏图例会在运行时跟随 registry。生成器拒绝添加第四个方向,除非使用--force-count;该参数还会在 registry 中记录allowMore;故事描述中的“1–N”句子是唯一 需要手动更新的内容。phase 2 在kit.ts中重新定义 slot props 的类型后,add-direction会拒绝执行并打印手动操作步骤,因为生成的 kit 将无法适配新的 props。 - 列出实验室:
scaffold.mjs list。 - 重命名方向、添加界面,或让方向进入生命周期的下一阶段:按照
references/lab-anatomy.md第 5 和第 8 节以及references/lifecycle.md手动操作。 - 发布:使用
<SLUG>_DIRECTIONS_OUT_DIR=<dir>/paperclip-<slug>-directions构建, 从输出中移除sw.js,然后在其父目录执行vercel deploy <that dir> --prod --yes; basename 会作为项目名称,alias 则是公开 URL。 详情见references/today-fixtures-and-build.md第 11 节。
不要
- 不要同时运行两套完整的
uiVitest 测试套件;只运行实验室自身的文件。 - 如果开发服务器中的单元格超过八个,不要从
d=all&s=board启动;要显示完整看板,请使用静态启动入口(<slug>-directions)。 - 不要照搬 artifact lab 的
html:not(.dark)token 写法;新实验室应在基础块中放置浅色值,并在.dark [data-direction=…]下放置深色值。 - 不要编辑实验室中的 motion 块。是否更改 rise 或 fan 由 Tonio 决定。
- 不要在将纳入 PR 的内容中添加注释、
package.json脚本、锁文件变更、PAP id 或 localhost URL。
维护 skill
生成器模板源自 assets/PRECEDENT 中记录的提交所采用的先例。
scripts/scaffold.test.mjs 会锁定生成结构,并断言替换后 motion 资源仍与先例中的块一致;先例变更时,
重新推导模板并更新锁定版本。references/generator.md 说明了模板约定和上下文对象。
参考资料
| 文件 | 阅读时机 |
|---|---|
references/questions-and-defaults.md | 提问前;推导表、作为标志行的评估提示词 |
references/lab-anatomy.md | 绘制框架或更改工具栏、状态或画板时 |
references/today-fixtures-and-build.md | 挂载 Today、获取模拟数据、构建、捕获或部署时 |
references/motion-spec.md | 涉及任何悬停动效时;各方向的检查清单 |
references/drawing-phases.md | 搭建脚手架后,逐阶段阅读 |
references/design-proposals-storybook.md | 故事文件、目录门禁、主题 |
references/lifecycle.md | 采用、发布或弃用某个方向时 |
references/canonical-directory.md | 仅在 Tonio 批准治理 PR 时 |
references/repo-gates.md | PR 前 |
references/generator.md | 更改生成器时 |