GENEVIS
無料相談受付中
相談する
Webサイト技術メモ

Three.jsの背景演出に、停止・再開・障害時の表示を組み込む

更新日:

GENEVISのトップページとCOMPANYページには、Three.jsによる背景演出があります。停止した姿勢から再開すること、演出が使えないときも本文を読めることを実装しました。対象は2026年9月10日時点のコードです。スマートフォン実機の性能や電池消費は未検証です。

再生してよい条件と、描画の処理を分ける

両ページとも、src/scripts/hero-motion.jsで画面内か、タブが表示中か、利用者が停止しているかを判定します。同じディレクトリ内で、シーンの生成、描画、資源の解放はhero-three.js、時間と補間の計算はhero-animation.jsへ分けています。COMPANY用の文字サイズ・粒子数・描画品質などはhero-scene-config.jsで切り替えます。

再生できるのは、次の条件がそろったときです。

  • ページ離脱による破棄や、ページ退避による一時停止の状態ではない。
  • 停止操作や、動きを減らす設定で再生を抑止されていない。
  • ヒーローが画面内にあり、タブも表示されている。

通信節約や低速回線の情報が取得できた場合は、初期状態を停止にします。この判定は取得できるブラウザーの情報に依存するため、すべての端末で同じ回線情報を得られる前提にはしていません。

再生条件がそろってから演出のモジュールを読み込み、完了直後にも条件を確認します。その時点で停止中や画面外ならシーン生成を見送ります。シーン生成内のフォント待機中に停止した場合は、生成完了後に停止を反映します。

自サイト配信へ移しても、描画部分の取得は遅らせる

9月10日に、Three.jsを外部CDNから取得する構成から、npmで管理してサイトと一緒に配信する構成へ変更しました。バージョンは移行前と同じ0.185.1に固定し、package-lock.jsonで管理しています。

演出用の5ファイルをpublic/scripts/からsrc/scripts/へ移し、両ページで共用するHeroMotionScript.astro<script>から読み込み制御を取り込みます。Astroが処理するスクリプトでは、npmパッケージを含む依存関係をバンドルできます。Astro公式のスクリプト処理の説明

描画側のhero-three.jsは静的に取り込まず、再生条件がそろった後にimport('./hero-three.js')で取得します。生成結果でも読み込み制御と描画部分は別ファイルになり、TOPとCOMPANYが同じ配信用ファイルを参照します。従来のimport mapは不要になりました。

配信場所を変えても、回転の慣性や光の演出、停止・再開の計算は変えていません。外部CDNへの接続をなくすことと、GPUでの描画負荷を減らすことは別の変更です。

停止中の時間を、アニメーションへ足さない

描画の予約を止めるだけでは、再開時に時刻の差をまとめて取り込み、回転や浮遊が先へ飛ぶことがあります。そこで、再生している間だけ増える時間を持たせました。

時計は停止時に累積時間を残し、前フレームの時刻だけを解除します。再開後の最初のフレームは差分を0にして、次から時間を加えます。実装の要点を抜き出すと次の形です。

const delta = previous === null
  ? 0
  : Math.min(100, Math.max(0, now - previous));
previous = now;
time += delta;

この例ではnowtimeの単位はミリ秒です。長いフレーム停止でも一度に進む量を100ミリ秒に制限しています。実時間へ厳密に追いつくことより、背景の動きが急に飛ばないことを優先した、この演出固有の判断です。

停止中に画面サイズが変わる場合は、描画サイズとカメラを更新して、保持した姿勢を描き直します。再描画のためだけに時計を進める必要はありません。

表示前と障害時の状態を、黒背景として決める

初期状態は黒背景で、本文やナビゲーションは演出と独立したHTMLです。描画が成功してからキャンバスへ表示用のクラスを付けます。

モジュールの取得失敗や描画中の例外では、表示を解除し、シーンの資源を解放します。今回のサイトでは、代わりの動画や静止画像は追加していません。演出が使えなくても、会社情報と相談方法へ進めることを優先しています。

WebGL contextの喪失は、描画エラーによる破棄と分けました。喪失中は停止してキャンバスを隠し、復旧イベントでサイズを再設定します。そのうえで再生要求が残っていれば再開します。動きを減らす設定による非表示も、シーン側で判定を維持します。

一時停止と、資源の解放を区別する

画面外へスクロールしただけで毎回シーンを作り直すと、読み込みや初期化を繰り返すことになります。通常の停止ではシーンを保持し、ページを破棄するときや回復不能なエラーで解放する構成です。

pagehideの際、戻る・進む操作のためにページが保存される場合は一時停止にし、保存されない離脱では破棄します。復帰時は再生条件をもう一度確認します。

Three.jsのgeometry、material、textureなどのGPU資源は、不要になった時点で明示的な解放が必要です。Three.js公式の資源解放に関する説明

この実装では、シーンが管理する資源を集合へ登録し、破棄時にdispose()を呼びます。イベントと監視処理の解除もまとめ、破棄後の二重処理はフラグで防ぎます。requestAnimationFrameの予約取消しも、同じ後片付けに含めています。

確認できたことと、残っている測定

2026年9月10日の配信切り替え後に既存の10テストを再実行し、停止時間の除外、重複開始、30・60・120Hzでの補間、COMPANY用の描画上限と画面内への収まりを確認しました。

生成したサイトをPCのEdgeで開き、TOP・COMPANYの320・390・1280px幅で描画と画面外停止・復帰を確認しました。両ページとも外部への通信はなく、同じ描画ファイルを1回取得しました。停止・再開はPC幅でクリックとキーボードを確認しています。760px以下は既存のデザインで停止ボタンが非表示のため、スマートフォン幅では操作処理を直接呼び出す検証にとどまります。非表示タブとページ退避・復帰は、状態とイベントを模擬して確認しました。

動きを減らす設定・JavaScript無効・通信節約時は描画ファイルを初期取得せず、取得失敗・WebGL無効時は黒背景と本文を維持することも確認しました。通信節約中の再生操作、ダウンロード中に停止してからの再開、WebGL contextの喪失・復旧も、今回の配信構成で検証しています。

過去のブラウザー検証では、トップの停止姿勢・画面外停止・停止中のリサイズ、WebGL contextの喪失と復旧、模擬描画エラー後の表示解除を確認しています。COMPANYでも停止・再開や、JavaScript・WebGLが使えない場合、配信元を遮断した場合の黒背景を確認した記録があります。

PC上でスマートフォン幅を使った確認は、実機の性能測定ではありません。解像度に上限を設けたことだけで、実機の発熱や電池消費が改善したとも言えません。実機での評価は別の作業として残しています。

この背景で再利用したいのは、特定の光や回転の表現より、動ける条件と動けないときの状態を先に決める考え方です。表示に成功した場面だけでなく、停止、復帰、失敗、破棄までを一つの実装として扱います。

失敗時の状態から次の動作を決める別の実装例として、問い合わせフォームの再送と処理状態の管理も記録しています。

RELATED SERVICE

この記事に関連する支援

UNIT 01

サイト制作

企画、構成、文章、デザイン、実装まで。新規制作もリニューアルも、公開後の運用を見据えて進めます。

サイト制作の詳細

RELATED ARTICLES

あわせて読みたい

TOP