@khorsheed/dsh-game 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.
Files changed (99) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.en.md +53 -0
  3. package/README.i18n.yaml +6 -0
  4. package/README.md +52 -2
  5. package/cordis.patch.yml +23 -0
  6. package/lib/client.js +30348 -0
  7. package/lib/index.js +4154 -0
  8. package/lib/typert.host.d.ts +3 -0
  9. package/lib/typert.host.js +3769 -0
  10. package/lib/typert.remote-client.d.ts +101 -0
  11. package/lib/typert.remote-client.js +2082 -0
  12. package/lib/types/agent.d.ts +20 -0
  13. package/lib/types/agent.js +42 -0
  14. package/lib/types/checks.d.ts +44 -0
  15. package/lib/types/checks.js +267 -0
  16. package/lib/types/client/DesignView.d.ts +22 -0
  17. package/lib/types/client/DesignView.js +134 -0
  18. package/lib/types/client/ElementsView.d.ts +21 -0
  19. package/lib/types/client/ElementsView.js +187 -0
  20. package/lib/types/client/GameTab.d.ts +14 -0
  21. package/lib/types/client/GameTab.js +256 -0
  22. package/lib/types/client/PlayFrame.d.ts +54 -0
  23. package/lib/types/client/PlayFrame.js +129 -0
  24. package/lib/types/client/PlayView.d.ts +19 -0
  25. package/lib/types/client/PlayView.js +161 -0
  26. package/lib/types/client/Preview3D.d.ts +50 -0
  27. package/lib/types/client/Preview3D.js +176 -0
  28. package/lib/types/client/ProjectSwitcher.d.ts +20 -0
  29. package/lib/types/client/ProjectSwitcher.js +75 -0
  30. package/lib/types/client/Recipe3DEditor.d.ts +19 -0
  31. package/lib/types/client/Recipe3DEditor.js +44 -0
  32. package/lib/types/client/StyleGallery.d.ts +18 -0
  33. package/lib/types/client/StyleGallery.js +27 -0
  34. package/lib/types/client/TurnCard.d.ts +62 -0
  35. package/lib/types/client/TurnCard.js +100 -0
  36. package/lib/types/client/VersionsView.d.ts +17 -0
  37. package/lib/types/client/VersionsView.js +68 -0
  38. package/lib/types/client/chat-node.d.ts +42 -0
  39. package/lib/types/client/chat-node.js +77 -0
  40. package/lib/types/client/contract.d.ts +125 -0
  41. package/lib/types/client/contract.js +6 -0
  42. package/lib/types/client/definition.d.ts +22 -0
  43. package/lib/types/client/definition.js +28 -0
  44. package/lib/types/client/index.d.ts +21 -0
  45. package/lib/types/client/index.js +229 -0
  46. package/lib/types/client/locales.d.ts +376 -0
  47. package/lib/types/client/locales.js +727 -0
  48. package/lib/types/client/looks.d.ts +36 -0
  49. package/lib/types/client/looks.js +105 -0
  50. package/lib/types/client/markdown.d.ts +11 -0
  51. package/lib/types/client/markdown.js +52 -0
  52. package/lib/types/client/preset-visibility.d.ts +94 -0
  53. package/lib/types/client/preset-visibility.js +115 -0
  54. package/lib/types/client/preview-entry.d.ts +24 -0
  55. package/lib/types/client/preview-entry.js +107 -0
  56. package/lib/types/client/refs.d.ts +36 -0
  57. package/lib/types/client/refs.js +44 -0
  58. package/lib/types/client/style-samples.d.ts +5 -0
  59. package/lib/types/client/style-samples.js +196 -0
  60. package/lib/types/fsutil.d.ts +26 -0
  61. package/lib/types/fsutil.js +104 -0
  62. package/lib/types/hooks.d.ts +83 -0
  63. package/lib/types/hooks.js +108 -0
  64. package/lib/types/index.d.ts +30 -0
  65. package/lib/types/index.js +22 -0
  66. package/lib/types/kits/canvas2d.d.ts +6 -0
  67. package/lib/types/kits/canvas2d.js +60 -0
  68. package/lib/types/kits/ids.d.ts +11 -0
  69. package/lib/types/kits/ids.js +6 -0
  70. package/lib/types/kits/index.d.ts +26 -0
  71. package/lib/types/kits/index.js +28 -0
  72. package/lib/types/kits/three3d.d.ts +12 -0
  73. package/lib/types/kits/three3d.js +188 -0
  74. package/lib/types/kits/types.d.ts +52 -0
  75. package/lib/types/kits/types.js +6 -0
  76. package/lib/types/look3d.d.ts +20 -0
  77. package/lib/types/look3d.js +175 -0
  78. package/lib/types/panel-session.d.ts +21 -0
  79. package/lib/types/panel-session.js +16 -0
  80. package/lib/types/project.d.ts +132 -0
  81. package/lib/types/project.js +494 -0
  82. package/lib/types/remote.d.ts +182 -0
  83. package/lib/types/remote.js +256 -0
  84. package/lib/types/skills.d.ts +13 -0
  85. package/lib/types/skills.js +140 -0
  86. package/lib/types/store.d.ts +325 -0
  87. package/lib/types/store.js +1285 -0
  88. package/lib/types/tools.d.ts +12 -0
  89. package/lib/types/tools.js +301 -0
  90. package/lib/types/trash.d.ts +5 -0
  91. package/lib/types/trash.js +64 -0
  92. package/lib/types/types.d.ts +522 -0
  93. package/lib/types/types.js +85 -0
  94. package/lib/types/vfs.d.ts +92 -0
  95. package/lib/types/vfs.js +217 -0
  96. package/locale/en.json +6 -0
  97. package/locale/zh.json +6 -0
  98. package/package.json +132 -3
  99. package/runtime/dsh3d.js +1279 -0
@@ -0,0 +1,522 @@
1
+ /**
2
+ * Wire and storage shapes shared by the host half, the Remote face and the
3
+ * browser half. Pure types and constants — no node imports, so the client
4
+ * type program includes this file as-is.
5
+ * @module @khorsheed/dsh-game/types
6
+ */
7
+ /** The project manifest's file name, at the project root. */
8
+ import type { KitRef } from './kits/types.ts';
9
+ export declare const MANIFEST_FILE = "game.json";
10
+ /** The plugin's own directory inside a project (snapshots, check results, logs). */
11
+ export declare const STATE_DIR = ".game";
12
+ /** One art style the gate accepts: a stable id, its label, a one-line look and its palette. */
13
+ export interface ArtStyle {
14
+ readonly id: string;
15
+ readonly label: string;
16
+ readonly look: string;
17
+ /** The style's palette: element looks and the pixel editor draw from it. */
18
+ readonly palette: readonly string[];
19
+ }
20
+ /**
21
+ * The example styles the user picks from (decision D10). Without image
22
+ * generation the game draws everything in code, so each style is one a
23
+ * canvas/HTML game can render faithfully; `custom:<text>` covers the rest.
24
+ */
25
+ export declare const ART_STYLES: readonly ArtStyle[];
26
+ /**
27
+ * The 3D example styles (the 3d-three kit, proposal 2026-10-21-game-3d G8):
28
+ * toon shading with an ink outline over a paper ground. The ids are what
29
+ * `dsh3d.createWorld({ style })` takes.
30
+ */
31
+ export declare const ART_STYLES_3D: readonly ArtStyle[];
32
+ /**
33
+ * A 3D project's rendering style as data (`game.json` `style3d`): the model
34
+ * writes it from the user's own description; `preset` names the built-in
35
+ * starting point (`ink` / `qinglv`) the other keys override. dsh3d applies
36
+ * it at `createWorld`.
37
+ */
38
+ export interface Style3D {
39
+ readonly preset?: string;
40
+ readonly bg?: string;
41
+ readonly ground?: string;
42
+ readonly ground2?: string;
43
+ readonly water?: string;
44
+ readonly outline?: string;
45
+ /** Outline thickness in world units; 0 turns the ink line off. */
46
+ readonly outlineWidth?: number;
47
+ /** Toon shading bands (2 = hard cel, 5 = soft). */
48
+ readonly shades?: number;
49
+ /** Fog start and end distance. */
50
+ readonly fog?: readonly [number, number];
51
+ /** Sun intensity. */
52
+ readonly light?: number;
53
+ /** The sun casts shadows (game-wide; off unless set). */
54
+ readonly shadows?: boolean;
55
+ /** Rim light on toon surfaces (0 = off … 2), and its color. */
56
+ readonly rim?: number;
57
+ readonly rimColor?: string;
58
+ /**
59
+ * Per-scene overrides, keyed by the game's own scene names (dsh3d
60
+ * `enterScene(name)`): background, ground colors, water, fog and light.
61
+ * Shading bands and the outline stay global.
62
+ */
63
+ readonly scenes?: Readonly<Record<string, SceneStyle3D>>;
64
+ }
65
+ /** What one scene may override in `style3d`. */
66
+ export interface SceneStyle3D {
67
+ readonly bg?: string;
68
+ readonly ground?: string;
69
+ readonly ground2?: string;
70
+ readonly water?: string;
71
+ readonly fog?: readonly [number, number];
72
+ readonly light?: number;
73
+ }
74
+ /** The project manifest (`game.json`). Everything but id/title is the agent's to fill over time. */
75
+ export interface GameManifest {
76
+ readonly schema: 1;
77
+ readonly id: string;
78
+ readonly title: string;
79
+ /** The one-pager's core: what the player does and why it is fun, in a sentence or two. */
80
+ readonly pitch: string;
81
+ /** Element categories the game has (角色 / 敌人 / 道具 …); element files declare one of these. */
82
+ readonly elementTypes: readonly string[];
83
+ /** An {@link ART_STYLES} id, or `custom:<description>`. */
84
+ readonly artStyle: string;
85
+ /** Design pillars, pinned at the top of the design doc. */
86
+ readonly pillars: readonly string[];
87
+ /** Passing candidates deploy into the play area without a click (default on, decision D6). */
88
+ readonly autoConfirm: boolean;
89
+ /** The tunable numbers the 试玩 drawer shows; `value` is the finalized default. */
90
+ readonly params: readonly GameParam[];
91
+ /** The palette element looks draw from (the style's, unless the agent set its own). */
92
+ readonly palette: readonly string[];
93
+ readonly createdAt: string;
94
+ /** The runtime kit the project is pinned to; absent = `2d-canvas` v1 (projects made before kits). */
95
+ readonly runtime?: KitRef;
96
+ /** 3D projects: the rendering style as data (see {@link Style3D}). */
97
+ readonly style3d?: Style3D;
98
+ }
99
+ /** One tunable number (`game.json` `params[]`); the game reads it from `window.dshParams[key]` every frame. */
100
+ export interface GameParam {
101
+ readonly key: string;
102
+ readonly label: string;
103
+ readonly min: number;
104
+ readonly max: number;
105
+ readonly step: number;
106
+ readonly value: number;
107
+ readonly unit?: string;
108
+ }
109
+ /**
110
+ * An element's appearance (`look` in an element file): pixel rows per
111
+ * state. Each row is a string; `.` is transparent, `0-9a-z` index the
112
+ * look's own `palette` (base 36).
113
+ */
114
+ export interface ElementLook {
115
+ readonly palette: readonly string[];
116
+ readonly states: Readonly<Record<string, readonly string[]>>;
117
+ }
118
+ /** Body archetypes a `parts3d` look builds on. */
119
+ export declare const BODY_BASES: readonly ["quadruped", "bird", "fish", "serpent", "humanoid"];
120
+ export type BodyBase = typeof BODY_BASES[number];
121
+ /** Built-in parts a `parts3d` look can attach; a project can register more with `dsh3d.definePart`. */
122
+ export declare const PART_TYPES: readonly ["ear", "horn", "tail", "wing", "fin", "eye", "face"];
123
+ export type PartType = typeof PART_TYPES[number];
124
+ /** One part of a `parts3d` look; sizes are in body units (body length ≈ 1). */
125
+ export interface PartSpec {
126
+ readonly type: PartType | (string & {});
127
+ readonly count?: number;
128
+ readonly size?: number;
129
+ readonly length?: number;
130
+ /** Spread of a multi-part fan (tails, wings), degrees. */
131
+ readonly fan?: number;
132
+ readonly thickness?: number;
133
+ /** A `palette` key or a `#rrggbb` color. */
134
+ readonly color?: string;
135
+ /** `face` only: `human` gives a human face. */
136
+ readonly style?: string;
137
+ /** A project-defined part's own parameters (anything beyond the shared keys). */
138
+ readonly extra?: Readonly<Record<string, number | string>>;
139
+ }
140
+ /** One procedural motion: amplitude (degrees, or a fraction for breath/bob) and period (seconds). */
141
+ export interface MotionSpec {
142
+ readonly amplitude?: number;
143
+ readonly period?: number;
144
+ }
145
+ /**
146
+ * A 3D look built from a parts recipe: a body archetype, its proportions,
147
+ * attached parts, a named palette and procedural motions. The 3d-three kit's
148
+ * `dsh3d.build` turns it into a model; bodies and parts are an open set (a
149
+ * project registers its own with `defineBase` / `definePart`).
150
+ */
151
+ export interface Parts3DLook {
152
+ readonly kind: 'parts3d';
153
+ /** A built-in {@link BodyBase} or a body the project registers with `dsh3d.defineBase`. */
154
+ readonly base: BodyBase | (string & {});
155
+ readonly proportions: Readonly<Record<string, number>>;
156
+ readonly parts: readonly PartSpec[];
157
+ /** Named colors: `body`, `accent`, `eye`, `belly`… */
158
+ readonly palette: Readonly<Record<string, string>>;
159
+ /** `tailSway`, `breath`, `flap`, `swim`, `bob`. */
160
+ readonly motion: Readonly<Record<string, MotionSpec>>;
161
+ /** Overall size in world units (default 1). */
162
+ readonly scale?: number;
163
+ /** The panel's default view of it. */
164
+ readonly preview?: PreviewAngle;
165
+ /** Refine-path (Blender) knobs; ignored by the live builder. */
166
+ readonly refine?: Readonly<Record<string, number>>;
167
+ }
168
+ /** A 3D look loaded from a project glTF file; `recipe` keeps the parts it was baked from. */
169
+ export interface GltfLook {
170
+ readonly kind: 'gltf';
171
+ /** Project-relative path to a `.glb` / `.gltf`. */
172
+ readonly src: string;
173
+ readonly scale?: number;
174
+ /** `toon` (default): the style's toon shading over the model's colors, vertex colors and textures; `original`: its own materials. */
175
+ readonly material?: 'toon' | 'original';
176
+ /** Ink outline around the model (default: on with toon, off with original). */
177
+ readonly outline?: boolean;
178
+ /** The clip that plays on its own (default: one named idle / 待机 / stand, else the first). */
179
+ readonly animation?: string;
180
+ /** The panel's default view of it. */
181
+ readonly preview?: PreviewAngle;
182
+ /** Base color by the model's material name (`{ "冠": "#c9a23a" }`). */
183
+ readonly tint?: Readonly<Record<string, string>>;
184
+ /** Per bone (by name): a scale (one number or x/y/z) and a rotation offset in degrees, on top of any animation. */
185
+ readonly bones?: Readonly<Record<string, BoneTweak>>;
186
+ /** Shape-key weights by name (`{ "smile": 0.6 }`). */
187
+ readonly morphs?: Readonly<Record<string, number>>;
188
+ readonly recipe?: Parts3DLook;
189
+ }
190
+ /** One bone's tweak in a glTF look. */
191
+ export interface BoneTweak {
192
+ readonly scale?: number | readonly [number, number, number];
193
+ readonly rotate?: readonly [number, number, number];
194
+ }
195
+ /** A preview angle in degrees: yaw 0 looks at the face (models face +x), 90 from the side, 180 from behind; pitch looks down. */
196
+ export interface PreviewAngle {
197
+ readonly yaw?: number;
198
+ readonly pitch?: number;
199
+ }
200
+ /** Any 3D look. */
201
+ export type Look3D = Parts3DLook | GltfLook;
202
+ /** Any look a kit may accept: 2D pixel rows or a 3D look. */
203
+ export type AnyLook = ElementLook | Look3D;
204
+ /** Whether a look is the 2D pixel-row kind. */
205
+ export declare function isPixelLook(look: AnyLook): look is ElementLook;
206
+ /** The characters a look row may use, in palette-index order. */
207
+ export declare const LOOK_CHARS = "0123456789abcdefghijklmnopqrstuvwxyz";
208
+ /** One design-doc chapter. `generated` chapters are written by the plugin, never by hand. */
209
+ export interface ChapterSpec {
210
+ readonly id: string;
211
+ readonly title: string;
212
+ readonly file: string;
213
+ readonly generated?: boolean;
214
+ }
215
+ /** The chaptered design doc (decision D12): fixed chapters, pillars pinned first. */
216
+ export declare const CHAPTERS: readonly ChapterSpec[];
217
+ /** A chapter's state: nothing yet, being written, or marked final with a `状态:定稿` line. */
218
+ export type ChapterStatus = 'todo' | 'draft' | 'done';
219
+ /** One chapter as the panel shows it. */
220
+ export interface ChapterView {
221
+ readonly id: string;
222
+ readonly title: string;
223
+ readonly file: string;
224
+ readonly status: ChapterStatus;
225
+ readonly text: string;
226
+ readonly generated: boolean;
227
+ /** Last-modified time (ms) of the chapter's source, 0 when unknown. */
228
+ readonly mtime: number;
229
+ }
230
+ /** One element file (`elements/*.json`) after validation. */
231
+ export interface ElementView {
232
+ readonly file: string;
233
+ /** Position inside the file when it holds an array, else -1. */
234
+ readonly index: number;
235
+ readonly id: string;
236
+ readonly type: string;
237
+ readonly name: string;
238
+ /** Every other top-level scalar, for the numbers table and the field editor. */
239
+ readonly stats: Readonly<Record<string, string | number | boolean>>;
240
+ /** The 2D pixel look, if the element has one. */
241
+ readonly look: ElementLook | null;
242
+ /** The 3D look, if the element has one (3d-three projects). */
243
+ readonly look3d: Look3D | null;
244
+ /** The 设定 text (the element's `lore` field): who it is, its temper, how it meets the player. '' when unwritten. */
245
+ readonly lore: string;
246
+ }
247
+ /** Longest 设定 the panel saves. */
248
+ export declare const LORE_MAX = 2000;
249
+ /** What 提交为新版本 did. */
250
+ export type CommitResult = {
251
+ readonly ok: true;
252
+ readonly kind: 'deployed' | 'candidate';
253
+ readonly version: number;
254
+ } | {
255
+ readonly ok: true;
256
+ readonly kind: 'failed';
257
+ readonly failures: readonly {
258
+ readonly where: string;
259
+ readonly message: string;
260
+ }[];
261
+ } | {
262
+ readonly ok: true;
263
+ readonly kind: 'unchanged' | 'no-entry';
264
+ };
265
+ /** One appearance proposal set from `game_propose`: up to 3 variants, the user picks one. */
266
+ export interface LookProposal {
267
+ readonly elementId: string;
268
+ readonly at: string;
269
+ readonly request: string;
270
+ readonly variants: readonly {
271
+ readonly label: string;
272
+ readonly note: string;
273
+ readonly look: AnyLook;
274
+ }[];
275
+ /** Index the user picked, once picked. */
276
+ readonly picked?: number;
277
+ }
278
+ /**
279
+ * The opening of the message the panel writes into the composer for its
280
+ * changes (「写进对话」). The pre-step hook recognizes a sent message by it and
281
+ * clears exactly the changes the message lists.
282
+ */
283
+ export declare const PANEL_CHANGES_MARK = "\u3010\u9762\u677F\u6539\u52A8\u3011";
284
+ /** One net change the user made in the panel and has not yet sent to the agent. */
285
+ export interface PendingChange {
286
+ /** Stable key so repeated edits of one thing collapse into one entry (`param:speed`, `look:fog`, `design:core-loop`). */
287
+ readonly key: string;
288
+ /** Short label for the dock and the model (`参数 移动速度 1.4→1.8`). */
289
+ readonly text: string;
290
+ }
291
+ /** One check failure, already worded for the model and the panel. */
292
+ export interface CheckFailure {
293
+ /** `smoke`, `data`, or the test file's project-relative path. */
294
+ readonly where: string;
295
+ readonly message: string;
296
+ }
297
+ /** One check run's result, persisted at `.game/checks.json`. */
298
+ export interface CheckRecord {
299
+ readonly fingerprint: string;
300
+ readonly at: string;
301
+ readonly ok: boolean;
302
+ readonly failures: readonly CheckFailure[];
303
+ /** Test cases that ran and passed. */
304
+ readonly passed: number;
305
+ /** Why the browser part did not run (no Chrome found, say); the data part still did. */
306
+ readonly skipped?: string;
307
+ /** The automatic fix round this run belongs to (1-based), 0 when not steered. */
308
+ readonly attempt: number;
309
+ /** Set when the fix cap was hit and the plugin stopped steering. */
310
+ readonly gaveUp?: boolean;
311
+ }
312
+ /** A deployed (or candidate) version. */
313
+ export interface VersionRecord {
314
+ readonly version: number;
315
+ readonly at: string;
316
+ readonly fingerprint: string;
317
+ /** Who cut it: the user (检查并发版 / 提交), the agent (\`game_publish\`), or the end-of-turn check. Absent on older versions. */
318
+ readonly by?: VersionSource;
319
+ /** One line about what changed (the turn's last words, or the plugin's own note). */
320
+ readonly note?: string;
321
+ }
322
+ /** Who cut a version. */
323
+ export type VersionSource = 'user' | 'agent' | 'turn';
324
+ /** What the working files hold that the play area does not (the panel's 有新改动还没进游戏 bar). */
325
+ export interface WorkingChanges {
326
+ /** The version compared against (the waiting candidate, else the live one); null before any. */
327
+ readonly against: number | null;
328
+ readonly hasEntry: boolean;
329
+ /** Build files added, changed or removed (first 30 of \`count\`). */
330
+ readonly count: number;
331
+ readonly files: readonly {
332
+ readonly path: string;
333
+ readonly kind: 'added' | 'changed' | 'removed';
334
+ }[];
335
+ /** The newest change's time. */
336
+ readonly lastAt: string | null;
337
+ /** Someone is still writing: a bound session's turn is running, or a file changed in the last 20 s. */
338
+ readonly busy: 'turn' | 'recent' | null;
339
+ /** The panel edits among them. */
340
+ readonly edits: readonly PendingChange[];
341
+ /** The last check ran after the newest change and failed: its findings. */
342
+ readonly failed: readonly {
343
+ readonly where: string;
344
+ readonly message: string;
345
+ }[] | null;
346
+ }
347
+ /** A version's place in the history. */
348
+ export type VersionStatus = 'current' | 'candidate' | 'rejected' | 'past';
349
+ /** One row of the 版本 view. */
350
+ export interface VersionRow extends VersionRecord {
351
+ readonly status: VersionStatus;
352
+ /** Test cases that passed when this version was checked. */
353
+ readonly passed?: number;
354
+ }
355
+ /** Files that differ between two versions. */
356
+ export interface VersionDiff {
357
+ readonly added: readonly string[];
358
+ readonly removed: readonly string[];
359
+ readonly changed: readonly string[];
360
+ }
361
+ /** One playtest-log line. */
362
+ export interface LogEntry {
363
+ readonly at: string;
364
+ readonly text: string;
365
+ }
366
+ /** A project row in the deployment-level registry. */
367
+ export interface ProjectRow {
368
+ readonly id: string;
369
+ readonly title: string;
370
+ readonly root: string;
371
+ readonly createdAt: string;
372
+ readonly updatedAt: string;
373
+ }
374
+ /** What one agent turn changed in the bound project (the turn-tail card). */
375
+ export interface TurnReport {
376
+ readonly turn: number;
377
+ readonly projectId: string;
378
+ readonly title: string;
379
+ readonly at: string;
380
+ /** A version that became live (or a candidate) during the turn. */
381
+ readonly version: {
382
+ readonly kind: 'deployed' | 'candidate';
383
+ readonly version: number;
384
+ } | null;
385
+ /** The turn's end-of-turn check, when one ran. */
386
+ readonly check: {
387
+ readonly ok: boolean;
388
+ readonly fixes: number;
389
+ readonly gaveUp: boolean;
390
+ readonly passed: number;
391
+ readonly failures: number;
392
+ } | null;
393
+ readonly elements: readonly {
394
+ readonly id: string;
395
+ readonly name: string;
396
+ readonly what: 'new' | 'removed' | 'look' | 'fields';
397
+ readonly fields?: readonly string[];
398
+ /** 3D looks before and after the turn (JSON), for the card's side-by-side previews. */
399
+ readonly looks?: {
400
+ readonly before: string | null;
401
+ readonly after: string;
402
+ };
403
+ }[];
404
+ readonly chapters: readonly {
405
+ readonly id: string;
406
+ readonly title: string;
407
+ }[];
408
+ readonly params: readonly {
409
+ readonly key: string;
410
+ readonly label: string;
411
+ readonly from?: number;
412
+ readonly to: number;
413
+ }[];
414
+ /** Other changed source files (code, assets, index.html). */
415
+ readonly code: readonly string[];
416
+ readonly tests: readonly string[];
417
+ }
418
+ /** One project as the switcher shows it. */
419
+ export interface ProjectCard {
420
+ readonly id: string;
421
+ readonly title: string;
422
+ readonly root: string;
423
+ readonly updatedAt: string;
424
+ readonly pitch: string;
425
+ readonly artStyle: string;
426
+ readonly version: number | null;
427
+ readonly elements: number;
428
+ /** The last check's screenshot (webp, base64), when there is one. */
429
+ readonly thumb?: string;
430
+ }
431
+ /** The panel's view of one project. */
432
+ export interface ProjectView {
433
+ readonly id: string;
434
+ readonly title: string;
435
+ readonly root: string;
436
+ readonly manifest: GameManifest | null;
437
+ /** Why the manifest could not be read, when it could not. */
438
+ readonly manifestError?: string;
439
+ readonly chapters: readonly ChapterView[];
440
+ readonly elements: readonly ElementView[];
441
+ readonly elementErrors: readonly CheckFailure[];
442
+ readonly current: VersionRecord | null;
443
+ readonly candidate: VersionRecord | null;
444
+ readonly lastCheck: CheckRecord | null;
445
+ readonly hasEntry: boolean;
446
+ /** The user's slider values that differ from the finalized defaults. */
447
+ readonly paramOverrides: Readonly<Record<string, number>>;
448
+ /** Panel changes the agent has not read yet (`game_read` shows, then clears them). */
449
+ readonly pending: readonly PendingChange[];
450
+ /** Panel edits in the working files that no version carries yet — the panel's 提交为新版本. */
451
+ readonly uncommitted: readonly PendingChange[];
452
+ /** Open (unpicked) and recent appearance proposals, newest first. */
453
+ readonly proposals: readonly LookProposal[];
454
+ readonly versions: readonly VersionRow[];
455
+ readonly log: readonly LogEntry[];
456
+ /** Set while a style change waits for its candidate (decision: a restyle always goes through a candidate). */
457
+ readonly restyleTo?: string;
458
+ /** What the waiting candidate changed against the live version, by element id (the play area's diff rings). */
459
+ readonly candidateDiff: {
460
+ readonly changed: readonly string[];
461
+ readonly added: readonly string[];
462
+ } | null;
463
+ }
464
+ /** What the tab needs to render a session: its bound project (if any) plus the list to pick from. */
465
+ export interface SessionGameState {
466
+ readonly bound: ProjectView | null;
467
+ readonly projects: readonly ProjectRow[];
468
+ }
469
+ /** One file of a playable bundle: text as-is, binary as base64. */
470
+ export type BundleFile = {
471
+ readonly type: string;
472
+ readonly text: string;
473
+ } | {
474
+ readonly type: string;
475
+ readonly b64: string;
476
+ };
477
+ /** A deployed version's files, ready for the sandbox loader. */
478
+ export interface PlayBundle {
479
+ readonly projectId: string;
480
+ readonly version: number;
481
+ readonly files: Readonly<Record<string, BundleFile>>;
482
+ }
483
+ /** Failure codes the Remote face answers with. */
484
+ export type GameError = 'not-found' | 'unbound' | 'denied' | 'invalid' | 'no-version' | 'io'
485
+ /** Project deletion: the folder no longer holds this project's game.json / is the session's own workspace / the trash move failed. */
486
+ | 'not-a-project' | 'is-workspace' | 'trash-failed';
487
+ /** A project deletion's answer: done (with where the folder went), or a failure; a failed trash move says why. */
488
+ export type DeleteProjectResult = {
489
+ readonly ok: true;
490
+ readonly trashedTo?: string;
491
+ } | {
492
+ readonly ok: false;
493
+ readonly error: GameError;
494
+ readonly reason?: string;
495
+ };
496
+ /** A Remote call's failure. */
497
+ export interface GameFailure {
498
+ readonly ok: false;
499
+ readonly error: GameError;
500
+ }
501
+ /** A Remote mutation's answer: `T` (which carries `ok: true`) or a failure. */
502
+ export type GameResult<T extends {
503
+ readonly ok: true;
504
+ } = {
505
+ readonly ok: true;
506
+ }> = T | GameFailure;
507
+ /** Minimal mirror of the official pluginInventory snapshot (entries + preset groups). */
508
+ export interface GamePluginInventorySnapshot {
509
+ readonly entries?: readonly {
510
+ readonly moduleName: string;
511
+ readonly enabled?: boolean;
512
+ }[];
513
+ readonly agentPresets?: readonly {
514
+ readonly id: string;
515
+ readonly broken?: string;
516
+ readonly rows: readonly {
517
+ readonly moduleName: string;
518
+ readonly enabled?: boolean;
519
+ }[];
520
+ }[];
521
+ }
522
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Wire and storage shapes shared by the host half, the Remote face and the
3
+ * browser half. Pure types and constants — no node imports, so the client
4
+ * type program includes this file as-is.
5
+ * @module @khorsheed/dsh-game/types
6
+ */
7
+ export const MANIFEST_FILE = 'game.json';
8
+ /** The plugin's own directory inside a project (snapshots, check results, logs). */
9
+ export const STATE_DIR = '.game';
10
+ /**
11
+ * The example styles the user picks from (decision D10). Without image
12
+ * generation the game draws everything in code, so each style is one a
13
+ * canvas/HTML game can render faithfully; `custom:<text>` covers the rest.
14
+ */
15
+ export const ART_STYLES = [
16
+ {
17
+ id: 'pixel', label: '像素', look: '16×16 / 32×32 像素块,有限调色板,整数倍放大不糊',
18
+ palette: ['#1a1c2c', '#5d275d', '#b13e53', '#ef7d57', '#ffcd75', '#a7f070', '#38b764', '#257179',
19
+ '#29366f', '#3b5dc9', '#41a6f6', '#73eff7', '#f4f4f4', '#94b0c2', '#566c86', '#333c57'],
20
+ },
21
+ {
22
+ id: 'flat', label: '扁平矢量', look: '纯色几何形,圆角,少量阴影,配色明快',
23
+ palette: ['#264653', '#2a9d8f', '#8ab17d', '#e9c46a', '#f4a261', '#e76f51', '#fefae0', '#3d405b'],
24
+ },
25
+ {
26
+ id: 'line', label: '手绘线稿', look: '黑色描线 + 淡彩填充,线条略抖',
27
+ palette: ['#222222', '#f7f3e8', '#f2c6c2', '#c9e4de', '#c6def1', '#faedcb', '#dbcdf0', '#8a8a8a'],
28
+ },
29
+ {
30
+ id: 'neon', label: '霓虹几何', look: '深色底,发光的线框与粒子',
31
+ palette: ['#0d0221', '#261447', '#ff3864', '#2de2e6', '#f6019d', '#fdf500', '#7b2cbf', '#ffffff'],
32
+ },
33
+ {
34
+ id: 'paper', label: '剪纸拼贴', look: '纸张纹理色块,轻微投影,层叠感',
35
+ palette: ['#f2e8cf', '#e0c9a6', '#bc4749', '#6a994e', '#386641', '#a7c957', '#3d348b', '#5c4033'],
36
+ },
37
+ {
38
+ id: 'mono', label: '极简单色', look: '一种主色加黑白,靠形状和留白区分',
39
+ palette: ['#111111', '#f5f5f5', '#e63946', '#9a9a9a', '#5a5a5a', '#d0d0d0'],
40
+ },
41
+ ];
42
+ /**
43
+ * The 3D example styles (the 3d-three kit, proposal 2026-10-21-game-3d G8):
44
+ * toon shading with an ink outline over a paper ground. The ids are what
45
+ * `dsh3d.createWorld({ style })` takes.
46
+ */
47
+ export const ART_STYLES_3D = [
48
+ {
49
+ id: 'ink', label: '水墨', look: '低多边形 + 墨线描边 + 宣纸底与远雾,留白多',
50
+ palette: ['#2a2622', '#efe7d6', '#e9dfcc', '#b8442f', '#8f897b', '#4c5747', '#a7bab4', '#46698a'],
51
+ },
52
+ {
53
+ id: 'qinglv', label: '青绿山水', look: '石青石绿的山、赭色描边、暖纸底,色块鲜明',
54
+ palette: ['#4f3b28', '#f1e8cf', '#3c8a78', '#3a6f93', '#d9d9b0', '#2c6a57', '#77a9bb', '#b8442f'],
55
+ },
56
+ ];
57
+ /** Body archetypes a `parts3d` look builds on. */
58
+ export const BODY_BASES = ['quadruped', 'bird', 'fish', 'serpent', 'humanoid'];
59
+ /** Built-in parts a `parts3d` look can attach; a project can register more with `dsh3d.definePart`. */
60
+ export const PART_TYPES = ['ear', 'horn', 'tail', 'wing', 'fin', 'eye', 'face'];
61
+ /** Whether a look is the 2D pixel-row kind. */
62
+ export function isPixelLook(look) {
63
+ return !('kind' in look);
64
+ }
65
+ /** The characters a look row may use, in palette-index order. */
66
+ export const LOOK_CHARS = '0123456789abcdefghijklmnopqrstuvwxyz';
67
+ /** The chaptered design doc (decision D12): fixed chapters, pillars pinned first. */
68
+ export const CHAPTERS = [
69
+ { id: 'pillars', title: '支柱说明', file: 'design/pillars.md' },
70
+ { id: 'core-loop', title: '核心循环', file: 'design/core-loop.md' },
71
+ { id: 'mechanics', title: '机制与规则', file: 'design/mechanics.md' },
72
+ { id: 'lore', title: '元素设定', file: 'design/lore.md', generated: true },
73
+ { id: 'elements', title: '元素与数值', file: 'design/elements.md', generated: true },
74
+ { id: 'levels', title: '关卡与节奏', file: 'design/levels.md' },
75
+ { id: 'art-audio', title: '美术与音效', file: 'design/art-audio.md' },
76
+ { id: 'playtest', title: '试玩记录', file: 'design/playtest.md', generated: true },
77
+ ];
78
+ /** Longest 设定 the panel saves. */
79
+ export const LORE_MAX = 2000;
80
+ /**
81
+ * The opening of the message the panel writes into the composer for its
82
+ * changes (「写进对话」). The pre-step hook recognizes a sent message by it and
83
+ * clears exactly the changes the message lists.
84
+ */
85
+ export const PANEL_CHANGES_MARK = '【面板改动】';