mcpField
V
visual-feedback-loop

visual-feedback-loop

github.com/vladmdgolamテスト・品質952 回インストール2 週間前に更新
リポジトリ

visual-feedback-loop について

Visual Feedback Loop は、開発中に Web アプリの表示を確認するスキルです。サーバーがブラウザーと連携してスクリーンショットを取得し、メタデータやピクセル差分でコード状態ごとの描画変化を追跡できます。

主な機能

  1. 01ブラウザー経由の画面キャプチャ
  2. 02タイムスタンプ付き画像とメタデータの保存
  3. 03ピクセル差分による画像比較
  4. 04コードコミットとページパラメーターの記録
  5. 05SSE によるキャプチャ要求の調整

活用シーン

  1. 01Web アプリの現在の表示確認
  2. 02コード変更前後の画面比較
  3. 03画像に対応するコード状態の追跡

インストール

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

$npx skills add https://github.com/vladmdgolam/agent-skills --skill visual-feedback-loop

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

同梱ファイルreferences/errors.mdreferences/setup-nextjs.md

詳細

ビジュアルフィードバックループ

反復的な開発中に、実行中のウェブアプリのビジュアル出力をキャプチャし、確認して比較します。

仕組み

Agent (CLI)                     Server                            Browser
     |--- GET /api/dev-screenshot -->|--- SSE "capture" ----------->|
     |    ?param=value               |                              |-- capture canvas
     |                               |<-- POST { dataUrl } ---------|
     |                               | writes:
     |                               |   .screenshots/{UTC}.webp
     |                               |   .screenshots/{UTC}.json  (metadata)
     |                               |   .screenshots/latest.webp (convenience copy)
     |<-- { ok, path, latest } ------|

エージェントはブラウザーに直接アクセスできません。サーバーが中継します。GET がトリガーとなり、SSE がブラウザーに通知し、ブラウザーがキャプチャして POST で返すと、GET が完了します。

使い方

現在の表示をキャプチャします:

curl http://localhost:3000/api/dev-screenshot

パラメーターを指定してキャプチャします(アプリ固有のもので、ブラウザークライアントが解釈します):

curl 'http://localhost:3000/api/dev-screenshot?component=header&theme=dark'
curl 'http://localhost:3000/api/dev-screenshot?letter=б&depth=0.8'

その後、結果を読み取ります。レスポンスには path(タイムスタンプ付きファイル)と latest(便利なコピー)が含まれます:

Read .screenshots/latest.webp
ビジュアル回帰(ピクセル差分)

ImageMagick を使って、正解のスクリーンショットと比較します:

magick compare -metric RMSE .screenshots/ground-truth.webp .screenshots/latest.webp .screenshots/diff.webp

RMSE の出力:0.01 は約 1% の差(レンダリングノイズ)、0.03+ は目に見える変化です。確認用に差分画像を保存してください。

メタデータサイドカー

各スクリーンショットには、同じ UTC タイムスタンプの JSON サイドカーが付与されます:

{
  "timestamp": "2026-02-25T08:22:12.655Z",
  "git": { "commit": "0a5726f", "dirty": true },
  "params": { "letter": "о", "chamferModel": "membrane", "cameraView": "front" },
  "format": "webp",
  "file": "2026-02-25T08-22-12-655Z.webp"
}

これを使うと、どのコードの状態とパラメーターでスクリーンショットが生成されたかを追跡できます。複数のコード変更をまたいで反復する場合に欠かせません。

A/B 比較ワークフロー
  1. 正解画像をキャプチャします:curl '...?letter=о' → {UTC}.webp のファイル名を控えます
  2. コードを変更し、ブラウザーを更新します
  3. もう一度キャプチャします:curl '...?letter=о'
  4. 差分を取ります:magick compare -metric RMSE .screenshots/{ground-truth}.webp .screenshots/latest.webp .screenshots/diff.webp
  5. 差分画像を読み込み、RMSE の値を確認します

コンソールから実行する場合:await window.__takeDevScreenshot()

ルール

  1. キャプチャ後は必ず .screenshots/latest.webp を読み込んでください。 レンダリングが正しいと思い込んではいけません。
  2. アプリの URL を開いたブラウザータブが必要です。 タイムアウトは SSE 接続がないことを意味します。ユーザーに更新を依頼してください。
  3. リクエストは一度に 1 件だけです。 2 件目の GET は 409 を返します。最初のリクエストが完了(成功/エラー/10 秒のタイムアウト)するまで待ってください。
  4. エラーはタイムアウトではなく、即座に返されます。 クライアントはエラーを POST で返します:{ ok: false, error: "..." }。
  5. HMR への耐性。 モジュールの再読み込み後も状態を維持できるよう、サーバー側の SSE 状態を globalThis に保存してください。クライアントの EventSource は自動的に再接続します。コード変更後もスクリーンショットを撮れない場合は、ユーザーに更新を依頼してください。
  6. HMR は画面外のレンダリングパスを更新しません。 useEffect 内のクロージャは古いモジュール参照を保持します。レンダリングロジックを変更した後は、必ずユーザーにハードリフレッシュを依頼してください(macOS では Cmd+Shift+R、Windows/Linux では Ctrl+Shift+R)。

トラブルシューティング

症状対処方法
タイムアウト:ブラウザーから応答がありませんブラウザーでアプリを開く/更新する
409:すでに処理中ですタイムアウト(10 秒)まで待つ
黒い画像/空の画像ブラウザーのタブを更新する
一度は動作するが、その後タイムアウトするHMR により SSE が機能しなくなりました。タブを更新してください(globalThis パターンを使っている場合はまれです)
コードの変更がスクリーンショットに反映されないHMR は画面外のレンダラーを更新しません。ハードリフレッシュしてください(macOS では Cmd+Shift+R、Windows/Linux では Ctrl+Shift+R)
異なるコードの状態のスクリーンショットを比較しているJSON サイドカーで git コミットと dirty フラグを確認する

すべてのエラーについては、references/errors.md を参照してください。

セットアップ

このパターンはフレームワークに依存しません。GET/POST ルートと SSE を備えた HTTP サーバーがあれば使用できます。参照実装では Next.js を使っていますが、同じ方法は Express、Fastify、Hono、Vite 開発サーバープラグイン、その他の Node.js HTTP サーバーでも動作します。

Next.js の完全な実装(API ルート、SSE リスナー、WebMCP 登録)については、references/setup-nextjs.md を参照してください。ルートハンドラーを使用するフレームワークに合わせて調整してください。クライアント側の SSE リスナーとキャプチャロジックは、サーバーフレームワークにかかわらず同一です。

コメント