# ゲームデータ仕様

任意のcardStates[].variablesは実カード別の変数差分（文字列辞書）です。省略時は従来のcardDefs[].variablesを使い、保存・再読込で個体IDと共に維持します。新しい型付きの所有者部品・変数参照も[個体値と参照](physical-card-values.md)を参照してください。既存ゲームの一括変換は不要です。

チームタブの`kind: "token"`は`tokenAffiliation: "player"`も利用できます。所属チームの参加者だけを各実体タブへ作り、`tokenOwnerId`はそのプレイヤーです。定義の枠番号は全体の参加順を維持し、実行時のID・所属情報はエンジンが設定します。形式20・処理形式4と通常タブの既存挙動を維持します。

`Expr.cardGrid`と`NumericValue.card-grid`は、従来の固定IDに加え`cards: CardSelector`で実カード1枚を参照できます。固定IDとの同時指定は不可です。個人タブの所有者・所在・カード種類を指定し、移動後も個体を追跡します。型・0枚／複数枚の扱い・一時値の参照は[配置枠の値](card-grid-values.md)を参照してください。保存形式のバージョン変更や既存ゲームの自動変換は行いません。

カード定義`items[].cardDefs[].description`は任意の文章です。空・未指定は説明なし、改行保持、表示はプレーンテキスト。カード一覧／JSON／カードCSVのdescription列で編集でき、ゲーム中の「詳細」から閲覧します。表面を見られない相手へ説明は配信しません。旧データの変換は不要です。[部品仕様](component-reference.md#カードの説明とゲーム中の確認)。

操作はフェーズ別ボタンへ統一する。回数は通常の変数・条件で管理し、汎用のセーブポイント・条件／配置検査・操作制限を組み合わせる。旧設定は読込時だけ変換し、進行中の旧部屋は新規開始する。私有記録と秘密情報の参加者別配信を維持する。

準備画面の選択肢付き全体変数`settings.globalVariables[].choices`は[オプション変数の契約](game-options-and-tabs.md)を参照。省略した既存変数は従来動作。

## サムネイル画像

`metadata.thumbnail` は表示用画像です。編集画面の選択時・JSON読込後のサーバー保存時に長辺960px以内（拡大なし）・品質85のJPEGへ変換します。縦横比・全体を維持し、透明部分は白、アニメーションは先頭フレームです。`metadata.thumbnailOriginal` は復元用原画像参照、`metadata.thumbnailEncoding` は変換済みの場合だけ `jpeg-960-q85-v1`。両者省略の旧JSONも有効です。参照の保存・書出・再読込を維持します。原画像はカタログや参加者の定義には公開しません。カード・ピース・ルール画像は対象外。[例](examples/thumbnail-jpeg.json)。

選択肢なしの通知・確認は`notice`処理。`notice.mode`は`notify`／`acknowledge`、`notice.title`は1～1000文字、任意の`notice.buttonLabel`は1～100文字。本文はmessage／messageParts、表示対象はplayerTargetです。既定ボタン文言は閉じる／確認しました。確認要求ID・対象ID・回答マップは実行時の私有継続であり、作者JSONへ保存しません。モードと本文はローカル／サーバーで共通。形式20／4と旧選択ウィンドウ互換を維持します。[処理仕様](action-reference.md#通知確認)。

## タイマーの時間終了時の処理

`kind:"timer", timerMode:"down"`の`actions`は0到達時の通常処理配列です。省略・空なら0で停止するだけ。`timerEndPhaseIds`は対象フェーズID配列（省略・空は全フェーズ、開始は`start`）。終了時と実行直前に判定し、不一致を後から実行しません。カウントアップに終了処理は設定できません。自動処理に「実行者」はいないため、プレイヤー対象を明示し、実行者・選択中カード・旧操作者入力を参照しないでください。共通処理・分岐・明示対象の入力ウィンドウは通常形式で使えます。[サンプル](examples/timer-end.json)。

オンラインの予約・一回性・回答待ちの順序はサーバー管理。停止再開は同じ計測、リセット・終了後の明示開始は新計測。動作中の短縮・直接0設定も終了、停止中の0設定は開始時に判定します。終了済みへの加算だけでは再発火しません。`timerRunId`・`timerCompleted`・`timerCompletionPending`は実行状態であり作者JSONへ生成する必要はありません。形式20／4を維持します。

標準トランプの生成寸法は`item.width:97.7,height:148.3`。表裏の画像クロップは既存`cardTemplate.layers`へ保存する。[正確な初期値例](examples/trump-default-layout.json)。任意カードの寸法・保存済みレイアウトを強制変換する規則ではなく、形式20／4は変更しない。

## 全体文字変数・一括サイコロ

`settings.globalVariables[]`は`{id,name,type?,defaultValue}`。`type:number|text`、省略は数値。文字初期値は10000文字以内で空・日本語・改行を許可する。実行値は数値／文字を維持する。文字は`variable`の`set`のみ、同型を代入し、数値の文字化は一時式の`to-text`で明示する。型不一致を暗黙変換しない。文章・ログ・文字比較は既存の`global-variable`参照を使う。

`dice`の任意`diceTargets:string[]`（重複不可）は複数サイコロID。省略時は旧`source`、一覧があれば一覧優先、空一覧は何もしない。`temporaryBindings.diceTargets`には部品単体／配列式・抽出を使える。各個体の面・重みで独立抽選し、演出ONは一処理全対象同時・待機1回。OFFは即時。既存の公開保護を維持。形式20／4を維持。[機能例](examples/global-text-batch-dice.json)はヨット本体ではない。

ピース配置はActionに任意の`destinationGridRow` / `destinationGridColumn`（0始まり整数・両方省略は自動）、`placementSuccess` / `placementReason` / `placementCount`（既存の真偽値／文字列／数値の単体一時変数ID）を持つ。行列の同名temporaryBindingsへ数値式を指定可能。既存JSONは新項目を付けず従来の自動配置を保つため、形式20／処理形式4を維持し移行処理は不要。成功時だけ指定面・所属・配置を同時更新。一括は部分成功、結果は内部の分割計画を集約する。[引数・JSON断片](action-reference.md#ピースの指定マス配置)。

表示／活性条件はcomparison.leftのcard-countで選択枚数を判定。cards.conditionはselected-by-actorとcard-typeのANDで場所・種類を絞る。card-type.cardSetId必須、cardDefinitionIdsは任意の非空・重複なし配列。本人の選択だけ、山は実枚数。旧条件と形式20／4を維持。[完全例](examples/selected-cards-button.json)。

タブの任意項目`viewpoint`は`{mode:"off"|"player"|"team", players?:方向[], teams?:{チームID:方向}}`。方向は`bottom/right/left/top`、省略はbottom。playersは準備時の座席順で新規公開は最大20、現在の手番順ではない。過去の21人以上の保存済み版は変更せず部屋を作れる。チーム無効時・所属なし・観戦者はbottom。生成タブは定義元を継承する。方式切替でも双方の設定を保持できる。カードの位置・回転値・権限は変わらない。形式20／4の任意拡張で旧データの変換不要。例：`examples/board-viewpoint.json`。

turnも`multipleAllowed:true`を使えます。`markerOwners.turn`は所有者配列で、空は手番なしです（先頭への補完なし）。既存move/give/removeを使用し形式20／4を維持、変換不要です。一時値`game.turn-players`は全所有者のplayer配列、既存`game.turn-player`は先頭1人またはnullです。チーム同時手番はチーム所属プレイヤーを全員選んで付与します。

共通処理呼び出しは `type:"commonCall", commonProcessId:"登録済みID"` を使用します。旧 `source` の重複保存は不要です。参照解決は `commonProcessId ?? source` で、空の専用IDは未設定として拒否します。形式20／4は変更しません。例：`examples/common-call-save.json`。

タブの `hidden` は表示用フラグです。通常の非表示タブを倉庫として処理から参照・検索・移動できます。秘密情報はカード・変数の公開範囲やプレイヤー／チームの閲覧権限で区別します。既存データの変換、形式20／4の変更は不要です。

非表示タブからの予備札移動に専用フィールドは不要です。既存`move`・`cardSelector`・`destinationLocations`を使います。ホルダー移動は実行時`holderId`と`tab`を同時に更新し、作者の部品配置は変更しません。公開検査は選択locationの実候補を対象にします。形式20／4は維持します。例：`examples/hidden-stock-transfer.json`。

一時値の公開範囲は保存前にも検証します。限定公開の値やその値に依存する条件結果を全員公開のログ・変数・共有処理へ渡す明確な矛盾は保存エラー、対象者・カード状態等で変化するものは保存可能な警告です。警告には該当処理へのリンクがあります。実行時の安全チェックは維持し、該当処理・参照元・公開先・停止理由を表示します。秘密の値・回答・カード内容は表示しません。公開が意図された場合に限り、既存の `temporaryPublish:true`（variable/message/logのみ）を編集者が明示します。自動的に公開設定へ変更せず、警告を消すために公開を有効化しないでください。保存形式の項目・版は変わりません。自動送信や専用送信機能はありません。

## 全部品のプレイヤー別展開

全種類のItemに既存の`playerBoxGroupId`（1人目のID）と`playerBoxSlot`（1〜99）を使用できます。キー名と`::player-box::N`のID形式は互換性のため維持します。通常タブで最大人数分を編集し、実行時は参加人数分だけを生成します。1枠目が共通の見た目・初期値・処理の正本です。位置と`playerBoxShowName`は個別に保持し、新規枠は元枠の名前表示設定も継承します。実行時の`playerBoxOwnerId`はエンジンが設定します。値・タイマー状態・カード個体などの実行状態は独立です。プレイヤー／チームタブの自動展開とは重ねません。所属付きトークンの展開とも排他です。

テキストの`textParts`内ではPlayerTarget `{kind:"part-owner"}`がこのテキストの所有者を参照します。閲覧者・実行者・手番とは異なり、所有者不在なら対象なしです。通常タブのプレイヤー別部品とプレイヤータブ内の部品に対応し、チーム所有者を個人へ勝手に置き換えません。形式20／処理形式4を維持します。例：[player-parts.json](examples/player-parts.json)。透明テキストの青い点線は編集補助でありJSONへ保存しません。

一時値の部品属性`property.path:["id"]`は文字型の実行部品IDです。部品名・カード定義IDと混同しないでください。playerのidは既存の参加プレイヤーIDで、選択回答との照合に使います。cardのidは参照できません。[型別の完全表](reference-contract.md)と[選択結果の接続例](examples/player-choice-continuation.json)を参照してください。保存エラーは作者向け診断であり、診断や修復リンクをJSONへ保存しません。


現在の新規形式は `schemaVersion: 20`、`operationSchemaVersion: 4` です。旧形式は順次移行され、既存のActionデータは保持されます。v20では通常の変数変更・繰り返しに一時値を接続し、確認画面と新規server-v1部屋で実行します。オンライン待機中の一時値は作者JSONではなく私有継続へ保存します。

## リザルト設定

編集画面では順位・成績を変数から選ぶ。個人はplayer-variable（players:actor）、協力はglobal-variable、チームはteam-variableまたはチームメンバー合計のplayer-variable（players:all）。順位は数値変数、成績は個人の文字変数も利用可能。variableIdの空文字は未選択として保存を拒否する。既存のNumericValue式は読み込み・再保存で保持し、UIの選び直しでだけ置き換える。計算値は終了前の処理で変数へ反映する。

任意の `settings.result` に mode（individual／team／cooperative）、ranking（value:NumericValue、order:ascending／descending、最大8件）、metrics（id、label、value:NumericValue、unit、最大8件）、successTitle、failureTitle、objectives（id、label、condition:CommonCondition、valueParts?:LogMessagePart[]、最大12件）を保存する。協力のsuccessCondition、補足messagePartsは任意。チーム戦はteams.enabledが必要。順位判定値を自動公開せずmetricsに明示した値だけ成績表示する。全同点は1・1・3位。未設定は空の既定リザルト。v20より前のスキーマにも同じ設定を移行して保持する。例は[リザルトサンプル](examples/result-screen.json)。終局の順序は[公開実装パターン](authoring-patterns.md#タイマー確認終局)を参照。

処理の `gameEnd` は引数なしの終端。以降の処理（呼出元やループも含む）を実行しない。runtime.resultとruntime.terminationは部屋の実行状態であり配布定義へ出力しない。正常終了は閲覧だけの最終盤面とし、手動中断と区別する。

## 処理編集のデータ構造

## 一時変数処理（形式20／処理形式4）


`runtimeTemporary*` は実行時専用の私有継続です。作者JSON・書き出し・サンプルへ入れず、混入した場合は保存を拒否します。登録済みreferenceId・属性・引数パスと型は[完全表](reference-contract.md)に従います。通常処理の引数は任意項目 `temporaryBindings:{"正式引数パス":TemporaryExpression}` から参照します。「任意項目」は未登録パスを許す意味ではありません。既存Expr等の値は保持し、同じ引数のbindingを実行時だけ評価して置換します。操作前の表示条件には、その操作で後から作る一時変数は指定できません。明示公開は `temporaryPublish:true`（variable/message/logだけ）です。noticeには付けません。共通処理は `returnType` と `returnValue` を対で定義し、呼出側commonCallの `temporaryResult` に受取先の一時変数IDを指定します。専用temporaryProgram・一時operation形式は廃止済みです。

処理編集の「このゲームのデータ構造」で、実際の変数・部品・タブ・フェーズ名と型を確認できます。ゲーム直下のプレイヤー[]・チーム[]・タブ[]・部品[]・全体変数[]・人数別変数[]・マーカー[]・フェーズ[]をたどります。設定欄も同じ構造を使い、引数に合わない型、空一覧、未使用のチームは出しません。変数の参照は変数名→値、カード対象は場所→カード[]→条件→並び順→選択数、収納先は場所で終わります。編集時点で未確定の参加者・手札や、ルームの秘密データを取得する機能ではありません。ツリーは表示専用でJSONへ保存せず、既存のPlayerTarget／CardSelector／CardLocation／値参照へ変換します。JSON Schemaの現行形式は20／処理形式4です。


編集・確認画面は2026-10-19に一本化しました。マイゲームの「編集する」と各ボタンの処理編集はメソッド形式、確認・実部屋はスクロール盤面を使います。旧UI用のクエリや処理コード文字列をJSONへ生成しないでください。schemaVersion19／operationSchemaVersion3、既存サンプルとSchemaのデータ形・初期値・実行解釈は変更ありません。


カードレイアウト画面内のサイズ変更も、部品の既存width／height（px）だけへ保存します。cardTemplateやcardDefsにサイズを重複保存しません。編集UIは最小1px・0.1px刻みで、百分率のレイヤー配置と文字サイズを保持します。JSON形式19／処理形式3および従来データの解釈は変更しません。

## 保存エラーの修復リンクとリセット

保存時の未選択検査は、正式な処理配列（actions／initialActions／elseActionsおよび進行イベントのstart／end）と条件式の参照に限定する。カード・サイコロのテンプレートlayersのtype:variableや、盤面部品のkind:box等を処理・値参照として扱わない。表示項目のために架空の処理設定を要求しない。

編集画面の保存エラーには、部品・ボタン・初期処理・フェーズイベント・共通処理の名称を含む「開く」リンクを出す。内部では検査時の構造化パスを現在のゲームに照合して所有者と処理IDを解決し、翻訳済みエラー文を解析して配列位置を推測しない。入れ子の処理も既存ダイアログで選択・表示し、新画面では対象行へフォーカス・スクロールする。通信エラーなど修復先を特定できないものに誤ったリンクを出さない。移動だけでデータを変更しない。sourceが空の変数処理は編集専用の未選択として開き、対象変数を選ぶまでは保存を許可しない。

リセットの新規編集はゲーム全体だけとし、方式・参照元・プレイヤー・対象種類は表示しない。実行前確認は維持する。新規メソッドはリセット（）で、JSONは既存のtype:reset、mode省略またはgameを使う。過去の対象限定リセットを黙って全体リセットへ変更することは危険なため、読み込み・実行互換を残し、「ゲーム全体のリセットに変更」を押した時だけ対象指定を除去する。新規JSONやAI生成で対象限定方式を提案しない。JSON形式19／処理形式3は変更しない。


## 部分設定・文章・処理順の編集

編集中の専用設定（通知・選択表示・入力表示・操作権限・カード文章操作）は必須の兄弟項目が未設定でも処理行を表示する。保存時の検査は維持し、不足項目を行内の未選択から設定できる。通知の表示場所だけは実行器の既定値（画面上部/toast）を使うため、秒数や通知種類のみを確定してもその既定値を補って保存できる。その他の必須項目を推測して保存しない。1行の変換エラーはその行に表示し、他の行や分岐を隠さない。未完成時は保存不可で、戻る・取消・コード確認を維持する。

プレイヤーの条件なしは「全プレイヤー」と表示し、選ぶと並び順へ進む。カード条件の「条件なし」とは区別する。プレイヤー情報の「プレイヤー名（文字）」は既存の player-name 参照であり、内部コードは .名前 とする。変数の .変数.名前 と混同しない。メッセージ・ログの「組み立てる」で文字と変数・参照値を順に追加し、「この文章にする」で一度だけ反映する。途中の閉じるは元の文章を保持する。

処理行の専用ハンドルはPointer Eventsで同じブロック内のドラッグ並び替えを行う。分岐とループは中身ごと動かし、ID・未登録の保持項目を維持する。上下移動と戻る／進むも残す。通常の入力やスクロールはドラッグ開始に使わない。編集画面・設定・処理ダイアログの？から既存の60秒診断を開ける。診断は編集イベントと文字数など数値メタデータだけを記録し、文章・ゲームJSON・名前・認証情報を送らない。送信はユーザー操作のみ。JSON形式19／処理形式3は変更しない。


## 自明な選択の省略・条件追加・処理行操作

一つに決まる対象（実行者・表示者・ボタン所有者・ループ中・単独ターン指定（複数不可または順番基準）・単独所持マーカー）は選んだ時点で確定し、並び順・選択数・追加の確定を省略する。ANDで単一対象を絞る場合も一件以下だが、ORで別候補を加えると複数になる。最大／最小は同点があり得るため単一扱いしない。引数だけが一件限定なら並び順を残して選択数の画面だけ省略する。一人の手札という収納先は一件でも、その中のカードは複数なのでカードの並び順・選択数は別に指定する。新規の条件・AND／OR追加は条件全体を未選択にし、最初と同じ条件ナビゲーションを開く。比較式や対象値を自動挿入しない。処理行は複製・上へ・下へを持ち、同じブロック内で移動する。複製は直下へ追加して入れ子の処理・分岐に新IDを付け、参照先IDと未登録の保持項目は維持する。並び替えと戻る／進むは元のIDを維持する。既存条件が変換できない場合は元データを保持してエラー表示し、空の分岐として上書きしない。既存JSONを読み込んだだけで対象指定を書換えず、新規・再指定の単一対象は既存のactor/turn等の形式で保存する。JSON形式19／処理形式3は変更しない。

## 条件導線と保存制約（2026-10-18）

条件編集は参照先→判定→値の段階選択を使用する。マーカー条件はマーカー→所持／未所持→対象プレイヤーを選び、条件行に対象プレイヤー・マーカー名・所持有無を表示する。全条件／いずれか・常に成立／不成立・値比較・フェーズ所属ボタンのフェーズ条件は新規候補に出さず、AND／OR／NOT／括弧と参照選択へ統合する。既存条件と内部のsource順序は読み込みで変更しない。sourceは新規の並び順候補に出さず、元の順とも表示しない。所属フェーズを持たない盤面ボタンではフェーズ→実行中／実行中ではないも選べる。新規カード・収納先選択は名前の昇順。新規プレイヤー選択はターン順昇順、単一マーカーは表示と確定値とも選択数1。並び替え値は対象の変数、同値は候補の取得順を維持する。未選択の編集はルール確定不可。保存済み処理でも必須対象が欠けていれば、配布データ作成とサーバー公開で拒否し、処理の経路・不足項目を返す。文字列としての「未選択」は拒否しない。JSON形式19／処理形式3は変更しない。

## 対象の共通選択（形式19の追加項目）

PlayerTargetにselect・and・or・team、turn.basis、CardSelector.selection、CardLocation.multiple.selectionを追加します。selectionはorder（source/ascending/descending/random）、key、count（allまたは1以上の整数）を持ちます。条件を評価し、並べた後に件数を制限します。既存データの省略値は元の順・全件で、読み込み時に新しい指定を自動挿入しません。処理・条件・文章は同じ型を使用します。新しいJSONはこの拡張に対応した実行器で使用してください。[処理仕様](action-reference.md#共通対象クエリ)・[サンプル](examples/target-selection.json)を参照してください。

## タブの盤面寸法・初期表示範囲（形式19の省略可能項目）

背景画像は盤面の幅に合わせた倍率（幅100%・高さauto）で上端から繰り返します。高さの拡張は下方向だけで、画像を縦に引き伸ばしません。高さハンドルのライブ表示は編集UIだけの一時状態で、JSONは離して確定した高さ・座標のみを保存します。

`background.width` と `background.height` はそれぞれ任意の100〜10000の整数px。省略した軸は従来の `size` が決める幅950／620／700px・高さ500／840／700pxを使います。横幅はJSONで指定し、編集画面で高さを変更しても保持します。`tabs[].background` に同じ項目を設定でき、未設定のタブはルート背景を継承します。`initialViews` に `desktop` と `portrait` を任意指定し、それぞれ `{x,y,width,height}` を論理pxで保存します。x,yは0以上、width,heightは20以上で、矩形全体が盤面内に収まる必要があります。スマホ横はdesktopを使います。確認・実部屋の初期カメラだけに使用し、部品座標・寸法は変えません。範囲未設定はスマホ縦が左上・全幅×100px、PC・スマホ横は盤面全体です。指定矩形は縦横とも収め、盤面が列より狭い場合は左右中央・上揃えです。新規タブは950×500px、サイズプリセット選択は撤去しましたが既存のsize・height・initialViewsは保持します。

高さの編集では `item.y = 旧y × 旧高さ / 新高さ` として物理位置を保ち、部品実寸・x・別タブを維持します。回転を含め部品を切る縮小は拒否します。初期表示範囲は盤面縮小時に端末ごとにheight=min(旧height,新盤面height)、y=min(旧y,新盤面height−調整後height)へ自動調整します。x・width・収まる範囲・未設定の端末は維持し、同時保存・Undoします。JSON読み込み時の盤面外矩形の拒否は従来どおりです。読込時に既存座標を変換せず、heightやinitialViewsを自動挿入しません。保存・書き出し・再読込でも明示した任意項目を保持します。例: `examples/board-initial-view.json`。

形式19の省略可能項目として、テキスト部品のtextParts、数値変数変更のvariableValue.kind=formula、PlayerTarget.kind=button-owner、ターンマーカーのturnPlayerOnlyを使用できます。省略時は既存動作を維持します。詳細はcomponent-reference.md、action-reference.md、examples/composed-values.jsonを参照してください。

タブ内ボタンの修正とピース分離は既存項目の実行解釈の修正で、形式・バージョン・保存設定は追加しません。プレイヤー／チームタブ内の部品参照は元定義IDで保存し、起動時に生成IDへ展開します。ボックスを移動元にしたピース処理には、その箱内カードに付属するピースも含みます。例は `examples/tab-buttons.json`。

`cardTemplate.layers`／`diceTemplate.layers` の `x,y,width,height` は枠に対する百分率で、座標0〜100・サイズ100以内という制約はありません（幅・高さは1以上）。負の座標や拡大画像をJSON往復で保持します。完全に枠外のレイヤーは編集画面の「枠外・重複項目の整理」の削除操作で削除しますが、読込・一覧切替・実行時に自動削除しません。枠に一部でも重なるレイヤーは保存し、ゲーム画面は従来どおり枠内へクリップします。形式・バージョン追加は不要です。

所有者付きボックスの表示設定はカード入庫時の初期値であり、入庫後のカード自身の `visibilityMode`／`privateTo`／表裏を優先します。`entryVisibilityBoxId` は同じ箱での再適用を防ぐ実行時スナップショット項目で、作者JSONには指定しません。旧部屋は最初の読込時だけ初期化し、以後は手動変更を保持します。作者JSONの形式・バージョンとDBは変更しません。

操作 `log` の `logParts` は固定文字・プレイヤー名・既存の変数参照を結合する1〜30項目の配列です。出力は1000文字まで。schemaVersion 19／operationSchemaVersion 3の任意拡張で、既存データの既定値や移行結果は変更しません。実行済み本文・実行者・イベントIDは実行時の状態であり作者設定ではありません。公開範囲の注意と例は action-reference.md を参照してください。

`type: "reveal"` は `cardSelector` を必須とする収納済みカードの全員公開です。新しい永続フィールドは増やさず、実カードの既存 `visibilityMode`・`privateTo`・表裏だけを更新します。位置・順序・個体IDは不変で、ボックス入庫時の初期設定とは別です。手札の公開カードは他プレイヤー・観戦者も確認できます。詳細は action-reference.md と examples/in-place-hand-reveal.json を参照してください。

処理の任意項目 `showAnimation`（移動・めくる・シャッフル・サイコロのみ）は既定false。既存JSONの再読込でONへ移行しません。ONのカード移動は表示対象がある端末で1処理1回の移動音を鳴らします。演出中もスクロール・視点等の閲覧は可能ですがゲーム状態の更新はできません。新規ゲームの背景グリッド初期値はfalseで、保存済みのtrue／falseは維持します。演出の実行時情報は作者向けJSONに記載しません。詳細は action-reference.md の演出を参照。

プレイヤーボックスを複製すると、最大人数分の全枠へ新しい共通 `playerBoxGroupId` と一意なIDを割り当てます。座標差・共通サイズ・共通設定を保持し、元とは独立します。名前ラベルの接続・省略・吹き出しとカードの継承バッジ省略は表示規則で、新しい保存項目は追加しません。

`settings.activityLogEnabled` は動作ログの表示設定（boolean、省略時false）。ONではプレイヤー一覧と同じ領域のログタブで表示する（PC・スマホ横は盤面の右、スマホ縦は盤面の下）。初期は一覧タブ、OFFではタブ切替を出さない。実行時 `activityLog` に直近200件を保持する。通常操作は秘密のカード内容・入力・回答・匿名所有者を自動記録しない。ボタン実行は実行者名とボタン名を一度だけ記録し、内部のカード移動などの自動ログは追加しない。選択カードが押下時点で表向きかつ全員に公開されている場合、その先頭カード名を同じ行に添える。本人・チーム限定、裏面、山の下、未選択カードの名前は記録しない。確認モードも同じ履歴を表示し、回答待ちから再開してもボタン名を重複させない。例外は作者が `logParts` で明示した公開本文・参照値である。処理由来の更新は実行時 `automationFeedbackId` で区別し、操作音・サイコロ演出を抑止する。実行時値を部品の設定へ追加しない。

新規のリセット処理は `type: "reset"`、`mode: "game"`（省略可）だけを使用します。旧データのpart/global/player/team/markerは読み込み・実行互換のために保持します。全体以外は `source` に対象定義IDを保存し、個人・チーム変数には `playerTarget` を保存します。省略したmodeは全体です。ゲーム定義の保存・書き出しでは処理を保持し、実行時の初期盤面を定義自体へ書き戻しません。

サムネイル表示は全画面で16:9枠へ画像全体を中央配置し、画像のトリミングや保存値の変換は行いません。

ターンマーカーの明示的な移動（`type: "marker"`, `source: "turn"`, `mode: "move"` またはmode省略）は、同じ所有者でも終了→開始を実行し、ターン世代を更新します。設定JSONに新しい項目は不要です。通常の状態同期はイベントを再実行しません。例は `examples/same-player-turn.json` を参照してください。

標準画像は `shared/builtin-game-image-manifest.json` の完全一致パスを保存し、書き出し・再読み込みでも参照を維持します。標準のサイコロ1～6面、チームアイコン、トランプ、背景などが対象です。数字サイコロ7～500は `/assets/numbered-dice/7.svg` ～ `500.svg` をサーバーが配信します。既存の埋め込みSVGは全内容が標準画像と一致する場合だけ参照へ戻し、編集済みSVG・外部URL・クエリ付きパスは標準画像と見なしません。`metadata.thumbnail` などの独自画像の `idb-image:` は端末保存領域から読み直し、書き出し時に画像のdata URLへ変換します。元画像が欠けている場合は画像を除去せず書き出しを止め、再設定を案内します。

カード移動の新規作成時は `sourceAmountMode: "per-destination"` と移動元の `cardSelector`、移動先配列 `destinationLocations` を保存します。枚数は各移動先に適用します。既存データで省略した場合の実行時解釈は `total`（合計）のままです。明示した `total` / `per-location` も維持します。

最新版は `schemaVersion: 20`、`operationSchemaVersion: 4` です。ルートには `name`、`version`、`metadata`、`tabs`、`items`、`background`、`settings` を配置します。

## metadata

`version` は1以上の整数の編集版番号で、サーバー公開版の採番とは別です。保存・配布定義・書き出しで保持します。旧サーバー定義で欠落した場合のみ読込時に1へ補完します。

- `description`: ホームに表示する説明
- `minPlayers` / `maxPlayers`: 新規公開・再保存は1〜20人の整数で、最少人数は最大人数以下。過去に保存済みの21人以上の版は従来の定員で部屋を作れますが、再保存するには20人以下へ変更してください。
- `genres`: 複数ジャンル。現行JSONの必須項目
- `durationRange`: `10-30`、`30-60`、`60-120`、`120-180`、`180-plus`。現行JSONの必須項目
- `genre` / `durationMinutes`: 旧入力用の互換項目。現行の書き出しでは使用しない
- `rules`: 最大20件の `{ id, title, image?, body }`

## tabs / items / background

タブは最低1件必要です。各部品の `tab` は存在するタブIDを参照します。部品は一意な `id`、`kind`、`tab`、`name`、`x`、`y`、`width`、`height` を持ちます。重要部品は `x=5〜95`、`y=8〜92` を推奨します。背景の標準は横長です。

背景はゲーム本体の `background` とタブごとの `tabs[].background` に指定できます。`size` は `landscape`（950×500）、`square`（700×700）、`portrait`（620×840）。`preset` は `wood`（木目）、`mat`（マット）、`custom`（オリジナル）、`none`（なし）です。木目とマットはサイズ別の内蔵JPGが自動選択されます。現在形式のJSONに `image` を書く場合は、`/backgrounds/wood-table-landscape.jpg` のように種類とサイズに一致させてください。`custom` は自分でアップロードした画像、`none` は画像なしを表します。旧PNG参照はv16→v17変換APIで対応するJPGへ置き換えます。

完全な許可フィールドは `schema/game.schema.json` を参照してください。

サイコロ部品は `diceFaces[]` に `{ "id": "face-1", "name": "成功", "copies": 2, "variables": { "name": "成功", "point": "3", "image": "/assets/dice-face-6.svg" } }` のような面を保存します。`diceVariableDefs[]` はカードと同じ `name` / `type`（`text` / `number` / `image`）で、`diceTemplate` は全ての面に共通の表レイアウトです。新規サイコロの初期設定では画像型 `image` 変数を各面に用意し、共通レイアウトの画像変数レイヤーから参照します。盤面とゲーム画面はそのレイアウトを表示し、別の点・数字を重ねません。サイコロには裏面、描画・入力領域、ピース配置マスはありません。`copies` は複製個数ではなく抽選の重みで、各面の出現確率はその `copies` を全ての面の合計で割った値です。`value` は面IDではなく面一覧の1始まりの順番、`sides` は面の件数です。`diceCanRoll: false` なら手動で押しても振れませんが、処理の「サイコロを振る・変更」は実行できます。処理・条件では `{ "kind": "dice-variable", "partId": "dice-id", "variableKey": "point" }` で現在の面の変数を参照できます。古い `diceFaces` のないデータは `sides` 件の等確率面と初期画像変数を補って扱います。画像のない旧式のカスタム面は従来の面名レイアウトを維持します。

サイコロの実行時だけ使う任意項目 `diceRollId` は1～80文字のロール識別子です。手動・処理のランダム抽選ごとに生成してオンライン状態へ共有し、同じ面の連続結果も一度ずつ演出します。作者の初期JSONには指定しません。出目 `value` と重みは識別子で変更せず、演出（約600ms）で処理を待たせません。再接続の初期状態は演出しません。

完全な例は [`examples/weighted-dice.json`](./examples/weighted-dice.json) を参照してください。

カード一覧は部品ごとに最大500種類、サイコロの面一覧は部品ごとに最大500面です。種類数・面数の制約であり、各種類の枚数・重みや部品数の合計ではありません。CSVの更新・追加後もこの上限を確認します。

カード一覧のCSV入出力は、JSONの新しい形式ではありません。カード部品の `cardDefs[]` と `variableDefs[]` のうち、カードID（`item-key`）、名前（`label`）、固定枚数（`item-count`）、`copy-mode`、`count:<人数>`、文字・数値変数（`var:text:<名前>` / `var:number:<名前>`）だけを扱います。同じ `item-key` は更新、空欄や未登録のIDは追加し、CSVにないカードは残します。トランプのマークと数字は独立した `suit`・`rank` 列ではなく、`var:text:suit`・`var:text:rank` として扱います。旧CSVの独立列は取り込めません。画像、カードの表裏、ピースの配置マス、テンプレートはCSVに含めず、既存カードでは維持します。PCIO形式の `image` 列は読み込めますが、外部画像URLは取り込みません。取込前に更新・追加件数と画像の除外件数を確認します。

サイコロの面一覧も同じ一覧編集・CSV処理を使います。`item-key` は面ID、`label` は面名、`item-count` は1～10000の固定重み、`copy-mode` は `fixed`、変数列は `var:text:<名前>` / `var:number:<名前>` です。人数別の `count:<人数>` 列は使いません。面一覧は1～500件で、CSVにない面と既存の画像・レイアウトは維持します。追加・更新のプレビューを確認してから一括適用し、不正な入力は部分適用しません。保存先は従来の `diceFaces` / `diceVariableDefs` / `diceTemplate` のままでカード用の個体・裏面・枚数モードの項目を混入させません。面の並べ替えは現在面IDを維持します。

カード部品ごとの `items[].handExitFace` は、その部品の全カードを手札から手動で盤面・ボックス・ゴミ箱へ出す向きを `front`（表）/ `back`（裏）/ `choose`（配置時に選ぶ）で指定します。省略時は従来どおり `back` です。旧v18の `cardDefs[].handExitFace` はv19への変換で部品に移し、異なる値が混在すると `choose` にします。`choose` の場合はカードごとの表・裏がすべて決まるまで移動コマンドを送らず、キャンセルすると手札に残ります。プレイヤーボックスの表示が `owner` または `others` の場合はボックス設定を優先して選択を出さず、`all` の場合だけカード設定を適用します。ボタン処理で向きを明示する `face` はこの手動操作設定の対象外です。

`box` の `boxShufflePosition` は `outside-top` / `outside-right` / `outside-left` / `outside-bottom` のみを新規データに指定します。旧データの `inside-*` は読み込み時に `outside-bottom` へ変換されます。

編集画面の「カード・ピースサイズにする」は、選択したカードまたはピースの幅と高さにそれぞれ10（左右・上下各5）を足し、ボックスの `width` / `height` に保存します。これらは通常の数値項目で、自動追従設定ではありません。シャッフルボタンは選択した枠外の辺から5px離れて描画されます。

プレイヤーボックスは最大人数分の `box` 部品です。1人目は `playerBoxSlot: 1` と自身のIDを `playerBoxGroupId` に設定し、2人目以降は同じグループIDと人数を指定します。1人目を共通設定の正本とし、2人目以降で個別に保持するのは `id`、`playerBoxSlot`、配置位置 `x` / `y` と名前表示 `playerBoxShowName`（boolean、省略時true）です。名前・サイズ・形・その他の設定が食い違うJSONは読み込み・編集時に1人目の値へ統一されます。編集画面ではどのボックスを選んでも共通の部品設定を開き、サイズハンドルでの変更も全員分へ反映します。位置・名前表示は各枠で指定でき、名前表示ONの枠だけに仮のプレイヤーアイコンと名前を表示します。ゲーム中は参加人数を超えるボックスを表示せず、実プレイヤーのアイコンと名前を枠の上側に表示します。開始時の見え方 `playerBoxInitialVisibility` は `all` / `owner` / `others` です。実行時に対応プレイヤーIDと入庫時の初期設定を保持します。ボタン処理 `playerBoxVisibility` は `source` に1人目のボックスID、`playerTarget` に対象プレイヤー、`mode` に見え方を指定し、以後の入庫へ適用します。箱を出たカードも現在の表裏・公開範囲を維持します。

プレイヤーボックスは通常タブにのみ配置できます。プレイヤータブの `box` は通常のボックスとして扱い、`playerBoxSlot` と `playerBoxGroupId` を設定しないでください。編集画面ではプレイヤーボックスのプレイヤータブへの移動・貼り付け、およびプレイヤーボックスを含むタブからプレイヤータブへの種類変更を受け付けません。

チームボックスも通常タブの `box` です。1枠目は `teamBoxSlot: 1` と自身のIDを `teamBoxGroupId` に設定し、残りは同じグループIDとチーム定義順の枠番号を指定します。1枠目が名前・サイズ・収納方法・その他の共通設定の正本で、各枠が個別に持つのは `id`、`teamBoxSlot`、`x`、`y`、`teamBoxShowName` です。`teamBoxShowName`は任意booleanで省略時true、falseならその枠のチーム名・アイコンを隠します。共有設定の変更後も枠ごとの値を保持し、カードの表裏・公開範囲・権限は変更しません。編集画面でどの枠を選んでも共通設定を変更でき、サイズ変更は全枠へ反映します。実行時は実際に参加するチームの枠だけを表示し、枠の上側にチームアイコンと名前を表示します。`teamBoxInitialVisibility` は `all`（全員同じ面）/ `team`（所属チームだけ表）/ `non-team`（所属チーム以外だけ表）です。表示は `teamBoxVisibility` 処理でも変更できます。カードが箱を出ると箱の表示設定は適用されません。チームタブ内のボックスは通常のボックスとして扱い、`teamBoxSlot` を設定しません。

カード・ピースの場所や移動先でプレイヤーボックスを指定するときは、人数分の実体IDを列挙せず、1人目の共通部品IDを `boxId` に入れ、`players` に対象プレイヤーを指定します。例：`{ "kind": "box", "boxId": "player-box-a", "players": { "kind": "actor" } }`。同じゲームに複数のプレイヤーボックス群がある場合は群ごとに別の `boxId` を使います。ゲーム中は指定した各プレイヤーに対応する実体ボックスへ解決され、参加していない席には適用されません。通常のボックスは `players` を付けず、従来どおり個別IDを指定します。既存JSONで個別の席IDを指定した場所は、その席だけを指す指定として維持します。

プレイヤータブの通常ボックスにも `playerBoxInitialVisibility`、チームタブの通常ボックスにも `teamBoxInitialVisibility` を設定できます。`Slot` / `GroupId` は不要で、タブの所有プレイヤー・チームを対象とします。スタック・ホルダーの両方で入庫時だけ初期値を適用し、取り出しても現在の表裏・公開範囲を維持します。省略時は従来のカード面と `holderPrivate` の扱いを維持します。明示時は古い `holderPrivate` より入庫初期表示を優先し、タブの閲覧権限は変更しません。

新規チームは異なる識別色と背景色・図形を一枚にした内蔵画像 `/assets/teams/default-1.svg`〜`default-8.svg` で初期化します。既存チームの色・画像は上書きしません。人数別の構成を追加すると均等配分が入力され、その後に1対4などへ編集できます。自動構成は `compositions` へ勝手に保存せず、未設定人数の表示・準備部屋・開始処理で同じ計算を使います。

## settings のプレイヤー表示

`settings.teams` は省略時にチームなしです。使用時は `enabled: true` と一意なIDを持つ `teams[]`（`id`、`name`、`color`、任意の `icon`）、参加人数ごとの `compositions[]`（`id`、`name`、`playerCount`、`capacities: [{teamId,count}]`、任意の `default`）を設定します。同じ人数に1対4と2対3など複数の案を定義できます。人数別の定員合計はその人数と一致させ、構成案がない人数は定義順の全チームで均等配分し、余りを先頭のチームから1人ずつ追加します。人数より多いチームは定員0として参加しません。明示された構成案は優先し、不正な構成案を自動配分で置き換えることはありません。準備部屋のホストは構成案を選び、所属を手動で割り当てるか、開始時にランダムに確定します。チーム名・色・アイコンはゲーム中のプレイヤー一覧に表示します。`teammatesCanViewHands` と `teammatesCanViewPlayerTabs` は仲間の個人領域の閲覧を許可する設定で、省略時は無効です。これらはカード操作権限を与えません。

タブの `type: "team"` は参加中のチームごとに一つのタブと、そのタブ内の部品群を生成します。通常は所属チームだけがタブを開けます。`otherPlayersCanView: true` の場合は他チームにもタブを表示します。`type: "player"` と同様に、タブ内のボックス・カード・ピースの実行時IDはチームごとに分離します。チームタブ内のホルダーで `holderPrivate: true` を指定すると、そのチームの参加者だけに中のカードを表示します。チームタブを使うには `settings.teams.enabled: true` が必要です。処理の場所は `{ "kind": "team-tab", "tabId": "タブ定義ID", "players": { "kind": "actor" } }` で指定し、選んだプレイヤーの所属チームのタブを参照します。`players: { "kind": "all" }` は所属するチームごとに一回だけ展開されます。`boxIds` にタブ内のボックス定義IDを列挙すると、対象をその収納部品に絞れます。

盤面と手札のカードは、チームゲームのときに `visibilityMode: "team" | "non-team"` も選べます。このとき `privateTo` は対象チームの ID です。`team` は対象チームだけが表、`non-team` は対象チーム以外が表を見ます。チーム未所属の観戦者は `team` の表を見られません。チーム変数は `settings.teams.variables` に `id`、`name`、`type: "number" | "text"`、`defaultValue`、`visible` を定義します。実行時は各チームが独立した値を所有し、`source: "team:変数ID"` の `variable` 処理で対象プレイヤーの所属チームを更新します。比較・値の参照には `{ "kind": "team-variable", "variableId": "変数ID", "players": { "kind": "actor" } }` を指定します。複数の同一チームのプレイヤーは一つのチームとして集計・変更します。

チーム手札は個人の `players[].hand` と別の実行時状態 `teamHands[チームID]` です。チームが有効で参加者がいる場合に生成され、チームのメンバーだけがカードを直接操作できます。処理の場所では `{ "kind": "team-hand", "players": { "kind": "actor" } }` のように選びます。対象プレイヤーから所属チームを解決し、同じチームを重複して処理しません。オンライン保存では他のチーム手札や個人手札と独立した更新として統合します。

対象プレイヤーの `kind: "team-turn"` は、準備部屋で確定した独立のチーム順 `teamOrder` とチーム内順 `teamMemberOrder` から一人を選びます。`teamPosition` は `current` / `next` / `previous` / `offset`、`memberPosition` は `first` / `current` / `next` / `previous` / `offset` です。`offset` のときはそれぞれ `teamOffset` または `memberOffset`（整数）を指定します。チームが無効、またはターンマーカーが無効なら対象はありません。選択は現在のターンマーカー所有者を起点とし、それ自体は手番を進めません。手番を変更したい場合は、選んだプレイヤーをターンマーカーの移動先に指定します。

カードを手札へ移す処理の `handVisibility` にも `team` / `non-team` を指定できます。この場合、受け取るプレイヤーのチームが表示対象になります。チーム未所属の受取人には安全側の `owner`（本人だけ）を適用します。

人数別構成のJSON例は [`examples/team-compositions.json`](./examples/team-compositions.json) を参照してください。

`sharedCursor` は共有ポインターの表示設定です。省略または `true` なら、他プレイヤーがカードを移動中だけプレイヤーを示すポインターとカードのゴーストを表示します。`false` ならポインターを隠し、匿名のカードゴーストだけを表示します。どちらでも移動中のカードは他プレイヤーが同時に持てません。通常のカーソル移動は共有しません。旧 `sharedCursorAnonymous` は読み込み互換のため残せますが、表示には影響しません。

`showOtherHands` は他プレイヤーの手札ウィンドウを開けるかの設定です。手札は一つの領域で、カードごとに `visibilityMode: "owner" | "others" | "all" | "team" | "non-team"` を持ちます。`owner` は本人だけ表、`others` は本人以外が表、`all` は全員が同じ面を見ます。限定表示を許可しないカードでも手札内の `owner` は使えます。盤面で限定表示を使うにはカード側の許可が必要です。

`playerVariables[]` は `{ id, name, type, defaultValue, visible, image? }` を指定します。`type` は `number` または `text`、`defaultValue` は文字列です。`visible: true` の変数はゲーム画面のプレイヤー一覧に名前と値が表示されます。`image` は表示中だけ設定でき、名前の前にマーカー画像と同じ18pxで表示されます。`visible: false` なら `image` は含めません。編集画面で表示をOFFにすると画像設定も削除されます。

公開範囲は任意の `publication:"public"|"owner"|"team"`（省略public）で指定します。visibleとは独立です。秘密の役職・答えをvisible:falseだけで保護しないでください。teamは所属チーム限定、未所属者へのチーム公開はありません。チーム変数ではowner/teamとも所属チーム内です。全体変数は共有値です。[安全な反映パターン](authoring-patterns.md#秘密情報を安全に扱う)を参照してください。

`variable` 処理の新しい設定値は `variableValue` に保存します。全体・プレイヤーの文字変数は文字の代入のみ、数値型の変数は数値の代入・加減算です。手札を参照する場合は `hand-count`（枚数）か、`card-variable` の `cards.location.kind: "hand"`（カード変数）を使います。後者は対象プレイヤーとカード条件で指定します。変更先がプレイヤー変数のとき、手札の `players: { "kind": "assignment-target" }` は同じ処理の `playerTarget` で選ばれた現在の変更先を指します。複数人への変更では各人の手札を別々に評価し、該当カードがない人は変更しません。`actor` は常に実行者です。旧 `handZone` はv17→v18変換で削除します。文字のカード変数は各人につき候補を1枚に絞ってください。旧 `amount` だけの処理は数値処理として読み込みます。

`settings.markers` の `id: "turn"` は固定のターンマーカーです。`orderEnabled: true` で手番を有効にし、ゲーム開始時は準備部屋で決めた順番の先頭プレイヤーが所有します。所有者のプレイヤー枠をハイライトし、`multipleAllowed: true` なら複数人の枠をハイライトできます。現在基準の対象は所有者全員を参照し、単体専用の`game.turn-player`だけは最初の所有者を基準にします。`orderEnabled: false` では手番自体が存在せず、手番を参照する条件・処理は対象なしとして扱います。名前は「ターンマーカー」固定で、画像は設定しません。ターン順そのものは準備部屋で設定します。

ターンマーカー操作の任意`turnTeamId`で、指定チームだけ独立して進められます。チーム有効・複数可ONが必要で、他チームの所有者を維持します。省略は全体。次／前／差分はそのチーム内順です。全員から除去しても実行状態`turnPositions`の全体・各チーム別の直前位置を保持し、次の人で再開します。条件・表示・権限は除去中に対象なしのままです。初回のチーム所有者は順番基準で明示設定し、リセットで位置を初期化します。作者JSONへ実行位置を記述しません。形式20／処理形式4のまま、既存データの変換不要。[例](examples/independent-team-turns.json)。

標準の読み取り専用値「参加人数」は、観戦者を除く実際の参加プレイヤー数です。編集画面の数値・条件では「参加人数（自動）」を選び、JSONの値指定には `{ "kind": "participant-count" }`、旧式の処理・条件の式には `{ "kind": "participantCount" }` を使います。`playerCountVariables[]` は人数ごとに任意の値を設定する別機能です。参加人数を変数変更処理の変更先にはできません。フェーズメッセージでも `parts` に `{ "kind": "participant-count" }` を追加して表示できます。

通常マーカーは `settings.markers[]` の `ownerScope` を `"player"`（既定）または `"team"` にできます。チーム所有のマーカーに対する処理は、選んだプレイヤーの所属チームへ一度だけ適用されます。ゲーム中の `markerOwners` では `team:チームID` を保存し、チーム欄に表示します。所有者条件はそのチーム全員を対象にします。ターンマーカーはチーム所有にできません。

## 盤面ボタンとフェーズボタン

盤面ボタンの背景表示は既存の `backgroundEnabled` を使用します。省略／`true` は背景あり、`false` は背景色・枠線・影なし。文字・画像・操作は保持し、青い点線の範囲ガイドは編集画面だけに表示します。既存データの変換や形式番号の更新は不要です。

フェーズボタンは `settings.actionButtons[]` に置き、所属する `phaseId` の間だけ上部に表示します。盤面ボタンは `items[]` の `kind: "button"` に置き、`tab`、位置、`buttonShape: "square" | "circle"`、表示文字 `buttonText`、文字色 `buttonTextColor`（`#RRGGBB`、省略時は白）、文字サイズ `buttonFontSize`（1～200 px、省略時は標準）、画像参照 `front` を持てます。条件と処理列は両者で同じ構造です。`{ "kind": "current-phase", "phaseId": "start" }` で現在フェーズを指定できます。表示・操作条件を省略すると、対応する「常に」のチェックがオンになり条件を評価しません。ただし操作権限は別途適用されます。画像だけを出す場合は `buttonText: ""` とし、管理用の `name` は残します。

## 手札の操作権限

`permission` 処理で `subjects: ["hands"]` を指定すると、手札操作の権限を変更できます。同じプレイヤーの手札内でカードを並べ替えるには `view`（閲覧）と `move`（移動）が必要です。この移動には `hand-in` / `hand-out` は不要です。手札から盤面・ボックス・ゴミ箱へ出す場合は `hand-out`、盤面などから手札へ入れる場合は `hand-in`、別プレイヤーの手札へ渡す場合は両方が必要です。`select` は複数選択用の独立権限です。接続中の本人以外の手札を直接操作することはできません。

## フェーズの上部メッセージ

文字の部分書式は `formattedText: [{ "text": "文字", "font": "sans", "bold": true, "underline": false }]` を元の文字列と併用します。`font` は `sans`・`serif`・`rounded`・`mono` です。各 `text` の連結が元の文字列と一致しない場合、表示は元の文字列を優先します。盤面テキストは `item.formattedText` と `item.name`、盤面ボタンは `buttonFormattedText` と `buttonText`、フェーズボタンは `formattedName` と `name`、カード・サイコロの固定文字レイヤーは `formattedText` と `text` を併用します。動的な変数・入力レイヤーはレイヤー全体の `font`・`bold`・`underline` を指定します。上部メッセージの文章パートも `formattedText`、動的なパートは `format` を指定します。古いデータで書式を省略した場合は従来どおり表示します。

書式データの抜粋例は [`examples/formatted-text.json`](./examples/formatted-text.json) を参照してください。

ゲーム開始・リセット時は `settings.initialActions` を順に実行し、すべて完了した後にフェーズ1（IDは `start`）の `settings.automationEvents.phase.start.start` を1回実行します。初期処理が空でもフェーズ1の開始処理は実行します。選択・入力の回答待ちがある場合は、回答後に初期処理の残りを終えてから実行します。初期処理内で別のフェーズへ移動した場合は、その移動先の開始処理を実行し、フェーズ1の開始処理を追加で実行しません。フェーズ開始処理は初期処理の一部として重複して記述しないでください。

`settings.phaseMessages[]` は `{ id, phaseId, audience, displayCommonCondition?, parts }` です。`phaseId` は `start` または `settings.phases[]` のIDです。`audience` は既存の `PlayerTarget`、`displayCommonCondition` はボタン表示条件と同じ `CommonCondition` です。省略すると無条件に表示します。

ボタンの `displayCommonCondition`（表示）と `activeCommonCondition`（操作可否）、上部メッセージの `displayCommonCondition` は同じ条件構造を使います。`comparison.operator` の `in-right` は従来の部分文字列判定で、空でない左辺を文字列にして右辺に含む場合に成立します。`one-of` は `right` を最初の候補、`rightValues` を追加候補（最大19件）として、左辺といずれかが等しければ成立します。右辺の候補は合計20件までです。文字の固定値は `{ "kind": "fixed-text", "value": "人狼" }` です。大小比較は両辺を数値にできる場合だけ成立します。UIの「より大きい（＞）」などは左辺を基準に表示します。

実行したプレイヤーの手札条件は `{ "kind": "button-state", "predicate": "selected-hand-card" | "hand-card", "cardSetId": "カード部品ID", "cardDefinitionIds": ["カード定義ID1", "カード定義ID2"], "cardPresence": "has" | "not" }` でカード種類を複数指定します。`has` は指定したカードのどれか1種類があれば成立し、`not` はどれもなければ成立します。旧形式の単一 `cardDefinitionId` も読み込み・実行できます。新しく編集した条件は `cardDefinitionIds` で保存します。`selected-hand-card` は選択中の手札だけを調べ、未選択時は不成立です。`hand-card` は選択操作なしで手札全体を調べます。変数を比べる場合は `predicate` を `selected-hand-variable` または `hand-card-variable` とし、`cardVariableKey`、`selectionMode`（`any` / `all` / `sum` / `count`）、`operator` を指定します。文字比較は `comparisonValueKind: "text"` と `textValue`、数値比較は `comparisonValueKind: "number"` と数値の `value` を使います。`operator: "one-of"` では `textValue` または `value` を最初の候補とし、`comparisonValues` に追加候補を最大19件指定します。古いデータで `comparisonValueKind` がなければ数値比較として扱います。カード種類の判定は名前ではなく定義IDを使用します。

複数カード指定だけを抜き出したJSON例は [`examples/multi-card-hand-condition.json`](./examples/multi-card-hand-condition.json) にあります。

`parts` は順に連結する最大30件の項目です。文章は `{ "kind": "text", "text": "残り " }`（500文字まで）。値参照は `{ "kind": "timer", "id": "timer-id" }`、`counter`、`global-variable`、`player-variable`、または `{ "kind": "card-variable", "id": "card-set-id", "variableKey": "point" }` です。プレイヤー変数は表示中の本人、カード変数はそのカード部品由来の公開・表向き最上部カードを参照します。見えないカードや参照先のない値は `—` と表示します。タイマーはカウント中も秒ごとに更新され、一時停止・再開・リセットに追従します。文章はHTML・JavaScript・式として解釈しません。

## トークン部品

`kind: "token"` を使用する。既存schemaVersion 19へ追加可能な項目で、既存のカード・ピースをトークンへ変換しない。所属・匿名・共通サイズ・個別配置・移動権限は[部品仕様](component-reference.md#トークンtoken)を参照。画像は既存のfront画像参照と同じ保存・配布・書き出し経路を使う。所属付きトークンをプレイヤー／チームタブへ置いて二重展開しない。[サンプル](examples/player-team-tokens.json)を参照。


## プレイヤー参照の対象指定（2026-10-17）

手札枚数・プレイヤー変数は「実行したプレイヤー」に固定しない。条件分岐の左辺・右辺、および枚数・個数・角度・時間・変更する値の数値参照で、対象プレイヤーを独立して選ぶ。

- Exprの hand / player に省略可能な players: PlayerTarget を追加。形式19／処理形式3の後方互換の追加であり、既存データへ対象を自動挿入しない。
- 未指定は「条件全体の対象」または従来の各処理の参照先（受取人など）を継承する。明示指定のactorは条件対象・受取人ではなく実行者。ターン順は現在手番を基点にする。
- 明示した複数対象の手札枚数・数値変数は合計し、対象なしは0。プレイヤー変数の文字比較は対象が1人なら文字を保持する。複数人の文字変数の比較には合計を使わず、1人に絞る。
- ボタンの「目的から選ぶ」は手札枚数／プレイヤー変数／手札全体のカード・カード変数／マーカー所有の条件に players を持てる。省略は従来どおり実行者（表示判定時は表示者）。複数人は全員一致、対象なしは不成立。ここでは合計せず一人ずつ判定する。
- 選択中の手札・ホルダーは引き続き操作した本人の選択であり、別プレイヤーへ振り替えない。プレイヤー変数の変更先と参照元は別指定である。
- カード条件の比較値も共通NumericValueの対象選択を使う。無関係な旧式・カード個体選択の意味は変更しない。

参照先は共通PlayerTarget形式。形式19の省略可能な追加項目で、旧データを書き換える移行はありません。サンプルは[対象の異なる手札比較](examples/player-value-targets.json)を参照。

条件分岐の組合せは `branches[].conditionMode`（and／or、省略and）と `additionalConditions`（最大4件のCommonCondition）を使用する。元のleft/operator/right等は第一条件として維持し、分岐間は上から最初の成立を実行する。追加なしは旧形式と同じ。追加条件の深さ免除は不可。操作条件のプレイヤー文字比較はcomparisonValueKind="text"とtextValueを明示し、数値はvalue（旧形式は数値のまま）。固定テキストは候補に限定しない。内部IDを名称へ書き換えず、UI表示だけ名称を解決する。例: examples/compound-branch.json。

進行処理の組み方は[公開実装パターン](authoring-patterns.md#タイマー確認終局)を参照。phaseは同一sourceでも終了→開始を実行。messageParts（LogMessagePart配列）は実行時に解決し、messageConfig.severityはerror/warning/message。PlayerTarget.player-variableのoperator=max/minは数値の同点全員を返す。loopはmode=count/while/playersとbranches[0].actions、loopBreakで最内ループを終了、loop-playerで対象を参照する。実行中のruntimeLoopState/runtimeLoopFramesは作者JSONに保存しない。最大1000反復・10000ステップ・100フェーズ移動で停止する。旧データは変換不要、新操作を旧クライアントで実行する互換性は保証しない。

## メソッド形式の編集画面



新しい編集画面の一行UIと「コードで編集」は、同じ型付きの条件・処理・参照を既存形式へ変換する編集UIです。コード文字列そのもの、編集中のエラー・履歴・復元用入力をゲームJSONへ追加しないでください。型・参照・利用先の制約に反するコードは確定できません。設定呼出・括弧をAI向けJSONの新しいキーとして出力せず、従来どおりAction等の構造で記述してください。

テキスト部品の新画面にある「表示者」は、保存時には既存のactor参照を表示者として評価する従来の文脈へ戻します。playerTarget.kind=viewerやviewerAvailableなどのUI用項目をJSONへ追加しないでください。フェーズメッセージは引き続き独立したPhaseMessagePartで、表示者の変数と項目別の書式を保持します。


新コードUIのユーザー変数は `全体.変数.名前`、`実行者.変数.状態`、`実行者.チーム.変数.状態` で参照します。これは画面の式であり、JSONの変数ID・Action・Expr・NumericValueの構造は変わりません。JSON Schema、JSONサンプルと生成プロンプトにはコード用の「変数」キーを追加しません。元のIDと明示的なplayersを保持してください。専用設定とマーカー所持・選択手札などの条件は新UIの型付きメソッドから既存JSONへ変換します。未来の未知条件・未知の専用項目は保存を停止し、黙って変換・削除しません。


新UIの選択・入力・権限・専用条件の互換例は `examples/method-specialized-actions.json`。メソッド文字列や「設定」キーを新たにJSONへ書かず、引き続き現在のAction・Expr等を出力してください。既存のJSON Schemaと生成プロンプトの形式は変更しません。


### 手札整列の編集表示

新しい編集画面の並び替え元「手札」「選択中の手札」は既存の `source: "actor-hand"`／`"selected-hand"` へ変換する。`sourcePlayerTarget` を省略すると実行者の手札を使用する。これは編集表示の追加と既存実行経路の修正であり、Schemaの項目・既定値・選択肢やAIのJSON出力形式を拡張しない。


### 行内編集の対象表示とJSON

「全プレイヤー.手札.カード（変数.pont > 3）」は画面上の表示であり、JSONではCardSelectorのlocation={kind:"hand",players:{kind:"all"}}、condition={kind:"card-variable",cardSetId:"対応するカード部品ID",variableKey:"pont",operator:">",value:{kind:"fixed",value:3}}とする。収納先のシャッフル・整列はtype=shuffle／sort、cardSelector.condition.kind=allを使用し、場所ごとに処理する。複数場所はlocation.kind=multipleとlocations配列。UIの型名・候補・編集中の経路・ドット表記を保存しない。現行形式はschemaVersion 20／operationSchemaVersion 4。例はexamples/inline-target-editing.json。


編集画面の赤い［未選択］は編集中だけの表示です。ゲームJSONへ未選択という文字・値・フィールドを出力しないでください。対象・回数・値を指定してから既存の型へ変換します。既存の省略値とJSON Schemaの既定値は変更しません。繰り返しは従来のloop.mode=count／while／playersとcount・condition・playerTargetを使います。例と生成プロンプトのJSON形式、schemaVersion19／operationSchemaVersion3は維持します。

## 通常処理に統合した一時変数
variableでtemporaryDefinitionとtemporaryValueを設定し、sourceはtemporary:<ID>にします。loopはmode:arrayとarray式を選択できます。詳しい引数・型・公開制御は[action-reference.md](action-reference.md)、抜粋は[統合サンプル](examples/integrated-temporary-actions.json)を参照してください。旧type:temporaryは廃止され、自動変換・無断削除はしません。

収納済みカードの公開変更は既存Action `reveal` のmode（all／owner／others／team／non-team、省略all）とplayerTargetを使う。限定公開の基準は単一プレイヤー。カード入力はcardTextChange.messagePartsを既存のメッセージ部品形式で保存し、messageより優先する。新しいプログラム形式・バージョン移行は追加しない。

テキスト部品はname（処理参照用の部品名）とtextContent（固定表示文字）を分離する。textContent未指定は旧name表示のまま、textPartsがある場合は動的表示を優先する。文字輪郭はtextOutline（既定false）・textOutlineColor（既定#ffffff）・textOutlineWidth（0.5〜5、既定1）で保存する。既存形式へ任意項目を追加するものでバージョン移行は不要。

## ターンと全員回答待ち（形式20／4）

`settings.turn`はターン専用設定です。`enabled`（既定true）、`playerOnly`・`multipleAllowed`（既定false）、`allowOwnHand`・`allowOwnTab`（既定true）を指定します。手番外でも許可する本人手札内／個人タブ内の操作は、その領域を出ない操作だけです。明示的禁止・閲覧権限・回答待ち中の変更禁止は優先します。マーカー一覧にはカスタムマーカーを設定します。旧`markers[id=turn]`は読み取り互換を維持し、新`turn`があれば新設定を優先します。ターン／マーカー設定の編集で正規化します。一括変換不要です。既存処理の`source:turn`と実行状態`markerOwners.turn`は互換アダプターとして維持します。

選択／入力の全員回答待ちには作者JSONの新項目はありません。回答済み・対象外・観戦者には人数だけを上部に表示し、未回答者だけに回答欄を表示します。回答中も閲覧・タブ・スクロール・拡大縮小は利用でき、状態変更・別処理は停止します。確認モードでは視点切替で全員分を回答できます。`answerProgress`は参加者別の実行時投影であり、作者JSONに記入しません。例は[全員回答と個人領域の操作](examples/answer-wait.json)。

## 名前付きプレイヤー選択の接続（形式20／4）

一時式のプレイヤー属性`property.path:["id"]`は既存の参加プレイヤーID（Player.id）の文字列を返します。名前・席番号ではありません。認証参加者ではアカウントと同じIDを使う場合がありますが、accountIdなどの別属性は追加しません。`choice.sourceKind:players`の回答`game.input.texts`との包含比較で`game.players`を抽出すると、同名でも型付き対象として使えます。参照と回答の公開ラベルを保持します。`temporaryBindings`辞書は通常のPlayerTargetとして検査せず、正式引数と一時式の専用検査を適用します。旧JSONの変換は不要です。
## 選択と変数キー整列

カード部品のcanMoveは手動移動の既定値であり選択可否と独立する。選択の制限は既存の操作権限selectを使用する。新規canSelect項目は生成しない。処理sortの任意cardSortKeysについては[action-reference](action-reference.md#カード変数の整列基準)を参照。省略した旧ゲームのソート・移動規則は変更しない。形式20／4、DB構造は維持する。

## 選択カードの個体参照（形式20／4）

場所を cardSelector で指定した choice/card-location の回答は `game.input.cards`（card配列）で後続の移動へ接続します。候補・未選択札は回答対象以外へ配信せず、公開回答も選んだ個体の不透明な参照だけを公開します。属性の秘密保護は維持します。候補不足・空候補・旧JSONの扱いは [処理仕様](action-reference.md#場所付きカード選択の結果)を参照してください。
## フェーズ別ボタンとセーブポイント

操作はフェーズ別ボタンへ統一する。回数は通常の変数・条件で管理し、汎用のセーブポイント・条件／配置検査・操作制限を組み合わせる。旧設定は読込時だけ変換し、進行中の旧部屋は新規開始する。私有記録と秘密情報の参加者別配信を維持する。

操作はフェーズ別ボタンへ統一する。回数は通常の変数・条件で管理し、汎用のセーブポイント・条件／配置検査・操作制限を組み合わせる。旧設定は読込時だけ変換し、進行中の旧部屋は新規開始する。私有記録と秘密情報の参加者別配信を維持する。

部品のrotationは省略可能で、既定は0度です。読み込み・初期化・描画・移動境界・スナップで同じ値を使用します。省略のままでも対応し、作者が既存JSONを個別変換する必要はありません。JSON形式20／処理形式4は維持します。

公開範囲の警告は外部JSONの「読込」と「サーバーに保存」で検査します。同じ参照元と理由は1件にまとめ、公開先と該当箇所を展開できます。JSON読込の「全文をコピー」には全箇所を含めます。編集中・ドラッグ後の自動検査は行いません。警告だけなら読込・保存は可能です。実行時も現在の対象と秘密情報の公開範囲を検査します。

得点更新の直後に同じカードを全員公開する手順と、一体で反映できる条件は[秘密情報の扱い](authoring-patterns.md#秘密情報を安全に扱う)を参照してください。既存の `variable`・`reveal` を使い、Schemaと形式は同じです。


実カードを手札・ホルダー・盤面で直接選択する場合は、場所付きカード選択に `choice.display:"surface"` を指定します。複数枚を選んで上部バーで一度に確定できます。ピース・独自候補には使えません。省略時は従来の一覧表示です。サーバーの候補・枚数・公開範囲・継続処理の検査は同じです。詳細は [カード個体の選択](physical-card-values.md) を参照してください。

## ゲーム内のプレイヤー色・チーム色

編集は「プレイヤー設定→プレイヤーの色」と「チーム設定→識別色」。自動設定はどちらも初期・省略OFF。ONは標準パレット、OFFは手動色を使い、切替で手動色を失わない。

`settings.playerColors`は`{ "automatic": false, "colors": ["#123456", "#abcdef"] }`。colorsは開始時プレイヤー順の0始まり配列で最大20件、各値は#と6桁の16進色。省略枠は標準色。同色指定可。人数上限を減らしても後ろの配色は保持し、ゲーム開始後の手番順・リセット・再接続で確定済み参加者色を変更しない。

`settings.teams.automaticColors`は省略false。ONは定義のteams配列順から標準色を解決し、既存の`teams[].color`を上書きしない。OFFはその手動色を使う。チーム手番順や所属の並べ替えでは色は変わらない。旧JSONは従来のプレイヤーパレットと手動チーム色を維持。schemaVersion20／operationSchemaVersion4の任意項目追加で、DB・旧データ移行は不要。[完全な例](examples/participant-colors.json)。

チームタブ内の本人の `tokenAffiliation:"player"` トークンは、同じ所属チームタブ内での手動移動に限り自動モード・手番外でも利用できます。カード権限を流用せず `tokens:move` で判定し、明示的な禁止と `canMove:false` / `tokenMovement:"none"`、所有者限定、回答待ち・終了・秘密情報の制限は維持します。一般のチームタブ操作や他人・チーム所属の駒、別タブへの移動には手番例外を広げません。追加JSON項目・個別変換は不要です。例は `examples/player-team-tokens.json`。
# 山札の先頭選択

実カードのchoiceに既存Actionフラグ `topOnly:true` を指定できます。省略・falseの既存選択は変更せず、trueでは各収納先・山の先頭1枚だけを候補にします。裏向きなら名前・定義ID・変数・説明・表面画像を送らず裏面だけを表示します。条件all、並べ替え・件数指定・候補変数条件なしが制約です。形式20／4を維持し、旧基盤は未対応。[操作・移行・例](physical-card-values.md#山札の一番上だけを選ぶ)。

`Action.type:"showCard"` は実カード1枚の拡大表示です。`cardSelector`／`playerTarget`は必須（型付きbindingも可）、`message`／`messageParts`は任意。表示のみで確認回答・公開範囲変更を行いません。実行状態の `runtimeNotice.cardInspection` はサーバー生成値のため作者JSONへ書きません。[仕様](action-reference.md#カードを拡大表示showcard)。

外部JSONの「読込」は、元の画像形式、公開Schema、処理の設定・参照・公開範囲を検証し、エラーを場所と理由の一覧で表示します。エラーがあるファイルは取り込まず、編集中のゲームを保持します。作者のSVG・外部画像URL・一時画像参照は使用できません。PNG・JPEG・WebP・GIFを埋め込んでください。正式な組込み画像の参照は既存の例外です。保存済み下書きを修復するために開く操作とは区別します。

## 本人の所有カード内訳

`settings.cardInventory` は任意設定です。`{ "title": "デッキ内容", "boxIds": ["personal-deck", "personal-discard"], "includeHand": true }` のように集計する個人ボックスの定義IDを指定します。タイトルは1～80文字、IDは重複なし最大64個です。共有市場は指定できません。省略または `enabled: false` なら従来通りです。

本人だけに名前・枚数・説明を表示し、手番外や回答待ちでも開閉できます。閉じると元の画面へ戻り、カードのコピー・移動・タブ切替・シャッフルはしません。山札順序、次に引くカード、物理IDは配信しません。オンラインではサーバーが集計し、クライアントで伏せ札から復元しません。

一時確認用には `temporaryBoxIds` と `ownerVariable` を追加し、移動前にカード個体へ元の所有者を記録します。通常は参加者ID、`ownerPlayerVariable` を指定した場合は登録プレイヤー変数の一意な値で照合します。値の欠落・重複は対象外です。通常ボックスと一時ボックスを重複指定できません。永久破棄は集計対象外です。

[完全なサンプル](examples/card-inventory.json)を参照してください。新設定を追加したゲームは対応基盤で新しく開始します。一時所有者の記録がない途中状態の所属は推測しません。

カウンター部品の`counterControlsEnabled`は任意boolean（省略true）。falseで手動の＋／−を非表示・操作禁止にします。通常のcounter処理には適用しません。保存・書出・再読込で明示したfalseを保持し、旧データの省略を無断で書き換えません。形式20／4を維持します。
