AQ Tech Blog

Figma Make × Claude Codeでデザインから実装まで 第2回:実装編

作成者: hideyoshi.koeda|2026年06月22日

はじめに ― 前回のおさらいと今回やること

デジタルエンジニアリング部 Eビジネスエンジニアリング課の小枝です。
前回は、Figma Makeにプロンプトからデザインとプロトタイプを生成してもらいました。
今回はそれをもとに、Claude Codeでコードの品質を上げてもらいます。

Figma Makeが出力したコードを見てみよう

出力されたコードを開いて、使われている技術の確認をします。


技術スタック(React / TypeScript / Tailwind CSS v4 / shadcn/ui)の確認

  • React
    UIを構築するJavaScriptライブラリ。コンポーネント単位で画面を組み立てる。
  • TypeScript
    型付きJavaScript。補完やコンパイル時のエラー検出が効く。
  • Tailwind CSS v4
    クラス名を直接HTMLに書くCSSフレームワークの最新版。CSS変数ベースの設定が特徴。
  • shadcn/ui
    Tailwind CSS + Radix UIベースのコンポーネント集。コードを自分のプロジェクトにコピーして使うスタイル。

モダン環境未経験でもここまで出てきたという驚き

普段はデザインがメインの業務なので、Reactには触れてきませんでした。
今回、特に指定していなかったのに、Reactとshadcn/uiを採用してくるのは便利になったというか……。AIの進化ってすごい。

Figma Makeのコードをそのまま動かしてみる

Figma Make上での動作は確認済みですが、Claude Codeに渡す前にローカルでも起動してみます。


ローカル環境でのセットアップ手順

README.mdが生成されているので、手順に沿って起動します。
ちゃんと生成されているのも便利。

Figma Make上のデザインそのままの画面が表示されました。


動作確認と気になった点

動作は概ね問題ないです。 ただ、hoverやボタンの大きさなど調整したいところがいくつかあるので、修正点をClaude Codeに伝えて対応してもらいます。

Claude Codeに渡して仕上げる

まず、見た目やマイクロインタラクション等の修正から進めます。

複数の修正をまとめて頼むと意図しない変更が入りやすいそうなので、1回に1つの修正を加えます。

実際にこんな指示を出しました(一例)。

配色選択のボタンにhoverのアニメーションの設定と、カーソルをポインターにしてください。アニメーションは0.3秒、easeにしてください。

アニメーション自体は動作しましたが、hover時の装飾を明確に指定しなかったので透過度を変更するなどの処理になり、修正するために複数のやり取りが発生しました……。
最終的には選択時と同じ装飾にしてくださいと指定してコントロールできました。あいまいな指示が良くなかったです。

カラーピッカーとシャッフルボタンも同じようにしてください。また、カラーピッカーのアウトラインも非表示にしてください。

この指示の後、アウトラインが非表示にならなかったのと、押せる感が薄くなったので、カラーピッカーのアイコンについても追加してもらいました。

当初はアクセントカラーが3色で配色の種別にトライアドを用意してもらいましたが、途中で4色になったので名前と挙動の調整をお願いします。

Figma Makeの時に4色にしてもらいましたが、記述や計算式に関しては特に指定していなかった部分です。
ちゃんと直してもらえました。


TypeScript型定義やコンポーネント設計の整理

いろいろ修正も入れましたし、Claude Codeにコードレビューをしてもらいました。

コードを見た上でのアドバイスです。

現状の App.tsx は大きく3つの役割が混在しています:

色の計算ロジック(hexToRgb、generatePalette など、1〜173行)
型定義(ColorScheme、ColorPalette)
画面の描画(App コンポーネント本体)
Reactを知らなくても取り組みやすい順番でいうと:

ステップ1:型定義を切り出す(一番簡単)
src/types.ts を作って ColorScheme と ColorPalette を移すだけ。Reactの知識ゼロでできます。

ステップ2:色の計算関数を切り出す(次に簡単)
src/utils/color.ts を作って hexToRgb から generatePalette までを移す。これも純粋な関数なのでReactと無関係です。

ステップ3:コンポーネント分割(Reactの理解が必要)
左パネル・右パネル・下段を別ファイルにする。これは「propsで値を渡す」というReactの概念が必要になるので、1・2が終わってから検討するのが良いと思います。

ひとまずステップ1と2をやってもらうことにしました。
必要なファイルの作成とApp.tsxの整理をしてもらいましたが、何をしたのかの解説もお願いしました。

「何をしたか」を図で説明します。

Before(変更前)

App.tsx(1ファイルに全部)
├── type ColorScheme = ...       ← 型定義
├── interface ColorPalette = ... ← 型定義
├── function hexToRgb() ...      ← 色計算
├── function rgbToHsl() ...      ← 色計算
├── function getContrastRatio()  ← 色計算
├── function generatePalette()   ← 色計算
└── function App() { ... }       ← 画面描画

After(変更後)

types.ts       → 型定義だけ
utils/color.ts → 色計算の関数だけ
App.tsx        → 画面描画だけ(上2つをimportして使う)

なぜ分けるのか、一言でいうと「1つのファイルには1つの役割」というルールに従うためです。

料理で例えると、レシピ(型定義)・調理道具の使い方(色計算)・盛り付け(画面描画)が1枚の紙に書いてあったのを、3枚に分けたイメージです。どこに何が書いてあるか探しやすくなります。

import というのは「他のファイルから持ってくる」命令です。変更後の App.tsx の先頭にある:

import { generatePalette, getReadableColor } from '../utils/color';
これは「utils/color.ts の中にある generatePalette と getReadableColor を使わせてもらう」という意味です。

想定より分かりやすい説明をしてくれて良かったです。判断しやすい。

ステップ3に関しては計画を立てた上で進めてくれました。
以下はClaude Codeの出力をそのまま引用しています。

ステップ3(コンポーネント分割)の内容を確認してから計画を立てます。

Used tool: Agent

Read src/app/App.tsx

計画を書きます。

Here is Claude's plan:

# Context
現在のApp.tsxは型定義と色計算関数を分割済み。次のステップとして、UIコンポーネントを分割し、可読性と保守性を向上させる。

# Plan

App.tsxを3つの子コンポーネントに分割:

## 1. CSSOutputPanel.tsx(最初に実装)
- 役割: 下段のCSS出力エリア
- 必要なprops: `palette: ColorPalette`
- ローカルstate: `copied`(コピー完了フラグ)

## 2. ColorSwatchPanel.tsx
- 役割: 右パネルの3色スウォッチ表示
- 必要なprops: `colors: string[]`
- stateなし(純粋な表示コンポーネント)

## 3. KeyColorPanel.tsx
- 役割: 左パネルのキーカラー選択と操作
- 必要なprops: `keyColor`, `scheme`, `onKeyColorChange`, `onSchemeChange`, `onRandomColor`
- ローカルstate: `hoveredScheme`, `hoveredColorPicker`, `hoveredShuffle`

## 4. App.tsx(親)
- state保持: `keyColor`, `scheme`, `palette`
- useEffect: `keyColor`と`scheme`変更を監視
- 子コンポーネントをレイアウトで配置

## ファイル構造
src/
├── types.ts
├── utils/color.ts
├── app/
│   ├── App.tsx(整理済み)
│   └── components/
│       ├── KeyColorPanel.tsx(新規)
│       ├── ColorSwatchPanel.tsx(新規)
│       └── CSSOutputPanel.tsx(新規)

# Verification
- `npm run dev` で開発サーバー起動
- 各コンポーネントが正しく表示されることを確認
- ボタン操作・色変更・コピー機能がすべて動作することを確認
- コンソールにエラーがないこと確認


計画が既に承認済みなので、実装を進めます。

3つのコンポーネントを順番に作ります。最初に `CSSOutputPanel.tsx`:
次に `ColorSwatchPanel.tsx`:
次に `KeyColorPanel.tsx`:
最後に `App.tsx` を新しい子コンポーネントに置き換えます:

Read src/app/App.tsx

完了です。最終的なファイル構造:

src/
├── types.ts                    # 型定義
├── utils/color.ts             # 色計算関数
└── app/
    ├── App.tsx                # 親コンポーネント(25行)
    └── components/
        ├── KeyColorPanel.tsx   # 左パネル
        ├── ColorSwatchPanel.tsx # 右パネル
        └── CSSOutputPanel.tsx  # 下段

`App.tsx` が元の 236行から 41行に削減されました。各コンポーネントが責任を持つので、今後の変更が簡単になります。

変更を行いました。

各コンポーネントに機能が分割され、責任の所在が明確になりました。
ここまで対応してもらえてすごく助かります。

コードレビューもClaude Codeにお願いしてみました

コードの修正が終わったので、Claude Codeに自己レビューをお願いしました。
ここまでしてくれるならきっと良いレビューも上がってくるだろうと。


改善点

P0(今すぐ修正すべき)

  • ランダムカラー生成のバグ — 16777215を16777216に変更。現在は白(#FFFFFF)が生成されません
  • RGB値がクリップされていない — 負数や255超過の値で不正なカラーコードが生成される可能性
  • 無効なカラー入力時の処理 — 警告なく黒に変換されてしまう

P1(高優先度)

  • キーボードフォーカススタイルがない — Tabキーで操作するユーザーが現在位置を把握できない
  • スクリーンリーダー対応不足 — aria-labelがなく、視覚障害者に情報が伝わらない
  • motion-reduce対応が不完全 — OS設定で「視差効果を減らす」を選んだユーザーに対応していない

P2(中優先度)

  • コントラスト計算の重複 — 同じ計算が複数回実行されている
  • CSS生成ロジックの重複 — 2箇所で同じコードが書かれているので、一度のバグで両方壊れる

P3(コード品質)

  • マジックナンバーが散在 — 75, 0.618など、意味不明な数字がコードに埋め込まれている
  • ホバーステート管理の重複 — hoveredScheme、hoveredColorPicker、hoveredShuffleのロジックが同じ

思っていた以上にしっかりしたレビューを上げてくれました。
今回はユーザビリティを重視しているので、まずP2まで対応してもらうことにしました。
P3は規模が小さかったのでついでにお願いしました。P0から順番に進めます。


修正対応

P0の対応内容

バグ修正・エラーハンドリングの追加

  • ランダムカラー生成のバグ修正(App.tsx:18)— 16777215 → 16777216に変更。白(#FFFFFF)が生成されるように
  • RGB値のクリップ(color.ts:19)— 0未満・255超過の値が入っても不正な色コードが生成されないように
  • 無効なカラーコードのエラーハンドリング(color.ts:5-16)— hexToRgbの戻り値をnull許容型に変更。console.warnを出力してnullを返すように
  • 重複importの削除(color.ts:1-3)— 2行あったimportを1行に統一

P1の対応内容

アクセシビリティ・操作性の改善

  • フォーカス表示(KeyColorPanel.tsx)— スキームボタン・シャッフルボタンにfocus-visible:outlineを追加。Tabキー操作時だけアウトラインが出る
  • スクリーンリーダー対応 — カラーピッカー・シャッフルボタン・スキームボタンにaria-label / aria-pressedを追加
  • motion-reduce対応 — motion-reduce:transition-noneを追加。OSの「視差効果を減らす」設定が有効な場合はアニメーションを無効化

P2の対応内容

コントラスト計算・CSS生成ロジックの重複解消

  • getContrastInfo()の追加(color.ts)— textColor・contrastValue・meetsAA・meetsAAAを1回の計算でまとめて返す
  • getContrastInfoに集約(ColorSwatchPanel.tsx)— getContrastRatioを複数回呼んでいたのを1回に
  • buildColorEntries関数の追加(CSSOutputPanel.tsx)— 色とラベルの生成ロジックを1箇所に集約

P3の対応内容

マジックナンバーの定数化・ホバー管理の共通化

  • LAYOUT定数を追加(constants/design.ts新規)— 75・0.618などのマジックナンバーを定数化。App.tsx・KeyColorPanel・ColorSwatchPanelで参照
  • useHoverStateフックを追加(hooks/useHoverState.ts新規)— isHoveredとhoverPropsをまとめて返す共通フック。{...hoverProps}と書くだけでイベントを展開できる

順番に指示を出して修正してもらい、最後に対応内容をまとめて報告してもらいました。
数分で対応してこういった報告をしてもらえるの、良いです。
ともあれ、P0~3の修正点すべてを対応してもらったので、改めてレビューをお願いしました。

レビュー2回目


良い点

  • コンポーネント名・関数名が役割を正確に伝えている
  • 型定義が明確でTypeScriptが適切に活用されている
  • コンポーネントの責務が整理されている

改善点

高優先度

内容 ファイル
generatePalette() のswitch文が長く、同じパターンが4回繰り返されている src/utils/color.ts
カラーピッカーとシャッフルボタンのスタイルロジックが重複している src/app/components/KeyColorPanel.tsx

中優先度

内容 ファイル
schemeLabels がコンポーネント内にあり、他から再利用できない src/app/components/KeyColorPanel.tsx
handleCopy にCSS生成・クリップボード操作・状態管理が混在している src/app/components/CSSOutputPanel.tsx
buildColorEntries() が同一レンダリング内で2回呼ばれている src/app/components/CSSOutputPanel.tsx
ハードコードされた色値(#1e1e1e など)が散在している 全体
useHoverState の戻り値の hoverProps という名前が何をspreadするか分かりにくい src/app/hooks/useHoverState.ts

低優先度

内容 ファイル
getLuminance の計算式(WCAG基準)にコメントがない src/utils/color.ts
16777216 が何の数字か分からない src/app/App.tsx
setTimeout のクリーンアップがなくメモリリークの可能性 src/app/components/CSSOutputPanel.tsx

初回レビューで取り残した項目がわらわらと出てきました。
漏れ抜け方がロボット掃除機みたいな印象がありますね。 でもまあせっかくなので、すべて対応してもらうことにします。

高優先度から順番に進めてもらいます。


修正対応

# 優先度 ファイル 変更内容
color.ts getContrastInfo() を追加、getContrastRatio の複数回呼び出しを1回にまとめ
KeyColorPanel.tsx ICON_CIRCLE_CLASS 定数・getIconCircleStyle() 関数を抽出、カラーピッカーとシャッフルボタンの重複スタイルを統合
hooks/useHoverState.ts useHoverState カスタムフック導入、onMouseEnter/Leave の定型パターンを再利用可能に
constants/design.ts SCHEME_LABELS を移動、KeyColorPanel のラベルオブジェクトを定数化
CSSOutputPanel.tsx buildCSSText() 抽出、copyToClipboard() 抽出、colorEntries を一度だけ計算、handleCopyasync/try-catch に変更
constants/theme.ts(新規) THEME 定数を作成、CSS出力パネルの配色をファイルに集約
color.ts getLuminance にWCAGコメント追加、generateRandomHex() を抽出
CSSOutputPanel.tsx setTimeout クリーンアップ、useRef + useEffect でタイマー漏れを防止

こちらも数分で対応が終わり、報告までしてもらいました。 便利すぎる。

レビュー3〜5回目

その後も対応→レビュー→対応のサイクルを繰り返しました。
回を重ねるごとに指摘が細かくなっていきます。
重要度高めのものから検知しやすいのかもしれないです。

3回目は初期カラーの二重定義(定数化で解消)や、関数間のロジック重複、変数名の統一など6件。
4回目は破壊的代入の修正漏れや不要な再レンダリング(useMemoで解消)など5件。
5回目は低優先度2件のみで、ほぼスタイルの統一の話でした。

5回目の修正後のチェックでようやく指摘がなくなり、問題のないコードになりました。
思ったより回数がかかりましたね……。
途中トークンの上限が見えてきたりしたので、レビューの範囲や回数はもう少し工夫ができたのかもしれません……。

アプリ完成!

アプリが完成しました!主な機能は4つ!

  1. キーカラー選択
    カラーピッカー(ピペットアイコン)でベースカラーを視覚的に選択。
    ランダム生成ボタン(シャッフルアイコン)でランダムなカラーを即生成。
    選択中のカラーがHEXコードで表示される。
  2. 配色スキーム切り替え
    キーカラーをもとに4種類の配色理論でパレットを自動生成。
    • コンプリメンタリー(補色)
    • アナログ(類似色)
    • テトラディック(4色配色)
    • モノクロマティック(明度違いの同系色)
  3. カラースウォッチ表示
    生成された4色のアクセントカラーを表示。
    各スウォッチに表示される内容
    • HEXコード
    • WCAGコントラスト比(数値)
    • AA / AAA適合バッジ(アクセシビリティ確認)
  4. Tailwind CSS出力
    • 生成パレットをそのまま使えるTailwind CSSクラスを出力
    • ワンクリックコピーボタンでクリップボードにコピー

アクセシビリティチェック機能を深掘りする

今回のカラーピッカーアプリでは、コントラスト比チェック機能を搭載しています。
Figma Makeへのプロンプトの時点で明確に指定して作ってもらいました。

コントラスト比はWCAGの基準に沿って計算されていて、式は (明るい色のL + 0.05) / (暗い色のL + 0.05) です。
AA基準が4.5:1、AAA基準が7:1なので、これを自動で判定して分かりやすくしています。

Claude Codeのレビューでは getLuminance にWCAGの計算式コメントを追記する提案もありました。
可読性に気を配ってくれるのも良い働きです。

2ツールの役割分担を振り返る

今回使ってみて、2つのツールの役割分担がはっきりしていると感じました。

Figma Make は「速く動くものを作る」ツール。UIのビジュアルから一気にコードまで出してくれるスピード感は、体験としてかなり面白かったです。優秀なアシスタントが付いてくれた感じですね。 一方、Claude Codeは「品質・保守性を上げる」ツール。レビューを繰り返すことで、とりあえず動くコードが整理されきれいになりました。

最初から完璧を目指すより、まずFigma Makeで形にしてClaude Codeで品質を上げる、という流れが自分には合っていそうです。

やってみての所感

Figma Makeの時点でここまで動くものができるとは正直思っていませんでした。プロトタイプを作るスピード感がすごい。
ただ、思いつくまま生成させるとコントロールが難しくなるので、事前に伝えておく要件はある程度整理しておいたほうが良さそうです。
あとはAIに寄りかかりすぎないことですかね。AIが出したものをそのまま使うのではなく、自分でちゃんと理解・確認しながら使う姿勢は大事だと思います。

Claude Codeを使ってみての所感

デザイナー目線で使ってみると、コードの説明が丁寧で「なぜこうすべきか」まで教えてもらえるのが良かったです。
Figma Makeは「デザインを出してくれる」ツールですが、Claude Codeは「一緒に考えてくれる」感覚に近いかもしれないです。

気になった点としては、トークンの上限があるのでやり取りが長引くと会話を切り直す必要があることですかね。
レビュー範囲の区切り方などをもう少し工夫できたかなと思います。