テーマ
開発・テストガイド
SDK はサーバーなしでのローカル開発から、マルチプレイテスト、パブリッシュまでの一連のワークフローをサポートしています。
ローカル開発(素の vite)
素の vite で 1 player 用の生 debug をする場合:
bash
npm run dev
# http://localhost:5173 を開く素の vite (single-frame) の動作:
- 親 frame として
index.htmlがそのまま出るだけ。 SDK は!isHostedで早期 return し、run()/sync()/init()は何もしない - pure vite の HMR や 1 player view のスタイル調整には十分
複数 player でのマルチプレイシミュレートやサーバー authoritative logic の debug には次節の uzu dev を使う。
uzu dev (harness + in-memory サーバー)
uzu dev は scenario の dev command を子 process で起動しつつ、 別 port で harness page (iframe grid + HUD + inspector) と in-memory GameRoom / SyncRoom / RelayRoom (本番と同一 WebSocket プロトコル) を serve するサブコマンドです。
scenario ディレクトリ配下では以下のいずれかで起動できます:
bash
# scenario ディレクトリ内で
pnpm run harness # 各 scenario の package.json に "harness": "uzu dev" が仕込まれている
# node_modules/.bin 経由で直接
npx uzu devscenario 側は run<S>({ logic, events }) (or sync / init) を書くだけ。 mount コードや import 文は不要です。
動作
- 起動すると 2 つの HTTP server が並走する:
- scenario の vite (or 任意の) dev server —
dev.command(defaultpnpm run dev) を子 process で起動 - CLI harness server — free port で開き、 harness page +
/ws/games/dev/:roomId//ws/sync/:roomId//ws/rooms/:roomIdの WebSocket endpoint を提供
- scenario の vite (or 任意の) dev server —
- 子 iframe には
?server=ws://localhost:<port>&roomId=<key>&seatId=dev_N&seats=<json>&revisionId=devが付き、 SDK は既存 online mode で dev-server に接続します (本番 Cloudflare Worker への接続経路と同じ shape) - manifest で
"admin": true/"spectator": trueを宣言すると、 グリッドに進行管理席 (admin_0) / 観戦席 (spec_0) の iframe が追加されます。 これらはseatsにkind: 'admin' | 'spectator'として載り、 ゲームの player 数には数えません。 scenario 側はsetup()で kind を見て観戦系の view / 権限に振り分けます - GameRoom の roster は dev-server が manifest から組んで注入します (server 権威)。 接続クエリの roster 申告は採用しないため、 リロード前の古い harness タブが reconnect しても roster は汚れません
- virtual server は Node.js 上で走るため、 disconnect / reconnect / message ordering / seq gap リカバリなど dev でしか再現しなかった bug が early に出ます
- 各 iframe の inner viewport 短辺が
devMinIframeShortEdge(default 360 CSS px) を下回らないよう、 親 frame のbodyに CSSzoomを自動で当てる。 5p landscape を mac 標準モニタで開くような狭い viewport でも iframe 内部のwindow.innerWidth/Heightは実機サイズ相当を保つ
プレイヤー / orientation の解決順序
manifest.jsonのcharacters配列長 →playerCountmanifest.jsonのplayerCount/orientation- ハードコード fallback (
playerCount: 2,orientation: 'portrait',devMinIframeShortEdge: 360)
manifest.json の dev フィールド
dev.command と dev.readyPattern は任意フィールド。 詳細は manifest リファレンス 参照。
jsonc
{
"dev": {
"command": "pnpm run dev",
"readyPattern": "Local:\\s+http://[^\\s]+:(\\d+)",
},
}HUD
harness page 左上に浮遊する "UZU" ボタン。 クリックすると State Inspector などのデバッグ機能にアクセスできます。
State Inspector
sync() モードを使用している場合、State Inspector で現在の同期 state を JSON 形式でリアルタイムに確認できます(200ms 自動更新)。
デバッグボタンをクリックし、State Inspector を選択してください。
ビルドとパブリッシュ
ビルド
bash
npm run build # tsc && vite build → dist/ に出力パブリッシュ
uzu publish コマンドでビルドからデプロイまでを一括実行します。
bash
uzu publish # ビルド → ZIP → R2 アップロード → リビジョン登録
uzu publish --skip-build # ビルド済みの場合はスキップ可能publish には認証が必要です。ローカルでは uzu login --env dev で保存した認証情報が使われます。
処理フロー:
manifest.jsonからid,playerCount,outputを読み取りmanifest.jsonのbuildコマンドを実行outputディレクトリを ZIP 化- R2 バケットに ZIP をアップロード
manifest.jsonのserverActionLogicPathの有無でモード判定serverActionLogicPathあり → ServerAction: logic をビルド → R2 + WfP にデプロイserverActionLogicPathなし → SyncState: クライアント zip のみ
- UZU にリビジョン登録
- UZU Studio の URL を出力
CI から publish する (publish token)
ブラウザを開けない CI では、publish token を環境変数で渡します。uzu-cli は UZU_PUBLISH_TOKEN があればそれを短命の ID Token に交換して publish します (認証情報の優先順位は UZU_PUBLISH_TOKEN → uzu login の認証情報)。
bash
uzu token create --env dev --name "github actions" # 平文はこの 1 回だけ表示される
uzu token list --env dev
uzu token revoke <id> --env devyaml
- name: Publish
run: pnpm run publish
env:
UZU_PUBLISH_TOKEN: ${{ secrets.UZU_DEV_PUBLISH_TOKEN }}- token は発行者本人の権限で動きます。発行者が publish できるシナリオだけが対象です。
- 平文は再表示できません。失くしたら revoke して発行し直します。
uzu tokenコマンドはuzu loginの認証情報でしか使えません。UZU_PUBLISH_TOKENからは token を発行・失効できません (漏れたトークンで失効を回避されないため)。- 現状 dev 環境のみ対応です。
デバッグのヒント
state が同期されない場合
- ブラウザの DevTools Console でエラーを確認
- デバッグボタンの State Inspector で state を確認
connection.onPatchFailedコールバックでパッチエラーを検知
ローカルモードで動作するが Dev Harness で動作しない場合
initialState()が全プレイヤーで同じ結果を返すか確認(ランダム値を使う場合はSeededRandomを使用)patchのパスが正しい JSON Pointer 形式か確認(例:/board/0/1)