phaser-feedback について
phaser-feedbackは、プレイヤーの報告を検証済みのゲーム修正につなげるスキルです。フィードバックの分類、原因候補ごとの整理、プレイテストシナリオでの再現を進め、シナリオを回帰テストとして残します。
主な機能
- 01報告の原文と状況の記録
- 02不具合・調整・設計・情報不足の分類
- 03原因候補ごとの報告整理
- 04再現可能なプレイテストシナリオの作成
- 05修正の検証とデグレード確認
- 06再現シナリオの回帰テスト化
活用シーン
- 01断続的に起きるゲームの問題の調査
- 02バグとバランス・設計への意見の切り分け
- 03プレイヤー報告を継続的な回帰チェックに変換
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ yakoub-ai/ phaser4-gamedev --skill phaser-feedbackインストール後、Claude Code で/phaser-feedbackを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
examples/worked-session.mdreferences/feedback-to-scenario.mdresponse-templates.mdtriage-guide.md詳細
プレイヤーのフィードバックを修正リリースにつなげる
フィードバックは、あなたのコードを知らない人が書いた文章として届きます。
「ジャンプがふわふわしてて、ときどきプラットフォームをすり抜けて落ちちゃう。あとボスが 無理ゲー。ショップも壊れてる」
4つの記述、4種類の異なる問題、そしてそのうち通常この言葉が意味するようなバグはちょうど1つだけです。それらをすべて同じように扱うと、修正セッションはプレイヤーの実際の不満が手つかずのまま終わってしまいます。
このスキルが実行するループ:
intake ──► triage ──► group by root cause ──► reproduce (failing scenario)
│
report back ◄── verify ◄── fix
│
└──► scenario is kept as a regression test
違いを生むステップは 修正の前に再現する です。プレイヤーが説明した理由で失敗するプレイテストシナリオは、あなたがプレイヤーを理解した証拠になります。それがなければ、あなたは文章をコードにパターンマッチングしているだけであり、最もよくある結果は、誰も不満を言っていない何かに対するもっともらしい修正です。
ステップ 1 — 受け付け
フィードバックは そのままの文言 で受け取ります。整えたり、技術的な言葉に翻訳したり、曖昧に見える部分を削ったりしないでください。正確な言葉には情報が含まれています:
- 「ときどき」/「たまに」/「一度だけ」→ 頻度に関する主張であり、再現方法が変わります(下記の
--repeatを参照) - 「しばらくすると」/「後になると」→ 状態蓄積またはリークに関する主張
- 「自分の携帯で」/「全画面で」→ プラットフォームに関する主張であり、デバイスの姿勢が必要です
- 「以前は動いていた」→ リグレッションに関する主張であり、バグを探す前にコミットを見つけます
各項目を、その出所と報告者が与えた文脈とともに記録します。複数の報告者が同じことを言っている場合は、件数を書き留めます。頻度は、あなたが得られる最も安価な優先度シグナルです。
プラットフォームに関わるものについては、何よりも先に姿勢を確認します: ブラウザとバージョン、iOS か Android か、Safari のタブか PWA か Capacitor か、画面の向き、タッチかマウスか。ほとんどの「モバイルのバグ」は特定プラットフォームのバグであり、これがないと区別できません。
ステップ 2 — 4種類にトリアージする
これがセッションの成否を決めるステップです。種類ごとに異なる対応が必要であり、1つを誤って分類するとサイクル全体が無駄になります。
| 種類 | ゲームは… | 必要なもの | 誰が決めるか |
|---|---|---|---|
| 不具合 | すべきでないことをする | 失敗するシナリオ、次に修正 | あなた |
| チューニング | コードが言うとおりに動くが、数値がおかしく感じる | 数値目標、次に値の変更 | ユーザー |
| 設計 | 設計どおりに動いており、その設計が望まれていない | GDD の変更 | ユーザー |
| 対応不能 | — | 報告者への具体的な質問 | 報告者 |
上記の例に適用すると:
| 引用 | 種類 | 理由 |
|---|---|---|
| 「ときどきプラットフォームをすり抜けて落ちちゃう」 | 不具合 | 衝突判定が失敗している。誰もそれを設計していない。 |
| 「ジャンプがふわふわしてる」 | チューニング | 重力とジャンプ速度は設定されたとおりに動いている。 |
| 「ボスが無理ゲー」 | チューニング または 設計 | 曖昧 — HP の数値か、戦闘全体か? 尋ねること。 |
| 「ショップが壊れてる」 | 対応不能 | どう壊れているのか? 再現への道筋がない。 |
好みの問いに対して指標をでっち上げないでください。 難易度の感触、アートの読みやすさ、オーディオミックス、「楽しいかどうか」は、ヘッドレスブラウザでは決着できません。これらは人間を必要とするものとしてラベル付けし、ラベルを付けたままにしておきます。好みの問いに対する偽の数値目標は、恣意的な方向への自信に満ちた変更を生み出します。
チューニングの報告を黙って不具合に格上げしないでください。 「ボスが無理ゲー」を不具合として修正すると、存在しないダメージ計算のバグを探すことになります。チューニングとして修正すると、「この戦闘はどれくらいかかるべきか — 何発で、どれくらいの長さか?」と尋ねて数値を変えることになります。2つ目はほぼ常に正しく、ユーザーの答えが必要です。
コードに触れる前にトリアージを書き留め、ユーザーに見せてください。誤分類を正してもらうのは一言で済みますが、修正後にそれに気づくとセッション全体のコストになります。
ステップ 3 — 疑わしい根本原因ごとにグループ化する
別々の報告でも、原因が 1 つであることは少なくありません。調査を始める前にそれらをグループ化してください。単一の根本原因は、個別のパッチを積み重ねるよりも多くのことを説明でき、グループ化された症状は、どれか 1 つの症状よりもはるかに速くその原因を指し示します。
"sometimes i fall through the platform"
"the moving platform drops me at the top" ──► one suspect:
"i clipped into the wall when i dashed" high velocity vs. collision step
3 件のチケット、おそらく修正は 1 つ。フレームごとにボディが十分に大きく移動し、薄いコライダーをトンネリングしてすり抜けているのです。これらを個別にパッチすると、3 つの特殊ケースを書くことになり、来週には 4 件目の報告が届きます。
グループ化に抵抗する報告は、それ自体が 1 つのグループです。無理にまとめないでください。
ステップ 4 — 失敗するシナリオとして再現する
修正の前にシナリオを書きます。それが失敗するのを確認します。それを永久に保持します。
シナリオとは、プレイヤーの言葉が機械で検証できるものに変わる場所です。語彙さえ分かれば、変換は機械的です。完全な対応表については references/feedback-to-scenario.md を参照してください。
// playtest/repro-fall-through-platform.mjs
export default [
{ name: 'set up the reported situation', action: 'eval', code: `
const s = scene('GameScene');
s.player.setPosition(400, 100); // above the platform
s.player.body.setVelocityY(1200); // the reporter was falling fast
` },
{ name: 'player lands on the platform, does not pass through',
action: 'waitFor',
expression: `scene('GameScene').player.body.blocked.down`,
timeout: 3000 },
{ name: 'and is still above it',
action: 'expect',
expect: { expression: `scene('GameScene').player.y`, below: 500 } },
];
実行します:
node "${CLAUDE_PLUGIN_ROOT}/skills/phaser-playtest/scripts/playtest.mjs" \
--project . --scenario playtest/repro-fall-through-platform.mjs
それは失敗しなければなりません。 最初の実行で通ってしまった再現は、何も再現できていません。そして次に書く修正は、何もないものを狙うことになります。そうなったとき、間違っているのはシナリオであり、報告ではありません。戻って、さらに詳しい情報を集めてください。
「ときどき」は頻度の主張であり、それ専用のツールがあります
node ".../playtest.mjs" --project . --scenario playtest/repro.mjs --repeat 10
その判定結果は、どんな種類のバグなのかを教えてくれます:
| 判定結果 | 診断 |
|---|---|
10/10 runs clean | 再現していません。シナリオにプレイヤーが行った何かが欠けています。 |
INTERMITTENT — failed in 3/10 | 本物であり、レースコンディションか RNG の形をしています。 |
failed in all 10 — consistent | フレークではありません。再現は正確なので、直接修正してください。 |
断続的な結果に対しては、--seed 42 を追加します。それが一貫した結果になれば、そのバグは RNG の経路、つまりコードが処理していない状態に到達するスポーンロールやルートロールに依存しています。シードを指定しても断続的なままなら、原因はタイミングです。フレームの順序、非同期ロード、または update() と競合するイベントです。この 2 つは異なる修正を必要とし、これを最も安価に見分ける方法がこれです。
主張とアサーションの対応づけ
| 報告者が言ったこと | これでアサートする |
|---|---|
| 「ときどき起きる」 | --repeat 10 |
| 「敵がスタックする」 | sample + expect: { stat: 'range', atLeast: n } |
| 「カメラがぶれる」 | sample + expect: { stat: 'stddev', atMost: n } |
| 「倒すのに永遠にかかる」 | timeout 付きの waitFor |
| 「理由もなくヘルスが減る」 | sample + expect: { stat: 'delta', equals: 0 } |
| 「しばらくすると遅くなる」 | --heap、さらにシーンを再起動する repeat ブロック |
| 「自分のスマホでだけ壊れる」 | --device iphone / --device android |
| 「操作が言うことを聞かない」 | 複数のキーを押す hold — 斜め入力は独自の入力経路です |
| 「アップデート後に壊れた」 | 前のコミットをチェックアウトして、同じシナリオを実行する |
ステップ 5 — 修正
標準的な規律が当てはまります。そしてここでは、あなたが伝聞の説明をもとに作業しているため、その規律はより厳しく当てはまります:
- まず調査します。 ソースを読みます。修正を書く前に、何が原因で、なぜ起きるのか、そして何を提案するのかを説明します。
- 2 回試して、それから方針を変えます。 あるアプローチを 2 回試して失敗したら、立ち止まり、本当に異なる 2 つか 3 つのアプローチを提案します。2 回失敗したアプローチを 3 回目に反復しないでください。
- グループ化した原因を修正し、個々の症状を修正しない。 3 件の報告が根本原因を共有していたなら、1 つの修正で 3 件すべてを閉じられるはずです。1 件しか閉じられないなら、グループ化が間違っていたのです。そう言って、残り 2 件を個別にパッチするのではなく、グループ化し直してください。
ステップ 6 — 検証
2 つのことが真でなければならず、両方を確認する必要があります:
# 1. The repro now passes — and for an intermittent bug, passes repeatedly.
node ".../playtest.mjs" --project . --scenario playtest/repro-fall-through-platform.mjs --repeat 10
# 2. Nothing else broke.
npx tsc --noEmit
node ".../playtest.mjs" --project . --mode build
for f in playtest/*.mjs; do node ".../playtest.mjs" --project . --scenario "$f"; done
断続的だったバグにとって、1 回の成功した実行は検証ではありません。それは、そのバグを見つけにくくしたのと同じコイントスです。再現にかかった回数以上に再実行してください。
結果を誠実に報告します。 再現は通ったが、別の 2 つのシナリオが今度は失敗するなら、そう言ってください。1 つのバグを 2 つのバグと引き換えにする修正は、完了していません。
ステップ 7 — 報告を返し、シナリオを残す
返信は自分の言語ではなく、報告者の言語で書いてください。報告者は体験を説明しているので、その体験がどう変わったかを伝えます。
「ときどきプラットフォームをすり抜けて落ちてしまう」 — 修正しました。物理ステップの間に薄いプラットフォームを高速で通り抜けることがありました。高速落下でも正しく着地するようになりました。
「ジャンプがふわふわしている」 — 変更しました。ジャンプの頂点に到達するまでの時間が 0.6 秒から 0.35 秒になりました。これが意図していたものであるか教えてもらえると助かります。
「ボスが倒せない」 — まだ変更していません。戦闘はどれくらいの長さであるべきですか、あるいは何回くらいの挑戦が妥当だと感じましたか?体力、与ダメージ、攻撃頻度を調整できます。
「ショップが壊れている」 — 再現できませんでした。どこをクリックして、代わりに何が起きましたか?
この返信に価値があるのは三つの点です。修正したもの、変更して確認してほしいもの、そして報告者にまだ求める必要があるものです。修正点を並べるだけの返信では、報告者を必要とする二つの項目が失われてしまいます。
シナリオをコミットします。 playtest/repro-*.mjs は恒久的なリグレッションテストになりました。これがフィードバックを複利的に蓄積させる仕組みです。この方法で修正された報告はそれぞれ、再発を防ぐチェックを残します。半年分の報告は、実際のプレイヤーがあなたのゲームで本当に行ったことを符号化したスイートになります — これはどれだけユニットテストを積んでも生み出せないものです。
アンチパターン
- 再現する前に修正する。 ここで最もコストの高い間違いです。あなたは自分のコードについて、見知らぬ人の説明をもとに作業しています。最初の読みが正しい確率は高くなく、再現が通ることはそれを安価に確かめる唯一の方法です。
- 報告を浄化する。 「ふわふわしている」を「重力を調整する」と書き換えると、相手が何を望んでいたかをまだ把握していないという事実を捨ててしまいます。
- 好みの問いを指標として扱う。 「ボスは楽しいか」に数値を割り当てると、誰も求めていない方向へ自信を持って何かを変えてしまいます。
- 同じ原因を共有しているのに、一度に一つの報告ずつ修正する。 特殊ケースを生み出し、根本的なバグが新たなチケットを生み続けます。
- 断続的なバグに対する一度のグリーンな実行。 それはまさに、そもそもバグを隠していたコイントスの結果です。
- 修正後に再現を削除する。 再発を防ぐ唯一の成果物を捨ててしまいます。
- 修正しなかった項目について沈黙する。 報告者は「やらないと決めた」と「無視した」を区別できず、後者は次の報告を失わせます。
追加リソース
参照ファイル
references/triage-guide.md— 四つの種類を詳しく解説し、実際のフィードバック文字列を掘り下げ、曖昧なケースや分類後の優先順位の付け方を扱います。references/feedback-to-scenario.md— フィードバックの言い回しからシナリオの構成要素への完全な変換表と、よくある不満の形に対する完全な実例シナリオ。references/response-templates.md— 報告者への返信、プレイヤー向けチェンジログの書き方、そして次の報告が今回より良くなるようなループの閉じ方。
例
examples/worked-session.md— 散らかった Discord の貼り付け一つを端から端まで: トリアージ、グループ化、三つの再現シナリオ、修正、検証、そして返信。
関連
skills/phaser-playtest/— ハーネス、完全なシナリオリファレンス、そしてこれらすべてが機能するためにゲームが必要とする計測skills/phaser-debugger/— 再現が存在した後の根本原因調査skills/phaser-gdd/— 設計種のフィードバックの行き先: セクション 13 の受け入れ基準skills/phaser-analyze/— リークを仮定する前の、パフォーマンス報告向け