フレームワークなしのHTML+JSだけで5本のゲームを運営している話
VANNAN GAMESの5作品は、すべて素のHTML・CSS・JavaScriptだけで動いています。ReactもUnityもビルドツールもありません。1ゲーム=HTML1枚+JS1本が基本形です。流行に逆らっているようですが、個人開発のこの規模だと合理的な選択だと思っているので、構成と代償を正直に書きます。
構成: エディタで保存したらデプロイできる
リポジトリにあるのはそのまま配信されるファイルだけです。ローカルでは小さな開発サーバを立てて確認し、gitでpushすると静的ホスティング(EdgeOne Pages)がそのまま公開します。ビルド工程がないので「ビルドが壊れて公開できない」が原理的に起きません。依存パッケージもゼロなので、脆弱性アラートに追われることも、1年後にnpm installが通らなくなることもありません。
ゲームの実装は作品ごとに素直に書きます。ノベルゲームはDOM、アクションはcanvas、カードゲームはDOMとCSSアニメーション。効果音はWeb Audioでコード生成し(音源ファイル不要)、BGMだけmp3を使います。セーブはlocalStorageです。
フレームワークの代わりに「決めごと」を持つ
道具が素朴なぶん、運用の決めごとでカバーしています。たとえば——
キャッシュ対策は、CSS・JSを参照する側に ?v=12 のような版数クエリを手で付け、ファイルを変えたら必ず+1します。原始的ですが「直したのに反映されない」事故はこれで根絶できました。逆に一度、HTMLに1年キャッシュが付いてしまい、更新が誰にも届かない事故を起こしてから、HTMLは毎回再検証する設定にしています。
開発専用ページは、ファイル名をドット始まりにします。使っているホスティングはドットファイルを配信しないので、リポジトリに入れたまま本番では404になる。カード素材の検収ページなどはこの仕組みで公開を防いでいます。
そしていちばん大事な決めごとが、仕様・設計判断・ハマった罠をリポジトリ内のリファレンスに開発と同じコミットで書き残すことです。フレームワークの規約がない世界では、過去の自分の判断だけが規約なので、これを怠ると数週間で無法地帯になります。
代償も、ある
良いことばかりではありません。型がないのでリファクタリングは慎重になりますし、コンポーネントの再利用機構がないので、全ページ共通のフッターにリンクを1つ足すだけで15ファイルの編集になります(実際にありました)。UIの状態管理も全部手書きで、「ボタンの位置が要素の出現でズレる」ような泥臭いバグを自分で踏んで自分でルール化してきました。規模が10作品を超えたら、どこかで仕組みに投資し直すことになると思います。
テストは「ブラウザを自動で操作」が主力
テストフレームワークも入れていませんが、無検証で出しているわけではありません。主力はブラウザの自動操作です。ゲームを実際に起動し、スクリプトでボタンを押させて、負け画面まで通しでプレイさせる。UIの座標が要素の出現でズレていないかは、各状態で座標をサンプリングして数値で比較します。ロジック部分については、ゲームルールを丸ごと移植したシミュレータ(バランス調整用)が事実上の結合テストを兼ねていて、本体とシミュレータで挙動が食い違えばどちらかのバグです。型もテストランナーもない代わりに、「実物を動かして測る」を徹底する。素朴ですが、ゲームという題材にはむしろ合っていると感じています。
手作りゆえに踏んだ罠たち
フレームワークが守ってくれない世界では、素朴な罠を自分で踏んで学ぶことになります。実際に踏んだものをいくつか。HTMLの hidden 属性で要素を隠していたら、CSSで display:flex を当てた瞬間に hidden が無視されて常時表示になった(display指定はhiddenのdisplay:noneを上書きします)。left:50% で中央寄せした要素が、幅の計算の都合で親の半分の幅に折り返された。画像の読み込み判定を描画時のスナップショットで行っていたため、回線の遅い初回アクセスでは読み込み完了後も代替表示のまま固まった。——どれもフレームワークなら顔も見ずに解決してくれる類いの問題です。
大事なのは、踏んだ罠を必ずリファレンスに書き残すことです。「left:50%の折返しにはwhite-space:nowrap」のような一行が積み重なって、いまでは自分専用のフレームワーク規約のようなものができつつあります。罠を2度踏まなければ、手作りのコストは思ったより高くつきません。
それでもこの構成にしている理由
個人開発の最大の敵は、技術的負債ではなく「開発が止まること」です。環境構築ゼロ・待ち時間ゼロ・壊れる工程ゼロの構成は、平日の夜に30分だけ触る、みたいな開発リズムと相性が抜群でした。ページを開いた瞬間に遊べるゲームを、保存した瞬間に公開できる環境で作る。この速度感は、少なくともこの規模では、どんなフレームワークより効きます。