@vgai/engine 0.2.0 → 0.4.0-canary.20260715.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 (123) hide show
  1. package/README.md +3 -1
  2. package/package.json +24 -4
  3. package/schemas/engine-api.json +124 -0
  4. package/schemas/engine-api.md +53 -0
  5. package/schemas/engine-capabilities.json +124 -0
  6. package/schemas/inputmap.schema.json +314 -0
  7. package/schemas/mat.schema.json +286 -0
  8. package/schemas/prefab.schema.json +10148 -0
  9. package/schemas/scn2d.schema.json +475 -0
  10. package/schemas/vgai-game.schema.json +383 -0
  11. package/schemas/vscn.schema.json +11007 -0
  12. package/src/adapter/{world-kind.ts → adapter-surface.ts} +6 -6
  13. package/src/adapter/authoring.ts +77 -0
  14. package/src/adapter/first-party-systems.ts +23 -34
  15. package/src/adapter/game-adapter.ts +8 -8
  16. package/src/adapter/host-context.ts +2 -4
  17. package/src/adapter/index.ts +4 -4
  18. package/src/adapter/system-adapter.ts +88 -22
  19. package/src/adapter/vgai-scene-game-adapter.ts +244 -194
  20. package/src/animation/anim-graph-types.ts +12 -43
  21. package/src/animation/animation-clock.ts +479 -0
  22. package/src/animation/camera-ownership.ts +467 -0
  23. package/src/animation/cinematic-cues.ts +451 -0
  24. package/src/animation/clip-map.ts +41 -0
  25. package/src/animation/gsap-registration.ts +184 -0
  26. package/src/animation/theatre-clock-binding.ts +111 -0
  27. package/src/animation/theatre-director.ts +347 -0
  28. package/src/animation/theatre-object-binding.ts +661 -0
  29. package/src/animation/xstate-animation-binding.ts +436 -0
  30. package/src/animation/xstate-animation-meta.ts +319 -0
  31. package/src/audio/index.ts +39 -7
  32. package/src/audio/tone-clock-binding.ts +98 -0
  33. package/src/audio/tone-context.ts +129 -0
  34. package/src/audio/tone-offline-render.ts +167 -0
  35. package/src/audio/wav-encode.ts +119 -0
  36. package/src/character/cloth-sim.ts +533 -0
  37. package/src/character/spring-chain.ts +307 -0
  38. package/src/core/game-loop.ts +57 -2
  39. package/src/core/seeded-random.ts +161 -0
  40. package/src/core/system-runner.ts +20 -3
  41. package/src/core/types.ts +50 -0
  42. package/src/data/data-asset.ts +167 -0
  43. package/src/data/data-check-core.ts +242 -0
  44. package/src/data/data-ref.ts +145 -0
  45. package/src/data/vite-plugin-data.ts +290 -0
  46. package/src/dev/performance-profiler.ts +213 -0
  47. package/src/dev/webgl-gpu-timer.ts +53 -0
  48. package/src/ecs/component-manager.ts +45 -12
  49. package/src/ecs/game-component.ts +95 -11
  50. package/src/humanoid/bake.operation.ts +326 -0
  51. package/src/humanoid/body.ts +663 -0
  52. package/src/humanoid/clips.ts +149 -0
  53. package/src/humanoid/compose.ts +209 -0
  54. package/src/humanoid/generate.ts +189 -0
  55. package/src/humanoid/index.ts +36 -0
  56. package/src/humanoid/schema.ts +108 -0
  57. package/src/humanoid/skeleton.ts +345 -0
  58. package/src/index.ts +48 -0
  59. package/src/input/input-manager.ts +1886 -33
  60. package/src/input/input-types.ts +158 -3
  61. package/src/input/prompt-labels.ts +122 -0
  62. package/src/input/rebind-controller.ts +105 -0
  63. package/src/input/schema.ts +206 -52
  64. package/src/manifest/index.ts +5 -5
  65. package/src/manifest/load.ts +125 -72
  66. package/src/manifest/schema.ts +362 -255
  67. package/src/react/game-state.tsx +135 -32
  68. package/src/react/root-adapter.tsx +49 -0
  69. package/src/react/unmanaged-root-detector.ts +66 -0
  70. package/src/react/use-data.ts +124 -0
  71. package/src/react/use-selection.tsx +135 -0
  72. package/src/runtime/create-runtime.ts +112 -273
  73. package/src/runtime/debug-bridge.ts +483 -0
  74. package/src/runtime/debug-registry.ts +856 -0
  75. package/src/runtime/game.ts +342 -93
  76. package/src/runtime/gameplay-rng-trap.ts +134 -0
  77. package/src/runtime/input-router.ts +7 -7
  78. package/src/runtime/mount-game.ts +40 -38
  79. package/src/runtime/mount-manifest.ts +169 -37
  80. package/src/runtime/render-audio-control.ts +168 -0
  81. package/src/runtime/render-control.ts +522 -0
  82. package/src/runtime/render-seed.ts +79 -0
  83. package/src/runtime/state-bridge.ts +24 -10
  84. package/src/runtime/types.ts +110 -33
  85. package/src/scene/asset-loaders.ts +10 -36
  86. package/src/scene/asset-paths.ts +0 -2
  87. package/src/scene/asset-ref-check.ts +248 -0
  88. package/src/scene/asset-registry.ts +22 -0
  89. package/src/scene/component-registry.ts +14 -3
  90. package/src/scene/defaults.ts +1 -0
  91. package/src/scene/light-camera-factory.ts +11 -3
  92. package/src/scene/parse.ts +133 -0
  93. package/src/scene/scene-apply.ts +55 -4
  94. package/src/scene/scene-loader.ts +91 -123
  95. package/src/scene/scene-types.ts +0 -1
  96. package/src/scene/schema/animation.ts +30 -79
  97. package/src/scene/schema/entity.ts +20 -0
  98. package/src/scene/schema/index.ts +2 -46
  99. package/src/scene/schema/light.ts +16 -1
  100. package/src/scene/schema/material.ts +96 -91
  101. package/src/scene/schema/scene-file.ts +1 -7
  102. package/src/scene/user-data.ts +22 -10
  103. package/src/setup/setup-renderer.ts +10 -3
  104. package/src/tools/define-tool.ts +191 -0
  105. package/src/world2d/authoring-2d.ts +17 -1
  106. package/src/world2d/collision-2d.ts +1 -1
  107. package/src/world2d/pixi-game-adapter.ts +19 -17
  108. package/src/world2d/scene2d-loader.ts +1 -0
  109. package/src/world2d/types.ts +8 -2
  110. package/src/animation/anim-graph.ts +0 -406
  111. package/src/animation/anim-system.ts +0 -28
  112. package/src/animation/property-track.ts +0 -178
  113. package/src/animation/schema.ts +0 -204
  114. package/src/audio/ambient.ts +0 -300
  115. package/src/audio/impacts.ts +0 -212
  116. package/src/audio/movement.ts +0 -140
  117. package/src/audio/musical.ts +0 -200
  118. package/src/audio/ui-sounds.ts +0 -171
  119. package/src/audio/vehicle.ts +0 -235
  120. package/src/audio/weapons.ts +0 -152
  121. package/src/runtime/scene-ui-bridge.ts +0 -86
  122. package/src/runtime/scene-ui-data.ts +0 -119
  123. package/src/scene/schema/ui.ts +0 -602
@@ -0,0 +1,383 @@
1
+ {
2
+ "$comment": "AUTO-GENERATED by scripts/generate-schema.ts — do not edit manually",
3
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
4
+ "type": "object",
5
+ "properties": {
6
+ "$schema": {
7
+ "description": "Optional JSON Schema URI for editor autocomplete and validation",
8
+ "type": "string"
9
+ },
10
+ "manifestVersion": {
11
+ "type": "number",
12
+ "const": 2,
13
+ "description": "Manifest file format version (v2 clean roots)"
14
+ },
15
+ "name": {
16
+ "type": "string",
17
+ "description": "Game display name"
18
+ },
19
+ "appId": {
20
+ "description": "Stable reverse-domain application id used by packaged targets",
21
+ "type": "string"
22
+ },
23
+ "editorPort": {
24
+ "description": "Stable preferred local editor port; launchers may fall forward when occupied",
25
+ "type": "integer",
26
+ "minimum": 1024,
27
+ "maximum": 65535
28
+ },
29
+ "version": {
30
+ "type": "string",
31
+ "description": "The game's own version (used for orphan detection)"
32
+ },
33
+ "engine": {
34
+ "type": "object",
35
+ "properties": {
36
+ "version": {
37
+ "type": "string",
38
+ "description": "Exact @vgai/engine semver this game was scaffolded/last upgraded against — an identity pin, not a range"
39
+ }
40
+ },
41
+ "required": [
42
+ "version"
43
+ ],
44
+ "description": "Engine version pin"
45
+ },
46
+ "roots": {
47
+ "minItems": 1,
48
+ "type": "array",
49
+ "items": {
50
+ "type": "object",
51
+ "properties": {
52
+ "id": {
53
+ "type": "string",
54
+ "description": "Unique id for this root within the manifest (enforced-unique, D-V6 — GameManifestSchema.roots rejects duplicates)"
55
+ },
56
+ "description": {
57
+ "description": "Optional one-line description of this root's game/content (e.g. an ingested game's blurb — the manifest-native replacement for a registry entry's description field)",
58
+ "type": "string"
59
+ },
60
+ "adapter": {
61
+ "anyOf": [
62
+ {
63
+ "type": "string",
64
+ "enum": [
65
+ "threejs",
66
+ "pixijs",
67
+ "react"
68
+ ]
69
+ },
70
+ {
71
+ "type": "object",
72
+ "properties": {
73
+ "module": {
74
+ "type": "string",
75
+ "description": "Game-folder-relative path to a custom adapter module (trust boundary)"
76
+ },
77
+ "surface": {
78
+ "type": "string",
79
+ "enum": [
80
+ "threejs",
81
+ "pixijs",
82
+ "react"
83
+ ],
84
+ "description": "Native surface exposed by this custom adapter contract"
85
+ }
86
+ },
87
+ "required": [
88
+ "module",
89
+ "surface"
90
+ ],
91
+ "additionalProperties": false
92
+ },
93
+ {
94
+ "type": "object",
95
+ "properties": {
96
+ "surface": {
97
+ "type": "string",
98
+ "enum": [
99
+ "threejs",
100
+ "pixijs",
101
+ "react"
102
+ ],
103
+ "description": "Native surface captured from the unmodified game"
104
+ },
105
+ "ingest": {
106
+ "type": "object",
107
+ "properties": {
108
+ "strategy": {
109
+ "type": "string",
110
+ "enum": [
111
+ "shared",
112
+ "deduped",
113
+ "iframe-reachable",
114
+ "opaque-embed"
115
+ ],
116
+ "description": "Capture mechanics rung this ingested root uses (§4) — also the root`s natural local capability tier"
117
+ },
118
+ "entryHtml": {
119
+ "description": "Entry HTML path, project-relative. WIRED for opaque-embed (D-W2, docs/WAVE4-FTUE-HARDENING-DESIGN.md): the file`s bytes are read verbatim through the project-static route and hosted in a sandboxed iframe (embed-only, no scene introspection), for both pixijs and threejs roots. Legal but NOT wired to a mount for iframe-reachable (a named error at resolve names this — use `bundleUrl` instead, the wired reachable route).",
120
+ "type": "string"
121
+ },
122
+ "assets": {
123
+ "description": "Path-substring -> served-URL rewrites for this ingested game (IngestGame.assets today)",
124
+ "type": "object",
125
+ "propertyNames": {
126
+ "type": "string"
127
+ },
128
+ "additionalProperties": {
129
+ "type": "string"
130
+ }
131
+ },
132
+ "domStubs": {
133
+ "description": "DOM API stub ids this ingested game requires to run headlessly/in-realm",
134
+ "type": "array",
135
+ "items": {
136
+ "type": "string"
137
+ }
138
+ },
139
+ "captureTimeoutMs": {
140
+ "description": "Max time to wait for in-realm/cross-realm capture before failing loudly",
141
+ "type": "number"
142
+ },
143
+ "bundleUrl": {
144
+ "description": "Absolute URL of the externalized built game bundle — the WIRED iframe-reachable mount route (iframe-reachable only), for BOTH pixijs (Track P, ingest-iframe-2d.ts's mountIngestGame2DIframeReachableMulti) and threejs (D-W1, docs/WAVE4-FTUE-HARDENING-DESIGN.md, ingest-iframe-reachable-adapter.ts's mountIngestGameIframeReachableBundle). PRECONDITION: the bundle must externalize its root`s own runtime as a bare, un-rewritten import (`pixi.js` for pixijs, `three` for threejs — `vgai bundle` does this for you) so it resolves through the iframe importmap to the HOST instance the capture trap is installed on; a bundle with an inlined runtime is unreachable and degrades to the embed-only floor. Exactly one of bundleUrl/entryHtml is required when strategy is iframe-reachable.",
145
+ "type": "string"
146
+ },
147
+ "baseHref": {
148
+ "description": "Iframe <base href> so the game's relative asset URLs resolve (iframe-reachable only).",
149
+ "type": "string"
150
+ },
151
+ "assetBaseUrl": {
152
+ "description": "Host-side basePath forced onto the trapped runtime's own asset resolution — pixi's `Assets.init` for a pixijs root, three's `DefaultLoadingManager.setURLModifier` for a threejs root (D-W1) — absolute, or root-relative (resolved against the editor page's own origin at mount time, ingest-mode.ts, so a static manifest never has to know the dev-server port) (iframe-reachable only — a document.write iframe keeps the parent window.location).",
153
+ "type": "string"
154
+ },
155
+ "extraDeps": {
156
+ "description": "Bare specifiers of this root's externalized deps beyond its own runtime (pixi.js/three — e.g. '@pixi/sound', 'gsap'). Resolved by the editor's host-namespace registry into module namespaces when known (D-P1 — the manifest carries data, not code); an unregistered specifier falls back to the open project's own node_modules (D-Z3, docs/WAVE3-ADAPTER-PLUMBING-DESIGN.md), served as a verbatim iframe importmap URL. Throws a named error if neither resolves it (iframe-reachable only).",
157
+ "type": "array",
158
+ "items": {
159
+ "type": "string"
160
+ }
161
+ },
162
+ "pixiModuleUrl": {
163
+ "description": "PIXI-ONLY: standalone matching-major pixi ESM URL to trap instead of the host pixi, for version-skewed games (e.g. a v6 game on a v8 host); this field's PRESENCE is how the skew is expressed (D-P2 — no separate strategy/tier for version skew) (iframe-reachable only). Declaring this on a `kind: \"threejs\"` root is schema-legal (this field is kind-agnostic here) but throws a NAMED not-supported error at resolve — three has no version-skew mount this wave (D-W7, docs/WAVE4-FTUE-HARDENING-DESIGN.md: a hypothetical `threeModuleUrl` is explicitly parked, no consumer exists).",
164
+ "type": "string"
165
+ },
166
+ "bodyHtml": {
167
+ "description": "HTML injected into the iframe body before the game script boots (e.g. a `<div id=\"game-root\">` the game expects to find) (iframe-reachable only).",
168
+ "type": "string"
169
+ }
170
+ },
171
+ "required": [
172
+ "strategy"
173
+ ],
174
+ "description": "Ingest adapter configuration for an unmodified game (a repo-vendored game or your own external folder)"
175
+ }
176
+ },
177
+ "required": [
178
+ "surface",
179
+ "ingest"
180
+ ],
181
+ "additionalProperties": false
182
+ }
183
+ ],
184
+ "description": "This root's adapter and sole rendering/lifecycle discriminator"
185
+ },
186
+ "scene": {
187
+ "description": ".vscn.json / .scn2d.json scene path (default adapters only — ingest adapters keep their own formats)",
188
+ "type": "string"
189
+ },
190
+ "entry": {
191
+ "description": "Module exporting setup()/adapter (default adapters' code-authored alternative to `scene`)",
192
+ "type": "string"
193
+ },
194
+ "zOrder": {
195
+ "default": 0,
196
+ "description": "Canvas stacking order (COMPOSITION-DESIGN); ties broken by array order",
197
+ "type": "integer",
198
+ "minimum": -9007199254740991,
199
+ "maximum": 9007199254740991
200
+ },
201
+ "pausable": {
202
+ "default": true,
203
+ "description": "Whether play-mode pause/step applies to this root",
204
+ "type": "boolean"
205
+ },
206
+ "loop": {
207
+ "default": "gated",
208
+ "description": "gated: host-driven loop (default). self-driven: this root drives its own loop (the \"composited, unsynchronized\" tier) — an axis independent of capability tier",
209
+ "type": "string",
210
+ "enum": [
211
+ "gated",
212
+ "self-driven"
213
+ ]
214
+ },
215
+ "capabilities": {
216
+ "description": "Per-delivery-context capability tier declarations (§4). Declaring above the adapter's ceiling for that context is an error; declaring at or below it (including `unsupported`) is legal.",
217
+ "type": "object",
218
+ "properties": {
219
+ "local": {
220
+ "description": "Declared capability tier when served via the local CLI (Vite pipeline); omitted -> derived (§4)",
221
+ "type": "string",
222
+ "enum": [
223
+ "first-party",
224
+ "shared",
225
+ "deduped",
226
+ "iframe-reachable",
227
+ "opaque-embed",
228
+ "unsupported"
229
+ ]
230
+ },
231
+ "hosted": {
232
+ "description": "Declared capability tier when served hosted (no bundler: esbuild-wasm + externals only); omitted -> derived (§4)",
233
+ "type": "string",
234
+ "enum": [
235
+ "first-party",
236
+ "shared",
237
+ "deduped",
238
+ "iframe-reachable",
239
+ "opaque-embed",
240
+ "unsupported"
241
+ ]
242
+ }
243
+ }
244
+ }
245
+ },
246
+ "required": [
247
+ "id",
248
+ "adapter"
249
+ ],
250
+ "additionalProperties": false
251
+ },
252
+ "description": "The Game's explicit, non-empty adapter-root composition. There is no implicit root."
253
+ },
254
+ "authoring": {
255
+ "description": "Editor-only authoring metadata; never runtime ownership",
256
+ "type": "object",
257
+ "properties": {
258
+ "hierarchy": {
259
+ "description": "Editor projection for native adapter roots",
260
+ "type": "object",
261
+ "properties": {
262
+ "rootLabels": {
263
+ "description": "Optional editor labels keyed by adapter-root id",
264
+ "type": "object",
265
+ "propertyNames": {
266
+ "type": "string"
267
+ },
268
+ "additionalProperties": {
269
+ "type": "string"
270
+ }
271
+ },
272
+ "groups": {
273
+ "description": "Optional editor-only hierarchy groups",
274
+ "type": "array",
275
+ "items": {
276
+ "type": "object",
277
+ "properties": {
278
+ "id": {
279
+ "type": "string",
280
+ "description": "Unique editor-only group id"
281
+ },
282
+ "label": {
283
+ "type": "string",
284
+ "description": "Editor-only group label"
285
+ },
286
+ "roots": {
287
+ "minItems": 1,
288
+ "type": "array",
289
+ "items": {
290
+ "type": "string"
291
+ },
292
+ "description": "Adapter-root ids shown under this editor-only group"
293
+ }
294
+ },
295
+ "required": [
296
+ "id",
297
+ "label",
298
+ "roots"
299
+ ]
300
+ }
301
+ }
302
+ }
303
+ }
304
+ }
305
+ },
306
+ "server": {
307
+ "description": "Multiplayer server config (Colyseus), if this game registers a room",
308
+ "type": "object",
309
+ "properties": {
310
+ "room": {
311
+ "type": "string",
312
+ "description": "Colyseus room name"
313
+ },
314
+ "module": {
315
+ "description": "Module path for the Colyseus room bootstrap; defaults to the scaffolded server bootstrap",
316
+ "type": "string"
317
+ }
318
+ },
319
+ "required": [
320
+ "room"
321
+ ]
322
+ },
323
+ "resolution": {
324
+ "description": "Canvas resolution",
325
+ "type": "object",
326
+ "properties": {
327
+ "width": {
328
+ "type": "number",
329
+ "description": "Canvas width in pixels"
330
+ },
331
+ "height": {
332
+ "type": "number",
333
+ "description": "Canvas height in pixels"
334
+ }
335
+ },
336
+ "required": [
337
+ "width",
338
+ "height"
339
+ ]
340
+ },
341
+ "debug": {
342
+ "description": "Debug-bridge production gating (D18) — governs whether ?vgai-debug=1 installs window.__vgai outside dev builds.",
343
+ "type": "object",
344
+ "properties": {
345
+ "allowInProduction": {
346
+ "type": "boolean",
347
+ "description": "Allow the ?vgai-debug=1 introspection bridge and debug-command invocation in production builds. Default false: the bridge only installs in dev builds. The runtime reader is the debug-bridge installer (D18)."
348
+ }
349
+ },
350
+ "required": [
351
+ "allowInProduction"
352
+ ]
353
+ },
354
+ "determinism": {
355
+ "description": "Seeded-RNG determinism contract (D15, docs/D15-DETERMINISM-DESIGN.md) — governs whether ctx.random is boot-seeded from a reproducible seed and whether the gameplay-rng-ban scan / dev-mode Math.random phase trap are active for this project.",
356
+ "type": "object",
357
+ "properties": {
358
+ "seededRandom": {
359
+ "type": "boolean",
360
+ "description": "Declares that ALL gameplay RNG in this project flows through ctx.random (the named-stream seeded PRNG, docs/D15-DETERMINISM-DESIGN.md) rather than raw Math.random/Date.now/performance.now. Three runtime enforcers key off this flag: the boot-time seeding reader (mount-manifest.ts seeds ctx.random from defaultSeed/?vgai-seed=/explicit config, in that precedence, only when true), the gameplay-rng-ban burn-down scan (test/gameplay-rng-ban.test.ts — lints this project's src/ for raw RNG/wall-clock calls), and the dev-mode Math.random phase trap (runtime/gameplay-rng-trap.ts — warns once per call site during a gameplay frame, never throws). Default false: an undeclared project gets no determinism contract at all (that IS the opt-out — no dead field, per the T4.1 policy)."
361
+ },
362
+ "defaultSeed": {
363
+ "description": "The seed ctx.random boots from when seededRandom is true, unless overridden by ?vgai-seed=<int> (the query param always wins over this manifest default) or an even higher-precedence explicit config value a host passes directly. Optional — omit to fall back to the runtime's own fixed default seed.",
364
+ "type": "integer",
365
+ "minimum": -9007199254740991,
366
+ "maximum": 9007199254740991
367
+ }
368
+ },
369
+ "required": [
370
+ "seededRandom"
371
+ ]
372
+ }
373
+ },
374
+ "required": [
375
+ "manifestVersion",
376
+ "name",
377
+ "version",
378
+ "engine",
379
+ "roots"
380
+ ],
381
+ "additionalProperties": false,
382
+ "description": "Game manifest (vgai.game.json) — the complete v2 project configuration"
383
+ }