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)、または適切な要素がない場合はケバブケースのロール名(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. 最も重要なルール
ファイル全体を一度に処理してはいけません。 まず読み取り専用で調査し、すべてのレイヤーを3つに分類します。自動命名(安全に自動修正可能)、意味のある名前付き(レビューが必要)、曖昧(ユーザーへの確認が必要)です。その後、小規模なバッチに分けてリネームし、検証します。自動命名レイヤー(Rectangle 12 → button)のリネームは安全な範囲内であり、確認なしで適用できます。すでに意味のある名前が付いているレイヤーのリネームは判断を伴うため、必ずレビューが必要です。メインコンポーネントのシェイプのリネームはデフォルトで禁止です(すべてのインスタンスの名前が変わるためです)。execute_code の呼び出し1回につき、論理的なバッチを1つだけ処理し、バッチ間でチェックポイントを設けます。
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. Plugin API の基本事項
ドメインに関係する注意点と落とし穴(全項目は shared/plugin-api-gotchas.md を参照):
shape.nameは通常の書き込み可能な文字列です。shape.name = "button"としてリネームします。リネームメソッドはありません。書き込みは同期的に行われるため、トークンの適用とは異なり、同じ呼び出し内でshape.nameを読み戻して確認できます。- リネームによってジオメトリは変わりません。移動、サイズ変更、親の変更は行われません。このため、自動命名レイヤーのリネームは元に戻すことができ、安全です。
- コンポーネントのメインシェイプ:
shape.isComponentMainInstance()で検出します。メインインスタンスと、その内部にネストされたすべてのシェイプに対して true を返します。これらのいずれかをリネームすると、すべてのコピーのコンポーネント名が変わるため、安全な範囲外です。コピーインスタンス(isComponentCopyInstance()が true)であればリネームできます。注:メインインスタンスもインスタンスであるため、isComponentInstance()も true になります。メインシェイプの検出にisComponentInstance() === falseを使ってはいけません(実際にこのバグがありました)。分岐する前に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 は使用しません(コンポーネント用です)。
- 合格基準(定量的)— 対象範囲に自動生成された名前が残っていないこと。見出しとして機能するテキストレイヤーの 100% に
h1~h6の名前が付いていること。すべてのインタラクティブコンテナーがbutton/input/select/labelであること。すべてのリストコンテナーがul/olで、その子要素がliであること。変更された、意味のある名前が付いたレイヤーには、変更理由が記録されていること。名前を変更されたメインコンポーネントのシェイプが 0 個であること。
6. 必須ワークフロー
Phase 0 — 調査(読み取り専用)
- 目標: ガイダンスを読み込み、レイヤーの完全な一覧を作成し、各レイヤーの nameStatus を分類します。
- 手順:
high_level_overviewを 1 回呼び出します。次にexecute_codeでscripts/inspectLayerStructure.jsを実行し、各シェイプについて次の項目を収集します。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の推論ルールをローカルで適用します。各行を次のいずれかに分類します。safe(自動命名 → 変更)、review(意味のある名前 → 変更案)、ambiguous(信頼度が低い → 質問)。各行に 1 行の理由を記録します。 - 終了条件: 曖昧な行を分離した、名前変更マップ
{ shapeId: { old, new, bucket, reason, confidence } }があること。 - ✋ チェックポイント: 分類ごとにまとめた、変更前/変更後の完全な一覧を提示し、review と ambiguous の行について承認を得ます。(safe の行は autofix モードで事前承認されていますが、一覧には表示します。)
Phase 2 — 名前変更(書き込み、一括処理)
- 目標: 承認されたマップを冪等に、上から下へ(親を子より先に)、1 回の呼び出しにつき 1 バッチで適用します。
- 手順: 承認済みの
RENAME_MAPを設定したscripts/renameLayer.jsを貼り付けます。スクリプトはメインコンポーネントのシェイプをスキップし、すでに対象の名前になっているレイヤーをスキップして、変更前/変更後のペアを返します。1 回の呼び出しにつき 100 件以下のバッチにします。各バッチの後に台帳を更新します。 - 終了条件: 承認された各行が適用済み、または理由を明示してスキップされていること。エラーが 0 件であるか、エラーが報告されていること。
- ✋ チェックポイント:
export_shape('page','png','shape')(または名前を変更したボード)と、名前を変更した件数の概要を提示し、承認を得ます。
7. 重要なルール
- 書き込みを行う前に、名前変更計画全体を提示してください。 レイヤー名は引き継ぎ、コードのエクスポート、監査に影響するため、名前を間違えると後続のワークフローが気づかれないまま破損します。
- 自動修正で自動適用されるのは
auto-generated → semanticの名前変更のみです。 意味のある名前が付いたレイヤーへの変更は、常に レビュー 対象です。 - メインコンポーネントのシェイプ名は変更しないでください。
isComponentMainInstance()(メインインスタンスとその内部要素で true)で判定し、該当するものはスキップして報告します。コピーインスタンスの名前は変更できます。 - 上から下へ名前を変更してください。 親を子より先に変更すると、実行途中でもツリーの構成が分かりやすく、台帳も読みやすくなります。
- 冪等にしてください。 再実行しても、すでに対象の名前になっているレイヤーには何も変更を加えてはいけません。
- ここではジオメトリに触れてはいけません。 このスキルが書き込むのは
shape.nameのみです。resize()も、親の変更も行いません。 - HTML のセマンティック名はそのまま、ロール名はケバブケースにし、パスカルケースは使わないでください。
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。 - ロールコンテナ(ケバブケース):
card-grid、button-group、field-row、avatar-stack、nav-list。 - 兄弟要素に同じ要素名がある場合の識別用の修飾語:
button-primary、button-ghost、li-pricing。
9. モードとポリシー
shared/modes-and-policies.md を参照してください。このスキルの mode-default は autofix ですが、適用範囲は限定されています。
- 提案: 名前変更計画のみを生成し、何も変更しません。
- レビュー(レビュー後に適用): すでに意味のある名前が付いたレイヤー、および曖昧な行すべてに対するデフォルトです。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要素名をそのまま使うことを優先します。該当する要素がない場合に限り、ケバブケースのロール名を使います。
- 同じ要素を持つ兄弟要素がある場合は、ケバブケースの説明語を追加します:
button-primary、button-secondary、li-home、li-about。 - 見出しには、フォントサイズだけでなく、ページの視覚的な階層に合ったレベルを指定します。見出しレベルの順序については、
references/02-semantic-inference.mdを参照してください。 Rectangle 12、Group 4、Boardのまま公開しないでください。レイヤー名をパスカルケースにしないでください(パスカルケースはコンポーネント用です)。
13. 誤った正当化を防ぐための表
| LLMがする言い訳 | それが誤りである理由 | 決定論的な対策 |
|---|---|---|
| 「このレイヤーにはすでに名前があるので、ついでに改善しておきます。」 | 人が意図して付けた名前は安全な名前の集合に含まれません。台帳を使わずに黙って上書きすると、意図が失われ、元に戻せなくなります。 | 要確認に分類します。自動適用しないでください。フェーズ1のチェックポイントで変更前→変更後を提示し、承認を待ちます。 |
| 「これは明らかにボタンなので、パディングやサイズも調整しておきます。」 | このスキルが変更するのはshape.nameのみです。ジオメトリの変更を自動修正することはなく、別のスキルの対象です。 | 停止します。名前だけを変更します。ジオメトリに関する所見は確認用のメモとして記録し、resize()/setParentXYを呼び出さないでください。 |
| 「コンポーネントのメインシェイプの名前を変えるのは、インスタンスの名前を変えるのと同じです。」 | メインシェイプの名前を変えると、ファイル内のすべてのインスタンスでコンポーネント名が変わります。これは共有アセットの編集であり、自動修正してはいけません。 | isComponentMainInstance()に基づいて分岐します。メインインスタンスとその内部のすべてをスキップし、skipped: main componentとして報告します。 |
「大きなテキストはすべて、フォントサイズだけを基準にh1にします。」 | h1が複数あると見出しの階層が崩れ、このスキルが満たすべきアクセシビリティの前提条件も満たせません。 | 視覚的な目立ちやすさに基づいて見出しを並べます。領域ごとにh1を1つとし、続けてh2/h3を指定します。references/02-semantic-inference.mdのレベル規則を使います。 |
「繰り返し表示されるこの3つのカードは、それぞれsectionです。」 | リスト内で繰り返される兄弟要素は、単独のsectionではなく、ul内のliです。誤ったラベルを付けると、コードレビュー時の対応関係が崩れます。 | 兄弟要素の数と構造の一致に基づいて繰り返しを検出します。コンテナーにul、子要素にli(説明語付き)を指定します。 |
| 「速く済ませるために、ツリー全体を1回のexecute_code呼び出しで名前変更します。」 | 一度に処理するとチェックポイントの意味がなくなり、実行途中で推論を誤っても復旧できなくなります。 | 呼び出し1回あたり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 プラグインとしてインストールした場合はプラグインルートにあり、このファイルから 2 つ上のディレクトリにある ${CLAUDE_PLUGIN_ROOT}/shared/… を参照します。