Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【ITニュース解説】Modern Libraries with Classic Games

2025年09月18日に「Dev.to」が公開したITニュース「Modern Libraries with Classic Games」について初心者にもわかりやすく解説しています。

作成日: 更新日:

ITニュース概要

Webゲーム開発でPixiJSを使用時、ユーザー操作前に常にレンダリング処理(ticker)が動くとPageSpeedスコアが低下する課題があった。これを解決するため、最初の操作までtickerを停止。CPU負荷を減らし、Core Web Vitalsを改善しつつ、ユーザー体験は維持できた。

出典: Modern Libraries with Classic Games | Dev.to公開日:

ITニュース解説

ウェブアプリケーション開発において、特にゲームのような動きのあるコンテンツでは、ユーザー体験とパフォーマンスの両立が非常に重要だ。今回、オンラインソリティアゲームの開発事例を通じて、スムーズなアニメーションとGoogleのCore Web Vitals基準を満たすための工夫、そして思わぬ落とし穴とその解決策について深く掘り下げていく。

このソリティアゲームは、当初から「バターのように滑らかなアニメーション」と、Googleのパフォーマンス指標であるCore Web Vitalsで高評価を得ることを目指して開発された。しかし、最初のバージョンでは、見た目や操作感は良好だったにもかかわらず、Google PageSpeed Insightsというツールでの評価は芳しくなかった。その原因は非常に巧妙で、ページの読み込みが完了した瞬間から、ユーザーが何も操作していない段階でも、ゲームの描画ループ(PixiJSというライブラリの「ticker」機能)が動き続けていたことにある。この描画ループは、ウェブブラウザがアニメーションを表示するために利用するrequestAnimationFrameという仕組みを常に実行しており、ユーザーがアイドル状態であってもCPU(中央演算処理装置)を継続的に消費していた。この無駄なCPU使用が、PageSpeed Insightsの評価ツールであるLighthouseのテストで検出され、パフォーマンス指標を大きく低下させていたのだ。具体的には、メインスレッドが常に忙しい状態となり、「Total Blocking Time(TBT)」などの指標が悪化する原因となっていた。

この問題を解決するための基本的な考え方は非常にシンプルだった。それは、「ユーザーが何らかの操作を行うまで、描画ループを開始しない」というものだ。しかし、この一見簡単な解決策を実装するには、いくつかの技術的な配慮が必要となる。

まず、なぜこのゲーム開発においてPixiJSというライブラリが選ばれたのかを説明する。PixiJSは、ウェブ上で2Dグラフィックを高速に描画するためのライブラリで、特にゲーム開発で強みを発揮する。ソリティアゲームでは、「ピクセル単位で正確なグラフィック表現」「カードのドラッグ&ドロップ操作の軽快さ」「スマートフォンから4Kモニターまで対応する画面サイズへの柔軟な適応」といった要件があった。PixiJSはこれらの要件に対して以下の機能を提供している。GPUアクセラレーションによる2Dレンダリング(WebGL)で描画を非常に高速に行い、複数の画像やテキストを効率的にまとめて描画する「自動バッチ処理」機能も備えている。描画したいオブジェクトを階層構造で管理できる「シーングラフ(Containers)」により、画面の変更があった際に、開発者が手動ですべてを再描画する手間が省け、PixiJSが自動で効率的に描画してくれる。マウス、タッチ、ペン入力などの様々な操作を統一的に扱える「ポインター&インタラクションシステム」があり、カードのドラッグ&ドロップのような操作を簡単に実装できる。画面の解像度や、高精細ディスプレイに対応するための機能があり、どんなデバイスでもグラフィックが鮮明に表示される。ゲームの進行やアニメーションを制御するための安定したループ機能と、アプリケーションの初期化やサイズ変更といったライフサイクルイベントを管理する仕組みが提供されている。また、フィルター効果、ビットマップフォント、アニメーションツールとの連携など、拡張機能が豊富で、必要に応じて段階的に導入できる「エコシステム」も強みだ。もしこれらを素のHTMLの<canvas>要素で実装しようとすれば、描画エンジン、イベント処理、バッチ処理、スケーリングといったPixiJSが提供する多くの機能を自分たちで作り直す必要があっただろう。PixiJSを使うことで、開発者はゲームのロジックやデザインに集中でき、素早く製品をリリースできたのである。

では、具体的なPageSpeed改善策の実装について見ていこう。 まず、PixiJSアプリケーションの初期設定で、描画ループが自動で開始しないようにする。これは、PIXI.Applicationの初期化オプションでautoStart: falseを指定することと、念のためthis.app.ticker.stop()を明示的に呼び出すことで実現する。これにより、ページが読み込まれた直後から描画ループが勝手に動き出すことを防ぐ。

次に、ユーザーが操作する前の状態では、どのように画面を更新するかという問題がある。例えば、ゲームが最初に表示された時や、ウィンドウのサイズが変更された時などだ。この場合は、描画ループを動かす代わりに、「render on demand(要求に応じて描画)」というアプローチを採用する。つまり、何らかの変更があった時だけ、this.app.renderer.render(this.app.stage)というメソッドを呼び出して、画面を一度だけ描画するのだ。これにより、必要のない描画ループが回り続けることを防ぐ。

そして、いよいよユーザーが初めてゲームを操作したときに、描画ループを開始する仕組みを実装する。これはstartTickerOnFirstInteraction()という関数で行われる。この関数は、ウェブページのどこかでユーザーが「pointerdown(マウスクリックやタッチ開始)」「touchstart(タッチ開始)」「keydown(キーボード入力)」といった最初の操作を行ったことを検知するためのイベントリスナーを登録する。これらのイベントが発生すると、start()という関数が一度だけ実行される。start()関数の中では、this.app.ticker.start()が呼び出され、ゲームの描画ループがようやく開始されるのだ。イベントリスナーにはonce: trueというオプションが指定されており、一度発火したら自動的にそのリスナーが解除されるため、無駄な処理が残らない。また、passive: trueというオプションは、スクロールのパフォーマンスに影響を与えないようにするために設定される、より高度な最適化である。

さらに、ウェブサイトが別のタブに隠れたり、最小化されたりした場合に、無駄な処理を停止させるための工夫もされている。これはsetupVisibilityPause()という関数で実装される。document.addEventListener('visibilitychange', ...)を使って、ページの表示状態が変わったことを検知する。もしページが非表示になった場合(document.hiddentrue)、this.app.ticker.stop()を呼び出して描画ループを停止させる。これにより、バックグラウンドのタブでゲームが動き続けることによるバッテリー消費やCPU使用を防ぐことができる。ページが再び表示された場合、もしユーザーが既にゲームを操作したことがあれば(hasInteractedというフラグで判断)、this.app.ticker.start()を呼び出して描画ループを再開する。まだ操作していない状態であれば、renderOnce()を呼び出して一度だけ画面を更新するに留める。

レスポンシブデザインへの対応も、PageSpeedに配慮して実装されている。ウィンドウやコンテナのサイズ変更時に、描画ループが動いていない場合でも正しく画面が更新されるようにする。これはResizeObserverというモダンなAPIを使って、特定の要素のサイズ変更を検知し、this.app.renderer.resize(w, h)でレンダラーのサイズを調整した後、必要に応じてrenderOnce()を呼び出すことで実現する。サイズ変更イベントは連続して発生しやすいので、setTimeoutを使って少し待ってから処理を実行する「デバウンス」という手法も取り入れ、無駄な処理を減らしている。

これらの主要な改善策に加えて、さらにいくつかの小さな最適化もパフォーマンス向上に貢献する。例えば、高精細ディスプレイであっても、window.devicePixelRatioの値を2などに制限することで、過剰な解像度での描画によるGPU負荷の増加を防ぐことができる。また、複数の小さな画像を一つの大きな画像にまとめる「スプライトシート」や「テクスチャアトラス」を利用することで、GPUの切り替え回数を減らし、メモリ使用量を最適化できる。ゲーム開始時に必要ないオーディオや重いアセットは、遅延ロードすることで、初期読み込み速度を向上させ、LCP(Largest Contentful Paint)というCore Web Vitals指標の改善にも繋がる。さらに、ぼかしや光沢のような高負荷なフィルター効果は、ユーザーが操作するまではオフにしておくことで、アイドル時のCPU消費を抑えることができる。

なぜこれらのパフォーマンス改善が重要なのかというと、現代のウェブサイトでは「Core Web Vitals」というGoogleの指標が検索エンジンのランキングに影響を与えるからだ。特にモバイル環境では、パフォーマンスが良いサイトほど検索結果で優遇される傾向がある。ゲームのようなアプリケーションでは、描画ループが無意識のうちにバックグラウンドでCPUを消費しがちだが、今回のような「初回操作まで描画ループを開始しない」というパターンを採用することで、Lighthouseの評価指標(低いCPU使用率、低いTBT)を改善できるだけでなく、実際のユーザー体験においても、INP(Interaction to Next Paint)やバッテリー寿命の向上に貢献する。ユーザーにとっては、操作する前には何も無駄な動きがないため、体験は全く変わらない。しかし、システムの裏側では、非常に効率的な動作が実現されているのだ。

この開発事例から得られる教訓は、ウェブゲーム開発においてPixiJSのようなライブラリがGPUの高速描画やクリーンなAPI、豊富なエコシステムにより非常に適していること、そしてGoogle Lighthouseがバックグラウンドでの無駄な作業を厳しく評価するため、その対策が必須であるということだ。具体的には、「自動開始を無効化し、必要に応じて一度だけ描画し、初回操作で描画ループを開始、そしてタブが非表示になったら描画ループを停止する」というパターンが、ユーザー体験を損なわずにCore Web VitalsとPageSpeedスコアを向上させるための非常に効果的な方法である。

関連コンテンツ

関連IT用語