はじめに
Variables と Text Styles の使い分け編 では、何をVariablesで管理し、何をText Stylesで管理すべきかを整理した。今回は、設計したVariablesをエクスポートし、Kotlin(Compose Multiplatform)コードに変換するまでの流れを解説する。
対象はColorsとTokensの2種類。TypographyはVariablesではなくText Stylesで管理することを推奨するため、本記事では扱わない。詳細は Stylesからコード生成の偏 を参照。
Variablesのエクスポート方法
方法はいくつかあるが、それぞれ制限がある。
| 方法 | 結果 |
|---|---|
| Figma MCP | ❌ 選択中のアイテムのみ。全Variables一括取得は不可。デザインシステムの初回実装に不向き。 |
| Figma REST API | ❌ Variables エンドポイントはEnterpriseプランのみ対応。ほとんどの場合は利用できない。 |
| サードパーティプラグイン(Tokens Studio等) | 🔺 JSONエクスポート可能。ただしOrganizationアカウントでは承認が必要な場合あり、利用できない場合がある。 |
| 手動エクスポート(推奨) | 🟢 Figma標準機能。シンプルで確実。手動でJSONファイルを取得する必要がある。 |
手動エクスポートの手順
Variablesパネル右上のメニュー → Export variables
デザインシステムは毎日更新するものではなく、デザイナーからエンジニアへのハンドオフのタイミングで渡せば十分だ。手動エクスポートで十分に運用できる。
エクスポートされるJSONの構造
コレクションごとにJSONファイルが生成される。
{
"color": {
"primary": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"alpha": 1,
"hex": "#00356E"
},
"$extensions": {
"com.figma.variableId": "VariableID:1:56"
}
},
"primary-light": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"alpha": 1,
"hex": "#0066CC"
},
"$extensions": {
"com.figma.variableId": "VariableID:1:57"
}
},
...
}
}
{
"spacing": {
"none": {
"$type": "number",
"$value": 0,
"$extensions": {
"com.figma.variableId": "VariableID:8:36"
}
},
"xxs": {
"$type": "number",
"$value": 2,
"$extensions": {
"com.figma.variableId": "VariableID:8:37"
}
},
...
}
}
$extensions.com.figma.variableId に格納されているVariable IDをKotlinコメントとして保持することで、将来の差分更新時にどの変数がどのFigma変数に対応するかが追跡できる。
AIへのプロンプト
ColorsとTokensをそれぞれ独立したプロンプトで処理することを推奨する。一つの巨大プロンプトにまとめるより、AIの精度が上がる。
Colors.kt 生成プロンプト
## コンテキスト
- Kotlin Multiplatform / Jetpack Compose プロジェクト
- 対象プラットフォーム: Android / iOS
- デザインシステム: Figma Variables JSONからエクスポート
## 入力(Input)
- `tools/figma-design-system/variables/Colors/LightMode.tokens.json`
- `tools/figma-design-system/variables/Colors/DarkMode.tokens.json`
## 出力(Output)
- `composeApp/src/commonMain/kotlin/com/acme/designsystem/Colors.kt`
## 処理(Process)
JSONの全エントリーをループ処理し、各変数に以下のルールを適用する。
### 命名規則
kebab-case → PascalCase:
- `primary` → `Primary`
- `primary-light` → `PrimaryLight`
- `on-surface-secondary` → `OnSurfaceSecondary`
### 値変換
- `$value.hex` → `Color(0xFFHEXVALUE)` 16進数は大文字
- 例: `#00356E` → `Color(0xFF00356E)`
### Variable IDコメント形式
```kotlin
val Primary = Color(0xFF00356E) // #00356E | Figma: VariableID:1:56
```
Variable IDは `$extensions.com.figma.variableId` から取得する。
### 構造保持
- `AppColors.Light` / `AppColors.Dark` オブジェクト構造維持
- グループコメント維持 (`// Primary Colors`, `// Surface Colors` 等)
- ファイルヘッダーコメント (Figma URL含む) 維持
### 変数の追加/削除
- JSON新規変数 → 適切なグループに追加(命名規則適用)
- JSON削除変数 → Kotlinコードから削除
- Figma変数名変更 → Kotlin名更新、Variable IDコメント保持
## 検証
- プロパティ名重複なし、命名規則適用
- 各プロパティには適切なコメントがある。Variable ID保持
- 値がJSONソースと完全一致。16進数カラーは大文字 (`0xFF00356E`)
- LightモードとDarkモード両方更新済み
- Androidコンパイル可能: `./gradlew :composeApp:compileDebugKotlin`
## 例
### 入力 `LightMode.tokens.json`
```json
{
"primary": {
"$value": { "alpha": 1, "hex": "#00356E" },
"$extensions": { "com.figma.variableId": "VariableID:1:56" }
}
}
```
### 出力 `Colors.kt`
```kotlin
object AppColors {
object Light {
// Primary Colors
val Primary = Color(0xFF00356E) // #00356E | Figma: VariableID:1:56
}
object Dark {
// Primary Colors
val Primary = Color(0xFF4A90E2) // #4A90E2 | Figma: VariableID:1:56
}
}
```
参考までの生成されたコード:
package com.acme.designsystem
import androidx.compose.ui.graphics.Color
/**
* Design System Colors
* Generated from Figma AcmeColors variables
* Supports both Light and Dark modes
*
* Figma File: https://www.figma.com/design/IvL6Y4lMrPnXRDdt1waDdE/Design-Components?node-id=31-6
* Source: figma-variables/Colors/
*/
object AppColors {
object Light {
// Primary Colors
val Primary = Color(0xFF00356E) // #00356E | Figma: VariableID:1:56
val PrimaryLight = Color(0xFF0066CC) // #0066CC | Figma: VariableID:1:57
val OnPrimary = Color(0xFFFFFFFF) // #FFFFFF | Figma: VariableID:1:66
// Secondary Colors
val Secondary = Color(0xFFE60012) // #E60012 | Figma: VariableID:1:59
// ... (中略) ...
}
object Dark {
// Primary Colors
val Primary = Color(0xFF4A90E2) // #4A90E2 | Figma: VariableID:1:56
val PrimaryLight = Color(0xFF66A3FF) // #66A3FF | Figma: VariableID:1:57
val OnPrimary = Color(0xFF000000) // #000000 | Figma: VariableID:1:66
// Secondary Colors
val Secondary = Color(0xFFFF4444) // #FF4444 | Figma: VariableID:1:59
// ... (中略) ...
}
}
Tokens.kt 生成プロンプト
## コンテキスト
- Kotlin Multiplatform / Jetpack Compose プロジェクト
- 対象プラットフォーム: Android / iOS
- デザインシステム: Figma Variables JSONからエクスポート
## 入力(Input)
- `tools/figma-design-system/variables/Tokens/Mode 1.tokens.json`
## 出力(Output)
- `composeApp/src/commonMain/kotlin/com/acme/designsystem/Tokens.kt`
## 処理(Process)
JSONの全エントリーをループ処理し、各変数に以下のルールを適用する。
### 命名規則
略語 → フル名:
- `none` → `None`
- `xxs` → `ExtraExtraSmall`
- `xs` → `ExtraSmall`
- `sm` → `Small`
- `md` → `Medium`
- `lg` → `Large`
- `xl` → `ExtraLarge`
- `xxl` → `ExtraExtraLarge`
- `xxxl` → `ExtraExtraExtraLarge`
### 値変換
- `$value` → `Dp` (例: `16` → `16.dp`)
### Variable IDコメント形式
```kotlin
/**
* Large spacing: 16dp
* Figma: VariableID:8:41 (spacing.lg)
*/
val Large: Dp = 16.dp
```
Variable IDは `$extensions.com.figma.variableId` から取得する。
### 構造保持
- `AppTokens` オブジェクト構造維持
- ファイルヘッダーコメント (Figma URL含む) 維持
### 変数の追加/削除
- JSON新規変数 → 追加(命名規則適用)
- JSON削除変数 → Kotlinコードから削除
- Figma変数名変更 → Kotlin名更新、Variable IDコメント保持
## 検証
- プロパティ名重複なし、命名規則適用
- 各プロパティには適切なコメントがある。Variable ID保持
- 値がJSONソースと完全一致
- Androidコンパイル可能: `./gradlew :composeApp:compileDebugKotlin`
## 例
### 入力 `Mode 1.tokens.json`
```json
{
"lg": {
"$value": 16,
"$extensions": { "com.figma.variableId": "VariableID:8:41" }
}
}
```
### 出力 `Tokens.kt`
```kotlin
object AppTokens {
/**
* Large spacing: 16dp
* Figma: VariableID:8:41 (spacing.lg)
*/
val Large: Dp = 16.dp
}
```
参考までの生成されたコード:
package com.acme.designsystem
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
/**
* Design System Tokens
* Generated from Figma AcmeTokens variables
*
* Figma File: https://www.figma.com/design/IvL6Y4lMrPnXRDdt1waDdE/Design-Components?node-id=31-6
* Source: figma-variables/Tokens/Mode 1.tokens.json
*/
object AppTokens {
/**
* No spacing: 0dp
* Figma: VariableID:8:36 (spacing.none)
*/
val None: Dp = 0.dp
/**
* Extra Extra Small spacing: 2dp
* Figma: VariableID:8:37 (spacing.xxs)
*/
val ExtraExtraSmall: Dp = 2.dp
/**
* Extra Small spacing: 4dp
* Figma: VariableID:8:38 (spacing.xs)
*/
val ExtraSmall: Dp = 4.dp
// ... (中略) ...
}