🎨

あるべき場所に帰ろう!ReActに立ち返りClaude Code + Playwright MCP + Figma MCPでデザインを反映

に公開

VTeacher所属のSatokoです!
普段はフロントエンドをメインとして、QA的なことや進捗管理など、いろいろやっています。
最近の趣味はAIとのおしゃべりです!

FigmaのMCPサーバーさん

ところで!

せっかくFigmaにMCPサーバーがあるのに、生成されたコードがいまいちで、一時的に話題になった以降は、Figma MCPサーバーの利用を諦めてしまった人はいませんか?

いま、心の中で(あ、はい・・・)と答えた人そこのあなた!

この記事の続きを是非読んでください!

エージェント機能=人に依存していた職人気質の作業を繰り返す

いまでは「エージェント」という機能が一般的になってきましたが、私が初めてこの言葉を聞いたのはRAG(LangChain)を触ったときでした。この頃のAgentは旧機能となり、現在は非推奨のようですが、それを見たときはやはり衝撃的で、AIの醍醐味を感じたことを覚えています。「レビューをAIに任せたい!」など、同じ発想や期待を持つ人が増えたことが、いまのAIエージェントの発展につながったのだと思っています!

https://gihyo.jp/book/2023/978-4-297-13839-4

  • 第5章 LangChainの活用
    • 5.2 Agents
      • Agentsの概要
      • Agentsの使用例
      • Agentsの仕組み― ReAct (Reasoning and Acting) という考え方

本題ですが、Figma MCPサーバーを諦めた人が増えてきた?

本題に戻ります!

せっかくFigmaのMCPサーバーがあるのに、期待するコードが生成されない、今は使っていない、Figma MCPサーバーの利用を諦めた、という人が散見されるようになりました。


しくしくばなな

たしかに・・・
Figma MCPサーバーの利用をVibe Coding頼りでやってしまうと、その自動で生成されたコードのデザイン再現率はいまひとつだと思います。

そこで!!!

原点である ReAct (Reasoning and Acting) に立ち返りましょう!

ReAct は「Reasoning(思考)」と「Acting(行動)」を交互に出力させるプロンプト手法/パラダイムで、思考と行動の交互反復が ReAct (Reasoning and Acting) の核です。

1. モデルが「Reasoning Traces:(思考)」を出力して方針を決める。
2. 方針に従って「Actions:(行動)」を起こす。
3. 「Observations:(観察)」としてモデルはそれを踏まえて再び Reasoning Traces に戻る。

https://research.google/blog/react-synergizing-reasoning-and-acting-in-language-models/

噛み砕いて、今回の例に当てはめると・・・

エージェント機能=人に依存していた職人気質の作業を自動化して繰り返す機能

ReAct思考で仕様ドリブン

実践的には Spec Kit や Kiro など、仕様ドリブン(Spec-driven)の流れになってきていると思います。Viable coding(実用的なコーディング)として、改めてFigmaのMCPサーバーに挑戦してみましょう!Claude CodeなどはエージェントなのでReActの思考をもともと汲んでいますが、そのReActをさらにReActで包んであげるイメージでやってみます!

人間がやる場合の手順書をSpec(仕様)とする

人力で、FigmaからCSSを反映させる場合、次の作業を繰り返すと思います。

1. Figmaを見て、コンポーネントをクリックして、CSSを確認思考
2. CSSをファイルに反映(コーディング)行動
3. 目で見て差異がないかを確認観察

これを仕様ドリブンでViable coding的にやるにはどうしたら良いかを考えていきます!

  • 思考の部分
  1. Figmaを見て、コンポーネントをクリックして、CSSを確認

ここは Figma MCPサーバー を使えば良さそうです。
MCPサーバー経由でデータを取得します。

  • 行動の部分
  1. CSSをファイルに反映(コーディング)

ここは生成AI(Claude CodeやCodexなど)に任せれば良さそうです。

  • 観察の部分
  1. 目で見て差異がないかを確認

ここをどうするか、ですが、これはPlaywrightのMCPサーバーを使うことにします。ご存知の通り、PlaywrightはE2Eテストの定番で、VRT(Visual Regression Test)にも対応していますので、つまり、E2Eテストにより、目視確認の役割(Observations)を担当させます!

https://playwright.dev/docs/test-snapshots

Figmaを開いて、あらかじめ人力でスクリーンショットを撮って保存しておきましょう!これを使ってE2Eテストコードを書いておきます。
AIには、VRT(Visual Regression Test)の要領で 観察 を行ってテストに合格するまで繰り返すように指示します。

整理すると次のような手順です。

  • 問題の切り分けをしやすくするために、古典的ではありますが、いきなり動的ファイル(.tsx など)に手を加えるのではなく いったん静的ファイル(.html)を作ってから 動的ファイルに反映することを推奨します。
1. 思考: Figma MCPサーバー 経由でデータ取得
2. 行動: Claude Codeなどで、htmlファイルを作成
3. 確認: Playwright MCPサーバー経由でVRTのテストコードを実施
- テストに合格(差異10%以内)するまで繰り返す

結論から言うと、とても良いです!

この方法なら、ある程度高めの精度が出せると思います!
(デザイナーによってレイヤーの分け方等に癖があるので、プロンプト調整が必要です)

やってみましょう!

Figma MCPサーバー

ダウンロード版のFigmaが必要です。

https://help.figma.com/hc/ja/articles/32132100833559-Dev-Mode-MCPサーバー利用ガイド

現在はオープンベータ版で、初期版より変更が加えられている印象です。
基本的な部分は同じですが、UIはちょくちょく変わっています!

プロフェッショナル、ビジネス、またはエンタープライズプランのDevまたはフルシートで利用できます

このように書かれていますが、申請後は現時点で約3日間の無料体験を利用できるはずです!

Figma MCPサーバーの設定は、Claude Codeでしたら、次の通りです!

claude mcp add --transport sse figma-dev-mode-mcp-server http://{Figmaが表示するMCPサーバーのURLを使ってください}

Playwright MCPサーバー

Playwright(本体)はこちらです。

https://www.npmjs.com/package/playwright

MCPサーバーはこちらです。

https://github.com/microsoft/playwright-mcp

Playwright MCPサーバーの設定は、Claude Codeでしたら、次の通りです!

claude mcp add playwright npx @playwright/mcp@latest

VRTのテストコード

期待値となる正解画像が必要なので、あらかじめFigmaを開いて人力でスクリーンショットを撮っておきましょう。

テストコードのサンプルは次の通りです!
(10%の差異までであれば合格としています)

import { chromium } from '@playwright/test';
import { compareScreenshot } from './vrt-utils';
import path from 'path';
import fs from 'fs';

/**
 * test.htmlとvrt.pngを比較するテストを実行します
 */
async function runTest() {
  console.log('test.htmlとvrt.pngを比較テストを開始します...');

  // ブラウザを起動
  const browser = await chromium.launch();
  const context = await browser.newContext();
  const page = await context.newPage();

  try {
    // test.htmlのファイルパスを絶対パスに変換
    const testHtmlPath = path.join(process.cwd(), 'test.html');
    const fileUrl = `file://${testHtmlPath}`;

    console.log(`ページを開きます: ${fileUrl}`);

    // test.htmlをファイルシステムから読み込む
    await page.goto(fileUrl);

    // 少し待ってCSS/フォントが適用されるようにする
    await page.waitForTimeout(1000);

    console.log('スクリーンショットを比較します...');

    // スクリーンショットを撮影
    const screenshotBuffer = await page.screenshot();

    // スクリーンショットを保存(比較用)
    const tempScreenshotPath = path.join(process.cwd(), 'e2e/vrt/temp-screenshot.png');
    fs.writeFileSync(tempScreenshotPath, screenshotBuffer);

    console.log(`一時スクリーンショットを保存しました: ${tempScreenshotPath}`);

    // vrt.pngと比較
    const result = await compareScreenshot({
      page,
      name: 'test-html',
      baseImagePath: path.join(process.cwd(), 'vrt.png'),
      threshold: 0.1, // 10%までの差異を許容
    });

    console.log(`比較結果: 差異 ${(result.diffPercentage * 100).toFixed(2)}% (許容値: 10%)`);
    console.log(`異なるピクセル数: ${result.pixelDiff}`);

    if (result.diffPercentage <= 0.1) {
      console.log('テスト成功: 画像の差異が許容範囲内です');
    } else {
      console.error('テスト失敗: 画像の差異が許容範囲を超えています');
      process.exit(1);
    }
  } catch (error) {
    console.error('テスト実行中にエラーが発生しました:', error);
    process.exit(1);
  } finally {
    // ブラウザを閉じる
    await browser.close();
  }
}

// スクリプトを実行
runTest().catch(err => {
  console.error('エラーが発生しました:', err);
  process.exit(1);
});

準備ができました!
あとはAIに指示するだけです。

AIへの指示(プロンプト)

次のようなプロンプトを使用して、テストが合格するまでAIに修正を繰り返してもらいましょう!

次のタスクを順に実行してください。

- [ ] 1. Reasoning Traces:(思考): 次のURLからFigmaの対象データを取得してしてください。
https://{Figma上の対象を右クリックして「選択範囲のリンク」のURL}
- [ ] 2. Actions:(行動): タスク1で取得したデータを忠実に反映したtest.htmlを作成してください。
- [ ] 3. Observations:(観察): Playwriteを使用して `test:vrt:compare-test-html` を実行してください。

タスク3のテストに合格するまで、タスク1に戻って test.html を修正する作業を繰り返してください。

実際にやってみた結果はこちらです!

結果としては左寄せ(センタリング忘れ?10%の許容をしている)にはなってしまっていますが、かなりの再現率にはなっているかと思います!

期待値 結果

ぜひとも、みなさんも試してみてください!

次のおすすめ記事:

https://zenn.dev/vteacher/articles/article-tanaka-20250909

Discussion