scenario-unity-web について
Unity 6.3プロジェクトのWeb公開を支援する開発スキルで、ホスト別のビルド、圧縮、メモリ、ページ連携を扱います。実際のホストとブラウザーで、読み込み、容量予算、グラフィックスAPI、画面を検証する手順が特徴です。
主な機能
- 01ホスト別のWebビルド設定
- 02ビルド容量と圧縮ヘッダーの確認
- 03ページとUnity間の連携設定
- 04Chromeでの読み込みとメモリ検証
- 05起動予算と読み込み時間の監査
活用シーン
- 01サイトやポータル向けUnity Webビルドの準備
- 02圧縮やヘッダーによる読み込み問題の調査
- 03ページとゲーム間のメッセージ連携の検証
- 04モバイル起動時のメモリと転送量の測定
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ scenario-labs/ skills --skill scenario-unity-webインストール後、Claude Code で/scenario-unity-webを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/critique.mdexpert-notes.mdgui-paths.mdprocedures.mdsources.mdscripts/ut_web.pyscripts/AgentKit/Web/WebJobs.csscripts/AgentKitOptional/Addressables/WebAddressablesJobs.csscripts/AgentKitOptional/Tests/AgentWeb.EditorTests.asmdefWebReleasePolicyTests.csscripts/WebRuntime/Optional/Addressables/WebDeferredAddressable.csscripts/WebRuntime/Plugins/WebGL/AgentWebBridge.jslibscripts/WebRuntime/Scripts/WebBridge.csWebErrorReporter.csWebLeaderboard.csscripts/WebRuntime/WebGLTemplates/AgentWeb/index.html詳細
Unity Web(ウェブの専門家)
Web のエキスパートレベルでは、プレイヤーが実際にゲームを入手する環境でビルドを評価します。ゲームプレイが始まるまでのバイト数、適切なヘッダーを付けて実際のホストから配信されること、どのグラフィックス API が実行されたか、ヒープがどれだけ増加したかを報告する実際のブラウザーで読み込まれること、そしてページとゲームが通信できることが評価対象です。基本方針は、圧縮方式はホストが選択し、予算は最初にプレイ可能になる時点までを測定し、配信されたビルドがエラーゼロでヘッドレス起動し、実際に確認したスクリーンショットが得られるまでは何も達成したとみなさないことです。ターゲット:Unity 6000.3.21f1、URP 17.3、macOS 上の Chrome ヘッドレスです。ここで名前が挙がっている兄弟スキルが利用可能なスキルにない場合は、ユーザーにインストールを依頼してください(npx skills add scenario-labs/skills --skill <name>)。無人で進める場合は、ツールスキーマに基づいて作業を続け、欠落している点を明記してください。
必須の背景知識: scenario-unity-expert(チャネル、レビューループ、6.3 の落とし穴)。ツールキット:
ut_env、ut_run(build(P, "web")、run_tests を含む)、ut_review、およびこのスキルの
scripts/ut_web.py、
scripts/AgentKit/Web/WebJobs.cs、
scripts/WebRuntime/(ブリッジ、.jslib、エラーレポーター、テンプレート)。
スタンス(専門家の見解)
- 圧縮方法を決めるのはホストです。 独自の HTTPS サーバーまたは CDN では、Brotli を使用し、フォールバックを無効にして、ファイルごとに
Content-Encodingを設定し、すべての.wasm*にapplication/wasmを設定します(6.3 Manual)。平文の HTTP では gzip を使用します(LAN アドレスでは Chrome が Brotli を拒否し、ERR_CONTENT_DECODING_FAILEDになったことを確認済みです。localhostは例外です)。itch.io では Decompression Fallback を有効にします(Max O'Didily 8iApGVX--B0 [00:01:40])。Poki では無効にします。 - ゲームプレイ開始までのバイト数を予算化します。 CrazyGames は最初の
gameplayStartまでの初回ダウンロードを集計します。モバイルのホームページでは 20 MB、それ以外では 50 MB、ファイル数は 1,500 個です。遅延コンテンツはその時点以降にリクエストする必要があります(ネットワークログで確認できます)。プリロードタグは、最初にプレイ可能になる時点で必要なバンドルにのみ使用します。これにより、そのバイト数が集計対象の時間枠に含まれます(開始前に +0.84 MB 増加したことを確認済みです)。 - 指標は読み込み時間です。ブロードバンド以上では、バイナリと CPU が支配的になります。 読み込み時間が 25%短縮すると、セッション数は 50%増加しました(Craven、LlE35onVdmQ [00:08:40])。86 Mbps を超えると効果は頭打ちになります [00:11:26]。CPU のスロットリングとレイテンシを使って測定します。ホスティングのカバレッジは読み込み時間です(Loveridge、FYsVftoLBP8 [00:16:12])。待ち時間も設計しましょう。何もないプログレスバーではなく、操作方法のテキストを添えたローディングカードを表示し(Craven [00:14:16])、その後、音声のロックも解除するタップ操作でプレイを開始します。
- スレッドは 1 つ、ヒープは 1 つ、ブラウザーのクロックを使います。 ThreadPool API はすべて、復旧不能なハングを引き起こします。
Awaitable、コルーチン、UnityWebRequestを使用してください(Task.Run(...).Resultでタブがフリーズしたことを確認済みです)。ヒープは Initial Memory Size から拡張され、拡張時にスマートフォンでクラッシュすることがあります。計測したセッションに基づいて Initial の値を決めます(32 MB から 68~74 MB に増えたことを確認済みのため、80 に設定し、拡張なし)。targetFrameRateは -1 のままにします。Unity はリフレッシュレートを取得できません(6.3 Manual)。 - WebGL 2 を出荷し、WebGPU はコンピュート用途とし、暗黙のフォールバックに備えます。 6.3~6.5 では実験的機能、6.6 以降ではサポートされていますが、オプトインが必要です。WebGL 2 をその下に残し、
SystemInfo.graphicsDeviceTypeをログに記録してください(エラーなしで WebGL 2 が使われた平文 HTTP ページを確認済みです)。WebGL 2 ではスキニングを CPU で処理します(キャラクター 30 体で、WebGPU の 30 fps に対して 7 fps。Duncan 3bu4WZUCGYc [~00:15:13])。また、非方向性ライトマップのみを使用できます。 - ページとゲームの間で共有できる取り決めは限られています。
.jslibは ES5 で記述し、文字列はヒープポインターとして扱い、返信はmakeDynCallから静的な[MonoPInvokeCallback]に渡し、SendMessageでは正確な名前のオブジェクトに JSON 文字列を 1 つ送信します。Unity はデフォルトでページ全体のキーボード入力を取得します。ページ上の名前入力欄に何も入力できなかったため、WebGLInput.captureAllKeyboardInput = falseにしました(確認済み)。システムフォントはありません。CJK とギリシャ語の名前が表示されず、Font.HasCharacterは文字が存在すると返しました(確認済み)。ポータルはindex.htmlを無視または書き換えるため、ブリッジは.jslibに置きます。 - 設定した内容と、実際に出荷される内容は異なります。 Strip Engine Code は、バンドルで使用されるクラスのみを残します(
Could not produce class with ID 182が発生したことを確認済みです。対処法は link.xml)。Code Optimization とテクスチャのサブターゲットはLibrary/に保存されます。新しいクローンでは Shorter Build Time と表示されます(確認済み)。Safari は iframe 内で IndexedDB を使用できません(6.3 Manual)。そのため、itch.io の Safari ユーザーはすべてのコンテンツを再読み込みすることがあります。 - ライブサービスとして出荷し、バイト数に見合わないものは削除します。 ハッシュ付きの名前を使い、前のビルドを保持し、段階的ロールアウトを 5%で実施し(Loveridge [frame 00:23:29])、リリースごとにシンボルとエラー収集ツールを用意します。「ゲームの視覚的な忠実度を 1~2%しか向上させないのなら……削除すべきです」[00:11:15]。このケースでは URP のポスト処理データに 1.61 MB かかりました。
最初に確認すること
ホストまたはポータル(圧縮、フォールバック、ページの所有者、iframe)はすべて確認します。対象ユーザーと対応ブラウザーの下限(WebAssembly 2023にはSafari 16.4以上、Chrome 91以上、Firefox 89以上が必要ですが、UnityはiOS Safari 15に対応しています。CrazyGamesではデフォルトでiOS上のUnityが無効になります)。ゲームプレイ開始までのバイト数と、明示した回線速度および地域での所要秒数の予算。2Dまたは3D、URP、ライトマップ、スキニングされた群衆。必要な計算能力(WebGPU)。ページ API とページ上のテキストフィールド。スクリプトでプレイヤーが使用できるテキスト(フォント)。デスクトップとモバイル(DXT/ASTCデータの両方)。オーディオ(最初のタップ時)。Unity のバージョン。デフォルト:WebGL 2 のみ。独自の HTTPS + Brotli。ポータルのモバイルでは20 MB、それ以外では30 MB(Loveridge [00:03:29])。Explicitly Thrown。WebAssembly 2023を有効化。反復作業中は Disk Size、リリース時は LTO を使用した Disk Size。Maximum Memory は2048 MB、Initial は測定値に基づいて設定。スマートフォンでは DPR 1。targetFrameRate は -1。
ワークフロー
- 事前確認と監査。
ReadSettings、AuditWeb(シーン、ライティング、スキニング、ストリッピング、スプラッシュ、ポストデータ、インポート)、ut_web.scan_hang_apis(ハング、targetFrameRate)、scan_jslib、package_report。ゲート:監査エラーがゼロ。有効なシーンリストが空でないこと(Cam Ayres bF_eUuxGEcA [00:04:02])。コストのかかるパッケージにはすべて正当な理由があること。 - ホストごとの設定。 プリセット(
own-https、plain-http、itch、poki、crazygames、dev)を指定してWebJobs.ApplySettingsを実行し、必ずcode_optimizationとtexture_subtargetを渡します。build_target="WebGL"を指定して起動します。CIではwrite_policyとWebReleasePolicyTests(EditMode)で保護します。ゲート:設定の読み戻しと8つのポリシーテストが成功すること。 - 相互運用。
ut_web.install_runtime(P)を実行します。WebBridge、WebLeaderboard、WebErrorReporterを接続します(完全なコードは手順 P3)。ゲート:コンパイルエラーがゼロ、スキャン結果に問題がないこと、ブリッジオブジェクトの名前がページからの呼び出しと一致していること。 - ビルド。
ut_run.build(P, "web", out=...)を実行します。バンドルの場合:最初にWriteBundleLinkXmlを実行します。ゲート:Succeeded、ファイル一式が設定と一致、size_reportを記録、build_log_reportを確認(そこで順位付けし、ディスク上のバイト数で判断)。 - 配信とヘッダーの監査。 ローカルで
serveとheader_auditを実行し、その後、実際のホストでも実行します。ゲート:エラーがゼロ、送信されたバイト数がディスク上のバイト数と一致すること。 - Chromeで読み込み。 ページのモックを使って
browser_check(..., metrics_seconds=8, reload=True)を実行します。ゲート:ready、gameplay_start、機能イベントが発生すること。バナーがゼロ、予期しないコンソールエラーがゼロであること。意図したready.api。開始後に遅延リクエストが発生すること。モバイル設定でヒープが増加しないこと。FPSが安定していること。ウォームリロードで.data本文が再取得されないこと(304は許容)。スクリーンショットが開くこと。 - 予算と読み込み時間。
budget_checkを実行します。帯域制限付き読み込み(20 Mbps、40 ms、CPU x4)と、遠隔地域向けの250 msの実行を行います。ゲート:十分な余裕をもって合格すること。 - バリエーション。 itch(フォールバック、zip、iframe ホスト)、ポータル SDK、安全でないオリジンおよび安全なオリジンでの WebGPU、DXT/ASTCの両方(
merge_texture_variants)、スマートフォンのエミュレーション(DPR上限)。各バリエーションで、手順5~7のゲートを満たすこと。 - リリース。 LTO を使用した Disk Size、シンボルをアーカイブ、
AGENTWEB_ERROR_URLまたはWebErrorReporter.endpointを設定、前回のビルドを保持、ロールアウト計画(P12)。Verified と Assumed を記載した引き継ぎ資料を作成します。
数値
| 値 | 対象 | 出典 |
|---|---|---|
| 20 / 50 MB、1,500 ファイル | CrazyGames の初回ダウンロードから最初の gameplayStart まで(モバイルのホームページ/一般) | CrazyGames |
| 30 MB | スタジオのバイナリルール(「最低限必要な基準」) | Loveridge [00:03:29] |
| +3.6 / +1 / +0.7 MB | URP、URP のポストプロセッシング、TextMeshPro のリソース | CrazyGames tests |
| 9.47 MB、8.1 s | リリースデモビルド(LTO):初回ダウンロード、20 Mbps、40 ms、CPU x4 での gameplay_start までの時間 | 観測値 |
| +0.83 s | レイテンシが 40 ms ではなく 250 ms の場合の同じ読み込み | 観測値 |
| -1.61 MB | URP レンダラーのポストデータをオフ(10.08 MB から 8.47 MB) | 観測値 |
| 32 から 68-74 MB | 起動時のデフォルトの Initial Memory Size からのヒープ増加。80 MB に設定した場合は増加なし | 観測値 |
| 2048 MB | Maximum Memory Size。Chrome/Firefox 119 以前では、この値を超えるとバグが発生 | 6.3 Manual |
| 7 から 30 fps | スキニングされたキャラクター 30 体、WebGL(CPU スキニング)と WebGPU の比較 | Duncan [~00:15:13] |
| 48 / 86 Mbps | モバイル/ブロードバンドの中央値。これを超えると効果が頭打ちになる速度 | Craven [00:10:53] |
測定値の詳細:references/expert-notes.md(Numbers、全項目)。
品質ゲート
- 測定可能性: 読み戻しテストとポリシーテストが合格し、監査とスキャンに問題がなく、
BuildReportが Succeeded であること。 実際のホストでheader_auditのエラーが 0 件であること。意図した API でbrowser_checkが ok であること。開始後に遅延実行されること。ヒープが一定であること。エラーがコレクターに届くこと。budget_checkが合格し、スロットリングされた読み込みが予算内であること。 - 視覚品質: キャンバスのスクリーンショットを開き、シーンがレンダリングされていること。900x500、DPR 1、および幅 390 px の縦向きキャンバスで UI が判読できること。プレイヤーが入力できるすべてのスクリプトの行、読み込みカード、バナーが読みやすいこと。
よくある間違い
| 間違い | 発生する症状 | 修正 |
|---|---|---|
| 圧縮ビルドに簡易ローカルサーバーを使う | SyntaxError、「Unable to parse ...framework.js.br」 | ut_web.serve または拡張子ごとの Content-Encoding |
| 通常の HTTP で Brotli を使う | ERR_CONTENT_DECODING_FAILED | HTTPS を使うか、gzip を使い、HTTP 経由のダウンロードを許可します |
Task.Run、HttpClient、スレッド、タイマーを使う | 処理が実行されず、.Result によってタブがフリーズします | Awaitable、コルーチン、UnityWebRequest |
「モバイル向け」に targetFrameRate = 30 を設定する | Unity が 60 Hz を想定して独自のループをタイミング調整します | -1 のままにし、意図的に制限する場合のみ調整します |
| 起動時のメモリを少なく設定し、スマートフォンで増加させる | 起動時にヒープが 32 MB から 74 MB になり、連続したメモリブロックがないとクラッシュします | Initial を実測したピーク値に設定します(heap_advice) |
| ストリッピングを強く設定し、バンドルを使う | Could not produce class with ID が表示され、コンポーネントが見つかりません | WriteBundleLinkXml を使い、再ビルドします |
| CI で Release 設定が使われていると想定する | 新しいクローンでは「Shorter Build Time」とデフォルトのテクスチャ形式が読み込まれます | すべてのジョブで両方を設定するか、Build Profile をコミットします |
| キャンバスの隣にページの入力欄がある | キー入力が取り込まれません | WebGLInput.captureAllKeyboardInput = false(SetKeyboardCapture) |
| どのスクリプトでもプレイヤー名を表示し、組み込みフォントを使う | グリフが空白になりますが、Font.HasCharacter は引き続き true を返します | 代替フォントを同梱するか、名前を HTML で描画し、各スクリプトのスクリーンショットを撮ります |
| Graphics API の一覧やバージョンに関する通説を信頼する | WebGPU ビルドが WebGL 2 で実行される、「WebGPU は 6.3 で本番対応済み」といった事態が起こります | オリジンごとに API をログに記録します。6.3 から 6.5 は実験的機能、6.6 はオプトインです |
.jslib で {{{ }}} または ES6 を使う | ビルドに失敗します | ES5 を使い、コメント内でマクロを使わないようにします(scan_jslib) |
ポータル向けの index.html にページのロジックを記述する | CrazyGames では表示されず、Poki では書き換えられます | .jslib またはポータルの SDK を使います |
| テンプレートのデフォルト設定をそのままリリースする | Shorter Build Time、Minimal ストリッピング、WASM 2023 がオフの場合、WASM が未圧縮で 46 MB になります | リリース用のプリセットを使います |
引き継ぎ
- 受け取るもの:scenario-unity-architecture からハングを引き起こす API を含まないコード(スキャンで見つかった問題は差し戻します); scenario-unity-pipeline-automation から Addressables のレイアウト、CI、Build Profile(このスキルはポリシーテスト、LZ4、遅延読み込み、link.xml を提供します);scenario-unity-mobile から ASTC と DXT、タッチ操作、安全領域;scenario-unity-ui から 900x500、DPR 1、縦向きでも判読できるキャンバス、プレイヤーのテキスト用の代替フォント;scenario-unity-rendering-lighting から Web URP ティア(カスケード 1〜2 個、ポストプロセスは軽量またはなし、非方向性ライトマップまたはリアルタイム);scenario-unity-shaders および scenario-unity-vfx から WebGPU 対応のコンピュートと WebGL 2 のフォールバック;scenario-unity-performance からフレームとメモリの予算。
- 引き渡すもの:scenario-unity-expert とユーザーに、ホストごとのビルドフォルダー、ヘッダーテーブルまたはサーバー設定、
size_report、budget_check、browser_checkの証拠(API、イベント、開始前のバイト数、ヒープ、fps、スクリーンショット)、ポリシーファイル、zip、シンボル、Verified と Assumed の一覧を渡します。
Unity 6.3 に関する注意事項
- メニュー上の表記は「Web」ですが、コードでは
BuildTarget.WebGL、PlayerSettings.WebGL、UNITY_WEBGL、Assets/WebGLTemplatesを使います。6.5 より前は、Build Profile を作成するパブリック API はありません。WebGLInputはUnityEngine.WebGLModuleにあり、Web プレイヤービルドでのみ使用できます。UNITY_WEBGL && !UNITY_EDITORでガードしてください。 - URP テンプレートには Brotli と Shorter Build Time が含まれ、WebAssembly 2023 はオフ、ストリッピングは Minimal です(確認済み)。
WebAssembly 2023 は 6.5 でデフォルトになります(Emscripten 4.0.19。6.3 では
3.1.39-gitと表示されます)。 - WebGPU は 6.3 では実験的な機能で、URP のみ対応しています。PSO トレースと Microphone は 6.4 で追加されます。6.6 では対応済みとなり、オプトイン、Device Filter、互換モードが利用できます。
- Build Profile のテクスチャ圧縮設定は Player Settings を上書きします(テクスチャごとの上書きはその両方より優先されます)。また、Code Optimization と同様に、ProjectSettings の外に保存されます。
unityInstance.GetMetricsInfo()(ヒープ、fps、カクついたフレーム)は、Diagnostics Overlay なしでリリースビルドでも動作します(Diagnostics Overlay の JS メモリ読み取り値は Safari と iOS では N/A です)。6.3 では IP 経由で実行中の Web ビルドをプロファイリングできます。Frame Debugger は Web では動作しません。
参考資料
references/procedures.md:完全なコード(ブリッジを含む)、ライブテスト、記録された結果を含む 24 の手順。references/expert-notes.md:タイムスタンプ、詳細な数値、不一致の表を含む、専門家による判断。references/critique.md:自己レビューの評価基準。references/gui-paths.md:ウィンドウとメニューを使った同じ作業。references/sources.md:すべてのソース、認証情報、タイムスタンプ、改訂履歴。scripts/ut_web.py、scripts/AgentKit/Web/WebJobs.cs、scripts/AgentKitOptional/(Addressables ジョブ、EditMode ポリシーテスト)、scripts/WebRuntime/(ブリッジ、エラーレポーター、.jslib、AgentWeb テンプレート)。