2026年7月のある一週間で、私はブラウザゲームを5本、自分のサイトに公開した。マインクラフト風のボクセルサバイバルゲーム、マリオカート風の3Dレーシングゲーム、キャンディークラッシュ風のマッチ3パズル、実世界の地図上で1,200を超える州を手続き的に生成してプレイする大戦略ゲーム、そして韓国の妖怪を題材にしたスーパーマリオ風プラットフォーマーだ。5本ともブラウザだけで完結し、バックエンドもビルド工程もなく、ドメイン代以外の予算はゼロだった。そして5本とも、ほぼすべてAIコーディングエージェントとペアを組んで作った——私はプロダクトオーナー兼テスター、そして実際に画面を見る唯一の人間という役割を担った。
私はこのサイトをAI・テック分野で運営しているが、今回は普段扱っているCRUDアプリやコンテンツパイプラインとはまったく異なる種類のソフトウェアで、AIエージェントがどこまでやれるのかを見たかった。物理演算・手続き的コンテンツ生成・敵AIが絡むリアルタイムゲームでは、「コンパイルが通る」と「面白い」の間の距離がまるで違う。5本を実際に公開して学んだのは、本当のパイプラインがどういう形をしているか——そしてこの全体を可能にした、たった一つの決断についてだった。
ゲーム5本、フォルダ構造は一つ
各ゲームはサイトのpublic/games/<スラッグ>/以下に、いくつかの静的ファイルとして存在する——index.htmlと.jsファイルが1〜2本、3Dゲームの場合はThree.jsのような小さなベンダーライブラリが一つ加わる程度だ。バンドラーもビルド工程も、パッチを気にすべきnpm依存関係ツリーもない。各ゲームのスラッグ・タイトル・説明文を5言語で保持する登録ファイルが一つあり、ゲーム一覧ページ、各ゲームの詳細ページ、サイトマップはすべてそのリスト一つから自動生成される。6本目のゲームを追加するというのは、配列に項目を一つ足すことに等しい。
5本を簡単に紹介すると:
- ボクセルサバイバルゲーム — 昼夜サイクル、異なる行動パターンを持つモンスター7種、3日目の夜ごとに現れるボス戦、実績システム、武器を振るう一人称視点の戦闘まで備える。
- 3Dカートレース — 丘・バンク・S字カーブのあるサーキット、異なるステータスを持つプレイアブルキャラクター11種、ドリフトでチャージするターボ、そしてレースが台本のようにならずに接戦を保つラバーバンドCPU。
- マッチ3パズル — 8x8のボード、特殊タイル4種(一色を丸ごと消すレインボータイルを含む)、パーティクルエフェクト、そして音声ファイルを一切使わずWeb Audio APIだけで合成した132bpmのBGM。
- 大戦略ゲーム — 実際の国境線をシードにボロノイ分割で約1,200州を生成した実世界地図、人口・食料生産シミュレーション、それぞれ独自の外交・戦争ロジックを持つAI国家230か国。
- プラットフォーマー — クリボーやノコノコの代わりに処女鬼(チョニョグィ)・トッケビ・チョスンサジャ(冥府の使者)といった韓国の妖怪が登場するランアンドジャンプゲーム、手作業で設計した5ステージ、ヨッシー役を担う騎乗可能なユニコーンまで。
これらのどれ一つとしてサーバーは必要としなかった。進行状況とローカルランキングはlocalStorageに保存され、エクスポート/インポートボタンのおかげでセーブファイルは単なるJSONダウンロードだ——バックエンドがないことへの事実上唯一の回避策であり、加えて将来本物のクロスデバイスランキングを繋ぎたくなった場合に備えたフック(未使用のREMOTE_API定数)も残してある。
デプロイのループ
サイト自体は静的なAstroビルドで、新しくビルドしたdist/フォルダをgh-pagesブランチへ強制プッシュする2行のスクリプトでGitHub Pagesに公開される——新しく公開するものができるたびにただ実行するだけだ。ゲーム(そしてサイトの他の部分)の言語切り替えは、個別のローカライズされたルートではなく普通の?lang=クエリパラメータで処理しており、おかげでi18nフレームワークなしにゲームのビルド一つで5言語をサービスできる。モバイル対応は後から書き直すのではなく、上に重ねるレイヤーとして追加した:タッチデバイスは自動的に検出され(pointer: coarse、デスクトップでテストする際は?touch=1で強制)、仮想十字キーとボタンは、キーボード操作がもともと使っていたのとまったく同じキー状態オブジェクトに値を書き込む——だからゲームロジック自体は、入力が親指から来たのかキーボードから来たのかをまったく知る必要がない。
最も重要だった決断:人間なしでテストすること
このプロジェクトがそのスピードで実際の公開までたどり着けた本当の理由はここにある。ゲームは本質的にインタラクティブで視覚的なため、AIエージェントが自力で検証するのが特に難しいソフトウェアだ——テキストの差分だけを見て「物理挙動が正しい」と断言することはできない。最初はヘッドレスブラウザで人間のようにゲームを操作しようとした。ところがこれは、実際にぶつかるまでわかりにくい理由でうまくいかない:ヘッドレスChromeの仮想時間(virtual-time budget)はrequestAnimationFrameをきちんと駆動してくれないのだ。rAFベースのゲームループは、仮想時間をどれだけ長く設定してもヘッドレス自動化の下では実用的な速度で回らない。「ページを開いて、待って、スクリーンショットを撮る」というテストは、ほとんど何も検証していないに等しい。
この5本すべてを、誰もマウスに触れることなく検証可能にした解決策はこうだ:すべてのゲームに?test=simモードを搭載し、requestAnimationFrameと実時計から完全に切り離した固定タイムステップでゲーム物理を同期的に進行させ、判定結果はconsole.logではなくconsole.warnで記録する——ヘッドレスChromeのstderrキャプチャはwarnは確実に拾うが、普通のlogは取りこぼす。決定論的で同期的なステップ進行+warnレベルのロギング、このたった一つのパターンのおかげで、AIエージェントはプラットフォーマーの5ステージすべてがクリア可能か、マッチ3のボードが絶対にデッドロックしないか、戦略ゲームでAIが数十ターン進行した後もプロヴィンスの隣接関係が対称性を保っているか、すべてのセーブファイルが正しく往復保存・復元されるかを——実際にブラウザタブでゲームを開いた人間が一人もいない状態で——確認できた。さらに軽量な補助モード?shot=1はフレームクロックを一瞬だけ止めて、特定の劇的な瞬間(爆発の最中、ボスとの遭遇)をタイミング運に頼らずスクリーンショットで捉え、ゲームのカバー画像に使えるようにする。
一番学びの多かったバグ
大戦略ゲームは約1,200の州を描く際、各州の数値IDを色としてエンコードし、隠しキャンバスにラスターとして描画したうえで、そのピクセルの色を読み戻して「この座標はどの州か」「どの州同士が隣接しているか」といった問いに答える方式を取っている。キャンバスを絵ではなくルックアップテーブルとして使う、なかなか気の利いたトリックだ——キャンバスが図形の境界でアンチエイリアシングを適用するという事実を忘れるまでは。そのブレンディングが、あらゆる州の境界で実際には存在しないIDを静かに生み出し、その結果、重心計算と隣接データが個々には微小でも積み重なると奇妙な形で汚染された——計算上のドイツの中心点が大西洋のど真ん中に来ていたのだ。解決策は、デコードしたすべてのピクセルをその州の実際のベクター境界ボックスと照合して検証し、その検証に失敗したピクセルは周囲のピクセルの多数決で置き換えることだった。この教訓は他のゲームにもそのまま応用できた:レンダリング用の描画面を絵ではなくデータ構造として再利用するときはいつでも、アンチエイリアシング・ブレンディング・ミップマッピングといったレンダリングパイプライン自身の親切機能が、そのまま正確性のバグになりうる。
この作業でAIエージェントが本当に得意なこと
5本作ってみての正直な結論は、AIコーディングエージェントは一人でのゲーム開発をまさに遅くしている部分において本当に強いということだ:セーブシステムを組み上げること、スプライト素材を調達する代わりにキャンバス上で手続き的にベクターアートを生成すること、測定さえできれば難易度カーブをチューニングすること(たとえばマッチ3のバランス調整は、単に数千回のシミュレーションプレイを走らせて1手あたりの平均スコアを目標値と比較するだけの作業だ)、そしてあるゲームで検証済みのパターンを次のゲームに移植すること。しかし出来上がったものを実際にプレイしてみることの代わりにはならない——いくつかのバグは、合成テストのアサーションは技術的には通過しているのに実際の挙動は間違っているという場合にしか露見せず、それを見つける本当の防波堤はコンタクトシートのスクリーンショットを目視するか、完成前に自分の手でプレイしてみることだけだった。プロジェクト全体で最もレバレッジの大きかった作業は、どれか一本のゲームではなく、?test=simというパターンを最初に一度きちんと作っておいたことだ——おかげで2本目以降のゲームは、誰の目も介さずに検証する手段をそのまま受け継ぐことができた。
5本すべてmenewsoft.com/gamesで無料でプレイできる。