Claude Media
Claude CodeでFigmaプラグインを開発する手順

Claude CodeでFigmaプラグインを開発する手順

Figma Plugin APIをClaude Codeで実装する手順を、manifest.jsonの設定からUI構築、サンドボックスの制約まで扱います。

Claude CodeでFigmaプラグインを作る流れは、Figmaデスクトップアプリで雛形を作り、Claude Codeで実装して、Figmaで実行して確かめる往復です。雛形づくりと実行はFigma側の操作で、manifest.jsonの設定・TypeScriptのロジック・HTMLのUIはClaude Code側で進めます。

既存のデザインをコードにしたいだけなら、プラグインは作らずにFigma MCPサーバーの使い方の方法が合います。以下は、プラグインを自作する場合の手順と、Claude Codeが外しやすい制約です。

Figmaプラグインとは何をするものか

Figmaプラグインとは、Figmaのエディタ内で動作し、ファイルの内容を読み書きするプログラムです。ロジックはJavaScript、UIはHTMLで書きます。Plugin APIはfigmaというグローバルオブジェクトを通じて公開され、レイヤー(ノード)の色・位置・階層・テキストといったプロパティを操作できます。

対応エディタはFigma Design・FigJam・Dev Mode・Figma Slides・Figma Buzzの5種類で、manifest.jsonのeditorTypeフィールドで指定します。

ユーザーが同時に実行できるプラグインとアクションは1つだけで、バックグラウンドで動き続けるプラグインは作れません。処理が終わったらfigma.closePlugin()を必ず呼び、Figma側に終了を伝えます。

開発に必要な前提知識と環境

Figmaプラグインの開発にはJavaScriptとHTMLの基礎知識が必須で、公式はTypeScriptとVisual Studio Codeの組み合わせを推奨環境としています。

  • Figmaデスクトップアプリ: プラグイン開発とテストはデスクトップアプリでのローカルファイル読み込みが前提です。ブラウザ版だけでは開発フローが完結しません。
  • Node.jsとnpm: TypeScriptや@figma/plugin-typings、ESLint設定などの依存関係をインストールするために使います。
  • Visual Studio Code(または任意のエディタ): 公式のクイックスタートはVS Codeが前提です。ただしJavaScript、またはJavaScriptに変換できる言語なら、好みのエディタで書けます。

この環境が整った状態でClaude Codeを使うと、プラグインのプロジェクトフォルダを直接編集し、npm installやtscのビルドコマンドをターミナル越しに実行できます。コードの修正とビルドを1か所で完結させられるのが実務上のメリットです。

雛形づくりから最初の実行まで

Figmaのメニュー操作はClaude Codeからできないので、手順は人の操作とClaude Codeの操作が交互に並びます。

手順

雛形から最初の実行までの流れ

  1. 1

    [Figma] 雛形を作る

    デスクトップアプリで新規デザインファイルを開き、Plugins > Development > New pluginからFigma designを選んで名前を付けます。続けてCustom UIを選び、Save asで保存先を決めます。

  2. 2

    [Claude Code] 作業ディレクトリとして開く

    保存されたフォルダでclaudeを起動します。manifest.jsonとpackage.jsonが入っていることを最初に見せておくと、以降の修正が手早く進みます。

  3. 3

    [Claude Code] 依存関係を入れる

    npm installを実行させます。型定義とリンターが入り、Claude CodeがAPIのメソッド名や引数を型から確かめながら書けるようになります。

  4. 4

    [Claude Code] manifest.jsonを要件に合わせる

    networkAccess・editorType・documentAccessなどを、作りたい機能に合わせて編集させます。

  5. 5

    [Claude Code] ロジックとUIを実装する

    TypeScriptのコードとHTMLのUIを書かせ、ビルドをウォッチモードで回しながら反復します。

  6. 6

    [Figma] 実行して結果を伝える

    Plugins > Developmentからプラグイン名を選んで実行し、挙動をClaude Codeに伝えます。

作業フォルダで起動するコマンドと依存関係のインストールは次のとおりです。

cd my-figma-plugin
claude
npm install

npm installでtypescript・@figma/plugin-typings・@figma/eslint-plugin-figma-pluginsなどがpackage.jsonのdevDependenciesから入ります。

TypeScriptのビルドは、VS CodeならCtrl+Shift+B(MacはCommand+Shift+B)からwatch-tsconfig.jsonを選ぶとウォッチモードで動きます。VS Codeを閉じたり開き直したりするたびにこの操作が必要です。VS Codeのタスクを使わない場合は、ターミナルでtscをウォッチモードで起動します。

初回の動作確認は、クイックスタートの雛形で行えます。プラグインを実行してCreateを押すと、キャンバスに5つのオレンジの長方形ができます。ここまで通れば環境は整っています。

Figmaにはホットリロードの設定もあり、有効にするとコードを編集してビルドし直すたびにプラグインが最新の内容で再起動します。無効のままだと手動で再起動する必要があるので、Claude Codeに修正させる往復が多いときは有効にしておくと楽です。

プロジェクト外のフォルダを参照させる

デザイントークンの定義など、プラグインのフォルダの外にあるファイルを読ませたいときは、--add-dirで作業対象を広げます。claude --helpでは、このオプションは--add-dir <directories...>(ツールのアクセスを許可する追加ディレクトリ)と表示されます。

claude --add-dir ../design-tokens

Claude Codeに最初に渡す制約メモ

Plugin APIには、一般的なブラウザ向けコードの感覚で書くと外す制約があります。作業フォルダのCLAUDE.mdに最初から書いておくと、同じ指摘を何度も繰り返さずに済みます。次の例は、このあと各節で説明する制約を短くまとめたものです。

# Figmaプラグインの制約
- main thread(manifest.jsonのmainが指すコード)では fetch / XMLHttpRequest / setTimeout / DOM を使わない
- ネットワーク処理とDOM操作は figma.showUI で開く iframe 側(ui.html)に書く
- UIからの送信は parent.postMessage({ pluginMessage: ... }, "*") の形にする
- 処理が終わったら figma.closePlugin() を必ず呼ぶ
- manifest.jsonの id は書き換えない。documentAccess は "dynamic-page" にする

manifest.jsonの主要フィールド

プラグインの挙動はmanifest.jsonで宣言します。新規作成時にFigmaが最小限の雛形を自動生成しますが、公開まで進めるなら次のフィールドを把握しておく必要があります。

フィールド型役割
name型string役割メニューに表示されるプラグイン名
id型string役割更新の公開先になるプラグインID(Figmaが割り当て)
api型string役割対象とするPlugin APIのバージョン
main型string役割プラグインロジック(JS)へのパス
ui型stringまたはmap役割UI用HTMLへのパス(単一ならfigma.showUI(__html__)で参照)
editorType型string[]役割対応エディタ(figma/figjam/dev/slides/buzz)
documentAccess型"dynamic-page"役割ページの動的読み込みに対応することを示す、新規プラグインでは必須のフィールド
networkAccess型object役割プラグインがアクセスできるドメインの許可リスト

公式ドキュメントが示す最小構成の例は次のとおりです。

{
  "name": "MyPlugin",
  "id": "737805260747778092",
  "api": "1.0.0",
  "editorType": ["figma", "figjam"],
  "main": "code.js",
  "ui": "ui.html",
  "documentAccess": "dynamic-page",
  "networkAccess": { "allowedDomains": ["none"] }
}

editorTypeは複数並べられますが、["figjam", "dev"]の組み合わせはサポート外です。Claude Codeに複数エディタ対応を頼むときは、この組み合わせを避けるよう伝えます。

idはFigmaが割り当てる値で、「New plugin」の作成時に新しいmanifestとともに発行されます。公開の時点で新しいIDを取得することもできます。手で書き換えると更新の公開先が変わるため、AIに任せる編集の対象から外しておくと安全です。

documentAccessを省略すると、ファイルを開いて最初にプラグインを実行したときに全ページを読み込もうとし、「Loading n pages for plugin…」という通知がユーザーに表示されます。

networkAccessの書き方

allowedDomainsは["none"](外部通信なし)から["*"](全ドメイン許可)まで指定できます。["*"]のほか、ローカルや開発用サーバーをallowedDomainsに含めるときは、理由を書くreasoningフィールドが必須です。

開発中だけローカルサーバーに接続したい場合は、devAllowedDomainsにhttp://localhost:3000のように書きます。公開用のallowedDomainsに開発サーバーを混ぜずに済みます。

パターンの末尾のスラッシュも挙動を分けます。www.example.com/images/はそのパス配下の複数のリソースを許可し、スラッシュなしのapi.example.com/rest/getはそれより深いパスへのアクセスを止めます。REST APIの特定のエンドポイントだけに絞りたいときは、スラッシュなしの書き方が使えます。

手の込んだ構成で使うフィールド

  • uiにmapを指定すると、複数のHTMLファイルを__uiFiles__から参照できます
  • buildは、mainとuiを読み込む前に実行するシェルコマンドを指定する実験的なフィールドで、TypeScriptのコンパイルやWebpackの実行に使えます。コマンドはmanifestのあるディレクトリで実行されます
  • parametersは、クイックアクションのメニューから入力を受け取る仕組みです。公式は、パラメーターを使うと多くの場合カスタムUIを作らずに済むと案内しています
  • menuとfigma.commandを組み合わせると、1つのプラグインに複数のコマンドを持たせられます

UIを構築する — showUIとpostMessage

UIは1枚のHTMLで始められます(複数ファイルはmapで指定します)。figma.showUI(__html__)を呼ぶと、Figma内の<iframe>にそのHTMLの内容が表示されます。プラグイン本体(main threadのコード)とUI(iframe内)は別の実行環境なので、postMessageによるメッセージパッシングでやり取りします。

UIからプラグイン本体へ送る場合、HTML側は次のように書きます。

<script>
  parent.postMessage({ pluginMessage: "anything here" }, "*")
</script>

プラグイン本体側で受け取るには次のように書きます。

figma.ui.onmessage = (message) => {
  console.log("got this from the UI", message)
}

逆方向(プラグイン本体からUIへ)は次のように送ります。

figma.ui.postMessage(42)

UI側で受け取るには次のように書きます。

<script>
  onmessage = (event) => {
    console.log("got this from the plugin code", event.data.pluginMessage)
  }
</script>

プラグイン本体では送る値をそのまま渡しますが、UI側ではpluginMessageプロパティに包み、postMessageの第2引数に"*"を付けます。受け取るときも値はevent.data.pluginMessageに入ります。この非対称は書き間違えやすい点なので、生成されたコードがどちらの形になっているかを見てください。

送れるのは、オブジェクト・配列・数値・文字列・真偽値・null・undefined・Date・Uint8Arrayです。メソッドやプロトタイプチェーンは復元されません。BlobやArrayBuffer、Uint8Array以外のTypedArrayは送れません。figma.showUI()を呼んだ直後からプラグイン本体のメッセージを送れ、iframeの読み込みが終わるまではキューに積まれます。

ライト/ダークテーマへの追従には、figma.showUI()のthemeColorsオプションと、それが提供するCSS変数をUI側で使います。公式が強く推奨している書き方です。

実行環境の制約 — サンドボックスとiframe

役割分担は次のとおりです。

くらべる

どちらで何を書くか

Figmaのデータ担当

main thread

サンドボックス化されたJavaScript環境で動き、レイヤーの階層(シーン)にアクセスできます。ES2020以降の言語機能(async/await・オプショナルチェイニング・BigIntなど)も使えます。fetch・XMLHttpRequest・setTimeout・DOM操作は使えません。

ブラウザAPI担当

iframe(UI)

figma.showUI()で作る<iframe>の中で動きます。HTML/JavaScriptを自由に書け、ネットワーク通信などのブラウザAPIを使えます。Figmaのシーンにはアクセスできません。

両者のやり取りはメッセージパッシングだけです。外部APIの結果でレイヤーを作る処理なら、iframeでfetchした結果をpostMessageでmain threadに渡し、受け取った側がレイヤーを作ります。

main threadで使えるAPIの一覧を確かめたいときは、プラグインの最初の1行にconsole.log(this)を置いて実行します。Claude Codeが「このAPIは使えるか」で迷ったときは、この出力を貼って判断させられます。

networkAccessでドメインを制限している場合、許可リストに無いドメインへのアクセスはCSPエラーとしてブロックされます。制限が及ぶのはプラグイン自身のリクエストだけです。プラグインがiframeでWebサイトを表示する場合、制限はそのサイトのドメインにだけ掛かり、サイトが読み込む外部リソースには及びません。

ユーザーはプラグインの実行中いつでも取り消せます。そのときはFigma自身がfigma.closePlugin()を呼びます。プラグイン側が呼び忘れると、「Running[プラグイン名]」というトースト通知が出続けます。

公開前に知っておく制約

Figmaはプラグインの利用状況やエラー・クラッシュのレポートを提供していません。利用状況を把握したい場合は、自前の分析基盤や監視サービスを組み込みます。Figma Communityでの反応は、開発者に週1回の通知で届きます。

サポート窓口もプラグイン開発者が自分で用意する仕組みです。審査申請の際に、メールアドレスか、WebサイトまたはヘルプセンターのURLを連絡先として登録します。

公開後のアップデートは、Figmaの承認を一度通れば、再審査なしですぐ反映されます。更新時には変更内容をバージョン履歴に書け、データの扱いが変わったときはセキュリティの開示フォームも更新できます。ユーザー側から旧バージョンへ戻す手段は無く、取り消したい場合は開発者自身が古いバージョンを再公開します。

審査に出す前には、想定外の状態でプラグインがどう振る舞うかも洗い出します。公式のチェックリストの観点は次のとおりです。

  • 選択なし・想定外のノード・複数選択・コンポーネントを選択した状態での挙動(コンポーネントの変更は数百のインスタンスに波及しうる)
  • テキストレイヤーのフォントが見つからない場合の挙動
  • コンポーネントがチームライブラリ由来の場合の挙動
  • ネットワークがオフラインのときの挙動
  • プラグインを開いたままにしたとき、参照中のノードが削除された場合や、マルチプレイヤーの変更が入った場合の挙動
  • レイヤーが回転している場合の位置計算
  • ファイルが非常に大きい場合の読み込み範囲(必要なページだけ読み込む方法がないか)

バンドラーを使っている場合は、出力サイズをリリースモードのビルドで確認することも挙げられています。

よくあるつまずき

  • documentAccess: "dynamic-page"を書き忘れると、複数ページのファイルで最初の実行時に全ページ読み込みが走り、体感速度が落ちます
  • fetchをmain thread側で直接呼んでエラーになります。ネットワーク処理はUIのiframe側に書きます
  • networkAccessのallowedDomainsにアクセス先を登録し忘れ、CSPエラーで通信がブロックされます
  • figma.closePlugin()を呼び忘れ、「Running」通知が消えないまま残ります
  • UIからのメッセージをpluginMessageで包み忘れ、プラグイン本体で値を受け取れません
  • 選択中のノードの種類を決め打ちで実装すると、何も選択していない場合や、想定外の種類のノードを選択している場合にエラーになります

自作プラグイン以外にもFigmaとClaudeを繋ぐ方法はあります。デザインからコードを生成したいだけならFigma MCPサーバーの使い方が近道です。Cowork経由でコードとデザインを往復させる運用はCowork Figma連携でコードとデザインを往復させる手順にまとめています。Claude DesignとFigmaの役割分担が気になる場合はClaude DesignとFigmaの違いを確認してください。

まとめ

Figmaプラグインは、Figmaデスクトップアプリでの雛形作成と実行確認、Claude Codeでのコード編集を往復して作ります。Claude Codeに渡す最初の指示は、main threadではfetchもDOMも使えず、通信はiframeに寄せるという分担です。同じ設計判断はChrome拡張(Manifest V3)のservice worker分離にも共通しており、Claude CodeでChrome拡張を開発する手順で扱っています。

参照した一次ソース

この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。

  1. developers.figma.com/docs/plugins
  2. developers.figma.com/docs/plugins/plugin-quickstart-guide
  3. developers.figma.com/docs/plugins/manifest
  4. developers.figma.com/docs/plugins/creating-ui
  5. developers.figma.com/docs/plugins/how-plugins-run
  6. developers.figma.com/docs/plugins/prerequisites
  7. developers.figma.com/docs/plugins/publishing
この記事を共有:XはてブLinkedIn