penpot-document-handoff について
Penpot のデザインを、コンテキストカード、番号付きピン、対応する注記、任意のツールチップを備えた引き継ぎ資料にするスキルです。元のデザインには触れず、横に表示切り替え可能な注釈レイヤーを追加します。
主な機能
- 01デザインの横にコンテキストカードを作成
- 02番号付きピンと対応する注記を追加
- 03一時的な状態に任意のツールチップを追加
- 04注釈コンポーネントとトークンを再利用
- 05注釈をグループ化して一括で表示切り替え
活用シーン
- 01レビュー担当者向けに背景やビジネスルールを記録
- 02UI 領域と所見や推奨事項を関連付け
- 03ツールチップで一時的な UI 状態を説明
MCP 対応
Penpot MCP ツールでデザインや注釈コンポーネントを調べ、独立した注釈レイヤーを作成し、レビュー用の画像をエクスポートします。元のデザインは変更しません。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ penpot/ penpot-ai-kit --skill penpot-document-handoffインストール後、Claude Code で/penpot-document-handoffを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/01-annotation-anatomy.md02-handoff-brief.md03-layout-placement.md04-component-and-tokens.md05-anti-rationalization.md06-error-recovery.mdscripts/addTooltipCallout.jsbuildContextCard.jsfinalizeHandoff.jsplacePinAndNote.jssetupAnnotationKit.js詳細
penpot-document-handoff — デザイン → 注釈付き引き継ぎ
1. タイトル + 仕組み
penpot-document-handoff は、完成済み(または作業中)のデザインを、それだけで内容がわかる引き継ぎ資料に変換します。デザインの左側には コンテキストカード(「How might we」の目標、ビジネスルール、リンク、デザイナー、ステータス、求める/求めないフィードバック)、UI 領域には 番号付きピン、右側には対応する 観察/推奨事項のノートカード を配置し、一時的な状態には必要に応じて ツールチップ を追加します。すべての注釈は 表示/非表示を切り替えられるグループ にまとめられるため、レビュー担当者はワンクリックで注釈のない元のデザインに戻せます。既存の注釈コンポーネントキットと annotation.* トークンがあれば再利用し、なければ最小限のものを提案します(人間による承認が必要です)。すべての変更は execute_code 経由で行い、export_shape で見た目を検証し、penpotUtils.shapeStructure で構造を読み取ります(ツールの全機能については shared/penpot-mcp-tool-reference.md を参照)。まず対象のデザインと既存の注釈コンポーネントキットおよびトークンを検出し、その後、注釈レイヤーを 段階的に、1 回の呼び出しにつき注釈 1 つずつ 作成します。注釈は必ず 兄弟レイヤー として追加し、デザイン自体は決して編集しません。
2. 最も重要なルール
デザインの上ではなく横に注釈を置き、1 回の呼び出しにつき注釈は 1 つだけ追加します。 ドキュメント化するデザインは読み取り専用です。横に独立した表示/非表示を切り替えられる注釈レイヤーを追加し、元のデザインの図形は一切移動、スタイル変更、再構成しません。まずコンテキストカードを作成し、その後、ピンとノートを一度に 1 つずつ追加して、都度チェックポイントを作成します。注釈一式を 1 回の execute_code 呼び出しで生成するのは失敗につながります。
3. Penpot MCP ツールリファレンス
ツールの全機能については shared/penpot-mcp-tool-reference.md を参照してください。このスキルで主に利用する呼び出しは次のとおりです。
penpotUtils.shapeStructure / findShape / findShapes(デザインとキットのコンポーネントを特定)、
penpot.library.local.components + comp.instance()(注釈キットを再利用)、
penpot.createBoard() / addFlexLayout()(キットがない場合は作成)、
penpot.group()(表示/非表示を切り替えられるグループ。penpot_api_info で確認)、
shape.applyToken(アクセント/サーフェス/文字のスタイルを適用)、
各チェックポイントで export_shape('selection'|<id>) を実行します。
4. プラグイン API の基本
注意点の番号は shared/plugin-api-gotchas.md を参照してください。
- 設計は読み取り専用の入力です。
shapeStructureで読み取り、子のbounds(絶対位置の x/y/幅/高さ)からピンのアンカーポイントを解決します。設計に対してresize/親の変更/detach/removeを呼び出してはいけません。 - 注釈カードはフレックスレイアウトのボードです(参照システムと同じ
column-reverse)。カード内では絶対位置の x/y を使わず、追加順+間隔+パディングで構成します。 - ピンとコンテキストカードはページ上の絶対位置に配置します(設計のレイアウト内にはありません)。
x/yを直接設定するか、レイアウトボードの子にする場合はlayoutChild.absolute = trueを設定します(#14:絶対位置の子はページ座標を使用し、ボードは端でクリップされます)。 - #3 テキストの自動サイズ調整 —
resize()の後(resize()はfixedに強制します)、growTypeをauto-width/auto-heightに設定します。textBoundsを読み返す前に約 100 ms 待ちます。 - #2 非同期のトークン適用 — 1 回の呼び出しで適用し、後続の呼び出しで
resolvedValueを確認します。 - #11 新しいボードはすべて、不透明な白の塗りで作成されます。これはこのスキルの重大な失敗要因です。
createBoard()はfills = [{ fillColor: "#FFFFFF", fillOpacity: 1 }]を初期設定します。そのままにすると、構造用ラッパーの四角い白い角が、包んでいる角丸カードの背後から見えてしまいます。また、白をそのまま使うボードはシステムの配色に準拠しません(テーマに合わせることはできません)。塗りの方針: ノート/コンテキストカードとツールチップは実際のサーフェスなので、背景をcolor.annotation.surfaceにバインドします(リテラル値は使いません)。内側のセクションボードとラッパーは構造用なので、board.fills = []で塗りをクリアします。 - #13b フォントの完全一致 —
penpot.fonts.all.find(f => f.name === "Work Sans") || nullを null ガード付きで使用します。findByNameは部分一致検索です。フォントが見つからない場合はデフォルトを維持し、font-fallbackを報告します。 - 非表示化用のラップ:すべての注釈シェイプを収集し、名前付きのグループ 1 つにまとめて
group()でグループ化します。非表示にするにはgroup.hidden = trueを設定します。group()/グループ化のシグネチャを使用する前に、penpot_api_infoで確認してください。
5. トークン対応ブリーフの契約
変更を加える前に依頼内容を言い換えて確認します。作業対象に注釈を重ねず、注釈パレットをハードコードしないシニアのデザインシステム/ハンドオフ専門家として対応します。
- コンテキスト — 製品、対象ユーザー、記録する機能/フロー、対象読者(開発者、PM、デザインレビューなど)。
- 目的 — 記録する単一のデザイン(ボード/フレームまたは選択範囲)と、ハンドオフで明確にすべきこと。
- 入力 — デザインボードの ID、ハンドオフブリーフの内容(US 番号、タイトル、「How might we」の目標、コンテキスト/ビジネスルール、リンク、デザイナー、ステータス、プラットフォーム、フィードバックを求める内容/求めない内容)、ピンを配置する UI 領域の一覧と、それぞれの所見テキスト(任意で推奨事項も含む)、ツールチップが必要な一時的な状態。
- 制約 — デザインを変更しない。注釈キットがあれば再利用し、なければ提案する。アクセント/サーフェス/文字スタイルをトークンにバインドする(不足している場合は
annotation.*トークンを提案し、人が承認する)。ピンは 1 から連番にし、ノートと 1 対 1 で対応させる。すべてを非表示にできるグループ内に配置する。 - 受け入れ基準 — デザインがバイト単位で変更されていない。各ピンに対応するノートが厳密に 1 つあり、各ノートにも対応するピンが厳密に 1 つある。番号は 1 からの連番。すべての注釈テキストが注釈用の文字スタイルトークンにバインドされている。アクセントとサーフェスがトークンにバインドされている。グループの切り替え 1 回でレイヤー全体を表示/非表示にできる。3 列の読み順(コンテキスト|デザイン|ノート)が保たれている。
6. 必須ワークフロー
目視でのセルフレビュー(必須): 視覚的な成果物を示す各 ✋ チェックポイントの前に、
shared/visual-self-review.mdに記載されているエクスポート → 確認 → 修正のループを実行します。直前に作成したユニットをエクスポートし、チェックリストに照らして画像を自分で確認し、目に見える不具合を修正してください(最大 2 回)。残っている不具合があれば明記し、同じエクスポートを提示します。
フェーズ 0 — 調査(読み取り専用)。 high_level_overview を実行します。対象のデザイン(penpot.selection または名前付きボード)を特定し、その ID を storage.dh にコピーします。その構造を読み取り(scripts/locateDesign パターン、深さ 2~3)、ピン留め可能な領域を列挙します。注釈キットとトークンを確認します(scripts/setupAnnotationKit.js の dryRun)。✋ チェックポイント: デザインを確認し、キットが存在するか作成が必要かを確定します。
フェーズ 1 — 引き継ぎブリーフ。 コンテキストカードの内容とピンのリスト(領域 → 所見 → 任意の推奨事項)を収集/確認します。references/02-handoff-brief.md / prompts/handoff-brief.md を使用します。
✋ チェックポイント: 描画を始める前に、ブリーフとピンのリストを承認します。
フェーズ 2 — 注釈キットの準備。 キットのコンポーネントと annotation.* トークンが存在する場合は再利用します。存在しない場合は、references/04-component-and-tokens.md に従って最小限のキット(Critique Card、Chip Note、Pointer S/L、Tooltip)とトークン(color.annotation.accent、color.annotation.surface、color.annotation.on-accent、color.annotation.body、font.annotation.title|body|label)を提案し、承認後にのみ作成します(scripts/setupAnnotationKit.js)。✋ チェックポイント: キットとトークンの名前/値/ティアを承認します。
フェーズ 3 — コンテキストカード。 Critique Card を作成/インスタンス化し、ブリーフの内容を記入して、デザインの左側に配置します(scripts/buildContextCard.js)。✋ チェックポイント: カードを export_shape します。
フェーズ 4 — ピンと注釈(1 回の呼び出しにつき 1 つ)。 各領域について、デザイン上の領域に固定した番号付き Pointer/L ピンを配置し、同じ番号の Chip Note を右側の列に配置します(scripts/placePinAndNote.js)。一時的な状態には、任意で Tooltip を追加します(scripts/addTooltipCallout.js)。execute_code の呼び出し 1 回につき注釈 1 つ。 ✋ チェックポイント: それぞれ(または少数ずつまとめて)追加した後に export_shape します。
フェーズ 5 — 仕上げと監査。 すべての注釈シェイプを Hide this to quit notes という名前の非表示切り替え可能なグループにまとめます。セルフ監査(scripts/finalizeHandoff.js)を実行します。デザインが未変更であること、ピンと注釈が一致していること、番号が連続していること、トークンがバインドされていること、3 列の順序を確認します。violations が空でなければゲートを通過できません。完了を報告する前に修正します。報告します。
7. 重要なルール
- デザインは絶対に変更しないでください。 元のシェイプのジオメトリ、塗りつぶし、名前、構造を変更してはいけません。このスキルで追加するのは、兄弟となる注釈レイヤーのみです。フェーズ 5 の監査では、デザインのシェイプ一式または境界が変わっていると実行が失敗します。
execute_codeの呼び出し 1 回につき注釈 1 つ。 まずコンテキストカードを作成し、その後、各ピンと注釈を個別に作成します。レイヤー全体を一度に作成してはいけません。- ピンと注釈の対応および番号の連続性。 すべての Pointer ピンには、同じ番号の Chip Note がちょうど 1 つ対応します。番号は 1 から N まで欠番なく続きます。キャンバス上のピン(L)と注釈のヘッダーにあるピン(S)は、同じ番号を共有します。
- キットを再利用し、トークンを提案する。値を直接指定しない。 既存の注釈コンポーネントをインスタンス化します。キット/トークンがない場合は、レビューのもとで提案して作成します。
#1A88E0/#E4F3FFを直接指定してはいけません。 - 3 列レイアウト。 左にコンテキストカード、中央に未変更のデザイン、右に縦に並べた注釈カードを配置します。ピンは指し示す領域に重ねます。
- 各カード内はすべてフレックス。 カード/セクションはフレックスの Board(参考例のような
column-reverse)にします。テキストを絶対位置で配置したり、通常の Group にしたりしてはいけません。 - すべてを 1 つのグループから非表示にできるようにする。 すべての注釈シェイプを名前付きの単一グループ内に配置し、レビュアーがワンクリックでクリーンなデザインに切り替えられるようにします。
- デフォルトモードはレビューです。 ジオメトリを作成したら各フェーズでチェックポイントを設けます。キット/トークンの作成は自動修正してはならない変更であり、承認が必要です。
8. ドメインアーキテクチャ
注釈レイヤーは、変更していないデザインの周囲に3つの列で配置します。
[ Critique Card ] [ the design (read-only) ] [ Chip Note #1 ]
#US · title ┌─────────┐ number+TITLE
State/Copy/Platform │ ① ② ③ │ ← Pointer/L pins Observation
status pill │ UI… │ on the regions Recommendation?
HMW goal └─────────┘ [ Chip Note #2 ] …
links · designers (+ Tooltip/Top|Bottom for
context transient states)
feedback wanted
feedback NOT wanted
カード、ピン、ツールチップはすべて、1つのグループで囲みます:Hide this to quit notes
コンポーネントキットとトークンの分類については、references/01-annotation-anatomy.md、references/04-component-and-tokens.mdを参照してください。
9. モードとポリシー
デフォルトはレビュー(shared/modes-and-policies.md)です。ジオメトリ、コンポーネント、トークンを作成する場合は、必ずチェックポイントが必要です。このスキルが自動適用できる安全な項目:ドキュメントのメタデータ(plugin-dataタグ)の追加と、作成した自動命名の注釈レイヤーの名前変更です。自動修正は決して行いません:キットコンポーネントの作成、annotation.*トークンの作成、および(常に)ドキュメント対象のデザインに対する変更です。塗りのポリシー:ノート/コンテキストカードは実際のサーフェスなので、背景をcolor.annotation.surfaceにバインドします。内側のセクションボードは構造要素なので、fills = []とします。
10. 状態管理
RUN_IDの下に(shared/state-management.md)、storage.dhとファイル内のパンくず情報を使って台帳を管理します:phase、designBoardId、kit:{critiqueCardId,chipNoteId,pointerSId,pointerLId,tooltipId,created}、tokens:{accent,surface,...}、contextCardId、notesColumnX、groupId、pins:[{n,regionId,pinId,noteId}]、pinCounter。再開時は台帳を読み直し、構造を読み取って実際の状態(グループとピン)を再確認してから、pinCounterの続きから進めます。
11. ユーザーのチェックポイント
| フェーズの後 | 表示する成果物 | 確認事項 |
|---|---|---|
| 0 ディスカバリー | デザインの概要+ピンを配置できる領域+キット/トークンの有無 | 対象とキットの計画を確認しますか? |
| 1 ブリーフ | コンテキストカードの内容+番号付きピン一覧 | ブリーフとピンを承認しますか? |
| 2 キット | 提案するコンポーネント+トークン名/値/階層(作成する場合のみ) | キットとトークンを承認しますか? |
| 3 コンテキストカード | カードのexport_shape | 内容/配置を承認しますか? |
| 各ピン+ノート | 領域とノートのexport_shape | 承認または調整しますか? |
| 5 仕上げと監査 | 非表示にできるグループ+監査結果 | 引き継ぎを承認しますか?それとも反復しますか? |
12. 命名規則
shared/naming-conventions.md。コンポーネントはPascalCase(Critique Card、Chip Note、Pointer、Tooltip。再利用する場合は、参照システムの名前を維持します)。トークンはannotationセット配下のドット表記(color.annotation.accent、font.annotation.label)。レイヤーはkebab-caseまたは意味がわかる名前(context-card、note-card、pin、annotations)。非表示にできるグループには、識別しやすい名前Hide this to quit notesを維持します。ピンのラベルは整数のインデックスです。
13. 合理化を防ぐための一覧
| LLM が持ち出す言い訳 | それが間違っている理由 | フローを停止させる決定論的な対策 |
|---|---|---|
| 「デザインの上にメモのテキストをそのまま置く/レイヤーの色を変えて強調すればいいだけです。」 | 成果物を変更してしまいます。引き継ぎ用の注釈は削除可能で、非破壊でなければなりません。 | 停止してください。メモ欄に兄弟の注釈シェイプを追加するか、ポインターのピンをオーバーレイしてください。元のシェイプは絶対に編集しないでください。デザインが変更されていると、フェーズ 5 の監査に失敗します。 |
「呼び出し回数を減らすため、すべてのピンとメモを 1 回の execute_code で作成します。」 | 一括出力は監査できず、ピンとメモの番号がずれてしまいます。 | 呼び出し 1 回につき注釈 1 つにしてください。export_shape でチェックポイントを作成し、その都度 storage.dh.pinCounter を進めてください。 |
「アクセントブルーは飾りにすぎないので、#1A88E0 をハードコードします。」 | システム外の値はガバナンスに反し、テーマ変更やブランド変更にも対応できません。 | color.annotation.accent にバインドしてください。存在しない場合は、承認を得るために提案(名前/値/階層)してください。 |
| 「このメモにピンは本当に必要ありません。一般的な内容です。」 | 孤立したメモは、レビュー担当者が頼りにする番号から領域を読み取るモデルを損ないます。 | すべてのチップノートに、具体的な領域を指すポインターのピンを付けてください。本当に全体に関わる内容なら、メモではなくコンテキストカードに記載してください。 |
| 「チップノートコンポーネントをインスタンス化するより、プレーンテキストブロックのほうが速いです。」 | 生のテキストはシステムから逸脱し、キットに合わせたスタイル変更も適用されません。 | キットのコンポーネントをインスタンス化してください。キットがない場合は、レビューを受けて一度だけ作成し、再利用してください。 |
| 「メモの番号はあとで振り直します。今は順番は重要ではありません。」 | 番号の欠落や重複は、引き継ぎを気付かれないまま損ないます。 | すべての段階で番号を連続させ、一致させてください。欠落や重複があると監査で拒否されます。 |
| 「非表示にできるグループは省略します。レイヤーは十分整理されています。」 | 1 つの切り替え操作がないと、レビュー担当者は注釈のないクリーンなデザインに戻せません。 | 完了を報告する前に、すべての注釈シェイプを単一の Hide this to quit notes グループにまとめてください。 |
14. ヘルパーコードスニペット
// Phase 0 — lock the target design + enumerate pinnable regions (READ-ONLY)
const design = penpot.selection[0] || penpotUtils.findShape(s => s.name === "REPLACE-ME-board");
if (!design) return { error: "Select the design board to document, or pass its name." };
storage.dh = Object.assign(storage.dh || {}, { designBoardId: design.id });
const regions = (design.children || []).map(c => ({
id: c.id, name: c.name, type: c.type,
x: Math.round(c.x), y: Math.round(c.y), w: Math.round(c.width), h: Math.round(c.height)
}));
return { design: { id: design.id, name: design.name, x: Math.round(design.x), y: Math.round(design.y),
w: Math.round(design.width), h: Math.round(design.height) }, regionCount: regions.length, regions };
// Reference palette/typography of the annotation system (verified from the example file).
// Use these as the VALUES when proposing annotation.* tokens — do NOT paint them raw on shapes.
return {
color: { accent: "#1A88E0", surface: "#E4F3FF", onAccent: "#FFFFFF", body: "#000000" },
type: { family: "Work Sans",
label: { size: 12, weight: 500, case: "uppercase", fill: "accent" },
body: { size: 14, weight: 400, fill: "body" },
title: { size: 24, weight: 400, fill: "body" } },
card: { bg: "surface", padding: [24,12,24,12], flexDir: "column-reverse", sectionGap: 24, labelGap: 4 },
pin: { L: 40, S: 24, radius: 9999, bg: "accent", number: "onAccent" }
};
15. 参考リソース
penpot_api_info('Board')、penpot_api_info('LibraryComponent')、penpot_api_info('Text')、penpot_api_info('Context','group')— グループ化する前に、シグネチャを確認してください。shared/penpot-mcp-tool-reference.md(ツールの概要)、shared/plugin-api-gotchas.md(#11 fill policy、非同期トークン、resize→growType)、shared/tokens-schema.json(トークンのtypeの表記)。
16. 補足ファイル
references/(段階的開示形式の詳細資料)
| ファイル | 読み込むタイミング | 内容 |
|---|---|---|
references/01-annotation-anatomy.md | フェーズ 2~4 | リバースエンジニアリングしたシステム:批評カードのセクション、チップノートの構造、ポインター S/L、ツールチップ、パレット/文字スタイル、非表示にできるグループ。 |
references/02-handoff-brief.md | フェーズ 1 | コンテキストカードの内容とピン一覧を引き出し、構成する方法。 |
references/03-layout-placement.md | フェーズ 3~4 | 3 列の配置、ピンのアンカー計算、メモの積み重ね、間隔のリズム。 |
references/04-component-and-tokens.md | フェーズ 2 | 注釈コンポーネントキットと annotation.* トークンの提案を見つけるか作成する方法。 |
references/05-anti-rationalization.md | すべてのフェーズ | 対策を含む、よくある失敗パターンの詳細な一覧。 |
references/06-error-recovery.md | 失敗時 | キットの欠落、番号の不整合、誤ったデザイン編集、グループ化/グループ解除の問題からの復旧方法。 |
scripts/(execute_code に貼り付けるテンプレート)
| ファイル | フェーズ | 目的 |
|---|---|---|
scripts/setupAnnotationKit.js | 0/2 | キットとトークンを一覧化します。dryRun ではない場合は、最小限のキットを作成し、トークンを提案します。 |
scripts/buildContextCard.js | 3 | Critique Card を作成/インスタンス化し、ブリーフの内容を記入します。 |
scripts/placePinAndNote.js | 4 | 領域に番号付きピンを1つ追加し、対応する Chip Note を追加します。 |
scripts/addTooltipCallout.js | 4 | 一時的な状態やホバー状態に対応する Tooltip コールアウトを任意で追加します。 |
scripts/finalizeHandoff.js | 5 | 注釈を非表示にできるグループで囲み、パリティ/未変更/トークンの監査を実行します。 |
Doctrine のパス。 ネイティブインストールでは、shared/… と policies/… はこのバンドル内を参照します(インストーラーによってベンダー化されます)。Claude Code プラグインとしてインストールした場合は、プラグインのルートに配置されます。このファイルから2階層上の ${CLAUDE_PLUGIN_ROOT}/shared/… です。