penpot-mcp について
penpot-mcpは、Penpotのデザインプロジェクトやデザインシステムを扱うMCP対応エージェント向けのスキルです。Penpot公式MCPサーバーを通じて現在開いているファイルを調査・編集し、読み取り、計画、小規模な変更、検証の順で作業します。
主な機能
- 01リモートまたはローカルのMCPサーバーに接続
- 02ページ・レイヤー・コンポーネントを確認
- 03JavaScript APIでデザインを読み書き
- 04図形のエクスポートやローカル画像の取り込み
- 05小さく変更して構造を検証
活用シーン
- 01Penpotファイルのページやコンポーネントの確認
- 02デザインシステムの作成・保守
- 03Penpotでのプロトタイプやインタラクション制作
- 04MCP接続や操作のトラブルシューティング
MCP 対応
Penpot公式MCPサーバーに接続し、ファイル構造の確認、API情報の照会、JavaScript実行、図形のエクスポートなどのツールをMCPクライアントに提供します。ローカルモードではローカル画像の取り込みにも対応します。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ ar27111994/ penpot-mcp --skill penpot-mcpインストール後、Claude Code で/penpot-mcpを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/design-system-workflows.mddesign-to-code-workflows.mdpenpot-api-patterns.mdprototyping-workflows.md詳細
Penpot MCP スキル
公式 MCP サーバーを通じて Penpot で、実運用レベルのデザインプロジェクトやデザインシステム — フロー、インタラクション、アニメーション、トークン、視覚効果を含む — を作成・監査・保守するための AI エージェントワークフローです。
対応 AI エージェント
MCP 互換のあらゆるクライアントで動作します: Claude Code、Cursor、VS Code / Copilot、Codex / OpenCode、Amp、Cline、Windsurf、Claude Desktop (mcp-remote 経由)、および HTTP または SSE の MCP トランスポートをサポートするあらゆるエージェント。
アーキテクチャの概要
MCP Client (any MCP-compatible agent / IDE)
↕ HTTP (or stdio via mcp-remote proxy)
MCP Server (hosted remote OR local npx)
↕ WebSocket / plugin bridge
Penpot Plugin (running inside the open design file)
MCP は、常にアクティブな Penpot ブラウザータブ内で現在フォーカスされているページに対して動作します。同時に MCP を所有できるタブは 1 つだけです。
MCP は Penpot MCP プラグインを通じて動作します。任意のインストール済みコミュニティプラグインを列挙・インストール・起動・操作するための文書化された方法は提供していません。他のプラグインとの連携は、ユーザーが明示的に依頼した場合、またはファイル上で確認できる証拠によってプラグインが関連する場合にのみ行ってください。
1. 接続のセットアップ
リモート MCP (ほとんどのユーザーに推奨)
- Penpot → Your account → Integrations → MCP Server → 有効化
- MCP キーを生成 (一度だけ表示されます — 安全に保管してください。ユーザーごとに同時に保持できるキーは 1 つだけです)
- サーバー URL をコピー:
https://<your-penpot-domain>/mcp/stream?userToken=YOUR_MCP_KEY - MCP クライアントの設定に追加 (以下のスニペットを参照)
- デザインファイルを開く → File → MCP Server → Connect
ローカル MCP (上級者向け。追加のファイルシステムアクセス)
npx @penpot/mcp@stable # keep running; matches current Penpot release
npx @penpot/mcp@beta # for beta/test environments
- プラグインをロード: Plugins → Load from URL →
http://localhost:4400/manifest.json - プラグイン UI で Connect to MCP server をクリック → プラグインウィンドウは常に開いたままにしてください
- クライアント URL:
http://localhost:4401/mcp(認証なし。単一クライアント構成に推奨) - SSE フォールバック:
http://localhost:4401/sse(/mcpトランスポートで競合が発生する場合、または stdio のみのクライアントでmcp-remoteを使う場合に使用)
クライアント設定スニペット
Claude Code — プロジェクトスコープの MCP サーバーはリポジトリルートの .mcp.json に置かれ、.claude/settings.json には置かれません (このファイルには enabledMcpjsonServers / enableAllProjectMcpServers しかなく、これらは .mcp.json で既に定義されているサーバーの信頼を切り替えるものです — このファイル自体が mcpServers ブロックを保持することは決してありません):
{
"mcpServers": {
"penpot": { "type": "http", "url": "REMOTE_OR_LOCAL_URL" }
}
}
または、ファイルを手で編集せずに登録できます:
claude mcp add --transport http penpot REMOTE_OR_LOCAL_URL
Cursor:
{ "mcpServers": { "penpot": { "url": "REMOTE_OR_LOCAL_URL", "type": "http" } } }
VS Code / Copilot (.vscode/mcp.json — VS Code はここでトップレベルの servers オブジェクトを期待しており、settings.json 内の mcp.servers という_設定_ではありません):
{
"servers": {
"penpot": { "type": "http", "url": "REMOTE_OR_LOCAL_URL" }
}
}
Codex / OpenCode:
{
"servers": {
"penpot": { "url": "REMOTE_OR_LOCAL_URL", "transport": { "type": "http" } }
}
}
Claude Desktop (stdio のみ — プロキシが必要):
npx -y mcp-remote http://localhost:4401/sse --allow-http
トラブルシューティングチェックリスト
- MCP サーバープロセスを再起動する
- プラグインを再接続する(File → MCP Server → Connect)
- MCP クライアントを再起動する/ツールを再読み込みする
Error: Already connected to a transport→ 他の MCP クライアントを閉じてください。/mcpが競合する場合は/sseをフォールバックとして使用してください- エージェントの実行中は常にプラグインウィンドウを開いたままにしてください
- Chromium が
https://design.penpot.appからlocalhostへのアクセスをブロックする場合は Firefox を推奨します - MCP キーの有効期限切れ → Penpot の → Integrations で再生成し、すべてのクライアント設定を更新してください
The Penpot plugin tab appears to be suspended by the browser (no heartbeat for Ns)(サーバー ≥ 2.18)→ プラグインが 30 秒間何も送信しないと、サーバーはタブをフリーズ状態とみなします。これは必ずしも バックグラウンドタブとは限りません: サーバーアップグレード後、ブラウザが古いプラグインコードを 配信し続けることがあり、そのコードはハートビートを一切送信しません。Penpot のサイトデータを消去し、 ハードリロードしてから、プラグインを再度開いて Connect を押してください。 サーバーログの確認:New WebSocket connection establishedの後に何も出力されない場合は、古い プラグインコードを示している可能性があります。特にアップグレード後はそうです。ただし、一時停止した バックグラウンドタブも同じパターンを生むため、これは手がかりとして扱い、証拠とはしないでください。- 2.18.0 以降、MCP キーは通常の Penpot API アクセストークンとして受け入れられなくなりました(セキュリティ 修正 #10960/#10962)。REST API を呼び出すインテグレーションには、独自のアクセストークンが必要です。
No Penpot instance connected for user token→ プラグインが接続されていない(パネルが閉じているか、 接続後に再び閉じられた)か、プラグインの MCP キーがクライアント URL のuserTokenと異なっています
2. 利用可能な MCP ツール
| ツール | モード | 説明 |
|---|---|---|
high_level_overview | 両方 | ファイル全体の構造、ページ、レイヤー、コンポーネントを読み取ります |
penpot_api_info | 両方 | Penpot プラグイン API のドキュメントを照会します |
execute_code | 両方 | Penpot プラグインコンテキストで JavaScript を実行します — 主要な読み書きツール |
export_shape | 両方 | シェイプを PNG/SVG としてエクスポートします(リモート: 制限あり、HTTP エラーで失敗する場合があります) |
import_image | ローカルのみ | ローカルファイルパスから画像をデザインにインポートします |
リモート MCP はローカルパスから画像をインポートできません。
export_shapeは HTTP エラーで失敗する場合があります — エクスポートの成功に頼るのではなく、常に API 経由で構造的に検証してください。
export_shape は mode: "shape"(デフォルト、子孫を含むシェイプ)または mode: "fill" を取ります。後者は
シェイプの塗りとして使用される元の画像をエクスポートします(PNG のみ)。
ツールの登録は条件付きです(サーバー 2.18)。 「両方」の 4 つのツールは常に登録されます。
import_image はサーバーがファイルシステムにアクセスできる場合にのみ存在するため、ローカルモードでのみ利用できます。
cljs_repl、cljs_compiler_output、clj_check_parentheses、import_penpot_file、
read_taiga_issue は開発者向けツールであり、開発環境でのみ登録され、マルチユーザーモードでは決して登録されません。
したがって、リモートチームサーバーが公開するツールはちょうど 4 つです。それ以外のツールを前提に作業を計画しないでください。
まず接続を確認する(常に)
セットアップ手順の前に、まず penpot_api_info または high_level_overview を呼び出してください。成功すれば、セットアップは完全にスキップしてください。
コミュニティプラグインのガードレール
- MCP がユーザーのインストール済みプラグイン一覧を読み取ったり、別のプラグインの UI/API を呼び出したりできると想定しないでください。
- 通常のデザイン、プロトタイピング、トークン、エクスポートのタスクでは、MCP ネイティブの読み取り/書き込みを優先してください。
- コミュニティプラグインが実質的に役立つ可能性がある場合は、まずファイルから確認できる証拠を探してください: 生成されたレイヤー、ライブラリアセット、コメント、名前空間付きの共有プラグインデータなどです。
- ユーザーがインストール済みプラグインの一覧を提供した場合は、ユーザー提供のコンテキストとして扱い、タスクがそのプラグインの公称機能に明確に対応する場合にのみプラグインを選択してください。
- コミュニティプラグインを使用または依存する前に、ユーザーの確認を求めてください。独自の UI がある場合は、ユーザーに手動で実行してもらい、その後ファイルを再確認してください。
- ユーザーが明示的にプラグインの閲覧、検索、発見、インストールを求めない限り、Plugins list のようなプラグインマーケットプレイス/ブラウザープラグインを決して使用しないでください。日常的なタスクのためにプラグインを自動で検索/インストールしないでください。
JavaScript API
execute_code は Penpot プラグイン API に対して JS を実行します。execute_code を呼び出す前に必ず references/penpot-api-patterns.md を読んでください。 トークン、ライブラリ作成、ページ管理、視覚効果、ストレージ、冪等性ヘルパーを含む完全な API を網羅しています。
3. 安全第一のワークフロー(常にこの順序に従ってください)
1. READ → Inspect, list, analyze (never skip)
2. PLAN → Describe intended changes BEFORE applying
3. WRITE → Small atomic batches; one logical unit per call
4. VERIFY → Structural read after each write batch (not export-based)
書き込み呼び出しの制限 — 厳守してください:
execute_code呼び出し 1 回あたり最大約 5〜10 個のシェイプ操作- バッチ間で一時停止して検証する
- 1 回の呼び出しで「すべてを構築する」ことは決してしないでください — MCP の書き込みは大きなバッチでタイムアウトし、エラーの表示もなく部分的な更新が残ります
ページ切り替え — 2 回呼び出しパターン(Penpot ≤ 2.16.x では必須、2.17+ では防御的な習慣):
Call N: penpot.openPage(page) ← switch page (currentPage still reports OLD page on ≤ 2.16)
Call N+1: any operation ← now on new page; currentPage updated
⚠️ Penpot ≤ 2.16.x のみ — 2.17.0 でアップストリーム修正済み(#10078): penpot.currentPage は openPage() の後の次のツール呼び出しまで更新されません。openPage() と同じ呼び出しでシェイプを書き込むと、以前にアクティブだったページに黙って適用されます。これはプラグインブリッジのバグであり、恒久的な API 契約ではありません。Penpot ≥ 2.17.0 では、currentPage は openPage() の直後に更新され、2 回呼び出しパターンは不要です — それでも無害な防御的習慣として維持してください。2.18.0 の型では openPage(page: Page | string): Promise<void> が宣言されており、その JSDoc の例では await penpot.openPage(page) を実行した後、同じ呼び出しで書き込みを行っています。ただし、情報源は一致していません: penpot/penpot-ai-kit でのライブプローブ(2026-08-10 付、修正後)では、依然として旧来の 2 回呼び出し動作が確認されました。ご利用のインスタンスでプローブされるまでは、呼び出しを await しかつ 2 回呼び出しパターンを維持してください。
remove() は呼び出しをまたぐと信頼できません — shape.remove() で削除されたボードは、その後の構造クエリ(getPages() → shapeStructure())で再び現れることがあります。削除は現在の呼び出しでは成功したように見えますが、ページ構造が再読み取りされると、以前のセッションの古いボードが再び現れることがあります。(2.18.0 までアップストリームの修正は公開されていません — クリーンアップはベストエフォートとして扱い、後の呼び出しで常に構造的に検証してください。)
書き込みの前に必ずページを検証してください: openPage() の後は、シェイプを作成する前に、常にまず軽量な読み取り専用の呼び出しを行ってください(例: penpot.currentPage?.name を返す)。
大規模なワークフローには storage を使用してください:
// Call 1: compute and store your design token data
storage.tokenData = { colors: { primary: '#HEX' }, spacing: 8, ... };
// Call 2+: retrieve from storage instead of recomputing
const fallback = { colors: {}, spacing: 8 }; // safe default if session reset
const DS = storage.tokenData || fallback;
スタータープロンプト(接続後は常に最初に実行してください):
"List all pages in this file."
"Show all components on this page."
"Analyze the design structure and summarize the token system."
4. ロールとプロンプトエンジニアリング
エージェントのロールを正確に定義する
BAD: "You are a creative designer."
GOOD: "You are a Senior Product Designer expert in design systems, WCAG accessibility,
Penpot plugin API constraints, and Penpot-to-code workflows. You do not make
product decisions without data. You never invent tokens, colors, or components
not present in the file. You always work in small reversible batches."
構造化ブリーフテンプレート
CONTEXT: [product name, target user, current state of file]
GOAL: [specific problem — e.g., "build design token system and foundations page"]
INPUTS: [page names, board names, component names, token paths, brand colors]
CONSTRAINTS:
- Max ~10 shape operations per execute_code call
- Always use idempotency helpers (ensureColor, ensureTypography, etc.)
- Never switch page and write in the same call
- Never invent font weights not confirmed installed for this family
- Verify structurally after each batch — do not rely on export_shape
- Store shared data in storage global for cross-call access
QUALITY CRITERIA: [how you'll know it's done]
ネガティブ(常に含めてください)
- 「トークンセットにない色をでっち上げないでください。」
- 「このフォントファミリーでインストール済みであることが確認されていないフォントウェイトを使用しないでください。」
- 「同じ execute_code 呼び出しでページを切り替えて書き込まないでください。」
- 「検証に export_shape に依存しないでください — 構造 API チェックを使用してください。」
- 「重複する色/タイポグラフィを作成しないでください — 作成前に必ず確認してください。」
イテレーションパターン
1. Discovery → read all pages, library assets, tokens, existing components
2. Proposal → describe planned structure, wait for approval
3. Foundation → build token sets + themes + colors + typographies (batched)
4. Structure → create pages (all in one call), then build boards per page (separate calls)
5. Components → register library components from source boards
6. Verify → structural checklist — count colors, typographies, components, token sets
5. トークン対応プロンプティング
グローバル RULESET ブロック(すべてのデザインシステムプロンプトの先頭に付加してください)
GLOBAL RULESET
- SOURCE: Penpot MCP only
- NO_GUESSING: true
- IF_MISSING: mark as TODO
- PREFER: structured data > prose
- OUTPUT: deterministic, stable ordering
- BATCH_LIMIT: ~10 ops per execute_code call
- PAGE_SWITCH: separate call from writes
- IDEMPOTENCY: always check-before-create
- STORAGE: use storage global for cross-call data
SIZE CONSTRAINTS
- design-system.json: tokens + mappings only
- components.catalog.json: real components only
- layout-and-rules.md: max ~300 lines
STYLE
- Use schemas, key:value, compact bullets
- No narrative explanations
トークン階層
Tier 1 (Global): color.base.neutral.100, spacing.base.8
Tier 2 (Semantic): color.bg.default, color.text.primary
Tier 3 (Component): color.button.primary.bg
参照トークンには他のトークンを指定できます: '{color.base.neutral.100}' — 波括弧構文を使用してください。
6. ワークフローレシピ
開始する前に、関連するリファレンスを読んでください:
- API 全体、トークン、ページ管理、ストレージ、視覚効果 →
references/penpot-api-patterns.md(execute_codeを呼び出す前に必ずお読みください) - デザインシステムの作成/監査 →
references/design-system-workflows.md - デザインからコードへの生成 →
references/design-to-code-workflows.md - プロトタイピング: フロー、インタラクション、アニメーション →
references/prototyping-workflows.md
クイックリファレンス: 一般的なタスクのプロンプト
ゼロからのデザインシステム:
"Read all existing pages, colors, typographies, and token sets in this file."
"Build the token system: create token sets [base, theme-light, theme-dark],
populate with [color palette] + spacing (8px grid) + border radii + motion tokens.
Use addToken idempotency. Store DS object in storage. Max 15 tokens per call."
"Create library colors from the base token set.
Use ensureColor pattern. 5 colors per call, pause after each batch."
"Create typographies for the scale: [paste scale].
Use ensureTypography. Check installed font variants first."
複数ページのデザインシステム:
"Create pages: [Page1], [Page2], [Page3] — all in one call (list all pages to create).
Then report the current page list before doing anything else."
"Switch to page [PageName]. Confirm currentPage before writing."
"Build the [BoardName] board on the current [PageName] page.
Max 8 shapes per call. Pause after."
プロトタイピングのタスク:
"List all boards on this page and their existing interactions."
"Create a prototype flow entry for '/flows/onboarding-start' using Page.createFlow."
"Add click→navigate interactions from [BoardA] to [BoardB] with Dissolve 300ms."
"Audit all interactions: list broken destinations and prototype coverage percentage."
視覚効果:
"Apply a backdrop blur effect to the [BoardName] overlay:
[N]px layer-blur, [N]px borderRadius, semi-transparent surface fill,
and a drop shadow. Describe the values you'll use before applying."
"Add linear gradient fill to [ShapeName]: brand primary → transparent, top to bottom."
7. デザインファイルのベストプラクティス
ファイルとページの構造
- ページ構成の戦略を 1 つ選んでください:
- ドメイン別: 例
Foundations、Mobile、Desktop - アトミックレベル別: 例
Tokens、Primitives、Components、Patterns
- ドメイン別: 例
- キャンバス: ワイヤーフレームを左 → 最終デザインを右
- すべてのボードには明確な目的と視覚的なエントリーポイントがあります
レイヤーの命名
- 機能ベース:
background、icon-close、label-primary✅ - 見た目ベースにしない:
rectangle-23、blue-box❌ /による階層:component/card/default、overlay/confirm-delete
コンポーネント
- 命名:
mobile/card/default、mobile/nav-bar createComponent([shapes])を使ってソースシェイプから登録する- ソースシェイプがすでにページ上に配置されている場合は、先にクローンを作成する
スペーシングとレイアウト
- 基本単位: 8px。すべてのマージン/パディングはこれから導出します。
- スペーシング用の不可視の矩形は使わない — Flex/Grid レイアウトを使用してください
視覚効果とグラスモーフィズム
- グラスのレシピ:
blurs: [{ type: 'layer-blur', value: 20 }]+borderRadius: 20+ シャドウ - シャドウの色:
{ color: '#hex', opacity: 0.06 }(r/g/b/a ではありません) - ゴーストボーダーはアクセシビリティ上、明確に必要な場合にのみ使用してください
プロトタイピング
- フローエントリーボード: プレフィックス
/flows/[journey]-start - オーバーレイボード: プレフィックス
overlay/ page.createFlow('name', entryBoard)または Prototype パネルでフローを作成する
アクセシビリティ
- すべてのテキストで WCAG AA コントラストを最低基準とする
- タッチターゲットは最小 44px(iOS)/ 48dp(Android)
- ステータスの伝達に色だけを使わないでください
引き継ぎの準備
- コンポーネント/変数の名前は開発者が読めるものにする
- 重複を作らない — 単一の信頼できる情報源とする
8. モデルの選定
- 常にフロンティアモデルを使用してください(Claude Sonnet/Opus、GPT-4o、Gemini Pro)
- 画像ベースのタスクには VLM が必須です
- より複雑なタスク → より強力なモデル
- トークンが制約されるワークフロー → §5 の RULESET ブロックを適用してください
9. 主な注意点
MCP/インフラストラクチャ:
| 注意点 | 対処法 |
|---|---|
| MCP はフォーカスされているページにのみ作用します | 各書き込みバッチの前にページのフォーカスを確認してください |
| 書き込み操作は即時です — MCP 経由の取り消しはできません | 適用する前に計画し、説明してください |
| 大きなバッチはサイレントにタイムアウトします | 1 回の呼び出しあたり最大約 10 操作まで。各操作後に確認してください |
| ページ切り替えは非同期です | 同じ呼び出しでページを切り替えて書き込みを行わないでください |
export_shape は HTTP エラーで失敗することがあります | API 経由で構造的に検証してください。エクスポートはベストエフォートです |
| リモート MCP はローカルファイルシステムを読み取れません | import_image にはローカル MCP を使用してください |
| アクティブな MCP タブは 1 つだけです | エージェントを実行する前に他の Penpot タブを閉じてください |
Error: Already connected to a transport | 他の MCP クライアントを閉じてください。/mcp が競合する場合は /sse をフォールバックとして使用してください |
| MCP キーは一度しか表示されません | すぐにコピーしてください。紛失した場合は再生成してください |
| 30 秒間ハートビートがない = 「タブが一時停止」(≥ 2.18) | トラブルシューティングを参照してください。アップグレード後の古いプラグインコードは、フリーズしたタブと同じように見えます |
| 2.18 へのアップグレード後のエクスポートは 2.17 と異なることがあります | セルフホストインスタンスを 2.18.0 にアップグレードした後の export_shape 出力で確認されています。ボードの子要素の上に内側シャドウが描画され (アクティブなナビ項目が空でレンダリングされ)、auto-width テキストが古い幅でクリップされました。デザインのせいにする前にキャンバスを確認してください |
| 期限切れのキーはすべての接続をブロックします | Integrations で再生成してください。すべての設定を更新してください |
| Chromium ≥142 は localhost をブロックします | Firefox を使用するか、ローカルネットワークを明示的に許可してください |
Penpot プラグイン API (詳細 → references/penpot-api-patterns.md):
| 注意点 | 対処法 |
|---|---|
shape.width / shape.height は読み取り専用 | shape.resize(w, h) を使用します |
親を持つシェイプでは shape.x / shape.y は読み取り専用 | penpotUtils.setParentXY(shape, x, y) を使用します |
ルートレベルのボードでは shape.x / shape.y | ✅ 直接代入が機能します |
appendChild は z オーダーを無視する | insertChild(index, shape) を使用します |
| 列方向では Flex の子要素が逆順になる | 最後に挿入したものが視覚的に最上位になります |
penpot.createText(...) は null を返すことがある | resize/style の呼び出し前にガードし、利用できない場合は明確なエラーを返します |
resize() の後にテキストがクリップされる | text.resize() のたびに必ず growType をリセットします |
| フォントウェイトが拒否される | そのフォントファミリーに明示的にインストールされているウェイトのみを使用します |
ライブラリの fontSize は文字列でなければならない | 16 ではなく "16" です。ライブラリのタイポグラフィは fontFamily ではなく fontFamilies を使用します |
16 進数には LibraryColor.color を使用 | .fillColor ではなく .color = '#hex' です |
shape.blurs は配列である | shape.blurs = [{ type: 'layer-blur', value: 20 }] |
| シャドウの色の形式 | {r,g,b,a} ではなく { color: '#hex', opacity: 0.15 } です |
タイポグラフィの fontId が古いままになる | 既知の API 制限です。レンダリングされたレイヤーは正しい ID を使用します |
storage はサーバー再起動時にリセットされる | 読み取り時には必ずフォールバック値を使用します |
Page.findShapes() は条件オブジェクトを受け取る | 述語ではなく page.findShapes({ type: 'board' }) です |
createComponent は配列をラップする | createComponent(shape) ではなく createComponent([shape]) です |
penpot.fonts.findByName は部分文字列で一致する(penpot-ai-kit、ここでは未検証) | "Roboto" が "Roboto Mono" を返すことがあります。penpot.fonts.all を完全一致の name でフィルタリングします |
layoutChild.horizontalSizing = "fill" は flipX = true を設定することがある(penpot-ai-kit、ここでは未検証) | サイズ変更後に flipX を読み戻してリセットします |
| バリアントグループには厳密な複数ステップの順序が必要 | penpotUtils.createVariantContainer([{ shape, properties: { Size: 'S' } }, …]) を使用します。インスタンスでは instance.switchVariant(pos, value) で切り替えます |