こんにちは。アイレット株式会社デザイン事業部の上瀧です。
今回はFigmaのプラグイン作成に初めて触れてみたため、簡単な手順と所感について記していきます。
Figmaプラグイン開発の概要
Figmaプラグイン開発には、HTML/JavaScriptのウェブベースの技術を使用します。
ローカル環境でFigmaデスクトップアプリを起動しながら開発を進めることが可能で、提供されているPlugin APIを操作します。
完成したら審査を経てコミュニティへ公開し、他のユーザーに使ってもらうことも可能です。
環境を作って動かしてみる
まずテンプレートを用いて環境を作ってみたいと思います。
プラグインの新規作成

新規ファイルを開き、メニューバーの「プラグイン」>「開発」>「プラグインの新規作成」をクリックします。

プラグイン名を入力し、テンプレートの種類を選択します。
今回は「カスタムUI」を選択しました。

ローカル環境のプロジェクトコード配置場所を選択します。

プラグインのパネルにも追加されました。
これで環境の下準備は完了です。
npmパッケージのインストール
Figmaアプリでプラグインを動作させるために、コードをコンパイルします。
$ cd path/plugin-sample $ npm install -D typescript @figma/plugin-typings
まず、ターミナルでTypeScriptのFigma型定義ファイルをインストールします。
$ npm run watch
次にwatchコマンドを実行してコンパイルとファイルを監視状態にしておきます。
Figmaアプリで動作確認

Figmaアプリのプラグインパネルから、作成したプラグイン名をクリックします。

プラグインテンプレートの「Rectangle Creator」のパネルが表示されます。
「Create」をクリックします。

パネルで指定した個数の正方形オブジェクトが生成されました。
最低限覚えたほうが良いこと
以上はテンプレートを動かしたのみですが、以降オリジナルのプラグインを開発するにあたり、最低限覚えたほうが良いことを挙げていきます。
テンプレートの種類
先ほど選んだ「カスタムUI」の他に「デフォルト」「1回実行する」があります。
「デフォルト」は中身が空白のテンプレートですが「1回実行する」はユーザーから値のインプットなしで実行される種類のプラグイン作成の際に利用できます。
ファイル構成
テンプレートプラグインのファイル構成について簡単に説明します。
| ファイル名 | 説明 |
|---|---|
| manifest.json | メタ情報を記載するファイル |
| code.ts | Plugin APIを操作・処理するファイル |
| code.js | code.tsコンパイル後のファイル |
| ui.html | 主にFigmaアプリに表示されるUI用のファイル |
この中ではcode.tsとui.htmlを主に編集しながら開発を進めていきます。
Figmaアプリ上で検証ツールも使えますのでデバッグも可能です。
処理とUIの関係性
特に初見の場合、難しく感じたのが処理側(code.ts)とUI側(ui.html)の関係性や役割の違いです。

How Plugins Run | Plugin API より引用
いずれかが処理を送る/受け取るの関係性ではなく、ともに送る/受け取ることが可能です。
postMessage で送信/ onmessage で受信します。
ただ処理側(code.ts)からFigmaのレイヤー階層にはアクセスできますが、UI側(ui.html)からはアクセスできない、などの仕組みになっています。
テンプレートを書き換えてみる
最後に簡単にテンプレートの中身を書き換えてみたいと思います。
ベースの構成は変えていませんが、星のオブジェクトに連番を付けるように変更してみました。
<!-- ui.html(一部省略) -->
<script>
document.getElementById('create').onclick = () => {
const textbox = document.getElementById('count');
const count = parseInt(textbox.value, 10);
parent.postMessage({ pluginMessage: { type: 'create-stars-with-numbers', count } }, '*')
}
</script>
// code.ts
figma.showUI(__html__);
figma.ui.onmessage = async msg => {
await figma.loadFontAsync({ family: "Inter", style: "Regular" })
if (msg.type === 'create-stars-with-numbers') {
const nodes: SceneNode[] = [];
for (let i = 0; i < msg.count; i++) {
// 星の作成
const star = figma.createStar()
star.name = 'star'
star.x = i * 50
star.y = 0
star.resize(50, 50)
star.pointCount = 5
star.fills = [{ type: 'SOLID', color: { r: 1, g: 1, b: 0 } }]
star.strokes = [{ type: 'SOLID', color: {r: 0, g: 0, b: 0} }];
star.strokeWeight = 1
star.innerRadius = 0.4
figma.currentPage.appendChild(star)
nodes.push(star)
// 連番の作成
const text = figma.createText()
text.name = 'number'
text.x = i * 50 + 24
text.y = 18
text.characters = `${i+1}`
text.fontSize = 10
text.textAlignHorizontal = 'CENTER'
text.fills = [{ type: 'SOLID', color: { r: 0, g: 0, b: 0 } }]
figma.currentPage.appendChild(text)
nodes.push(text)
}
figma.currentPage.selection = nodes;
figma.viewport.scrollAndZoomIntoView(nodes);
}
figma.closePlugin();
};
Figmaアプリで確認すると意図通りになっていました。

まとめ
プラグイン開発対象の範囲は、アプリにビルトインされている機能(例:コメント機能そのもの)は対象に含まれていないようでしたので、今後触ってできること/できないことも理解していければと思います。
今回は簡単な内容になりましたが、コミュニティへの公開を目的とせずにでも、各々のプロジェクト専用のプラグインを開発できれば、デザイン制作の効率化が図れる機会もありそうだなと感じました。