皆さん、こんにちは。あんちゃんです。このブログの名物(自称)となりつつある「AIとブラウザゲームを作る」シリーズ、今回はまたしてもテトリスです。前回はGeminiと組んでVer.3を完成させましたが、今回はAnthropicの「Claude」とタッグを組み、ゼロから新しいテトリスを作りました。ハイスコア保存、4段消し「TETRIS!」の派手な演出、そしてスマホで遊んでいて一番悔しかった「誤って画面更新して全部消える」問題への対策まで盛り込んだ意欲作です。……なのですが、今回の主役はゲームの機能ではありません。「スタートボタンは押せるのに、ゲームが始まらない」という怪奇現象との戦いです。文字化け、消えない2行、そして犯人探しの果てに辿り着いた意外な真実。WordPressでゲームを公開したい人が必ずハマる罠を全部踏み抜いてきたので、興奮冷めやらぬままお届けします。

PCブラウザ版の操作方法はこれ↓
← → でブロックを左右に移動。
↑またはX で右回転、Z で左回転。
↓ でソフトドロップ、Space で一気に落とすハードドロップ!
C でホールド、P で一時停止だよ。
最初に「スタート」ボタンを押してね。
スマホはゲーム下のボタンで操作!盤面を左右スワイプで移動、タップで回転もできるよ。
今回の相棒はClaude。テトリス再挑戦のはじまり

Geminiと作ったVer.3は、ぼくにとって一つの到達点でした。じゃあなぜまた作るのか。理由はシンプルで、遊び込むうちに「欲」が出てきたからです。ハイスコアが残らないのは寂しい。4段消しがあっさりしすぎていて達成感が薄い。そして何より、スマホで熱中してプレイ中に画面を下にスワイプした瞬間、ブラウザの「引っ張って更新」が発動してゲームが全部消える——あの絶望を、なんとかしたかったのです。
そこで今回はClaudeに開発を任せてみました。最近のClaudeはコードを書くだけでなく、自分でテストブラウザを立ち上げて動作確認までしてくれます。「作りました、動くはずです」ではなく「作って、動かして、スクリーンショットで確認しました」と返ってくる。この違いは想像以上に大きくて、開発のテンポがまるで変わりました。
v1.2.2に詰め込んだ新機能たち
まずは完成したテトリスの機能を紹介させてください。上のゲームで実際に体験できます。
- ハイスコア保存:端末に自動保存され、次に遊ぶときも表示されます。
- 段数で変わるリッチ演出:1段消しはSINGLE、4段消しは「TETRIS!」の大文字が浮かび、ブロックの破片が飛び散り、画面が揺れます。連続で消せばコンボ、テトリスを連発すればBACK-TO-BACKのボーナスも。
- 誤リロード対策:一手ごとに局面を自動セーブ。万一画面が更新されても「つづきがあります」から同じ局面を再開できます。プレイ中は引っ張って更新自体も効きにくくしてあります。
- 本格仕様:ホールド、ネクスト表示、落下位置が見えるゴーストピース、偏りのない7-bag方式の出現順。
- 効果音:回転や消去に合わせてポップな音が鳴ります(♪ボタンでON/OFF切替)。
そしてゲーム画面の右下に、小さく「v1.2.2」というバージョン表示があります。実はこれ、飾りではありません。この数字が今回の事件解決の重要な手がかりになるのですが、それは後のお話。
過去のテトリス開発の歴史はこちらからどうぞ。ぼくがどれだけこのゲームに執着しているかが分かります。

事件簿①:日本語が全部「文字化け」した
最初の事件は公開テストの初日に起きました。ローカルでは完璧に動いていたテトリスをWordPressに載せた途端、「スタート」も「一時停止」も、日本語という日本語が謎の記号の羅列に化けたのです。原因は文字コード。貼り付け先のページがコードをどの文字コードで解釈するかによって、日本語部分の運命が変わってしまうのです。
ここでClaudeが提案してきた解決策が豪快でした。「日本語を一文字も使わなければ化けようがありません」。つまり、コード内の日本語をすべて数値の参照表現に変換してしまうのです。たとえば「テトリス」はこうなります。
<!-- 変換前 -->
<div>テトリス</div>
<!-- 変換後:どの文字コードで読んでも「テトリス」に戻る -->
<div>テトリス</div>
ファイル全体を英数字(ASCII)だけにしてしまえば、文字コードの解釈に「揺れ」が存在しなくなります。人間が生のコードを見ると呪文のようですが、ブラウザで表示すればちゃんと日本語に戻る。もちろん手作業では無理なので、Claudeは日本語の読めるソースファイルから変換済みファイルを自動生成する仕組みまで作ってくれました。これで文字化けは完全勝利。……しかし、本当の戦いはここからでした。
事件簿②:ボタンは押せるのに、ゲームが始まらない

文字化けを克服し、意気揚々とWordPressのカスタムHTMLに貼り付けたぼくを待っていたのは、さらに不可解な現象でした。テトリスの画面は完璧に表示されている。スタートボタンにカーソルを合わせれば色が変わるし、押せば沈み込む「押し感」もある。なのに、何も始まらない。
Claudeの見立てはこうでした。「押し感はCSS(見た目の担当)が作っています。つまり見た目は生きているのに、JavaScript(動きの担当)だけが死んでいる状態です」。人間でいうと、笑顔のまま意識を失っているような不気味さです。
容疑者①:テーマの「高速化」機能
最初の容疑者は、このブログでも使っているWordPressテーマ「Cocoon」の高速化設定でした。ページ表示を速くするためにコードの改行を削って詰めてくれる機能なのですが、これがJavaScriptの // 形式のコメントと最悪の相性だったのです。
// この形式のコメントは「行末まで」がコメント扱い
var score = 0; // スコア初期化
var lines = 0;
// ↓改行が消えて1行に詰められると……
var score = 0; // スコア初期化 var lines = 0;
// ↑「var lines = 0;」までコメントに飲み込まれて消滅!
改行が消えた瞬間、コメント以降のコードが丸ごとコメントに飲み込まれ、プログラム全体が文法エラーで即死する。Claudeはコード内の約40箇所のコメントをすべて、改行が消えても安全な /* */ 形式に書き換え、さらに「全部の改行を削除した状態でも動くか」というシミュレーションまでして修正を確認してくれました。これで解決……と思ったのですが。
容疑者②:まさかの「カスタムHTMLブロック」本人
修正版を貼っても、まだ始まらない。ここで効いてきたのが、例のバージョン表示です。Claudeいわく「右下のバージョン番号はJavaScriptが動いて初めて表示されます。ページのソースにコードは存在するのに番号が出ていないなら、コードが一行も実行されていないと確定できます」。スクリーンショット1枚で状況を診断できるように仕込まれていたのです。
そして真犯人が判明します。ぼくがコードを貼っていたカスタムHTMLブロック、よく見るとHTML・CSS・JavaScriptの3つのタブに分かれた高機能なエディターになっていました。プラグインで拡張されたブロックだったのです。このタイプはHTML欄に書いた<script>を実行しない作りになっていることがある。つまりぼくがどんなに完璧なコードを貼っても、そもそも実行される場所ではなかった。ボタンの押し感だけが虚しく残っていた理由が、これで全部つながりました。
解決策は「原点回帰」のiframe方式
ではどうするか。答えは過去の自分が持っていました。以前のシューティングゲームやテトリスVer.3で使っていた、「ゲームのHTMLファイルをメディアライブラリにアップロードして、記事にはiframeだけを貼る」方式です。記事側に貼るのはたったこれだけ。
<div style="width:100%; max-width:560px; margin:0 auto;">
<iframe src="https://tokodomo.xyz/wp-content/uploads/2026/07/tetris_v1.2.2.html"
style="width:100%; height:860px; border:none;" scrolling="no" title="テトリス"></iframe>
</div>
ゲーム本体は独立したファイルとして読み込まれるので、テーマの高速化もプラグインの加工も一切受けません。ファイル名にバージョン番号を入れておけば、更新のたびに新ファイルをアップしてURLを差し替えるだけで、キャッシュに古い版が残る事故も起きません。高さの860pxという数字も適当ではなく、PC・スマホ・小型スマホの画面をそれぞれ実測して「どの端末でも切れない最小値」として算出したものです。この記事の上で動いているテトリスが、まさにこの方式です。
事件簿③:4段消したのに2行残る、テトリスの矜持を問うバグ
実は埋め込み問題と並行して、ゲーム本体にも重大バグがありました。棒状のIミノを差し込んで、気持ちよく4段消し——のはずが、なぜか2行だけ消え残るのです。スコアは4段分入っているのに、盤面には2行残っている。テトラー(テトリス愛好家)として見過ごせない事件です。
ぼくがプレイ画面のスクリーンショットを順番に送って報告すると、Claudeは原因を特定してくれました。消えるべき行を削除する処理で、「1行消すたびに、上に空の行を1行追加する」という書き方をしていたのが問題でした。
/* バグ版:削除と追加を同じループでやっていた */
for (var k = rows.length - 1; k >= 0; k--) {
grid.splice(rows[k], 1); /* 行を1つ削除 */
grid.unshift(emptyRow()); /* 直後に空行を先頭へ追加 ←これが罠 */
}
/* 修正版:まず全部削除してから、まとめて空行を追加 */
for (var k = rows.length - 1; k >= 0; k--) {
grid.splice(rows[k], 1);
}
for (var e = 0; e < cleared; e++) {
grid.unshift(emptyRow());
}
先頭に行を追加した瞬間、盤面のすべての行番号が1つずつズレます。すると次に消すはずだった行の番号が実際とは別の行を指してしまい、無関係な行を巻き込んで消していた。結果、本来消えるべき行のうち2行が取り残される——症状と数字までピッタリ一致する原因でした。Claudeは新旧のロジックを机上で比較するテストまで書いて、「旧版はきっかり2行分のブロックが残り、新版はゼロになる」ことを証明してくれました。
完成したv1.2.2と、AIとの開発で学んだこと
数々の事件を乗り越えて完成したv1.2.2。今回の開発をまとめると、こうなります。
- 文字化けはASCII化で根絶:日本語を数値参照に変換し、文字コードの影響を受けないファイルに。
- 「押せるのに始まらない」の真犯人はブロック:見た目(CSS)が生きていてJSだけ死んでいたら、実行環境を疑う。
- 公開はiframe方式が最強:メディアライブラリにアップしてiframeで読む。テーマやプラグインの干渉から完全に自由。
- バージョン表示は最高のデバッグツール:右下の小さな数字が「JSは動いているか」「最新版が反映されたか」を一目で教えてくれる。
「エラーを画面に出す」という発想の転換
今回いちばん感心したのは、Claudeが仕込んだ自己診断機能です。ゲームの起動に失敗すると、その理由がゲーム画面の中に赤字で表示されるようになっています。普通、エラーは開発者ツールという専門画面を開かないと見えません。でもぼくのようにスクリーンショットで状況を報告するスタイルだと、「画面にエラーが書いてある」だけで診断が一気に進む。実際、原因の切り分けはこの仕組みとバージョン表示のおかげで劇的に速くなりました。AIに開発を頼むときは、AIが状況を把握しやすい仕掛けをコード自体に入れてもらう。これは今後の合言葉になりそうです。
次なる野望
ハイスコアは端末に保存できるようになりましたが、次はやっぱり「読者同士で競えるランキング」を作りたい。サーバー側の仕組みが必要になるので難易度は上がりますが、Claudeとならなんとかなる気がしています。それまで、まずはこの記事のテトリスでハイスコアを育てておいてください。ぼくの記録は28,000点超えです。挑戦、待ってます。それでは、また!

4段消しの「TETRIS!」演出、ぜひ一度は見てほしい!画面が揺れて破片が飛んで、最高に気持ちいいよ!!
ちなみに、このAIと一緒にブラウザゲームを作るシリーズ、最新作としてキーボードで曲を演奏する音楽タイピングゲーム『タイポニカ』も作りました。こちらもブラウザで、しかも無料ですぐ遊べます。よかったらのぞいてみてくださいね。

新作の落ち物パズル「モチダマ」も作りました。よかったらこちらもどうぞ。

ゲームで遊んだ思い出のほうの話も書きました。メガドライブを買ってもらえなかった子どものころの、セガへの感謝の記事です。よかったらこちらもどうぞ。

新作の縦スクロール・シューティング「スター・アマンダ」も作りました。よかったらこちらもどうぞ。



コメント