mcpField
P
penpot-build-from-code

penpot-build-from-code

github.com/penpot设计与 UI108127 次安装3 周前更新
代码仓库

关于 penpot-build-from-code

penpot-build-from-code 是将 JSX、HTML、Vue/Svelte 模板及样式代码转为可编辑 Penpot 画面的设计技能,面向需要让界面代码遵循现有设计系统的设计与开发人员。它先盘点令牌和组件,再逐段构建并验证画面。

主要功能

  1. 01盘点设计令牌与组件
  2. 02按区块逐步构建画面
  3. 03将样式绑定到语义令牌
  4. 04优先复用组件实例
  5. 05导出画面并检查结构
  6. 06验证令牌覆盖与遗留值

适用场景

  1. 01把 React 页面代码重建为 Penpot 画面
  2. 02将 HTML 或 Vue 模板映射到现有设计系统
  3. 03检查新画面中的未绑定样式值

MCP 相关

该技能通过 Penpot MCP 工具读取令牌、组件和画面结构,并使用工具创建及修改画面。它还通过导出画面进行视觉检查。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/penpot/penpot-ai-kit --skill penpot-build-from-code

安装后在 Claude Code 中输入/penpot-build-from-code确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
01-discovery.md
02-component-assembly.md
03-token-binding.md
04-incremental-transform.md
05-anti-rationalization.md
06-error-recovery.md
scripts/
buildSection.js
createScreenWrapper.js
inspectDesignSystem.js
validateScreen.js

详细介绍

从代码构建 — 将应用代码转换为系统内 Penpot 屏幕

1. 标题 + 工作原理

此技能可将现有应用程序产物(JSX/TSX、HTML、Vue/Svelte 模板、CSS/Tailwind 或 styled-components 树)重建为可编辑、绑定到系统的 Penpot 屏幕。所有修改都通过 execute_code 完成;使用 export_shape 进行视觉验证;使用 penpotUtils.shapeStructure 读取结构(完整工具接口:shared/penpot-mcp-tool-reference.md)。核心做法是先探索(阶段 0 会枚举必须映射到的现有令牌和组件),然后逐步、逐节转换代码,将每个 CSS/样式值映射到语义令牌,将每个重复的 UI 部分映射到现有库组件——绝不硬编码十六进制颜色或网格外间距,也绝不把组件重新实现为原始方框。

2. 最重要的一条规则

绝不一次性生成整个屏幕,也绝不硬编码令牌已能表达的值。 每次调用只构建屏幕中的一个部分(每次调用进行一个逻辑上的 execute_code 步骤),并且在编写任何填充、间距、圆角或字体之前,先根据已发现的令牌集进行匹配。从代码得出的 #0066FF 不是填充色,而是设计系统中的一次查找。如果没有匹配的令牌,你就提出一个并停止;不能自行臆造。一次调用中转换整个页面,或将原始计算 CSS 粘贴到图形上,正是此技能要避免的失败模式。

3. Penpot MCP 工具参考

完整接口:shared/penpot-mcp-tool-reference.md。此技能主要使用以下调用:

  • 探索(只读): penpotUtils.tokenOverview()、penpot.library.local(组件、令牌)、penpotUtils.shapeStructure(shape, depth)、penpotUtils.findShape/findShapes。
  • 屏幕框架: penpot.createBoard()、board.addFlexLayout()、penpotUtils.addFlexLayout(container, dir)。
  • 构建部分: penpot.createRectangle/createText/createEllipse/createPath、component.instance()、container.appendChild(child)、child.layoutChild。
  • 令牌绑定: shape.applyToken(token, properties[])、token.resolvedValue、penpotUtils.findTokenByName。
  • 验证: export_shape(单独的工具调用)和一次 shapeStructure 读取。

4. 插件 API 要点

这些容易踩坑的地方,用一句话概括——完整说明见 shared/plugin-api-gotchas.md:

  • #1 样式数组不可变 — 赋值一个全新的 fills/strokes 数组;绝不要修改 fills[0]。
  • #2 应用令牌是异步的(约 100 ms) — 在一次 execute_code 调用中应用,并在后续调用中验证 resolvedValue。
  • #3 resize() 会强制将文本的 growType 设为 'fixed' — 调整需要流式排布的文本大小后,将 growType 设为 'auto-width'/'auto-height'。
  • #4 Flex/grid 会覆盖子元素的 x/y — 通过添加顺序和间距/内边距/对齐/分布来定位子元素;仅在需要退出布局时设置 child.layoutChild.absolute = true。
  • #5 width/height 和 parentX/parentY 为只读 — 使用 shape.resize(w, h) 和 penpotUtils.setParentXY(shape, x, y)。
  • #6 修改实例内部结构前先分离实例 — 先调用 detach(),并说明这一操作。
  • #7 必须添加,否则不会显示在画布上 — 使用 container.appendChild(child)(或 penpot.currentPage.root)。
  • #8 内边距令牌 — 内边距令牌在 2.17 及更高版本中生效;旧版实例中,createScreenWrapper.js 会回退为镜像数字,并记录账本例外。
  • #9 switchVariant(pos, value) — pos 是 variants.properties 中的索引(参见 storage.run.ds.componentsByRole[role].axes),绝不是轴名称。
  • #13b 精确匹配字体 — penpot.fonts.all.find(f => f.name === "…");findByName 会进行子字符串搜索。
  • #15 在添加后设置 layoutChild — 仅当子元素已位于布局画板中时,才设置 layoutChild.*;openPage 是异步的。
  • #16 在填充尺寸调整后处理 flipX — 每个使用填充尺寸的部分完成后都运行 clearFlip 扫描(shared/visual-effects.md)。
  • #17 布局几何信息 — 读取几何信息前先执行 await board.waitForLayoutUpdate()(替代 sleep-100ms 的惯用写法)。
  • 使用前,通过 penpot_api_info(type, member) 核实任何不熟悉的签名。

5. 令牌感知型需求简报约定

在进行任何修改前,先按此约定重述请求。以资深设计工程师的身份行事,将设计系统视为唯一事实来源;只要存在令牌,就绝不硬编码值。

  • 背景 — 这段代码来自哪个产品/界面,由谁使用,对应哪个页面/视图(例如“B2B 管理控制台的桌面端设置页面”)。
  • 目标 — 单一且具体:“将 <SettingsPage> 组件重建为可编辑的 Penpot 画板,并绑定现有的 semantic 令牌集,复用 Button、InputField 和 Card 组件。”
  • 输入 — 实际代码(组件文件、CSS/Tailwind 配置、设计令牌导出文件,如有)、目标 Penpot 页面、已发现的令牌集、已发现的组件库。
  • 约束 — 禁止操作(不使用原始十六进制值、不使用偏离 4px 网格的间距、不重新发明组件、未经批准不得调用 detach());不可违反的规则(使用语义令牌而非原始令牌;优先使用现有组件而非新建图形);视口宽度。
  • 验收标准 — 量化指标:≥95% 的颜色/间距/圆角/字体值绑定到令牌(由 validateScreen.js 验证);标记出的孤立原始值为零;所有具有匹配库组件的重复 UI 部件都必须是实例,而非图形;所有间距均符合 4px 网格;图层名称具有语义(不能使用 Rectangle 12)。

6. 强制工作流

视觉自查(强制): 在每个展示视觉成果的 ✋ 检查点之前, 运行 shared/visual-self-review.md 中的导出 → 检查 → 修复循环——导出刚完成的单元, 根据检查清单自行检查图像,修复可见缺陷(最多迭代 2 次),并展示同一份导出结果,同时指出任何仍然存在的缺陷。

阶段 0 — 发现(只读)

**目标:**梳理现有 Penpot 设计系统,为代码中的值找到对应位置。不做任何修改。

  1. 调用一次 high_level_overview。
  2. execute_code:运行 scripts/inspectDesignSystem.js → 列出令牌集、每个令牌(name、type、resolvedValue)以及每个库组件(name、id、变体轴)。缓存到 storage.run.ds。
  3. execute_code:运行 penpotUtils.tokenOverview(),确认当前启用的主题/令牌集。
  4. 将输入代码解析为区段大纲(页眉、导航、主视觉、表单、卡片网格、页脚……)和样式清单(代码使用的每个不同颜色/间距/圆角/字体值)。 **退出标准:**你已准备好:(a) 按解析值索引的令牌映射;(b) 按用途索引的组件目录;(c) 区段大纲;(d) 样式清单,其中每个值都已匹配令牌,或标记为 UNMAPPED。 ✋ 检查点:展示令牌/组件覆盖情况和 UNMAPPED 列表。询问哪些 UNMAPPED 值应作为拟议的新令牌,哪些应作为已记录的例外接受。参见 references/01-discovery.md。
阶段 1 — 屏幕容器

**目标:**创建带有正确弹性容器和 RUN_ID 台账条目的屏幕 Board。

  1. execute_code:运行 scripts/createScreenWrapper.js(按 Board 名称实现幂等)→ 创建一个尺寸与视口一致的 Board,调用 addFlexLayout('column'),并将间距和内边距绑定到间距令牌(2.16.x 中,内边距需镜像并添加 padding-mirrors-token 例外)。 **退出标准:**存在一个空的、尺寸正确的弹性列布局 Board;其 id 已记入台账。 **✋ 检查点:**对空 Board 调用 export_shape;在填充内容前确认尺寸/方向。
阶段 2 — 逐步构建区段(每个区段重复)

目标:根据代码片段,在系统中准确构建一个区段。参见 references/02-component-assembly.md、references/03-token-binding.md、references/04-incremental-transform.md。

  1. execute_code:为该区段运行 scripts/buildSection.js——对于有匹配目录组件的部分,优先使用 component.instance();仅为真正定制的部分创建原始形状;通过 applyToken 将每个填充/间距/圆角/字体绑定到令牌。
  2. execute_code(单独调用,与 Agent 的回合间隔约 100 ms):读取 token.resolvedValue / shapeStructure,确认绑定已应用。
  3. 对该区段调用 export_shape。 **退出标准:**区段能够渲染,每个值都已绑定令牌或被批准为例外,组件均为实例。 ✋ 检查点:展示该区段;“看起来不错”仅表示批准当前区段。继续前先说出下一个区段的名称。
阶段 3 — 验证与报告

**目标:**证明屏幕符合系统规范。

  1. execute_code:运行 scripts/validateScreen.js → 令牌覆盖率、孤立原始值列表、结构合理性检查(已设置弹性布局、没有自动命名图层、实例与形状的对比)。
  2. 生成结构化报告(AGENTS.md 的第 12 节)。 **退出标准:**达到验收标准,或明确列出所有待审查的差距。 **✋ 检查点:**展示覆盖情况和剩余差距;请求签字确认。

7. 关键规则

  1. 始终先执行 high_level_overview;任何写入操作前都必须先完成 Phase 0 探索。
  2. 每次 execute_code 修改调用只能处理一个区段。绝不在一次调用中构建多个区段。
  3. 每个颜色、间距、圆角、边框和字体值在应用前都必须解析为 token。如果存在匹配的 token,形状上就不能使用原始 hex/rgb/px 值。
  4. 所有间距、内边距和间隔都必须是 4px 的倍数(将代码值四舍五入到最近的网格 token;如有例外,须记录)。
  5. 优先使用语义层级的 token,而非基础 token,以确保主题切换正常(tokens-schema.json)。
  6. 任何存在匹配库组件的 UI 部分都必须使用实例,不能手工构建形状组。
  7. 绝不自行发明 token。如果某个代码值没有匹配项,请提出建议(名称/值/层级),然后暂停并等待批准。
  8. Token 应用是异步的——必须在后续的 execute_code 调用中验证 resolvedValue,不能在同一次调用中验证。
  9. 未经明确批准,绝不对实例调用 detach();如有调用,须报告。
  10. 根据代码中的用途使用语义化 kebab-case 图层名称(nav、header、card-container)——绝不能使用 Rectangle 12。
  11. 每个阶段结束后都要写入 RUN_ID 台账;确保每次创建操作均可幂等执行(按名称检查是否已存在)。

8. 领域架构

此技能生成屏幕树,并使用设计系统映射。

  • 设计系统映射(Phase 0 输出,缓存在 storage.run.ds 中):
    • tokensByValue: { "#0066FF": "color.action.primary.bg", "16": "spacing.4", ... } — 反向索引,可快速将代码值查找为 token。
    • tokensByName: { "color.action.primary.bg": {type, resolvedValue} }。
    • componentsByRole: { button: {id, variants}, input: {...}, card: {...} }。
  • 区段大纲(来自代码): 有序列表 [{ role, codeFragment, childrenRoles }]。
  • 样式清单: [{ codeValue, cssProp, matchedToken | "UNMAPPED" }]。
  • 屏幕树(Penpot 输出): Board(flex column) → section Boards(flex) → 组件实例 + 绑定形状。
  • 台账(RUN_ID): { runId, phase, created:[{kind,name,id}], proposedTokens:[...], exceptions:[...], pendingReview:[...] }。

9. 模式与策略

默认模式为审查(Apply-with-review):构建每个区段,然后在检查点暂停,在继续下一个区段前提供 export_shape 和摘要。链接:shared/modes-and-policies.md。

  • 安全集(可自动应用): 语义化图层重命名;将原始值替换为与某个 token 的解析值完全相等的 token(无损替换);添加插件数据/元数据。
  • 始终需要审查: 创建屏幕 Board 和任何几何形状;实例化/重构组件;任何新 token 提案;detach();任何非精确相等、需要判断的 token 匹配。

10. 状态管理

链接:shared/state-management.md。台账命名空间为 penpot-ai,以 RUN_ID 为键(例如 bfc-2026-06-05-a)。

  • storage.run.ds — Phase 0 中缓存的设计系统映射(token、组件)。
  • setSharedPluginData('penpot-ai', '<RUN_ID>.phase', n) — 当前阶段。
  • setSharedPluginData('penpot-ai', '<RUN_ID>.ledger', JSON) — {boardId, sectionsBuilt:[role], proposedTokens, exceptions}。
  • 恢复: 重新读取台账,重新运行 inspectDesignSystem.js 以重新推导 DS 映射,再运行 shapeStructure(board) 查看哪些区段已存在,并从 ledger.phase 继续。幂等步骤可确保重新运行安全。

11. 用户检查点

阶段之后展示的产物要询问的问题
0 探索Token/组件覆盖率表;未映射的样式值"哪些未映射值应成为 token 提案,哪些应记录为例外?"
1 外层框架空 Board 的 export_shape + 尺寸"视口尺寸和列方向是否正确?"
2 区段(逐个)区段的 export_shape + token 绑定摘要"批准此区段吗?(会明确指出下一个区段的名称)"
3 验证覆盖率、孤立值列表、结构合理性检查"批准,还是先处理列出的问题?"

12. 命名约定

链接:shared/naming-conventions.md。领域细则:

  • Screen Board:screen-<view-name>(kebab 格式),例如 screen-settings。
  • Section Board:使用语义化 HTML 角色——header、nav、main、section、footer,或 kebab 格式的角色名称,如 card-grid、field-row。
  • 组件实例保留目录中的组件名称。
  • 提议的令牌遵循 tokens-schema.json 中的点分层级;优先采用根据代码用法提炼、描述意图的语义名称(color.action.primary.bg,而不是 color.blue.500)。

13. 反合理化对照表

LLM 的借口错误原因可确定性执行并中止流程的对策
“CSS 写的是 #0066FF,我就直接把它设为填充色。”硬编码的十六进制值不属于设计系统,无法适配主题,也不符合治理要求。在 storage.run.ds.tokensByValue 中查找。若匹配 → applyToken。若不匹配 → 提议一个令牌并停止,等待审批。绝不设置原始十六进制值。
“Tailwind 的 p-5 是 20px,设成 20 就差不多了。”直接使用字面值会绕过令牌比例尺,也可能不符合网格。四舍五入到最接近的 4px 网格间距令牌,然后执行 applyToken。只有获得批准后,才能记录例外情况。
“有 Button 组件,不过用圆角矩形加文字画一个更快。”重新实现系统组件会破坏更新、变体和交接的一致性。若存在 storage.run.ds.componentsByRole.button,则调用 component.instance() 并设置属性/变体。只有真正定制的部分才使用原始形状。
“我会用一次 execute_code 构建整页,省得多次调用。”一次性构建会隐藏失败,并产出未绑定、未经验证的结果。每次调用构建一个区块;在之后的调用中验证令牌绑定;在继续下一区块前执行 export_shape 并创建检查点。
“这个代码值没有对应令牌;我自己添加 color.misc.x,这样就能继续了。”默默臆造令牌会污染系统,并绕过人工治理。将其连同名称/值/层级添加到 ledger.proposedTokens,并在发现检查点停止。不得擅自创建。
“令牌读取失败;我还是把值硬编码进去作为备用方案吧。”硬编码备用值正是此技能禁止的孤立值;回读是异步的。在之后的 execute_code 调用中重新读取 resolvedValue。如果确实失败,应修复绑定——绝不能添加原始备用值。

14. 辅助代码片段

// Reverse-index lookup: code value -> token (Phase 2, inside buildSection)
const ds = storage.run.ds;
const tokenName = ds.tokensByValue[String(codeValue).toLowerCase()]; // e.g. "#0066ff" -> "color.action.primary.bg"
if (tokenName) {
  const token = penpotUtils.findTokenByName(tokenName);
  shape.applyToken(token, ["fill"]);            // verify resolvedValue in a LATER call
} else {
  ledger.proposedTokens.push({ from: codeValue, suggest: "propose a semantic token", tier: "semantic" });
}
return { applied: !!tokenName, codeValue };
// Prefer an existing component over a raw shape
const role = "button";
const cat = storage.run.ds.componentsByRole[role];
let node;
if (cat) {
  const comp = penpot.library.local.components.find(c => c.id === cat.id);
  node = comp.instance();                         // instance, not a redrawn box
} else {
  node = penpot.createRectangle();                // bespoke only
}
container.appendChild(node);
return { role, usedComponent: !!cat, id: node.id };

15. 参考资源

  • penpot_api_info("LibraryComponent")、penpot_api_info("Shape", "applyToken")、penpot_api_info("Board", "addFlexLayout")、penpot_api_info("Token", "resolvedValue") — 使用前先验证。
  • shared/penpot-mcp-tool-reference.md(工具接口)、shared/plugin-api-gotchas.md(易踩陷阱)、shared/tokens-schema.json(令牌类型/层级)、shared/naming-conventions.md、shared/state-management.md。
  • 相关技能:penpot-build-screen(基于需求简述的生成流程)、penpot-foundations(系统缺少可映射令牌时使用——其推断模式)、penpot-audit-accessibility(构建后的对比度检查)。

16. 支持文件

references/
文件加载阶段用途
references/01-discovery.md阶段 0枚举令牌/组件;构建反向值→令牌索引和按角色分类的组件目录;将代码解析为章节大纲和样式清单。
references/02-component-assembly.md阶段 2决定使用实例还是形状;实例化库组件、设置变体/属性;使用 flex 组装定制部分。
references/03-token-binding.md阶段 2将代码样式映射到语义令牌;applyToken 属性名称;异步验证;提出新令牌。
references/04-incremental-transform.md阶段 2逐节循环、排序、更新记录、恢复执行。
references/05-anti-rationalization.md所有阶段扩展的应对措施,包含具体的代码转换陷阱。
references/06-error-recovery.md失败时诊断绑定失败、孤立值、flex/x-y 冲突、分离失误。
scripts/
文件阶段用途
scripts/inspectDesignSystem.js0枚举令牌集/令牌和库组件;构建值→令牌反向索引及按角色分类的组件目录;在 storage 中缓存。
scripts/createScreenWrapper.js1幂等地创建屏幕 Board,设置 flex 列布局以及绑定令牌的内边距/间距。
scripts/buildSection.js2根据代码片段构建一个章节:实例化组件、创建定制形状、绑定令牌。
scripts/validateScreen.js3计算令牌覆盖率、列出孤立原始值、检查结构是否合理(flex、名称、实例)。

规范路径。 在原生安装中,shared/… 和 policies/… 在此软件包内解析(由安装程序随附);在 Claude Code 插件安装中,它们位于插件根目录 — ${CLAUDE_PLUGIN_ROOT}/shared/…,从本文件起向上两级目录。

评论

支持 Markdown