penpot-build-screen について
既存のデザインシステムに沿って、ブリーフから画面を作る Penpot スキルです。フレックスレイアウトで段階的に構築し、コンポーネントとセマンティックトークンを再利用しながら、視覚確認と品質監査を行います。
主な機能
- 01既存のトークンとコンポーネントを確認
- 02画面をセクションごとに構築
- 03コンポーネントとセマンティックトークンを再利用
- 04フレックスまたはグリッドレイアウトを使用
- 05確認用の書き出しと品質監査
活用シーン
- 01プロダクトブリーフから画面を作成
- 02既存の Penpot デザインシステムを拡張
- 03レイアウト、トークン、間隔の整合性を確認
MCP 対応
`execute_code` を通じて Penpot MCP ツールを使用します。`export_shape` による視覚確認と、`penpotUtils.shapeStructure` による構造の確認が含まれます。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ penpot/ penpot-ai-kit --skill penpot-build-screenインストール後、Claude Code で/penpot-build-screenを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/01-brief-analysis.md02-style-profiles.md03-layout-composition.md04-component-recipes.md05-critique-framework.md06-anti-rationalization.md07-error-recovery.mdscripts/assembleScreen.jsauditScreenQuality.jsbuildSection.jscreateScreenFrame.jssetupOrReuseSystem.js詳細
penpot-build-screen — ブリーフからシステム内画面へ
1. タイトルと仕組み
penpot-build-screen はブリーフから洗練されたシステム内画面を作成します。変更はすべて
execute_code を通じて行い、export_shape で視覚的に検証し、
penpotUtils.shapeStructure で構造を読み取ります(ツールの全容:shared/penpot-mcp-tool-reference.md)。まず
既存のデザインシステム(penpot-foundations/ローカルライブラリ経由のトークンとコンポーネント)を
検出し、その後、フレックスボード内でセクションごとに画面を構築し、トークンを適用して
コンポーネントを再利用します。画面全体を一度の呼び出しで生成することはありません。
2. 最も重要な唯一のルール
システムを再利用し、段階的に構築します。 生のシェイプよりも既存のコンポーネントやセマンティックトークンを優先してください。セクションを1つ構築したら、export_shape でチェックポイントを作成してから次へ進みます。システムが存在しない場合は、最小限のものだけを初期構築し、実質的な作業は penpot-foundations に引き継いでください。
3. Penpot MCP ツールリファレンス
ツールの全容:shared/penpot-mcp-tool-reference.md。主な呼び出し:画面とセクションには penpot.createBoard()/addFlexLayout()、コンポーネントの再利用には penpot.library.local.components と comp.instance()、トークンの適用には shape.applyToken、チェックポイントには export_shape('selection'|'page') を使用します。
4. プラグイン API の基本
Gotcha の番号は shared/plugin-api-gotchas.md を参照してください。
- 画面とセクションはフレックスレイアウトを持つボードです。追加順序と間隔、配置/均等配置を使って構成します。
component.instance()でコンポーネントを再利用します。システムのパーツを生のシェイプとして描き直さないでください。- #3 テキストの自動サイズ調整 —
resize()(fixedに設定される)を実行した後に、growTypeをauto-width/auto-heightに設定します。 - #4 フレックスは子要素の x/y を上書きします — ストレッチ/マージンには
layoutChildを使用します。 - 色/間隔/角丸/書体はセマンティックトークンに適用し、ハードコードは避けてください。
- #11 新しい Board はすべて不透明な白の塗りつぶしで作成されます — これはこのスキルの重大な失敗要因です。
createBoard()はfills = [{ fillColor: "#FFFFFF", fillOpacity: 1 }]を設定します。そのままにすると、構造用ラッパーの四角い白い角が角丸の子要素の背後にはみ出し、角丸が壊れて見えます。また、白をそのまま保持したレイアウト用ボードはダークモードに切り替わりません(トークンがなく、システムから外れています)。塗りつぶしの方針: ボードごとに決めます — 構造用ボード(セクション、行、ラッパーなど、レイアウトのみを担うもの)はboard.fills = []にします。サーフェス(画面の背景、カード、シート、ボタン)は、リテラル値ではなくcolor.bg.*トークンを適用します。レイアウト用コンテナーはデフォルトで透明にします(shared/modes-and-policies.md)。 - #13b フォントの完全一致 —
penpot.fonts.all.find(f => f.name === "…")を使用します。findByNameは部分文字列検索です。 - #15 —
layoutChild.*はappendChildの後にのみ設定します。openPageは非同期です(2回呼び出すプロトコル:作成して開き、その後createBoardの前にcurrentPage.idをアサートします)。 - #16 — セクションごとに
clearFlipを実行します(塗りつぶしサイズの子要素でflipX = trueが発生することがあります。標準ヘルパーはshared/visual-effects.mdを参照)。 - #17 — ジオメトリを読み取る前に
await board.waitForLayoutUpdate()を実行します(sleep-100msの慣用パターンに代わる方法です)。 - #18 — 画像の塗りつぶし:
const img = await penpot.uploadMediaUrl(name, url); shape.fills = [{ fillOpacity: 1, fillImage: img }]を設定し、次の呼び出しで検証します —shared/visual-effects.mdを参照してください。 - 不慣れなシグネチャは、まず
penpot_api_infoで確認してください。
5. トークンを考慮したブリーフの契約
- コンテキスト — 製品、対象ユーザー、プラットフォーム、ブランドの雰囲気。
- 目的 — 対象となる単一画面と、ユーザーの主な目標。
- 入力 — コンテンツ/セクション、既存のトークンとコンポーネント、スタイルプロファイル、ビューポートサイズ。
- 制約 — 既存のコンポーネントを使用すること、グリッドに沿った間隔、セマンティックトークンのみを使用すること、禁止パターン、
shared/design-quality.md§7 に記載された兆候を含めないこと、strict anti-slop が有効な場合は、方向性の決定ステップで拒否されたキーを含めないこと(shared/anti-slop.md§1)。 - 受け入れ基準 — 明確な階層構造、4px のリズム、AA コントラスト、システムの再利用、レスポンシブ対応の意図が明記されていること、7 つすべての評価軸で design-quality スコアが 3 以上であること(
shared/design-quality.md§8)。満たさない場合は、弱い評価軸を明示してください。strict anti-slop が有効な場合は、slop スコアが 35 以下であること(penpot-anti-slopdiagnose)。
一般的なものではなく、意図的な美的判断を行うシニアプロダクト/ビジュアルデザイナーとして振る舞ってください。
6. 必須のワークフロー
ビジュアルの自己レビュー(必須): ビジュアルを提示するすべての ✋ チェックポイントの前に、
shared/visual-self-review.mdのエクスポート → 確認 → 修正のループを実行してください。作成したばかりの単位を エクスポートし、チェックリストに照らして画像を自分で確認し、目に見える不備を修正します(最大 2 回の イテレーション)。残っている不備があれば、その内容を明示したうえで同じエクスポートを提示してください。
フェーズ 0 — 検討。 high_level_overview を実行し、トークン/コンポーネントを確認します(scripts/setupOrReuseSystem.js)。ブリーフを分析します(references/01-brief-analysis.md)。スタイルプロファイル(references/02-style-profiles.md)と名前付き画面スケルトン(shared/design-quality.md §5)を選択します。このセッションで以前に作成した画面がないか台帳を確認し、多様性ルールを適用します(1 つ以上の軸を変え、どの軸かを述べること)。Anti-slop のオプトイン: 保存済みの設定(penpot-anti-slop → scripts/antiSlopPrefs.js)を読み込みます。設定がなく、ブリーフにも記載がない場合は、shared/anti-slop.md §0 にある質問を(ユーザーの言語で、ファイルごとに 1 回)尋ね、回答を保存します。設定が on の場合は、プロファイルとスケルトンを選ぶ前に方向性の決定ステップ(penpot-anti-slop references/02-direction-playbook.md)を実行し、そこで拒否されたキーを制約に反映します。✋ チェックポイント:ブリーフ、スタイル、スケルトン、セクション一覧(strict モードが有効な場合は方向性のブロックも含む)を確認します。
フェーズ 1 — フレーム。 scripts/createScreenFrame.js で画面ボードを作成します(冪等。ID を返し、背景/間隔/パディングのトークンを紐付けます)。ビューポートサイズを設定します。✋ チェックポイント。
フェーズ 2..N — セクション。 scripts/buildSection.js を使用して、トークン化されたフレックスボードとして各セクションを作成し、コンポーネントを再利用します。execute_code の呼び出し 1 回につき 1 セクションを作成します。各セクションの後に ✋ チェックポイント(export_shape)。
フェーズ N+1 — 組み立てと評価。 scripts/assembleScreen.js でセクションを組み立てます。scripts/auditScreenQuality.js で、レイアウトの網羅性(すべてのボードに flex/grid があること)、トークンの紐付け、グリッドに沿った間隔、命名を確認します。boardsWithoutLayout が空でない場合はゲートに失敗します。完了を報告する前に、フラグが付いた各ボードにレイアウトを追加してください。続いて、スコア付き評価(references/05-critique-framework.md)を実行します。最終エクスポートを shared/design-quality.md §8 の 7 つの評価軸それぞれで 1~5 点で評価します。いずれかの軸が 3 未満の場合は、対象を絞って修正します(最大 2 回)。その後、design-quality レポートを出力します(shared/report-schemas/design-quality-report.schema.json に従った Markdown + JSON 形式とし、台帳にも反映します)。strict モードが有効な場合: 画面ボードに対して penpot-anti-slop diagnose を実行し、その slop スコアをレポートに含めます(distinctiveness 軸に反映されます)。ワークフロー外では、スコアが 35 を超える場合、完了を宣言するのではなく、優先して修正すべき項目を提示します。レポートを出力します。
7. 重要なルール
- デフォルトでは Flex — すべてのコンテナはレイアウト Board です。 Board を作成したらすぐに、子要素を追加する前に、flex(
addFlexLayout())または grid(addGridLayout())レイアウトを設定してください。画面のルート、すべてのセクション、そして入れ子になったすべてのグループ(カード、行、リスト、統計情報のまとまり、フォームフィールド、ボタングループ)が対象です。UI 要素の配置に絶対座標x/yを使うこと、また UI のレイアウトに単なる Group を使うことは、絶対に避けてください。レイアウトのない Board はバグです。Phase N+1 の監査(boardsWithoutLayout)では、該当する Board が1つでもあるとビルドに失敗します。 - 生のシェイプを作成する前に、既存のコンポーネントを再利用してください。
- セマンティックトークンにバインドし、色、間隔、角丸、文字スタイルをハードコードしないでください。
- 1回の呼び出しにつき1つのセクションを作成し、
export_shapeでチェックポイントを設けてください。 - すべての間隔を4pxグリッドに合わせ、一貫したリズムを保ってください。
- ここでデザインシステム全体を立ち上げないでください。
penpot-foundationsに引き継いでください。 - レスポンシブ対応の意図(サイズ設定:fill/auto/fix)を明示してください。
8. ドメインアーキテクチャ
画面 = ルート flex Board(縦方向) → セクション Board(それぞれ独自の flex) → コンポーネントのインスタンス + トークン化されたプリミティブ。構成は明確な視覚的階層に従います。主要なアクションを目立たせ、コンテンツをグループ化し、間隔スケールに沿って余白を設け、セマンティックな文字スタイルのトークンを使用します。
9. モードとポリシー
デフォルトはreviewです。ジオメトリ/レイアウトの変更には、常にチェックポイントが必要です(shared/modes-and-policies.md)。
10. 状態管理
RUN_ID の下に台帳を保持します。内容は phase、screenBoardId、sections:[{name,id,done}]、styleProfile、skeleton、designQuality(§8 のレポートオブジェクト)、antiSlop(pref、direction、reports[] — strict mode が有効な場合)です。オプトインの設定自体は、ファイル全体に適用されるプラグインデータ penpot-ai → prefs.antiSlop です。再開時は、構造を読み直してください。
11. ユーザーのチェックポイント
| フェーズ後 | 成果物 | 確認事項 |
|---|---|---|
| 0(pref 未設定) | anti-slop のオプトインに関する質問(shared/anti-slop.md §0) | ありきたりな AI 風の見た目を避けますか? |
| 0 | brief + style + skeleton + sections(strict の場合は direction ブロックも) | 方向性を承認しますか? |
| 1 | 空のフレーム export_shape | フレーム/ビューポートを承認しますか? |
| 各セクション | セクションの export_shape | セクションを承認しますか? |
| 組み立て | 画面全体の export_shape + スコア付きの批評(7つの評価軸) | 承認しますか/反復しますか? |
12. 命名規則
shared/naming-conventions.md:レイヤーにはセマンティック HTML(header、main、section、nav、button)を使用し、画面の Board にはビュー名(Dashboard)を付けます。
13. 合理化を防ぐための表
| 言い訳 | なぜ間違っているのか | 対策(中断) |
|---|---|---|
| 「コンポーネントを使わずに、ボタンをさっと描こう。」 | 生のシェイプはシステムとの一貫性が崩れます。 | 既存のコンポーネントをインスタンス化してください。再発明より再利用を優先します。 |
| 「間隔/色をハードコードしたほうが速い。」 | リズム/テーマ設定/ガバナンスが損なわれます。 | セマンティックトークンにバインドし、間隔を4pxに合わせてください。 |
| 「画面全体を一度に生成しよう。」 | 一度に生成した出力はありきたりで、監査できません。 | チェックポイントを設けながら、セクションごとに構築してください。 |
| 「中央揃えのカードとありきたりなグラデーションで問題ない。」 | 出力が似通うことで、特徴のないブランドらしさに欠ける UI になります。 | 意図的なスタイルプロファイルを適用し、美的な選択に理由を持たせてください。 |
| 「ユーザーは忙しいから、anti-slop の質問は省こう。」 | strict mode を選ぶのはユーザーです。どちらかを推測しても間違いです。 | prefs.antiSlop を読み取ってください。未設定なら、1回だけ質問します(shared/anti-slop.md §0)。 |
| 「ここでトークンをさっと設定しよう。」 | Foundations の役割は専用のスキルにあります。 | 些細な作業を除き、penpot-foundations に引き継いでください。 |
「x/y で配置したほうが速いから、そうしよう。」 | 絶対座標はサイズ変更、リフロー、テーマ設定に対応できず、システムにも沿いません。 | flex/grid の Board で囲み、追加順とギャップ/整列で配置してください。 |
| 「これらをまとめるだけなら、単なる Group で十分。」 | Group はレイアウトを行わず、要素を囲むだけです。 | addFlexLayout() を使った Board を使用してください。監査ではレイアウトのない Board が検出されます。 |
| 「この小さなコンテナにレイアウトは必要ない。」 | すべての UI コンテナには、リズムとレスポンシブ対応のためにレイアウトが必要です。 | 子要素を追加する前に、必ず flex/grid を設定してください。例外はありません。 |
14. ヘルパーコードスニペット
// Screen frame (Phase 1)
const screen = penpot.createBoard();
screen.name = "Dashboard";
screen.resize(1440, 1024);
const flex = screen.addFlexLayout();
flex.dir = "column";
flex.horizontalSizing = "fix"; flex.verticalSizing = "auto";
penpot.currentPage.root.appendChild(screen); // append first (#7); layoutChild only after append (#15)
// SPACING: bind tokens, never literals (#8: padding tokens bind on ≥ 2.17; numeric mirror + ledger exception otherwise)
const gap = penpotUtils.findTokenByName("spacing.24");
if (gap) screen.applyToken(gap, ["rowGap"]); else flex.rowGap = 24;
const pad = penpotUtils.findTokenByName("spacing.32");
const FLEX_PROP = { paddingTop: "topPadding", paddingBottom: "bottomPadding", paddingLeft: "leftPadding", paddingRight: "rightPadding" };
for (const side of Object.keys(FLEX_PROP)) {
try { if (!pad) throw new Error("no token"); screen.applyToken(pad, [side]); }
catch (e) { flex[FLEX_PROP[side]] = pad ? Number(pad.resolvedValue) : 32; } // record { kind: "padding-mirrors-token" } in the ledger
}
// FILL POLICY (gotchas #11): the screen root is THE one surface — bind its bg to a token so it flips in
// dark mode. Every section nested inside stays transparent (buildSection.js clears their default white).
screen.fills = []; // drop Penpot's default opaque #FFFFFF
const bg = penpotUtils.findTokenByName("color.bg.default");
if (bg) screen.applyToken(bg, ["fill"]); // bound surface, not a literal
storage.bs = { screenBoardId: screen.id };
return { screen: screen.id, bgBound: !!bg, gapBound: !!gap, padBound: !!pad };
15. 参考リソース
penpot_api_info('Board')、penpot_api_info('LibraryComponent')、penpot_api_info('Text')。
16. 関連ファイル
references/: 01-brief-analysis.md、02-style-profiles.md、03-layout-composition.md、04-component-recipes.md、05-critique-framework.md、06-anti-rationalization.md、07-error-recovery.md。エフェクト、画像プレースホルダー、グラデーションについては shared/visual-effects.md を参照してください。
scripts/: setupOrReuseSystem.js、createScreenFrame.js(フェーズ 1 のフレーム:冪等、トークンに紐づく背景/間隔/パディング、台帳)、buildSection.js、assembleScreen.js、auditScreenQuality.js。
ドクトリンのパス。 ネイティブインストールでは shared/… と policies/… はこのバンドル内のパスとして解決されます(インストーラーによってベンダー化されます)。Claude Code プラグインとしてインストールした場合は、プラグインのルートにあり、このファイルから 2 つ上のディレクトリにある ${CLAUDE_PLUGIN_ROOT}/shared/… がパスになります。