playproof について
playproofは、開発者やコーディングエージェント向けのブラウザーゲームテストツールです。仮想クロックにより、再現可能なフレーム単位の確認、スクリプト操作、クラッシュ検出、デバイスレイアウト検査、性能測定を行えます。
主な機能
- 01決定的なフレーム取得と比較
- 02スクリプト操作とストーリーボード実行
- 03再現可能なランダムクラッシュ探索
- 04デバイスサイズ別のレイアウト検査
- 05フレームペーシングと性能指標
- 06シナリオ別の動作スナップショット
活用シーン
- 01アニメーション変更のフレーム単位での確認
- 02記録した手順によるゲームクラッシュの再現
- 03スマートフォンとデスクトップの画面レイアウト確認
- 04CIでの動作・デバイス検査
MCP 対応
playproofは、ツールを呼び出すアプリ向けのMCPサーバーとしても動作し、検査用の画像をツールから直接返します。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
ツール
6掲載時のツール一覧 · 5 日前に更新
| パラメーター | 型 | 必須 | 説明 |
|---|---|---|---|
| fps | number | いいえ | シート上の1秒あたりのタイル数(デフォルト:約24タイルに合わせて調整) |
| area | string | いいえ | ゲーム領域の CSS セレクター(デフォルト:最大のキャンバス) |
| zoom | string | いいえ | 動く領域に合わせて切り抜く("auto")か、ゲーム領域に対する割合で x,y,w,h を指定します |
| ready | string | いいえ | ゲームの読み込み完了後に true となる JavaScript 式 |
| steps | string | いいえ | 「;」で手順を区切ります。手順(「;」または改行で区切り、「#」で始まる行はコメント):wait <time> 指定時間待つ(仮想時間:即時かつ正確)tap <x,y>|@label ゲーム領域内をタップ/クリック("50%,80%" またはピクセル座標 "120,300")press <x,y> <time> 長押し drag <x,y> <x,y> [time] スワイプ/ドラッグ(デフォルト 300ms)key <Key> [time] キーを押す。例:Space、ArrowLeft、a、Enter(デフォルトで 50ms 押し続ける)type <text> テキストを入力 click <css selector> DOM 要素(メニュー、HTML ボタン)をクリック shot [label] ストーリーボード用のスクリーンショットを撮影 film <time> [fps] 時間の経過中にフレームをキャプチャ until <js expression> [time] 式が真になるまで時間を進める(デフォルトのタイムアウトは 5s)js <js expression> ページ内で JavaScript を評価し、結果をログに記録 時刻形式:500、500ms、1.5s。 |
| device | string | いいえ | エミュレートするデバイス:"iPhone 15"、"Pixel 8"、"desktop"(デフォルト)、または "390x844@3 mobile" |
| target | string | いいえ | ゲームの URL(例:http://localhost:5173)、フォルダー(./dist)、または HTML ファイル。playproof.config.json に設定されている場合は省略可能です。 |
| compare | string | いいえ | 比較対象となる以前の frames 実行の出力フォルダー |
| waitFor | string | いいえ | 開始前に待機する CSS セレクター |
| duration | string | いいえ | 撮影時間。例:800ms、1.5s(デフォルト 1s) |
| scenario | string | いいえ | playproof.config.json 内のシナリオ名。手順、時間、ズーム、デバイスを指定します |
詳細
コーディングエージェントは数分でウェブゲームを書けますが、ゲームの動きを見届けることはできません。playproof を使えば、エージェント(そしてあなたも)がゲームをフレームごとに確認し、スクリプトによる入力でプレイし、クラッシュを探し、スマートフォンの画面で確認し、動作の滑らかさを測定できます。デスクトップでも、実際の Android スマートフォンでも利用できます。結果はすべて、読み取りやすい画像と、問題がありそうな箇所を示す短い概要として返されます。

Canvas 2D、DOM、Phaser 3、PixiJS 8、three.js、Godot 4 のウェブエクスポート、Unity WebGL ビルドでテスト済みです。それぞれを2回実行しても、同じフレームが得られます(npm run test:engines)。
インストール
エージェントに依頼する
これを Claude Code、Codex、Cursor、Gemini CLI、またはその他のコーディングエージェントに貼り付けます。
Install playproof from https://github.com/EmirhanOzl/playproof
エージェントが自身に適した下記のコマンドを選びます。
Claude Code
claude plugin marketplace add EmirhanOzl/playproof
claude plugin install playproof@playproof
Codex
codex plugin marketplace add EmirhanOzl/playproof
codex plugin add playproof@playproof
Gemini CLI
gemini extensions install https://github.com/EmirhanOzl/playproof
Cursor、OpenCode、GitHub Copilot、その他のエージェント
npx skills add EmirhanOzl/playproof
Claude Desktop、その他の MCP アプリ
コマンドを実行する代わりにツールを呼び出すアプリ向けに、playproof はツールから画像を直接返す MCP サーバーとしても動作します。アプリの MCP 設定に追加してください。
{
"mcpServers": {
"playproof": { "command": "npx", "args": ["-y", "playproof", "mcp"] }
}
}
エージェントを使わない場合
インストールは不要です。ゲームのフォルダーで npx playproof init を実行すると、playproof.config.json が作成されます(開発サーバー、ビルドフォルダー、または HTML ファイルを検出します)。または、任意のコマンドに開発サーバー、ビルドフォルダー、HTML ファイルを直接指定できます。
npx playproof frames http://localhost:5173 --device "Pixel 8" --do "tap 50%,50%" --duration 1s
playproof はインストール済みの Chrome または Edge を使用します。必要に応じて、npx playproof install-browser で専用の Chromium をダウンロードできます。
理由
スクリーンショットで捉えられるのはランダムな一瞬だけなので、ゲームを壊れたように感じさせる要素は見過ごされがちです。動き出す前の予備動作がないジャンプ、ワープするスプライト、1フレームだけのちらつき、何も起きないボタン、何百回もタップした後のクラッシュ、どのスマートフォンでもぼやけるキャンバスなどです。
playproof はゲームを仮想クロックで実行します。時間は playproof が進めたときだけ、正確に1フレームずつ進みます。そのため、どの瞬間も記録でき、実行するたびに同じピクセルが得られます。さらに、モデル(または人)が実際に確認できるようにフレームを並べます。実行結果が毎回まったく同じなので、エージェントは動きを記録し、コードを変更してからもう一度記録し、変更の影響を正確に確認できます。
できること
frames:アニメーションを確認する
ゲームを1フレームずつ撮影してコンタクトシートを作成します。破線の枠は前のタイルから変化した部分を示し、棒グラフは各フレームで画面のどの程度が変化したかを示します。playproof は突然のジャンプ(テレポート、トゥイーンの欠落)、1フレームのちらつき(描画順のバグ、状態の一部しか更新されない問題)、停止(動作の停滞)、まったく動かない状態にフラグを立てます。
npx playproof frames ./dist --device "Pixel 8" --do "tap @Play; wait 400ms; key Space" --duration 700ms

--animate を追加すると、実際の速度で再生されるアニメーション PNG も取得できます。自分で確認したり、プルリクエストに添付したりできます。動くものが小さい場合は、--zoom auto を追加します。playproof はデバイスのフル解像度で撮影し、動きの大部分がある位置に合わせて各フレームを切り抜くので、キャラクターのつぶれや伸びがタイルいっぱいに表示されます。
さらに、オニオンスキンも描画します。動き全体を1枚の画像に重ねて表示し、古い動きほど薄くなります。残像の間隔がイージングを表します(間隔が広いほど速く、狭いほど遅い)。これは、アニメーターが軌道、予備動作、オーバーシュートを評価する際に見るものと同じです。
frames --compare:変更の影響を確認する
撮影し、コードを変更してから、--compare <earlier run> を指定してもう一度撮影します。以前の実行の各サンプルフレームが、現在の同じフレームの上に並び、差分が輪郭で示されます。また、以前の実行の動きが新しい棒グラフの上に線として描画されます。実行は決定的なため、「同一」は完全に同一を意味します。
npx playproof frames http://localhost:5173 --do "tap @Play; key Space" --out .playproof/before
# ...change the jump...
npx playproof frames http://localhost:5173 --do "tap @Play; key Space" --compare .playproof/before

play:スクリプトを実行してストーリーボードを作成する
npx playproof play http://localhost:5173 --device "Pixel 8" \
--do "shot title; tap @Play; wait 400ms; key Space; film 600ms; until window.playproof.state().screen === 'over' 20s; shot game over; tap @Retry; shot retry"

monkey:クラッシュを探すランダムプレイ
タップ、ドラッグ、長押し、高速な3連続タップ、キー入力、タブをバックグラウンドに送る操作を、ランダムに、ただしシードによって再現可能な形で実行します。捕捉されなかったエラー、リクエストの失敗、ハング(無限ループ)、ソフトロック(入力は受け付けるものの何も変化しない状態)、レンダーループの停止を報告します。各エラーにはその状況を正確に再現するコマンドが付属し、実行全体は repro.steps に保存されます。play --script で操作を1つずつ再生し、重要な操作だけが残るまで行を削除できます。
ゲームがボタンを公開している場合(下記のフックを参照)、monkey が探索を行います。各画面で、同じ操作を繰り返す前に、まだ押していないボタンを試します。screens.png には到達したすべての異なる画面が表示されるので、ランダムプレイヤーがどこまで進めるか、またどの画面に到達できなかったかを確認できます。
npx playproof monkey ./dist --device "Pixel 8" --steps 300
ERROR Uncaught error: TypeError: Cannot read properties of undefined (reading 'activate')
during: action 13: tap 699,820, wait 119ms
at HTMLCanvasElement.<anonymous> (http://127.0.0.1:52009/:51:40)
Reproduce: playproof monkey "./dist" --seed 1 --steps 13 --device "Pixel 8"
devices:スマートフォン、タブレット、デスクトップを並べて確認する
9つの画面でゲームを読み込み、その画面でのみ発生するレイアウトのバグを確認します。ぼやけたキャンバス(devicePixelRatio に合わせたスケーリングがない)、引き伸ばされたキャンバス、キャンバスの切れ、ページのスクロール、viewport meta の欠落、touch-action: none の欠落、テキストの切れ、小さすぎるタッチターゲットが対象です。複数のデバイスで同じ問題が見つかった場合、報告は1回だけです。
npx playproof devices http://localhost:5173

実際の Android 端末で、Chrome またはアプリ内で
frames、play、monkey、perf は、--android(Chrome のタブ)または --app <package> を指定すると、USB 接続された Android 端末上で実行されます。--app <package> を指定すると、Capacitor、Cordova、Ionic で構築されたアプリ内の WebView に接続します。playproof は仮想クロックを使ってアプリのページを再読み込みするため、実機上の実際のアプリで、フレーム単位で正確な同じシートを取得できます。完了後には通常の状態に戻して再読み込みします。localhost は自動的に端末へ転送されます。
npx playproof frames http://localhost:5173 --android --do "tap 50%,60%" --duration 800ms
npx playproof monkey --app com.example.mygame --steps 200
npx playproof perf --app com.example.mygame --duration 10s --monkey
Capacitor アプリと Cordova アプリのデバッグビルドでは WebView のデバッグが有効になっています。それ以外のビルドについては、webContentsDebuggingEnabled を参照してください。Chrome では、playproof は専用のタブを開き、そのタブとのみ通信して、処理後にタブを閉じます。他のタブを一覧表示したり読み取ったりすることはありません。
perf:ローカルまたは実機でのフレームペーシング
ゲームをアイドル状態にする、スクリプトを実行する(--do)、またはランダムなタップを行う(--monkey)間の実際のフレーム時間を測定します。fps、p95/p99、ディスプレイのリフレッシュレートに対するドロップフレーム数、メインスレッドの長時間タスク、ヒープの増加量を計測します。ローカルでは、ミドルレンジのスマートフォンを想定して CPU を 4 倍遅くします。--android を指定すると、USB 接続された Android 端末上の Chrome を測定します。localhost は自動的に端末へ転送されます。
npx playproof perf ./dist --duration 10s --monkey
npx playproof perf http://localhost:5173 --android

シナリオと check:動きのスナップショットテスト
ゲームのデフォルト設定と、確認したいタイミングを playproof.config.json に記述します(エディターでは スキーマ に基づいて自動補完されます)。
{
"$schema": "https://unpkg.com/playproof/schema/config.schema.json",
"target": "http://localhost:5173",
"device": "Pixel 8",
"scenarios": {
"title": { "duration": "800ms" },
"jump": { "do": "tap @Play; wait 400ms; key Space", "duration": "700ms", "zoom": "auto" }
},
"check": { "monkey": { "steps": 200 }, "devices": true }
}
その後、ターゲットを省略でき、--scenario jump を指定するとステップリスト全体が置き換えられます。
npx playproof frames --scenario jump
playproof check は各シナリオを撮影し、playproof-baselines/ 内のベースラインと比較してから、monkey と devices を実行します。初回の実行でベースラインが書き込まれるので、コミットしてください。その後は、シナリオの動きに変更があると、変更箇所が正確にわかる compare.png とともにチェックが失敗します。--update を指定すると、その変更を受け入れられます。フォントとアンチエイリアスの違いを考慮し、ベースラインはオペレーティングシステムごとに保存されます。
npx playproof check # everything
npx playproof check --only jump # one scenario
npx playproof check --update # accept the current motion
CI での実行
- uses: actions/checkout@v7
- uses: EmirhanOzl/playproof@v0
with:
start: npm run preview
wait-for-url: http://localhost:4173
このアクションは Chromium をインストールし、playproof check(または command と args を使った任意のコマンド)を実行して、ジョブページにサマリーを書き込み、画像をアーティファクトとしてアップロードします。チェックを実行するマシンと環境を一致させるため、CI で Linux のベースラインを一度生成してください(初回の実行で書き込まれます。アーティファクトからダウンロードするか、そこで --update を実行してください)。
ステップ
--do と --script <file>(ファイルでは 1 行につき 1 ステップ)で使用します。ステップは ; で区切ります。座標はゲーム領域(最大の canvas、または --area <selector>)を基準とします。
| ステップ | 意味 |
|---|---|
wait 500ms | 時間を進めます(仮想クロックでは即座かつ正確です) |
tap 50%,80% / tap 120,300 / tap @Play | タップまたはクリックします。@label はゲームが公開するターゲットを使います |
press 50%,50% 800ms | 長押しします |
drag 10%,50% 90%,50% 300ms | スワイプします |
key Space [200ms] | キーを押します(デフォルトでは 50 ms 押したままにします) |
type hello | テキストを入力します |
click #start | DOM 要素をクリックします |
shot [label] | ストーリーボード用のスクリーンショットを撮ります |
film 1s [30] | 時間の経過中にフレームをキャプチャします |
until <js> [5s] | 式が true になるまで時間を進めます |
expect <js> | 式が true でなければ実行を失敗させます(左辺の値を表示します) |
background 5s | ゲームをバックグラウンドに移し(フレームなし)、その後前面に戻します |
js <js> | 値を評価してログに記録します |
時間:500、500ms、1.5s。
オプション:ゲーム内のフック
必須ではありませんが、小さな関数を 4 つ追加すると、テストの精度が向上します。
window.playproof = {
ready: () => assetsLoaded, // boolean, function or promise: when to start
state: () => ({ screen, level, score }), // logged; used to tell a soft-lock from a busy screen
targets: () => [{ x, y, width, height, label: "Play" }], // CSS px; enables "tap @Play" and aims the monkey at buttons
area: () => ({ x, y, width, height }), // the game world inside a letterboxed canvas; crops every capture
};
フックがない場合は、読み込みを待つために --ready "<js expression>" または --wait-for <selector> を使い、タップにはパーセンテージを指定します。examples/jumper では、フックを完全なゲーム内で使用する例を確認できます。
仕組み
- 仮想クロック。 ゲームスクリプトが実行される前に、playproof は
requestAnimationFrame、setTimeout/setInterval、performance.now、Dateを置き換え、CSS アニメーションのタイムラインを停止します。時間は停止した状態で始まります。時間を進めると、タイマーとフレームが正確な順序で 60 fps で実行されるため、wait 2sがミリ秒で完了し、2 回の実行で同じフレームが生成されます。 - 再現可能な読み込み。 ページの読み込み中、playproof は自動でフレームを進めます。ゲームで実時間のかかる処理(ネットワークリクエスト、WebAssembly のコンパイル、画像や音声のデコード、IndexedDB)が進行中の場合、仮想時間はその処理が終わるまで待つため、マシンや接続が遅くても速くても、同じフレームが得られます。安定化時間はゲームのレンダーループが始まった時点から計測されます。これは、Unity や Godot などのエンジンが独自のクロックを開始するタイミングです。
- シード付き乱数。
Math.randomにシードを設定します(--seedまたは--seed off)。 - 実際の入力。 タッチデバイスでは実際のタッチイベントを使用します(Chrome がそこから生成するポインターイベントとマウスイベントも含みます)。それ以外のデバイスではマウスイベントを使用します。入力をポーリングするゲームで認識されるよう、キーの押下状態を数フレーム維持します。
- ログではなく画像。 コンタクトシート、オニオンスキン、ストーリーボード、チャートは空の Chromium ページに描画するため、playproof の依存関係は
playwright-coreだけで、ネイティブ画像ライブラリは不要です。
出力
各実行では .playproof/<time>-<command>/(または --out <dir>)に、画像、すべての数値を含む report.json(フレームごとの動き、ステップログ、フレーム時間)、summary.txt、後で比較するための tiles/ 内のサンプリング済みフレームが書き込まれます。.gitignore に .playproof/ を追加してください。--json を指定すると、サマリーの代わりにレポートが出力されます。
終了コード:0 は重大な問題なし、1 はエラーあり(クラッシュ、リクエスト失敗、ステップ失敗、実機スマートフォンでのフレーム落ち)、2 は playproof 自体を実行できなかったことを示します。これにより、CI チェックで monkey と devices を使用できます。
要件
- Node.js 22.18 以降。
- Chromium ベースのブラウザー:インストール済みの Chrome または Edge、あるいは
npx playproof install-browser。--browser chromium|chrome|msedge|<path>で選択します。 --androidと--appを使用する場合:adb(Android platform-tools)、USB デバッグが許可されたスマートフォン、画面の電源がオンでロック解除されていること。
制限事項
- 音声、動画、Web Workers、WebAssembly スレッドは実時間で動作するため、シミュレーションをワーカーで実行するゲームではフレーム単位の完全な再現はできません。
- ローカルの
perf数値は GPU を使わないエミュレーションによるものです。変更前後の比較には適していますが、フレームレートの保証には使えません。GPU レンダリングには--headedを、実機での確認には--androidを使用してください。 - 動きに関する検出結果はヒューリスティックです。急なジャンプは意図的なカットかもしれませんし、1 フレームのフラッシュは意図的なヒットエフェクトかもしれません。そのため、確認事項として提示されます。
- 現時点では Chromium のみです。
開発
npm install
node src/cli.ts install-browser # once
npm run check # type check + unit and end-to-end tests
npm run docs:images # regenerate the README images with playproof itself
2 つのサンプルゲームはテスト対象でもあります。examples/jumper は小規模でシンプルなゲームで、examples/buggy には playproof が検出することをテストで確認する、仕込まれたバグが 8 つあります。
Issue やプルリクエストを歓迎します。CONTRIBUTING.md をご覧ください。
ライセンス
MIT
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。