AIフレンドリーなFigmaデータとは?
X-tech推進本部 倉原見た目が同じでも、中身が違えば生成されるコードも変わります。コンポーネント、バリアブル、オートレイアウト――Figmaの機能を活用した設計とそうでない設計を、Figma MCP Serverのget_design_contextを通して比較します。
Figma MCP Serverのget_design_contextとは
Figma MCP Serverツールとは、AIがFigmaから情報を引き出すために自律的に呼び出す「関数」のことです。
Figma MCP Serverでは、以下のようなツールが使用可能です。
get_design_contextget_variable_defsget_code_connect_mapget_screenshotcreate_design_system_rulesget_metadataget_figjam
AIはMCPサーバーを経由して、これらのツールを使ってFigmaから各デザインデータを取得できます。生成AIはこれらのツールを駆使してデータを取得し、そのデータを基にフロントエンド実装を行います。
その中でget_design_contextはFigmaのデザインをReactとTailwindベースのコードとして取得するツールです。
AIフレンドリーなFigmaデザインとは
Figma MCP Serverの公式ドキュメントには次のような記載があります。
Structure your Figma file for better code
Provide the best context for your design intent, so the MCP and your AI assistant can generate code that's clear, consistent, and aligned with your system.
- Use components for anything reused (buttons, cards, inputs, etc.)
- Link components to your codebase via Code Connect. This is the best way to get consistent component reuse in code. Without it, the model is guessing.
- Use variables for spacing, color, radius, and typography.
- Name layers semantically (e.g. CardContainer, not Group 5)
- Use Auto layout to communicate responsive intent.
中略...
- Use annotations and dev resources to convey design intent that's hard to capture from visuals alone, like how something should behave, align, or respond.
要約すると下記のようになります。
- 再利用するものにはコンポーネントを使っていること。
- Code Connectを使って、コンポーネントをソースコードにリンクさせていること。
- バリアブルを使っていること。
- レイヤーに意味的な名前を付けていること(例:
Group 5ではなくCardContainer)。 - AutoLayoutを使って、レスポンシブの意図を伝えていること。
- アノテーションを使って、挙動や配置などビジュアルだけでは捉えにくい意図を伝えること。
つまり、これらを満たしているFigmaデザインがAIフレンドリーなFigmaデザインであると言えます。
検証
ここに2つのヘッダーデザインを用意しました。
Aデザイン案
Bデザイン案
見た目はほとんど同じですが次のような違いがあります。
Aデザイン案
- テキストがダミーである。
- コンポーネントを使っていない。
- バリアブルを使っていない。
- AutoLayoutを使っていない。
- レイヤーの名前がContentのみ。
Bデザイン案
- テキスト内容が実際に使う内容になっている。
- 再利用するパーツにはコンポーネントを使っている。
- バリアブルを使っている。
- AutoLayoutを使っている。
- レイヤーの名前を意味的なものにしている。
Aデザイン案は全くAIフレンドリーではないFigmaデータで、Bデザイン案はAIフレンドリーなデザインデータです。
では、これらのFigmaデザインからデータを取得するために、Figma MCP Serverのget_design_contextを実行しましょう。すると次のようなコードが返ってきます。
Aデザイン案からget_design_contextで取得したコード
const imgContent = "http://localhost:3845/assets/9ea1d243d60bf2ec9b470cf94fd9d951d3a7a569.svg";
export default function Content() {
return (
<div className="bg-white relative size-full" data-name="content" data-node-id="192:527">
<div className="absolute h-[28px] left-[39px] top-[30px] w-[164px]" data-name="content" data-node-id="192:528">
<img alt="" className="block max-w-none size-full" src={imgContent} />
</div>
<div className="absolute h-[28px] left-[418px] top-[30px] w-[632px]" data-name="content" data-node-id="192:544">
<div className="absolute h-[28px] left-0 top-0 w-[56px]" data-name="content" data-node-id="2002:268">
<p className="absolute css-ew64yg font-['Noto_Sans_JP:Regular',sans-serif] font-normal leading-[28px] left-0 text-[#343640] text-[length:var(--font\/size\/14,14px)] top-0" data-node-id="2002:269">
テキスト
</p>
</div>
<div className="absolute h-[28px] left-[96px] top-0 w-[56px]" data-name="content" data-node-id="2002:270">
<p className="absolute css-ew64yg font-['Noto_Sans_JP:Regular',sans-serif] font-normal leading-[28px] left-0 text-[#343640] text-[length:var(--font\/size\/14,14px)] top-0" data-node-id="2002:271">
テキスト
</p>
</div>
<div className="absolute h-[28px] left-[192px] top-0 w-[56px]" data-name="content" data-node-id="2002:272">
<p className="absolute css-ew64yg font-['Noto_Sans_JP:Regular',sans-serif] font-normal leading-[28px] left-0 text-[#343640] text-[length:var(--font\/size\/14,14px)] top-0" data-node-id="2002:273">
テキスト
</p>
</div>
<div className="absolute h-[28px] left-[288px] top-0 w-[56px]" data-name="content" data-node-id="2002:274">
<p className="absolute css-ew64yg font-['Noto_Sans_JP:Regular',sans-serif] font-normal leading-[28px] left-0 text-[#343640] text-[length:var(--font\/size\/14,14px)] top-0" data-node-id="2002:275">
テキスト
</p>
</div>
<div className="absolute h-[28px] left-[384px] top-0 w-[56px]" data-name="content" data-node-id="2002:276">
<p className="absolute css-ew64yg font-['Noto_Sans_JP:Regular',sans-serif] font-normal leading-[28px] left-0 text-[#343640] text-[length:var(--font\/size\/14,14px)] top-0" data-node-id="2002:277">
テキスト
</p>
</div>
<div className="absolute h-[28px] left-[480px] top-0 w-[56px]" data-name="content" data-node-id="2002:278">
<p className="absolute css-ew64yg font-['Noto_Sans_JP:Regular',sans-serif] font-normal leading-[28px] left-0 text-[#343640] text-[length:var(--font\/size\/14,14px)] top-0" data-node-id="2002:279">
テキスト
</p>
</div>
<div className="absolute h-[28px] left-[576px] top-0 w-[56px]" data-name="content" data-node-id="2002:280">
<p className="absolute css-ew64yg font-['Noto_Sans_JP:Regular',sans-serif] font-normal leading-[28px] left-0 text-[#343640] text-[length:var(--font\/size\/14,14px)] top-0" data-node-id="2002:281">
テキスト
</p>
</div>
</div>
<div className="absolute bg-[#5c6473] h-[56px] left-[1265px] rounded-[999px] top-[16px] w-[134px]" data-name="content" data-node-id="2002:282">
<p className="absolute css-ew64yg font-['Noto_Sans_JP:Regular',sans-serif] font-normal leading-[28px] left-[25px] text-[length:var(--font\/size\/14,14px)] text-white top-[14px]" data-node-id="2002:283">
ボタンラベル
</p>
</div>
</div>
);
}
Bデザイン案からget_design_contextで取得したコード
const img = "http://localhost:3845/assets/56250fb903cd7fd78c0bdd5df91b5a7ee0c603d5.svg";
const imgMitsuelogo1 = "http://localhost:3845/assets/db9ab65b2e697f33adea85ef1c29c4c175db3b67.svg";
type ButtonProps = {
className?: string;
label?: string;
showIcon?: boolean;
color?: "red" | "black";
size?: "large" | "small";
state?: "default" | "hover";
};
function Button({ className, label = "ボタンラベル", showIcon = false, color = "red", size = "large", state = "default" }: ButtonProps) {
if (color === "black" && size === "small" && state === "default") {
return (
<div className={className} data-name="color=black, size=small, state=default" data-node-id="18:677">
<p className="css-ew64yg font-[family-name:var(--font\/family\/japanese,'Noto_Sans_JP:Regular',sans-serif)] font-[var(--font\/weight\/regular,400)] leading-[28px] relative shrink-0 text-[color:var(--color\/white\/white,white)] text-[length:var(--font\/size\/14,14px)]" data-node-id="18:640">
{label}
</p>
</div>
);
}
return (
<div className={className} data-name="color=red, size=large, state=default" data-node-id="18:676">
<p className="css-ew64yg font-[family-name:var(--font\/family\/japanese,'Noto_Sans_JP:Medium',sans-serif)] font-[var(--font\/weight\/medium,500)] leading-[44px] relative shrink-0 text-[color:var(--color\/white\/white,white)] text-[length:var(--font\/size\/22,22px)]" data-node-id="18:642">
{label}
</p>
{showIcon && (
<div className="absolute bg-[var(--color\/red\/red-1,#a02424)] content-stretch flex items-center justify-center right-[30px] rounded-[var(--border\/radius\/full,999px)] size-[48px] top-1/2 translate-y-[-50%]" data-name="arrow icon" data-node-id="45:117">
<div className="h-[10px] relative shrink-0 w-[5px]" data-name="path" data-node-id="I45:117;18:669">
<div className="absolute inset-[-7.07%-28.28%-7.07%-14.14%]" style={{ "--stroke-0": "rgba(255, 255, 255, 1)" } as React.CSSProperties}>
<img alt="" className="block max-w-none size-full" src={img} />
</div>
</div>
</div>
)}
</div>
);
}
type GlobalNavigationMenuProps = {
className?: string;
label?: string;
state?: "default" | "hover";
};
function GlobalNavigationMenu({ className, label = "グロナビラベル", state = "default" }: GlobalNavigationMenuProps) {
return (
<div className={className} data-name="state=default" data-node-id="20:837">
<p className="css-ew64yg font-[family-name:var(--font\/family\/japanese,'Noto_Sans_JP:Regular',sans-serif)] font-[var(--font\/weight\/regular,400)] leading-[28px] relative shrink-0 text-[color:var(--color\/gray\/gray-3,#343640)] text-[length:var(--font\/size\/14,14px)]" data-node-id="20:835">
{label}
</p>
</div>
);
}
export default function Header() {
return (
<div className="bg-[var(--color\/white\/white,white)] content-stretch flex items-center justify-between px-[var(--margin\/40,40px)] py-0 relative size-full" data-name="header" data-node-id="27:86">
<div className="h-[28px] relative shrink-0 w-[164px]" data-name="mitsuelogo 1" data-node-id="18:727">
<img alt="" className="block max-w-none size-full" src={imgMitsuelogo1} />
</div>
<div className="content-stretch flex gap-[var(--margin\/40,40px)] items-center relative shrink-0" data-name="global navigation menu list" data-node-id="23:847">
<GlobalNavigationMenu className="content-stretch flex items-center justify-center relative shrink-0" label="サービス" />
<GlobalNavigationMenu className="content-stretch flex items-center justify-center relative shrink-0" label="実績紹介" />
<GlobalNavigationMenu className="content-stretch flex items-center justify-center relative shrink-0" label="ナレッジ" />
<GlobalNavigationMenu className="content-stretch flex items-center justify-center relative shrink-0" label="セミナー" />
<GlobalNavigationMenu className="content-stretch flex items-center justify-center relative shrink-0" label="ニュース" />
<GlobalNavigationMenu className="content-stretch flex items-center justify-center relative shrink-0" label="会社情報" />
<GlobalNavigationMenu className="content-stretch flex items-center justify-center relative shrink-0" label="採用情報" />
</div>
<Button className="bg-[var(--color\/gray\/gray-5,#5c6473)] content-stretch flex items-center justify-center px-[var(--margin\/25,25px)] py-[var(--margin\/14,14px)] relative rounded-[var(--border\/radius\/full,999px)] shrink-0" color="black" label="お問い合わせ" size="small" />
</div>
);
}
ソースコードを比較すると次にような違いがあります。
1. コンポーネントの使用
- Aデザイン案
- 単一の
Contentコンポーネントに全てを直書き。ナビゲーション項目は7回同じ構造を繰り返し、ボタンもインラインで記述。再利用可能なコンポーネントが存在しないため、変更時は7箇所を個別に修正する必要があります。 - Bデザイン案
Button、GlobalNavigationMenu、Headerの3つのコンポーネントに分割。ナビゲーション項目はGlobalNavigationMenuコンポーネントをlabelプロップで呼び出し。ボタンもButtonコンポーネントとして再利用可能で、color、size、labelなどのプロップで柔軟に変更できます。
2. バリアブルの使用
- Aデザイン案
- 色は直値で記述(
text-[#343640]、bg-[#5c6473])。一部CSS変数(var(--font\/size\/14,14px))は使用していますが、Figmaのバリアブル設計が反映されていません。 - Bデザイン案
- 全てのデザイントークンをCSS変数として使用。例えば、色は
var(--color\/gray\/gray-3,#343640)、スペーシングはvar(--margin\/40,40px)、ボーダー半径はvar(--border\/radius\/full,999px)。Figmaのバリアブル設計がそのままコードに反映されています。
3. レイヤー名の意味性
- Aデザイン案
- 全ての要素が
data-name="content"。レイヤーの役割が判別できず、AIが構造を理解しにくい状態です。 - Bデザイン案
- 意味のある名前を使用。
data-name="header"、data-name="mitsuelogo 1"、data-name="global navigation menu list"、data-name="arrow icon"など。各要素の役割が明確で、AIが構造を理解しやすい状態です。
4. AutoLayoutによるレスポンシブ設計
- Aデザイン案
absoluteで固定座標を指定(left-[39px] top-[30px]、left-[418px] top-[30px]など)。画面幅が変わるとレイアウトが崩れ、レスポンシブ対応ができません。- Bデザイン案
flexレイアウトを使用(flex items-center justify-between、flex gap-[var(--margin\/40,40px)] items-center)。画面幅に応じて自動的に調整され、FigmaのAutoLayout設計がコードに反映されています。
まとめ
見た目が同じでも、Figmaでの設計方法によって生成されるコードの品質は大きく異なります。
プロンプトの質を上げることは言うまでもありませんが、FigmaデータがAIフレンドリーであればあるほど、AIによるコード生成の品質向上につながります。