技術詳細版 / ultracode × Fable 5
AIに塊魂を作らせたら、
実在の東京を呑み込む
ゲームになった
マルチエージェントで設計→実装→レビュー→公開まで。
注目した技術要素を全部出します(削る・飛ばすのは自由)
🟢 この資料もAIと作成技術詳細・全量
これだけのプロンプトで動いた — goal機能
/goal
fableの性能を見るためにブラウザ動作する3Dゲームを作りたい
塊魂のようにオブジェクトを取り込んで大きくなると
シームレスにもう一段階大きい視界と大きさに変えて
取り込むスケールが大きくなっても重くならない仕組みに
ultracodeで実行してデプロイまで完了させて
全作業の思考・意思決定・実装方法をログに残して
cloudflare pages で public 公開して
完成するまで頑張って。
トークン上限に行きそうになったら止めて報告して
この1プロンプト(goal機能)から、設計→実装→レビュー→公開まで自走。各バージョンの実プロンプトは右の記事に全文掲載 →
完成物
- ブラウザで動く塊魂風3Dゲーム
- 秋葉原 2cm → 東京 → スカイツリー → 宇宙
- スタック: Three.js r177 + Vite 6 のみ
- 純粋静的・サーバーレス(Cloudflare Pages)
- 外部アセットは東京地図284KBとドナック20KBのみ。残りは全部コード生成
fable-katamari.pages.dev

エンディング:夜の地球に東京の光
何を検証したか(要件)
- ブラウザ3Dの塊魂(取り込んで成長)
- 成長で「一段階大きい視界」へシームレス移行
- スケールが5桁変わっても重くならない
- ultracode(マルチエージェント)で実行
- 全作業の思考・意思決定をログに残す
- 公開 — そしてオーナーの追加注文に5バージョン応える
= Fable 5 が「一貫した品質で複雑なソフトを育て続けられるか」の実験
のべ約150体
のエージェント / 約1,816万(18M)トークン / 5バージョン / 実働約19時間
数字はすべて作業ログの実測値
B. ultracode
AIが自分を多数エージェントに分裂させて開発する。今日の主役
3つの型
型1 設計コンペ
N案を独立に出す→審査AIが採点・統合(judge panel)
型2 並列実装
契約を凍結→5ストリーム並列→統合者が配線
型3 敵対的レビュー ★
指摘→別AIが反論・論破→確定/棄却
道具は Workflow ツール:pipeline / parallel の合成、resumeFromRunId で中断再開
型1 — judge panel(独立提案→審査)
- 🟦 設計A:パフォーマンス最優先
- 🟩 設計B:ゲーム体験最優先
- 🟨 設計C:シンプルさ最優先
- 🟪 審査:採点→最良案ベースに長所を移植
各案は構造化スキーマを強制
schema = {
scaleSystem, physics, rendering,
spawning, fileLayout,
interfaces, risks
}
// 3案を互いに不可視で並列生成
// → 🟪 が採点し統合
🟪 協議ログ(実際の採否)
| 提案 | 主張の核心 | 採否 |
| 🟦性能(9点) | シム単位帯[0.5,2.5] + 1F相似変換 S=0.2、SoA/零アロケーション | ベース採用 |
| 🟩体験(8.5) | シームレス法則:tierIndexは見た目だけ、ゲーム量は半径の連続関数 | 移植 |
| 🟨簡潔(7.5) | 最少パーツ・デバッグ容易性 | 部分採用 |
| — | クラスト焼き込み(重い) | 却下→埋没カリング |
| 3案一致 | 物理エンジン不使用・自作アーケード物理 | 独立に全員一致 |
互いに知らない3体が、物理の結論で一致したのが象徴的
型2 — 契約凍結 + 並列 + 統合
- Phase 0 で全モジュール契約(イベント/型/定数/骨格スタブ)を凍結
- 各ストリームは他人のファイルを触らない=5本を真に並列実装
- 統合者だけが
main.js で配線
// v4: main.js に「形だけ一致する no-opスタブ」を置き
// 置換用の構築式と引数順をコメントで埋め込む
const osmSpawner = NOOP; // ← new OsmSpawner(store, hashes, pools, bus, scaleMgr, world)
// → 統合は「構築式の差し替え」だけ。呼び出し側の書換ゼロ
型3 — 敵対的レビュー ★ 今日いちばんの推し
for finding in review_findings:
skeptic = spawn_independent_agent()
verdict = skeptic.try_to_refute(finding)
# コードを読み、到達可能性・数値根拠・仕様適合を検査
if verdict == REFUTED:
reject(finding) # 偽陽性として棄却
else:
confirm(finding); fixer.queue(finding)
レビューの指摘をそのまま信じない。別AIがわざと反証を試みる
敵対的レビューの実例(v1)
🟥 指摘:「?r= デバッグ起動でフレーム1の大量吸収が起きる」
🟧 反証:「症状は実在。だがスポーン内容は tierIndexと_scaleExp依存で、ballRadiusSim非依存。提案修正は同じ結果=無効。むしろ prewarm 閾値を踏む分わずかに悪化」 → 棄却
v1:指摘の36%を偽陽性として棄却(9/25)。確定21件中16件を修正
中断からの再開 — resumeFromRunId
- セッショントークン上限が v3で1回・v4で3回発生
- 回復後
resumeFromRunId でキャッシュ温存して再開
- 例:v3レビューはフィクサー/バリデータのみ再実行(設計・敵対検証は再利用)
- 毎回 二重実行ゼロで完走
長時間・大規模ワークフローが途中で死んでも回復できる
C. シームレスな無限スケール
塊魂の真骨頂を、技術でどう繋ぐか
課題
2cm 〜 数百m / 月 を、
5桁のスケール差で60fps、しかも継ぎ目なく
- 素朴にやると:座標が巨大化して float32 精度が崩壊(ジッタ)
- ティア境界で見た目がポップ/ヒッチする
- オブジェクト数が増えて重くなる
核心 — 相似変換リスケール
// シムは常にボール半径 [0.5, 2.5] の狭帯で回す
on TIER_UP:
for e in all_sim_entities: // 球・物体・原点・粒子…
e.position *= S // S = 0.2
e.radiusSim *= S
worldScale /= S // 累積スケールを逆向きに
// 実寸 trueRadius は double で別管理 → この操作で不変
1フレームで世界全体を一様縮小。シムの数値は常に「ちょうど良い大きさ」
なぜ継ぎ目が見えないか
- カメラ位置・注視点・フォグは radiusSim の純関数
- 全状態を一律 0.2倍 = 相似変換 → 描画結果がピクセル同一
- 実測:KeyR強制リスケールでワールド描画はバイト同一(差分はHUD時計の407pxのみ)
- v5地表の再計算でも 1 ulp(1.7e-16)しかズレない
実寸は double 管理なので、月でも惑星でも float32 精度が保たれる
対の原則 — シームレス法則
吸収判定・カメラ・フォグ・速度は、すべて半径の連続関数。
ティア番号は見た目(スポーン内容・パレット・演出)だけを駆動する。
- ゲーム量がティア境界で不連続にならない → ポップ/ヒッチが構造的に消える
- v5「謎の溝」修正も:地表を 実半径0.6→3mでフェード(連続)→ リスケール不変
自作アーケード物理(依存ゼロ)
- 動体はボール1個だけという割り切り(コア ~314行)
- 衝突候補はティア帯別の空間ハッシュ(フラット型付き配列)でマイクロ秒
- 取り込んだ物はボール子階層に取り付け時1回だけ行列書込、埋没で自動間引き
- ゼロ・パー・フレーム・アロケーション(モジュールレベルのスクラッチ)
物理エンジンを入れない=バンドルも軽い(v1で gzip 154KB)
描画 — InstancedMesh プール + ドローコール台帳
- アーキタイプ×ティアの InstancedMesh プール
- ドローコール上限を台帳で管理(v1=55 → v2=60 → v3以降=72)
- レビュー確定例:生インスタンスが0になった瞬間に
mesh.count を畳む(ティアを跨いで蓄積していた)
- v4 EXTRAは BatchedMesh(1メッシュで複数ジオメトリ)で +draw を抑制
実測:街中 50〜58 / 72、フィナーレ最悪 70 / 72
E. リアル東京(v4)
OpenStreetMap の実データをボクセル化
なぜ Google Maps でなく OpenStreetMap か
- Google Maps Platform ToS は派生データセット化・再配布を禁止
- → OpenStreetMap(ODbL)採用。帰属表示で合法に「実在の東京」
- リリースゲートに ODbL 遵守を組込:アプリ内クレジット / ライセンスリンク / 抽出日時 / 派生DB公開(data/osm-raw + scripts/osm)

OSM由来の実在ビルで埋まった東京
ビルド時パイプライン(決定論的・再実行でバイト同一)
fetch Overpass(UA必須/スロット監視/429リトライ/再開可能)
build dedupe(type,id) → 外環ステッチ → 投影 →
カバレッジ重心クリップ → 除外ゾーン → OBB → 高さ →
ボクセル量子化 → 長屋マージ(14,546) →
クリアランスベイク(13,367 inset/14,319 drop) →
バンド分け → KEEP_K間引き → FKT4 v1 バイナリ
verify 予算/カウント±20%/重複0/POLY u16/バイト同一/
ナビゲビリティ/ランドマーク実距離 → predeployゲート
成果と勘所
284KB に圧縮
- 実在ビル 14,563棟(水平1:5/高さ1:2.5)
- 道路 12,980 / 河川・公園 1,478
- core 105KB + outer 181KB(上限1,536KB)
ナビゲビリティ・ベイク
- 1:5だと実街路がボールより狭い
- 道路回廊に食い込む建物を内側に押す/落とす
- 到達率 r=1で100% / r=3で96.7% をゲートに
ランタイム & リスケール法則の適用
- OsmWorld:シャード fetch + デコード、ティア2デッドラインで手続き生成にフォールバック(ワンウェイ)
- OsmSpawner:共有ObjectStoreに
FLAG_OSM、アドミッション制御で生存数4096を保証
- BatchedMesh プール2本(容量2048/1024、boot時に容量充足アサート)
- 地表Groupの変換は
scale=1/worldScale, pos=-shift の純関数=実座標タイルでもリスケール不変
① 銅像→月 のピボット(v2)
- 当初「民家→街の銅像ゴール」で設計
- 批評AIが15件の重大問題検出(屋内カメラ破綻、ドアのソフトロック…)
- オーナーが実プレイ→「ゴールは月に変更、家の中案は取り下げ」
- 判断:最もリスクの高い地形/壁/段差を丸ごとキャンセル。旧設計の流用部はJSONにサルベージして再投入
② 成長暴走の構造的修正(v3)
- キュレート配置がティア帯ウィンドウ外で吸収判定に不可視→ 東京タワーをすり抜け
- 修正:DYNAMIC RE-BANDING — 昇格時に生存配置の
tierOf を clamp(naturalBand, t-1, t+1) で再スタンプ
- 既存64個/フレームのラウンドロビン内で償却、約370配置すべてに効く
③ 開幕が真っ暗(v4→v5)— 一番の珍事
原因:実在のJR総武線の高架が、実座標でちょうどスタート地点の真上を通り、線路リボンが2cmボールの「天井」になっていた
- 地表の浮かせ量がフォグ下限で半径の90%/道路Yオフセットが半径の3倍も重なる
- 修正:浮き/オフセットを半径10%上限でクランプ+パイプラインで店周辺のリボンをクリップ+verifyに再発ゲート
リアルデータゲームならではのバグ
④ 批評AIが自走して検算した(v4設計)
- 批評エージェントが設計の数字を信じず自分でOverpassカウントクエリを再実行
- 見積もりが実測の1.5倍ズレ(建物58,155棟)と発覚 → 全予算を実測で再導出、ペーシング 2.2x→2.8x
- 実装でもランドマークは手打ちIDでなく名前/タグクエリで解決+実距離アサート
役割を与えると、検証手段を自律的に選ぶ
テスト・検証駆動 — Fableの自走力の源泉 ★
- エージェントの約71% / トークンの約58%が検証・レビューに投下
- 敵対的検証で71件中31件(44%)を偽陽性として棄却(v1 9/30・v2 6/19・v3 16/22)
- ヘッドレス約3,000アサート(最大塊v4 OSM 2,376)+ 実機検証25パス
- KeyR pixel-identity を1 ulpまで /
osm:verify ALL GREEN ゲート(到達率≥95%・バイト同一・予算240KB)
- ビルド緑でも壊れる回帰を自己捕捉:ACCEL_K終端速度デッドキャップ / 開幕不可視 / 成長暴走 / 批評AIのOverpass再実測
「たくさん作れる」より前に「たくさん検証して自分の出力を疑える」。これが精度と自走の背骨
v1 → v5 早見表
| 版 | テーマ | 主な追加 | 規模 |
| v1 | 無限スケール土台 | 相似変換/シームレス法則/自作物理 | 48体/377万 |
| v2 | 月ゴール | BGM/背景/スコア/銅像→月ピボット | 38体/382万 |
| v3 | 箱庭東京 | スマホ最適化/コレクション/ドナック実況 | 40体/607万 |
| v4 | リアル東京 | OSM 14,563棟/モデル品質/3回中断再開 | ~16体/352万 |
| v5 | ポリッシュ | 開幕誘導/スタックチャン/地球エンディング | 6体/98万 |
AIに任せて見えたこと
- AIの指摘は 別のAIに論破させると精度が上がる(偽陽性36%棄却)
- エージェントは役割を与えると自走して検算(Overpassを自分で叩く)
- 契約凍結が並列を可能にする — 統合は構築式の差し替えだけ
- 中断は
resumeFromRunId で回復可能
- そして最後は 人間が遊んでバグを見つけた(自動検証はエラー0で素通り)
まとめ
AIと人が組むと、ここまで作れる
judge panel・契約凍結並列・敵対的検証 + 相似変換リスケール + OSM 284KB。
すべて実コードと実測値に裏打ちされている。
遊ぶ:fable-katamari.pages.dev
ソース(MIT):github.com/aieo-product/fableDemoGame
ありがとうございました 🌏