Communitygithub.com

figma-lens: Figma デザインに一致する UI を構築

Figma デザインからピクセルパーフェクトな UI を実装するためのスキルです。figma-lens のエクスポート(design/<frame>/spec.md, tokens.json, スクリーンショット, SVG アイコン)を使用し、Figma MCP や Dev Mode は不要です。ユーザーが「Figma から」画面やコンポーネントの構築、実装、一致、修正を依頼したり、design/ フォルダや figma-lens のエクスポートに言及したり、Figma フレームに一致する Flutter または Web(HTML/CSS/React/Tailwind)コードを希望する場合に使用します。

figma-lens: Figma デザインに一致する UI を構築 とは?

figma-lens は、Figma デザインからピクセルパーフェクトな UI を実装するための AI エージェントスキルです。このスキルは、Figma プラグインとローカルブリッジを使用して、選択したフレームを設計仕様(spec.md)、トークン、アセット、スクリーンショットとしてエクスポートします。エクスポートされたデータは design/ ディレクトリに整理され、エージェントは spec.md を読み取り、レイアウトツリー、変数、スタイル、アセットを把握します。その後、コンポーネントマップを使用して既存のウィジェットやトークンを再利用しながら、トップダウンで UI を構築します。比較・修正ループにより、実際のビルド結果と Figma デザインをスクリーンショット差分で比較し、不一致が 3% 以下になるまで修正を繰り返します。Flutter と Web(CSS/Tailwind/React)の両方をサポートし、各プラットフォーム向けのレイアウトマッピングテーブルを提供します。このスキルは、Cursor、Claude Code、Codex などの AI エージェントが、Figma デザインを正確にコードに変換する際のガイドとして機能します。

対応✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/MohamedRamadanSalah/figma-lens/tree/HEAD/skill/figma-lens

お気に入りのAIに質問する

このエージェントスキルを事前に読み込んだ状態で新しいチャットを開きます。

ドキュメント

figma-lens: Figma に一致する UI を構築

figma-lens は Figma プラグインとローカルブリッジを組み合わせたツールです。ユーザーが Figma デスクトップでフレームを選択し、Export to Claude をクリックすると、ブリッジがフレームごとに 1 つのフォルダを書き出します。

design/
  INDEX.md                  ← エクスポートされた全フレームの一覧(ここから開始)
  <frame>/
    spec.md                 ← 最初に読むこと: 正確な値を持つコンパクトなレイヤーツリー
    spec.json               ← spec.md だけでは不十分な場合の完全なデータ(+ Figma からのレイヤーごとの CSS)
    tokens.json             ← 変数(全モード)、スタイル、生の値の使用回数
    [email protected]           ← フルレンダリング(デフォルト 2x)
    sections/NN-name.png    ← トップレベルブロックの切り抜き(フル解像度)
    assets/*.svg            ← アイコン/ベクターアート、すぐに使用可能
    images/*                ← 画像フィルとして使用される元のビットマップ
    compare/                ← `figma-lens check` によって書き込まれる(report.md, side-by-side.png, diff.png)
figma-lens.map.json         ← (プロジェクトルート)Figma コンポーネント/トークン → このプロジェクトの実際のコード

figma-lens コマンドは figma-lens リポジトリの CLI です(npm link でグローバルに利用可能にできます。それ以外の場合は node <figma-lens>/bin/figma-lens.js … を実行します)。figma-lens help で全コマンドを確認できます。

エクスポートがまだない場合

  1. ユーザーのプロジェクト用にブリッジを起動し、バックグラウンドで実行し続けます: figma-lens bridge --out <project>/design
  2. ユーザーに Figma デスクトップでフレームを選択してもらい、プラグイン → 開発 → Figma Lens → Export to Claude を実行してもらいます。
  3. design/INDEX.md を読んで、エクスポートが到着したことを確認します。

エクスポートが可能な場合に、説明からデザインを推測しないでください。エクスポートを依頼してください。

ワークフロー

  1. spec.md を完全に読む(小さいファイルです)。フレームサイズ、レイアウトツリー、変数とスタイル、アセットを確認します。
  2. 画像を見る。 sections/*.png を 1 枚ずつ詳細に確認します。[email protected] は全体像を把握するためだけに使用します。大きな画像は表示時に縮小されるためです。値は常にスペックから取得し、ピクセルを測定することはしません。
  3. コンポーネントマップを使用する(「コンポーネントマップ」を参照)。spec.md 内の ⇒ USE … は必須です: そのウィジェット/コンポーネントとそのプロップマッピングを使用し、生の値の代わりにマップされたトークン((color/primary ⇒ AppColors.primary))を使用します。(not in map) とマークされた項目については、コードベース内で既存のテーマとウィジェット(Flutter では ThemeData、AppColors、TextTheme、間隔定数、lib/widgets、Web では CSS 変数、Tailwind 設定、src/components)を検索します。トークンが存在しない場合のみ生の値を使用し、どのトークンを追加したかをユーザーに伝えます。
  4. コンポーネントを再利用する。 component Button {Type=Primary} とマークされたレイヤーは、プロジェクトの既存の Button ウィジェットまたはコンポーネントを一致するプロップで使用する必要があります。存在しない場合のみ新しいものを作成し、再利用可能にしてマップに追加します。
  5. トップダウンでツリーに従って構築する。 オートレイアウトは Row/Column/flex にマッピングされます(以下の表を参照)。@x,y レイヤー(オートレイアウトがない、または absolute)のみ Stack/Positioned または絶対配置が必要です。
  6. エクスポートされたファイルを使用する。 assets/*.svg と images/* をプロジェクトのアセットフォルダに配置し、参照します。アイコンを再描画したり、別のアイコンセットに置き換えたりしないでください。
  7. テキストは spec.md の "…" から正確にコピーする。 大文字小文字、句読点、アラビア語/RTL 文字列を含みます。複数の run 行があるテキストはリッチテキスト(TextSpan / ネストされたスパン)が必要です。
  8. 比較と修正のループ(下記)で検証する。コードを読んだだけで画面が完成したと宣言せず、スクリーンショットの差分で証明してください。

比較と修正のループ

画面を構築した後、実際の結果を Figma と比較し、異なる部分を修正します:

  1. ビルドを実行してその画面を表示します:
    • Web: 開発サーバーを起動し、ルートを開きます。
    • Flutter web: flutter run -d web-server --web-port 8080 を実行し、その URL を使用します。
    • Flutter Android: エミュレーター/デバイスでアプリを実行し、画面に移動します。
  2. チェックする:
    • Web / Flutter web: figma-lens check --design design/<frame> --url http://localhost:<port>/<route> (ビューポートはフレームのサイズとスケールに自動的に設定されます)。
    • Android: figma-lens check --design design/<frame> --adb --crop-top <ステータスバー px> [--crop-bottom <ナビゲーションバー px>] (ステータスバー ≈ 24–48 dp × デバイス密度; アプリコンテンツのみが比較されるように切り取ります)。
  3. design/<frame>/compare/report.md を読む(不一致率、最大の差異領域、および各領域の Figma レイヤー ID)そして compare/side-by-side.png を見る(Figma | ビルド | 差分、赤 = 異なる部分)。
  4. トップダウンで修正する: 最初に高さまたは間隔の違い(それ以降のすべてをずらす)、次にサイズ、色、タイポグラフィ、半径、シャドウ。リストされた各レイヤー ID を spec.md で調べて正確な値を確認します。
  5. チェックを再実行する。 レポートには前回のスコアが表示されるため、進捗状況を確認できます。
  6. 不一致が 3% 以下になったら停止する(テキストのアンチエイリアシングは 0 にはなりません)、または連続する 2 回の実行で改善が見られなくなったら停止します。その後、最終スコアと一致させられなかった項目、およびその理由(フォントの欠落、プラットフォームのレンダリング、動的データ)を報告します。

ルール: 実際のコードを修正し、差分を不正に操作しないこと(アプリ内にデザインのスクリーンショットや画像を入れない)。チェック時にはデザインと同じデータ/テキストを使用します(必要に応じてモックデータ)。そうしないと、テキストの違いがスコアを支配します。

コンポーネントマップ

figma-lens.map.json(プロジェクトルート)は、Figma コンポーネントとトークンをこのプロジェクトのコードにマッピングします:

{
  "components": {
    "Button": { "flutter": "lib/widgets/app_button.dart#AppButton", "web": "src/components/Button.tsx#Button", "props": { "Label": "label", "Type": "variant" } },
    "Icon/*": "SvgPicture.asset('assets/icons/<name>.svg')"
  },
  "tokens": { "color/primary": { "flutter": "AppColors.primary", "web": "var(--color-primary)" } }
}
  • マップがまだない場合 → figma-lens map --design design を実行します。これにより、エクスポートからすべてのコンポーネントとトークンが空の値("")で追加されます。
  • 自分で入力する: コードベース内で各コンポーネント(名前、外観、プロップで)と各トークン値を検索し、path#Symbol(または式)を記述します。まだ何も存在しない場合のみ "" のままにします。"Prefix/*" はファミリー全体(アイコン)に一致します。
  • マップを編集した後、figma-lens render design/<frame> を実行して、spec.md に ⇒ USE 矢印が表示されるようにします。ブリッジは新しいエクスポートごとにマップも適用します。
  • マップされていないコンポーネントに対して新しい再利用可能なウィジェットを作成した場合は、マップに追加します。

spec.md の読み方

  • 単位はデザインピクセル(design px)で、CSS px および Flutter の論理ピクセル(logical px)と同じです。スクリーンショットのスケールを掛けないでください。
  • row|column gap G pad t,r,b,l main:X cross:Y はオートレイアウトです。pad 16 は四辺すべてが 16 であることを意味します。gap auto は space-between を意味します。
  • w:FILL h:HUG は各軸のサイズ設定を示します: FIXED(表示される正確なサイズ)、HUG(コンテンツに合わせる)、または FILL(利用可能なスペースを取る)。
  • @x,y は親要素内の位置です。absolute はオートレイアウト内の絶対配置された子要素を意味します。pin H/V は制約を示します(MIN = left/top、MAX = right/bottom、STRETCH = 両方、CENTER、SCALE)。
  • bg A + B はペイントを下から上にリストします。(name) は Figma 変数、[style name] は Figma スタイルです。
  • 色は #RRGGBB または #RRGGBBAA(アルファは最後)です。
  • テキストは "chars" · Family Style (weight) size/lineHeight color の形式を使用します。lineHeight は px、%、または auto です。ls は文字間隔(px)、またはフォントサイズの % です。
  • radius 12 はすべての角を設定します。radius tl,tr,br,bl は各角を設定します。smoothing は iOS スタイルの角のスムージングです。近似するか、Flutter でスクアークルパッケージが使用されていない限り無視します。
  • drop-shadow x,y blur B spread S color、inner-shadow、layer-blur R、background-blur R。
  • → assets/x.svg はレイヤーがアイコンであることを意味します。リストされたサイズで SVG を使用します。
  • vars{itemSpacing=space/md} はレイヤープロパティがその変数にバインドされていることを意味します。トークンを使用します。

Flutter マッピング

FigmaFlutter
column / rowColumn / Row(Flutter ≥ 3.27 では spacing: G を使用、それ以外は SizedBox ギャップ)
wrap, rowGap RWrap(spacing: G, runSpacing: R)
pad t,r,b,lPadding(padding: EdgeInsets.fromLTRB(l, t, r, b))。順序に注意。
main MIN / CENTER / MAX / SPACE_BETWEENMainAxisAlignment.start / center / end / spaceBetween
cross MIN / CENTER / MAX / BASELINECrossAxisAlignment.start / center / end / baseline(baseline には textBaseline が必要)
主軸上の HUGmainAxisSize: MainAxisSize.min
親の主軸上の FILLExpanded(または Flexible); grow N は flex: N を設定
親の交差軸上の FILL親で CrossAxisAlignment.stretch、または SizedBox(width: double.infinity)
FIXED w×hSizedBox(width: w, height: h)
@x,y / absoluteStack + Positioned(left: x, top: y); 右/下には pin を使用
bg 単色BoxDecoration(color: Color(0xAARRGGBB))。アルファを先頭に移動: #11223380 → 0x80112233
グラデーション線形 from/toLinearGradient(begin: Alignment(fx*2-1, fy*2-1), end: Alignment(tx*2-1, ty*2-1), colors, stops) を使用。from/to は spec.json から
radiusBorderRadius.circular(r) または BorderRadius.only(...)
境界線 W 色 insideBorder.all(width: W, color: …)(inside は Flutter のデフォルト; center/outside は strokeAlign が必要)
drop-shadow x,y blur B spread SBoxShadow(offset: Offset(x, y), blurRadius: B, spreadRadius: S, color: …)
background-blur RClipRRect + BackdropFilter(filter: ImageFilter.blur(sigmaX: R/2, sigmaY: R/2))
不透明度Opacity(またはペイントの色アルファ)
テキスト size/lineHeightTextStyle(fontSize: size, height: lineHeight / size)。% の場合: height: pct/100。Figma の垂直方向の中央揃えに合わせるには leadingDistribution: TextLeadingDistribution.even を設定。
ウェイト 600FontWeight.w600
ls px / ls %letterSpacing: px / letterSpacing: size * pct / 100
省略記号 maxLines NmaxLines: N, overflow: TextOverflow.ellipsis
align CENTERtextAlign: TextAlign.center。RTL 画面の場合は TextAlign.start と EdgeInsetsDirectional を使用。
assets/x.svgSvgPicture.asset('assets/…/x.svg', width:, height:)(flutter_svg)
画像フィル FILL / FITImage.asset(fit: BoxFit.cover / BoxFit.contain)

Web(CSS / Tailwind / React)マッピング

FigmaCSS
column / rowdisplay:flex; flex-direction: column / row; gap: Gpx
wrap, rowGap Rflex-wrap: wrap; column-gap: G; row-gap: R
pad t,r,b,lpadding: t r b l(CSS と同じ順序)
main MIN / CENTER / MAX / SPACE_BETWEENjustify-content: flex-start / center / flex-end / space-between
cross MIN / CENTER / MAX / BASELINEalign-items: flex-start / center / flex-end / baseline
HUGwidth/height: fit-content(または単に auto)
FILL(主軸)flex: 1 1 0; min-width: 0
FILL(交差軸)align-self: stretch
FIXEDwidth: Wpx; height: Hpx; flex-shrink: 0
@x,y / absolute親 position: relative; 子 position:absolute; left:x; top:y(右/下には pin を使用)
色 #RRGGBBAAそのまま有効な CSS
グラデーション線形 Ndeglinear-gradient(Ndeg, c1 p1%, c2 p2%)
drop-shadowbox-shadow: x y B S color(inner-shadow は inset を追加)
layer-blur / background-blur Rfilter: blur(R/2 px) / backdrop-filter: blur(R/2 px)
テキストfont: weight size/lineHeight family; letter-spacing(ls % → pct/100 em)
省略記号 maxLines Ndisplay:-webkit-box; -webkit-line-clamp:N; -webkit-box-orient:vertical; overflow:hidden
assets/x.svg<img src> またはインライン SVG; エクスポートされたサイズを維持

spec.json には、ほとんどのレイヤーに対して Figma が生成した CSS(css)も含まれています。CSS 値をクロスチェックするために使用します。トークンとレイアウト構造は引き続き上記のツリーから取得します。

ルール

  • スペックの値は画像で見えるものより優先されます。矛盾する場合はスペックを信頼し、矛盾点を指摘してください。
  • ユーザーがトークンへの正規化を依頼しない限り、値を丸めたり「改善」したりしないでください(14 は 14 のまま、16 にしない)。
  • 非表示のレイヤーはエクスポートされません。エクスポートに含まれていない状態(ホバー、エラー、空)をでっち上げないでください。それらのフレームを依頼してください。
  • 欠落しているフォントを報告してください。フォントファミリーがプロジェクトにバンドルされていない場合は、その旨を伝え、ユーザーに何を追加すべきか(pubspec フォント / @font-face)を指示します。
  • 複数のブレークポイントや状態がある場合は、ユーザーに各フレームをエクスポートするよう依頼してください。それぞれが独自のフォルダになります。

関連スキル