@vgai/engine 0.5.11 → 0.5.13
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 +6 -5
- package/dist/adapter/authoring.d.ts +51 -28
- package/dist/adapter/authoring.d.ts.map +1 -1
- package/dist/adapter/body-marks.d.ts +59 -0
- package/dist/adapter/body-marks.d.ts.map +1 -0
- package/dist/adapter/body-marks.js +62 -0
- package/dist/adapter/constraint.d.ts +41 -0
- package/dist/adapter/constraint.d.ts.map +1 -0
- package/dist/adapter/constraint.js +27 -0
- package/dist/adapter/hierarchy-marks.d.ts +138 -0
- package/dist/adapter/hierarchy-marks.d.ts.map +1 -0
- package/dist/adapter/hierarchy-marks.js +148 -0
- package/dist/adapter/index.d.ts +1 -1
- package/dist/adapter/index.d.ts.map +1 -1
- package/dist/adapter/ingest/contract-system-adapters.d.ts +64 -0
- package/dist/adapter/ingest/contract-system-adapters.d.ts.map +1 -0
- package/dist/adapter/ingest/contract-system-adapters.js +134 -0
- package/dist/adapter/ingest/game-contract.d.ts +87 -9
- package/dist/adapter/ingest/game-contract.d.ts.map +1 -1
- package/dist/adapter/ingest/game-contract.js +7 -6
- package/dist/adapter/ingest/scene-capture.d.ts +31 -4
- package/dist/adapter/ingest/scene-capture.d.ts.map +1 -1
- package/dist/adapter/ingest/scene-capture.js +29 -7
- package/dist/adapter/ingest/structural-ids.d.ts +1 -1
- package/dist/adapter/ingest/structural-ids.js +2 -2
- package/dist/adapter/reflection-probe.d.ts +53 -0
- package/dist/adapter/reflection-probe.d.ts.map +1 -0
- package/dist/adapter/reflection-probe.js +18 -0
- package/dist/asset-formats/index.d.ts +4 -10
- package/dist/asset-formats/index.d.ts.map +1 -1
- package/dist/asset-formats/index.js +3 -8
- package/dist/asset-formats/material.d.ts +0 -66
- package/dist/asset-formats/material.d.ts.map +1 -1
- package/dist/asset-formats/material.js +0 -8
- package/dist/asset-formats/mesh.d.ts +1 -2
- package/dist/asset-formats/mesh.d.ts.map +1 -1
- package/dist/asset-formats/mesh.js +3 -13
- package/dist/asset-formats/render-env.d.ts +2 -2
- package/dist/asset-parse-error.d.ts +4 -5
- package/dist/asset-parse-error.d.ts.map +1 -1
- package/dist/asset-parse-error.js +4 -5
- package/dist/config.d.ts +7 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +7 -0
- package/dist/data/curve.d.ts +116 -0
- package/dist/data/curve.d.ts.map +1 -0
- package/dist/data/curve.js +230 -0
- package/dist/data/vite-plugin-data.d.ts +2 -2
- package/dist/data/vite-plugin-data.d.ts.map +1 -1
- package/dist/data/vite-plugin-data.js +24 -15
- package/dist/dev/performance-profiler.d.ts +1 -0
- package/dist/dev/performance-profiler.d.ts.map +1 -1
- package/dist/dev/performance-profiler.js +25 -2
- package/dist/ecs/user-data.d.ts +49 -1
- package/dist/ecs/user-data.d.ts.map +1 -1
- package/dist/ecs/user-data.js +34 -0
- package/dist/index.d.ts +2 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -3
- package/dist/manifest/index.d.ts +3 -3
- package/dist/manifest/index.d.ts.map +1 -1
- package/dist/manifest/index.js +2 -2
- package/dist/manifest/load.d.ts +15 -67
- package/dist/manifest/load.d.ts.map +1 -1
- package/dist/manifest/load.js +11 -103
- package/dist/manifest/schema.d.ts +18 -103
- package/dist/manifest/schema.d.ts.map +1 -1
- package/dist/manifest/schema.js +59 -179
- package/dist/pixi/index.d.ts +2 -3
- package/dist/pixi/index.d.ts.map +1 -1
- package/dist/pixi/index.js +2 -3
- package/dist/pixi/ingest.d.ts +7 -75
- package/dist/pixi/ingest.d.ts.map +1 -1
- package/dist/pixi/ingest.js +6 -14
- package/dist/pixi/scene-capture.d.ts +2 -2
- package/dist/pixi/scene-capture.js +2 -2
- package/dist/react/use-data.d.ts +10 -5
- package/dist/react/use-data.d.ts.map +1 -1
- package/dist/react/use-data.js +15 -15
- package/dist/render/viewport-shading.d.ts +1 -1
- package/dist/render/viewport-shading.d.ts.map +1 -1
- package/dist/render/viewport-shading.js +14 -0
- package/dist/runtime/create-runtime.d.ts +12 -0
- package/dist/runtime/create-runtime.d.ts.map +1 -1
- package/dist/runtime/create-runtime.js +7 -2
- package/dist/runtime/mount-game.d.ts +1 -1
- package/dist/runtime/mount-game.d.ts.map +1 -1
- package/dist/runtime/mount-manifest.d.ts.map +1 -1
- package/dist/runtime/mount-manifest.js +5 -1
- package/dist/world3d-react/r3f-adapter.d.ts.map +1 -1
- package/dist/world3d-react/r3f-adapter.js +69 -39
- package/dist/world3d-react/renderer-config.d.ts +15 -0
- package/dist/world3d-react/renderer-config.d.ts.map +1 -1
- package/dist/world3d-react/renderer-config.js +15 -0
- package/dist/world3d-react/world-context.d.ts +2 -1
- package/dist/world3d-react/world-context.d.ts.map +1 -1
- package/dist-config/config.js +140 -20
- package/dist-config/config.js.map +4 -4
- package/package.json +1 -1
- package/schemas/engine-capabilities.json +10 -10
- package/schemas/vgai-project.schema.json +21 -76
- package/src/adapter/authoring.ts +54 -31
- package/src/adapter/body-marks.ts +69 -0
- package/src/adapter/constraint.ts +71 -0
- package/src/adapter/hierarchy-marks.ts +155 -0
- package/src/adapter/index.ts +2 -3
- package/src/adapter/ingest/contract-system-adapters.ts +174 -0
- package/src/adapter/ingest/game-contract.ts +98 -9
- package/src/adapter/ingest/scene-capture.ts +61 -11
- package/src/adapter/ingest/structural-ids.ts +2 -2
- package/src/adapter/reflection-probe.ts +75 -0
- package/src/asset-formats/index.ts +4 -10
- package/src/asset-formats/material.ts +0 -11
- package/src/asset-formats/mesh.ts +3 -16
- package/src/asset-parse-error.ts +4 -5
- package/src/config.ts +13 -0
- package/src/data/curve.ts +263 -0
- package/src/data/vite-plugin-data.ts +48 -14
- package/src/dev/performance-profiler.ts +21 -2
- package/src/ecs/user-data.ts +50 -0
- package/src/index.ts +2 -3
- package/src/manifest/index.ts +3 -15
- package/src/manifest/load.ts +27 -143
- package/src/manifest/schema.ts +65 -223
- package/src/pixi/index.ts +2 -15
- package/src/pixi/ingest.ts +13 -87
- package/src/pixi/scene-capture.ts +2 -2
- package/src/react/use-data.ts +15 -20
- package/src/render/viewport-shading.ts +16 -1
- package/src/runtime/create-runtime.ts +30 -5
- package/src/runtime/mount-game.ts +1 -1
- package/src/runtime/mount-manifest.ts +5 -1
- package/src/world3d-react/r3f-adapter.tsx +73 -39
- package/src/world3d-react/renderer-config.ts +31 -0
- package/src/world3d-react/world-context.ts +2 -1
- package/dist/asset-formats/instances.d.ts +0 -17
- package/dist/asset-formats/instances.d.ts.map +0 -1
- package/dist/asset-formats/instances.js +0 -31
- package/dist/asset-formats/parse.d.ts +0 -20
- package/dist/asset-formats/parse.d.ts.map +0 -1
- package/dist/asset-formats/parse.js +0 -34
- package/dist/pixi/ingest-iframe.d.ts +0 -82
- package/dist/pixi/ingest-iframe.d.ts.map +0 -1
- package/dist/pixi/ingest-iframe.js +0 -166
- package/dist/render/instance-mesh.d.ts +0 -5
- package/dist/render/instance-mesh.d.ts.map +0 -1
- package/dist/render/instance-mesh.js +0 -19
- package/schemas/mat.schema.json +0 -255
- package/src/asset-formats/instances.ts +0 -38
- package/src/asset-formats/parse.ts +0 -39
- package/src/pixi/ingest-iframe.ts +0 -255
- package/src/render/instance-mesh.ts +0 -25
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The hierarchy-presentation convention: how a game tells the editor which
|
|
3
|
+
* parts of its LIVE scene graph are one component instance, and which parts are
|
|
4
|
+
* implementation rather than content.
|
|
5
|
+
*
|
|
6
|
+
* ## Why marks and not a second tree
|
|
7
|
+
*
|
|
8
|
+
* The live tree IS the display surface. A hierarchy derived from source would
|
|
9
|
+
* be a mirror layer — a second model of the world that drifts from the one on
|
|
10
|
+
* screen — so the boundaries a reader needs have to live ON the nodes. That is
|
|
11
|
+
* what these marks are, and it is the whole mechanism: a component WRAPS its
|
|
12
|
+
* functionality and MARKS its root; the editor supports the convention
|
|
13
|
+
* generically and never learns which library, importer or lane produced the
|
|
14
|
+
* node.
|
|
15
|
+
*
|
|
16
|
+
* ## STRUCTURE IS THE TREE'S JOB. MARKS ONLY CLASSIFY.
|
|
17
|
+
*
|
|
18
|
+
* There is deliberately no mark that says "show this row somewhere else". A
|
|
19
|
+
* group owns its children by CONTAINING them; a prefab owns its parts by
|
|
20
|
+
* CONTAINING them. If an object reads as belonging under something it is not
|
|
21
|
+
* parented to, the tree is wrong and the tree is what to fix — because the
|
|
22
|
+
* panel is not the only reader. `getWorldPosition`, raycasting, disposal,
|
|
23
|
+
* `traverse`, every physics or gameplay walk and every person reading the
|
|
24
|
+
* source all follow real parenthood, and a presentation-only "logical parent"
|
|
25
|
+
* would be true for exactly one of them.
|
|
26
|
+
*
|
|
27
|
+
* The usual reason a world gets this wrong is that three's parent chain is a
|
|
28
|
+
* TRANSFORM chain: `matrixWorld` is unconditionally `parent × local`, so an
|
|
29
|
+
* object that must not inherit its owner's pose — a physics-driven body writing
|
|
30
|
+
* a world transform every step, a world-space trail or decal, a follow camera
|
|
31
|
+
* that must escape its target's rotation — gets mounted at the scene root, and
|
|
32
|
+
* ownership is lost as a side effect. **That trade is not necessary.** Set
|
|
33
|
+
* `object.matrixWorldAutoUpdate = false` (three r144+) and the parent's
|
|
34
|
+
* propagation skips it: the object stays parented where it belongs and its
|
|
35
|
+
* `matrixWorld` becomes yours to write. Keep it parented, own the matrix, and
|
|
36
|
+
* the hierarchy needs no help.
|
|
37
|
+
*
|
|
38
|
+
* These two marks then have exactly one job left, which is CLASSIFICATION:
|
|
39
|
+
* which of the objects that really are here is the game, and which is the
|
|
40
|
+
* machinery underneath it.
|
|
41
|
+
*
|
|
42
|
+
* ## What the hierarchy is FOR
|
|
43
|
+
*
|
|
44
|
+
* It shows YOUR GAME: the structure you authored, plus the objects your game
|
|
45
|
+
* makes while it runs. Nothing else. Three consequences, and every rule below
|
|
46
|
+
* follows from them:
|
|
47
|
+
*
|
|
48
|
+
* - **A spawned object is content.** A bullet you fired, a wave of enemies, a
|
|
49
|
+
* prop pulled out of a pool and parented into the level — these are rows.
|
|
50
|
+
* They exist, you can select them, and they are usually the exact things you
|
|
51
|
+
* opened the panel to look at. An object your game frees stops being a row,
|
|
52
|
+
* because it stopped existing.
|
|
53
|
+
* - **An implementation artifact is not.** The bones behind a rig, the batched
|
|
54
|
+
* renderer behind a particle system, the instanced-mesh pools behind a tile
|
|
55
|
+
* field, the `target` object three needs in order to aim a directional
|
|
56
|
+
* light: machinery a library or a helper builds so one thing you DID author
|
|
57
|
+
* can work. It belongs UNDER that thing, folded, not beside it.
|
|
58
|
+
* - **"Not in the source file" is the wrong test for either.** Half of a
|
|
59
|
+
* running world is not in the source file — that is what running means.
|
|
60
|
+
* Folding spawned gameplay because a document does not name it is the same
|
|
61
|
+
* defect as listing bones, in the more damaging direction: the rows it loses
|
|
62
|
+
* are the ones you were looking for.
|
|
63
|
+
*
|
|
64
|
+
* ## The two marks
|
|
65
|
+
*
|
|
66
|
+
* - {@link markComponentRoot} — "this subtree is one instance of `<name>`."
|
|
67
|
+
* The editor renders it as ONE row, closed, expandable on demand. Put it on
|
|
68
|
+
* the EARLIEST point the node exists: the constructor that makes it, or the
|
|
69
|
+
* ref callback that receives it. A component whose root is a plain `<mesh>`
|
|
70
|
+
* marks that mesh.
|
|
71
|
+
* - {@link markBuiltInternal} — "this is IMPLEMENTATION, not content." It is
|
|
72
|
+
* **subtree-scoped**: marking the root of a built subtree marks everything
|
|
73
|
+
* under it, so a 60-bone rig costs one call and folding is transitive. The
|
|
74
|
+
* editor hides these rows and offers them behind the same "Reveal Internals"
|
|
75
|
+
* action a source-backed instance's internals already use — revealed rows
|
|
76
|
+
* are read-only, because there is no authored source for a rename or a
|
|
77
|
+
* reparent to write to.
|
|
78
|
+
*
|
|
79
|
+
* An instance therefore reads as the parent of everything meaningful beneath
|
|
80
|
+
* it: content nested inside an implementation node is listed under the instance
|
|
81
|
+
* rather than lost with it (the editor's `hierarchy-component-marks.ts` calls
|
|
82
|
+
* that promotion), so marking a rig does not hide the mesh skinned to it.
|
|
83
|
+
*
|
|
84
|
+
* ## Mark it where the subtree is ATTACHED, by whoever attaches it
|
|
85
|
+
*
|
|
86
|
+
* A mark belongs at the attach seam: the code that puts an implementation
|
|
87
|
+
* subtree into the world marks it in the same breath, because that code is the
|
|
88
|
+
* only thing that knows the subtree is implementation. Not a later sweep of the
|
|
89
|
+
* tree — "everything present at time T that the source did not name" is the
|
|
90
|
+
* wrong predicate twice over. It arrives too early for anything attached
|
|
91
|
+
* asynchronously (a model clone landing after its bytes resolve, a node gated
|
|
92
|
+
* on an audio decode) and too late in principle for anything attached
|
|
93
|
+
* afterwards (every spawn) — and were it re-run to catch those, it would
|
|
94
|
+
* classify each spawned object as implementation, which is the second bullet
|
|
95
|
+
* above inverted. Attach-seam marking has neither failure: it fires once, at
|
|
96
|
+
* the moment the answer is known, and an unmarked node is content by default.
|
|
97
|
+
*
|
|
98
|
+
* The subtree scope is what keeps this cheap — one call per attached root, not
|
|
99
|
+
* one per node, so a rig or a pool costs one line at the one place that builds
|
|
100
|
+
* it.
|
|
101
|
+
*
|
|
102
|
+
* ## What is NOT built-internal
|
|
103
|
+
*
|
|
104
|
+
* A node your game means as content — even one a class rather than JSX
|
|
105
|
+
* constructs — is content. `vgaiBuiltInternal` is not "the editor cannot write
|
|
106
|
+
* this"; that question is `TransformProvider.editability`'s, answered per
|
|
107
|
+
* channel with a sentence. This mark answers "is this implementation", and
|
|
108
|
+
* getting it wrong hides real content.
|
|
109
|
+
*
|
|
110
|
+
* Both keys live in the typed `userData` registry (`../ecs/user-data.ts`) so
|
|
111
|
+
* their literal strings are spelled exactly once; this module is the only
|
|
112
|
+
* reader/writer, which is why the helpers below exist at all rather than
|
|
113
|
+
* `setUserData` calls scattered through emitters and prefabs.
|
|
114
|
+
*/
|
|
115
|
+
import { getUserData, setUserData } from '../ecs/user-data';
|
|
116
|
+
/**
|
|
117
|
+
* Declare `node` the root of one component instance, displayed under `name`.
|
|
118
|
+
*
|
|
119
|
+
* `name` is the COMPONENT's name (`'Coin'`, `'HeroBox'`), not the instance's —
|
|
120
|
+
* the instance is already named by `node.name`, and the editor prints both.
|
|
121
|
+
*/
|
|
122
|
+
export function markComponentRoot(node, name) {
|
|
123
|
+
setUserData(node, 'vgaiComponentRoot', name);
|
|
124
|
+
}
|
|
125
|
+
/** The component name `node` is the root of, or `undefined` for an ordinary node. */
|
|
126
|
+
export function componentRootName(node) {
|
|
127
|
+
const name = getUserData(node, 'vgaiComponentRoot');
|
|
128
|
+
return typeof name === 'string' && name ? name : undefined;
|
|
129
|
+
}
|
|
130
|
+
/** Whether `node` is a marked component-instance root. */
|
|
131
|
+
export function isComponentRoot(node) {
|
|
132
|
+
return componentRootName(node) !== undefined;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Declare `node` (and everything under it) IMPLEMENTATION of whatever node it
|
|
136
|
+
* sits under, rather than content of its own. Call it on the ROOT of the built
|
|
137
|
+
* subtree only, at the seam that attaches it — see this module's header for why
|
|
138
|
+
* the seam and not a sweep.
|
|
139
|
+
*/
|
|
140
|
+
export function markBuiltInternal(node) {
|
|
141
|
+
setUserData(node, 'vgaiBuiltInternal', true);
|
|
142
|
+
}
|
|
143
|
+
/** Whether `node` itself carries the implementation mark. Ancestry is the
|
|
144
|
+
* CALLER's walk — see this module's header for why the mark is subtree-scoped
|
|
145
|
+
* but not restamped onto descendants. */
|
|
146
|
+
export function isBuiltInternal(node) {
|
|
147
|
+
return getUserData(node, 'vgaiBuiltInternal') === true;
|
|
148
|
+
}
|
package/dist/adapter/index.d.ts
CHANGED
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
* `@engine/adapter/first-party-systems` createNavigationAdapter
|
|
24
24
|
*/
|
|
25
25
|
export type { AdapterSurface } from './adapter-surface';
|
|
26
|
-
export type { AssetDropContext, AssetDropProvider, AssetSubjectProvider, AuthoringAdapter, AuthoringAssetSubject, AuthoringCapabilities, AuthoringProvenance, BoxEditProvider, BoxEditReferencePoint, ColorSampleProvider, CreationSiteProvider, DOMRectLike, EditorNode, EditorNodeRole,
|
|
26
|
+
export type { AssetDropContext, AssetDropProvider, AssetSubjectProvider, AuthoringAdapter, AuthoringAssetSubject, AuthoringCapabilities, AuthoringProvenance, BoxEditProvider, BoxEditReferencePoint, ColorSampleProvider, CreationSiteProvider, DOMRectLike, EditorNode, EditorNodeRole, HierarchyProvider, InspectorProvider, NodeCreationSite, PersistenceProvider, PickProvider, PropertyDescriptor, RectProvider, RelatedSubjectLink, RelatedSubjectsProvider, SelectionProvider, SelectionResolution, StoriesProvider, StoryRef, StructureProvider, TextProvider, TransformChannel, TransformEditability, TransformObservation, TransformProvider, } from './authoring';
|
|
27
27
|
export type { ColyseusNetworkingConfig } from './colyseus-networking-adapter';
|
|
28
28
|
export type { CanvasHostContext, DomHostContext, HostContextBase, HostContextFor, HostSurface, ThreeHostContext, } from './host-context';
|
|
29
29
|
export type { MountedPixiRoot, MountedReactRoot, MountedRoot, MountedRootBase, MountedThreeRoot, RootAdapter, RootStateObserver, SurfaceAdapter, SurfaceAdapterFor, } from './root-adapter';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/adapter/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxD,YAAY,EACV,gBAAgB,EAChB,iBAAiB,EACjB,oBAAoB,EACpB,gBAAgB,EAChB,qBAAqB,EACrB,qBAAqB,EACrB,mBAAmB,EACnB,eAAe,EACf,qBAAqB,EACrB,mBAAmB,EACnB,oBAAoB,EACpB,WAAW,EACX,UAAU,EACV,cAAc,EACd,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/adapter/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxD,YAAY,EACV,gBAAgB,EAChB,iBAAiB,EACjB,oBAAoB,EACpB,gBAAgB,EAChB,qBAAqB,EACrB,qBAAqB,EACrB,mBAAmB,EACnB,eAAe,EACf,qBAAqB,EACrB,mBAAmB,EACnB,oBAAoB,EACpB,WAAW,EACX,UAAU,EACV,cAAc,EACd,iBAAiB,EACjB,iBAAiB,EACjB,gBAAgB,EAChB,mBAAmB,EACnB,YAAY,EACZ,kBAAkB,EAClB,YAAY,EACZ,kBAAkB,EAClB,uBAAuB,EACvB,iBAAiB,EACjB,mBAAmB,EACnB,eAAe,EACf,QAAQ,EACR,iBAAiB,EACjB,YAAY,EACZ,gBAAgB,EAChB,oBAAoB,EACpB,oBAAoB,EACpB,iBAAiB,GAClB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AAC9E,YAAY,EACV,iBAAiB,EACjB,cAAc,EACd,eAAe,EACf,cAAc,EACd,WAAW,EACX,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EACV,eAAe,EACf,gBAAgB,EAChB,WAAW,EACX,eAAe,EACf,gBAAgB,EAChB,WAAW,EACX,iBAAiB,EACjB,cAAc,EACd,iBAAiB,GAClB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAC9F,YAAY,EACV,YAAY,EACZ,eAAe,EACf,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,mBAAmB,EACnB,eAAe,EACf,kBAAkB,EAClB,iBAAiB,EACjB,QAAQ,EACR,eAAe,EACf,eAAe,EACf,OAAO,EACP,iBAAiB,EACjB,QAAQ,EACR,eAAe,EACf,iBAAiB,EACjB,cAAc,EACd,kBAAkB,EAClB,gBAAgB,EAChB,QAAQ,EACR,cAAc,EACd,WAAW,GACZ,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Projects a game's declared {@link VgaiGameSystemAdapters}
|
|
3
|
+
* (`window.vgaiGame.systems.systemAdapters`) onto the host's ordinary
|
|
4
|
+
* {@link SystemAdapters} bag — the ingest-realm counterpart of a first-party
|
|
5
|
+
* world's `ctx.registerSystemAdapter`, and the sibling of
|
|
6
|
+
* `contract-debug-adapter.ts` (which owns the `debug` slot).
|
|
7
|
+
*
|
|
8
|
+
* ## Why a projection with a verdict per slot
|
|
9
|
+
*
|
|
10
|
+
* The ingestion bar (docs/BRINGING-AN-EXISTING-GAME.md §The ingestion
|
|
11
|
+
* checklist) admits exactly two terminal states per slot: IMPLEMENTED or
|
|
12
|
+
* IMPLEMENTED-EMPTY. `SystemAdapters` alone cannot express the second — an
|
|
13
|
+
* omitted key means "unsupported", which is the same shape as "nobody looked".
|
|
14
|
+
* So this returns THREE lists, and the caller hands the non-`bound` ones to the
|
|
15
|
+
* coverage report, where a positively-answered absence prints as terminal and an
|
|
16
|
+
* unanswered slot prints as a work order.
|
|
17
|
+
*
|
|
18
|
+
* ## Why the shape check
|
|
19
|
+
*
|
|
20
|
+
* A slot that declares `{}` would otherwise register as "implemented" and light
|
|
21
|
+
* up an editor panel over an object with no methods. Each slot therefore names
|
|
22
|
+
* the members its interface makes REQUIRED, and a declaration missing any of
|
|
23
|
+
* them is `malformed` — reported by name, never silently bound and never
|
|
24
|
+
* silently dropped. This is the same honesty the anti-shim rule asks of the
|
|
25
|
+
* other direction: a wrong "present" claim is as much a defect as a wrong
|
|
26
|
+
* "empty" one.
|
|
27
|
+
*
|
|
28
|
+
* Nothing here calls a declared method. Presence and shape only.
|
|
29
|
+
*/
|
|
30
|
+
import type { SystemAdapters } from '../system-adapter';
|
|
31
|
+
import type { VgaiGameSystemAdapters, VgaiGameSystems } from './game-contract';
|
|
32
|
+
/** The slots a game may declare through the contract (`debug` is projected from
|
|
33
|
+
* `commands`/`state` instead — see {@link VgaiGameSystemAdapters}). */
|
|
34
|
+
export type ContractSystemSlot = keyof VgaiGameSystemAdapters;
|
|
35
|
+
/** Fixed slot order, so two reports of the same mount are diffable line for
|
|
36
|
+
* line (the same rule the coverage report's row order follows). */
|
|
37
|
+
export declare const CONTRACT_SYSTEM_SLOTS: readonly ContractSystemSlot[];
|
|
38
|
+
/** One slot the game positively answered as having nothing behind it. */
|
|
39
|
+
export interface ContractSystemEmptySlot {
|
|
40
|
+
readonly slot: ContractSystemSlot;
|
|
41
|
+
/** The game's own source-level evidence, verbatim. */
|
|
42
|
+
readonly evidence: string;
|
|
43
|
+
}
|
|
44
|
+
/** One slot whose declaration could not be honoured, and why. */
|
|
45
|
+
export interface ContractSystemMalformedSlot {
|
|
46
|
+
readonly slot: ContractSystemSlot;
|
|
47
|
+
readonly reason: string;
|
|
48
|
+
}
|
|
49
|
+
export interface ContractSystemAdapterProjection {
|
|
50
|
+
/** Real adapters, ready to spread onto a `MountedRoot`'s `systems`. */
|
|
51
|
+
readonly bound: Partial<Pick<SystemAdapters, ContractSystemSlot>>;
|
|
52
|
+
/** Slots answered IMPLEMENTED-EMPTY, with the evidence. */
|
|
53
|
+
readonly empty: readonly ContractSystemEmptySlot[];
|
|
54
|
+
/** Slots declared but unusable — bound to nothing, reported by name. */
|
|
55
|
+
readonly malformed: readonly ContractSystemMalformedSlot[];
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Read the declared slots and sort each into exactly one verdict. A game that
|
|
59
|
+
* declared no `systemAdapters` at all projects to three empty lists — which is
|
|
60
|
+
* the "nobody answered" case, and is deliberately NOT the same as declaring
|
|
61
|
+
* every slot empty.
|
|
62
|
+
*/
|
|
63
|
+
export declare function projectContractSystemAdapters(systems: VgaiGameSystems | undefined | null): ContractSystemAdapterProjection;
|
|
64
|
+
//# sourceMappingURL=contract-system-adapters.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract-system-adapters.d.ts","sourceRoot":"","sources":["../../../src/adapter/ingest/contract-system-adapters.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,KAAK,EAAE,sBAAsB,EAAuB,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAEpG;wEACwE;AACxE,MAAM,MAAM,kBAAkB,GAAG,MAAM,sBAAsB,CAAC;AA8B9D;oEACoE;AACpE,eAAO,MAAM,qBAAqB,EAAE,SAAS,kBAAkB,EAM9D,CAAC;AAEF,yEAAyE;AACzE,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,IAAI,EAAE,kBAAkB,CAAC;IAClC,sDAAsD;IACtD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,iEAAiE;AACjE,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,IAAI,EAAE,kBAAkB,CAAC;IAClC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,+BAA+B;IAC9C,uEAAuE;IACvE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,cAAc,EAAE,kBAAkB,CAAC,CAAC,CAAC;IAClE,2DAA2D;IAC3D,QAAQ,CAAC,KAAK,EAAE,SAAS,uBAAuB,EAAE,CAAC;IACnD,wEAAwE;IACxE,QAAQ,CAAC,SAAS,EAAE,SAAS,2BAA2B,EAAE,CAAC;CAC5D;AAsBD;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,eAAe,GAAG,SAAS,GAAG,IAAI,GAC1C,+BAA+B,CAgDjC"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Projects a game's declared {@link VgaiGameSystemAdapters}
|
|
3
|
+
* (`window.vgaiGame.systems.systemAdapters`) onto the host's ordinary
|
|
4
|
+
* {@link SystemAdapters} bag — the ingest-realm counterpart of a first-party
|
|
5
|
+
* world's `ctx.registerSystemAdapter`, and the sibling of
|
|
6
|
+
* `contract-debug-adapter.ts` (which owns the `debug` slot).
|
|
7
|
+
*
|
|
8
|
+
* ## Why a projection with a verdict per slot
|
|
9
|
+
*
|
|
10
|
+
* The ingestion bar (docs/BRINGING-AN-EXISTING-GAME.md §The ingestion
|
|
11
|
+
* checklist) admits exactly two terminal states per slot: IMPLEMENTED or
|
|
12
|
+
* IMPLEMENTED-EMPTY. `SystemAdapters` alone cannot express the second — an
|
|
13
|
+
* omitted key means "unsupported", which is the same shape as "nobody looked".
|
|
14
|
+
* So this returns THREE lists, and the caller hands the non-`bound` ones to the
|
|
15
|
+
* coverage report, where a positively-answered absence prints as terminal and an
|
|
16
|
+
* unanswered slot prints as a work order.
|
|
17
|
+
*
|
|
18
|
+
* ## Why the shape check
|
|
19
|
+
*
|
|
20
|
+
* A slot that declares `{}` would otherwise register as "implemented" and light
|
|
21
|
+
* up an editor panel over an object with no methods. Each slot therefore names
|
|
22
|
+
* the members its interface makes REQUIRED, and a declaration missing any of
|
|
23
|
+
* them is `malformed` — reported by name, never silently bound and never
|
|
24
|
+
* silently dropped. This is the same honesty the anti-shim rule asks of the
|
|
25
|
+
* other direction: a wrong "present" claim is as much a defect as a wrong
|
|
26
|
+
* "empty" one.
|
|
27
|
+
*
|
|
28
|
+
* Nothing here calls a declared method. Presence and shape only.
|
|
29
|
+
*/
|
|
30
|
+
/**
|
|
31
|
+
* The members each slot's interface makes NON-optional. A declaration missing
|
|
32
|
+
* one of these cannot honour the interface, whatever else it carries.
|
|
33
|
+
*
|
|
34
|
+
* This table is the single place the required surface is spelled; it is checked
|
|
35
|
+
* against the interfaces by the compiler at the point of use below (each list
|
|
36
|
+
* is typed as keys of its own adapter), so it cannot drift into naming a member
|
|
37
|
+
* that does not exist.
|
|
38
|
+
*/
|
|
39
|
+
const REQUIRED_MEMBERS = {
|
|
40
|
+
physics: ['ownerOf', 'freeze', 'commit', 'unfreeze'],
|
|
41
|
+
networking: [
|
|
42
|
+
'peers',
|
|
43
|
+
'networkId',
|
|
44
|
+
'authority',
|
|
45
|
+
'editable',
|
|
46
|
+
'getConnectionState',
|
|
47
|
+
'getRoomInfo',
|
|
48
|
+
'getReplicationStats',
|
|
49
|
+
'subscribe',
|
|
50
|
+
],
|
|
51
|
+
navigation: ['hasNavMesh', 'findPath', 'debugMesh'],
|
|
52
|
+
audio: ['setMuted', 'isMuted'],
|
|
53
|
+
renderDebug: ['captureFrame'],
|
|
54
|
+
};
|
|
55
|
+
/** Fixed slot order, so two reports of the same mount are diffable line for
|
|
56
|
+
* line (the same rule the coverage report's row order follows). */
|
|
57
|
+
export const CONTRACT_SYSTEM_SLOTS = [
|
|
58
|
+
'physics',
|
|
59
|
+
'networking',
|
|
60
|
+
'navigation',
|
|
61
|
+
'audio',
|
|
62
|
+
'renderDebug',
|
|
63
|
+
];
|
|
64
|
+
const EMPTY_PROJECTION = {
|
|
65
|
+
bound: {},
|
|
66
|
+
empty: [],
|
|
67
|
+
malformed: [],
|
|
68
|
+
};
|
|
69
|
+
function isEmptyRecord(value) {
|
|
70
|
+
return value.present === false;
|
|
71
|
+
}
|
|
72
|
+
function missingMembers(slot, value) {
|
|
73
|
+
const missing = [];
|
|
74
|
+
for (const member of REQUIRED_MEMBERS[slot]) {
|
|
75
|
+
if (typeof value[member] !== 'function') {
|
|
76
|
+
missing.push(member);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return missing;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Read the declared slots and sort each into exactly one verdict. A game that
|
|
83
|
+
* declared no `systemAdapters` at all projects to three empty lists — which is
|
|
84
|
+
* the "nobody answered" case, and is deliberately NOT the same as declaring
|
|
85
|
+
* every slot empty.
|
|
86
|
+
*/
|
|
87
|
+
export function projectContractSystemAdapters(systems) {
|
|
88
|
+
const declared = systems?.systemAdapters;
|
|
89
|
+
if (!declared)
|
|
90
|
+
return EMPTY_PROJECTION;
|
|
91
|
+
const bound = {};
|
|
92
|
+
const empty = [];
|
|
93
|
+
const malformed = [];
|
|
94
|
+
for (const slot of CONTRACT_SYSTEM_SLOTS) {
|
|
95
|
+
const value = declared[slot];
|
|
96
|
+
if (value === undefined || value === null)
|
|
97
|
+
continue;
|
|
98
|
+
if (typeof value !== 'object') {
|
|
99
|
+
malformed.push({
|
|
100
|
+
slot,
|
|
101
|
+
reason: `declared as ${typeof value}; expected an adapter object or { present: false, evidence }`,
|
|
102
|
+
});
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
if (isEmptyRecord(value)) {
|
|
106
|
+
const evidence = value.evidence;
|
|
107
|
+
if (typeof evidence !== 'string' || evidence.trim() === '') {
|
|
108
|
+
// An empty claim with no evidence is exactly the "wrong empty claim"
|
|
109
|
+
// the bar calls a defect — it asserts an absence nobody can re-check.
|
|
110
|
+
malformed.push({
|
|
111
|
+
slot,
|
|
112
|
+
reason: 'declared `present: false` with no `evidence` string to back the absence',
|
|
113
|
+
});
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
empty.push({ slot, evidence });
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
const missing = missingMembers(slot, value);
|
|
120
|
+
if (missing.length > 0) {
|
|
121
|
+
malformed.push({
|
|
122
|
+
slot,
|
|
123
|
+
reason: `declared an adapter missing required member(s): ${missing.join(', ')}`,
|
|
124
|
+
});
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
bound[slot] = value;
|
|
128
|
+
}
|
|
129
|
+
return {
|
|
130
|
+
bound: bound,
|
|
131
|
+
empty,
|
|
132
|
+
malformed,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
@@ -15,8 +15,10 @@
|
|
|
15
15
|
* endpoint by endpoint: capture infers what it can (the scene), the game
|
|
16
16
|
* declares what inference can't reach (its DOM root, its session lifecycle).
|
|
17
17
|
*
|
|
18
|
-
* Origin (root), F17+F21 (lifecycle), WO-SYS1 (systems)
|
|
18
|
+
* Origin (root), F17+F21 (lifecycle), WO-SYS1 (systems), WO-SYS2
|
|
19
|
+
* (`systems.systemAdapters`).
|
|
19
20
|
*/
|
|
21
|
+
import type { AudioAdapter, NavigationAdapter, NetworkingAdapter, PhysicsAdapter, RenderDebugAdapter } from '../system-adapter';
|
|
20
22
|
/**
|
|
21
23
|
* Session lifecycle endpoints. Declaring `start` means "I support cold
|
|
22
24
|
* mount": when the host sets `window.__vgaiMountCold` before the game's entry
|
|
@@ -62,6 +64,27 @@ export interface VgaiGameStateProvider {
|
|
|
62
64
|
tier?: 'observable' | 'assisted';
|
|
63
65
|
read(): unknown;
|
|
64
66
|
}
|
|
67
|
+
/**
|
|
68
|
+
* One top-level semantic hierarchy group from the game's OWN model. `count`
|
|
69
|
+
* is recomputed by the game when the host reads the hierarchy; it is not
|
|
70
|
+
* inferred from render objects. The editor presents these rows beside the
|
|
71
|
+
* captured render tree, so a system-driven game can say what its content is
|
|
72
|
+
* without pretending its scene graph is authored truth.
|
|
73
|
+
*/
|
|
74
|
+
export interface VgaiGameHierarchyGroup {
|
|
75
|
+
id: string;
|
|
76
|
+
label: string;
|
|
77
|
+
count: number;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Synchronous read plus an optional game-owned invalidation signal. The
|
|
81
|
+
* editor never polls or guesses when a game's model changed; a dynamic game
|
|
82
|
+
* subscribes its ordinary authoring hierarchy to the same truth it reads.
|
|
83
|
+
*/
|
|
84
|
+
export interface VgaiGameHierarchyProvider {
|
|
85
|
+
(): VgaiGameHierarchyGroup[];
|
|
86
|
+
subscribe?(listener: () => void): () => void;
|
|
87
|
+
}
|
|
65
88
|
/**
|
|
66
89
|
* The game's SYSTEM surface: what its content actually IS, as opposed to how
|
|
67
90
|
* it renders. An ingested game's content is not always its scene graph — in a
|
|
@@ -69,9 +92,10 @@ export interface VgaiGameStateProvider {
|
|
|
69
92
|
* is reached through the game's own verbs, which `root`/`lifecycle` could not
|
|
70
93
|
* express.
|
|
71
94
|
*
|
|
72
|
-
*
|
|
73
|
-
* `adapter/ingest/contract-debug-adapter.ts
|
|
74
|
-
*
|
|
95
|
+
* Every member is read by a concrete consumer: commands/state are projected
|
|
96
|
+
* by `adapter/ingest/contract-debug-adapter.ts` onto the host's ordinary
|
|
97
|
+
* `DebugAdapter` (`adapter/system-adapter.ts`), while `hierarchy` is projected
|
|
98
|
+
* by the editor onto the ordinary `AuthoringAdapter.hierarchy` surface. Thus
|
|
75
99
|
* `game.commands()`/`game.state()` reach an ingested game through the same
|
|
76
100
|
* bridge first-party content uses, with no second vocabulary for agents to
|
|
77
101
|
* learn. That is deliberate scope: this
|
|
@@ -84,6 +108,60 @@ export interface VgaiGameSystems {
|
|
|
84
108
|
commands?: VgaiGameCommand[];
|
|
85
109
|
/** State reads, enumerated by `game.providers()` and read by `game.state(...)`. */
|
|
86
110
|
state?: VgaiGameStateProvider[];
|
|
111
|
+
/** Semantic hierarchy groups from the game's own model, recomputed on read. */
|
|
112
|
+
hierarchy?: VgaiGameHierarchyProvider;
|
|
113
|
+
/**
|
|
114
|
+
* The game's own {@link SystemAdapters} slots — the ingest-realm equivalent
|
|
115
|
+
* of a first-party world's `ctx.registerSystemAdapter`. Read and projected by
|
|
116
|
+
* `contract-system-adapters.ts` onto the mounted root's `systems` bag, so an
|
|
117
|
+
* ingested game's physics/audio/navigation/networking reach the editor's
|
|
118
|
+
* ordinary panels through the SAME registry a native world publishes to.
|
|
119
|
+
*/
|
|
120
|
+
systemAdapters?: VgaiGameSystemAdapters;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* A slot's IMPLEMENTED-EMPTY answer: "this game genuinely has no X", carried
|
|
124
|
+
* with the source-level evidence that establishes it.
|
|
125
|
+
*
|
|
126
|
+
* This exists because `SystemAdapters` is capability-by-PRESENCE, and presence
|
|
127
|
+
* has only two values while the ingestion bar (docs/BRINGING-AN-EXISTING-GAME.md
|
|
128
|
+
* §The ingestion checklist) has three inputs: bound, positively-absent, and
|
|
129
|
+
* not-yet-answered. Omitting a slot cannot tell the last two apart — an editor
|
|
130
|
+
* reading a bare absence cannot know whether anyone ever looked. Declaring this
|
|
131
|
+
* record says someone looked, says what they found, and turns a work-order row
|
|
132
|
+
* into a terminal one.
|
|
133
|
+
*
|
|
134
|
+
* It is deliberately NOT an adapter whose methods return zeros: a
|
|
135
|
+
* `getConnectionState()` of `'disconnected'` on a game with no transport at all
|
|
136
|
+
* is a fabrication (it implies a connection that could exist), which the
|
|
137
|
+
* anti-shim rule forbids. The absence is stated, never simulated.
|
|
138
|
+
*/
|
|
139
|
+
export interface VgaiGameSystemEmpty {
|
|
140
|
+
/** Always `false` — the discriminant that separates this from an adapter. */
|
|
141
|
+
present: false;
|
|
142
|
+
/**
|
|
143
|
+
* Why the slot is empty, in SOURCE terms: what was searched and what was
|
|
144
|
+
* found. "no netcode anywhere in `src/`" is a finished answer; "not
|
|
145
|
+
* implemented yet" is not one, and a reviewer reading this field is meant to
|
|
146
|
+
* be able to re-run the search.
|
|
147
|
+
*/
|
|
148
|
+
evidence: string;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* The declarable `SystemAdapters` slots, each either a real implementation or a
|
|
152
|
+
* positively-answered {@link VgaiGameSystemEmpty}.
|
|
153
|
+
*
|
|
154
|
+
* `debug` is deliberately NOT here: it is already the projection of
|
|
155
|
+
* `commands`/`state` above (`contract-debug-adapter.ts`), and a second door onto
|
|
156
|
+
* the same slot would let a game declare two different debug planes with no rule
|
|
157
|
+
* for which wins.
|
|
158
|
+
*/
|
|
159
|
+
export interface VgaiGameSystemAdapters {
|
|
160
|
+
physics?: PhysicsAdapter | VgaiGameSystemEmpty;
|
|
161
|
+
networking?: NetworkingAdapter | VgaiGameSystemEmpty;
|
|
162
|
+
navigation?: NavigationAdapter | VgaiGameSystemEmpty;
|
|
163
|
+
audio?: AudioAdapter | VgaiGameSystemEmpty;
|
|
164
|
+
renderDebug?: RenderDebugAdapter | VgaiGameSystemEmpty;
|
|
87
165
|
}
|
|
88
166
|
export interface VgaiGameContract {
|
|
89
167
|
/** Bump only on breaking shape changes; additive endpoints keep version 1. */
|
|
@@ -108,11 +186,11 @@ export interface VgaiGameContract {
|
|
|
108
186
|
* forward-compatibility hinge: a future v2 game on a v1 host is ignored
|
|
109
187
|
* (pre-contract fallbacks apply) rather than half-interpreted.
|
|
110
188
|
*
|
|
111
|
-
* `scope` is the REALM to read from, and defaults to this module's own
|
|
112
|
-
* —
|
|
113
|
-
* one global.
|
|
114
|
-
*
|
|
115
|
-
*
|
|
189
|
+
* `scope` is the REALM to read from, and defaults to this module's own
|
|
190
|
+
* `window` — the realm every ingest mount runs the game's modules in, where the
|
|
191
|
+
* game and the host share one global. It is a parameter at all because the
|
|
192
|
+
* contract is a property of the realm the game runs in, never of the realm that
|
|
193
|
+
* happens to be asking.
|
|
116
194
|
*/
|
|
117
195
|
export declare function readGameContract(scope?: Window | null | undefined): VgaiGameContract | null;
|
|
118
196
|
//# sourceMappingURL=game-contract.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"game-contract.d.ts","sourceRoot":"","sources":["../../../src/adapter/ingest/game-contract.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"game-contract.d.ts","sourceRoot":"","sources":["../../../src/adapter/ingest/game-contract.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EACV,YAAY,EACZ,iBAAiB,EACjB,iBAAiB,EACjB,cAAc,EACd,kBAAkB,EACnB,MAAM,mBAAmB,CAAC;AAE3B;;;;;;;;;GASG;AACH,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,IAAI,IAAI,CAAC;IACf,KAAK,CAAC,IAAI,IAAI,CAAC;IACf,MAAM,CAAC,IAAI,IAAI,CAAC;CACjB;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+EAA+E;IAC/E,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,GAAG,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACrD;AAED;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,YAAY,GAAG,UAAU,CAAC;IACjC,IAAI,IAAI,OAAO,CAAC;CACjB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,sBAAsB;IACrC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;GAIG;AACH,MAAM,WAAW,yBAAyB;IACxC,IAAI,sBAAsB,EAAE,CAAC;IAC7B,SAAS,CAAC,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC;CAC9C;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,eAAe;IAC9B,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,eAAe,EAAE,CAAC;IAC7B,mFAAmF;IACnF,KAAK,CAAC,EAAE,qBAAqB,EAAE,CAAC;IAChC,+EAA+E;IAC/E,SAAS,CAAC,EAAE,yBAAyB,CAAC;IACtC;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,sBAAsB,CAAC;CACzC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,mBAAmB;IAClC,6EAA6E;IAC7E,OAAO,EAAE,KAAK,CAAC;IACf;;;;;OAKG;IACH,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,sBAAsB;IACrC,OAAO,CAAC,EAAE,cAAc,GAAG,mBAAmB,CAAC;IAC/C,UAAU,CAAC,EAAE,iBAAiB,GAAG,mBAAmB,CAAC;IACrD,UAAU,CAAC,EAAE,iBAAiB,GAAG,mBAAmB,CAAC;IACrD,KAAK,CAAC,EAAE,YAAY,GAAG,mBAAmB,CAAC;IAC3C,WAAW,CAAC,EAAE,kBAAkB,GAAG,mBAAmB,CAAC;CACxD;AAED,MAAM,WAAW,gBAAgB;IAC/B,8EAA8E;IAC9E,eAAe,EAAE,CAAC,CAAC;IACnB;;;;;OAKG;IACH,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,SAAS,CAAC,EAAE,iBAAiB,CAAC;IAC9B;;;;OAIG;IACH,OAAO,CAAC,EAAE,eAAe,CAAC;CAC3B;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,GAAE,MAAM,GAAG,IAAI,GAAG,SAAyD,GAC/E,gBAAgB,GAAG,IAAI,CAKzB"}
|
|
@@ -15,18 +15,19 @@
|
|
|
15
15
|
* endpoint by endpoint: capture infers what it can (the scene), the game
|
|
16
16
|
* declares what inference can't reach (its DOM root, its session lifecycle).
|
|
17
17
|
*
|
|
18
|
-
* Origin (root), F17+F21 (lifecycle), WO-SYS1 (systems)
|
|
18
|
+
* Origin (root), F17+F21 (lifecycle), WO-SYS1 (systems), WO-SYS2
|
|
19
|
+
* (`systems.systemAdapters`).
|
|
19
20
|
*/
|
|
20
21
|
/**
|
|
21
22
|
* Read the declared contract, if any. The `contractVersion` gate is the
|
|
22
23
|
* forward-compatibility hinge: a future v2 game on a v1 host is ignored
|
|
23
24
|
* (pre-contract fallbacks apply) rather than half-interpreted.
|
|
24
25
|
*
|
|
25
|
-
* `scope` is the REALM to read from, and defaults to this module's own
|
|
26
|
-
* —
|
|
27
|
-
* one global.
|
|
28
|
-
*
|
|
29
|
-
*
|
|
26
|
+
* `scope` is the REALM to read from, and defaults to this module's own
|
|
27
|
+
* `window` — the realm every ingest mount runs the game's modules in, where the
|
|
28
|
+
* game and the host share one global. It is a parameter at all because the
|
|
29
|
+
* contract is a property of the realm the game runs in, never of the realm that
|
|
30
|
+
* happens to be asking.
|
|
30
31
|
*/
|
|
31
32
|
export function readGameContract(scope = typeof window === 'undefined' ? null : window) {
|
|
32
33
|
const declared = scope
|
|
@@ -67,11 +67,11 @@ export interface SceneCaptureOptions {
|
|
|
67
67
|
* each with its own offscreen renderer and its own little light rig) is a
|
|
68
68
|
* candidate to be captured AS THE GAME.
|
|
69
69
|
*
|
|
70
|
-
* That is what made
|
|
71
|
-
*
|
|
70
|
+
* That is what made the "a game bundling its own three is DETECTED, never
|
|
71
|
+
* silently mistaken for a capture" spec
|
|
72
72
|
* pass or fail on timing alone: whether a thumbnail happened to bake inside
|
|
73
|
-
* the game's
|
|
74
|
-
* preview scene as the game and
|
|
73
|
+
* the game's capture window. When it did, the editor adopted its own
|
|
74
|
+
* preview scene as the game and the mount reported success.
|
|
75
75
|
*
|
|
76
76
|
* Identity, not shape, is the discriminator: a host renderer and a game
|
|
77
77
|
* renderer are the same class, both built after install, both drawing real
|
|
@@ -80,10 +80,37 @@ export interface SceneCaptureOptions {
|
|
|
80
80
|
*/
|
|
81
81
|
isHostRenderer?: (renderer: unknown) => boolean;
|
|
82
82
|
}
|
|
83
|
+
/**
|
|
84
|
+
* Brackets ONE `render()` call the captured renderer makes.
|
|
85
|
+
*
|
|
86
|
+
* The trap already stands between an ingested game and its own
|
|
87
|
+
* `WebGLRenderer.render`, which is the only place a host can see the game's
|
|
88
|
+
* render pass begin and end — the game owns its loop, so nothing else in the
|
|
89
|
+
* editor gets a `finally` around it. That is exactly the bracket
|
|
90
|
+
* `dev/render-debug-adapter.ts`'s `beforeRender`/`afterRender` need, so the
|
|
91
|
+
* first-party `RenderDebugAdapter` works for an ingested game with no per-game
|
|
92
|
+
* shimming and no second capture mechanism.
|
|
93
|
+
*
|
|
94
|
+
* Neither hook may throw: they run inside the game's own render call, so an
|
|
95
|
+
* exception here would break the game's frame. The trap calls them in a
|
|
96
|
+
* `try`/`finally` for `after`, but a throwing `before` is the hook author's bug.
|
|
97
|
+
*/
|
|
98
|
+
export interface RenderPassHooks {
|
|
99
|
+
before(): void;
|
|
100
|
+
after(): void;
|
|
101
|
+
}
|
|
83
102
|
/** Handle returned by {@link installSceneCapture}. */
|
|
84
103
|
export interface SceneCaptureHandle {
|
|
85
104
|
/** The captured runtime, or null until the game renders its first frame. */
|
|
86
105
|
readonly captured: CapturedRuntime | null;
|
|
106
|
+
/**
|
|
107
|
+
* Install (or clear, with `null`) hooks bracketing every `render()` the
|
|
108
|
+
* CAPTURED renderer makes. Set AFTER capture, because the consumer
|
|
109
|
+
* (`RenderDebugAdapter`) is built from the captured scene and context. Only
|
|
110
|
+
* the captured renderer's renders are bracketed — the editor's own viewport
|
|
111
|
+
* renders come through the same trap and are not the game's frame.
|
|
112
|
+
*/
|
|
113
|
+
setRenderPassHooks(hooks: RenderPassHooks | null): void;
|
|
87
114
|
/** Resolve once a scene+camera is captured (rejects on timeout). */
|
|
88
115
|
waitForCapture(timeoutMs?: number): Promise<CapturedRuntime>;
|
|
89
116
|
/** Total `render()` calls observed through the trap (a liveness signal). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scene-capture.d.ts","sourceRoot":"","sources":["../../../src/adapter/ingest/scene-capture.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AAEH,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AAEpC,iFAAiF;AACjF,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC;IACnB,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC;IACrB,QAAQ,EAAE,KAAK,CAAC,aAAa,CAAC;CAC/B;AAED,+CAA+C;AAC/C,MAAM,WAAW,mBAAmB;IAClC;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,cAAc,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,OAAO,CAAC;CACjD;AAED,sDAAsD;AACtD,MAAM,WAAW,kBAAkB;IACjC,4EAA4E;IAC5E,QAAQ,CAAC,QAAQ,EAAE,eAAe,GAAG,IAAI,CAAC;IAC1C,oEAAoE;IACpE,cAAc,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IAC7D,4EAA4E;IAC5E,YAAY,IAAI,MAAM,CAAC;IACvB;gFAC4E;IAC5E,gBAAgB,CAAC,QAAQ,EAAE,KAAK,CAAC,aAAa,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC;IACjF;;;;;;;;OAQG;IACH,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5C,yEAAyE;IACzE,SAAS,IAAI,IAAI,CAAC;CACnB;AAsBD;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CACjC,cAAc,EAAE,OAAO,EACvB,kBAAkB,CAAC,EAAE,OAAO,EAC5B,IAAI,CAAC,EAAE,mBAAmB,GACzB,kBAAkB,
|
|
1
|
+
{"version":3,"file":"scene-capture.d.ts","sourceRoot":"","sources":["../../../src/adapter/ingest/scene-capture.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AAEH,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AAEpC,iFAAiF;AACjF,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC;IACnB,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC;IACrB,QAAQ,EAAE,KAAK,CAAC,aAAa,CAAC;CAC/B;AAED,+CAA+C;AAC/C,MAAM,WAAW,mBAAmB;IAClC;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,cAAc,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,OAAO,CAAC;CACjD;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,eAAe;IAC9B,MAAM,IAAI,IAAI,CAAC;IACf,KAAK,IAAI,IAAI,CAAC;CACf;AAED,sDAAsD;AACtD,MAAM,WAAW,kBAAkB;IACjC,4EAA4E;IAC5E,QAAQ,CAAC,QAAQ,EAAE,eAAe,GAAG,IAAI,CAAC;IAC1C;;;;;;OAMG;IACH,kBAAkB,CAAC,KAAK,EAAE,eAAe,GAAG,IAAI,GAAG,IAAI,CAAC;IACxD,oEAAoE;IACpE,cAAc,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IAC7D,4EAA4E;IAC5E,YAAY,IAAI,MAAM,CAAC;IACvB;gFAC4E;IAC5E,gBAAgB,CAAC,QAAQ,EAAE,KAAK,CAAC,aAAa,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC;IACjF;;;;;;;;OAQG;IACH,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5C,yEAAyE;IACzE,SAAS,IAAI,IAAI,CAAC;CACnB;AAsBD;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CACjC,cAAc,EAAE,OAAO,EACvB,kBAAkB,CAAC,EAAE,OAAO,EAC5B,IAAI,CAAC,EAAE,mBAAmB,GACzB,kBAAkB,CAoOpB"}
|