关于 penpot-rename-layers
penpot-rename-layers 是用于 Penpot 的设计技能,为图层推断语义 HTML 元素或 kebab-case 角色名,并按检查点分批重命名。它强调保留人工命名、跳过主组件图形,并在写入后验证结果。
主要功能
- 01识别自动生成、语义及自定义名称
- 02推断语义元素与角色名称
- 03分批应用并记录重命名
- 04跳过主组件图形
- 05导出图像检查结果
适用场景
- 01为无障碍审计整理图层名称
- 02为设计交付和代码审查统一命名
MCP 相关
该技能通过 Penpot MCP 工具读取图层结构、执行名称修改并导出图形供检查。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ penpot/ penpot-ai-kit --skill penpot-rename-layers安装后在 Claude Code 中输入/penpot-rename-layers确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/01-inspection.md02-semantic-inference.md03-renaming-strategy.mdscripts/inspectLayerStructure.jsrenameLayer.js详细介绍
语义层重命名
1. 标题 + 工作原理
此技能会重命名 Penpot 文件中的图层,让每个图层都带有其代表的语义 HTML 元素名称(nav、header、main、section、article、button、input、label、h1–h6、p、ul、li、img),或者在没有合适元素时,使用kebab-case 角色名称(card-grid、button-group、field-row)。语义名称是进行无障碍审查(只能从命名为 h1–h6 的图层读取标题层级)、设计转代码审查(审查者将 button 对应到 <button>)和顺利交接的前提条件。
所有修改都通过 execute_code 完成;使用 export_shape 进行视觉验证;使用 penpotUtils.shapeStructure 读取结构(完整工具列表:shared/penpot-mcp-tool-reference.md)。重命名只需执行 shape.name = "..."——没有 renameShape() API。
2. 最重要的一条规则
切勿一次性处理整个文件。 先只读检查,将每个图层归入三类之一——自动命名(可安全自动修复)、有意义的名称(需要审核)、含义不明确(需要询问用户)——然后分小批次重命名并逐批验证。重命名自动命名的图层(Rectangle 12 → button)属于安全范围,可以直接执行,无需询问。重命名已有有意义名称的图层需要判断,且始终需要审核。默认禁止重命名主组件形状(这会改变所有实例的名称)。每次 execute_code 调用只处理一个逻辑批次;批次之间设检查点。
3. Penpot MCP 工具参考
完整工具列表:shared/penpot-mcp-tool-reference.md。与此领域相关的调用:
| 调用 | 用途 |
|---|---|
penpotUtils.findShapes(pred, root) / findShapeById(id) | 收集清单;解析要重命名的形状 ID。 |
penpotUtils.analyzeDescendants(root, evaluator, maxDepth) | 遍历树,并将父级上下文传递给分类器。 |
shape.name = "..."(通过 execute_code) | 执行重命名——直接写入属性;不存在重命名方法。 |
export_shape(shapeId, 'png', 'shape') | 对已重命名区域进行视觉检查。 |
penpot_api_info('Board') | 在使用 name、isComponentMainInstance()、isComponentCopyInstance() 前进行验证。 |
4. 插件 API 要点
相关领域的事实与注意事项(完整列表见 shared/plugin-api-gotchas.md):
shape.name是可直接写入的字符串。 使用shape.name = "button"重命名。没有重命名方法。写入是同步的——与应用令牌不同,可以在同一次调用中读取shape.name来确认。- 重命名不会影响几何属性——不会移动、缩放或重新设置父级。这正是自动命名图层的重命名可逆且安全的原因。
- 组件主形状: 使用
shape.isComponentMainInstance()检测——主实例及其内部嵌套的每个形状都会返回 true。重命名其中任何一个,都会为所有副本重命名该组件——超出安全范围。可以重命名副本实例(isComponentCopyInstance()为 true)。注意:主实例本身也是一个实例,因此isComponentInstance()对它也会返回 true——不要用isComponentInstance() === false检测主形状(这是一个真实发生过的 bug)。在分支处理前,使用penpot_api_info('Board', 'isComponentMainInstance')验证。 - #5
width/height/parentX/parentY为只读——与重命名无关;处理时不要“修复”几何属性(这是另一项技能,绝不可自动修复)。 - 返回小型结构化对象(数量 + ID + 前后对照)。
- 不确定任何签名时,请调用
penpot_api_info——猜测是导致静默失败的首要原因。
5. 了解令牌的简报约定
重命名前,先将请求重述为一份约定。请以资深设计系统工程师的身份行事,将图层名称视为设计与代码之间的约定,绝不交付自动生成的名称,也绝不未经询问就覆盖人工精心设置的名称。
- 背景——产品与界面(例如“营销落地页”“设置界面”);接下来会使用这些名称的人(无障碍审查、代码审查、交接)。
- 目标——单一且具体:“将当前页面上所有自动命名的图层重命名为其语义 HTML 元素名或 kebab-case 角色名。”
- 输入——范围(当前页面/所选画板/整个文件)、Phase 0 中的实时图层树,以及
shared/naming-conventions.md(图层命名部分)。 - 约束——绝不重命名主组件形状;绝不修改几何属性;除非用户选择加入,否则保留已有明确含义的名称;语义 HTML 名称原样使用,角色名称使用 kebab-case;图层名称不得使用 PascalCase(该格式用于组件)。
- 验收标准(量化)——范围内剩余的自动生成名称数为 0;100% 充当标题的文本图层都带有
h1–h6名称;每个交互容器都命名为button/input/select/label;每个列表容器都命名为ul/ol,并包含li子项;每个被更改的、原本有意义的名称都记录了修改理由;重命名的主组件形状数为 0。
6. 强制工作流
Phase 0 — 探查(只读)
- **目标:**加载指导文档并建立完整的图层清单;分类每个图层的名称状态。
- **步骤:**调用一次
high_level_overview。然后使用scripts/inspectLayerStructure.js执行execute_code,逐个形状收集:id、name、type、nameStatus(auto-generated|semantic|custom)、位置/尺寸提示、子项类型、文本属性(fontSize/fontWeight/characters)、填充/描边标记,以及isComponentInstance()。将清单缓存到storage。 - **退出条件:**生成一份扁平清单,包含每个图层的
nameStatus和统计数据(autoGenerated、alreadySemantic、custom、componentInstances、textNodes)。 - ✋ **检查点:**展示清单与统计数据;在进行推断前确认范围(页面/画板/文件)。
Phase 1 — 语义推断(分析,不写入)
- **目标:**生成重命名计划,列出更名前后的名称、置信度,以及每行所属类别。
- **步骤:**在本地将
references/02-semantic-inference.md中的推断规则应用于缓存的清单。为每行指定类别:安全(自动命名 → 重命名)、需审核(名称有意义 → 提议更改)、有歧义(置信度低 → 询问)。为每行记录一句理由。 - **退出条件:**生成重命名映射
{ shapeId: { old, new, bucket, reason, confidence } },并单独列出有歧义的行。 - ✋ 检查点:按类别展示完整的更名前后对照表;就需审核和有歧义的行征求批准。(在自动修复模式下,安全项已预先批准,但仍须展示。)
Phase 2 — 重命名(写入,分批进行)
- **目标:**自上而下(父级在子级之前),通过幂等操作按批准的映射执行重命名,每次调用处理一批。
- **步骤:**将已批准的
RENAME_MAP粘贴到scripts/renameLayer.js。该脚本会跳过主组件形状、跳过名称已符合目标的图层,并返回更名前后的名称对。每次调用最多处理 100 项。每批处理后写入日志。 - **退出条件:**每个已批准的行都已应用或明确跳过(并注明理由);错误数为 0,否则报告错误。
- ✋ **检查点:**执行
export_shape('page','png','shape')(或导出已重命名的画板),并提供重命名数量摘要;完成签核。
7. 关键规则
- 写入前先展示完整的重命名计划。 图层名称会影响交接、代码导出和审计;名称错误会在下游工作流中悄无声息地造成问题。
- 自动修复仅会自动应用
auto-generated → semantic重命名。 任何对已有有意义名称的图层所做的更改都必须审核。 - 绝不重命名主组件形状。 根据
isComponentMainInstance()(主实例及其内部结构均返回 true)进行分支;跳过这些形状并在报告中说明。副本实例可以重命名。 - 自上而下重命名。 先处理父级,再处理子级,这样运行过程中树结构始终清晰,日志也易于阅读。
- 幂等。 对已使用目标名称的图层重新运行时,必须不做任何更改。
- 此处不得触碰几何属性。 此技能只写入
shape.name,不做其他操作。不得调用resize(),不得重新设置父级。 - 语义化 HTML 名称原样使用,角色名称使用 kebab-case,绝不使用 PascalCase。 使用
h1、nav、button、card-grid,而非H1、CardGrid。 - 报告范围限制。 如果进行过抽样、限制为前 N 项或跳过页面,必须在最终报告中说明。
8. 领域架构
此技能生成的内容:
名称状态分类(清单的骨架):
auto-generated— 匹配^(Board|Frame|Rectangle|Group|Ellipse|Text|Path|Bool|Image|Component|Vector)\s*\d*$。安全集;可自动修复。semantic— 已是有效的 HTML 元素名称或已知角色名称。除非有误,否则保持不变。custom— 由人工编写的非语义化名称(Hero copy v2)。覆盖前须审核。
重命名映射行: { shapeId, old, new, bucket: 'safe'|'review'|'ambiguous', reason, confidence: 0..1 }。
命名输出词汇:
- 结构:
header、nav、main、section、article、aside、footer、form、dialog、figure。 - 交互:
button、input、select、label、a。 - 文本:
h1–h6、p、small、caption、span。 - 列表/媒体:
ul、ol、li、img、svg、icon、hr。 - 角色容器(kebab-case):
card-grid、button-group、field-row、avatar-stack、nav-list。 - 同级元素使用相同元素名称时,用于区分的描述符:
button-primary、button-ghost、li-pricing。
9. 模式与策略
参见 shared/modes-and-policies.md。此技能的 mode-default 为自动修复,但范围有限:
- 建议: 仅生成重命名计划,不做任何更改。
- 审核(审核后应用): 对任何已有有意义名称的图层,以及所有含糊不清的行,默认采用此模式。在 Phase 1 检查点之后应用。
- 自动修复(仅限安全集): 将未命名/自动命名的图层重命名为语义化名称——这种更改不会造成破坏、可撤销且明确无误,是唯一无需询问即可自动应用的更改。其他所有情况均转为审核。主组件形状绝不会自动重命名(完全排除在外)。几何属性、变体/组件重构、
detach()和新令牌均不在此范围内,绝不自动修复。
10. 状态管理
参见 shared/state-management.md。使用 setSharedPluginData(命名空间 penpot-ai)维护权威日志,以 RUN_ID 为键(例如 rename-2026-06-05-a);使用 storage 缓存会话数据。
日志键:
${RUN_ID}.phase—"0"|"1"|"2"。${RUN_ID}.ledger— JSON{ runId, phase, scope, renameMap, created:[], decisions:[], assumptions:[], pendingReview:[] }。storage.run.inventory— 缓存的 Phase 0 清单。storage.run.renameMap— 已批准的映射。
恢复:重新读取文件内日志,通过 shapeStructure 重新推导实时树,然后从 ledger.phase 继续。幂等性(跳过已使用目标名称的图层)确保批量操作可安全重新运行。
11. 用户检查点
| 阶段之后 | 显示的产物 | 我们询问的内容 |
|---|---|---|
| 0 — 探索 | 图层清单 + 名称状态统计;已确定的范围 | “范围是否正确(页面 / 画板 / 文件)?是否继续推断?” |
| 1 — 推断 | 按类别(安全 / 需审核 / 有歧义)分组的完整更名前→后表格,每行包含置信度 + 原因 | “是否批准需审核和有歧义的重命名?是否有要覆盖的名称?” |
| 2 — 重命名 | 已重命名区域的 export_shape + 重命名 / 跳过 / 错误计数 | “名称看起来正确吗?是否批准此批次并继续下一批?” |
12. 命名约定
权威来源:shared/naming-conventions.md(Layers 部分)。领域特定规则:
- 优先直接使用语义 HTML 元素名称;仅在没有合适元素时,才使用 kebab-case 角色名称。
- 当同级元素共享同一元素名称时,添加 kebab-case 描述词:
button-primary、button-secondary、li-home、li-about。 - 标题级别应符合页面的视觉层级,而不只是字体大小——标题级别排序请参阅
references/02-semantic-inference.md。 - 绝不交付
Rectangle 12、Group 4、Board。图层名称绝不使用 PascalCase(PascalCase 仅用于组件)。
13. 反合理化对照表
| LLM 给出的借口 | 错误原因 | 确定性应对措施 |
|---|---|---|
| “这个图层已经有名称了,我顺手改进一下。” | 人为有意设置的名称不属于安全集;悄悄覆盖会丢失原有意图,且没有台账就无法撤销。 | 将其归入需审核。不要自动应用。在第 1 阶段检查点显示旧名称→新名称,并等待批准。 |
| “这显然是个按钮——我顺便调整一下它的内边距 / 尺寸。” | 此技能只写入 shape.name。几何属性变更绝不自动修复,应由其他技能处理。 | 停止。仅重命名。将几何属性观察结果记为审核备注;不要调用 resize() / setParentXY。 |
| “重命名组件的主图形就等于重命名实例。” | 重命名主图形会更改文件中所有实例所用的组件名称——这是共享资源编辑,绝不自动修复。 | 根据 isComponentMainInstance() 分支处理。跳过主实例及其内部的所有内容;报告为 skipped: main component。 |
“只看字体大小的话,我会把每个大号文本都标为 h1。” | 多个 h1 会破坏标题层级,也不满足此技能旨在实现的无障碍前提条件。 | 按视觉显著性排列标题:每个区域一个 h1,依次递减为 h2 / h3。使用 references/02-semantic-inference.md 中的级别规则。 |
“这三个重复的卡片各自都是一个 section。” | 列表中的重复同级元素应是 ul 中的 li,而不是独立的 section;错误标注会破坏代码审查映射。 | 根据同级元素数量 + 结构匹配情况检测重复项;将容器命名为 ul,子项命名为 li(并添加描述词)。 |
“为了快,我会在一次 execute_code 调用中重命名整个树。” | 一次性处理会绕过检查点,并使错误推断在执行过程中无法恢复。 | 每次调用最多处理 100 项,自上而下进行,并在批次之间写入台账。 |
14. 辅助代码片段
分类名称(用于检查):
const isAutoGenerated = n =>
/^(Board|Frame|Rectangle|Group|Ellipse|Text|Path|Bool|Image|Component|Vector)\s*\d*$/i.test(n || "");
const isSemantic = n =>
/^(header|footer|nav|main|section|article|aside|form|dialog|figure|button|input|select|label|a|h[1-6]|p|small|caption|span|ul|ol|li|img|svg|icon|hr)([-_ ].*)?$/i.test(n || "");
const nameStatus = n => isSemantic(n) ? "semantic" : isAutoGenerated(n) ? "auto-generated" : "custom";
安全地重命名一个图形(幂等,跳过主组件):
const shape = penpotUtils.findShapeById("REPLACE-ME-SHAPE-ID");
let result;
if (!shape) result = { error: "not found" };
else if (shape.isComponentMainInstance && shape.isComponentMainInstance())
result = { skipped: "main component", name: shape.name }; // true for the main instance AND its internals
else if (shape.name === "button") result = { skipped: "already named", name: shape.name };
else { const old = shape.name; shape.name = "button"; result = { old, new: shape.name }; }
return result;
15. 参考资源
penpot_api_info('Board')— 确认name可写,并检查isComponentMainInstance()、isComponentCopyInstance()、detach()。penpot_api_info('PenpotPage')和penpotUtils.shapeStructure,用于遍历树结构。shared/naming-conventions.md— 规范的图层命名规则。shared/modes-and-policies.md— 此技能所依赖的精确安全集定义。- 相关技能:
penpot-audit-accessibility(使用标题名称)、penpot-design-to-code-review(使用语义名称)。请先运行此技能。
16. 支持文件
参考资料(渐进式披露)
| 文件 | 阅读阶段 | 涵盖内容 |
|---|---|---|
references/01-inspection.md | 阶段 0 | 只读遍历、名称状态分类、组件检测、范围选择。 |
references/02-semantic-inference.md | 阶段 1 | 推断规则(结构/交互/文本/媒体/列表)、按标题级别排序、歧义处理。 |
references/03-renaming-strategy.md | 阶段 2 | 自顶向下分批处理、幂等性、跳过主组件、验证、记录表与恢复。 |
脚本(粘贴到 execute_code 中)
| 脚本 | 阶段 | 用途 |
|---|---|---|
scripts/inspectLayerStructure.js | 0 | 只读清单,包含 nameStatus 和推断信号。 |
scripts/renameLayer.js | 2 | 幂等地应用已批准的 RENAME_MAP;跳过主组件;返回操作前后结果。 |
规范路径。 在原生安装中,shared/… 和 policies/… 会解析到此资源包内(由安装程序一并安装);在 Claude Code 插件安装中,它们位于插件根目录 — ${CLAUDE_PLUGIN_ROOT}/shared/…,也就是本文件往上两级目录。