record-browser-gif について
record-browser-gifは、ブラウザー画面のデモGIFを作成するスキルです。分離した環境での録画、エンコード、検証を支援し、依頼がある場合に限りPull Requestへ添付します。
主な機能
- 01ブラウザー動画またはスクリーンショットの撮影
- 02GIFのエンコードと検証
- 03各ストーリーボードを単一の分離実行に限定
- 04依頼時のGIFのPull Requestへの添付
活用シーン
- 01Pull RequestのGUI変更を実演
- 02ローカルのUIデモGIFを作成
- 03公開前に録画内容を確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ deepseek-ai/ deepseek-harness --skill record-browser-gifインストール後、Claude Code で/record-browser-gifを入力して読み込まれたか確認します。
同梱ファイルscripts/encode_gif.pyscripts/test_encode_gif.py
詳細
ブラウザーの GIF を記録する
短く、事実に即した UI のデモをローカルの GIF として作成します。また、タスクにプルリクエストへの添付が含まれる場合に限り、このスキルの最後にある添付ワークフローを通じて公開します。利用可能なブラウザー操作のワークフローを引き続き優先します。そのワークフローが高いフレームレートでの連続キャプチャに対応している場合は、Playwright Videos を使用します。トリミング、再生速度、最後の静止時間、サイズ、ファイルサイズの調整には、同梱のエンコーダーを使用します。
アーカイブされた証拠チェーンの決定には、1 つのストーリーボードを 1 回の分離された実行から作成する理由と、公開時に成果物および実演対象のプルリクエストの HEAD の両方を再検証する理由が記録されています。
すべての GUI のプルリクエストに GIF を含める
ユーザーに見える製品の GUI 動作を変更するプルリクエストには、このスキルで記録したデモ GIF を必ず含め、添付ワークフローを通じてプルリクエストの本文に埋め込む必要があります。
記録自体も証拠の一部です。そのプルリクエストのブランチツリーから起動した実サーバー、実際の API キー、実際のモデルラウンドを使用してください。ユーザーが明示的にフィクスチャを使った記録を依頼した場合を除き、フィクスチャクエリ、モックトランスポート、合成イベントの注入、テスト専用フックで代用してはいけません。埋め込みの近くに、実演した正確なコミット SHA、それを提供したツリーとオリジン、使用したモードフラグやブラウザー状態の例外、実際のモデルラウンドが実行されたかどうかを記載し、レビュー担当者が記録によって何が証明されるのかを正確に把握できるようにしてください。
記録と公開を分ける
- 記録ではローカルの動画またはスクリーンショットと、1 つの
.gif成果物のみを生成します。リモートの状態は変更しません。 - 公開は、
gh --attachを使ってプルリクエストの本文に GIF を添付するか、それが適用できない場合にアセットブランチにプッシュして URL を埋め込む作業です。これは独立した最終ステップであり、タスクにプルリクエストへの GIF の添付が含まれる場合に限り実施します。プルリクエスト自体のブランチには触れません。 - 指定された記録条件を守ってください。実サーバーまたは実 API のデモでは、フィクスチャクエリ、モックトランスポート、合成イベントの注入、テスト専用フックを使用してはいけません。認証情報またはサーバーを利用できない場合は、フィクスチャで代用せず、その制限を報告してください。
- 認証情報の値を読み取ったり、公開したりしてはいけません。アプリケーションの通常の設定経路と、無害なデモ用プロンプトを使用してください。
アプリケーションを準備する
特定のプルリクエストの GIF は、そのプルリクエストのツリーを実演するものです。そのため、プルリクエストごとに準備します。
- ワークツリーがクリーンであることを確認し、
git rev-parse HEADで正確なコミットを記録してから、その記録したツリーをビルドします。ここではpnpm run build && pnpm run build:webを実行します。別のコミットのビルドを使って記録した GIF は、証拠の帰属を誤らせます。 - そのツリーから、ポートごとに 1 つのサーバーを起動します。
DSH_HOME、DSH_AGENTS_HOME、ワークスペース、セッションの状態には、新しいスクラッチ領域を使ってください。ブラウザーにも新しい分離コンテキストまたはプロファイルを使用します。ブラウザーのワークフローでそれを作成できない場合は、永続化されたクライアント状態が証拠に影響しないよう、移動する前にそのオリジンの Cookie とサイトストレージを消去してください。DEEPSEEK_API_KEYとルートの.envがなくても、実際の API 認証情報が~/.dsh/.credentials.yamlにある場合があります。スクラッチのDSH_HOMEを使う場合は、記録用オーバーレイを使用して、dsh-credentials-localプロバイダーのpathに既存ファイルの絶対パスを設定してください。キーはアプリケーションの通常の認証情報プロバイダーに解決させ、表示してはいけません。 - 1 つのストーリーボードを 1 回の証拠実行として扱います。公開するすべてのフレームは、そのサーバー、状態のルート、ワークスペース、セッション、およびモデルを使ったシナリオ実行から取得してください。キャプチャの自動化に失敗した場合は、そのフレームを破棄し、新しいルートからやり直してください。別々の実行のフレームをつなぎ合わせてはいけません。
- プルリクエストを切り替える際は、PID またはコマンドラインとの完全一致を使って古いサーバーを停止してください。広範な
pkill -fパターンは、サーバーを起動したシェル自体に一致して終了させる可能性があります。
フローを記録する
利用可能なブラウザー制御ワークフローのセットアップ、操作、クリーンアップに関する指示に従ってください。recordVideo が利用可能な場合は、同じ制御対象コンテキストで動画を有効にして、より多くの中間フレームを記録してください。それ以外の場合は、そのワークフロー内でスクリーンショットのキャプチャを使用してください。動画が利用可能かどうかによって、使用するブラウザー制御ワークフローを変えてはいけません。既存のユーザーブラウザーの状態は、明示的な隔離の例外として扱います。
ブラウザー制御が利用できない場合に限り、リポジトリで宣言されている Playwright の依存関係を使い、隔離されたヘッドレスブラウザーで実行し、キャプチャに関するメモにそのフォールバックを明記してください。このリポジトリでは、依存関係は apps/web/package.json から解決されます。別のドライバーをインストールしたり、ユーザーのブラウザーを開いたりしないでください。
記録を始める前に、オリジン、ビルド済みまたは開発用サーバー、トランスポート、モードのオーバーライドを特定してください。本番環境のデフォルトで、自動化から操作できないネイティブ画面が開く場合は、通常のアプリケーション設定を通じて、公式のブラウザー操作可能な本番バックエンドを選択し、そのオーバーライドを開示してください。
スクリプト、生動画、タイミングメモ、QA フレーム、GIF は、リポジトリの gitignore 対象である .playwright-mcp/ ディレクトリの下に保存してください。最初に実行ディレクトリを作成してください。
動画をキャプチャする
viewport と recordVideo.size を明示的に一致させてください。Playwright は、指定しないと動画を 800×800 に収まるよう縮小するため、UI のテキストが読みにくくなることがあります。
選択したブラウザー制御ワークフローを通じて動画を設定してください。スタンドアロンの Playwright フォールバックでは、次を使用します。
const { chromium } = createRequire(join(repo, 'apps/web/package.json'))('playwright')
const browser = await chromium.launch()
const size = { width: 1440, height: 900 }
const context = await browser.newContext({
viewport: size,
recordVideo: { dir: join(runDir, 'videos'), size },
})
try {
const page = await context.newPage()
const video = page.video()
// Navigate and exercise the real application here.
await context.close()
await video.saveAs(join(runDir, 'demo.webm'))
} finally {
await context.close()
await browser.close()
}
記録スクリプトで node:module から createRequire を、node:path から join をインポートしてください。repo と新しい runDir を絶対パスに設定してください。ページの動画ハンドルは、ページを閉じる前に保持してください。video.saveAs() を呼び出すかエンコードする前に、context.close() の完了を待ってください。ブラウザーだけを閉じても、動画のフラッシュは保証されません。各ページにはそれぞれ独自の動画があります。実演したページを明示的に選び、関係のないページや実行の動画を結合しないでください。失敗した実行は診断目的に限って使用します。
意味のある状態が 3〜6 個ある、短いストーリーを選んでください。操作する前に、一意のセマンティックロケーターを待機してください。アクセシブル名の完全一致には exact: true を使い、プロンプトのエコーには一致しない完全一致のテキスト完了条件を使用してください。固定時間の待機は、状態の確認後に読み取り時間を設ける目的であれば使用できますが、準備完了の判定には使用しないでください。動画をキャプチャする際は、アニメーションとスクロールを維持してください。
ツール呼び出し、拒否、または復旧を実演する際は、その詳細または軌跡を開き、動画でツールの識別情報、ステータスまたは安定したエラーコード、後続の結果が見えるようにしてください。一時的な実行中の状態が重要な場合は、時間のかかるフォアグラウンド操作を促すプロンプトを使い、具体的な DOM マーカーを確認してください。連続動画でその中間フレームをキャプチャできます。完了を明確にするため、モデルには短い最終センチネルを指示してください。実演する状態が見えたら、実 API を使った実行が不必要に長引かないよう停止してください。
秘密情報、個人情報、無関係なタブ、通知はキャプチャしないでください。ブラウザー動画に含まれるのはページの内容であり、ブラウザーのクロームは含まれません。認証情報を含む URL がアプリケーション上に表示されないようにしてください。中間状態も含め、選択した区間全体を確認してください。ビューポートは終始同じものを使用してください。
GIF をエンコードする
python3、ffmpeg、ffprobe が必要です。メディア用バイナリが見つからない場合は、許可なくソフトウェアをインストールせず、依存関係を報告してください。GIF_SKILL_DIR は使用前に単独の行でエクスポートしてください。同じコマンド内でインライン代入しても、引数の展開には反映されません。
export GIF_SKILL_DIR=/absolute/path/to/this/skill
python3 "$GIF_SKILL_DIR/scripts/encode_gif.py" \
/absolute/path/to/demo.webm \
/absolute/path/to/demo.gif \
--start 2 --end 32 --speed 2 --final-hold 3 \
--fps 10 --max-width 1200 --colors 128
--start と --end では、連続したソース区間を秒単位で指定します。デフォルトでは動画全体を 1× の速度で使用し、最後に 2 秒間の静止表示を追加します。--speed で再生速度を変更できます。デモが実測の応答遅延を示していると誤解されないよう、GIF の横に速度と選択した区間を記載してください。推測した実時間のオフセットではなく、動画で確認できる時刻を使用し、実演した動作の原因から結果までを完全に保持してください。最後の静止表示では、選択した最後のフレームを繰り返します。--fps では、エンコードする GIF のフレームレートを設定します。値を上げても、ソースの録画に含まれていない動きを復元することはできません。QA 用に元の WebM を残してください。別々の実行をつなぎ合わせたり、欠けている状態を合成したりしないでください。
エンコーダーは WebM コンテナの再生時間を調べ、パレット変換の前にトリミングと速度の調整を適用し、エンコード後の再生時間、アニメーション、幅、バイトサイズを確認します。空の区間や範囲外の区間、出力フレームが 2 枚未満になる選択、モードに適さないフラグ、意図しない上書きは拒否されます。ファイルサイズが大きい場合は、まず --max-width を下げ、次に --colors または --fps を下げてください。読みやすいテキストは維持してください。正確な出力パスを確認してから、--force を使用してください。
スクリーンショットのキャプチャ
連続した動画を利用できない場合や、ユーザーがストーリーボードを求めている場合は、利用可能なブラウザー制御のワークフローに従ってください。ブラウザーのスクリーンショット API を使い、分離した 1 回の実行から確認済みの状態を 3~6 枚キャプチャします。返された画像バイト列は、00-initial.png、01-typed.png などの名前で、1 つの実行ディレクトリ直下に直接保存してください。すべて同じ寸法と切り抜きを使用します。一時的な状態では、同じブラウザースクリプト呼び出し内で DOM マーカーをポーリングし、キャプチャしてください。
python3 "$GIF_SKILL_DIR/scripts/encode_gif.py" \
/absolute/path/to/frames /absolute/path/to/demo.gif \
--durations 1.5,1.5,1.5,3.5 --fps 10 --max-width 1200 --colors 128
すべてのスクリーンショットに同じ表示時間を適用します。異なる時間を指定する場合は、各フレームに正の時間を 1 つずつ指定し、状態が確定した後の表示時間を最も長くしてください。ディレクトリ入力では、フレームが 2 枚未満の場合や、寸法または表示時間の数が一致しない場合は拒否されます。動画のタイミング用フラグは動画ファイルにのみ適用され、--durations と --pattern はスクリーンショットのディレクトリにのみ適用されます。
成果物を検証する
- エンコーダーの JSON サマリーを読み、出力パス、ソース区間と速度(またはスクリーンショットの枚数)、エンコード後のフレーム数、寸法、再生時間、バイトサイズを確認します。
- ソースフレームだけでなく、エンコード後の GIF 自体を目視で確認します。遷移が読み取れること、最後の状態が十分な時間表示されること、機密情報が含まれていないことを確認してください。ビューアーが最初のフレームしか表示しない場合は、
ffmpegでエンコード後の GIF から代表的なフレームをデコードして確認します。エンコード前のスクリーンショットだけでは、エンコード後の順序、パレット、最後の静止表示を検証できません。 git status --shortを実行し、元動画、QA 用フレーム、成果物がすべて無視対象のパス内にのみ保存されていることを確認します。- GIF の絶対パスを返し、クライアントがローカルメディアに対応している場合は GIF を表示します。また、録画に実際の API、フィクスチャ、その他のトランスポートのどれを使用したかを明記します。タスクに GIF のプルリクエストへの添付が含まれない場合は、ここで終了してください。
エンコーダーの保守:メディアの前提条件を満たした状態で、python3 -m unittest discover -s "$GIF_SKILL_DIR/scripts" -p 'test_*.py' -v を実行してください。これらのローカルメディアテストはリポジトリの CI では実行されません。
GIF を公開する
この手順は、タスクに GIF のプルリクエストへの添付が含まれる場合にのみ実施してください。
プルリクエスト自身のブランチ、または長期運用ブランチにマージされるブランチには、GIF を決してコミットしないでください。そこにバイナリメディアをコミットすると、以降のすべてのクローンでリポジトリの履歴が肥大化します。GIF を GitHub にアップロードし、本文中の参照を 1 つのコマンドで書き換えられる gh --attach を優先してください。そうすれば、メディアを含むブランチを作らずに済みます。
gh で添付する
gh --attach を使うには、gh v2.99.0 以降(gh --version)、github.com 上のリポジトリ(GitHub Enterprise Server はサポートされていません)、リポジトリへの書き込み権限、および 10 MB 以下の GIF が必要です。検証済みの成果物がこの制限内であることを確認してください。超えている場合は、添付する前に --max-width、続いて --colors または --fps でサイズを縮小してください。
GIF は通常のローカルパス参照として本文ファイルに記述してください。--attach に渡すパスと同じパスを使います。gh は参照の位置と代替テキストを維持したまま、アップロード URL に書き換えます。

通常、デモ対象のプルリクエストが公開先です。ツール開発用のプルリクエストに、別のプルリクエストの内容だと明確にラベル付けした例を埋め込むこともできます。その場合は元の PR を明記し、以下の各確認でその PR の最新ヘッドを比較してください。例をツール開発ブランチのものとして記載しないでください。
添付する直前に、デモ対象のプルリクエストの最新ヘッド(新規のデモ対象プルリクエストの場合は、プッシュしたブランチの先端)を読み直し、GIF の横に記録したコミットと比較してください。変更されていたら作業を中止して、記録し直してください。その後、添付します。
gh pr create --body-file <body.md> --attach <path/to/demo.gif> # new pull request
gh pr edit <pr> --body-file <body.md> --attach <path/to/demo.gif> # existing pull request
--attach は繰り返し指定できますが、同じファイルを 2 回添付することはできません。本文で参照されていない GIF は末尾に追加され、その場合はフラグで設定した代替テキスト(--attach '<path>#<alt text>')が適用されます。書き換えられた参照では、本文の代替テキストが維持されます。添付後、デモ対象の最新ヘッドを読み直し、記録したコミットから変わっていないことを確認してください。最新の本文を読み直し、参照がアップロード URL を指していることを確認します。本文を GitHub の Markdown API でレンダリングし、想定した <img> があることを確認してから、アップロード URL を 1 回取得し、ステータスが 200 でコンテンツタイプが image/gif であることを確認してください。
assets ブランチに切り替える
gh --attach を使えない場合に限り、assets ブランチのワークフローを使ってください。該当するのは、GIF が 10 MB を超えたままの場合、gh が v2.99.0 より古い場合、またはリポジトリが github.com 上にない場合です。この場合、GIF は専用の孤立 assets ブランチ(親コミットがなく、メディアのみを含むブランチ)に保存します。1 つの assets ブランチで一連のプルリクエスト全体に対応し、名前は <series>-assets とします。既存のブランチは git ls-remote --heads origin '*assets*' で一覧表示できます。
以下いずれかのワークフローでプッシュする前に、assets ブランチにメディア以外が含まれていないことと、ステージングした GIF のチェックサムが検証済みのローカル成果物と一致することを確認してください。
既存の assets ブランチの場合は、公開作業が作業ツリーに影響しないよう、シャロークローンの単一ブランチのスクラッチクローンで作業します。
git clone --branch <assets-branch> --single-branch --depth 1 <repo-url> /tmp/assets-checkout
cp /absolute/path/to/demo.gif /tmp/assets-checkout/<name>.gif
cd /tmp/assets-checkout
git add <name>.gif
git commit -m "assets: <what it shows> gif (#<pr>)"
git push origin <assets-branch>
新しいシリーズの場合は、新しいシャロースクラッチクローン(git clone --depth 1 <repo-url> /tmp/assets-checkout)を作成し、git switch --orphan <assets-branch> で孤立ブランチを作成してから、同じ方法で GIF を追加、コミット、プッシュします。
プッシュ後、認証済みの GitHub API または raw リクエストを使って、リモート上のパス、バイト数、チェックサム、ステータス 200、コンテンツタイプ image/gif を確認してください。プライベートリポジトリのアセットの場合、匿名アクセスで 404 が返っても、そのアセットが存在しない証拠にはなりません。認証して確認してください。これにより確認できるのはリポジトリメンバーがレビューできることだけであり、一般公開されていることではありません。
プルリクエストの本文を編集する直前に、デモ対象のプルリクエストの最新ヘッドを読み直し、GIF の横に記録したコミットと比較してください。変更されていたら作業を中止して、記録し直してください。編集後、デモ対象の最新ヘッドを読み直し、記録したコミットから変わっていないことを確認してください。別途、本文を GitHub の Markdown API でレンダリングし、想定した <img> が含まれていることを確認します。
プルリクエストの本文には raw blob URL で GIF を埋め込んでください。?raw=true のサフィックスが必要です。通常の blob URL を使うと、画像ではなく GitHub のファイルページが表示されます。

assets ブランチを削除または書き換えたり、強制プッシュしたりしないでください。マージ済みのプルリクエストの本文では、その URL がいつまでも参照されます。新しいコミットの追加のみ行ってください。