こんにちは!プロダクトデザインとフロントエンドの境界線を溶かすような、ワクワクするモノづくりをしていますか?
今回は、オープンソースの次世代デザインツールとして世界中のエンジニアとデザイナーから熱い視線を注がれている「Penpot」を取り上げます。
Figmaのプラグインエコシステムは有名ですが、「うちの会社のデザインシステムに完全に準拠したアノテーションツールが欲しい」「社内の特定フォーマットでアセットを書き出す自動化スクリプトを組み込みたい」といった極めてニッチでリアルな要件にぶぶつかったとき、クローズドなエコシステムではモヤモヤすることがありますよね。
その点、完全オープンソースのPenpotなら、自分たちの手でその限界を軽々と突破できます。今回は、TypeScriptを使ってPenpotのオリジナルプラグインをゼロから開発し、キャンバスを自在に操るための極意を一緒に紐解いていきましょう。
これをマスターすれば、毎日の退屈な手作業が劇的に楽になり、チームのワークフローを根本からハックできるようになりますよ。それでは、開発の旅に出発しましょう!
—
1. なぜPenpotプラグインなのか?(開発思想とエコシステムの理解)
まず前提として、Penpotのアーキテクチャについて少しだけ触れておきます。
PenpotはSVGをネイティブフォーマットとして採用し、ブラウザ上で動く完全オープンソースのデザインツールです。そのプラグインシステムは、非常にモダンかつセキュアに設計されています。
- サンドボックス環境: プラグインのロジック(バックエンド側)はiframe内の隔離された空間で動き、Penpotのメインアプリケーションに直接悪影響を与えません。
- メッセージパッシング: UIパネル(HTML/CSS/JS)と、ドキュメントを操作するロジック(Plugin API)の間は、安全な非同期メッセージ通信で行われます。
- TypeScriptファースト: 型安全に開発できるため、APIの仕様書を睨めっこしながらコードを書く必要がありません。IDEの補完が強力な味方になります。
「自分たちのデザイン言語をコードから直接Penpotに流し込む」そんな夢のようなパイプラインを、これから一緒に作っていきましょう。
—
2. 開発環境の構築:最短で「Hello World」にたどり着くセットアップ
百聞は一見にしかず。まずは手を動かして、プラグインが動く最小限の環境を立ち上げます。
Node.js(v18以上推奨)がインストールされていることを確認してください。
ステップ1: プロジェクトの初期化と依存関係のインストール
任意のディレクトリで作業を開始します。今回はモダンな開発体験のために、Viteをベースにした構成をとります。
プロジェクトフォルダを作成して移動
mkdir penpot-custom-plugin
cd penpot-custom-plugin
必要なファイルを自作しても良いですが、今回は最速で動かすために最小限の構成を作ります
npm init -y
ステップ2: 必要な設定ファイル群の作成
プロジェクトルートに以下の2つの重要ファイルを作成します。これがプラグインの「戸籍」と「設計図」になります。
1. `manifest.json`(Penpotにプラグインの存在を教える設定ファイル)
2. `package.json`(ビルドスクリプトと依存関係)
まずは `manifest.json` を作成してください。
{
“name”: “My First Penpot Plugin”,
“slug”: “my-first-penpot-plugin”,
“version”: “1.0.0”,
“description”: “社内ニッチな要件を解決する最初のプラグイン”,
“icon”: “icon.svg”,
// ユーザーがプラグインを実行したときに開くUI(HTML)を指定
“ui”: “dist/index.html”,
// キャンバスを直接操作するバックグラウンドスクリプト
“code”: “dist/code.js”,
“permissions”: []
}
続いて、TypeScriptとViteを使ってビルドできるように `package.json` を整えます。
{
“name”: “penpot-custom-plugin”,
“private”: true,
“version”: “1.0.0”,
“type”: “module”,
“scripts”: {
“dev”: “vite build –watch”,
“build”: “vite build”
},
“devDependencies”: {
“@penpot/plugin-types”: “^0.1.0”,
“typescript”: “^5.0.0”,
“vite”: “^5.0.0”
}
}
(※ `@penpot/plugin-types` はPenpot公式が提供する型定義パッケージです。これのおかげで快適な補完生活が送れます!)
—
3. 魂を吹き込む:APIとUIの連携実装
ここからがエンジニアリングの醍醐味です。
Penpotプラグインは、主に以下の2つの世界で構成されています。
1. UI世界 (`index.html` / `ui.ts`): ユーザーが操作するボタンや入力フォーム(HTML/CSS)。
2. プラグイン世界 (`code.ts`): Penpotのキャンバス(DOMならぬFrameやRectangleなどのオブジェクト)をゴリゴリ操作する頭脳。
この2つを繋ぐコードを書いていきましょう。
ディレクトリ構造のイメージ
penpot-custom-plugin/
├── manifest.json
├── package.json
├── tsconfig.json
└── src/
├── code.ts # キャンバス操作のロジック
├── index.html # UIの見た目
└── ui.ts # UI側のインタラクション
① バックグラウンドスクリプト (`src/code.ts`)
まずは、UI側から「何か作って!」というメッセージを受け取り、キャンバスに赤い正方形を生成するロジックを書きます。
// src/code.ts
// PenpotのプラグインAPIをグローバルな `penpot` オブジェクトから取得します
penpot.ui.onMessage((message) => {
if (message.type === ‘create-rectangle’) {
console.log(‘UIからメッセージを受け取りました:’, message.text);
// 現在のページに新しい長方形(Rectangle)を作成
const rect = penpot.createRectangle();
// プロパティの設定(TypeScriptの型補完が効いて気持ちいい瞬間です!)
rect.name = message.text || ‘Awesome Rect’;
rect.resize(100, 100);
rect.x = 200;
rect.y = 200;
rect.fillColor = ‘#FF5733’; // 鮮やかなオレンジ色
// 選択状態にする
penpot.selection = [rect];
// 処理完了をUI側に通知(必要に応じて)
penpot.ui.sendMessage({ type: ‘notification’, text: ‘矩形を作成しました!’ });
}
});
② ユーザーインターフェース (`src/index.html`)
次に、ユーザーが操作するためのシンプルなUIパネルを作ります。
Penpot オートメーション
③ UI側のインタラクションスクリプト (`src/ui.ts`)
ボタンが押されたときに、`code.ts` へメッセージを飛ばすブリッジ役です。
// src/ui.ts
document.getElementById(‘create-btn’)?.addEventListener(‘click’, () => {
const inputElement = document.getElementById(‘rect-name’) as HTMLInputElement;
const text = inputElement ? inputElement.value : ”;
// parent.postMessage を使って、Penpotのサンドボックス環境へメッセージを送信
parent.postMessage(
{
pluginMessage: {
type: ‘create-rectangle’,
text: text,
},
},
”
);
});
// バックエンド(code.ts)からのメッセージを受け取るリスナー
window.addEventListener(‘message’, (event) => {
const message = event.data.pluginMessage;
if (message && message.type === ‘notification’) {
console.log(message.text);
}
});
—
4. いざ実戦!Penpotへのプラグイン読み込みと動作確認
コードを書いたら、いよいよPenpot上で動かしてみましょう!
1. ビルドの実行
npm run build
これで `dist/` フォルダの中に `code.js` と `index.html` が生成されます。
2. Penpotアプリでの読み込み
- ローカルまたはクラウド版のPenpotを開き、任意のデザインファイルに入ります。
- メニューバー、またはプラグイン管理画面(Plugins)を開きます。
- 「Load local plugin(ローカルプラグインの読み込み)」を選択し、先ほど作成したプロジェクトの根っこにある `manifest.json` を指定します。
3. 魔法の瞬間
プラグイン一覧に「My First Penpot Plugin」が出現します!それをクリックして起動し、UIパネルのボタンを押してみてください。
……どうですか?見事にキャンバスの指定した座標に、鮮やかなオレンジ色の正方形が出現したはずです!
—
5. 先輩エンジニアからのアドバイス:ここから実用的なツールへ昇華させるために
おめでとうございます!これであなたは、Penpotの拡張性を完全に手に入れました。
ここからさらに「社内ニッチな要件」を満たす実用的なツールに育て上げるためのヒントをいくつか置いておきます。
- 外部APIとの通信: `code.ts` 側からは制限がある場合でも、UI側 (`ui.ts`) なら通常のWebアプリと同様に `fetch` を使って社内のGitHub APIやJira、独自のデザインシステムサーバーと通信できます。取得したJSONデータをメッセージ経由で `code.ts` に渡し、キャンバスに自動レイアウトさせましょう。
- エラーハンドリング: ユーザーが何も選択していない状態でオブジェクトを操作しようとするとエラーになります。`if (penpot.selection.length === 0)` などのガード節を必ず挟み、親切なアラートをUI側に返す設計にしてください。
オープンソースの自由度を活かしたプラグイン開発は、あなたのチームの生産性を爆発的に高めるキラーコンテンツになります。
ぜひ、日々の「めんどくさい」を自動化するオリジナルプラグインを作ってみてくださいね!それでは、ハッピーコーディング!