Figmaを真の「デザインOS」へ昇華させる:デザイントークンとVariables駆動による大規模開発パイプラインの完全構築
プロダクトがスケールするにつれ、デザインとコードの乖離、いわゆる「デザインデット(負債)」は開発組織の速度を確実に殺していく。Figmaを単なるお絵描きツールとして扱っているうちは、マルチプラットフォーム展開やダークモード対応の波に呑まれて破綻する。
真のUI/UXエンジニアリングとは、Figmaをコードの「上流AST(抽象構文木)」として捉え、デザイントークンを介してCI/CDパイプライン直結の単一の真実の源泉(Single Source of Truth: SSOT)として構築することだ。
本稿では、FigmaのVariables(変数)機能の限界を突き詰め、マルチブランド・マルチテーマを完全自動制御する設計思想と、API/CLIを駆使したコードベースへの同期パイプラインの構築手法を、実戦的なコードとアーキテクチャ図とともに解説する。
—
1. デザイントークン階層アーキテクチャの設計
スケーラブルなデザインシステムを構築する際、最大の罠は「直接的な値をコンポーネントにバインドすること」だ。例えば、ボタンの背景色に直接 `#0066FF` を指定した瞬間、そのシステムは死に向かう。
デザイントークンは、以下の3階層(Three-tier Token Architecture)で厳密にレイヤリングされなければならない。
[ Primitive Tokens (プリミティブ) ]
└─ 色の生値や絶対的なピクセル値 (e.g., blue-500: #0066FF)
[ Semantic Tokens (セマンティック) ]
└─ 文脈や役割を示す抽象化 (e.g., color.background.primary: blue-500)
[ Component Tokens (コンポーネント固有) ]
└─ 特定のコンポーネント内でのみ使われる局所的定義 (e.g., button.bg.default: color.background.primary)
Figma上でこれを実装する際、Primitivesを直接UIデザインに適用してはならない。デザイナーが触るのはSemantic層までであり、Component層は原則としてコンポーネント内部のカプセル化にとどめる。この規律をFigmaのStyles and Variablesの構造として強制することが、破綻しないシステムの第一歩である。
—
2. Figma Variablesを活用したテーマ管理の極意
FigmaのVariables(変数)機能は、単なる「色の置き換え」ではない。これは実行時テーマ切り替え(Runtime Theming)のモデリング環境である。
コレクション設計のベストプラクティス
大規模開発においては、変数コレクションを明確に分離すること。
1. Primitive Collection: カラーパレット、スペーシングスケール(4pxベース)、ブレイクポイント
2. Semantic Collection: 背景、テキスト、ボーダー、インタラクション状態
3. Context / Mode Collection: Light / Dark / High Contrast などのモード切替
Light/Darkモード切替の内部実装手順
Figma上でModeを切り替える際、Semantic変数の値がモードごとにオーバーライドされるように設定する。
// 概念的な変数マッピングの構造
{
“semantic”: {
“color-bg-canvas”: {
“$type”: “color”,
“$value”: {
“light”: “{primitive.neutral.50}”,
“dark”: “{primitive.neutral.900}”
}
}
}
}
この構造をFigmaのVariablesパネル上で正確に再現し、コレクションの「Modes」機能を使ってマッピングを行う。デザイナーはフレームに対して特定のモード(例: Dark Mode)を適用するだけで、子孫要素のVariablesは自動的に解決される。
—
3. Figma REST APIとCLIを駆使した自動化パイプライン
Figma上の変更を手動でJSONに書き出し、PRを作るようなフローはエンジニアリングの怠慢だ。Figma REST APIと独自のCLIスクリプトを組み合わせ、デザイントークンの変更を検知してGitHubへ自動同期するパイプラインを構築する。
以下は、Figma REST APIからVariablesを取得し、W3C Design Tokens Format準拠のJSONへトランスパイルするNode.js製CLIスクリプトの実装例である。
/
- figma-token-sync.js
- Figma REST APIからVariablesをフェッチし、W3C準拠のデザイントークンに変換するスクリプト
/
import fs from ‘fs/promises’;
import fetch from ‘node-fetch’;
const FIGMA_FILE_KEY = process.env.FIGMA_FILE_KEY;
const FIGMA_ACCESS_TOKEN = process.env.FIGMA_ACCESS_TOKEN;
async function fetchFigmaVariables() {
const endpoint = `https://api.figma.com/v1/files/${FIGMA_FILE_KEY}/variables/local`;
const response = await fetch(endpoint, {
headers: {
‘X-Figma-Token’: FIGMA_ACCESS_TOKEN
}
});
if (!response.ok) {
throw new Error(`Figma API Error: ${response.statusText}`);
}
return await response.json();
}
function transformToW3CTokens(figmaData) {
const { variables, variableCollections } = figmaData.meta;
const tokens = {};
// コレクションIDとモードのマッピングを解決
const collections = Object.values(variableCollections).reduce((acc, col) => {
acc[col.id] = col;
return acc;
}, {});
for (const varId of Object.keys(variables)) {
const variable = variables[varId];
const collection = collections[variable.variableCollectionId];
// スコープや隠し変数のフィルタリング
if (variable.hiddenFromPublishing) continue;
const nameParts = variable.name.split(‘/’);
let currentLevel = tokens;
// 階層構造の構築
nameParts.forEach((part, index) => {
if (index === nameParts.length – 1) {
// 葉ノード(値の設定)
currentLevel[part] = {
$type: mapFigmaTypeToW3C(variable.resolvedType),
$value: resolveVariableValues(variable.valuesByMode, collection.modes)
};
} else {
currentLevel[part] = currentLevel[part] || {};
currentLevel = currentLevel[part];
}
});
}
return tokens;
}
function mapFigmaTypeToW3C(figmaType) {
switch (figmaType) {
case ‘COLOR’: return ‘color’;
case ‘FLOAT’: return ‘dimension’;
case ‘STRING’: return ‘string’;
case ‘BOOLEAN’: return ‘boolean’;
default: return ‘string’;
}
}
function resolveVariableValues(valuesByMode, modes) {
const resolved = {};
for (const [modeId, value] of Object.entries(valuesByMode)) {
const modeName = modes.find(m => m.modeId === modeId)?.name || modeId;
// エイリアス(他の変数への参照)の解決処理がここに必要
resolved[modeName.toLowerCase()] = formatValue(value);
}
return resolved;
}
function formatValue(val) {
if (typeof val === ‘object’ && val.type === ‘VARIABLE_ALIAS’) {
// エイリアスの場合は参照先のIDを持つ(実際のプロダクションではIDから変数名へ逆引きするマップが必要)
return `{ref:${val.id}}`;
}
if (typeof val === ‘object’ && ‘r’ in val) {
// RGBAオブジェクトをHEXに変換
const toHex = (n) => Math.round(n 255).toString(16).padStart(2, ‘0’);
return `#${toHex(val.r)}${toHex(val.g)}${toHex(val.b)}${val.a < 1 ? toHex(val.a) : ''}`;
}
return val;
}
async function main() {
try {
console.log('Fetching variables from Figma...');
const rawData = await fetchFigmaVariables();
console.log('Transforming to W3C Design Tokens...');
const w3cTokens = transformToW3CTokens(rawData);
await fs.writeFile(
'./tokens/design-tokens.json',
JSON.stringify(w3cTokens, null, 2),
'utf-8'
);
console.log('Successfully generated ./tokens/design-tokens.json');
} catch (error) {
console.error('Pipeline failed:', error);
process.exit(1);
}
}
main();
---
4. Style Dictionaryによるコードトランスパイルとパフォーマンス最適化
Figmaから出力されたJSONを、そのままアプリケーションコード(CSS Variables, Tailwind CSS config, iOS Swift, Android Kotlinなど)に変換するのが Style Dictionary だ。
ここで重要なのは、ビルド時のパフォーマンスと、生成されるコードのメモリ効率・バンドルサイズの最適化である。
Style Dictionary カスタム設定ファイル
// style.config.js
module.exports = {
source: [‘tokens//.json’],
platforms: {
css: {
transformGroup: ‘css’,
buildPath: ‘dist/css/’,
files: [{
destination: ‘_variables.css’,
format: ‘css/variables’,
options: {
outputReferences: true // 変数間の参照関係(var(–…))を維持して出力
}
}]
},
tailwind: {
transformGroup: ‘js’,
buildPath: ‘dist/tailwind/’,
files: [{
destination: ‘tailwind.tokens.js’,
format: ‘javascript/es6’
}]
}
}
};
パフォーマンス・メモリ消費の最適化ハック
大規模なデザインシステムになると、Figmaファイル内の変数やスタイルが数千〜数万個に及び、Figmaクライアント自体のメモリ消費量(RAM)が跳ね上がり、キャンバスの動作が重くなる。これを防ぐための実践的アプローチ:
1. ライブラリの分割(Modularization):
単一の巨大なFigmaファイルにすべてのトークンとコンポーネントを詰め込まない。`Core Primitives`、`Semantic Tokens`、各ドメインごとの `Component Library` へとライブラリを垂直分割し、Publish/Subscribe モデルで結合する。
2. 未使用変数のパージ(Dead Token Elimination):
Figmaのプラグイン APIを活用し、どのコンポーネントからも参照されていない「幽霊変数」を検知して削除するスクリプトを定期実行する。これにより、APIペイロードのサイズが削減され、ビルドパイプラインのレイテンシが劇的に改善される。
—
5. 結び:デザインとコードの境界線を消し去るために
Figmaをデザインツールとして扱っているうちは、エンジニアリング組織との壁は消えない。FigmaのVariablesとデザイントークンをコードのASTと同等の解像度で扱い、APIとCLIによってパイプラインに完全に組み込むこと。
その先にあるのは、デザイナーがFigma上で変数を操作した瞬間、GitHubでCIが走り、数分後にはプレビュー環境のUIが自動で更新されている――そんな、摩擦係数ゼロのシームレスな開発エコシステムの実現だ。
道具に使われるな。道具をハックし、自らのパイプラインの拡張とせよ。