@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.
- package/README.md +3 -1
- package/package.json +24 -4
- package/schemas/engine-api.json +124 -0
- package/schemas/engine-api.md +53 -0
- package/schemas/engine-capabilities.json +124 -0
- package/schemas/inputmap.schema.json +314 -0
- package/schemas/mat.schema.json +286 -0
- package/schemas/prefab.schema.json +10148 -0
- package/schemas/scn2d.schema.json +475 -0
- package/schemas/vgai-game.schema.json +383 -0
- package/schemas/vscn.schema.json +11007 -0
- package/src/adapter/{world-kind.ts → adapter-surface.ts} +6 -6
- package/src/adapter/authoring.ts +77 -0
- package/src/adapter/first-party-systems.ts +23 -34
- package/src/adapter/game-adapter.ts +8 -8
- package/src/adapter/host-context.ts +2 -4
- package/src/adapter/index.ts +4 -4
- package/src/adapter/system-adapter.ts +88 -22
- package/src/adapter/vgai-scene-game-adapter.ts +244 -194
- package/src/animation/anim-graph-types.ts +12 -43
- package/src/animation/animation-clock.ts +479 -0
- package/src/animation/camera-ownership.ts +467 -0
- package/src/animation/cinematic-cues.ts +451 -0
- package/src/animation/clip-map.ts +41 -0
- package/src/animation/gsap-registration.ts +184 -0
- package/src/animation/theatre-clock-binding.ts +111 -0
- package/src/animation/theatre-director.ts +347 -0
- package/src/animation/theatre-object-binding.ts +661 -0
- package/src/animation/xstate-animation-binding.ts +436 -0
- package/src/animation/xstate-animation-meta.ts +319 -0
- package/src/audio/index.ts +39 -7
- package/src/audio/tone-clock-binding.ts +98 -0
- package/src/audio/tone-context.ts +129 -0
- package/src/audio/tone-offline-render.ts +167 -0
- package/src/audio/wav-encode.ts +119 -0
- package/src/character/cloth-sim.ts +533 -0
- package/src/character/spring-chain.ts +307 -0
- package/src/core/game-loop.ts +57 -2
- package/src/core/seeded-random.ts +161 -0
- package/src/core/system-runner.ts +20 -3
- package/src/core/types.ts +50 -0
- package/src/data/data-asset.ts +167 -0
- package/src/data/data-check-core.ts +242 -0
- package/src/data/data-ref.ts +145 -0
- package/src/data/vite-plugin-data.ts +290 -0
- package/src/dev/performance-profiler.ts +213 -0
- package/src/dev/webgl-gpu-timer.ts +53 -0
- package/src/ecs/component-manager.ts +45 -12
- package/src/ecs/game-component.ts +95 -11
- package/src/humanoid/bake.operation.ts +326 -0
- package/src/humanoid/body.ts +663 -0
- package/src/humanoid/clips.ts +149 -0
- package/src/humanoid/compose.ts +209 -0
- package/src/humanoid/generate.ts +189 -0
- package/src/humanoid/index.ts +36 -0
- package/src/humanoid/schema.ts +108 -0
- package/src/humanoid/skeleton.ts +345 -0
- package/src/index.ts +48 -0
- package/src/input/input-manager.ts +1886 -33
- package/src/input/input-types.ts +158 -3
- package/src/input/prompt-labels.ts +122 -0
- package/src/input/rebind-controller.ts +105 -0
- package/src/input/schema.ts +206 -52
- package/src/manifest/index.ts +5 -5
- package/src/manifest/load.ts +125 -72
- package/src/manifest/schema.ts +362 -255
- package/src/react/game-state.tsx +135 -32
- package/src/react/root-adapter.tsx +49 -0
- package/src/react/unmanaged-root-detector.ts +66 -0
- package/src/react/use-data.ts +124 -0
- package/src/react/use-selection.tsx +135 -0
- package/src/runtime/create-runtime.ts +112 -273
- package/src/runtime/debug-bridge.ts +483 -0
- package/src/runtime/debug-registry.ts +856 -0
- package/src/runtime/game.ts +342 -93
- package/src/runtime/gameplay-rng-trap.ts +134 -0
- package/src/runtime/input-router.ts +7 -7
- package/src/runtime/mount-game.ts +40 -38
- package/src/runtime/mount-manifest.ts +169 -37
- package/src/runtime/render-audio-control.ts +168 -0
- package/src/runtime/render-control.ts +522 -0
- package/src/runtime/render-seed.ts +79 -0
- package/src/runtime/state-bridge.ts +24 -10
- package/src/runtime/types.ts +110 -33
- package/src/scene/asset-loaders.ts +10 -36
- package/src/scene/asset-paths.ts +0 -2
- package/src/scene/asset-ref-check.ts +248 -0
- package/src/scene/asset-registry.ts +22 -0
- package/src/scene/component-registry.ts +14 -3
- package/src/scene/defaults.ts +1 -0
- package/src/scene/light-camera-factory.ts +11 -3
- package/src/scene/parse.ts +133 -0
- package/src/scene/scene-apply.ts +55 -4
- package/src/scene/scene-loader.ts +91 -123
- package/src/scene/scene-types.ts +0 -1
- package/src/scene/schema/animation.ts +30 -79
- package/src/scene/schema/entity.ts +20 -0
- package/src/scene/schema/index.ts +2 -46
- package/src/scene/schema/light.ts +16 -1
- package/src/scene/schema/material.ts +96 -91
- package/src/scene/schema/scene-file.ts +1 -7
- package/src/scene/user-data.ts +22 -10
- package/src/setup/setup-renderer.ts +10 -3
- package/src/tools/define-tool.ts +191 -0
- package/src/world2d/authoring-2d.ts +17 -1
- package/src/world2d/collision-2d.ts +1 -1
- package/src/world2d/pixi-game-adapter.ts +19 -17
- package/src/world2d/scene2d-loader.ts +1 -0
- package/src/world2d/types.ts +8 -2
- package/src/animation/anim-graph.ts +0 -406
- package/src/animation/anim-system.ts +0 -28
- package/src/animation/property-track.ts +0 -178
- package/src/animation/schema.ts +0 -204
- package/src/audio/ambient.ts +0 -300
- package/src/audio/impacts.ts +0 -212
- package/src/audio/movement.ts +0 -140
- package/src/audio/musical.ts +0 -200
- package/src/audio/ui-sounds.ts +0 -171
- package/src/audio/vehicle.ts +0 -235
- package/src/audio/weapons.ts +0 -152
- package/src/runtime/scene-ui-bridge.ts +0 -86
- package/src/runtime/scene-ui-data.ts +0 -119
- package/src/scene/schema/ui.ts +0 -602
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
/**
|
|
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 {
|
|
10
|
-
* so no existing `import type {
|
|
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
|
|
13
|
+
export type AdapterSurface = 'threejs' | 'pixijs' | 'react';
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
|
-
* Exhaustiveness guard for `
|
|
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 `
|
|
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
|
package/src/adapter/authoring.ts
CHANGED
|
@@ -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
|
-
*
|
|
4
|
-
*
|
|
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, `
|
|
7
|
-
*
|
|
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
|
-
|
|
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,
|
|
31
|
-
for (const name of input.actionNames())
|
|
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'`
|
|
33
|
-
* self-driven
|
|
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
|
|
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
|
|
125
|
-
export type MountedWorldFor<K extends
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
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).
|
package/src/adapter/index.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
-
/**
|
|
81
|
-
|
|
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
|
}
|