uzu_code システム全体像
内部ドキュメント
このドキュメントは内部実装の詳細です。ゲーム開発者向けの情報は docs.code.uzu-app.com を参照してください。
概要
uzu_code は、WebView ベースの UGC ゲームプラットフォームである。 TypeScript で実装された Web ゲームを Flutter の WebView 内で実行し、ホスト (Flutter) とゲーム (JS) の間で双方向通信を行う。
ゲームは Scenario Content Server (Cloudflare Workers + R2) 経由で配信され、 マルチプレイは Cloudflare Workers + Durable Objects による play-server が担い、シナリオの reducer をサーバー側で実行して state を同期する。
アーキテクチャ全体図
┌──────────────────────────────────────────────────────────────┐
│ Emulator アプリ (dart/apps/uzu_code/emulator) │
│ │
│ ┌──────────────────┐ ┌─────────────────────────────────┐ │
│ │ParameterBuilder │ → │ EmulatorScreen (1P〜4P 選択) │ │
│ │ Screen │ │ ┌──────────┐ ┌──────────┐ │ │
│ │(設定入力画面) │ │ │ Player 1 │ │ Player 2 │ │ │
│ └──────────────────┘ │ │(WebView) │ │(WebView) │ │ │
│ ↑ │ └──────────┘ └──────────┘ │ │
│ endpoint / serverUrl │ ┌──────────┐ ┌──────────┐ │ │
│ │ │ Player 3 │ │ Player 4 │ │ │
│ │ │(WebView) │ │(WebView) │ │ │
│ │ └──────────┘ └──────────┘ │ │
│ └─────────────────────────────────┘ │
│ │
│ Desktop: DesktopEmulatorLoader (ZIP DL → gameDir 解決) │
└──────────────────────────────────────────────────────────────┘
│ │
│ GameService │ GamePlayScreen (uzu_code)
│ (HTTP ZIP DL │ ├ LocalServerService (localhost HTTP, dir mode)
│ + 展開・キャッシュ) │ ├ BridgeService (双方向通信)
│ │ └ PlayScreenController (Host ↔ Game)
│ │
↓ │
┌───────────────────────────────────┴──────────────────────────┐
│ Scenario Content Server (uzu-code content-server) │
│ │
│ Cloudflare Workers + R2 │
│ HMAC 署名付きサブドメイン URL でゲーム ZIP/ファイルを配信 │
└──────────────────────────────────────────────────────────────┘
↑
│ uzu publish
┌──────────┴───────────────────────────────────────────────────┐
│ UGC ゲーム (TypeScript + Vite) │
│ │
│ ┌───────────┐ ┌──────────────────────────────────────┐ │
│ │ Reversi │ │ 今後追加されるゲーム ... │ │
│ │ (example) │ │ │ │
│ └───────────┘ └──────────────────────────────────────┘ │
│ │
│ 共通: @uzuhq/code-sdk (javascript/uzu_code/sdk) │
│ CLI: @uzuhq/code-cli (javascript/uzu_code/cli) │
└──────────────────────────────────────────────────────────────┘
│ WebSocket
┌──────────┴────────────────────────────────────────────────────┐
│ Play Server (javascript/uzu_code/play-server/) │
│ │
│ Cloudflare Workers + Durable Objects │
│ └ GameHost: シナリオ logic を facet 実行 (/ws/games/{rev}/{room}) │
└──────────────────────────────────────────────────────────────┘ディレクトリ構成
uzu_code/
├── dart/
│ ├── packages/uzu_code/ # Flutter ライブラリ (ゲーム表示フレームワーク)
│ │ └── lib/
│ │ ├── uzu_code.dart # バレルエクスポート
│ │ ├── play_screen_controller.dart # Host ↔ Game 双方向通信コントローラ
│ │ ├── helpers/ # QueryParamsBuilder 等
│ │ ├── screens/ # GamePlayScreen (WebView, dir/url mode)
│ │ └── services/ # BridgeService, LocalServerService
│ └── apps/uzu_code/emulator/ # Emulator アプリ (マルチプレイヤーテスト用)
│ └── lib/
│ ├── main.dart # エントリーポイント
│ ├── config.dart # EmulatorConfig (起動パラメータ)
│ ├── player.dart # EmulatorPlayer データクラス
│ ├── screens/
│ │ ├── parameter_builder_screen.dart # 設定入力画面
│ │ ├── desktop_emulator_loader.dart # Desktop ZIP DL + 展開ローダー
│ │ └── emulator_screen.dart # マルチプレイヤー画面
│ ├── services/
│ │ └── game_service.dart # HTTP ZIP DL + キャッシュ管理
│ └── utils/ # open_url 等
├── javascript/uzu_code/
│ ├── sdk/ # @uzuhq/code-sdk (ゲーム⇔Flutter 通信 SDK)
│ │ └── src/
│ │ ├── index.ts # メインエントリ (init, run, on, send 等)
│ │ ├── types.ts # 型定義 (GameConfig, SendAction 等)
│ │ ├── reconnectable-ws.ts # ReconnectableWebSocket (自動再接続)
│ │ ├── dev-hooks.ts # window.__uzu_dev (外部 automation)
│ │ └── run/ # run() API 実装 (local, online)
│ ├── engine-core/ # 3 ランタイム共有のエンジン定義 (GameLogic 型 / ゲーム内時計 / json-patch / random)
│ │ # publish せず、SDK / cli / play-server が各自のビルドで取り込む
│ ├── room-core/ # サーバー専用のゲームルーム本体 (GameRoomCore)
│ │ # publish せず、cli の dev-server と play-server の facet が共有する
│ ├── cli/ # @uzuhq/code-cli (ビルド・パブリッシュ CLI / uzu dev)
│ │ └── src/dev-server/ # dev harness の in-memory GameRoom (本番と同一プロトコル)
│ ├── play-server/ # ゲームサーバー (CF Workers + DO)
│ │ └── src/
│ │ ├── index.ts # Worker エントリ (ルーティング)
│ │ ├── game-host.ts # GameHost Durable Object (supervisor)
│ │ └── game-worker-template/ # GameFacet エンジン (engine-core を焼き込んで配布)
│ ├── scenario-content-server/ # ゲームコンテンツ配信 (CF Workers + R2)
│ │ └── src/
│ │ └── index.ts # HMAC 認証 + R2 ZIP 展開配信
│ └── example_scenarios/
│ ├── quick_draw/ # サンプルゲーム (tickRate 0 + deadlines / 乱数)
│ ├── reversi/ # サンプルゲーム (run() API 使用)
│ └── shogi/ # サンプルゲーム (tick / 持ち時間あり)
├── Taskfile.yml # タスクランナー設定
├── docs/ # ドキュメント
└── plans/ # 設計ドキュメントコンポーネント一覧
| コンポーネント | ディレクトリ | 技術スタック | 詳細ドキュメント |
|---|---|---|---|
| Flutter ライブラリ | dart/packages/uzu_code/ | Flutter (Dart 3.11+), webview_flutter | flutter-host.md |
| Emulator アプリ | dart/apps/uzu_code/emulator/ | Flutter, uzu_code, audioplayers | emulator.md |
| Web ゲーム | 外部リポジトリに移行済み (サンプル: example_scenarios/) | TypeScript (strict), Vite | UZU Code docs |
| Flutter ↔ JS ブリッジ | 横断的 | WebView JavaScriptChannel, postMessage | bridge.md |
| PlayScreen SDK | javascript/uzu_code/sdk/ | TypeScript, @uzuhq/code-sdk | play-screen-sdk.md |
| Play Server | javascript/uzu_code/play-server/ | Cloudflare Workers, Durable Objects | play-server |
| PR プレビュー | javascript/uzu_code/cli/ | uzu-cli, R2 ライフサイクル | preview.md |
| Scenario Content Server | javascript/uzu_code/scenario-content-server/ | Cloudflare Workers, R2, HMAC 認証 | — |
データフロー
1. ゲーム開発
外部リポジトリで開発 → npm run build → dist/ にビルド出力
2. パブリッシュ
uzu publish → ビルド → ZIP 作成 → R2 アップロード → gRPC でリビジョン登録
uzu preview → ビルド → ZIP 作成 → R2 アップロード (リビジョン登録なし、14 日で自動削除)
3. Emulator 起動
ParameterBuilderScreen で endpoint / serverUrl を入力
→ Web: EmulatorScreen (gameUrl モード)
→ Desktop: DesktopEmulatorLoader (ZIP DL → gameDir モード)
4. ゲーム表示
GamePlayScreen が WebView でゲームをロード
→ dir モード: LocalServerService でローカル HTTP 配信
→ url モード: Scenario Content Server から直接配信 (iframe)
5. ゲームプレイ中の通信
Flutter → JS: 自分の通話の状態・アプリからサーバーへの伝言 (BridgeService → runJavaScript)
JS → Flutter: 音声再生・マイク操作・観測席が聴く部屋・WebSocket の状態・サーバーからの伝言 (FlutterHost.postMessage)
6. マルチプレイ通信
GamePlayScreen が URL に ?roomId=xxx&server=xxx&seatId=xxx&players=[...] を付与 (players = roster)
→ SDK が パラメータ検出 → uzu-code play-server に WebSocket 接続
→ クライアントは action を送り、サーバーが reducer で実行 → 結果を全員へ broadcast (onState)
→ サーバーは接続と通話の状態・部屋割り (presence) も全員へ配り、アプリが部屋とマイクを合わせるゲームコンテンツ配信
ゲームコンテンツは uzu-code content-server (Cloudflare Workers + R2) 経由で配信される。
- HMAC 署名付きサブドメイン URL で認証 (Firebase Auth 不要)
- R2 バケットから ZIP を取得し、個別ファイルとして配信
- Cache API によるキャッシュ (max-age 86400)
/__zip__エンドポイントで生 ZIP ダウンロード (モバイル向け)
開発コマンド
サーバー起動
bash
task uzu_code:play-server # play-server 起動 (wrangler dev)Emulator 起動
bash
task dev # Emulator 起動 (macOS)
cd dart/apps/uzu_code/emulator && flutter run -d macos # 直接起動検証・解析
bash
cd dart/packages/uzu_code && dart analyze # Flutter 静的解析
cd dart/apps/uzu_code/emulator && dart analyze