もしブラウザで生きた王国を走らせる業界の既定が、しばしば「まず画面をきれいにし、カクついたら影を落とし、遠景を削り、LOD をレンズ前でパチリと差し替え、報道文にモバイル最適化と書く」ことだとしたら、2026年10月18日、Esteban Estrada が codestz.dev に公開した『Invisible Wins: 60 FPS for a Whole Kingdom, Even on a Phone』は、その請求書を公衆の前で書き換えようとしている。作品は Guildhall。WebGL のブラウザタブで動き、目標は率直だ。M1 Pro で六十を保ち、電話でも滑らかに。本稿は完成品を長く試遊していない。以下の場面と数字は、作者の公開実験ノートとデモサイトの資料による。
一万二千ファイルの島は、二千八百十三枚の土地タイルと約三万五十二個の部品になる。家、木、柵、作物、城。その上に日課で動く群衆、波のある海、空、一日を回ってすべての影を引きずる太陽。それは「開けば勝ち」のデモではない。2026年10月12日、作者が意思決定ファイルに書いた一行は、どのフレームレートのスローガンより硬い。Performance must not change what you see——性能は、あなたが見るものを変えてはならない。
本稿を貫くイメージは look sheet であり、「見えない」ことだ。検査ツールの名に聞こえる。制作倫理としては検証可能な約束だ。まず画素レベルで画面を合わせ、それからどの一手が時間を節約したかを語る。節約したものは台帳に残す。変わるのはコスト。レンズの中の王国はバイト一致のまま。

一、既定の論理:最適化は画面を変えること、フレームが足りれば勝ち
業界の既定はきれいであり、だから怠惰でもある。
三次元ウェブがデスクトップから電話へ沈むと、チームは見慣れたメニューを開く。デバイスピクセル比を下げ、影距離を縮め、カスケードを切り、遠いメッシュを粗い殻に替え、「高く見える」ポストを半減する。プレイヤーも同じ語彙を学ぶ——「許容できる」「遠景はぼやけていい」「電話は中設定で十分」。その暗黙の合意が、「見えるダウングレード」を許される業界文法にする。
Guildhall はその文法に収まりにくい。島全体の尺度、太陽と共に回る昼夜の影、群衆の予定、天候とショーのプログラム、しかもブラウザ内で六十フレーム。予算は「王国全体」の体験に向いている。業界の直感はほぼ自動的に「遠景を差し替え、影を粗くし、ズームで LOD を跳ねさせる」へ向かう。
V1 はその穴に落ちた。ズームイン・アウトで世界が目に見えて入れ替わる。物が飛び出し、距離ごとに少し違う見え方。だから最初の性能コミットの前に、作者は規則を釘付けした。その一行は仕事をずっと難しくし、ずっと良くした。変更は見えないときだけ数える。見えないことを証明するには数字と画像が要る。意見ではない——作者自身の意見も含めて。
分岐はここだ。既定は、フレームが足りないときどの見た目を切るかを問う。彼らは、画面上はバイト一致のまま、どの実装をより安くしなければならないか——そして「確実な勝ち」に聞こえるどの案を、測定が退けさせるべきかを問う。
二、脚本を砕く:実験室プロトコル、そして場面より先に機械
性能は主張しやすく、証明しにくい。確実な勝ちに聞こえる案は、しばしばそうではない。作者は経験のリストを持って入った。LOD、キャッシュ影、軽い遠影、遠いクラスタのマクロ殻、群衆を遠影から外す、極小の影投射体のカリング、遠い安い水。どれも本物の技法だ。だがリストは推測のリストにすぎない。勝つもの、ほとんど費用がかからないもの、静かに見え方を変えるものがある。
だから最適化の前に契約と計画を書き、長い測定と実装を大きなモデル Fable 5.1 に計画どおり委ね、何を本線に入れるかは自分が決めた。契約はタスク票より実験室の手順に近い。固定機位:ヒーロー、中景、広角、十九時三十分の灯、忙しい正午の広場、海面低空——四千と一万二千ファイルで各三回、他は動かさない。台帳:変更ごとに姿勢別 before → after を追記;測定ノイズより小さい利得は戻す。阻む不変条件:look sheet(五つのズーム × 複数時刻、前後)、ポップのないズーム掃引、影が古くなったり跳んだりしないこと。コミットごとに技法は一つ、それぞれ数字付き。静かな機械、実機、人間の検査点:ベンチ中は他ブラウザなし;実機電話で確認;途中で本人が台帳と look sheet を見る;最後にコードを書いていないエージェントが全部を再実行。
測定が最初に見つけたのは遅いシェーダではなかった。機械そのものだった。
Mac の GPU タイマは嘘をつく。ANGLE over Metal では `EXT_disjoint_timer_query_webgl2` がコマンドバッファの壁時計時間を読み、二〜三十フレームかかって解決し、それ自体がフレームあたり約一点三ミリ秒を食う。タイマは任意にし、コストは引き算で測る。忙しいタブ一つでフレーム時間が約三倍。「静か」なベンチでは各姿勢が約三十四ミリ秒;作者の Chrome には生きた Guildhall タブが開いたままで、GPU プロセスが CPU の九〜十八パーセント。閉じると同じコミットが九点七 / 十二点二ミリ秒(p50 / p95)。何も退行していない。電話はノートを上回ることすらある。作者の Xiaomi では島が六十超、Mac の方が遅く感じた——エージェントのヘッドレスが GPU を分けていたから。以後すべてのベンチは `ps` で他ブラウザを確認し、台帳に記す。
それが経験がくれる規則だ。場面を最適化する前に、機械を隔離せよ。さもないと最適化しているのはノイズだ。

三、フレーム予算の具体的な刃:インスタンス、影、シェーダ、ワーカ、バイト
フレームがどこへ行くか、作者は重要度の順に開く。各枠が一つの教訓だ。
静的部品はすべて一つの three.js `BatchedMesh` に入る。ジオメトリは一組のバッファを共有し、島は一度の multi-draw。フルフレームは約三十五ドローコール——だから当時 WebGPU へ切り替える価値はまだなかった。ボトルネックはドローコールではない。Metal 上で本当に高いのはインスタンス数であり、三角数ではない。各パス前に three のバッチが全インスタンスを歩き、視錐テストし、描画リストへ入れてアップロードする。約一万八千インスタンスでは、その歩きが請求書だ。作者は自前の `LodBatchedMesh` に替えた。LOD 段は同じバッファに住み、段の間は二回列挙してディザ符号で約二〜二点八 CSS ピクセル帯でクロスフェード;遠いクラスタは一つの殻インスタンスに;カメラとインスタンスが変わらなければ前フレームのリストを再利用。LOD を切る(`?lod=0`)と広角が二十三〜二十五ミリ秒遅くなる。だが差が約一ピクセル以内のところでだけ替え、フェードする。
影は太陽に従い、毎回島を歩き直さなくてよい。カスケードは三つ。近接は約三十メートル幅・約二点三センチメートル毎テクセル、中段百メートル、そして町全体。カメラ静止時は再描画しない。太陽が四分の一度(`SHADOW_TURN = 0.25°`)回るたびに三つとも描き直す。日が走っていると毎秒約三十回のカスケード再描画。台帳は予想外の数を出した。日が走るとヒーロー視点が約三十フレーム毎秒失われる(ノート画像八十五→五十六、電話画像百五→五十八)。粗い回転角なら描画は減るが、影が目に見えて段々跳ぶ。規則はノーだ。第四ラウンドはサイドパスに独自バッファを与え、カスケード再描画のあと静止カメラで約一万八千を再走・再アップロードさせない。第五ラウンドは町カスケードのリストを保持(どの太陽角でも島全体を覆う箱、インスタンス変化まで一度だけ構築)し、約三十二 × 三十二のカリング格子を追加;走査はインスタンス順のまま、リストは同じ順・同じ内容、テストが証明する。日走行の CPU p95(CPU ×4 スロットル)ノート二十二点四→十九点八ミリ秒(第四)、ヒーロー十九点三→十六点二(第五)、電話ヒーロー十八点五→十六点二;第五の日走行行はどれも二点三〜三点四ミリ秒落ちた。できなかったことも正直に書く。太陽が回るフレームでは GPU がなお三カスケードを描き、ノート広角は動かなかった。
ヒッチも予想外だった。二十五ミリ秒超のフレームは、シェーダが初使用でリンクする一点に収束した。ANGLE over Metal では典型プログラムが三十〜五十ミリ秒、重いものは数百。並列コンパイル拡張は Metal 完了前に ready を報告しうる。二秒の猶予を測ってもなお三十五ミリ秒のヒッチ。だから世界が必要とするプログラムはすべて読み込みカバーの下でリンクし、ショー用はピン留め;バッチのウォームアップは実属性付きの一三角形代用品にした。一万二千ファイル島で二十五ミリ秒超のフレームは十→一;reveal 前にコンパイルしたプログラムは四十→三十二。
世界はワーカで建つ。第二ラウンドで生活計画もワーカへ——計画はバイト単位で同じ、テストが証明。最初のフレーム後の最長メインタスク:四千ファイル千九百九十九→三百二十三ミリ秒;一万二千三千七百六十七→四百九十五。残った約二点四秒の停滞は CPU でもシェーダでもなく、ジオメトリをスライスコピー中にバッチが描かれていたこと。前フレームがまだ描いているバッファへの `bufferSubData` ごとに ANGLE/Metal が約百三十メガを丸ごと再コピーした。修正はほとんど退屈だ。ジオメトリが揃うまでバッチを隠し、一度だけアップロード。バッチ構築四点八〜五点一→一点一〜一点四秒;島全体十点五→四点五秒。誰のリストにもなかった。トレースを読み、暇な GPU でなぜ GL 呼び出しが待つのかを問うた結果だ。
転送では Vercel がテキストと JS を圧縮するが `.glb` はそのまま送る。キャラリッグ単独で三点一四メガ。ビルドはライブラリ GLB をすべて gzip し、ページは `DecompressionStream` で解く。判定はファイル名ではなくバイト `1f 8b`。町の初回ロード九点二五→五点二四メガ;GLB 七点八九→四点零二;リッグ三点一四→零点八六;リクエスト四百十二→三百十一。
第二ラウンド末尾の小さな別コミットもそれぞれ計測。昼に消えている灯、共有パレット材質、SMAA と重なるキャンバス MSAA の除去、毎フレームのゴミ削減。上限なし四千ファイル・ヒーロー p50/p95 八点九 / 十一点七→六点三 / 八点一;一万二千ヒーロー九点零 / 十二点四→六点三 / 八点三。フレーム時間はおよそ二十五〜三十五パーセント減。絵は同じ。
第三ラウンドは最初の数秒。以前は町を開くと Studio の下に白い空キャンバスが一瞬;今はインラインのブートカバーが第一フレームから描かれ、世界自身のカバーへフェードする。キャプチャに初描画後の空白フレームはない。生活ワーカは約一秒で計画を始め、バッチ構築中に計画が着地する。コールド、vsync オン、三回の中央値:四千の reveal 四点九→三点七秒;一万二千七点一→五点一秒。reveal の六百ミリ秒はカバー自身のフェード。作者は残した。フェードはその瞬間の一部だから。

四、画質より先にペース、そして正直な否決表
「滑らか」の最後の授業は、どんな画質下げより先にペースがあることだ。六十・四十・三十を跳ねるレートは、安定した三十より悪く感じる。ステージは n 回目の vsync で描き、飛ばした vsync は描かずフックも走らせない;アニメはすべて実経過時間なので三十でも遅くならない。Auto は悪い秒が二連続で下げ、穏やかな八秒のあとでだけ上げ;持ちこたえなければ次の待ちを倍にする。Settings → Motion は Auto、Smooth 30、Max。模擬電話(三九〇×八四四、DPR 三、CPU ×6)で三十三点四 / 四十一点零→十六点七 / 十八点四ミリ秒。百二十ヘルツパネルで安定六十。三十のリズムすら保てないときだけ品質梯子が一段ずつ下がる——`TIERS` は全貌(dprFloor 一点五、shadowMap 二〇四八、lodBias 一、粒子二百五十六)から最低(零点七五 / 一〇二四 / 二点五 / 六十四)。電話は一段下、弱い GPU は二段下から;Auto は二十秒の平静後に全貌へ戻る。作者の M1 では段がフレームをほとんど動かさない——影解像度にかかわらず島は GPU 束縛——だから梯子はペースの後ろに座る。
毎ラウンドの締めは同じ。look sheet:同じ島、同じ凍結時計、正午・十六時三十分・十九時三十分で五ズーム、前後をキャプチャし画素差分。第三ラウンド十五枚すべて一致、平均差零点零零零 / 二百五十五。バイト対バイト。第四・五で唯一の差は、同じビルドの二回キャプチャ間で出没する最近ズームの平たい一片。四十八フレームの動く太陽ストリップもバイト一致。それが閾値だ。絵が動いたら最適化は本線に入らない。
台帳でいちばん好きなのは正直な否定だ。第四ラウンドのリストの「確実な勝ち」の多くは測定が否と言った。一テクセル未満の影投射体カリング——影が効くところに亜テクセルはほとんどなく、二テクセルなら見える影点が消える——作らない;群衆を遠カスケードから外す——もともと投していない、やることなし;島下の水を飛ばす・遠い安い水——二回作って測り、広角もヒーローも不動、本当に遠水を削るなら波を早くフェードする=見た目変更——破棄;軽い遠カスケード軟化、カスケード再描画のフレーム分散、太陽回転時の影再描画削減——コスト同じか見える——作らないか却下。受け入れた一点:一万二千ファイル島を最広角で見るとノート画像ではなお重い。残るレバーはすべて見た目に触れる。意思決定ファイルのメモ。「12k is too big and crazy。」デモ規模の島は滑らかだ。ぼやけた王国を積むより、そう言い切る方を選ぶ。
シリーズの主題はここで明確になる。体験が問題・規則・受け入れを定義し、AI は速く実行する。タイピングのほとんどはモデルがした。作者は契約と計画を書き、長いパスを委任し、何を出すかを決めた。実行が速いのは規則が明確だからだ。経験から来たのは、最初のコミット前に「性能は見えなく」と書いたこと;数字を信じる前に機械を隔離したこと;トレースを読んでバッファコピーが暇な GPU で待つ理由を問うたこと;look sheet がノーと言ったとき自分の案を否決させたこと。
結び:インディとは「見えない」受け入れに支払うこと
この十月十八日のノートを 2026年秋のブラウザゲーム現場に戻すと、まず打撃するのは静かな制作慣性だ。最適化は画面を変えることだと既定し、FPS スローガンが画素証拠より上だと既定し、「動くようになった」で足りると既定し、直したあとの王国が同じかと問う人は少ない。Estrada は別の道を開く。契約は六つの固定姿勢と三回の繰り返しほど素朴でよい。受け入れは平均差零点零零零 / 二百五十五ほど硬くてよい。否決表は「確実な勝ち」を公に釘付けできる。AI は速くてよい。船を出すかは人が決める。
小チームにとってこの材料は特に刺さり、特に有用だ。一万八千インスタンスの BatchedMesh も Fable 5.1 もなくてもよい。「もう十分」リストは必ずある。平均フレームだけ見て静かな機械を見ない最適化。ズームで跳ねる LOD を「プレイヤーは気づかない」と書くこと。FPS のために段々跳ぶ影。何も描かない変種をコンパイルしたウォームアップ。前後同じなのに本線に「勝利」として残した「水節約」。Guildhall の公開作業はコストを泥臭く書く。look sheet は黒くゼロになれる。台帳は一行一技法でよい。高いのはマージ前の人間検査点を払うこと、そして一万二千を最広角で見るとなお狂っていると意思決定ファイルに認めることだ。
実行可能な短い提示。
- 最初の性能コミットの前に拒否権の規則を書け。どの見た目が変形したら最適化は勝ちではないか。「見えない」を意思決定ファイルへ、事後の弁解へではない。
- 固定姿勢・繰り返し・静かな機械・実機——少なくとも一式を落地させよ。ノイズ未満の利得は戻せ。体感で勝利を宣言するな。
- コミットごとに技法は一つ、それぞれ before → after。画面を動かしうるカリングと軟化は、先に look sheet かバイト差分。黒くなってからマージ。
- 画質梯子より先にペース。六十と三十の間でばたつくより安定した三十。梯子は三十自体が保てないときだけ動かし、「確実な勝ち」のどれを否決したか記録せよ。
一万二千ファイル、約三万個、三十五ドロー、差分零点零零零、そして一行——「12k is too big and crazy」。デモがまだ動き、コードと台帳が公開されているあいだに、作り手は監査基準を言い切っている。六十に届くかではなく、六十に届いたあと、あなたが見るものはまだ同じ王国か。

出典と延伸
Esteban Estrada(2026-10-18)Invisible Wins: 60 FPS for a Whole Kingdom, Even on a Phone
Esteban Estrada(2026-10-18)Feet That Don't Skate: Why 'It Looks Right' Is the Hardest Requirement