mcpField
O
optimize-web

optimize-web

github.com/unity-technologies開発1.2k5.5k 回インストール1 日前に更新
リポジトリ

optimize-web について

Unity の Web ビルドのサイズと性能に関わる設定を監査・調整するスキルです。基準値と復元ポイントを作成し、Unity CLI と Editor を使った文書に基づく変更と検証を案内します。

主な機能

  1. 01Web ビルド設定の監査
  2. 02基準値と復元ポイントの作成
  3. 03圧縮とコードストリッピングのガイド
  4. 04Unity CLI による Editor 設定
  5. 05ビルドと実行時の検証手順

活用シーン

  1. 01Unity Web ビルドのサイズ削減
  2. 02圧縮とストリッピング設定の確認
  3. 03根拠資料に基づく Web Player 設定の適用
  4. 04変更前後のビルド設定の比較

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/unity-technologies/skills --skill optimize-web

インストール後、Claude Code で/optimize-webを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

SECURITY.md
scripts/
toktx-examples.sh
WebOptimizer.cs

詳細

Unity Web ビルドを小型化・高速化するために、Player Settings、圧縮、ストリッピング、サーバー設定を監査して適用します。

重要

  • 各手順で unity cli(unity command --format json)と unity-cli スキルを使用してください。利用可能な場合は unity-pipeline も使用してください。
  • 変更を加える前に、現在の動作のベースラインを確認し、後で結果が実際に変更によるものか判断できるようにしてください。
  • 変更が失敗した場合にロールバックできる復元ポイントを作成してください。
  • 指示された作業だけを行ってください。無関係なアセットやファイルは変更しないでください。
  • 変更が実行時の動作に影響する場合は、実際のシーンの動作を証明できる Debug.Log 行を追加してください(変更内容だけを示すものではありません)。後で検証するため、Play モードに入ったときにこれらのログを確認します。たとえば、修正によって GameObject のサイズが変わるようにする場合は、その Transform のスケールをログに出してください。
  • 長い説明は避けてください。

パフォーマンスに関する注意

  • 時間をかけて、作業を徹底してください。
  • 速度より品質を重視してください。

トピック全一覧

ワークフローや診断を進める前に:

  1. 実行または修正しようとしている内容に関連する特定のトピックを扱うドキュメントページを開いて読み、見落としがないか確認してください。
  2. 回答の中で、読んだファイル名を明記してください。

Unity に関するトレーニング済みの知識は、古くなっていたり、誤っていたり、異なる Unity バージョン向けだったりする可能性があるためです。

Editor のインストールフォルダーに Data/Documentation フォルダー(例:...Unity/Hub/Editor/6000.6.0b2/Editor/Data/Documentation)がある場合は、<editor-install>/Editor/Data/Documentation/en/Manual フォルダーから html ファイルを読んでください。それ以外の場合、ドキュメントページはオンラインの https://docs.unity.com/en-us/engine/<VERSION>/manual/ にあります。

このスキルが使用するパッケージ(com.unity.cloud.ktx、com.unity.addressables、com.unity.web.stripping-tool)については、ドキュメントページは Unity Manual をローカルで Markdown に変換したもので、<project-folder>/Library/PackageCache/<package-name>@*/ に保存されています。その特定の PackageCache サブフォルダー内の .md ファイルだけを読んでください。.md ファイルがない場合は、代わりに https://docs.unity3d.com/Packages/<package-name>@<VERSION>/manual/ を使用してください。

WebSearch よりも WebFetch を優先してください。より高速で、目的のリファレンスに直接アクセスできます。必要なページだけを取得してください。取得する前に、<VERSION> を以下の値に置き換えてください。

  • docs.unity3d.com:Unity のバージョン。例:6000.6
  • docs.unity3d.com のパッケージ:パッケージのバージョン。例:@6.6 または @2.0。不明な場合は、パッケージのバージョンを確認してください。
  • docs.unity.com:Unity のバージョン。例:6000.6

ProjectSettings/ProjectVersion.txt から Unity のメジャー・マイナーバージョンを読み取ってください(例:6000.0.58f1 から 6000.0。ビルド番号全体では 404 になります)。また、Packages/packages-lock.json から各パッケージのメジャー・マイナーバージョンを読み取ってください。

API リファレンス

API は UnityEditor.PlayerSettings、UnityEditor.PlayerSettings.WebGL、UnityEditor.WebGL.UserBuildSettings で、Unity Engine の一部です。Unity のバージョンごとに異なるため、特定のクラスやメソッドを使用する前に、プロジェクトの Unity バージョンを確認してください。

  1. unity-cli スキルを使用して、プロジェクトの Unity バージョンを確認します。
  2. Editor のインストールフォルダーに Data/Documentation フォルダーがある場合(例:.../Unity/Hub/Editor/6000.6.0b2/Editor/Data/Documentation)、その中の en/ScriptReference フォルダーにある html ファイルを grep し、残りの手順はスキップします。
  3. それ以外の場合は、https://docs.unity3d.com/<VERSION>/Documentation/ScriptReference/xrefmap.yml を取得してキャッシュします(<VERSION> を Unity のバージョンに置き換えます。例:6000.3)。このファイルには、各公開 API メンバーの完全修飾名が uid として記載されています(例:uid: 'UnityEngine.Rigidbody.AddForce(UnityEngine.Vector3)')。
  4. クラスやメソッドを検索するたびにファイルを再取得するのではなく、yml ファイルをローカルで grep します。ファイルは大きく(約 6 MB)、全体を読み込まないでください。
  5. uid を Markdown ページに変換します。括弧内のパラメーターを削除し、小文字に変換して、. を / に置き換え、.md を追加します。その後、https://docs.unity.com/en-us/engine/<VERSION>/script-reference/<converted uid> を取得します。たとえば、UnityEngine.Rigidbody.AddForce(UnityEngine.Vector3) は https://docs.unity.com/en-us/engine/6000.3/script-reference/unityengine/rigidbody/addforce.md になります。すべてのオーバーロードは同じページにあります。
    • コンストラクターには ctor を使用します(例:unityengine/vector3/ctor.md)。インデクサーには item を使用します(例:unityengine/vector3/item.md)。
    • ページ内のリンクは /engine/ で始まります。先頭に https://docs.unity.com/en-us を追加してください。
    • その Unity バージョンのページが存在しない場合は、代わりに xrefmap.yml の該当エントリーにある href を使用します(例:href: 'Rigidbody.AddForce.html' => https://docs.unity3d.com/6000.3/Documentation/ScriptReference/Rigidbody.AddForce.html)。

API はバージョン間で頻繁に非推奨になるため、学習時の知識に頼らず、必ずプロジェクトの Unity バージョンのドキュメントを使用してください。

KTX API(KtxUnity)は com.unity.cloud.ktx パッケージの一部です。Unity のバージョンではなくパッケージのバージョンごとに異なるため、特定のクラスやメソッドを使用する前に、プロジェクトにインストールされているパッケージのバージョンを確認してください。

  1. Packages/packages-lock.json から、インストールされているパッケージのバージョンを読み取ります。
  2. https://docs.unity3d.com/Packages/com.unity.cloud.ktx@<version>/xrefmap.yml を取得してキャッシュします(<version> をインストールされているパッケージのバージョンに置き換えます。例:3.4)。このファイルには、各公開 API メンバーの完全修飾名と、そのドキュメントページの href が対応付けられています。
  3. クラスやメソッドを検索するたびにファイルを再取得するのではなく、yml ファイルをローカルで grep します。ファイル全体を読み込まないでください。

手順

  1. プロジェクトのコンテキストを確認します。ProjectSettings/ProjectVersion.txt から Unity のバージョンを、Packages/packages-lock.json から必要なパッケージ(com.unity.cloud.ktx、com.unity.addressables、com.unity.web.stripping-tool)のバージョンを取得します。プロジェクトがない場合は、Unity 6000.0 を想定します。packages-lock.json に記載のないパッケージについては、そのパッケージのドキュメントにある最新バージョンを想定します。確認できたバージョンはすべて保持し、実際に不足している値だけをデフォルトにします。レポートには各想定を明記して、作業を続けます。ユーザーが最適化したい内容を指定しておらず、参照できるプロジェクトもない場合は、何を改善したいかを尋ねます。
  2. Full topic map から、タスクに関するドキュメントページを読みます。
  3. Running C# in the Editor の説明に従って eval を設定します。アクセス可能な Editor がない場合、または eval が見つからない場合は、その旨を伝えて手順 5 に進み、その後は手順 9 に進みます。レポートでは、ビルドの検証とランタイムチェックを未実施として記載し、手順 2 のユーザーの要望とドキュメントに基づいて推奨事項を提示します。
  4. 0. Pre-Flight と 1. Assess Current State を実行します。その結果をベースラインとします。
  5. 要望に合致する行を 2. Understand Request から選びます。
  6. 復元ポイントを作成してから、3. Web Build Optimization Workflow の変更を適用します。症状が 5. Troubleshooting に該当する場合は、その項目に従います。
  7. 4. Validation を実行します。[Pre-Flight] のスニペットを再実行し、値をベースラインと比較します。
  8. Final step のチェックを実行します。
  9. Final report を提出します。

Running C# in the Editor

Player Setting を読み書きする以下の各手順は、Unity CLI を通じて実行中の Editor 内で行います。Editor への接続は unity-cli スキルが担当します。CLI のインストール、接続済み Editor の確認、プロジェクトへの com.unity.pipeline パッケージの追加、Editor が本当に存在しない場合と Safe Mode で停止している場合の見分け、Editor のコマンドカタログの確認は、このスキルに従ってください。まずスキルの手順を実行し、ここで同じことを改めて調べないでください。

このスキルでは把握できない点が 2 つあります。

  • アクセス可能な Editor だけではなく、特に eval が必要です。 カタログに eval が表示されることを確認してください。利用できるかどうかは CLI ではなく Pipeline パッケージのバージョンによって決まるため、インストールが正常でも eval がない場合があります。見つからない場合はその旨を伝え、設定を読み書きする手順を省略してください。
  • 必要に応じて ProjectSettings/ProjectSettings.asset から Player Settings を読み取ることはできますが、その方法で書き込まないでください。 シリアライズされた名前は API の名前と一致しません。また、これらの設定のいくつかはビルドターゲットごとに異なり、手動で編集した値はビルドで実際に使用される値と食い違っても検出されません。Editor に接続できない場合は、書き込み手順を中止してください。

unity command eval --code '<snippet>' で C# を実行します。unity command のデフォルトのタイムアウトは 30 秒です。

eval への C# の渡し方

eval がコンパイルするのはファイルではなくステートメントブロックなので、using ディレクティブを使わず、完全修飾型名を使用してコードを記述してください。コードがコンパイルできない場合は、以下でエラーを確認してください。

エラー原因修正方法
CS0210using UnityEditor; のような using ディレクティブを、コンパイラーがリソース破棄ステートメントとして読み取っているディレクティブを削除し、型を修飾する
CS0246PlayerSettings のような非修飾型UnityEditor.PlayerSettings のように完全修飾名を使用する
CS0104Object が object と曖昧になっているUnityEngine.Object を使用する
このスキルが監査する設定の読み取り

1 回の呼び出しで、プリフライトの全体像を取得できます。Unity 6000.5.7f1 で検証済みです。

var target = UnityEditor.Build.NamedBuildTarget.WebGL;
var w = new System.Collections.Generic.List<string>();
w.Add($"activeBuildTarget={UnityEditor.EditorUserBuildSettings.activeBuildTarget}");
w.Add($"compressionFormat={UnityEditor.PlayerSettings.WebGL.compressionFormat}");
w.Add($"decompressionFallback={UnityEditor.PlayerSettings.WebGL.decompressionFallback}");
w.Add($"stripEngineCode={UnityEditor.PlayerSettings.stripEngineCode}");
w.Add($"managedStrippingLevel={UnityEditor.PlayerSettings.GetManagedStrippingLevel(target)}");
w.Add($"il2cppCodeGeneration={UnityEditor.PlayerSettings.GetIl2CppCodeGeneration(target)}");
w.Add($"apiCompatibilityLevel={UnityEditor.PlayerSettings.GetApiCompatibilityLevel(target)}");
w.Add($"exceptionSupport={UnityEditor.PlayerSettings.WebGL.exceptionSupport}");
w.Add($"debugSymbolMode={UnityEditor.PlayerSettings.WebGL.debugSymbolMode}");
w.Add($"dataCaching={UnityEditor.PlayerSettings.WebGL.dataCaching}");
w.Add($"wasm2023={UnityEditor.PlayerSettings.WebGL.wasm2023}");
w.Add($"initialMemorySize={UnityEditor.PlayerSettings.WebGL.initialMemorySize}");
w.Add($"maximumMemorySize={UnityEditor.PlayerSettings.WebGL.maximumMemorySize}");
w.Add($"memoryGrowthMode={UnityEditor.PlayerSettings.WebGL.memoryGrowthMode}");
w.Add($"targetFrameRate={UnityEngine.Application.targetFrameRate}");
w.Add($"vSyncCount={UnityEngine.QualitySettings.vSyncCount}");
return string.Join("\n", w);

正しい API 名を使う必要がある設定が 3 つあります。見た目から想像できる名前は存在せず、コンパイルに失敗するためです。

設定正しい形式存在しないもの
マネージドストリッピングレベルPlayerSettings.GetManagedStrippingLevel(NamedBuildTarget.WebGL)PlayerSettings.managedStrippingLevel
Wasm コード最適化UnityEditor.WebGL.UserBuildSettings.codeOptimizationPlayerSettings.WebGL.codeOptimization、PlayerSettings.WebGL.optimizationLevel
IL2CPP コード生成PlayerSettings.GetIl2CppCodeGeneration(NamedBuildTarget.WebGL)単独のプロパティ

UserBuildSettings は WebGL ビルドサポートモジュールにあるため、そのモジュールがインストールされている場合にのみ解決されます。ほかの設定とは別の呼び出しで読み取り、解決に失敗した場合は、不正なコードではなく「Web モジュールがインストールされていない」と判断してください。

codeOptimization は、ここに挙げた設定のうちプロジェクトファイルに保存されない唯一の設定です。 Library/EditorUserBuildSettings.asset に保存されますが、Library/ は標準の Unity .gitignore で無視されるため、この値はマシンごとに異なり、共有されません。チームメンバーや CI に引き継がれることもありません。ここから 2 つのことがわかります。API 経由で値を読み戻し、ProjectSettings/ProjectSettings.asset を探さないでください。適用に成功してもそこには存在しないため、値がないことは失敗を意味しません。また、リリースビルドを CI で実行する場合、リポジトリに値が含まれていると想定せず、ビルドステップとして CI で適用してください。

設定の適用

このスキルで行う書き込みのほとんどは 1 回のバッチ処理で、scripts/WebOptimizer.cs がそのバッチ処理をすでに実行します。このファイルでは [MenuItem] を使ってクラスを宣言しているため、eval の入力ではなくプロジェクトファイルです。クラス宣言はステートメントブロックに変換できません。Assets/Editor/ に保存し、Unity のコンパイルを待ってから、1 行で実行してください。

UnityEditor.EditorApplication.ExecuteMenuItem("Tools/Apply Web Release Settings");

using ディレクティブはそのまま残してください。ファイル内では正しいものです。単発の変更、たとえば単一の品質レベルやフレームレートの切り替えには、インラインの eval ステートメントを使って問題ありません。

書き込んだオブジェクトではなく、ディスクから確認する

設定を適用して同じセッション内で読み戻しても、何も証明できません。 Player Settings は保存されるまでメモリ上のオブジェクトであるため、読み戻すと、ProjectSettings/ProjectSettings.asset に実際に反映されたかどうかにかかわらず、割り当てた値が返されます。保存を省略した実行でも成功と報告されますが、Editor セッションが終了すると変更はすべて失われます。これは推測ではなく、実際に確認された現象です。すべてを適用し、Brotli / High / None を読み戻して完了を報告した実行でも、ディスク上のファイルは変更されていませんでした。

そのため、書き込み後は次の手順を実行してください。

  1. 保存します。 UnityEditor.AssetDatabase.SaveAssets() を呼び出します。WebOptimizer.cs はすでに自身で保存するようになっています。インラインの eval で書き込む場合は、明示的に保存する必要があります。
  2. 値を読み戻して報告します。 「適用に成功しました」ではなく、実際の値を報告して、ユーザーが保存内容を確認できるようにします。WebOptimizer.cs は 9 項目すべてをログに出力します。
  3. ビルドターゲットごとに設定される項目は、読み取った対象を明記します。 これらの設定のいくつかはターゲットごとに存在するため、あるターゲットでは正しい値でも、ビルド対象のターゲットでは未設定の場合があります。

ファイルを直接編集する場合にも、同じ落とし穴が逆向きに存在します。ProjectSettings.asset を手動で編集すると値は読み戻せますが、実行中の Editor とビルドは古い値を使い続けます。保存して再インポートした後に検証すれば、どちらの問題も検出できます。

バッチモードでこれを再現しようとしないでください。 -quit を指定して起動したバッチ Editor は終了時に設定を保存するため、保存していない書き込みも結果的に永続化され、実行は正しく見えます。保存するスクリプトと保存しないスクリプトのどちらも、-quit のもとでは成功します。この不具合が発生するのはライブ Editor セッションだけであり、実際に発見されたのもその環境です。不具合を検出できないテストでバッチ実行が成功したからといって、保存は不要だと結論づけるのは誤りです。

0. 事前確認

  1. Web ビルドターゲットを確認します: 上記の事前確認スニペットを使って EditorUserBuildSettings.activeBuildTarget を読み取ります。値は WebGL である必要があります。そうでない場合は、ユーザーに警告してください。
  2. 圧縮とストリッピングの設定を読み取ります: 上記の事前確認スニペットを使って compressionFormat、decompressionFallback、stripEngineCode、およびマネージドストリッピングレベルを読み取ります。ストリッピングレベルは PlayerSettings.GetManagedStrippingLevel(NamedBuildTarget.WebGL) です。PlayerSettings.managedStrippingLevel プロパティはありません。
  3. 例外処理と最適化の設定を読み取ります: 上記の事前確認スニペットを使って PlayerSettings.WebGL.exceptionSupport を読み取ります。Wasm コードの最適化レベルには UnityEditor.WebGL.UserBuildSettings.codeOptimization を使います。PlayerSettings.WebGL.codeOptimization と optimizationLevel という表記は存在せず、コンパイルできません。
  4. フレームレート設定を読み取ります: 上記の事前確認スニペットを使って Application.targetFrameRate と QualitySettings.vSyncCount を読み取ります。
  5. 追加のプレイヤー設定を読み取ります: 上記の事前確認スニペットを使って PlayerSettings.WebGL.dataCaching、PlayerSettings.WebGL.debugSymbolMode、PlayerSettings.WebGL.maximumMemorySize、および PlayerSettings.GetApiCompatibilityLevel を読み取ります。
  6. 圧縮、ストリッピング、フレームレート、およびプレイヤー設定を確認してから先に進んでください。

1. 現状を評価する

  1. ビルドレポートを確認します: ビルド後にユーザーに Window > General > Build Report を開いてもらい、サイズが最も大きいアセットとコードの要因を特定します。
  2. サーバー設定を確認します: ホスティングサーバーが Content-Encoding: br(Brotli)または Content-Encoding: gzip ヘッダーを送信しているか、また .wasm ファイルに Content-Type: application/wasm が設定されているかをユーザーに確認します。
  3. フレームレート設定を確認します: 上記の事前確認スニペットを使って Application.targetFrameRate を確認します。Web ではブラウザーに任せるため、-1 にする必要があります。
  4. メモリ設定を確認します: 上記の事前確認スニペットを使って PlayerSettings.WebGL.initialMemorySize と PlayerSettings.WebGL.memoryGrowthMode を読み取ります。
  5. 推奨事項を提示する前に、調査結果を報告してください。

2. リクエストを把握する

ユーザーの発言デフォルトの解釈
「ビルドが大きすぎる」/「ダウンロードが遅すぎる」エンジンコードのストリッピングをオンにする。マネージドストリッピングを High にする。Disk Size + LTO を使う。Brotli を使う
「Decompression Fallback」/「起動が遅い」Decompression Fallback をオフにする。Content-Encoding を送信するようサーバーを修正する
「Chrome でカクつく」/「Safari でカクつく」ブラウザーの DevTools でプロファイルを記録する。Safari は 60 fps に制限される
「ブラウザーでバッテリーを過剰に消費する」静的な画面では OnDemandRendering をオンにする。targetFrameRate = -1 にする
「例外処理のサイズが大きすぎる」リリースでは例外処理をなしにする。ブラウザーのベースラインが対応していれば Wasm 2023 の例外処理を使う
「CDN を設定する」Addressables のリモートグループを使い、CDN で Brotli/Gzip を有効にする
「WebAssembly 2023」ブラウザーのベースラインが対応したら有効にする。サイズが小さくなり、処理も速くなる
「メモリの拡張が遅い」初期メモリサイズをピーク時の推定値に合わせる。Geometric growth モードを使う
「KTX」/「Basis Universal」/「GPU のテクスチャ形式が不明」Basis Universal を使った KTX2 を使う。サイズ重視なら ETC1S、品質重視なら UASTC を使う
「未使用コードをストリッピングする」/「未使用パッケージを削除する」Web Stripping Tool を使い、未使用パッケージを削除し、シェーダーをストリッピングする
「Web 向けの品質設定」Quality Level を Very Low または Low にする。品質を下げるほど読み込みが速くなる
「シェーダーバリアントが多すぎる」Graphics 設定でライトマップモードとフォグモードを自動にする。インスタンシングと BRG のバリアントをストリッピングし、Always Included Shaders を監査する
「動画が再生されない」/「音声の問題」動画:URL のみ、または StreamingAssets を使う。音声:Web では AudioEffects を使わず、Mono を使って圧縮する
「プロファイラーのシンボル」/「Wasm のスタックを読み取れない」ビルドプロセッサーまたは emscriptenArgs を使ってプロファイリングシンボルを埋め込む
「iOS でクラッシュする」/「Safari のメモリ」iOS のメモリ制限を考慮する。拡張するより初期メモリサイズを大きく設定する。iOS 18 より前は Gigacage の上限が 2GB

3. Web ビルド最適化のワークフロー

重要:ワンクリック最適化スクリプト

このスクリプトを生成することを必ずユーザーに提案してください。 Unity の公式 Web 最適化ドキュメントには、推奨されるリリース設定を一度にすべて適用する、エディターメニュー用のスクリプトが用意されています。Assets/Editor/WebOptimizer.cs に配置してください。テンプレートについては、scripts/WebOptimizer.cs を参照してください。

ユーザーのプロジェクトの要件に合わせてスクリプトを調整してください(例:try/catch を使用している場合は例外処理を有効にする、HTTP ホスティングでは Brotli を Gzip に切り替える)。このスクリプトは、新しい Web プロジェクトで最も効果の大きい単一の対策です。設定の見落としを防げます。

Player Settings の監査

eval を通じて次の値を確認し、設定してください。

設定リリース時の推奨値
Compression FormatBrotli(HTTPS ホスティング);HTTP の場合は Gzip
Decompression Fallbackサーバーが正しく設定されている場合は オフ
Strip Engine Codeオン
Managed Stripping LevelHigh(リリース)/Medium(開発)
Code OptimizationDisk Size with LTO(リリース)/Build Times(開発)
WebAssembly Language Featuresブラウザーのベースラインが対応している場合は 2023
Enable ExceptionsNone(最小サイズ);try/catch が必要な場合は Explicitly Thrown Only
Initial Memory Sizeピーク時の推定値に合わせて調整します。小さすぎると拡張コストが高くなります
Memory Growth ModeGeometric
API Compatibility Level.NET Standard 2.1 — .NET Framework より小さいサイズです
IL2CPP Code GenerationOptimize Size — 実行時コストがわずかに増える代わりに、Wasm のサイズを小さくします
Debug Symbolsリリースでは オフ;開発ビルドでのみオン
Data Cachingオン — アセットデータをブラウザーの IndexedDB にキャッシュし、再読み込みを高速化します
Strip Unused Mesh Componentsオン — 未使用の頂点属性を削除します
Maximum Memory Sizeデフォルトは 2048 MB;複雑な 3D では最大 4096(Firefox と Chrome < 119 では 2048 を超えると問題が発生します)
vSyncCount0(ブラウザーがペースを制御します)
targetFrameRate-1(requestAnimationFrame を使用します)
圧縮とサーバー設定
圧縮方式使用する状況備考
BrotliHTTPS または localhost最も高い圧縮率です。ブラウザーが受け付けるのはセキュアコンテキストのみです
GzipHTTP 配信、レガシー CDN広く利用できます
Noneローカル開発/file://ペイロードが最大になります。リリースには使用しないでください

サーバーを次のように設定してください。

  • .br ファイルを Content-Encoding: br で配信します。
  • .gz ファイルを Content-Encoding: gzip で配信します。
  • .wasm には application/wasm、.js には application/javascript の Content-Type を設定します。
  • チャンクの取得を並列化するため、HTTP/2 または HTTP/3 を有効にします。

ホスト側で Content-Encoding を付与できない場合は、フォールバックとしてのみ Decompression Fallback = On に設定してください。約 150 KB の JS が追加され、起動が遅くなります。

例外処理
設定ビルドサイズ使用場面
None最小未処理例外を許容できるリリースビルド
Explicitly Thrown Onlyやや増加例外をキャッチするプロジェクトのデフォルト
Full最大、最も低速必要になることはまれです。リリースでは避けてください

Wasm 2023 では、より低コストな例外モデルが導入されています。ブラウザーのターゲットが対応している場合、Explicitly Thrown Only(従来方式)から Wasm 例外に切り替えると、サイズとコストの両方を削減できます。

未使用のリソースを削除する

ビルドサイズを削減するために監査する3つのカテゴリ:

1. 未使用のパッケージ — Packages/manifest.json と、Package Manager の In Project および Built-in ビューを確認します。プロジェクトで使用していないパッケージは削除するか、無効にしてください。Input System パッケージを使用していない場合、サイズを大きくする要因になります。

2. シェーダーのストリッピング — Edit > Project Settings > Graphics で設定します:

設定推奨事項
Lightmap ModesAutomatic(未使用のライトマップシェーダーバリアントをストリップします)
Fog ModesAutomatic(未使用のフォグシェーダーバリアントをストリップします)
Instancing VariantsStrip Unused
Batch Renderer Group VariantsStrip All(BRG を使用していない場合)
Always Included Shaders監査し、プロジェクトが参照していないシェーダーを削除します

ストリッピング後にテストし、参照されているシェーダーを削除していないことを確認してください。

3. Web Stripping Tool(com.unity.web.stripping-tool)— WebAssembly バイナリを分析し、未使用の Unity エンジンサブモジュール(例:2D 専用ゲームでの3Dグラフィックス)を特定します。Package Manager からインストールし、ビルドをプロファイリングしてから、除外するサブモジュールを設定します。Managed Stripping Level 単独の場合を超える、大幅なサイズ削減が期待できます。

Web 向けの品質設定

品質レベルを下げると、読み込み時間が短縮され、実行時のパフォーマンスが向上します。Edit > Project Settings > Quality で設定します:

  • Web のデフォルト品質レベルには Very Low または Low を使用します。
  • eval で設定します:UnityEngine.QualitySettings.SetQualityLevel(0, true);(0 = Very Low)。
  • ブラウザー内では不要な機能(リアルタイムシャドウ、ポストプロセスエフェクト、多数のパーティクルなど)を無効にする、Web 専用の品質レベルを作成することを検討してください。
Web でのフレームレート
  • eval で設定します:UnityEngine.Application.targetFrameRate = -1; — ブラウザーの requestAnimationFrame を使用します。
  • 注意:Safari は WebGL で 60 fps に制限されます。高リフレッシュレートのターゲットは適用されません。
  • 静的画面やアイドル画面では OnDemandRendering.renderFrameInterval を使用して 5~10 fps に下げ、バッテリーを節約します。
KTX / Basis Universal テクスチャ

Basis Universal の超圧縮を使用した KTX2 は、単一のテクスチャファイルを配布し、読み込み時にブラウザーのデバイスに最適な GPU フォーマット(デスクトップでは BC7、モバイルでは ASTC、古い Android では ETC2)にトランスコードします。GPU ファミリーごとに別々のテクスチャバリアントを配布する必要がなくなります。ターゲットハードウェアが不明な Web では特に重要です。

トピックガイダンス
パッケージPackage Manager から com.unity.cloud.ktx(KtxUnity)をインストールします
使用する場合Addressables 経由で実行時に読み込むテクスチャ、または不特定の GPU ターゲット向けに配信するアセットバンドル
使用しない場合プレイヤービルドに組み込まれたテクスチャ — Unity がビルド時に適切なフォーマットをすでに選択しています
超圧縮最小サイズにする場合は ETC1S(非可逆、ディフューズ/アルベドに適しています)、高品質にする場合は UASTC(ほぼ可逆、法線/UI に適しています)を使用します
エンコードtoktx または basisu CLI でオフラインエンコードします。実行時にはエンコードしないでください
リニアデータ法線マップ、マスク、またはデータテクスチャをエンコードする際は、sRGB 変換の誤りを防ぐため --assign_oetf linear を設定します
ミップマップエンコード時にミップマップを生成します(--genmipmap)。ブラウザー側でのミップマップ生成は高コストです
読み込みKtxTexture.LoadFromStreamingAssets を使用するか、UnityWebRequest でバイト列を読み込んで KtxTexture.LoadFromBytes を呼び出します
メモリトランスコードされたテクスチャは標準の GPU テクスチャです。メモリ使用量は KTX2 ファイルサイズではなく、ターゲットフォーマットのサイズに相当します
向きUnity の UV 規約に合わせるため、必ず --lower_left_maps_to_s0t0 を含めます

toktx CLI の例: アルベド(ETC1S)、法線/ディテール(UASTC)、ICC プロファイルエラー、リニアデータに対応するコマンドについては、scripts/toktx-examples.sh を参照してください。

Web でのストリーミング
  • CDN でホストし、Brotli / Gzip で圧縮したリモートグループで Addressables を使用します。
  • ゲーム全体を初回ダウンロードに含めるのは避け、レベルを必要に応じてストリーミングします。
  • 「インスタントプレイ」向けに、初回ダウンロードを 30 MB 未満に抑えます。レベルデータはその後に読み込みます。
  • 異なる GPU ハードウェアを対象にテクスチャをストリーミングする場合、プラットフォームごとのバリアントより KTX2 バンドルを優先します。1 つのバンドルですべてのブラウザーに対応できます。
Web ビルドのプロファイリング
ツール用途備考
Chrome DevTools > PerformanceCPU フレームグラフ、メインスレッドの分析WebGL のカクつきが発生した際に最初に確認します。Wasm のコールスタックを調べます
Chrome DevTools > Memoryヒープスナップショット、割り当てタイムラインJS/Wasm のメモリリークを特定します。シーンの読み込み前後でスナップショットを比較します
Firefox Profilerクロスプラットフォーム対応、共有可能な URL、ネイティブと Wasm の表示場合によっては Chrome より Wasm のシンボル解決に優れています。チームレビュー用にプロファイル URL を共有できます
Safari Web InspectoriOS Safari と macOS Safari のデバッグSafari 固有の問題には必須です。WebGL/Wasm ランタイムは Chromium と異なります
WebSocket 経由の Unity Profiler開発ビルドに接続し、標準マーカーを表示Unity 側のマーカー(GC、レンダリング、スクリプト)に使用します。ブラウザー側のオーバーヘッドは取得しません

症状別のツール早見表:

症状最初に使うツール次に使うツール
WebGL の引っかかり/カクつきChrome DevTools > PerformanceFirefox Profiler
時間の経過とともにメモリが増加するChrome DevTools > MemoryUnity Memory Profiler (WebSocket)
初回読み込みが遅いChrome DevTools > NetworkBuild Report Inspector
Safari のみで発生するレンダリングの問題Safari Web InspectorChrome DevTools と比較

プロファイリングシンボルの埋め込み — ブラウザのプロファイラーでは、デフォルトで難読化された Wasm 関数名が表示されます。Chrome/Firefox のフレームグラフで読みやすい C# メソッド名を表示するには、開発ビルドで Player Settings > Publishing > Debug Symbols を有効にするか、ビルドプロセッサーを追加します。

using UnityEditor;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;

public class WebProfilingBuildProcessor : IPreprocessBuildWithReport
{
    public int callbackOrder => 0;
    public void OnPreprocessBuild(BuildReport report)
    {
        PlayerSettings.SetAdditionalIl2CppArgs("--compiler-flags=--profiling-funcs");
    }
}

Emscripten 組み込みプロファイラー — PlayerSettings.WebGL.emscriptenArgs で一度に 1 つだけ有効にします。

フラグ表示内容
--cpuprofilerブラウザー内の CPU プロファイラーオーバーレイ
--memoryprofiler視覚的なメモリマップ(白=割り当て済み未使用、ピンク=スタック、青=動的、緑=断片化)
--threadprofilerスレッドアクティビティプロファイラー

GPU デバッグ — Web では Frame Debugger をサポートしていません。ブラウザーベースの代替手段として Spector.js を使用します。描画呼び出しと WebGL の状態を取得できます。

Firefox の about:memory — Firefox の URL として about:memory を入力し、Measure をクリックすると、タブごとの内訳(WASM コードサイズ、WASM ヒープ、.data ファイル、Web Audio)を確認できます。WASM ヒープが 300 MB を超えていないか注意してください(特に iOS Safari ではクラッシュのリスクがあります)。

エディターの Play モードはブラウザーのランタイムを再現しません。必ずブラウザーで計測してください。Chrome と Safari では GC と JIT の動作が異なるため、両方でテストしてください。

Web のメモリに関する指示
  • テクスチャとメッシュのRead/Write Enabledを無効にします。有効にすると、データが WASM ヒープに複製されます。
  • アセットを Addressables または AssetBundles に移動して、.data ファイルのサイズを小さくします。
  • 圧縮テクスチャ形式(KTX2/Basis)を使用して、ダウンロードサイズとデコード後のメモリ使用量の両方を削減します。
iOS Safari のメモリ制限
  • iOS < 18: WebContent プロセスの上限は約 1.5 GB です。WASM メモリ(Gigacage)の上限は 2 GB です。型付き配列はこのメモリプールを共有します。iPhone X(iOS 16)ではヒープの拡張上限は約 512 MB ですが、Initial Memory Size を事前に 512 MB~1.5 GB に設定すれば動作します。
  • iOS 18 以降: 制限はほぼ撤廃されています。iPhone 11 では約 4 GB を割り当てられます。
  • iOS では、拡張に頼らず、目標とするピーク値に合わせてInitial Memory Sizeを設定します。Safari は、段階的な拡張よりも大きなメモリを事前に割り当てるほうが適切に処理できます。
  • 古い iOS では、WASM ヒープが 300 MB を超えるとクラッシュのリスクが高まります。幅広い互換性を確保するため、200 MB 未満を目標にします。
Web 上的视频和音频
  • 動画: 再生できるのは、URL(CORS が有効になっているサーバー)または StreamingAssets からのみです。iOS でストリーミングするには、サーバーが HTTP の Range リクエストに対応している必要があります。ブラウザー互換の形式(MP4/H.264)を使用してください。
  • 音声: AudioEffects(ミキサーエフェクト)にはコンピュートシェーダーが必要です。WebGL では利用できません。ミキサーと MixerGroups は音量調整にのみ使用できます。読み込みを改善するには、音声を Mono に設定してください。about:memory で Web Audio が 100 MB を超えている場合、音声が非圧縮である可能性があります。Vorbis に切り替えてください。
Canvas と DPI

Canvas を拡大すると、新しい解像度が適用されます。Web テンプレートで devicePixelRatio を使用して DPI スケーリングを補正し、不必要に高い解像度でのレンダリングを避けてください。

4. 検証

  1. Pre-Flight スニペットを使って Player Settings を再確認します(圧縮、ストリッピング、例外、targetFrameRate)。
  2. プレイヤーを再ビルドし、Build Report のファイルサイズをベースラインと比較します。
  3. 少なくとも Chrome と Safari で確認します(GC と JIT の挙動は異なります)。
  4. ユーザーにフィードバックを求めるまでの反復は最大 3 回です。

5. トラブルシューティング

Strip Engine Code を有効にしてもビルドが大きい
  1. Managed Stripping Level が Medium または Low に設定されていますか? → リリースでは High に設定します。
  2. プラグインがリフレクションを使って、本来ならストリッピングされるエンジンモジュールにアクセスしていますか? → 必要なシンボルを保持するために link.xml を追加します。
  3. Exceptions が Full に設定されていますか? → Full はコードのオーバーヘッドが最も大きくなります。None または Explicitly Thrown Only に切り替えます。
Brotli が機能しない — Decompression Fallback が必要
  1. サーバーは Content-Encoding: br を送信していますか? → このヘッダーがないとブラウザーは展開できず、フォールバック用の JS デコンプレッサーが必要になります。
  2. ビルドは HTTP(HTTPS ではなく)でホストされていますか? → Brotli にはセキュアコンテキストが必要です。HTTP でホストする場合は Gzip に切り替えます。
Chrome では問題ないが、Safari でカクつく
  1. プロジェクトで Application.targetFrameRate = 60 が設定されていますか? → Safari WebGL ではブラウザーのフレーム制御と競合します。-1 に設定します。
  2. Safari の WebGL 実装で異なる動作をするシェーダーがありますか? → デバイスでテストしてください。Safari の WebGL/Wasm ランタイムは Chromium と異なるため、一部の GLSL 構文の扱いも異なります。
メモリ拡張の低速パスが発生する
  1. Initial Memory Size がプロジェクトのピークに対して小さすぎますか? → Wasm のメモリ拡張ではバッファー全体のコピーが必要です。Initial Memory Size を現実的なピーク推定値に設定します。
  2. Memory Growth Mode が Linear に設定されていますか? → より適切な増加曲線になるよう、Geometric に切り替えます。
フレームレートを 60 に設定しているのに、ブラウザーの動作が不安定
  1. コードで Application.targetFrameRate = 60 が設定されていますか? → Web ではブラウザーの requestAnimationFrame によるフレーム制御と競合します。-1 に設定します。
  2. vSyncCount が 0 以外ですか? → 0 に設定します。フレーム制御はブラウザーが行います。
Firefox が大きなファイルをキャッシュできない

Firefox は browser.cache.disk.max_entry_size によって、キャッシュエントリーごとのサイズを制限しています。ビルドがこの上限(デフォルトで約 50 MB)を超えると、アセットはキャッシュされません。対処法:Addressables を使って 51 MB 未満のバンドルに分割するか、ユーザーに about:config で設定を増やすよう案内します。

ローカル開発サーバーのセットアップ

適切な MIME タイプでビルドをローカルテストするには:

# Python (HTTP)
python -m http.server 55553 -d path/to/build

# Node.js (install serve-handler)
npx serve path/to/build -l 3001

Brotli のテストには HTTPS を使用してください。Brotli にはセキュアコンテキストが必要です。ローカルテスト用に OpenSSL で自己署名証明書を生成します。

最終ステップ

Web の設定はブラウザーのビルドでのみ有効になるため、クリーンコンパイルと Editor での Play モードだけでは不十分です。以下の確認を順番に実行してください。いずれかの確認に失敗した場合は、ドキュメントのページを読み直して見落とした点を確認し、修正してから再度確認してください。

  1. プロジェクトにコンソールエラーが一切ないことを確認します。
  2. 変更した各設定が保存されていることを、ディスクから確認する(書き込んだばかりのオブジェクトから確認しない)の説明に従って確認します。ProjectSettings/ProjectSettings.asset に新しい値が保持されており、codeOptimization は API 経由で読み取れる必要があります。
  3. Player を再ビルドした場合は、ローカル開発サーバーのセットアップの説明に従ってビルドを配信し、ブラウザーで開きます。その後、以下を確認します。
    • ブラウザーのコンソールに、圧縮解除の失敗やメモリ不足エラーなどのエラーが表示されていないこと。
    • Network タブで、.wasm、.data、.framework.js ファイルの Content-Encoding ヘッダーが圧縮形式(Brotli の場合は br、Gzip の場合は gzip)に一致し、ファイルサイズが Build Report と一致していること。
  4. フレームレートや品質レベルなど、変更がランタイムの動作に影響する場合は、ブラウザーのコンソールで Debug.Log の行を確認してから削除します。スクリーンショットの撮影と確認は、どうしても必要な場合を除き避けてください。時間がかかるためです。

最終レポート

実施したこととその理由を、簡潔ながらも内容の詰まりすぎていないチェックリストでユーザーに伝えます。以下を含めてください。

  • 変更前後のダウンロードサイズと、変更した各設定(圧縮、ストリッピング、例外、targetFrameRate)の旧値と新しい値。
  • プロジェクトに追加したスクリプト(例:Assets/Editor/WebOptimizer.cs)、変更した品質レベル、またはマシンごとに保存され、チームメンバーや CI には引き継がれない設定(codeOptimization)などの副作用。
  • 再ビルドなしでのブラウザーテストや、Editor を利用できなかった場合のすべての確認など、実施しなかった確認と、置いた前提。

ユーザーに追加の手順や判断が必要な場合は、Addressables のリモートグループに対する CDN のセットアップ、Safari でのテスト、ブラウザーの基準環境が対応した際に Wasm 2023 の機能セットへ移行することなどを挙げます。例:

I made the following changes:

[✓] Set Compression Format to Brotli and Strip Engine Code to on, because the server sends `Content-Encoding: br` over HTTPS.
[✓] Added `Assets/Editor/WebOptimizer.cs`, which applies the release settings from Tools > Apply Web Release Settings.

Follow these steps to finish:

1. Apply `codeOptimization` in your CI build step, because it's stored in `Library/` and doesn't travel with the project.
2. Test the build in Safari, because its garbage collection and JIT behaviour differ from Chrome.

関連項目

このスキルの範囲を超えるタスクについては、以下の Unity ツールを案内します。

  • Addressables パッケージ — ダウンロード予算に合わせてコンテンツを初期ペイロードから移す必要がある場合に、CDN 経由でリモートグループを配信します。
  • ブラウザーに接続した Unity Profiler — クロスプラットフォームのプロファイリング手法です。セクション 3 では、接続方法の Web 固有の部分を説明しています。
  • シェーダーバリアントのストリッピング(Graphics settings → Shader Stripping、ShaderVariantCollection)— バリアント数は Wasm サイズに直接影響するため、ストリッピングだけではサイズが減らなかった場合に確認する価値があります。
  • Project Settings → Player — このスキルが読み取るものと同じフラグを確認できます。インスペクターで見たいユーザーに案内してください。
  • モバイルブラウザーのバッテリー動作にも、セクション 3 と 4 のフレームレートおよび品質レベルに関するガイダンスが適用されます。ここではモバイル専用の手順はありません。

コメント