figma-codegen について
figma-codegenは、Figmaの選択範囲をコードに変換するスキルで、既存のコードベースになじむ実装を求める開発者向けです。デザイン構造やコンポーネント、トークンの対応関係を根拠に生成し、デザイン差分に基づく段階的な更新にも対応します。
主な機能
- 01Figmaの構造とデザイントークンを取得
- 02デザイン部品をコード部品に対応付け
- 03プロジェクトのトークンとスタイルを再利用
- 04画像アセットの出力とアイコンの対応付け
- 05デザイン変更を検出してコードを段階更新
- 06確認済みの部品・トークン対応を記録
活用シーン
- 01Figmaの選択範囲からUI部品を実装
- 02既存プロジェクトの部品にデザインを適合
- 03デザイン変更後に該当コードだけを更新
- 04後続作業で再利用する対応関係を記録
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ awdr74100/ figwright --skill figma-codegenインストール後、Claude Code で/figma-codegenを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/assets-and-icons.mdgrounding.mdmotion.mdresponsive.mdstylesheets.mdverify.md詳細
figma-codegen
Figma の選択範囲を、プロジェクトのほかの部分になじむコードに変換します。すでにあるコンポーネントやトークンを再利用し、本当に不足しているものだけを作成します。根拠のあるツールが大部分の作業を担うため、スクリーンショットを見て推測する必要はありません。このファイルはルーターです。詳しい説明は references/ にあります。該当する手順に進んだら、参照ファイルを読み込んでください。
使用するタイミング
- ユーザーが Figma の URL/選択範囲を貼り付けて、コードの作成を依頼した場合(「これをコードにして」「このコンポーネントを作って」など)。
- ユーザーが既存のコンポーネントを Figma のフレームに合わせて拡張したい場合。
複数の Figma ファイルを開いている場合
該当するときはツールの結果にその旨が示されるため、事前に確認する必要はありません。2 つ以上のファイルが接続されていて、どのファイルも指定されていない場合、結果にはファイル名を示す MORE THAN ONE FIGMA FILE IS OPEN ブロックが含まれます。これは重要です。指定しない場合、呼び出しはユーザーが最後に操作したファイルに従いますが、タブを切り替えると対象が変わるためです。その結果、あるファイルを読み取って別のファイルに書き込み、それでも成功と報告してしまう可能性があります。
このブロックが表示されたら、ほかの作業を始める前にファイルを指定してください。list_files で接続されているすべてのファイルを確認し、use_file({ fileName }) でこのセッションに使用するファイルを指定します。同じ名前のファイルを 2 つ開いている場合は use_file({ sessionId }) を使ってください。Figma では同名のファイルを開くことができ、x (Copy) のような名前になることがあります。その後の呼び出しは、タブがバックグラウンドにある間も含め、常にそのファイルを対象にします。ユーザーがどのファイルか指定していない場合は、名前から推測せずに確認してください。
ワークフロー
選択範囲に対して根拠のあるツールを実行してから、コードを生成します。レンダリング画像よりも、ツールの結果を信頼してください。
get_design_context(詳細度full、dedupeComponents: true)→ トークンが名前(Primary/500、spacing/4)に解決され、スタイルがglobalVarsに重複なくまとめられ、各インスタンスにmainComponent/componentPropertiesが含まれる構造ツリーを取得します。これがレイアウトとバインディングの信頼できる情報源です。dedupeComponents: trueを維持し、構築するサブツリーに深度制限を設けないでください。 → ツリーの読み方、ノードごとの忠実度カタログ(エフェクト、辺ごとの境界線、ストロークの配置、角ごとの角丸、ブレンド、マスク、グラデーション、画像のフィット方法、パターン、Figma Draw のリピートグループ/ブラシストローク/パス上のテキスト、自動レイアウト/グリッド、アスペクト比、スクロール/スティッキー、スタックとストロークスペース)、正確な情報源としての Dev Mode の注釈、1 回の呼び出しには大きすぎるページの情報を取得する方法については、references/grounding.mdを参照してください。component_map→ すべての Figma コンポーネントを、status(high / medium / low / unmapped)、candidate.filePath、matchedPropsを持つローカルコードコンポーネントにグループ化したもの。high/medium: そのコンポーネントを再利用します(candidate.filePathからインポート)。再生成しないでください。component_mapが報告しなかったコンポーネント名を勝手に作らないでください。candidate.ambiguousWith({ name, filePath }の上限付きリスト): Figma の名前が 2 つ以上のコードコンポーネントにほぼ等しく一致し、結合処理が自信を持って選択できなかったもの — これは要確認の選択であり、確信を持った再利用ではありません(token_mapのambiguousWithに相当します)。インポートする前に、当選したcandidateとこれらの次点候補のうち、この コンテキストにとって正しいコンポーネントがどれかを確認してください(誤った再利用はサイレントな視覚的バグになります)。その後、確認できたものをマップファイルに記録して、次回の実行で確実に判断できるようにします。選択が曖昧でなかった場合は存在しません。- 各エントリの
instances[].props(解決済みの variant / boolean / text の値)を再利用するコンポーネントに結び付けてください — インスタンスごとに 1 つの要素とし、それぞれ独自の props を持たせます。 candidate.unmatchedProps: そのコンポーネントに対応する prop が存在しない Figma の軸(先頭アイコン、requiredフラグ、アクティブ状態など)→ コンポーネント拡張の TODO として提示し、その場しのぎのマークアップで偽装しないでください。unmapped: プロジェクトのスタイルで新規に構築します。繰り返し現れる unmapped コンポーネント(instanceCount > 1)の場合は、その最初のインスタンスのサブツリーから構築します。それがdeduped/truncatedで返ってきた場合は、instances[0].nodeIdに対して一度get_design_contextを実行してください — 繰り返し現れるコンポーネントを目分量で再構築しないでください。- コンポーネントの自身の定義を出力する場合(それをレンダリングするだけでなく、その prop 型を扱う場合)、コンポーネント/インスタンスに対して
get_component_apiを実行すると完全なプロパティ API が返ります — すべての VARIANT オプションと、各 BOOLEAN/TEXT/INSTANCE_SWAP prop をそのデフォルト値とともに — これにより prop 空間が推測ではなく根拠に基づいたものになります。 - その API は prop の名前を示し、ツリーはそれぞれが駆動するレイヤーを示します。COMPONENT または INSTANCE 内のサブレイヤーは
componentPropertyReferences({ characters | visible | mainComponent: "PropName#1:2" })を持ちます。そのレイヤーを、たまたまレンダリングしている内容ではなく prop に結び付けてください。characters: "Label#1:2"は{props.label}であり、デザイン内のリテラル文字列ではなく、visible: "Show Badge#3:4"は条件付きでレンダリングされます。これがないと、正しいマークアップを出力しても props がまったくない状態になり、すべてのインスタンスが、あなたが見たものの値に固定されてしまいます。
token_map→ すべての Figma 変数が、status+ref+matchedByとともにプロジェクトのトークンに結び付けられています。 ドキュメントの共有ペイントスタイル(単色のスタイル。変数以前のファイルで使われるトークンの仕組み)も、source: 'style'として示され、同じ方法で結び付けられます。- マッピング済み:参照先は
candidate.ref(bg-primary-500、var(--color-primary-500))です。get_design_contextで解決された生の hex/px 値は決して使いません。色のmatchedBy: ['name'](値にずれがある)の場合は、それを使いつつ不一致を明示します。 candidate.ambiguousWith(複数のプロジェクトトークンがまったく同じ値を共有し、名前で区別できない場合):選択肢が限定され、確認が必要な候補です。コンテキストに意味的に合う方の兄弟トークンを選びます(または値を維持して差異を明示します)。確定済みの再利用として扱ってはいけません。- 変数がほとんどない、またはまったくないドキュメント(実際のファイルの多くが該当します)では、
get_design_context独自のprojectTokensマップがフォールバックになります。ペイロード内の生の色のうち、プロジェクトトークンの値と完全に一致するものは、そこで注釈が付けられます({ "#6266F0": { ref, name, matchedBy: ["value"] } })。hex 値をハードコードする前に照合し、意味的にコンテキストに合う場合はrefを出力します。matchedBy: ["value"]は、名前に依存しない値の一致を根拠とするエントリです。確定した結び付けではなく、検証が必要な仮説です。candidatesを含むエントリは、同じ値を持つトークンの中から意味に基づいて選ぶ必要があります。意味的に誤ったトークンは生の値より悪いため、生の値を維持して差異を記載します。また、結び付け済みの Figma 変数は、生の値の一致より常に優先されます。 framework-builtin(プロジェクトのユーティリティフレームワーク(Tailwind または UnoCSS)に組み込まれたスケール値。例:spacing/4、line-height/7、weight/Bold):builtin: { scale, step }を持ちます。任意のp-[16px]ではなく、ユーティリティ(p-4/gap-4、leading-7、font-bold)を組み合わせて使います。これは差異ではありません。from(SCSS 変数):参照先だけでは解決されません。作成するファイルで宣言元のファイルをインポートする必要があります。また、fromはリポジトリ相対パスですが、Sass はインポートするファイルを基準に@useを解決するため、書き込み先の場所を基準に再解決します。src/components/card.scssから参照する場合、from: src/styles/_tokens.scssは@use '../styles/tokens' as *となり、リポジトリ相対パスをそのまま使うことはありません。as *を指定すると、指定されたとおりのrefを使えます。プロジェクト独自の@useスタイルにより、名前空間を付けることもあります(@use '../styles/tokens'なら$color-primary-500はtokens.$color-primary-500になります)。インポートせずにrefを出力すると、スタイル上の軽微な問題ではなく、コンパイルエラーになります。unmapped:値を使いつつ、差異を明示します(トークンソースへの追加を提案します)。黙ってハードコードしてはいけません。figmaModes({ Light: …, Dark: … }。ファイルのテーマ軸はthemedCollectionsにあります):トークンはテーマに依存しています。figmaValueはデフォルトモードの値にすぎず、全体を表すものではありません。マッピング済みの場合:candidate.refを出力し、プロジェクトのトークン自体がテーマに応じて切り替わること(.dark/[data-theme]/prefers-color-scheme/dark:の仕組み)を確認します。プロジェクトが値を1つしか定義していない場合は、もう一方のモードの値をその仕組みに接続するか、テーマの差異を明示します。未マッピングの場合:デフォルトモードをベースとし、他のモードはプロジェクトのダークモードの仕組み(dark:バリアント/prefers-color-scheme)に従います。ネイティブモードを使わずにエンコードされたテーマ(ペアのコレクションや名前グループ(Color/Light/*+Color/Dark/*、プランで制限される場合の回避策))も同様に扱います。variableModes({ color: "Dark" })を持つノードは、そのモードで描画されます。同じトークン名を使い、そのモードの値が適用されます。トークン参照を維持し、そのモードに対応するプロジェクトの仕組みの下にサブツリーを配置します。同じものを表す Light と Dark のフレームは、2つのテーマに対応した1つのコンポーネントです。 →references/grounding.md。
- マッピング済み:参照先は
- グラウンディングで扱えないアセットをエクスポートする — ロゴ、写真、アイコンにはピクセルがなく、そうでなければ灰色のブロックとしてレンダリングされます。
IMAGEフィルノードにはsave_image_fills(クリップされた再レンダリングではなく元のアセット)、アイコンにはまずicon_map(キュレーションされた.svgを再利用)、合成後の見た目にのみget_screenshotを使います。 → アセット/アイコン/svg/カラーコントラクトの完全なワークフロー:references/assets-and-icons.md。
次に、検出されたスタックでコードを出力します(プロファイルは component_map / token_map で返されるため、自分で analyze_project を呼び出す必要はありません)。再利用するコンポーネントを組み立て、マッピングされていない部分をラップし、カラー/スペーシング/半径/タイポグラフィにトークン参照を適用します。
デザインの変更に合わせてコードを同期させる
コード生成が一発で終わることはほとんどありません — デザインは動き続けます。2 回目のパスを再生成ではなくインクリメンタルな編集にするには:
- 生成した後、セクション/コンポーネントの
nodeIdに対してdesign_diffを実行すると、ベースライン(そのget_design_context)が.figwright/snapshots/に保存されます。このファイルをコミットすれば、チームメイトがベースラインを共有できます。ツールが git に触れることはありません。 - 再同期を求められたとき(「デザインが変わったのでコンポーネントを更新して」)、同じ
nodeIdに対して再度design_diffを実行します。ノード単位・プロパティ単位の差分が返されます — 解決済みの値(フィル、パディング、テキスト文字列、トークンの再バインド)を持つadded/removed/changedノードで、それぞれに読めるpath(Card / Header / Title)が付きます。それらのノードがマッピングするコードだけを編集してください。画面を再生成しないでください。変更された各値は通常どおりグラウンディングします(これはget_design_contextのスライスです)。その後、update: trueを付けてdesign_diffを実行し、新しいデザインをベースラインとして受け入れます。 - コードを書いたときと同じ
nodeId単位でスコープを設定します。no-changesは、ベースライン以降デザインが変更されていないことを意味します — 何もする必要はありません。 - Motion は例外です。 スナップショットは完全な重複排除済みの
get_design_contextであり、Motion のサマリー(プリセット名、アニメーション対象のフィールド名、タイムラインの長さ)しか含みません — そのため、変更されたキーフレームの時間、値、イージング、あるいはプリセットの設定やプロパティがno-changesとして返ることがあり、重複排除で折りたたまれたインスタンスの子にはサマリーがまったく含まれません。アニメーションを再同期するには、ルートに対してget_motion_contextを再実行し、コードが実装している内容と比較してください。
検証済みのマッピングを記録する(次回の実行で再推測せずに再利用できるようにする)
結合は実行のたびに最初から導き直されます。再利用したコンポーネントが正しく描画された、曖昧な色を意味的に正しいトークンに解決したなど、確認済みのマッピングは、次回の実行で再推測せず、確定情報として扱えるよう記録する価値があります。追記専用のマップファイルが2つあり、それぞれ結合処理が最優先の情報源として読み込みます。
-
docs/figma-component-map.md—| FigmaName | code/path |形式の行(またはFigmaName -> path)。component_mapはそのコンポーネントをsource: 'map-file'、confidence 1 で返します。 -
docs/figma-token-map.md—| FigmaName | ref |形式の行。token_mapはmatchedBy: ['map-file']、confidence 1 で返します。refは出力する値で、ユーティリティ(bg-primary-500)、var(--color-primary-500)、またはトークン名そのものです。 -
記録した行は、以降の実行すべてでファジー結合より優先されます。証拠を記録し、単なる選択は記録しないでください。 判定基準は、自分で検証することです(§ レスポンシブ対応と検証):結果を描画し、Figma ノードと一致したことを確認してから、_実証した_マッピングを記録してください。誤った行があっても明確なエラーにはなりません。人が気づくまで、以降の生成すべてでそのコンポーネントやトークンが誤ってマッピングされ続けます。記録しないよりも悪い結果です。確信がない場合は記録しないでください。次回の再推測なら復旧できますが、確信を持って記録した誤った行は復旧できません。
-
記録するのは、結合処理が迷ったマッピングだけです。 確認できた
low/mediumのコンポーネントマッチ、新たに作成したunmappedコンポーネント(新しいファイルを記録)、またはambiguousWith/matchedBy: ['value']/unmappedで返され、意味に基づいて解決したトークンが対象です。すでにhighの決定的なマッチは省略してください。正しく導き直されるので、それらの行はノイズになるだけです。 -
これらのファイルはコミット対象のプロジェクトドキュメントです。行はメモ書きではなく、正しいと断言するコードの1行として扱ってください。 1つの figma 名に対して、1行につきターゲットは1つだけにし、レビューしやすい状態を保ってください。
-
ファイルの健全性を保ってください。
component_map/token_mapがstaleOverrides(記録したターゲットが解決できなくなった状態。ファイルまたはトークンの名前が変更または削除された場合に発生)を報告した場合、結合処理はすでにファジーな結果に劣化しています。その行を新しいターゲットに更新するか、削除してください。
レスポンシブ対応と検証
- 初期状態でレスポンシブにします — ルートは
w-fullとし、アートボードの固定幅は使いません。ブレークポイントはファイル内の他の幅のフレームを基準にします。→references/responsive.md。 - 完了とする前に、見た目を検証してください — プロジェクトのツールチェーンで描画し、デザインのビューポートでスクリーンショットを撮って、Figma ノードと比較し、ソースから修正します。
→
references/verify.md。
モーション(アニメーション)
実装するルートごとに、get_motion_context を一度呼び出してください。サブツリー内のすべてのモーションソース(インスタンスの子要素を含む)を一覧表示し、読み取れなかったものを報告します。ノードがなく、coverage.status: "complete" の場合に限り、アニメーションはありません。その場合、get_design_context の motion サマリーは、重複排除や予算の対象から外せるというヒントです。取得した内容はプロジェクト独自のアニメーション機構で実装し、リファレンスに記載された計測済みのルールに従って読み取ってください。トラックの合成、ループ、トリガーなど、どちらにも明示されていない事項は自分の仮定として扱い、そのことを明記してください。そのうえで、結果をソースと照らし合わせて検証します。フレームのアニメーションを省略するのは、影を省略するのと同じ種類の忠実度の欠落です。
→ references/motion.md。
ルール
- すべてのセクションで根拠を確認してください。スクリーンショットから値を目測してはいけません。 すべてのセクションで、px サイズ、色、フォントサイズ、角丸、間隔はすべて
get_design_contextから取得してください。スクリーンショットは視覚的な意図を示すものにすぎません。「簡単なセクション」だけ推測するのは、重大な見落としです。一度に根拠を確認するにはページが大きすぎる場合は、セクションのnodeIdで範囲を絞ってください。ページ全体に深さの上限を設けたり、大きすぎる呼び出しを再試行したりしてはいけません。 - 再生成より再利用を優先してください。
high/mediumのcomponent_map候補は、インポートして使用する必要があります。 - リテラルではなくトークンを参照してください。 マッピング済み変数の
refを出力し、生の値はunmappedの不足箇所に限って使用し、その不足箇所を隠さず明示してください。 - すべての視覚的プロパティを反映し、忠実度を損なわないでください。 エフェクト、各辺のボーダーと
strokeAlign、各コーナーの角丸、ブレンドモード、マスク、グラデーション、画像のscaleMode、パターンのタイリング、繰り返しグループのコピー(repeatTransforms)、オートレイアウト/グリッドの間隔は、すべてコンテキストに含まれています。それぞれを反映してください(一覧はreferences/grounding.mdを参照)。いずれかを省略するのは単純化ではなく、根拠の確認漏れです。繰り返しグループを一度だけ描画すると、12目盛りのダイヤルに目盛りが1つしかない状態になります。 - 視覚アセットを書き出し、偽造しないでください。 グレーのボックスや手入力のワードマークは不適切です。
- 独自のスタイルではなく、プロジェクトに合わせてください。 既存のインポートスタイル、ファイル構成、命名規則に合わせてください。
- クラス名は省略せずに記述し、
&から組み立てないでください。&が連結を意味する言語(SCSS/Sass/Less/Stylus/postcss-nested)では、.card { &__title {} }は.card__titleにコンパイルされます。これはコンパイル後にしか存在しない名前であり、マークアップが持つクラスはソースのどこにも現れません。そのため、ルールを1つ調整するにも__titleのような断片を検索し、該当する結果をすべて読む必要があります。代わりに、トップレベルでフラットに宣言してください。profile.styling.classNaming(component_map/token_map上)は、プロジェクト独自の慣習を示します。プロジェクトの慣習を優先してください。ampersandの場合は&__titleを記述し、flatまたは指定がない場合はフラットに記述してください。 → 修正方法に見えて実際にはそうではない子孫セレクターの落とし穴と、&が今も適切な場面については、references/stylesheets.mdを参照してください。 - 完了とする前に、レンダリングして確認してください。(
references/verify.mdを参照してください。) - 設定ファイルやウィザードのプロンプトは決して作成しないでください。すべてプロジェクトとツールから推測します。