mcpField
P
preview-widget

preview-widget

github.com/chunkytofustudiosデザイン・UI554 回インストール26 週間前に更新
リポジトリ

preview-widget について

アプリ全体を起動せずにFlutterの単一ウィジェットをWidget Previewerで表示するスキルです。コンポーネントのデザインを反復調整する開発者向けに、プレビューサーバー管理、ヘッドレス撮影、既存プレビューの検索を行うスクリプトを備えています。

主な機能

  1. 01Flutterの対応バージョンを確認
  2. 02プレビューサーバーの起動と停止
  3. 03ヘッドレスChromeでプレビューを撮影
  4. 04プロジェクト内のプレビュー注釈を検索
  5. 05コンポーネントの複数バリエーションを表示

活用シーン

  1. 01単一ウィジェットの見た目を調整
  2. 02ライト、ダーク、タブレット表示を比較
  3. 03アプリ全体を起動せず描画を確認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/chunkytofustudios/flutter-skills --skill preview-widget

インストール後、Claude Code で/preview-widgetを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

assets/
multi_preview.dart.template
preview_wrapper.dart.template
references/
limitations.md
preview_annotations.md
wrapper_patterns.md
scripts/
check_preview_support.sh
list_previews.sh
screenshot_preview.sh
start_preview.sh
tests/
check.bats
help.bats
helpers.bash
list_previews.bats
screenshot.bats
start.bats
tests/stubs/
chrome
flutter

詳細

Flutter ウィジェットを単独でプレビューする

Flutter の Widget Previewer でウィジェットを 1 つだけレンダリングし、アプリ全体を起動せずに、人と一緒にデザインの微調整、ライト/ダークのバリエーション、タブレット向けのサイズ調整などを繰り返せます。エージェントはライブプレビューをヘッドレスでスクリーンショットに撮影します。人は必要に応じて、同じ localhost URL を自身の Chrome で開いてプレビューを確認できます。

使用するタイミング

次の 3 つすべてに当てはまる場合に使用します。1 つでも当てはまらない場合は、このスキルは適していません。

  1. プロジェクトが Flutter プロジェクトである(作業ディレクトリに pubspec.yaml があり、lib/ が存在する)。
  2. Flutter ≥ 3.35 が PATH 上にある(または fvm flutter で利用できる)。プレビュー機能は stable では実験的ですが、デザインの検討には十分使えます。古い Flutter にはこの機能がありません。
  3. ユーザーが、画面全体やエンドツーエンドのフローではなく、単一のウィジェットを繰り返し調整したい。画面全体のビジュアル作業には design-polish と android-emulator を使用します。

セットアップ(呼び出し元のマシン)

要件満たす方法
Flutter ≥ 3.35bash scripts/check_preview_support.sh を実行します。バージョンが古い場合は、アップグレードを促すメッセージを表示して明確に失敗します。Flutter バイナリは FLUTTER_BIN=… で上書きできます(デフォルト:flutter、見つからない場合は fvm flutter にフォールバックします)。
Google Chrome / Chromiumプレビューをキャプチャするために、screenshot_preview.sh がヘッドレスで使用します。macOS では /Applications/Google Chrome.app が自動的に検出されます。Linux では google-chrome、chromium、chromium-browser のいずれかが PATH 上にあれば使用できます。CHROME_BIN=/path/to/chrome で上書きできます。
bash 3.2 以降(macOS のデフォルト)、awk、grep、find標準で利用できます。Python や Node は不要です。

マシンごとの認証、アカウント、トークンは不要です。すべて localhost 上で動作します。

同梱スクリプト

  • scripts/check_preview_support.sh — Flutter ≥ 3.35 を確認し、解決されたバイナリとバージョンを表示します。終了コード 0 = 準備完了、終了コード 1 = バージョンが古い、終了コード 127 = Flutter が見つからない。
  • scripts/start_preview.sh — flutter widget-preview start をバックグラウンドで起動し、ログから URL を解析して、小さな JSON 状態ファイルに書き込みます。冪等性があり、再実行すると既存の URL を返します。--stop でサーバーを停止します。デフォルトの状態ディレクトリ:./.preview-widget/(PREVIEW_WIDGET_STATE_DIR で上書きできます)。
  • scripts/screenshot_preview.sh — 起動中のプレビューのスクリーンショットを、ヘッドレス Chrome で撮影します。フラグ:--out <path>、--size WxH(デフォルト 1600x2400)、--wait <ms>(仮想時間の上限。デフォルト 10000)、--url <url>(状態ファイルを上書きします)。標準出力に絶対パスを表示します。
  • scripts/list_previews.sh — lib/ 内から @Preview(...)、@<Custom>Preview(...)、extends (Multi)?Preview の定義を検索し、すでに存在するものを再追加しないようにします。

4 つすべてのスクリプトで --help を利用できます。フラグを独自に指定する前に、ヘルプを確認してください。

Flutter プロジェクトごとの初回セットアップ

ウィジェットにアノテーションを付ける前に、プロジェクトにプレビューラッパーが必要です。これは、実際のウィジェットが前提とするグローバルな祖先チェーン(テーマキュービット/ProviderScope/MaterialApp/ローカライゼーション/MediaQuery のオーバーライドなど)を再現する、トップレベルの Widget previewWrapper(Widget child) 関数です。プレビューアの theme: パラメーターだけでは、単純でないアプリには不十分です。BlocBuilder<ThemeCubit, …> や Theme.of(context) を直接参照するウィジェットは、ツリーにキュービットがないと例外が発生するか、誤った表示になります。

手順:

  1. プロジェクトの lib/main.dart と lib/app.dart(または同等のルートファイル)を読みます。MaterialApp をラップするすべての要素(MultiBlocProvider、ProviderScope、MultiRepositoryProvider、カスタムの InheritedWidget、MediaQuery のオーバーライド、ロケール/ルーターの設定)を特定します。
  2. assets/preview_wrapper.dart.template を lib/preview_wrapper.dart にコピーします。
  3. インポートとプロバイダーリストを実際のルートツリーに合わせて記述し、実行時の状態が必要なプロバイダーはスタブ化します(例:UxCubit にはデフォルトの DeviceType.mobile を設定し、リポジトリのキュービットには空の状態またはフェイクの状態を設定します)。ラッパーはコンパイル時の tearoff であるため、コールバックはすべてトップレベルの公開関数である必要があります。
  4. パターンの例(BLoC、Riverpod、GoRouter、Localizations、MediaQuery、フォント)については、references/wrapper_patterns.md を参照してください。

ウィジェットに必要なプロバイダーがわからない場合は、ウィジェット本体で Theme.of、BlocBuilder<、context.watch<、context.read<、ProviderScope.containerOf、MediaQuery.of、Localizations.of、GoRouter.of を検索してください。これらはすべて、不可欠な祖先要素です。

ウィジェットごとのワークフロー

1. アノテーション対象を選ぶ

@Preview と @MultiPreview を適用できるのは、次の対象です。

  • Widget または WidgetBuilder を返すトップレベル関数
  • クラスの公開静的メソッド
  • 必須引数のない公開ウィジェットコンストラクター/ファクトリー

アノテーションに渡す値はすべて const である必要があります。また、コールバック(wrapper:、theme:、localizations:)はすべて、公開されたトップレベル関数(または静的関数)である必要があります。プライベートな状態をキャプチャするクロージャーはプレビューアに拒否されます。

2. アノテーションを付ける

プロジェクトのラッパーを使用する単一プレビュー:

import 'package:flutter/material.dart';
import 'package:flutter/widget_previews.dart';
import '../preview_wrapper.dart';

@Preview(name: 'MyButton — default', wrapper: previewWrapper)
Widget myButtonPreview() => const MyButton();

同梱の assets/multi_preview.dart.template から lib/preview_variants.dart を作成し、ライト+ダーク+タブレットのマルチプレビューマトリックスを設定します。

@StandardPreview()
Widget myButtonPreview() => const MyButton();

@Preview のパラメーター一覧と対象の制限に関するルールは、references/preview_annotations.md を参照してください。

3. プレビューサーバーを起動する
bash scripts/start_preview.sh
# → Preview: http://localhost:51530

冪等です。サーバーが起動中に再実行すると、URL が再表示されるだけです。状態ファイル .preview-widget/server.json には { "url", "pid", "log" } が格納されます。.preview-widget/ を .gitignore に追加してください。

4. 実行中のプレビューをスクリーンショットに撮る
bash scripts/screenshot_preview.sh
# → /tmp/preview-widget/preview-001.png

次に、PNG を Read してライブプレビューを確認します。デフォルトのキャプチャサイズはビューポート 1600×2400 です(プレビュータイルを約 3 つ縦に並べて表示できます)。より縦長にキャプチャするには --size 1920x4000 を、保存先を指定するには --out /tmp/foo.png を渡します。最初の描画が空白の場合は、--wait 20000(20 秒)に増やしてください。これはキャンバス/Skia の起動に必要な時間です。

5. 繰り返す
edit Dart → sleep 2 → screenshot → read → reason → repeat

ファイルを保存するとプレビューアが自動でホットリスタートするため、手動での再起動は不要です。2 秒のスリープにより、次のスクリーンショットを撮る前にホットリスタートが完了します。

6. ターンの最後に必ず URL を出力する

プレビューアに関する操作を行ったアシスタントのメッセージはすべて、次の行で終わる必要があります。

Preview: http://localhost:<port>

これにより、人間はいつでも参加したり、後から戻ってきたりできます。サーバーは start_preview.sh --stop を実行するまで起動したままです。

7. 完了したらクリーンアップする
bash scripts/start_preview.sh --stop

サーバーを停止し、状態ファイルを削除します。省略可能です。セッション間も起動したままで問題ありません。

既存のプレビューを確認する

新しい @Preview を追加する前に、プロジェクト内にすでにあるプレビューを確認してください。

bash scripts/list_previews.sh
# lib/widgets/foo.dart:42  @Preview(name: 'Foo - light', wrapper: previewWrapper)
# lib/widgets/bar.dart:17  @StandardPreview()
# lib/preview_variants.dart:9  final class StandardPreview extends MultiPreview {

対象範囲を指定するには、明示的なルートを渡します:bash scripts/list_previews.sh lib/src/widgets。

注意点

  • ラッパーが重要な役割を担います。 wrapper: previewWrapper を指定せずに単純な @Preview を使うと、ウィジェットのビルド時にプロバイダーやキュービットを読み込むアプリでは、クラッシュしたり正しく描画されなかったりします。ウィジェットが BlocBuilder<ThemeCubit> を使っていて、ラッパーがその上位に ThemeCubit を配置していない場合、プレビューでは ProviderNotFoundException が発生します。これはプレビューツールのバグではありません。
  • size: が制約するのはウィジェットであり、キャンバスではありません。 size: を指定していないウィジェットは、制約がない場合、プレビューツールのキャンバスの約半分のサイズに自動調整されます。単一コンポーネントのプレビューでは、ほとんどの場合望ましくありません。ボタンサイズのコンポーネントには size: Size(360, 80) を、タブレットレイアウトには size: Size(1024, 1366) を指定してください。
  • アノテーションの値はすべて const である必要があります。 wrapper:、theme:、localizations: のコールバックも含まれます。ラムダではなく、トップレベル(または static)の公開関数への参照でなければなりません。外部の値をキャプチャすると、コンパイルに失敗します。
  • プレビューするウィジェットでは、アセットパスに packages/<name>/... を指定する必要があります。 Image.asset('assets/foo.png') を使うウィジェットは実際のアプリでは動作しますが、プレビューツールでは動作しません。どちらの環境でも使えるように、Image.asset('packages/<your_pkg>/assets/foo.png') に変更してください。
  • dart:io、dart:ffi、ネイティブプラグインは使えません。 プレビューツールは Chrome で動作するため、File、Platform、ネイティブチャネル、プラットフォームプラグインにアクセスすると、プレビューの描画時にエラーが発生します。条件付きインポート(if (dart.library.html) など)で回避できます。
  • 初回の描画には時間がかかります。 初めてプレビューを読み込む際、Flutter の Web 環境が JS/Skia を起動するため、通常は 5~10 秒かかり、ディスクが遅い場合はさらに長くなります。デフォルトの --wait 10000 で通常は十分です。スクリーンショットの不具合を疑う前に、値を増やしてください(例:--wait 20000)。
  • スクリーンショットはページ全体のみです。 プレビューツールはプレビューごとの URL を公開しないため、screenshot_preview.sh はページ全体(すべてのプレビュータイルを縦に並べたもの)をキャプチャします。エージェントは各タイルの上に表示された name: ラベルをもとに、どのタイルがどれかを判断します。プレビューを 1 つだけ表示したい場合は、ほかのプレビューを一時的にコメントアウトするか、--size に縦長の値を指定し、group: パラメーターを使って関連するバリエーションを隣接させてください。
  • ホットリスタートは自動ですが、即時ではありません。 .dart ファイルを編集したら、スクリーンショットを撮る前にプレビューツールが反映するまで約 1~2 秒待ってください。ラッパー自体の編集は、反映にさらに時間がかかります。sleep 5 の後もスクリーンショットに古い状態が表示される場合は、サーバーを再起動してください(--stop を実行してから、再実行します)。
  • サーバーごとにプロジェクトは 1 つです。 Flutter 3.35 の時点では、プレビューツールは IDE の操作フローで複数プロジェクトのワークスペースをサポートしていません。CLI サーバーが認識するのは現在のプロジェクトのみです。プロジェクトで Pub ワークスペースを使っている場合は、ワークスペースのルートからサーバーを起動してください。
  • flutter widget-preview は実験的機能です。 API や CLI フラグは、Flutter のバージョンによって変更される可能性があります。このスキルで使っているフラグが動作しなくなった場合は、flutter widget-preview --help の内容と start_preview.sh が渡す引数を確認してください。

クイックリファレンス

# 0. (one-time) Verify Flutter is recent enough.
bash skills/preview-widget/scripts/check_preview_support.sh

# 1. (one-time per project) Copy the wrapper template, fill in providers.
cp skills/preview-widget/assets/preview_wrapper.dart.template lib/preview_wrapper.dart
# …edit lib/preview_wrapper.dart, then add `.preview-widget/` to .gitignore

# 2. Annotate the widget (in its own file or alongside it).
#    @Preview(name: 'MyWidget', wrapper: previewWrapper)
#    Widget myWidgetPreview() => const MyWidget();

# 3. Start server, capture URL.
bash skills/preview-widget/scripts/start_preview.sh
# → http://localhost:51530

# 4. Iterate: edit → sleep 2 → screenshot → read → repeat.
bash skills/preview-widget/scripts/screenshot_preview.sh

# 5. Stop when done.
bash skills/preview-widget/scripts/start_preview.sh --stop

プレビューツールに関わる操作を行ったアシスタントの各応答の最後には、Preview: http://localhost:<port> を記載して、人がプレビューを確認できるようにしてください。

コメント