デザインとコードの境界線を消滅させる:Penpot × Tailwind CSSによる「真の」単一ソース・オブ・トゥルース構築術
UI/UXの現場でよく見る「デザイナーが描いたデザインデータ」と「エンジニアが実装したコンポーネント」の乖離。この溝を埋めるために、我々はこれまで膨大なコストを払ってきた。Figmaのプラグインに依存し、トークンの同期ツールを導入し、それでもなお微調整のプルリクエストに時間を浪費する。
だが、Penpotにはその悪循環を断ち切るポテンシャルがある。オープンソースであり、SVGベースで設計されたこのツールを、「Tailwind CSSのエンジン」として再定義する。本稿では、デザインツール上の変数を直接Tailwindのユーティリティクラスへマッピングし、実装パイプラインを「完全自動化」するための解を提示する。
—
1. なぜPenpotでなければならないのか:アーキテクチャの真実
Figmaはブラックボックスだ。API経由で取得できるデータはJSONだが、その構造は非公開かつ変更が多い。対してPenpotはSVGというWeb標準をネイティブ言語として扱う。
Tailwind CSSの思想は「ユーティリティファースト」だ。これはデザインシステムの「アトミックな要素」と完全に一致する。Penpotのデザイン変数をTailwindの `tailwind.config.js` の `theme` 階層へダイレクトに流し込むことで、「デザイン変更=即座に全コンポーネントの再ビルド」という究極のワークフローが実現する。
2. 命名規則の統合:言語の同一化
エンジニアとデザイナーが「別の名前」で同じ色や余白を呼ぶことは、技術的負債の第一歩だ。Penpot側とTailwind側で、以下の命名規則を厳格に共有せよ。
- Color: `[base|primary|secondary]-[level]` (例: `primary-500`)
- Spacing: `[size]-[scale]` (例: `space-4`, `space-8`)
- Typography: `[family]-[weight]-[size]` (例: `sans-bold-lg`)
Penpotの「デザイン変数(Design Tokens)」機能で定義した名前が、そのままTailwindのクラス名となるよう設計する。ここで重要なのは、「Figma的なレイヤー名」ではなく「CSSのプロパティ名」をメタデータとして持つことだ。
3. 自動化の深淵:Penpot API × Node.js スクリプト
PenpotのAPIを利用し、デザインシステムの内容を抽出するCLIツールを構築する。以下のスクリプトは、Penpotのプロジェクトから色と空間の定義を抽出し、`tailwind.config.js` に自動出力するエンジンの一部だ。
/
- Penpot APIからデザイントークンを抽出し、Tailwind configを生成するスクリプト
- @description Penpotの内部APIからJSONを取得し、Tailwindのthemeオブジェクトを構築する
/
const axios = require(‘axios’);
const fs = require(‘fs’);
async function syncDesignTokens(apiKey, fileId) {
// Penpot APIエンドポイント (Self-hosted環境に合わせて変更)
const client = axios.create({ baseURL: ‘https://penpot.your-domain.com/api’ });
const { data } = await client.get(`/files/${fileId}/styles`, {
headers: { ‘Authorization’: `Token ${apiKey}` }
});
const themeConfig = {
colors: data.colors.reduce((acc, c) => ({ …acc, [c.name]: c.value }), {}),
spacing: data.spacings.reduce((acc, s) => ({ …acc, [s.name]: `${s.value}px` }), {})
};
const configContent = `module.exports = { theme: { extend: ${JSON.stringify(themeConfig, null, 2)} } };`;
fs.writeFileSync(‘./tailwind.config.js’, configContent);
console.log(‘✅ Tailwind config synchronized.’);
}
運用の極意:
1. CI/CDパイプラインへの統合: GitHub Actionsで `on: push` 時、あるいはデザイン側の更新トリガーでこのスクリプトを回せ。
2. 型安全の担保: 生成された `tailwind.config.js` から TypeScript の型定義(`@types/tailwindcss`)を自動生成するタスクを組み込めば、エンジニアはIDEの補完なしにはコーディングできない状態を作れる。
4. パフォーマンスとスケーラビリティへのハック
Penpotの大規模ファイルにおけるメモリ消費問題や、APIレスポンスの遅延に悩まされるようになったら、以下の対策を講じろ。
- Diff解析の導入: 毎回全スタイルを取得するのではなく、ETagや更新日時を比較し、差分のみを同期するゲートウェイを中間に立てる。
- SVGの最適化パイプライン: PenpotからエクスポートされるSVGは冗長になりがちだ。`svgo` をビルドプロセスに組み込み、AST(抽象構文木)レベルでクリーニングを行え。
- Design Tokenの階層化: デザイナーが「色」を定義する際、直接カラーコードを打たせるのではなく、`semantic-color`(意味論的色)として定義させる。`bg-primary` が `brand-blue` を参照するように設計すれば、ダークモード対応も一瞬で終わる。
結論:ツールを「使わされる」立場から「支配する」立場へ
多くのチームは、UIデザインツールを「絵を描く場所」と誤解している。しかし、真のUI/UXエンジニアにとって、それは「実装の仕様書を自動生成するプログラミング環境」に他ならない。
PenpotとTailwind CSSの組み合わせは、今のところ最も「コードに近い」デザインワークフローを提供してくれる。この連携を突き詰め、チームのコンテキストをコードに同期させろ。そうすれば、デザイン変更のたびに発生する「あの憂鬱な修正作業」は、歴史の遺物となるはずだ。
次は、君がこのスクリプトを自社環境にインストールし、最初のデプロイを自動化する番だ。健闘を祈る。