開発ツール

🛠 CLI リファレンス

対象: ひつまぶし向けのゲームを作る人・AI向けのドキュメント。 概要: 同梱CLI(init / dev / verify)のリファレンスです。コマンドの使い方を 扱います。検査結果の読み方や「何がどこまで確かめられるか」は 検証 にあります。


CLI

このパッケージには、ゲームリポジトリ向けのCLI(hitsumabushi)が同梱されています。

npm install @milightpartner/hitsumabushi-sdk

ゲームの置き場所(games/<gameId>/)の規約は ゲームマニフェスト仕様書 にあります。

npx hitsumabushi init

ゲームリポジトリ一式を作ります。空のディレクトリで実行してください。

mkdir my-game && cd my-game
npx -p @milightpartner/hitsumabushi-sdk hitsumabushi init
npm install

この時点で npm test と npm run verify が通ります。

SDKが既に入っているリポジトリでは npx hitsumabushi init で呼べます。

npx hitsumabushi init --game my-game --template turn-based
オプションデフォルト説明
--game <id>ディレクトリ名から生成ゲームID(URLセーフな小文字スラッグ)。ディレクトリ名がそのまま使えない場合は落ちます
--template <name>minimalminimal / turn-based / realtime / board(N×Nグリッド盤面)
--forceオフ既存ファイルを上書きする

生成されるもの:

├── games/<gameId>/
│   ├── index.html      ← テンプレートから生成
│   ├── manifest.json   ← gameId・人数・結果の型
│   ├── guide.md        ← 解説記事(ルール。必須)
│   └── game.test.js    ← 後述
├── package.json        ← scripts(dev / verify / test)と依存を追記
├── .gitignore
├── README.md
└── .claude/skills/hitsumabushi-game-developer/   ← AI開発Skill

既にあるファイルは上書きしません(--force で上書き)。package.json だけは既存を壊さないよう、足りないキーだけを追記します(設定済みの scripts.test などは残ります)。

同梱される games/<gameId>/game.test.js が何を守るかは 検証 — 何がどこまで確かめられるか にあります。

テンプレートは最小のAPIしか使いません

SDKの公開概念は約30個ありますが、ゲームが動くのに要るのは4個だけです。

層内容テンプレート
1. これだけで動くinit / sendGameData / sendGameOver / isSpectator使う
2. 対戦体験を良くするphase / onError / onObsModeChangeコメントで存在を示す
3. CPU・途中参加に対応するならsendGameDataAs / setMatchState / onMatchState書かない(board だけは setMatchState / onMatchState を使う)

第3層を最初から書き込むと、ゲームのルールと無関係なコードを「意味があるはず」と解釈して引きずることになります。必要になった時点で API リファレンス から足してください。

例外は board テンプレートです。盤面は試合中に必ず積み上がる状態なので、setMatchState が無いと途中入室した観戦者や再接続したプレイヤーには次の着手まで空の盤面が表示されます。「必要になった時点」が最初から来ているので、雛形に入れてあります。

npx hitsumabushi dev

OmoshiroGamePortal本体(Vite + おひつサーバー)を起動せずに、ローカルで多人数対戦フロー(INIT_GAME受信〜sendGameData往復〜sendGameOver)を検証できる、サーバー不要の軽量な開発ハーネスです。

npx hitsumabushi dev
# ビルド済みゲームが別ディレクトリにある場合
npx hitsumabushi dev --dir dist
# エントリが index.html でない場合・1ディレクトリに複数ゲームがある場合
npx hitsumabushi dev --dir public --entry games/my-game/index.html
# ポートを固定したい場合(未指定時はOSが空きポートを自動割り当て)
npx hitsumabushi dev --port 4000
# スマートフォン実機から開く場合(同じWi-Fiから見えるようにする)
npx hitsumabushi dev --host
オプションデフォルト説明
--dir <path>カレントディレクトリ配信するディレクトリ(リポジトリのルート)
--game <id>ゲームが1個ならそれ起動するゲーム(gameId またはディレクトリ名)。複数あって指定が無い場合は、一覧を出したうえで起動し、ブラウザ上のEntry欄で選べます
--entry <path>games/<gameId>/index.html を自動で決定games/ レイアウトでないディレクトリを直接指す場合のエントリHTML(--dir からの相対パス)。manifest.json はこのエントリと同じディレクトリから読まれる
--port <n>OSが自動割り当て待ち受けポート
--hostオフ(127.0.0.1 のみ)LANからの接続を受け付け(0.0.0.0 にバインド)、実機で開くためのURLを表示する。後述

URL はルートを開いても構いません

CLIが表示するURLには、解決済みのエントリがクエリで付いています。

Hitsumabushi dev harness running at http://localhost:4000/?entry=games%2Fmy-game%2Findex.html

クエリの無い http://localhost:4000/ を開いた場合も、サーバーが同じURLへリダイレクトします。 VS Code のポート転送通知「Open in Browser」、ブックマーク、履歴からはクエリの無いルートが開かれるため、そのままでは Entry が既定値 index.html のままになり、games/ レイアウトにはそれが無いので起動に失敗していました。

複数ゲームがあって --game の指定が無い場合は、開くべきものが決まらないのでリダイレクトしません。ブラウザ上の Entry 欄で選んでください。

スマートフォン実機から開く(--host)

既定ではループバック(127.0.0.1)にしかバインドしないため、同じWi-Fiにいるスマートフォンからは開けません。--host を付けると 0.0.0.0 にバインドし、実機で開くURLを表示します。

npx hitsumabushi dev --host
Hitsumabushi dev harness running at http://localhost:4000/?entry=...
  Network: http://192.168.1.23:4000/?entry=...   ← これをスマホで開く

LAN側のIPv4アドレスが複数あれば全部出ます。見つからない場合はその旨を表示します。

⚠️ 既定をループバックのままにしているのは意図的です。 ハーネスは --dir 配下をそのまま公開する開発用サーバーなので、同じネットワークにいる誰からでも読める状態を既定にはしません。実機で確認するときだけ付けてください。

実機でしか確認できない項目は 検証ガイド §5 にあります。

プレビューは本番相当の解像度で表示されます

各iframeには本番相当の論理サイズ(ゲームから見える解像度)を与え、画面に収まるよう見た目だけを縮小して並べます。Viewport で切り替えられます。

プリセット論理サイズ対応する本番の条件
デスクトップ(既定)1400×960PC。calc(100dvh - 120px)・最大幅1400pxのコンテナ
モバイル390×786スマートフォン縦持ち。再生中は calc(100dvh - 58px)
OBS配信1920×1080OBSブラウザソースの標準サイズ

論理サイズの正本は ポータル制約仕様書 §2 の表です。 上記はそのうち代表的な3つをプリセットにしたもので、機種ごとの実測値と**ポータルが保証する最小論理サイズ(308 × 480)**は仕様書側を参照してください。

  • 切り替えはiframeのリロードを伴わないため、対戦中でもそのまま切り替えられます
  • ラベルに 1400×960 @ 42% のように論理サイズと縮小率が出ます
  • 論理サイズより大きく拡大することはありません(プレイヤーが見ない画面を確認することになるため)
  • 人数が増えた場合は1行に詰め込まず折り返します(1人→1列、2〜4人→2列、5人以上→3列)

起動すると、指定ディレクトリ(デフォルトはカレントディレクトリ)をこのゲームの配信元として静的サーバーを立て、表示されたURLを開くとブラウザ上に操作パネルが表示されます。manifest.json を読み取ってプレイヤー人数(可変人数対応)・チーム戦の有無を判定し、指定した人数分の <iframe> を並べて実際のPortal Hostと同じ INIT_GAME を注入、GAME_DATA_RELAY を相互中継します。観戦者(isSpectator)の追加、OBSモードの切り替え、onStartMatchのリマッチ時再実行の検証(Rematchボタン)にも対応しています。

  • 本番同様、--dir配下のmanifest.jsonをそのまま同一オリジンから配信するため、CORSの問題なく動作します。
  • 指定した配信ディレクトリやエントリHTMLが存在しない場合は、起動せずにエラーになります(以前は起動だけ成功し、ブラウザで原因不明の空画面になっていました)。
  • ハーネスはSDKを配信しません。 ゲームは公開URL(API リファレンス §1)から <script> タグで読み込むため、ハーネス上でも静的ホストへデプロイした本番でも同じ記述がそのまま動きます。以前はハーネス専用パスを配信していましたが、それを参照したままデプロイすると本番で404になりゲームが無反応になるため廃止しました。詳細は Getting Started を参照してください。

バックグラウンドで起動する(AIコーディングエージェント向け)

npx hitsumabushi dev はCtrl+Cで止めるまで動き続けるフォアグラウンドのプロセスです。AIコーディングエージェントから使う場合など、起動後すぐに制御を戻したいときはポートを固定してバックグラウンドで起動してください。ポートを固定すればURLが確定するため、起動出力を待つ必要がありません。

# 起動(ログはファイルへ。URLは http://localhost:4000/ で確定する。
#       エントリのクエリはサーバーが付け直すので、このまま開いてよい)
npx hitsumabushi dev --port 4000 --dir dist > /tmp/hitsumabushi-dev.log 2>&1 &

# 停止
kill %1
# ジョブ番号が分からない場合
pkill -f "hitsumabushi dev --port 4000"
  • 利用しているエージェントにバックグラウンド実行の仕組みがある場合(Claude Codeの run_in_background 等)は、そちらを使う方が確実です。
  • ポートが既に使用中の場合は、その旨のエラーになります(別のハーネスが起動したままかどうかの判断に使えます)。
  • ⚠️ ハーネスの検証結果はブラウザ上にしか出ません。 iframeの操作(Launch・Rematch・OBSモード切替)とイベントログ(通信制約の警告を含む)の確認には人間の目が必要で、CLIから機械可読な結果を取得する手段は現状ありません。

Portalの通信制約の超過を検出します

ハーネスは中継したパケットを計測し、Portalの通信制約(32KB/パケット・60パケット/秒)の超過をイベントログに警告として表示します。「どのプレイヤーが・どちらの制約を・どれだけ超えたか」と、本番でどう扱われるか(サイズ超過は ERROR(PAYLOAD_TOO_LARGE) を返して破棄/レート超過は無言で破棄)を表示します。

⚠️ p1: 直近1000msで103パケット送信(上限60)。本番では43パケットが無言で破棄されます。
  • ハーネスは警告を出すだけで、パケットを破棄しません。 本番と挙動が異なりますが、ハーネス上でゲームが動かなくなって「ハーネスのバグ」と誤解されるより、開発を妨げずに気付けることを優先しています。表示された警告は、本番では実際にパケットが失われることを意味します。
  • 警告は制約ごとに1ウィンドウ1回まで間引かれ、ウィンドウ終了時に超過量のサマリが出ます(毎フレーム送信するゲームでログが埋まらないようにするため)。
  • 制約値はハーネスが独自に持つのではなく、契約モジュール(@milightpartner/hitsumabushi-sdk/limits)から読み込んでいます。

ハーネスで何が確認でき、何が確認できないかは 検証 — 何がどこまで確かめられるか を参照してください。


npx hitsumabushi verify

ゲームがPortalの要件を満たしているかを検査し、終了コードで結果を返します。開発ハーネスの検証はブラウザを開いて人間が目で見る必要がありましたが、こちらはCIやAIエージェントからそのまま使えます。

npx hitsumabushi verify            # ゲームが1個ならそれを、複数なら全部を検査する
npx hitsumabushi verify --game my-game
npx hitsumabushi verify --json     # CIで機械的に読む場合
オプションデフォルト説明
--dir <path>カレントディレクトリリポジトリのルート
--game <id>全ゲーム検査するゲーム(gameId またはディレクトリ名)
--entry <path>自動games/ レイアウトでないディレクトリを直接指す場合のエントリHTML
--jsonオフ結果をJSONで標準出力に出す

結果の読み方(4つのステータス・fail の基準・skip の意味・このツールが扱わないこと)は 検証 — 何がどこまで確かめられるか にあります。

複数ゲームがあるとき、--game を省くと全ゲームを検査します。 CIで1ゲームだけを検査する設定にしておくと、ゲームを1つ足したときに設定の追加を忘れて素通りするためです。

CIから使う

# .github/workflows/verify.yml
name: verify
on: [push, pull_request]
jobs:
  verify:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
      - run: npm ci
      - run: npx hitsumabushi verify

本番で壊れる不適合があれば終了コード1でジョブが落ちます(warn では落ちません)。結果をPRコメント等に加工したい場合は --json を使ってください。レポートは { ok, dir, summary, games: [{ gameId, entry, summary, results }] } の形で、ゲームが1個のときも games は長さ1の配列です(消費側が件数で分岐せずに済むようにしています)。