1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Claude Design × Claude Code で映画レビューアプリを Flutter で実装してみた

1
Posted at

この記事でやったこと

Anthropic Labs が 2026-04-17 にリリースした Claude Design で映画レビューアプリのデザインを作り、Handoff Bundle を Claude Code (Opus 4.7) に渡して Flutter アプリとして実装させてみました。

その過程を備忘録としてまとめてます。

サンプルプロジェクト: Movie Movie(ダークモード映画レビューアプリ)
スタック: Claude Design → Handoff Bundle → Claude Code → Flutter 3.32.8 / Riverpod
成果物: Dart 25 ファイル / Provider 14 個 / fvm flutter analyze クリーン / Android 実機で起動確認済み

まず結果から

Claude Design

image.png
image.png

Flutter (Claude Code)

Home Timeline Profile
トレンド一覧(hero / cards / list の 3 レイアウト切替) フィルタ可能な投稿フィード 統計 + 月グルーピングされた視聴履歴
Detail Review Search
ヒーロー + タイトル重ね + 配信サービス可用性 ドラッグでスコア入力(0–10 / 0.5 刻み)+ タグ / ネタバレ recent + mood ブラウズ / 検索結果

うまくHandoff Bundleが機能しFlutterのUIを実装できてます。

ワークフローは以下 2 Stepになります。

フェーズ 環境 成果物
Step 1: デザイン Claude Design(ブラウザ) React + Babel の Hi-Fi プロトタイプ / Handoff Bundle (ZIP)
Step 2: 実装 Claude Code(ローカル CLI) Flutter プロジェクト(Dart 25 ファイル)

Step 1 と Step 2 での引き渡しの接点が Handoff BundleというClaudeDesignで出力できるファイル群です。

Step 1: Claude Design でデザインする

1.1 最初のドラフトを出す

High fidelityを選択しましょう。

image.png

まずプロンプトは 1 行:

モダンでダークモードベースの映画レビュー Flutter アプリをデザインして。ホーム画面にはトレンドの映画一覧、詳細画面には評価とレビュー投稿フォーム、プロフィール画面には視聴履歴を表示して。

すると具体的な設計を詰める質問セットをClaude Design が返してきます。

image.png

回答:

項目 指定
app_name Movie Movie
device iOS (iPhone)
screens ホーム(トレンド)/ 映画詳細 / レビュー投稿 / プロフィール / 検索
vibe モダン・ミニマル(落ち着いたダーク、上品)
accent ライム / グリーン
rating_style 10 点満点スコア
interactions 詳細画面へのヒーロートランジション
content_density 情報リッチ
imagery プレースホルダー(striped SVG + タイトル)
tweaks ホームレイアウト(cards / list / hero)/ 言語(日本語 / 英語)

「Tweaks」は、Claude Designで作成したプロトタイプの右下に表示される浮遊パネルのことのようです。
image.png

出てきたのは React + Babel で動く HTML プロトタイプ。primitives.jsx / poster.jsx / ios-frame.jsx / screen-*.jsx に分かれた、そこそこのコンポーネント構成。

image.png

「Flutter 用なのに React?」と思うかもしれませんが、Claude Design のプレビューはブラウザ内で動く React/JSX で統一されているので、Flutter に変換するのは後段の Claude Code の仕事。Step 1 の段階では Flutter はまだ 1 行も書きません。

1.2 赤ペン修正:一発では通らない

Claude Design の肝は「生成物にインラインコメントで修正指示を返せる」こと。ここでのやり取りが、Step 1 で一番書いておきたいパート。

image.png

誤解されたナビゲーション指示

最初の指示:

Searchの下タブをHomeの上に移動

image.pngimage.png

Claude はタブバー内で Search を Home の左に並べ替えた

こちらが期待していたのは「下タブから Search を消して、Home のヘッダーに検索ボタンを置く」だったので、完全にすれ違い。言い直しました:

違います。Searchの下タブを削除してHomeのお知らせの横にボタンを追加する

今度は完璧。タブの削除、ヘッダーへのアイコン追加、さらに**「タップしたら検索画面に遷移し、戻るで戻れる」という画面遷移ロジックまで**セットで更新された。

image.png

この修正を従来の作業に落とし込むと、以下のような書き換えを行うことになります。

  • BottomNavigationBar の items から Search 用のBottomNavigationBarItem を削除
  • AppBarの拡張: HomeView の Scaffold 内にある AppBar(またはカスタムヘッダー)の actions プロパティに、IconButton(検索アイコン)を追加
  • ルーティングの紐付け: そのボタンの onPressed に、Navigator.push または GoRouter.go で検索画面へ飛ばす処理を記述

これを自分でやると「ウィジェットのツリーを掘り下げて、あちこち書き換える」手間が発生しますが、Claude Designなら会話だけでこのリファクタリングが秒で終わっているのが驚異的で心強いですね。

コメント機能でのマージン調整

ScoreBadge(9.1/10 のバッジ)が右下に張り付きすぎていたので、該当要素にインラインコメントで:

マージンを調整して欲しい

Claude は視覚的にバッジの位置を判定し、ヒーロー内部のパディングを 20 → 24 に変更。数値は一切指定していないです。

before after
image.png image.png

タイトル重複をロジックで解く

ヒーローでタイトルが 2 回描画されていたのでコメント:

タイトルが重複して表示されているのでこちらは表示なしにする

Claude の応答:

Poster コンポーネントは titleSize > 0 のとき {t} をレンダーする。
HomeHero は titleSize={28} なので、Poster のタイトル + Hero overlay のタイトル
の両方が描画されていた。Poster 側を titleSize={0} で非表示にする。

単にテキストを消すのではなく、プロパティベースで解決。他画面で Poster 単体を使うときは titleSize を指定すればタイトルが出る、という再利用性も保たれている。

image.png

日本語の改行問題

プロフィールタブの「プロフィール」が折り返して 2 行になっていた:

一行で表示したい

whiteSpace: nowrap + 幅拡張で対応。

image.png

UX の改善依頼(曖昧なやつ)

詳細画面で上映中か配信サービスで配信されていればそのリンクを表示してUXを改善したい

具体的な指定はなし。Claude は自分で以下を判断:

  • 劇場公開中 → ライム色の視認性高めハイライトカード(劇場名・上映館数・上映時間)
  • 配信サービス → 横スクロールタイル(サービス名・サブスク / レンタル価格・公開予定日)
  • ダミーサービス名:Plexine / Stereofilm / Talaya / StreamRoom(実在しない)

「もっと増やして」と投げたら Vinebox / Kinoscape / Branchcast を追加、4〜6 サービスが並ぶ構成に。UI のパターン(カード vs 横スクロールタイル)を文脈で使い分ける判断が入っている。

image.png

1.3 Handoff Bundle を書き出す

デザインが固まったら、右上メニューから「Handoff to Claude Code」を選ぶ。出てくる選択肢は 2 つ:

  1. コマンドとして、ターミナルに貼り付ける
  2. ZIP 直ダウンロード

スクリーンショット 2026-04-18 20.51.42.png

ZIP を開けた中身:

movie-app/
├── README.md              ← "# CODING AGENTS: READ THIS FIRST"
├── chats/chat1.md         ← デザイン中のやり取り全文
└── project/
    ├── Movie Movie.html   ← React + Babel のプロトタイプ本体
    ├── data.jsx           ← モックデータ
    ├── primitives.jsx     ← ScoreBadge / Chip / TabBar / 色トークン
    ├── poster.jsx         ← ストライプ SVG ポスター
    ├── availability.jsx   ← 劇場 / ストリーミング
    ├── screen-home.jsx    ← hero / cards / list 3 レイアウト
    ├── screen-detail.jsx
    ├── screen-review.jsx
    ├── screen-search.jsx
    ├── screen-profile.jsx
    ├── screen-timeline.jsx
    └── ios-frame.jsx

README.md の冒頭:

CODING AGENTS: READ THIS FIRST

Recreate them pixel-perfectly. Match the visual output; don't copy internal structure.

デザインの納品物自体が、AI エージェントに対する仕様書として書かれています

特に注目すべき3点:

  • 起点は Movie Movie.html — ユーザーが開いていた=メインデザインの可能性大。インポート先まで追跡すること
  • ピクセルパーフェクト、ただし構造はコピーしない — 見た目を一致させる。プロトタイプのHTML構造はそのまま使わず、ターゲット技術(React等)で書き直す
  • スクショ禁止・ソース直読 — 寸法や色はHTML/CSSに全部書いてある。レンダリングは無駄

日本語訳
https://github.com/nabetarojp/movie_movie/blob/main/handoff/movie-app/README.ja.md

Step 1 のまとめ

  • Claude Design はブラウザ内で完結。プロンプト → 質問 → ドラフト → 赤ペン修正 → Handoff Bundle
  • 出力形式は React + Babel の HTML プロトタイプ。Flutter 固有の情報はまだ入っていない
  • Bundle には AI エージェント向けの README が同梱される(これが Step 2 の入り口)

Step 2: Claude Code で Flutter に実装する

ここからは環境がガラッと変わりまして、ローカルのターミナルで Claude Code を起動する。Claude Design 側のコンテキストは Claude Code からは見えない。引き継がれるのは Handoff Bundle の中身だけ

最終的なコードはこちら

2.1 Claude Code への渡し方

ZIP を展開したディレクトリで Claude Code を起動し、以下を渡す:

  • Handoff Bundle のパス(README.md から読み始める)
  • 実装側の制約(ここで Flutter 固有の要件を初めて指定する)
    • Flutter 3.32.8 / Dart 3.8.1 に fvm で pin
    • Riverpod 4 層アーキテクチャ(UI / 状態 / ドメイン / データ)
    • ref.watch / ref.read の使い分けを規約化
    • Repository は必ず Provider 経由で注入(テストで override 可能にする)

image.png

アーキテクチャ指定は Claude Design 側ではなく Claude Code 側でやる。デザイン段階では「Flutter で作る」としか言っていないので、Riverpod を使ったアーキテクチャーであったり、Provider の粒度、規約は全部 Step 2 のプロンプトに含める。

2.2 生成されたディレクトリ構造

lib/
├── main.dart
├── core/theme/
│   ├── app_colors.dart        ← デザイントークン(Handoff から抽出)
│   └── app_theme.dart
├── data/
│   ├── models/movie.dart      ← Movie / HistoryEntry / Review / TimelineEntry / Availability
│   ├── mock_data.dart
│   └── repositories/movie_repository.dart
├── providers/
│   ├── repository_providers.dart
│   ├── app_settings_provider.dart   ← 言語 / Home レイアウト
│   ├── navigation_provider.dart     ← tab / detailId / reviewing / toast
│   ├── review_draft_provider.dart   ← ReviewDraft + SubmitReview(AsyncNotifier)
│   └── movie_providers.dart         ← trending / search / genre / timelineFilter / profileTab
├── widgets/
│   ├── score_badge.dart       ← 8.5 以上でアクセント塗り (sm/lg/xl)
│   ├── chip_pill.dart
│   ├── section_header.dart
│   ├── poster.dart            ← CustomPainter で seed ベースのストライプ描画
│   ├── tab_bar_mm.dart
│   └── ios_device.dart        ← デスクトップ時のみフレーム表示
└── features/
    ├── shell/app_shell.dart   ← タブ + 詳細 overlay + レビューシート + FAB + トースト
    ├── home/home_screen.dart  ← hero/cards/list 3 レイアウト
    ├── detail/
    │   ├── detail_screen.dart
    │   └── availability_section.dart
    ├── review/review_screen.dart
    ├── search/search_screen.dart
    ├── timeline/timeline_screen.dart
    └── profile/profile_screen.dart

画面実装マッピング

HTML (React) Flutter 実装 対応
HomeScreen (hero/cards/list) HomeScreen ✅ 3レイアウトすべて
HomeHero _HomeHero ✅ ポスター + overlay gradient + ScoreBadge(lg)
HScroll _HScroll ✅ 横スクロールポスター列
RankedRow _RankedRow ✅ 順位 + ミニポスター + メタ + ScoreBadge
DetailScreen DetailScreen ✅ 500pxヒーロー + Transform.translate(-60) でタイトル被せ
MetaRow, ReviewCard _MetaRow, _ReviewCard
Availability + TheatersCard + ServiceTile AvailabilitySection + 内部 Widget ✅ ストリーミング横スクロール
ReviewScreen (StarRow / Tag / Spoiler toggle) ReviewScreen + _ScoreRow + _Toggle ✅ 20ドットのドラッグで 0〜10 (0.5 刻み)
SearchScreen SearchScreen ✅ Recent / Browse by mood / 検索結果
TimelineScreen + TimelinePost TimelineScreen + _TimelinePost ✅ タグ・アクション行含む
ProfileScreen + StatBlock + HistoryRow ProfileScreen + _Stat + _HistoryRow ✅ 月別グルーピング
TabBar MMTabBar ✅ 3タブ (Home/Timeline/Profile)
React hero/sheet/panel アニメーション TweenAnimationBuilder ✅ Detail: scale 1.04→1.0 / Sheet: 下からスライドイン
FAB AppShellPositioned ✅ Home タブのみ表示、シャドウ付き
Toast AppShell + ref.listen ✅ 2.2秒で自動クリア
IOSDevice (フレーム) IOSDevice (デスクトップ表示のみ) ✅ モバイル実機では非表示

2.3 React → Flutter の翻訳

Handoff README に書いてある「内部構造はコピーせずにピクセルファーフェクトで再現しなさい」がどう実行されたか。

ポスター描画:SVG <pattern>CustomPainter

React 側:

Flutter 側:

  • movie.id から _hashSeed を計算
  • angle = (seed % 4) * 30 + 15 → 15 / 45 / 75 / 105° のいずれか
  • gap = 8 + (seed % 5)
  • 背景 #0D0D0E に accent(movie.tag × α 0.22)のストライプを重ね、下半分は黒グラデでフェード

SVG 要素の DOM 構造は写してこない。Flutter に合わせて CustomPainter で書き直しているようですね。

SVG 版 Flutter 版
<pattern> の自動タイリング for ループで gap*2 間隔に縦帯を手動敷設
patternTransform="rotate()" canvas.translate(中央) → rotate → translate(-中央) の3点セット
タイルはみ出しをブラウザが処理 対角線長ぶんの extra padding を上下左右に確保
<linearGradient> の下フェード DecoratedBox + LinearGradient(stops: [0.55, 1.0]) を Painter に分離
角マーカー/タイトル/メタの <div> Stack + Positioned + Text (フォントは google_fonts の JetBrainsMono で SF Mono を代替)
overflow: hidden + borderRadius: 10 ClipRRect(borderRadius: 10)

他の翻訳例

React 版 Flutter 版
CSS white-space: nowrap TextmaxLines: 1 + overflow: TextOverflow.ellipsis
transform: translateY(-60px) でタイトル被せ Transform.translate(offset: Offset(0, -60))
React の state lifting Riverpod の Provider 階層

Part 2 のまとめ

  • Claude Code は Claude Design のコンテキストを持たない。入り口は Handoff Bundle の README.md だけ
  • Flutter 固有の制約(バージョン / アーキテクチャ / 規約)は Part 2 のプロンプトで指定する
  • React → Flutter の翻訳は「見た目を合わせて、構造はネイティブのイディオムに書き直す」
  • 生成されたプロジェクトは CLAUDE.md で次回セッション用の規約を残す

未対応・次にやるなら

  • Tweaks パネルの移植: React 版の実行時言語切替 / レイアウト切替 UI は未移植。appSettingsProvider の API は既にあるので、設定画面を 1 つ足せば動く
  • 実データ接続: MovieRepositoryconst の in-memory。REST / GraphQL クライアントを書いて Provider を overrideWithProvider で差し替えるだけ
  • テスト: ProviderContainer(overrides: [movieRepositoryProvider.overrideWithValue(FakeRepo())]) パターンは書きやすい構造になっているが、実テストはまだ 0 件

やってみて分かったこと

  1. Claude Design と Claude Code は別ツール別責務。前者はデザイン+プロトタイプ、後者はプロジェクトへの実装。引き渡しは Handoff Bundle で行う
  2. Flutter の知識を入れる場所は Step 2。Step 1 では「ダークで情報リッチ」程度の抽象的な指示で十分。アーキテクチャを前倒しで指定する必要はない
  3. 一発で意図を伝えるのは諦めていい。誤解したら言い直す。1 ターンの修正が Figma での作業より軽い
  4. 曖昧な指示(Step 1 側)は AI に任せる価値がある。「UX を改善したい」レベルでも文脈を踏まえた構造を選んでくる
  5. 指定すべきは「設計」と「規約」(Step 2 側)。アーキテクチャ、状態管理、命名など、人間がピン留めしないと、生成コードは「動くけど保守しにくい」ものになるので、ここはエンジニアのスキル次第

画像の写経、プロパティの読み取り、規約に従ったボイラープレート、この辺の作業時間は確実に消滅してます。

人間が時間を使うのは、「何を作るか」を定義する時間(Step 1)と、「どう作るか」の規約を書く時間(Step 2) により集中できそうですね。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?