mcpField
O
optimize-web

optimize-web

github.com/unity-technologies開発60457 回インストール今日更新
リポジトリ

optimize-web について

Unity の Web ビルドサイズとパフォーマンスに関わる設定を監査、調整する開発スキルです。プロジェクトのバージョンに合わせたドキュメントを参照し、基準値と復元ポイントを用意してから範囲を限定して変更します。

主な機能

  1. 01Web Player 設定の監査
  2. 02圧縮とコードストリッピングの調整
  3. 03未使用リソースとシェーダーバリアントの確認
  4. 04デプロイとメモリ設定の確認
  5. 05基準値との比較による変更検証

活用シーン

  1. 01Unity Web ビルドサイズの削減
  2. 02圧縮とコードストリッピング設定の見直し
  3. 03Web ビルドのサーバー要件の確認
  4. 04Web ビルドのメモリ制約の診断

インストール

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

$npx skills add https://github.com/unity-technologies/unity-agent-plugin --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. プロジェクトのコンテキストを確認します。Unity のバージョンは ProjectSettings/ProjectVersion.txt から、必要なパッケージ(com.unity.cloud.ktx、com.unity.addressables、com.unity.web.stripping-tool)のバージョンは Packages/packages-lock.json から取得します。プロジェクトがない場合は、Unity 6000.0 と仮定します。packages-lock.json に記載されていないパッケージは、そのパッケージのドキュメントにある最新バージョンと仮定します。確認できたバージョンはすべてそのまま使用し、実際に不足している値だけを既定値で補います。レポートには仮定した内容をそれぞれ明記して、作業を続けます。ユーザーが何を最適化したいかを示しておらず、参照できるプロジェクトもない場合は、何を改善したいか尋ねます。
  2. トピックの全体マップから、タスクに該当するドキュメントページを読みます。
  3. エディターでの C# 実行の説明に従って script eval をセットアップします。エディターに接続できない場合、または script eval がない場合は、その旨を伝えて手順 5 に進み、その後は手順 9 に進みます。レポートでは、ビルド検証とランタイムチェックを未実施とし、手順 2 のユーザーの依頼とドキュメントに基づいて推奨事項を提示します。
  4. 0. 事前確認と1. 現状の評価を実行します。結果をベースラインとします。
  5. 依頼内容に該当する行を2. 依頼内容の把握から選びます。
  6. 復元ポイントを作成してから、3. Web ビルド最適化ワークフローに記載された変更を適用します。症状が5. トラブルシューティングに該当する場合は、その項目に従います。
  7. 4. 検証を実行し、事前確認のスニペットを再実行して、値をベースラインと比較します。
  8. 最終手順に記載されたチェックを行います。
  9. 最終レポートを提出します。

エディターでの C# 実行

以下の各手順で、プレーヤー設定の読み取りや書き込みを行う際は、Unity CLI を介して起動中のエディター内で実行します。接続を確立する役割は unity-cli スキルが担います。CLI のインストール、接続済みエディターの確認、プロジェクトへの com.unity.pipeline パッケージの追加、エディターが本当に存在しない場合とセーフモードで停止している場合の見分け、エディターのコマンドカタログの確認は、このスキルに従ってください。まずスキルの手順を実行し、ここで内容を再確認しないでください。

次の 2 点は、このスキルでは判断できません。

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

unity command script eval --caller plugin --skill optimize-web --code '<snippet>' を使用して C# を実行します。unity command のタイムアウトは既定で 30 秒です。

script eval に渡す C#

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

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

1 回の呼び出しで、Pre-Flight の全体像を取得できます。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 に保存されます。標準的な Unity の .gitignore ではすべて Library/ が Git の管理対象外となるため、この値はマシンごとに異なり、共有されません。チームメンバーや CI に引き継がれることもありません。結果として、次の 2 点に注意が必要です。API 経由で値を読み戻し、ProjectSettings/ProjectSettings.asset 内では探さないでください。適用に成功していてもそこには存在しないため、見つからなくても失敗ではありません。また、リリースビルドを CI で実行する場合は、リポジトリに値が含まれていると考えず、ビルド手順として CI 上で設定してください。

設定の適用

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

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

using ディレクティブはそのまま残してください。ファイル内では正しい記述です。単発の変更(単一の品質レベルやフレームレートの切り替えなど)には、インラインの script eval ステートメントを使用できます。

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

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

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

  1. 保存します。 UnityEditor.AssetDatabase.SaveAssets() を呼び出します。現在の WebOptimizer.cs は内部で保存しますが、インラインの script 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 公式のウェブ最適化ドキュメントには、推奨されるすべてのリリース設定を一度に適用する単一のエディターメニュースクリプトが用意されています。Assets/Editor/WebOptimizer.cs に配置してください。テンプレートは scripts/WebOptimizer.cs を参照してください。

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

Player Settings の監査

script eval を使用して、以下の値を確認し設定してください。

設定リリース時の推奨値
Compression FormatBrotli(HTTPS ホスティング);HTTP の場合は Gzip
Decompression Fallbackサーバーが正しく設定されている場合は Off
Strip Engine CodeOn
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リリースでは Off、開発ビルドのみ On
Data CachingOn — アセットデータをブラウザーの IndexedDB にキャッシュし、再読み込みを高速化します
Strip Unused Mesh ComponentsOn — 未使用の頂点属性を削除します
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 には Content-Type: application/wasm、.js には application/javascript を設定します。
  • HTTP/2 または HTTP/3 を有効にして、チャンクの取得を並列化します。

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

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

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

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

ビルドサイズを削減するために、次の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 を使用します。
  • script eval で設定します:UnityEngine.QualitySettings.SetQualityLevel(0, true);(0 = Very Low)。
  • ブラウザー内で不要な機能(リアルタイムシャドウ、ポストプロセスエフェクト、多数のパーティクルなど)を無効にする、Web 専用の品質レベルを作成することを検討してください。
Web でのフレームレート
  • script 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 でオフラインエンコードします。実行時にエンコードしないでください
リニアデータ法線マップ、マスク、データテクスチャをエンコードするときは --assign_oetf linear を設定し、誤った sRGB 変換を防ぎます
ミップマップエンコード時にミップを生成します(--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 のフレームレートおよび品質レベルに関するガイダンスが適用されます。ここではモバイル専用の手順はありません。

コメント