figmascopeのデフォルトエクスポートターゲットはJetpack Composeです。しかしバンドルはエージェント非依存です—IRノードの種類、トークン形式、文字列refはReact + Tailwindにも同じくらいクリーンにマッピングされます。エージェントにKotlinの代わりにJSXをターゲットにするよう指示するだけです。
このガイドではIR→JSXマッピング、tokens.jsonのトークンでtailwind.config.jsを拡張する方法、Reactサイドで最もドリフトが少ない出力を得るプロンプトパターンを説明します。
最初に重要な注意点
Composeはfigmascopeが最もテストするものです。IR、トークン形式、CONTEXT.mdの制約はComposeを念頭に設計されました。React + Tailwindは動作します—IRはクリーンにマッピングされます—しかし特にタイポグラフィとオーバーレイレイアウトでドリフトがわずかに多く見られます。おかしく見えるものにはフラグを立てて、最初のパスの後でトークンチェックを実行してください。
ステップ1:バンドルを生成して解凍する
unzip ~/Downloads/context-bundle.zip -d ./design/
ls design/
# CONTEXT.md _meta.json components/ screens/ strings.json tokens.json
ステップ2:デザイントークンでTailwindコンフィグを拡張する
プロンプトの前に、tokens.jsonをtailwind.config.jsにマッピングします。これはTailwindをトークン対応にする重要なステップです—classNameの文字列にハードコードされた16進値の代わりに、デザインに追跡可能なセマンティック名が得られます。
// tailwind.config.js
const tokens = require('./design/tokens.json')
// カラーマップを作成: { 'brand-7f5cfe': '#7F5CFE', ... }
const colors = Object.fromEntries(
Object.entries(tokens.color).map(([key, val]) => [
`brand-${key}`, val
])
)
// スペーシングマップを作成: { 'ds-4': '4px', 'ds-8': '8px', ... }
const spacing = Object.fromEntries(
Object.entries(tokens.spacing).map(([key, val]) => [
`ds-${key}`, `${val}px`
])
)
// ボーダー半径マップを作成
const borderRadius = Object.fromEntries(
Object.entries(tokens.radius).map(([key, val]) => [
`ds-${key}`, val === 9999 ? '9999px' : `${val}px`
])
)
module.exports = {
content: ['./src/**/*.{js,ts,jsx,tsx}'],
theme: {
extend: {
colors,
spacing,
borderRadius,
}
}
}
これによりbg-brand-7f5cfe、p-ds-16、rounded-ds-12のようなTailwindクラスが生成されます。最もきれいなクラス名ではありませんが追跡可能です—すべてのクラスはトークンキーに戻ります。
セマンティックエイリアスを好む場合、エイリアスレイヤーを追加します:
// theme.extend.colorsに追加:
primary: tokens.color['7f5cfe'],
background: tokens.color['f6f2ea'],
surface: tokens.color['ffffff'],
エージェントに両方渡してください—生のトークンコンフィグとセマンティックエイリアス—コンテキストに応じた正しい名前を選べるように。
ステップ3:エージェントにReact + Tailwindをターゲットにするようプロンプトする
CONTEXT.mdはデフォルトターゲットをComposeとしています。プロンプトで明示的にオーバーライドします:
./design/screens/home.jsonをTailwind CSSを使用したReact関数コンポーネントとして実装してください。
フレームワークオーバーライド:CONTEXT.mdのComposeの指示は無視してください。React + Tailwindをターゲットにしてください。
ルール:
- ./design/tokens.jsonを読んでください。トークンはTailwindコンフィグに拡張されています—
トークンキーに対応するTailwindクラスを使ってください(例:bg-brand-7f5cfe、p-ds-16)。
- UI文字列は./design/strings.jsonから来ます。キーでインポートして参照してください。
- IRノード種類マッピング:
stack (axis:vertical) → <div className="flex flex-col gap-[Xpx]">
stack (axis:horizontal) → <div className="flex flex-row gap-[Xpx]">
overlay → <div className="relative"> + アブソリュート配置の子
absolute → <div className="absolute" style={{"{{"}}top, left, width, height{{"}}"}}>
leaf (text) → <span> または <p> + Tailwindテキストクラス
leaf (rectangle) → <div> + bgとroundedクラス
- 16進値をハードコードしないでください。すべての色はトークンコンフィグのTailwindクラスを使用してください。
- 文字列をハードコードしないでください。strings.jsonのキーを使ってください。
出力先:src/screens/HomeScreen.tsx
IR→JSXマッピング
React + Tailwind向けの完全なマッピングテーブル:
| IR種類 | プロパティ | JSXパターン |
|---|---|---|
stack | axis: "vertical" | <div className="flex flex-col gap-ds-{n}"> |
stack | axis: "horizontal" | <div className="flex flex-row gap-ds-{n}"> |
overlay | レイヤーされた子 | <div className="relative"> + className="absolute ..."の子 |
absolute | x、y、w、h | <div className="absolute" style={{"{{"}}top: y, left: x, width: w, height: h{{"}}"}}> |
leaf | type: "text" | <span className="text-{size} font-{weight} leading-{lh} text-brand-{color}"> |
leaf | type: "rectangle" | <div className="bg-brand-{color} rounded-ds-{r}"> |
ギャップとパディング値:Tailwindコンフィグ拡張からのds-{n}スペーシングクラスを使います。ギャップ値がクリーンなトークンキーでない場合、Tailwindの任意値構文を使います:gap-[20px]。
実際の例:ホーム画面IRからJSXへ
Composeウォークスルーの同じIRを使います:
import strings from '../../design/strings.json'
export function HomeScreen() {
return (
<div className="flex flex-col gap-ds-24 p-ds-16 bg-brand-f6f2ea min-h-screen">
<h1 className="text-2xl font-bold leading-tight text-brand-1a1a2e">
{strings['home.title'].value}
</h1>
<div className="flex flex-col gap-ds-12">
<div className="bg-white rounded-ds-12 p-ds-16">
<span className="text-xs font-medium text-brand-7f5cfe">
{strings['home.card.label'].value}
</span>
</div>
</div>
</div>
)
}
すべてのclassNameは追跡可能です。gap-ds-24 → spacing.24 → 24px。text-brand-7f5cfe → color.7f5cfe → #7F5CFE。値がドリフトした場合(例:エージェントがgap-ds-24の代わりにgap-6と書く)、コードレビューで即座に見えます。
tokens.json + Tailwindコンフィグがうまく機能する理由
両システムはトークンファーストです。Tailwindはカスタム値でベースコンフィグを拡張します;tokens.jsonはすでにカスタム値マップとして構造化されています。拡張ステップ(上記のステップ2)は一度だけのセットアップです—その後、エージェントはデザインシステムに意味的に結び付けられたTailwindクラス名を使います。
結果:デザイントークンが変わると(プライマリカラーが#7F5CFEから#6B4EE6に変わるなど)、tokens.jsonの1つの値を更新し、コンフィグインポートを再実行し、Tailwindが再生成します。コンポーネントコードは変わりません。
トークンドリフトチェック
実装後、エージェントにドリフトを監査させます:
src/screens/HomeScreen.tsxのトークンドリフトを監査してください。
確認事項:
1. トークンコンフィグのTailwindクラスを通じて参照されていない16進カラー値。
2. ds-{n}クラスにすべきハードコードされたpxまたはremスペーシング値。
3. design/strings.jsonからソースされていないUI文字列。
違反をリストアップしてください。それらを修正するdiffを生成してください。
オーバーレイとアブソリュート — トリッキーなケース
オーバーレイノードはrelative親とabsolute配置の子が必要です。IRはz順で子をリストします(最初 = 最下層)。エージェントにJSXでこの順序を保持するよう指示してください—ReactはDOM順でレンダリングし、CSSposition: absoluteはそれに従ってスタックします。
アブソリュートノードはFigmaからの生のピクセル座標を使います。これらはほぼ常にオートレイアウトで構築されていないデザインから来ます。アブソリュートノードが多く見られる場合、通常はFigmaファイルが手動配置を持つことを意味します—生成されたコードは異なるビューポートサイズでは脆くなります。フラグを立てて、フレックスレイアウトにリファクタリングすることを検討してください。
ReactでのJSON文字列処理
Android(strings.jsonキーがR.string.*リソースIDにマッピング)とは異なり、ReactではJSONを直接インポートします:
import strings from '../../design/strings.json'
// 使用法
{strings['home.title'].value}
// またはフォールバックあり
{strings['home.title']?.value ?? strings['home.title']?.fallback ?? 'Untitled'}
i18nライブラリ(react-i18next、next-intl)を使っている場合、strings.jsonのドット記法キーは翻訳キー名前空間に直接マッピングされます。どのi18nライブラリを使っているかをエージェントに伝えてEDEK、正しいコールパターンを生成させてください。
Reactサイドの正直なギャップ
タイポグラフィユーティリティ。Tailwindのテキストユーティリティ(text-xs、text-2xl)はtokens.jsonのtypographyトークンと1:1でマッピングされません。Tailwindには固定の型スケールがあります;トークンファイルには任意のサイズがあります。TailwindのfontSizeコンフィグをトークン値で拡張するか、任意の値を使う必要があります(text-[24px])。両方動きます;コンフィグの拡張の方がきれいです。
行の高さ。同じ問題—Tailwindのleadingユーティリティは任意のlineHeight値にマッピングされません。leading-[{value}]を使うかコンフィグを拡張してください。
グラデーション。IRではサポートされていません。グラデーションフィルは_meta.jsonの警告として現れ、ノードのfillプロパティから省略されます。手動で処理してください。
これらはブロッカーではありません—既知のギャップです。トークン対応の基盤は堅固です;エッジは手動処理が必要なだけです。
figmascopeからバンドルをエクスポートして、このガイドをCursorワークフローまたはClaude Codeワークフローと一緒に使って実装を進めてください。