@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
@@ -1,26 +1,26 @@
1
1
  /**
2
- * `WorldKind` — the kinds of render surface a world can be (T7.1/T7.3/T6.2).
2
+ * `AdapterSurface` — the kinds of render surface a world can be (T7.1/T7.3/T6.2).
3
3
  *
4
4
  * Moved here (T7.5, `docs/BACKBONE-TASKS.md`'s D6 row) from `runtime/game.ts`
5
5
  * so `adapter/game-adapter.ts`'s kind-tagged `MountedWorld` types can name it
6
6
  * without a value-level import cycle (`runtime/game.ts` type-imports from
7
7
  * `adapter/game-adapter.ts` already). This is a leaf module — it imports
8
8
  * nothing — so anything may import it with zero risk of a cycle.
9
- * `runtime/game.ts` re-exports this SAME type (`export type { WorldKind }`),
10
- * so no existing `import type { WorldKind } from '../runtime/game'` call site
9
+ * `runtime/game.ts` re-exports this SAME type (`export type { AdapterSurface }`),
10
+ * so no existing `import type { AdapterSurface } from '../runtime/game'` call site
11
11
  * needed to change.
12
12
  */
13
- export type WorldKind = 'threejs' | 'pixijs' | 'react';
13
+ export type AdapterSurface = 'threejs' | 'pixijs' | 'react';
14
14
 
15
15
  /**
16
- * Exhaustiveness guard for `WorldKind` dispatch (v4 architecture-review
16
+ * Exhaustiveness guard for `AdapterSurface` dispatch (v4 architecture-review
17
17
  * §7.4-2: a hypothetical 4th kind must fail to COMPILE at every kind-dispatch
18
18
  * site, not silently contribute nothing or silently default to an existing
19
19
  * kind). Lives here — colocated with the kind vocabulary itself, not in a
20
20
  * generic util module — so the three call sites that need it
21
21
  * (`runtime/create-runtime.ts`'s mount loop, `editor/adapter-resolver.ts`'s
22
22
  * `resolveAllWorlds`, `editor/play-mode.ts`'s `installMultiWorldAuthoring`)
23
- * import it from the same leaf module that defines `WorldKind`, keeping the
23
+ * import it from the same leaf module that defines `AdapterSurface`, keeping the
24
24
  * type and its guard from drifting apart. The `never` parameter is the
25
25
  * compile-time half of the guard (TS refuses to call this with anything the
26
26
  * compiler hasn't already narrowed to zero remaining variants); the thrown
@@ -42,11 +42,68 @@ export interface AuthoringCapabilities {
42
42
  layout?: boolean;
43
43
  }
44
44
 
45
+ /**
46
+ * The adapter's own answer to "what is truth behind these rows, and how
47
+ * writable is it" (spec 29 §5, docs/unified-world-editor/
48
+ * 29-hierarchy-philosophy.md). Provenance never varies WITHIN one adapter's
49
+ * rows — it is a property of the world boundary — so it is declared ONCE per
50
+ * adapter and rendered at the SEAM (the composite's `world:<id>` group row,
51
+ * or the panel header for a bare adapter), never per row. Only the adapter
52
+ * knows its truth: the shell must read this field, never guess from adapter
53
+ * identity (rule zero). Machine-readable operation gates stay in
54
+ * {@link AuthoringCapabilities}/provider presence — this type carries the
55
+ * HUMAN explanation those gates can point at when an affordance is present
56
+ * but unavailable.
57
+ */
58
+ export interface AuthoringProvenance {
59
+ /**
60
+ * What the rows project:
61
+ * - `document` — an authored data file the editor owns (e.g. a scene file);
62
+ * - `source-code` — the game's own source is the document (e.g. JSX);
63
+ * - `foreign` — a live tree the editor does not own (an unmodified external
64
+ * game, or any world edited only through an overlay); edits go to the
65
+ * overlay, never the source;
66
+ * - `live` — a running game adopted at play time; edits are not persisted;
67
+ * - `boundary` — a declared world with no live editing surface here.
68
+ */
69
+ source: 'document' | 'source-code' | 'foreign' | 'live' | 'boundary';
70
+ /** Short badge text the shell shows verbatim at the seam (e.g. "scene",
71
+ * "jsx", "overlay", "read-only", "live"). */
72
+ label: string;
73
+ /** One sentence explaining the truth/writability — shown as the seam
74
+ * badge's tooltip and as the reason on disabled affordances. */
75
+ detail: string;
76
+ }
77
+
78
+ /**
79
+ * Semantic place a node occupies in the universal authoring hierarchy.
80
+ *
81
+ * `kind` below remains the adapter's native kind (`mesh`, `button`,
82
+ * `pixi-container`, ...). `role` says what the row MEANS to the editor shell,
83
+ * so presentation and interaction never have to infer semantics from an id,
84
+ * label, or substrate-specific kind string.
85
+ */
86
+ export type EditorNodeRole =
87
+ | 'folder'
88
+ | 'root'
89
+ | 'document'
90
+ | 'story'
91
+ | 'component'
92
+ | 'element'
93
+ | 'entity'
94
+ | 'boundary';
95
+
45
96
  /** A node in the authoring hierarchy — format-neutral (not a `SceneEntity`). */
46
97
  export interface EditorNode {
47
98
  /** STABLE id — survives reload (see ingest structural-path ids). */
48
99
  id: string;
49
100
  label: string;
101
+ /** Adapter-declared semantic role. Optional for third-party/older adapters;
102
+ * the shell falls back to the native `kind` only for icon selection. */
103
+ role?: EditorNodeRole;
104
+ /** Optional source-owned context kept visually subordinate to `label`, such
105
+ * as `<header>` beneath a React component name or a document's file path. */
106
+ secondaryLabel?: string;
50
107
  kind: 'mesh' | 'light' | 'camera' | 'group' | 'object' | (string & {});
51
108
  parentId: string | null;
52
109
  childIds: string[];
@@ -56,6 +113,12 @@ export interface EditorNode {
56
113
  transformOwner?: TransformOwner;
57
114
  /** D8 — member of a RootGroup, not the active one; children may be unloaded. */
58
115
  inactiveRoot?: boolean;
116
+ /** Design state currently projected into the live authoring surface. */
117
+ active?: boolean;
118
+ /** The adapter resolved this boundary, but it is not editable here. */
119
+ readOnly?: boolean;
120
+ /** The adapter could not resolve the declared authoring boundary. */
121
+ error?: boolean;
59
122
  };
60
123
  }
61
124
 
@@ -277,6 +340,16 @@ export interface ComponentsProvider {
277
340
  list(nodeId: string): { type: string }[];
278
341
  add(nodeId: string, type: string): void;
279
342
  remove(nodeId: string, type: string): void;
343
+ /**
344
+ * OPTIONAL read accessor (W3.1, docs/DATA-TOOLS-DESIGN.md §3.3): the raw
345
+ * authored config record for one attached component (`list()` names the
346
+ * types; this reads one type's per-entity data), or `null` when the entity
347
+ * or component doesn't exist. Returns a shallow copy — callers must write
348
+ * through `InspectorProvider.set('components.<Type>.<field>', v)`, never by
349
+ * mutating this. Absent ⇒ config is not readable through this provider
350
+ * (tools degrade to `config: null`).
351
+ */
352
+ config?(nodeId: string, type: string): Record<string, unknown> | null;
280
353
  }
281
354
 
282
355
  /** Asset drop (hierarchy + viewport). */
@@ -361,6 +434,10 @@ export interface ColorSampleProvider {
361
434
 
362
435
  export interface AuthoringAdapter {
363
436
  readonly capabilities: AuthoringCapabilities;
437
+ /** Spec 29 §5 — seam-level provenance ("what is truth behind these rows").
438
+ * Absent ⇒ the shell shows no provenance badge (degrade silently — never
439
+ * fabricate a claim the adapter didn't make). */
440
+ readonly provenance?: AuthoringProvenance;
364
441
  readonly hierarchy: HierarchyProvider; // required — minimum is "read the tree"
365
442
  readonly selection?: SelectionProvider;
366
443
  readonly transforms?: TransformProvider;
@@ -1,20 +1,22 @@
1
1
  /**
2
2
  * First-party implementations of the remaining `SystemAdapters` — input, assets,
3
- * animation, navigation — each a thin coordination/introspection boundary over the
4
- * real engine subsystem (the original vision named these as first-class System
3
+ * navigation — each a thin coordination/introspection boundary over the real
4
+ * engine subsystem (the original vision named these as first-class System
5
5
  * adapters; physics + networking shipped earlier). The editor speaks only the
6
- * interfaces; these wrap `InputManager`, the asset loader, `AnimGraph`, and
7
- * `NavMeshManager` so an external game could supply its own equivalents.
6
+ * interfaces; these wrap `InputManager`, the asset loader, and `NavMeshManager`
7
+ * so an external game could supply its own equivalents. (The former
8
+ * `AnimationAdapter`/`createAnimationAdapter` over the `AnimGraph` map was
9
+ * removed by E5 — AnimGraph no longer exists; see
10
+ * docs/AI-NATIVE-AUTHORING-IMPLEMENTATION-SPEC.md §3.3/§11 E5.)
8
11
  */
9
12
 
10
13
  import type * as THREE from 'three';
11
14
  import type { NavMeshManager } from '../ai/navigation';
12
- import type { AnimGraph } from '../animation/anim-graph';
13
15
  import type { InputManager } from '../input/input-manager';
14
16
  import { resolveUrl } from '../loader';
15
17
  import type { AudioContext as GameAudio } from '../setup/setup-audio';
16
18
  import type {
17
- AnimationAdapter,
19
+ ActionValueSnapshot,
18
20
  AssetAdapter,
19
21
  AudioAdapter,
20
22
  InputAdapter,
@@ -22,13 +24,25 @@ import type {
22
24
  NavPoint,
23
25
  } from './system-adapter';
24
26
 
25
- /** First-party `InputAdapter` over the engine `InputManager`. */
27
+ /** First-party `InputAdapter` over the engine `InputManager`. Reads each action through
28
+ * `InputManager.readAction`, dispatched on that action's OWN declared `valueType`
29
+ * (`getActionValueType`) — never a hardcoded getter — so a scalar/Vector2/pointer action
30
+ * surfaces its real typed value instead of being coerced through `isPressed` (F1-followup;
31
+ * `readAction` on the wrong type would throw, so dispatch must follow the declared type). */
26
32
  export function createInputManagerAdapter(input: InputManager): InputAdapter {
27
33
  return {
28
34
  poll: () => input.poll(),
29
35
  actions: () => {
30
- const out: Record<string, number> = {};
31
- for (const name of input.actionNames()) out[name] = input.isPressed(name) ? 1 : 0;
36
+ const out: Record<string, ActionValueSnapshot> = {};
37
+ for (const name of input.actionNames()) {
38
+ const type = input.getActionValueType(name);
39
+ // `readAction`'s return type is inferred from a literal `expectedType`; with `type`
40
+ // widened to `ActionValueType` here it collapses to `boolean | number | Vector2`, so
41
+ // digital's `boolean` is normalized to the adapter's 1/0 the same way the old digital-
42
+ // only adapter did — every other value type already reads as `number | Vector2`.
43
+ const raw = input.readAction(name, type);
44
+ out[name] = { type, value: typeof raw === 'boolean' ? (raw ? 1 : 0) : raw };
45
+ }
32
46
  return out;
33
47
  },
34
48
  };
@@ -41,31 +55,6 @@ export function createVgaiAssetAdapter(): AssetAdapter {
41
55
  return { resolve: (url) => resolveUrl(url) };
42
56
  }
43
57
 
44
- /** First-party `AnimationAdapter` over the runtime's `AnimGraph` map. */
45
- export function createAnimationAdapter(
46
- animGraphs: Map<THREE.Object3D, AnimGraph>,
47
- ): AnimationAdapter {
48
- const paramsOf = (g: AnimGraph): Record<string, number | boolean> => {
49
- const out: Record<string, number | boolean> = {};
50
- for (const name of g.parameterNames()) {
51
- const v = g.getParameter(name);
52
- if (v !== undefined) out[name] = v;
53
- }
54
- return out;
55
- };
56
- return {
57
- graphs: () =>
58
- [...animGraphs.entries()].map(([object, g]) => ({
59
- object,
60
- state: g.getCurrentState(),
61
- parameters: paramsOf(g),
62
- })),
63
- state: (o) => animGraphs.get(o)?.getCurrentState() ?? null,
64
- getParameter: (o, name) => animGraphs.get(o)?.getParameter(name),
65
- setParameter: (o, name, value) => animGraphs.get(o)?.setParameter(name, value),
66
- };
67
- }
68
-
69
58
  /**
70
59
  * First-party `AudioAdapter` over the engine's master-gain bus
71
60
  * (`setup-audio.ts`'s `AudioContext.masterGain`) — the seam `Game.play.pause()`
@@ -10,10 +10,10 @@
10
10
 
11
11
  import type { Container } from 'pixi.js';
12
12
  import type * as THREE from 'three';
13
+ import type { AdapterSurface } from './adapter-surface';
13
14
  import type { AuthoringAdapter } from './authoring';
14
15
  import type { HostContext } from './host-context';
15
16
  import type { SystemAdapters } from './system-adapter';
16
- import type { WorldKind } from './world-kind';
17
17
 
18
18
  /**
19
19
  * The ingested-world observation contract (T7.4 slice 2 — `docs/
@@ -29,8 +29,8 @@ import type { WorldKind } from './world-kind';
29
29
  export interface WorldStateObserver {
30
30
  /**
31
31
  * Notified at most once per frame IF the adapter can hook the game's own
32
- * update (`loop: 'gated'` worlds, `docs/CAPABILITY-TIERS.md` §(d));
33
- * self-driven worlds (`loop: 'self-driven'`, raw-rAF) may notify on their
32
+ * update (`loop: 'gated'` roots, `docs/CAPABILITY-TIERS.md` §(d));
33
+ * self-driven roots (`loop: 'self-driven'`, raw-rAF) may notify on their
34
34
  * OWN rAF cadence instead — consumers must not assume our frame timing.
35
35
  * Returns an unsubscribe function.
36
36
  */
@@ -119,10 +119,10 @@ export interface MountedReactWorld extends MountedWorldBase {
119
119
  * is typed against now, replacing the THREE-only `MountedGame`. */
120
120
  export type MountedWorld = MountedThreeWorld | MountedPixiWorld | MountedReactWorld;
121
121
 
122
- /** Map a {@link WorldKind} to its mounted-world shape (mirrors `NodeOf`/
122
+ /** Map a {@link AdapterSurface} to its mounted-world shape (mirrors `NodeOf`/
123
123
  * `BodyOf`/`ColliderOf` in `ecs/game-component.ts`) — lets generic code over
124
- * `K extends WorldKind` name the right surface without a manual union. */
125
- export type MountedWorldFor<K extends WorldKind> = K extends 'threejs'
124
+ * `K extends AdapterSurface` name the right surface without a manual union. */
125
+ export type MountedWorldFor<K extends AdapterSurface> = K extends 'threejs'
126
126
  ? MountedThreeWorld
127
127
  : K extends 'pixijs'
128
128
  ? MountedPixiWorld
@@ -139,11 +139,11 @@ export type MountedWorldFor<K extends WorldKind> = K extends 'threejs'
139
139
  export type MountedGame = MountedThreeWorld;
140
140
 
141
141
  /** The interface every game implements to run on the host. Generic over
142
- * {@link WorldKind} (T7.5) so a non-threejs implementer's `mount` returns its
142
+ * {@link AdapterSurface} (T7.5) so a non-threejs implementer's `mount` returns its
143
143
  * OWN kind-tagged surface instead of being cast through the threejs shape —
144
144
  * defaults to `'threejs'` so every pre-T7.5 implementer/call site
145
145
  * (`GameAdapter`, unparameterized) keeps compiling unchanged. */
146
- export interface GameAdapter<K extends WorldKind = 'threejs'> {
146
+ export interface GameAdapter<K extends AdapterSurface = 'threejs'> {
147
147
  /** Stable id (telemetry/registry/conformance). */
148
148
  readonly id: string;
149
149
  /** Build/start the game against a host-provided context; return the handle. */
@@ -4,7 +4,7 @@
4
4
  * This generalizes the old `GameContext`, which baked in first-party system
5
5
  * choices (a Rapier world, the postprocessing composer, the InputManager, …).
6
6
  * `HostContext` provides only what ANY game needs — the shared three instance, a
7
- * surface, a renderer, a loop, assets, a UI overlay — and lets a game *ask* for
7
+ * surface, a renderer, a loop, and assets — and lets a game *ask* for
8
8
  * a first-party subsystem via `requestSystem`, which the host may or may not
9
9
  * supply. The host never assumes Rapier/Colyseus; those live behind
10
10
  * `SystemAdapters` owned by the first-party implementer.
@@ -54,8 +54,6 @@ export interface HostContext {
54
54
  readonly loop: LoopHandle;
55
55
  /** Shared GLTF/texture cache. */
56
56
  readonly assets: AssetCache;
57
- /** HUD overlay container (pointer-events:none by default). */
58
- readonly ui: HTMLElement;
59
57
  /**
60
58
  * No GPU/DOM/audio available (Node conformance tests). A first-party adapter
61
59
  * skips postprocessing/render/audio/input-map loading but still builds the
@@ -68,7 +66,7 @@ export interface HostContext {
68
66
  /**
69
67
  * The Game root (T7.1 slice 1 — GAME-ROOT-DESIGN.md D6). The host
70
68
  * constructs the Game shell BEFORE mounting a `GameAdapter` and hands it
71
- * down here so an adapter can expose `ctx.game`/`ctx.worlds` to the game it
69
+ * down here so an adapter can expose `ctx.game`/`ctx.roots` to the game it
72
70
  * mounts. Absent in headless harnesses and foreign hosts that predate the
73
71
  * Game root — everything must keep working when this is undefined (the
74
72
  * zero-break guarantee for this slice).
@@ -10,15 +10,18 @@
10
10
  * docs/ADAPTER-ARCHITECTURE.md.
11
11
  */
12
12
 
13
+ export type { AdapterSurface } from './adapter-surface';
13
14
  export type {
14
15
  AssetDropProvider,
15
16
  AuthoringAdapter,
16
17
  AuthoringCapabilities,
18
+ AuthoringProvenance,
17
19
  BoxEditProvider,
18
20
  ColorSampleProvider,
19
21
  ComponentsProvider,
20
22
  DOMRectLike,
21
23
  EditorNode,
24
+ EditorNodeRole,
22
25
  FileMapProvider,
23
26
  HierarchyProvider,
24
27
  InspectorProvider,
@@ -41,7 +44,6 @@ export {
41
44
  createColyseusNetworkingAdapter,
42
45
  } from './colyseus-networking-adapter';
43
46
  export {
44
- createAnimationAdapter,
45
47
  createInputManagerAdapter,
46
48
  createNavigationAdapter,
47
49
  createVgaiAssetAdapter,
@@ -60,8 +62,7 @@ export type {
60
62
  export type { HostContext, HostSurface, LoopHandle, SystemRegistry } from './host-context';
61
63
  export { createRapierPhysicsAdapter } from './rapier-physics-adapter';
62
64
  export type {
63
- AnimationAdapter,
64
- AnimationGraphInfo,
65
+ ActionValueSnapshot,
65
66
  AssetAdapter,
66
67
  ConnectionState,
67
68
  InputAdapter,
@@ -82,4 +83,3 @@ export {
82
83
  type VgaiSceneConfig,
83
84
  VgaiSceneGameAdapter,
84
85
  } from './vgai-scene-game-adapter';
85
- export type { WorldKind } from './world-kind';
@@ -12,6 +12,7 @@
12
12
  */
13
13
 
14
14
  import type * as THREE from 'three';
15
+ import type { ActionValueType, Vector2 } from '../input/input-types';
15
16
  import type { Transform, TransformOwner } from './transform';
16
17
 
17
18
  /**
@@ -75,10 +76,22 @@ export interface NetworkingAdapter {
75
76
  subscribe(cb: () => void): Unsubscribe;
76
77
  }
77
78
 
79
+ /** One action's current value, tagged with its declared shape (F1 `ActionValueType`) so a
80
+ * consumer (editor input inspector, conformance suite) can render/assert on the real typed
81
+ * value instead of a lossy digital coercion. `value` is a `number` for `'digital'`
82
+ * (1 = pressed, 0 = not) and `'scalar'`, or a `Vector2` for `'vector2'`/`'pointerDelta'`/
83
+ * `'pointerPosition'` — narrow on `type` to know which. */
84
+ export interface ActionValueSnapshot {
85
+ type: ActionValueType;
86
+ value: number | Vector2;
87
+ }
88
+
78
89
  export interface InputAdapter {
79
90
  poll(): void;
80
- /** Current value of every named action (1 = pressed, 0 = not), for inspection. */
81
- actions(): Readonly<Record<string, number>>;
91
+ /** Every named action's current value, faithfully typed per its declared `ActionValueType`
92
+ * (F1, spec §12) — digital reads as 1/0, scalar as its float, vector2/pointerDelta/
93
+ * pointerPosition as `{x,y}`. Never coerces a non-digital action down to 0/1. */
94
+ actions(): Readonly<Record<string, ActionValueSnapshot>>;
82
95
  }
83
96
 
84
97
  /** URL remap so an ingested game's relative asset paths resolve under the host. */
@@ -86,25 +99,6 @@ export interface AssetAdapter {
86
99
  resolve(url: string): string;
87
100
  }
88
101
 
89
- /** A snapshot of one object's animation graph (state + parameter values). */
90
- export interface AnimationGraphInfo {
91
- object: THREE.Object3D;
92
- state: string;
93
- parameters: Record<string, number | boolean>;
94
- }
95
-
96
- /**
97
- * Inspect + drive a game's animation graphs (state machines / blend params). The
98
- * editor uses this to list animated objects, read their current state, and scrub
99
- * parameters — without owning the animation system.
100
- */
101
- export interface AnimationAdapter {
102
- graphs(): AnimationGraphInfo[];
103
- state(o: THREE.Object3D): string | null;
104
- getParameter(o: THREE.Object3D, name: string): number | boolean | undefined;
105
- setParameter(o: THREE.Object3D, name: string, value: number | boolean): void;
106
- }
107
-
108
102
  export interface NavPoint {
109
103
  x: number;
110
104
  y: number;
@@ -139,6 +133,78 @@ export interface AudioAdapter {
139
133
  isMuted(): boolean;
140
134
  }
141
135
 
136
+ /** One tick-stamped debug event (`ctx.debug.emit`, spec §3.3): `tick`/`simT`
137
+ * are the engine's own counters AT EMISSION, so events and state reads
138
+ * correlate frame-exactly across every door (in-page bridge, relay, panels).
139
+ *
140
+ * `seq` (run-4 friction #5 fix) is a registry-lifetime MONOTONIC counter,
141
+ * strictly increasing by one per `emit()` call regardless of `tick` —
142
+ * unlike `tick`, it is never shared by two events, which is what makes it
143
+ * safe to fence on. A debug command handler runs BETWEEN ticks (its
144
+ * emissions carry whatever `tick` is current at that instant, same as every
145
+ * other emission at that instant would), so two DIFFERENT events — or an
146
+ * event and a consumer's fence point — can legitimately share one `tick`;
147
+ * `seq` never collides the same way, so "everything after what I've already
148
+ * observed" is unambiguous. See `events(sinceTick, sinceSeq)` below. */
149
+ export interface TickStampedEvent {
150
+ tick: number;
151
+ simT: number;
152
+ event: string;
153
+ detail?: unknown;
154
+ seq: number;
155
+ }
156
+
157
+ /** One registered debug command's listing shape — `locus` is always present
158
+ * (defaults to `'client'` when a command didn't declare one) so every
159
+ * listing surface can print it without a fallback of its own. */
160
+ export interface DebugCommandInfo {
161
+ name: string;
162
+ description?: string | undefined;
163
+ /** JSON-Schema projection of the command's Zod args tuple, when declared. */
164
+ argsJsonSchema?: unknown;
165
+ locus: 'client' | 'server';
166
+ }
167
+
168
+ /**
169
+ * The debug/synthetic-player seam (`docs/SYNTHETIC-PLAYER-SPEC.md` §3.1):
170
+ * game-scoped introspection + actuation over whatever a game registers via
171
+ * `ctx.debug` (`registerStateProvider`/`registerCommand`/`emit`). NOT a
172
+ * gameplay API — this is the one seam the debug bridge, the editor's Debug
173
+ * Console/State Watch panels, and `@vgai/probe` all read/drive through.
174
+ */
175
+ export interface DebugAdapter {
176
+ providers(): { name: string; tier: 'observable' | 'assisted' }[];
177
+ /** One provider's current value. Throws `DebugError` code
178
+ * `STATE_PROVIDER_NOT_FOUND` (`data.registered`) for an unknown name. */
179
+ state(name: string): unknown;
180
+ /** One coherent snapshot of every registered provider — a throwing
181
+ * provider contributes `{ __error: String(err) }` for its own key rather
182
+ * than failing the whole snapshot. */
183
+ stateAll(): Record<string, unknown>;
184
+ commands(): DebugCommandInfo[];
185
+ /** Validates `args` against the command's declared Zod tuple (when
186
+ * present), then awaits the registered fn. Throws `DebugError` code
187
+ * `DEBUG_COMMAND_NOT_REGISTERED` for an unknown name,
188
+ * `DEBUG_COMMAND_ARGS_INVALID` for a validation failure, or
189
+ * `DEBUG_COMMAND_FAILED` wrapping anything the command itself threw. */
190
+ invoke(name: string, args: unknown[]): Promise<unknown>;
191
+ /** The tick-stamped event ring (cap 500, drops oldest).
192
+ *
193
+ * - `sinceSeq` given (run-4 friction #5 fix): filters to `seq > sinceSeq`
194
+ * — the unambiguous fence a consumer should use to mean "everything
195
+ * emitted after what I've already observed" (see `TickStampedEvent.seq`'s
196
+ * doc comment for why `tick` alone can't do this: a debug-command
197
+ * emission and a consumer's fence point can share one tick, and the
198
+ * old `tick > sinceTick` filter silently dropped same-tick events).
199
+ * Takes precedence over `sinceTick` when both are given.
200
+ * - `sinceTick` only: the ORIGINAL (pre-fix) filter, `tick > sinceTick` —
201
+ * kept for back-compat callers that only ever had a tick to fence on;
202
+ * still has the same-tick blind spot by construction, so a new caller
203
+ * should prefer `sinceSeq`.
204
+ * - Neither given: the whole ring. */
205
+ events(sinceTick?: number, sinceSeq?: number): TickStampedEvent[];
206
+ }
207
+
142
208
  /**
143
209
  * The set of optional subsystem providers a mounted game may expose. Absence of
144
210
  * a provider means "capability not supported" — the editor degrades gracefully.
@@ -148,7 +214,7 @@ export interface SystemAdapters {
148
214
  networking?: NetworkingAdapter;
149
215
  input?: InputAdapter;
150
216
  assets?: AssetAdapter;
151
- animation?: AnimationAdapter;
152
217
  navigation?: NavigationAdapter;
153
218
  audio?: AudioAdapter;
219
+ debug?: DebugAdapter;
154
220
  }