@yamat47/playmaker 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Takuya Yamaguchi
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,52 @@
1
- # Temporary Holding Version
1
+ # @yamat47/playmaker
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ アメリカンフットボールのプレー図を作成・表示する、UI フレームワーク非依存の TypeScript ライブラリ。
4
+ コンテナ要素に図を描き、編集 UI を置き、編集のたびに `PlayData` を渡す。永続化や共有は持たない。
5
+
6
+ - デモ: https://playmaker-demo.yamat47.me/
7
+ - ソースと詳しい使い方: https://github.com/yamat47/playmaker
8
+
9
+ ## インストール
10
+
11
+ ```sh
12
+ npm install @yamat47/playmaker
13
+ ```
14
+
15
+ ```ts
16
+ import { Playmaker, type PlayData } from "@yamat47/playmaker";
17
+ import "@yamat47/playmaker/styles.css";
18
+
19
+ const playmaker = new Playmaker(document.getElementById("play")!, {
20
+ mode: "edit", // "edit"(既定・編集 UI あり)/ "view"(読み取り専用)
21
+ initialData: saved, // 永続化しておいた PlayData(省略可)
22
+ onChange: (data: PlayData) => save(JSON.stringify(data)),
23
+ });
24
+ ```
25
+
26
+ バンドラを通さず、CDN から読むこともできる。依存は無く、フォントは JS に同梱してある。
27
+ URL の `0.1.0` は使う版に置き換える。
28
+
29
+ ```html
30
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@yamat47/playmaker@0.1.0/dist/playmaker.css" />
31
+ <div id="play" style="width: 960px; height: 600px"></div>
32
+ <script type="module">
33
+ import { Playmaker } from "https://cdn.jsdelivr.net/npm/@yamat47/playmaker@0.1.0/dist/playmaker.js";
34
+ new Playmaker(document.getElementById("play"));
35
+ </script>
36
+ ```
37
+
38
+ モダンブラウザと PC のマウス操作を想定する。
39
+
40
+ ## できること
41
+
42
+ - 選手(丸・四角)とラベル、ルート・ブロック・モーションの線を置き、ドラッグで動かす
43
+ - 位置は 0.5 ヤードの格子に揃う
44
+ - 同梱のフォーメーションとプレーのプリセットを読み込む(`FORMATION_PRESETS`、`PLAY_PRESETS`)
45
+ - 編集 UI を含まない PNG を書き出す(`exportToPng`)
46
+ - 色とフォントは CSS 変数(`--playmaker-*`)でホストに合わせる
47
+
48
+ 公開 API の一覧、`PlayData` の形、テーマの変数は、リポジトリの README にある。
49
+
50
+ ## ライセンス
51
+
52
+ MIT
@@ -0,0 +1,2 @@
1
+ .playmaker-root{--_playmaker-ui-font:var(--playmaker-ui-font,Roboto, system-ui, sans-serif);--_playmaker-ui-surface:var(--playmaker-ui-surface,#fff);--_playmaker-ui-text:var(--playmaker-ui-text,#000000de);--_playmaker-ui-border:var(--playmaker-ui-border,color-mix(in srgb, var(--_playmaker-ui-text) 23%, transparent));--_playmaker-ui-accent:var(--playmaker-ui-accent,#1976d2);--_playmaker-ui-accent-text:var(--playmaker-ui-accent-text,#fff);--_playmaker-ui-shadow:0 2px 1px -1px #0003, 0 1px 1px 0 #00000024, 0 1px 3px 0 #0000001f;--_playmaker-ui-text-dim:color-mix(in srgb, var(--_playmaker-ui-text) 60%, transparent);--_playmaker-ui-text-disabled:color-mix(in srgb, var(--_playmaker-ui-text) 30%, transparent);--_playmaker-ui-divider:color-mix(in srgb, var(--_playmaker-ui-text) 12%, transparent);--_playmaker-ui-accent-faint:color-mix(in srgb, var(--_playmaker-ui-accent) 8%, transparent);--_playmaker-ui-accent-outline:color-mix(in srgb, var(--_playmaker-ui-accent) 50%, transparent);width:100%;height:100%;font-family:var(--_playmaker-ui-font);color:var(--_playmaker-ui-text);font-size:14px;overflow:hidden}.playmaker-stage{grid-area:stage;width:100%;min-width:0;height:100%;min-height:0}.playmaker-root[data-mode=edit]{grid-template:"toolbar toolbar""stage panel"minmax(0,1fr)/minmax(0,1fr) auto;gap:12px;display:grid}.playmaker-canvas{width:100%;height:100%;display:block}.playmaker-root[data-mode=edit] .playmaker-canvas{touch-action:none}.playmaker-toolbar{border:1px solid var(--_playmaker-ui-divider);background:var(--_playmaker-ui-surface);color:var(--_playmaker-ui-text);box-shadow:var(--_playmaker-ui-shadow);border-radius:4px;flex-wrap:wrap;grid-area:toolbar;align-items:center;gap:6px;padding:8px 12px;display:flex}.playmaker-toolbar__button,.playmaker-panel__reset{font:inherit;letter-spacing:.02em;border:1px solid var(--_playmaker-ui-accent-outline);color:var(--_playmaker-ui-accent);cursor:pointer;background:0 0;border-radius:4px;font-weight:500;transition:background-color .15s,border-color .15s}.playmaker-toolbar__button:hover:not([aria-disabled=true]),.playmaker-panel__reset:hover{border-color:var(--_playmaker-ui-accent);background:var(--_playmaker-ui-accent-faint)}.playmaker-toolbar__button{padding:5px 12px}.playmaker-toolbar__button[aria-pressed=true]{background:var(--_playmaker-ui-accent);border-color:var(--_playmaker-ui-accent);color:var(--_playmaker-ui-accent-text)}.playmaker-toolbar__button[aria-disabled=true]{border-color:var(--_playmaker-ui-divider);color:var(--_playmaker-ui-text-disabled);cursor:not-allowed}.playmaker-toolbar__select{font:inherit;border:1px solid var(--_playmaker-ui-border);background:var(--_playmaker-ui-surface);color:var(--_playmaker-ui-text);cursor:pointer;border-radius:4px;padding:5px 8px}.playmaker-toolbar__select:hover{border-color:var(--_playmaker-ui-text)}.playmaker-toolbar__sep{background:var(--_playmaker-ui-divider);align-self:stretch;width:1px;margin:0 4px}.playmaker-panel{box-sizing:border-box;border:1px solid var(--_playmaker-ui-divider);background:var(--_playmaker-ui-surface);width:220px;max-height:100%;color:var(--_playmaker-ui-text);box-shadow:var(--_playmaker-ui-shadow);border-radius:4px;flex-direction:column;grid-area:panel;align-self:start;gap:12px;padding:12px 16px 16px;display:flex;overflow-y:auto}.playmaker-panel__title{margin:0;font-size:1.15em;font-weight:500}.playmaker-panel__hint{color:var(--_playmaker-ui-text-dim);margin:0;font-size:1em;line-height:1.5}.playmaker-panel__row{align-items:center;gap:8px;display:flex}.playmaker-panel__label{display:contents}.playmaker-panel__row-text{white-space:nowrap;color:var(--_playmaker-ui-text-dim);margin-right:auto}.playmaker-panel__row input,.playmaker-panel__row select{font:inherit;border:1px solid var(--_playmaker-ui-border);background:var(--_playmaker-ui-surface);min-width:0;color:var(--_playmaker-ui-text);border-radius:4px;flex:auto;padding:4px 8px}.playmaker-panel__row input:hover,.playmaker-panel__row select:hover{border-color:var(--_playmaker-ui-text)}.playmaker-root :is(button,input,select):focus-visible{outline:2px solid var(--_playmaker-ui-accent);outline-offset:1px}.playmaker-panel__swatches{flex:none;gap:6px;display:flex}.playmaker-panel__swatches--rows{grid-template-columns:repeat(4,auto);display:grid}.playmaker-panel__swatch{border:1px solid var(--_playmaker-ui-divider);cursor:pointer;border-radius:50%;width:22px;height:22px;padding:0}.playmaker-panel__swatch--outline{background:var(--_playmaker-ui-surface);border-width:3px}.playmaker-panel__swatch[aria-pressed=true]{outline:2px solid var(--_playmaker-ui-accent);outline-offset:2px}.playmaker-panel__reset{flex:none;padding:2px 8px;font-size:.93em}
2
+ /*$vite$:1*/
@@ -0,0 +1,319 @@
1
+ /**
2
+ * 今の PlayData のスキーマの版。スキーマを変えるときは 1 上げ、`PLAY_DATA_MIGRATIONS` に
3
+ * 1 つ前の版から変換する段を足す。
4
+ */
5
+ export declare const CURRENT_PLAY_DATA_VERSION: 2;
6
+
7
+ /** リスナを登録し、購読をやめるための IDisposable を返す。 */
8
+ declare type Event_2<T> = (listener: (e: T) => void) => IDisposable;
9
+ export { Event_2 as Event }
10
+
11
+ /**
12
+ * サイドラインの間の幅。規定は 160 フィート(53⅓ ヤード)だが、中央(26.5)が
13
+ * 0.5 ヤードの格子点に乗るように 53 ヤードへ丸める。本物の寸法との差は 1 フィートで、
14
+ * 図の見た目には出ない。
15
+ */
16
+ export declare const FIELD_WIDTH_YARDS = 53;
17
+
18
+ export declare const FIELD_ZONE_LABELS: {
19
+ readonly "own-redzone": "自陣RZ";
20
+ readonly middle: "中央";
21
+ readonly redzone: "相手RZ";
22
+ };
23
+
24
+ /**
25
+ * フィールドのどの範囲を映すか。
26
+ * - `middle`: センター付近
27
+ * - `redzone`: 相手のゴール側
28
+ * - `own-redzone`: 自陣のゴール側
29
+ */
30
+ export declare const FIELD_ZONE_VALUES: readonly ["own-redzone", "middle", "redzone"];
31
+
32
+ /**
33
+ * フィールド上の位置(ヤード)。縦は LOS(`field.losYard`)からの距離で持つので、
34
+ * ゾーンを切り替えて LOS が動いても、図は形を保ったまま一緒に動く。
35
+ * - lateralYard: 0 = 左サイドライン … FIELD_WIDTH_YARDS = 右サイドライン
36
+ * - downfieldYard: 0 = LOS。正が攻撃方向(画面の上)、負がバックフィールド
37
+ *
38
+ * どちらも GRID_STEP_YARDS の倍数で、モデルの中に格子の外の位置は無い。
39
+ */
40
+ export declare interface FieldPosition {
41
+ readonly lateralYard: number;
42
+ readonly downfieldYard: number;
43
+ }
44
+
45
+ export declare interface FieldState {
46
+ readonly zone: FieldZone;
47
+ /**
48
+ * LOS の絶対ヤード。今はゾーンから決まり、読み込んだデータの値は使わない。
49
+ * 保存するデータから選手の絶対位置を復元できるよう、値としては持たせる。
50
+ */
51
+ readonly losYard: number;
52
+ }
53
+
54
+ export declare type FieldZone = (typeof FIELD_ZONE_VALUES)[number];
55
+
56
+ /** 読み込むと、players を今の図に足す。プリセットのほかに、利用者が作った隊形も渡せる。 */
57
+ export declare interface Formation {
58
+ readonly id: string;
59
+ readonly name: string;
60
+ /** 読み込んだときの選手の配置には影響しない。 */
61
+ readonly side: TeamSide;
62
+ /** 1 人以上。 */
63
+ readonly players: readonly FormationPlayer[];
64
+ }
65
+
66
+ export declare const FORMATION_PRESETS: readonly Formation[];
67
+
68
+ /**
69
+ * 隊形の 1 人。`id` は持たず、読み込むたびに振る。同じ隊形を 2 回読んでも、
70
+ * 図にいる選手とも Undo で戻る選手とも id がぶつからない。
71
+ */
72
+ export declare type FormationPlayer = Omit<Player, "id">;
73
+
74
+ export declare function getFormationPreset(id: string): Formation | undefined;
75
+
76
+ export declare function getPlayPreset(id: string): PlayPreset | undefined;
77
+
78
+ /**
79
+ * 位置を置ける格子の刻み(ヤード)。横はサイドライン、縦は LOS を原点にする。
80
+ * 図の中の位置はすべてこの格子点にあるので、要素同士を揃える操作が無くても縦横が揃う。
81
+ */
82
+ export declare const GRID_STEP_YARDS = 0.5;
83
+
84
+ export declare interface IDisposable {
85
+ dispose(): void;
86
+ }
87
+
88
+ export declare interface ImageExportOptions {
89
+ /**
90
+ * PNG の幅(px)。高さはゾーンの窓の縦横比から決める。
91
+ * 未指定、有限でない値、1 未満は 1600 にし、4096 を超える幅は 4096 に切り詰める。
92
+ */
93
+ width?: number | undefined;
94
+ }
95
+
96
+ /**
97
+ * 1 本の線。起点は座標ではなく選手の id で持つので、選手を動かすと線の起点も付いてくる。
98
+ * `color` と `thickness` を省くと、テーマの色と種別ごとの既定の太さで描く。
99
+ */
100
+ export declare interface Line {
101
+ readonly id: string;
102
+ readonly kind: LineKind;
103
+ /** 起点となる選手の id。実在しない参照は復元時に除外される。 */
104
+ readonly startPlayerId: string;
105
+ /** 起点と終点の間の中継点(0 個可)。 */
106
+ readonly waypoints: readonly FieldPosition[];
107
+ /** 終点(ヤード空間)。 */
108
+ readonly end: FieldPosition;
109
+ readonly interpolation: LineInterpolation;
110
+ /** CSS の色の文字列。 */
111
+ readonly color?: string;
112
+ /** 種別ごとの既定の太さに対する倍率。省くと DEFAULT_LINE_THICKNESS。 */
113
+ readonly thickness?: number;
114
+ }
115
+
116
+ /**
117
+ * 線の補間方法。どの種別の線にも効く。
118
+ * - `straight`: 制御点を直線で結ぶ
119
+ * - `bezier`: 制御点をすべて通る滑らかな曲線で結ぶ
120
+ */
121
+ declare const LINE_INTERPOLATION_VALUES: readonly ["straight", "bezier"];
122
+
123
+ /**
124
+ * 線の種別。色ではなく終点の記法と線種で見分ける。
125
+ * - `route`: レシーバーやランナーの走路。終点に矢印を描く
126
+ * - `block`: ブロックの割り当て。route と同じ太さで、終点に T 字のバーを描く
127
+ * - `motion`: スナップ前の選手の移動。破線で、終点に矢印を描く
128
+ */
129
+ declare const LINE_KIND_VALUES: readonly ["route", "block", "motion"];
130
+
131
+ export declare type LineInterpolation = (typeof LINE_INTERPOLATION_VALUES)[number];
132
+
133
+ export declare type LineKind = (typeof LINE_KIND_VALUES)[number];
134
+
135
+ /**
136
+ * どの版で保存したデータでも、今の版の PlayData にする。壊れたデータを渡しても投げない。
137
+ * 返り値は新しいオブジェクトで、入力と参照を共有しない。
138
+ * 選手、線、waypoint は MAX_PLAYERS、MAX_LINES、MAX_WAYPOINTS_PER_LINE の個数までしか読まない。
139
+ */
140
+ export declare function migratePlayData(raw: unknown): PlayData;
141
+
142
+ export declare const PLAY_PRESETS: readonly PlayPreset[];
143
+
144
+ /** プレーの種類。色は持たず、一覧でどう見せるかは使う側が決める。 */
145
+ export declare type PlayCategory = "run-zone" | "run-gap" | "pass-quick" | "pass-dropback" | "pass-deep" | "pa" | "rpo" | "coverage" | "pressure";
146
+
147
+ /**
148
+ * プレー図のデータ。保存したものを `restorePlayData` に渡すと、古い版や版の無いもの、
149
+ * 新しい版のものも今の版に寄せて読む。
150
+ */
151
+ export declare interface PlayData {
152
+ readonly version: typeof CURRENT_PLAY_DATA_VERSION;
153
+ readonly field: FieldState;
154
+ /** 後の要素ほど上に重ねて描く。 */
155
+ readonly players: readonly Player[];
156
+ /** 後の要素ほど上に重ねて描く。 */
157
+ readonly lines: readonly Line[];
158
+ }
159
+
160
+ /**
161
+ * 型付きで組み立てて読み込む図。LOS の位置は読み込むときにゾーンから決め直すので、
162
+ * `field.losYard` は省略できる。
163
+ */
164
+ export declare interface PlayDataInput extends Omit<PlayData, "field"> {
165
+ readonly field: Omit<FieldState, "losYard"> & {
166
+ readonly losYard?: number | undefined;
167
+ };
168
+ }
169
+
170
+ /**
171
+ * 1 人の選手。`color` は CSS の色の文字列で、省くとテーマの色で描く。
172
+ * `fill` を省くと DEFAULT_PLAYER_FILL で描く。
173
+ */
174
+ export declare interface Player {
175
+ readonly id: string;
176
+ readonly position: FieldPosition;
177
+ readonly shape: PlayerShape;
178
+ readonly label: string;
179
+ readonly color?: string;
180
+ readonly fill?: PlayerFill;
181
+ }
182
+
183
+ /**
184
+ * 選手マーカーの塗り。枠線だけ(`outline`)か、色で塗りつぶす(`solid`)か。
185
+ * 形状とは独立に持ち、攻守や役割の見分けに使う。パネルはこの順にスウォッチを並べる。
186
+ */
187
+ declare const PLAYER_FILL_VALUES: readonly ["outline", "solid"];
188
+
189
+ /**
190
+ * 選手マーカーの形状。種類が多いと図が散らかるので、丸と四角の 2 種だけにする。
191
+ * どちらも外接円を当たり判定にできるので、hit-test は形状で分けない。
192
+ */
193
+ declare const PLAYER_SHAPE_VALUES: readonly ["circle", "square"];
194
+
195
+ export declare type PlayerFill = (typeof PLAYER_FILL_VALUES)[number];
196
+
197
+ export declare type PlayerShape = (typeof PLAYER_SHAPE_VALUES)[number];
198
+
199
+ /**
200
+ * container の中にプレー図を描き、edit モードでは編集 UI も置く。
201
+ * dispose すると、置いた要素をすべて取り除く。
202
+ * dispose したあとの変更は例外を投げずに何もせず、開発時だけ console.warn で知らせる。
203
+ * getPlayData と fieldZone は、dispose した時点の図を返す。
204
+ */
205
+ export declare class Playmaker implements IDisposable {
206
+ /**
207
+ * 編集コマンドと Undo / Redo の確定ごとに 1 回、最新の図の深いコピーを渡す。
208
+ * `version` は常に現行なので、受け取った値をそのまま永続化できる。
209
+ * 構築時、`setPlayData` と `restorePlayData` での読み込み、PNG の書き出しでは発火しない
210
+ * (読み込みは編集ではないため)。
211
+ * コピーはリスナごとに作るので、受け手が書き換えても、この図とほかのリスナには波及しない。
212
+ * 返り値を dispose すると購読をやめる。
213
+ */
214
+ readonly onDidChange: Event_2<PlayData>;
215
+ private readonly store;
216
+ private readonly root;
217
+ private readonly surface;
218
+ private readonly session;
219
+ private currentMode;
220
+ private panel;
221
+ private ui;
222
+ constructor(container: HTMLElement, options?: PlaymakerOptions);
223
+ get mode(): PlaymakerMode;
224
+ /**
225
+ * モードを切り替える。図と Undo の履歴は残し、編集 UI とポインタ、キーの入力だけを付け外しする。
226
+ * view にすると、ドラッグや作図の途中の操作は取り消し、選択の強調も描かない。
227
+ */
228
+ setMode(mode: PlaymakerMode): void;
229
+ get fieldZone(): FieldZone;
230
+ /**
231
+ * LOS をそのゾーンの既定の位置へ移し、選手と線も一緒に動かす。
232
+ * 編集なので Undo と onDidChange の対象になる。view モードでも呼べる。
233
+ */
234
+ setFieldZone(zone: FieldZone): void;
235
+ /**
236
+ * 隊形の選手を今の図に追記し、置いたら true を返す。攻守の隊形を順に重ねられる。
237
+ * 選手の位置は LOS からの相対(`lateralYard` と `downfieldYard`)で書く。
238
+ * 外から渡した隊形は正規化してから読むので、位置の読めない選手は捨てる。
239
+ * 置ける選手が 1 人もいないときと、置くと選手が 64 人を超えるときは、1 人も置かずに false を返す。
240
+ * 編集なので Undo と onDidChange の対象になる。view モードでも呼べる。
241
+ */
242
+ loadFormation(formation: Formation): boolean;
243
+ /**
244
+ * 型付きで組み立てた図を読み込み、今の図と置き換える。`getPlayData` の戻り値や、
245
+ * プリセットの `data` もそのまま渡せる。
246
+ * 型に合っていても、重複した id と件数の上限を超えた分は `restorePlayData` と同じく正規化する。
247
+ * 読み込みは編集ではないので、Undo の履歴は消え、onDidChange は発火しない。
248
+ */
249
+ setPlayData(data: PlayDataInput): void;
250
+ /**
251
+ * 永続化しておいた値を、形を確かめずに受け取って読み込み、今の図と置き換える。
252
+ * 旧版、版の無いもの、未来版、壊れたデータも、例外を投げずに今のスキーマへ寄せ、読めない要素だけを捨てる。
253
+ * 選手 64 人、線 128 本、線 1 本あたり waypoint 32 個を超える分は、先頭から上限までを残して捨てる。
254
+ * 読み込みは編集ではないので、Undo の履歴は消え、onDidChange は発火しない。
255
+ */
256
+ restorePlayData(raw: unknown): void;
257
+ /**
258
+ * 今の図の深いコピー。`version` は常に現行で、そのまま JSON にして永続化できる。
259
+ * `restorePlayData` か `initialData` に戻すと、同じ図になる。
260
+ * 編集でも件数の上限は超えられず、上限に達すると選手の追加、フォーメーションの読み込み、作図は何もしない。
261
+ */
262
+ getPlayData(): PlayData;
263
+ /**
264
+ * 呼んだ時点で確定しているプレー図を PNG 画像(Blob)として書き出す。
265
+ * 選択の強調、waypoint のハンドル、ドラッグや作図の途中の形、ツールバーとパネルは入らない。
266
+ * view と edit のどちらのモードでも使える。
267
+ * 同梱フォントを読み込み終えてから描くので、構築の直後に呼んでもヤードの数字と選手のラベルは同梱フォントになる。
268
+ * フォントを読み込めなかったときは代わりのフォントで描く。
269
+ * canvas を確保できないとき、PNG に変換できないとき、dispose したあとは、例外を投げずに reject する。
270
+ */
271
+ exportToPng(options?: ImageExportOptions): Promise<Blob>;
272
+ /**
273
+ * 図とパネルの色を、テーマの CSS 変数から読み直す。CSS 変数を変えてもブラウザは知らせてこないので、
274
+ * ホストが祖先の要素で変数を変えたあとに呼ぶ。
275
+ */
276
+ refresh(): void;
277
+ dispose(): void;
278
+ /** dispose したあとの呼び出しは何もしないので、開発時だけそのことを知らせる。 */
279
+ private warnIgnoredAfterDispose;
280
+ private replaceUi;
281
+ private createUi;
282
+ private draw;
283
+ /** view モードでは undefined を返し、格子や選択の強調のような編集中だけの層を描かせない。 */
284
+ private surfaceOverlay;
285
+ }
286
+
287
+ export declare type PlaymakerMode = "view" | "edit";
288
+
289
+ export declare interface PlaymakerOptions {
290
+ /**
291
+ * 最初のモード。既定は "edit"。"view" は編集 UI を置かず、ポインタとキーの操作も受けない。
292
+ * あとから `setMode` で切り替えられる。
293
+ */
294
+ mode?: PlaymakerMode | undefined;
295
+ /** 最初に表示する図。`restorePlayData` と同じく、形を確かめずに受け取って今のスキーマへ寄せる。 */
296
+ initialData?: unknown;
297
+ /** 構築時に `onDidChange` へ登録するリスナ。解除するには Playmaker を dispose する。 */
298
+ onChange?: ((data: PlayData) => void) | undefined;
299
+ }
300
+
301
+ /** 線まで描き込んだプレー図に、一覧に出すための情報を添えたもの。 */
302
+ export declare interface PlayPreset {
303
+ readonly id: string;
304
+ readonly name: string;
305
+ readonly side: TeamSide;
306
+ readonly category: PlayCategory;
307
+ /** パーソネルか隊形の短い注記(例: "11 pers"、"Nickel")。 */
308
+ readonly personnel: string;
309
+ /** コンセプトの 1 行の説明。 */
310
+ readonly summary: string;
311
+ /** そのまま setPlayData に渡せる。 */
312
+ readonly data: PlayData;
313
+ }
314
+
315
+ declare const TEAM_SIDE_VALUES: readonly ["offense", "defense"];
316
+
317
+ export declare type TeamSide = (typeof TEAM_SIDE_VALUES)[number];
318
+
319
+ export { }