mcpField
P
phaser-playtest

phaser-playtest

github.com/yakoub-aiテスト・品質29127 回インストール9 週間前に更新
リポジトリ

phaser-playtest について

phaser-playtestは、Phaser 4ゲームのランタイム検証スキルです。Playwrightベースのハーネスでブラウザーの読み込み、シーン、描画、アセット、FPS、エラーを確認し、回帰テスト用のシナリオも実行できます。

主な機能

  1. 01ヘッドレスChromiumでのランタイム検査
  2. 02シーン、キャンバス、アセットの検証
  3. 03FPS計測とエラー検出
  4. 04スクリプト入力と状態アサーション
  5. 05開発・ビルドのテストモード
  6. 06JSONレポートとスクリーンショット

活用シーン

  1. 01TypeScript検査だけでは分からないゲーム変更の検証
  2. 02ゲームの受け入れ条件のテスト
  3. 03スクリプト化したプレイセッションの再現
  4. 04CIでのゲーム検査

インストール

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

$npx skills add https://github.com/yakoub-ai/phaser4-gamedev --skill phaser-playtest

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

同梱ファイル

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

examples/
scenario.example.mjs
references/
instrumenting-games.md
playtest-harness.md
scripts/
playtest.mjs

詳細

Phaser 4 プレイテスト(ランタイム検証)

npx tsc --noEmit はコードがコンパイルできることを証明します。しかし、ゲームが実行されるかどうかについては何も示しません。以下の失敗はすべて型チェックを完璧に通過し、それでも壊れたゲームを出荷してしまいます:

失敗プレイヤーに見えるものTypeScript が言うこと
アセットパスのタイポ見えないスプライト何も言わない — 文字列だから
scene: [] にシーンが含まれていない黒い画面何も言わない
create() が最初の行の後で例外を投げる半分しか構築されていないシーン何も言わない
depth/alpha/カメラスクロールのミス空白のキャンバス何も言わない
物理ボディが追加されていないプレイヤーが床をすり抜ける何も言わない
上限のないエミッター12 fps何も言わない

ランタイム検証は任意ではありません。 シーンのライフサイクル、アセットの読み込み、物理、またはレンダリングに触れる変更を行った後は、ユーザーに動作すると伝える前にハーネスを実行してください。

実行する

node "${CLAUDE_PLUGIN_ROOT}/skills/phaser-playtest/scripts/playtest.mjs" --project .

ハーネスは開発サーバー自体を起動し、ヘッドレス Chromium を操作し、サーバーを再びシャットダウンします。設定もテストファイルも不要です。

プロジェクトに Playwright が必要です(一度だけ):

npm install -D playwright && npx playwright install chromium
チェック内容
  1. ページが読み込まれる — ドキュメントの HTTP ステータス
  2. キャンバスが作成される — サイズを持つ <canvas> が存在する(失敗 ⇒ Phaser が起動していない)
  3. Phaser インスタンスに到達できる — window 上の Phaser.Game を見つける
  4. ゲームが起動している — isBooted === true
  5. アクティブなシーン — どのシーンが実行され、それぞれが保持する表示オブジェクトの数
  6. シーンがコンテンツをレンダリングする — 表示リストが空のシーンに対して警告
  7. フレームレート — 実際のフレームでサンプリングした FPS の中央値と第5パーセンタイル
  8. キャンバスがコンテンツをレンダリングする — ピクセル分析;黒い画面を検出
  9. 未捕捉の例外がない — スタック付きの pageerror
  10. コンソールエラーがない
  11. すべてのアセットが読み込まれる — 開発サーバーが 200 text/html として偽装するファイルも含む

終了コード 0 = 合格、1 = チェック失敗、2 = ハーネスエラー。.playtest/report.json と PNG スクリーンショットを書き込みます。

オプション
フラグ目的
--project DIRプロジェクトルート(デフォルト: cwd)
--url URLサーバーを起動する代わりに、すでに実行中のサーバーをテストする
--mode dev|buildbuild は npm run build + preview を実行する — ベースパスとバンドルに関するバグを検出する
--scenario FILEスクリプト化されたプレイセッションを実行する(以下を参照)
--device iphone|androidモバイルのビューポート、DPR、タッチ、UA
--settle MS調査前に待機する(デフォルト 3000;遅いプリロードの場合は増やす)
--fail-on-warnコンソール警告を失敗として扱う(CI)
--jsonJSON のみを出力する — 結果を解析する場合に使用する
--headedブラウザを表示する

ゲームをテスト可能にする(1行)

詳細なチェックにはゲームインスタンスが必要です。バンドルされたゲームはそれをモジュールスコープに保持しているため、開発ビルドでのみ公開します:

const game = new Phaser.Game(config);
if (import.meta.env.DEV) (window as any).__PHASER_GAME__ = game;
export default game;

これがなくてもハーネスは黒い画面、例外、404 を検出しますが、シーン、FPS、状態のアサーションはスキップされます — そしてその旨を報告します。この行を追加してください;本番環境では何のコストもかかりません。決定的なテストのためのフック(シード付き RNG、時間制御、状態注入)については references/instrumenting-games.md を参照してください。

シナリオスクリプト

シナリオは入力を操作し、実行中のゲーム状態に対してアサーションを行います。game はすべての expression 内で実行中のインスタンスにバインドされます。

// playtest/combat.mjs
export default [
  { name: 'reaches gameplay', action: 'expect',
    expect: { expression: `game.scene.isActive('GameScene')`, equals: true } },

  { name: 'walk right', action: 'key', key: 'ArrowRight', duration: 600 },

  { name: 'player advanced', action: 'expect',
    expect: { expression: `game.scene.getScene('GameScene').player.x > 400`, equals: true } },

  { name: 'attack lands', action: 'press', key: 'Space',
    expect: { expression: `game.registry.get('enemyHp')`, atMost: 90 } },

  { name: 'after-combat', action: 'screenshot' },

  { name: 'holds frame rate', action: 'expect',
    expect: { expression: `game.loop.actualFps`, atLeast: 55 } },
];

アクション: wait(ms)、key(key、duration)、press(key)、click(x、y キャンバス相対)、screenshot(name)、expect。 アサーション: equals(深い比較)、atLeast、atMost、または真値のための裸の expression。

完全なリファレンス: references/playtest-harness.md。 実例: examples/scenario.example.mjs。

プランをテストに変換する

/phaser-gdd または phaser-architect エージェントからの受け入れ基準は、 そのままシナリオのステップに変換できます。シナリオは機能が仕様化された時点で書きましょう。 壊れてからではありません。

受け入れ基準シナリオのアサーション
「プレイヤーは 3 タイルの高さまでジャンプする」game.scene.getScene('GameScene').player.y、atMost: spawnY - 96
「敵は 3 回で倒れる」攻撃を 3 回押し、その後 enemy.active、equals: false
「スコアはシーンをまたいで保持される」GameOver を開始し、その後 game.registry.get('score')、atLeast: 10
「敵 50 体で 60fps で動作する」eval でスポーンし、その後 game.loop.actualFps、atLeast: 55

失敗を読み解く

ハーネスの出力最初に確認すべき根本原因
canvas created が失敗するシーンが constructor/init で例外を投げた、またはバンドルが 500 を返している。コンソールエラーを確認してください。
active scenes: no scene is runningシーンが scene: [] から抜けている、または create() が完了前に例外を投げた
canvas renders content が空白、シーンはアクティブオブジェクトがカメラ外、alpha: 0、depth の誤り、またはカメラが追従していない
scenes render content が空で警告create() が早期に return した — 通常は try に飲み込まれた例外
all assets load が text/html で失敗するパスのタイプミス、またはアセットが public/ ではなく src/ にある
frame rate が低いパーティクルの上限なし、オブジェクトプーリングなし、フレームごとのアロケーション。/phaser-analyze を使用してください。
Phaser game instance found が警告上に __PHASER_GAME__ の行を追加してください

CI

- run: npm ci
- run: npx playwright install --with-deps chromium
- run: npx tsc --noEmit
- run: node scripts/playtest.mjs --project . --mode build --fail-on-warn

playtest.mjs をプロジェクト自身の scripts/ にコピーして、CI がプラグインのインストールに依存しないようにしましょう。

規律

  • 機能を完了と報告する前にハーネスを実行しましょう — ユーザーがバグを報告してからではありません。
  • tsc が通ってもプレイテストが失敗するなら、その作業は完了していません。
  • 失敗したときは、コードを編集する前に .playtest/report.json とスクリーンショットを読みましょう。 調査優先は、phaser-debugger とまったく同じようにここでも当てはまります。
  • 主要な機能ごとにシナリオを playtest/ 配下に保ちましょう。それらは回帰テストです。

失敗がプレイヤー由来だった場合

コードを変更したからではなく、誰かがバグを報告したためにここに来たのであれば、 すぐにシナリオを書くのではなく skills/phaser-feedback/ を使用してください。これは まず報告をトリアージすること(「難しすぎる」という不満は欠陥ではなく、再現手順もありません)を カバーし、各主張の形を適切な構文に対応付けます — 「ときどき」には --repeat、「動かなくなる」には sample、 「時間がかかりすぎる」には waitFor、「時間とともに遅くなる」には --heap です。

コメント