Claude CodeとClaude Webを組み合わせてSVG状態遷移図を作った話
結論
Claude Codeでフロントエンド開発をしていると、SVGで図を作りたい場面がある。複雑なSVGの生成はClaude Codeが苦手なので、Claude Web(claude.ai)で図の構造を作り、Claude Codeに渡して実装するという分業が効果的だった。
最終的にできたのは、ボタン操作で状態が変わり、対応するカードがハイライトされるインタラクティブな状態遷移図。

背景: なぜ状態遷移図が必要だったか
Tax Assistantというプロジェクトで、勘定科目選択UIの色ルールをドキュメント化したかった。
クレジットカード明細の画面で「一致」「候補」「不一致」などのステータスを色で区別している。この色の使い分けルールをDesign Systemページにまとめていた。

勘定科目選択の色ルールは少し複雑で、以下の5状態がある。
| 状態 | 色 | 確定値 | 選択値 | 説明 |
|---|---|---|---|---|
| 未確定 | 紫 | なし | AI提案と同じ | AI提案のまま |
| 未確定(変更あり) | オレンジ | なし | AI提案と異なる | AI提案から変更 |
| 編集中 | 青 | あり | 確定値と同じ | 確定後の再編集 |
| 編集中(変更あり) | オレンジ | あり | 確定値と異なる | 確定値から変更 |
| 確定済み | 緑 | あり | - | 保存完了 |
「未確定(変更あり)」と「編集中(変更あり)」が同じオレンジなのは、どちらも「現在の選択が基準値と異なる」という状態を表すため。色を統一することで、ユーザーは「オレンジ = 変更あり」と直感的に理解できる。
テキストだけでは伝わりにくいので、状態遷移図を作ることにした。
試行1: イラストレーターでラフを作成
まず自分でイラストレーターで簡単なラフを作った。矢印は省略して、カードの配置と色だけ示したもの。

これをClaude Codeに渡して「この図をSVGで実装して」と依頼した。
結果は微妙だった。複雑なSVGの座標計算やパス描画はClaude Codeの苦手分野で、カードの配置がずれたり、矢印がおかしな方向を向いたりした。
試行2: Claude Webで図を生成
Claude Code単体では難しいと判断し、Claude Web(claude.ai)を使うことにした。Claude Webはアーティファクト機能でSVGやReactコンポーネントを生成できる。
イラストレーターのラフをClaude Webに渡して「この状態遷移図をSVGで作って」と依頼。

かなり良い図が生成された。矢印の配置も適切で、各状態の色分けも正しい。
試行3: Claude Codeでインタラクティブ化
Claude Webで生成したSVGをClaude Codeに渡し、Vueコンポーネントとして実装してもらった。
目標は以下の機能。
- ボタンで状態を操作(保存、編集、科目変更)
- 現在の状態に対応するカードがハイライト
- 勘定科目を選択すると色が変わる

基本的な動作はできたが、問題が発生した。
問題: ループのハイライトが正しくない
確定済み→編集→変更→保存というループを表現したかった。しかし「編集中(変更あり)」から保存したとき、上の「確定済み」カードがハイライトされてしまう。

原因は、ハイライト判定がcurrentStateのみで行われていたこと。状態がconfirmedになると、どの経路で確定したかの情報が失われ、常に同じカードがハイライトされていた。
本来は下の「確定済み」カード(ループの終点)がハイライトされるべき。
解決策1: 8カードに分割(V2)
最初の解決策として、「確定済み」カードを2つに分けた。
- 上の確定済み: 未確定から直接保存したとき用
- 下の確定済み: 編集中(変更あり)から保存したとき用

これで動作は正しくなったが、カードが8枚になって図が複雑になった。同じ「確定済み」状態なのにカードが2つあるのは冗長に感じる。
解決策2: 動的テキスト+ループ(V3)
最終的な解決策として、カードの内容を動的に変更するV3を採用。
ポイント:
- カードは5枚に削減
- 「編集中」カードの説明文が動的に変わる(例: 「確定値(接待交際費)と同じ = 青」)
- 保存時の経路を記録し、適切なカードをハイライト
状態管理
// 状態の型定義
type State = 'unconfirmed' | 'editing' | 'editing-changed' | 'confirmed'
const currentState = ref<State>('unconfirmed')
const selectedAccount = ref('会議費') // 現在選択中の科目
const confirmedAccount = ref<string | null>(null) // 確定済みの科目
const savedFromEditingChanged = ref(false) // 経路記録用フラグ
状態遷移関数
// 保存: 経路を記録して確定状態へ
function saveAccount() {
savedFromEditingChanged.value = currentState.value === 'editing-changed'
confirmedAccount.value = selectedAccount.value
currentState.value = 'confirmed'
}
// 編集: 確定済みから編集状態へ
function startEditing() {
currentState.value = 'editing'
}
// 科目変更: 状態に応じて変更あり状態へ
function selectAccount(account: string) {
selectedAccount.value = account
if (currentState.value === 'unconfirmed' && account !== aiSuggestedAccount) {
// 未確定でAI提案と異なる → 未確定(変更あり)は色だけ変わる
} else if (currentState.value === 'editing' && account !== confirmedAccount.value) {
currentState.value = 'editing-changed'
} else if (currentState.value === 'editing-changed' && account === confirmedAccount.value) {
currentState.value = 'editing'
}
}
ハイライト判定
// カードのハイライト判定
function isCardHighlighted(cardType: string): boolean {
return currentState.value === cardType
}
SVG側では、savedFromEditingChangedフラグを使ってどちらの「確定済み」カードをハイライトするか決定。
<!-- 上の確定済み: 未確定から直接保存 -->
<rect :filter="isCardHighlighted('confirmed') && !savedFromEditingChanged
? 'url(#card-highlight)' : ''" />
<!-- 下の確定済み: ループ経由で保存 -->
<rect :filter="isCardHighlighted('confirmed') && savedFromEditingChanged
? 'url(#card-highlight)' : ''" />
完成した状態遷移図
最終的なV3実装では、以下の操作ができる。
- 勘定科目を選択 → 「未確定(変更あり)」
- 保存 → 「確定済み」(上のカードがハイライト)
- 編集 → 「編集中」(動的テキストが更新)
- 別の科目を選択 → 「編集中(変更あり)」
- 保存 → 「確定済み」(下のカードがハイライト)

Claude CodeとClaude Webの使い分け
今回の経験から、以下の使い分けが有効だと感じた。
| タスク | 適したツール |
|---|---|
| 複雑なSVG図の生成 | Claude Web |
| コードベースへの統合 | Claude Code |
| インタラクティブ機能の実装 | Claude Code |
| 既存ファイルの編集 | Claude Code |
Claude Webはアーティファクトで視覚的なフィードバックを得ながら図を調整できる。一方Claude Codeは、プロジェクトのコンテキストを理解し、既存コードと整合性のある実装ができる。
両者を組み合わせることで、どちらか単体では難しいタスクも効率的に進められた。
まとめ
- 状態遷移図のような複雑なSVGは、Claude Webで生成してClaude Codeに渡すのが効果的
- ループを含む状態遷移は、経路を記録してハイライト先を切り替える
- 動的コンテンツを使えば、カード数を減らしつつ正確な状態遷移を表現できる