3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

watnow Advent Calendar 2024

Day 16

[Figma Plugin API] オブジェクトを一括変更するプラグインを作る!

Last updated at Posted at 2024-12-16

はじめに

watnow アドベントカレンダー2024 16日目は、Figma の Plugin API を使ってみたら思ったよりも簡単で面白かったのでオリジナルのプラグインを作ってみたよ、という記事です📝

今回作ったもの

オブジェクト置き換えくん

Figmaファイルの中にある同じ名前のオブジェクトを、指定した別のオブジェクトに一括で変更することができるプラグインです。実行のイメージはこんな感じ ↓

スクリーンショット 2024-12-15 1.27.07.png

それでは早速作っていきます!

プラグイン作成

準備

Figma デスクトップアプリを用意する

Figmaのプラグインの作成はデスクトップアプリから可能です。以下リンクからお使いの環境に合わせてダウンロードしてください。

エディターを用意する

特にエディターの指定はないので使いやすいツールを使ってください。ここでは Visual Studio Code を使用しています。

Node.js を用意する

プラグインのスクリプトは TypeScript で作成します。( Figma 推奨)TypeScript のプログラムをビルドするためには Node.js が使える環境を用意する必要があります。以下リンクからお使いの環境に合わせてダウンロードしてください。

ダウンロードできたかどうかは、ターミナルから以下のコマンドで確認することができます。

terminal.
node -v

新しいプラグインの作成

デザインファイルを作成する

Figmaのデスクトップアプリを立ち上げ、デザインファイル新規作成を選択します。

image.png

プラグインの新規作成

デザインファイル下部のツールバーからリソースをクリックし、プラグインとウィジェットを選択します。「プラグインの新規作成...」という項目があるのでここから始めます。

image.png

クリックすると以下のようなモーダルが出てくるので、今回は「Figmaデザイン」→「カスタムUI」を選択します。名前の欄に入力したものがローカルに作成されるフォルダ名になるので、アルファベットで自分のわかりやすい名前にすると良いと思います。名前を付けて保存しましょう。

image.png

image.png

プログラムの作成

プロジェクトファイルをエディターから開く

先ほど作成した新しいプラグインのフォルダを VSCode で開きます。

image.png

依存関係をインストールする

まず、Figmaプラグイン開発に必要な依存関係をインストールします。新しいターミナルを開いて以下のコマンドを入力します。

image.png

terminal.
npm install

ビルドする

プロジェクトを作成したときに作られるフォルダの中には、入力した数だけオブジェクトを新規作成するプラグインのスクリプトがすでに用意されています。ビルドして実行してみましょう。Mac の方は Command-Shift-B、Windows の方は Ctrl-Shift-B を押してください。npm: build を選択します。

image.png

プラグインを実行する

Figma に戻り、ツールバーのリソースから、先ほど作ったプラグインを選択します。

image.png

選択すると以下のようなパネルが開き、実行すると5つのオブジェクトが新規作成されました。

image.png

オブジェクトを一括変更するプログラムにする

今回プログラムの作成は ChatGPT にやってもらいました。code.ts と ui.html を以下のように書き換えます。

code.ts
/// <reference types="@figma/plugin-typings" />

figma.showUI(__html__, { width: 300, height: 200 });

figma.ui.onmessage = async (msg: { type: string; targetName: string; replacementName: string }) => {
  if (msg.type === 'replace') {
    const { targetName, replacementName } = msg;

    if (!targetName || !replacementName) {
      figma.notify("オブジェクト名を両方入力してください");
      return;
    }

    const allNodes = figma.currentPage.findAll();
    const targetNodes = allNodes.filter((node: SceneNode) => node.name === targetName);
    const replacementNode = allNodes.find((node: SceneNode) => node.name === replacementName);

    if (!replacementNode) {
      figma.notify("置き換え後のオブジェクトが見つかりませんでした");
      return;
    }

    let count = 0;
    for (const node of targetNodes) {
      if ('x' in node && 'y' in node) {
        const newNode = (replacementNode as SceneNode).clone();

        // 元の親ノードを取得
        const parent = node.parent;
        if (parent && 'appendChild' in parent) {
          parent.appendChild(newNode); // 親ノード(フレーム)に追加
        }

        // 元の位置を引き継ぐ
        newNode.x = node.x;
        newNode.y = node.y;

        // 元の相対位置(フレーム内の座標)を維持するために設定
        if ('relativeTransform' in node) {
          newNode.relativeTransform = node.relativeTransform;
        }

        // 元のオブジェクトを削除
        node.remove();
        count++;
      }
    }

    figma.notify(`${count}個のオブジェクトを置き換えました`);
    figma.closePlugin();
  }
};
ui.html
<!DOCTYPE html>
<html>
  <head>
    <style>
      body {
        font-family: Arial, sans-serif;
        padding: 16px;
        max-width: 300px;
      }
      input,
      button {
        width: 100%;
        margin-bottom: 8px;
      }
    </style>
  </head>
  <body>
    <label for="targetName">置き換え前のオブジェクト名:</label>
    <input type="text" id="targetName" placeholder="OldObject" />

    <label for="replacementName">置き換え後のオブジェクト名:</label>
    <input type="text" id="replacementName" placeholder="NewObject" />

    <button id="submit">実行</button>

    <script>
      const submitButton = document.getElementById("submit");
      submitButton.onclick = () => {
        const targetName = document.getElementById("targetName").value;
        const replacementName =
          document.getElementById("replacementName").value;

        parent.postMessage(
          { pluginMessage: { type: "replace", targetName, replacementName } },
          "*"
        );
      };
    </script>
  </body>
</html>

前述の手順で再度ビルドします。Figma に戻り、プラグインを選択すると以下のようなパネルが表示されました。

image.png

オブジェクトの名前を入力して実行すると...

画面収録 2024-12-16 22.27.13 (1).gif

望み通りのプラグインができましたー!!!🎉

おわりに

Figma のプラグイン、思っていたよりも簡単に作成できました。Figma の API には他にも以下のような種類と特徴があります。

APIの種類 主な用途 使用タイミング
REST API デザインデータの取得・操作、外部連携 他のサービスとデータをやり取りする場合
Plugin API Figma内部のカスタマイズ、自動化 デザイン作業を効率化したい場合、独自のツールを作成する場合
Webhook API イベント通知と連携、自動化 リアルタイムでイベントを検知して外部サービスに通知したい場合

目的に合わせた API 利用でもっともっと便利に Figma を使いこなせると良いですね!

2024年ももうあと少し、みなさま良いお年を〜☃️

参考

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?