Figma Bridge
Figmaには公開された書き込みAPIがありません。このスキルはローカルブリッジを使用します。名前付き操作をHTTP経由でプラグインに送り、Figma Plugin APIを介してFigma内部で実行します。OAuthもトークンも不要です。
リポジトリ: https://github.com/iggypcnfsky/figma-bridge — AGENTS.md、docs/ops-reference.md
前提条件 — 他の何よりも先に確認すること
figma が PATH に含まれているため、リポジトリをファイルシステムから検索してはいけません:
figma doctor # リポジトリ、サーバー、接続済みウィンドウ、img-forge + FALキーを一発で確認
figma clients # 接続中の各FigmaウィンドウのID、ファイル、ページを表示
figma rules # プロジェクト制約: タイプ階層、グリッド、フレームサイズ、バージョン命名規則
設計前に figma rules を読むこと。 これには「Poppins 20/25が最小」といった、キャンバスを見ただけではわからない非自明な制限が書かれています。"confirmed": false は仮定としてユーザーに確認する必要があることを意味し、{} は「ユーザーに尋ねよ、勝手に決めるな」を意味します。
コマンドがない場合は、node "$(figma where)/server.mjs" を尋ねた後にのみ使用してください。リポジトリを find したり、パスを推測したりしてはいけません。
pluginConnected: false→ 停止。ユーザーに、操作対象のファイルのウィンドウでPlugins → Development → Figma Bridgeを実行するよう依頼してください。リトライしても解決しません。/runからの503も同じ意味です。504 PLUGIN_GONEはプラグインウィンドウが閉じられたことを意味します。409は複数のFigmaウィンドウが接続されており、どれも選択されていないことを意味します。ユーザーが指定したファイル(--file <NAME>)またはクライアントID(--client <ID>)を選んでください。決して無闇にリトライしないでください。間違ったファイルを編集する恐れがあります。
ループ
- 状況把握.
./bin/figma status→ ファイル名、現在のページ、選択範囲、全ページ。 - 読み取り.
selection 2、node <id> 2、find {"name":"Header","allPages":true}。nodeIdを推測してはいけません — FigmaのIDは4022:2のようになっており、導出できません。 - 計画. 親、サイズ、順序を決定。新しいノードは
parentIdが指定されない限り現在のページに追加されます。 - 書き込み.
./bin/figma run '[{...},{...}]'。 - 検証.
./bin/figma export <id> out/check.png PNG 2を実行し、実際に画像を確認すること。
コマンド
./bin/figma op '{"op":"status"}'
./bin/figma run '[{"op":"createFrame","name":"Card","width":320,"height":200,"fill":"#0B0B0F",
"props":{"cornerRadius":16,"layoutMode":"VERTICAL","paddingTop":24,"paddingLeft":24,"itemSpacing":12}}]'
./bin/figma run '[{"op":"createText","parentId":"12:34","characters":"Title","fontSize":24,"color":"#FFFFFF"}]'
./bin/figma op '{"op":"varFill","nodeId":"12:34","variableName":"color/bg/surface"}'
./bin/figma export 12:34 out/card.png PNG 2
./bin/figma image 12:34 out/cover.png FILL # ローカル画像ファイル → 塗りつぶし(クラウドアップロード不要)
操作一覧: ping status pages variables styles fonts inventory · selection node find · createFrame createRect createEllipse createText createPage createInstance · update clone reparent remove goto group ungroup select · grids setGrids align distribute effects · applyStyle varFill · export imageFill · exec。
完全なパラメータ: docs/ops-reference.md。
知っておくと便利なデザインワークのショートカット:
- grid は GRID を意味する: ユーザーが「グリッドを設定して」と言った場合、列ではなく正方形のレイアウトグリッドを意味します:
{"op":"setGrids","nodeId":"…","grid":true}(デフォルトで40pxセル、40%)または"grid":40。columns/rowsは、ユーザーが列、12カラムグリッド、またはガター/マージンの値を指定した場合にのみ使用します。 グリッドを矩形で偽装してはいけません。applyStyleでkind:"grid"を使用すると保存済みのグリッドスタイルを適用できます。 - アイテムの行: アイテムを作成したら、
{"op":"align","nodeIds":[…],"mode":"TOP"}と{"op":"distribute","nodeIds":[…],"axis":"HORIZONTAL","gap":24}を使用します。 - 奥行き:
{"op":"effects","nodeId":"…","shadow":{"y":8,"blur":24,"color":"#00000033"}}または{"op":"effects","nodeId":"…","blur":{"type":"BACKGROUND","radius":20}}を使用します。 - グラデーション:
{"op":"gradient","nodeId":"…","kind":"linear","angle":135,"stops":[[0,"#8B76FF"],[1,"#0E0E12"]]}— 角度0は左→右、90は上→下。グラデーションを矩形の重ねで偽装してはいけません。 - デザインシステム:
COMPONENTID でcreateInstanceを使用し、instancePropsでバリアント(事前に名前を読むこと)を、instanceTextでテキストを変更(デタッチせずに)。applyStyleでスタイルを適用。ライブラリに既にあるものを再描画せず、インスタンスをデタッチしてテキストを「修正」しないこと。 - スペーシングチェック:
{"op":"measure","a":"1:2","b":"1:3"}は辺ごとのギャップと中心間距離を返します。配置を判断するためにスクリーンショットをエクスポートする代わりにこれを使用してください。 - スタイル:
saveStyleでtext/paint/effect/gridスタイルを名前で作成/更新し、applyStyleで適用。トークンを一度作成して、どこにでも適用します。 - レスポンシブ:
sizingで軸ごとにHUG/FILL/FIXEDと min/max を設定。constraintsはオートレイアウトではない子要素(STRETCH/MIN/MAX/CENTER/SCALE)をカバー。変更する前にnodeから両方を読み取ること。sizingはプロパティが適用されない場合、Figmoの理由とともにskippedを返します。
画像
アートワークが必要? 同梱の img-forge CLI(https://github.com/iggypcnfsky/img-forge)で生成してから配置します。生成はFigmaの外で行われるため、APIキーがプラグインコードに入らず、遅いレンダリングがキャンバスをブロックしません:
cd ../img-forge
./img gen --prompt "abstract gradient cover, purple to black" --preset 16:9@2k --out out/cover.png
./img edit --prompt "make it night with neon accents" --ref out/cover.png # 既存アセットの編集
cd ../figma-bridge
./bin/figma image 12:34 ../img-forge/out/cover.png FILL
FILL はノードに合わせてクロップ、FIT はレターボックス、TILE は繰り返し、CROP は既存のクロップを尊重します。ユーザーが選択したものを編集するには、まずエクスポート(./bin/figma export <nodeId> out/sel.png PNG 2)し、そのファイルを --ref として渡します。
プラグインウィンドウには、人間向けの Generate / Edit パネル(モデル、サイズプリセット、コスト、挿入)もあります。プログラムからパネルを操作しないでください — CLIを使用してください。CLIはより多くの機能(マスク、バリアント、ドライラン)を公開しています。そのパネルに保存されたプリセットは figma-bridge/presets.json に保存されます。
既存のドラフト上での構築
「完成していない」ドラフトでも、何が何の隣にあるか、何がグループ化されているか、要素の順序、スペーシングのリズムといった決定がコード化されています。設計前にそれを読み取り、維持してください。
{"op":"inventory"}— フレーム、そのサイズ、タイポグラフィ統計。{"op":"structure","nodeId":"<frame>"}— 子要素がギャップとreadingOrderで行にグループ化されたもの。これが作者が選んだグループ化です。{"op":"node",…,"depth":2}はより深い同じツリーを返します。- パターン(繰り返される左マージン、常に3列の上にあるタイトルなど)に注目し、それを維持します。リクエストが必要とするものだけを変更し、残りはそのままにします。
- 行った変更を報告します — 「レイアウトを改善しました」ではなく「フッターを40px上に移動しました」のように。
ドラフトを黙って正規化してはいけません。一貫性を保つためにユーザーが配置したものを動かす必要がある場合は、その旨を伝えて尋ねてください。ユーザーのグループ化を失った見た目だけきれいなスライドは、改善ではなく退行です。
ルール
- 書き込む前に読め。 最低2回の呼び出し: 検査してから変更。
- 1バッチ = 1つの思考。 ある操作は前の操作の結果を参照できないため、新しいノードの
idが必要な場合は2回の呼び出しに分割すること。 - 引き継いだ配置を尊重する: 兄弟の順序、近接性、グループ化は意図です。依頼がない限り、見た目を整えるためにドラフトを再構成しないでください。一貫性を保つためにユーザーの要素を動かす必要がある場合は、まず尋ねてください。
- 明示的な指示なしに既存のユーザーレイヤーに触れてはいけない(
update、remove、reparent)。自分の作成物にはBridge / …のプレフィックスを付けること。 - やり直しはオリジナルのすぐ隣に、可能な限り近くに配置する。 スライド/画面/セクションのやり直しを依頼された場合: それを複製し、
{"op":"placeNear","nodeId":"<new id>","move":true,"gap":80,"name":"Bridge / v2 — <name>"}を呼び出して、コピーが推測された座標ではなく最初の空いている側に配置されるようにします。オリジナルには触れないでください。ツールがfree: falseを報告した場合は、どこに配置するか尋ねてください。要素をその場で置き換えるのは、ユーザーが明示的に依頼した場合のみです。 gotoはユーザーのビューを変更する — リクエストがあった場合のみ使用。execは最後の手段。 動作します(Figmaのサンドボックスはnew Functionを許可)が、すべてのパラメータ検証をバイパスします。JSONシリアライズ可能な値のみを返すこと。- テストアーティファクトをクリーンアップする か、保持するかユーザーに尋ねること。
落とし穴
localhostを使用し、決して127.0.0.1を使用しないでください: プラグインマニフェストはhttp://localhost:3847のみを許可リストに含めています(devAllowedDomains)。FigmaはIPを拒否します。サーバーは127.0.0.1と::1の両方でリッスンします。figma.currentPageはそのFigmaウィンドウで開いているページであり、保存されたポインターではありません。タブを切り替えると、次の呼び出しで見えるものが変わります。- 位置は親に対する相対位置であり、
parentIdを省略すると 現在のページ を意味します。 - タイポグラフィに関する質問(フォント、サイズ、カウント)は1回の呼び出し:
{"op":"fonts"}。ファイル全体の場合は"allPages":trueを追加。独自のスクリプトでフレームを走査しないでください。 - スライドデッキの概要も1回の呼び出し:
{"op":"inventory"}はすべてのフレームをジオメトリ、minFontSize、フォント、グリッド数、塗りつぶしとともに返します。「フレーム11–19」を選択したり、最小サイズ以下のテキストを見つけたりするのに十分です。 - リファレンスにリストされていないフィールドにインデックスを付けないでください。
summaryはTEXTに対してfont、fontSize、lineHeight、letterSpacingを持ちます。それ以外はすべて、実際のAPI名でexecから取得します。混合スタイルは文字列"MIXED"になるため、.get()とフォールバックでガードしてください。 - 矩形は子を持つことができません。テキストやアイコンをシェイプの中に配置する必要がある場合は、フレームを使用してください。
- ローカル変数がない場合 →
variablesはcollections: []を返し、varFillは失敗します。最初に確認すること。 - テキストにはフォントが必要:
createTextはloadFontAsyncでフォントを読み込みます。ファミリが見つからない場合はInterを使用してください。 exportは8 MBで制限 — リトライする代わりにscaleを下げてください。- 現在のページではないページの子を読むには
loadAllPagesAsyncが必要です。ブリッジは自動で1回リトライしますが、allPages: trueを指定したfindを優先してください。 - プラグインファイル(
code.js、ui.html)を編集した後、ユーザーはプラグインを再実行する必要があります。manifest.jsonの変更は再インポートが必要です。