@volter/project 0.5.211 → 0.5.213
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/NOTICE +2 -2
- package/README.md +8 -15
- package/package.json +5 -26
- package/schemas/volter-project.schema.json +33 -145
- package/schemas/volter-settings.schema.json +11 -49
- package/src/adapter/adapter-module.ts +208 -465
- package/src/adapter/adapter-surface.ts +4 -32
- package/src/adapter/authoring-seam-contract.ts +7 -24
- package/src/adapter/authoring.ts +126 -265
- package/src/adapter/editor-looks.ts +98 -127
- package/src/adapter/finders/registry.ts +6 -21
- package/src/adapter/host-context.ts +17 -72
- package/src/adapter/index.ts +4 -77
- package/src/adapter/manifest-interpreter.ts +7 -50
- package/src/adapter/physics-adapter-2d.ts +4 -21
- package/src/adapter/root-adapter.ts +37 -111
- package/src/adapter/root-seam-contract.ts +3 -6
- package/src/adapter/root-stacking.ts +4 -46
- package/src/adapter/seam-evidence.ts +0 -16
- package/src/adapter/system-adapter.ts +24 -656
- package/src/adapter/system-seam-contract.ts +1 -91
- package/src/adapter/transform.ts +4 -3
- package/src/adapter/workspace-arrangement.ts +33 -49
- package/src/manifest/editor-port.ts +10 -36
- package/src/manifest/filename.ts +3 -42
- package/src/manifest/load-file.ts +9 -15
- package/src/manifest/load.ts +44 -179
- package/src/manifest/locate.ts +8 -32
- package/src/manifest/schema.ts +155 -427
- package/src/semver.ts +16 -0
- package/src/settings/keys.ts +9 -11
- package/src/settings/schema.ts +55 -44
- package/schemas/engine-api.json +0 -57
- package/schemas/engine-api.md +0 -22
- package/src/adapter/binding.ts +0 -445
- package/src/adapter/debug-registry-ref.ts +0 -19
- package/src/adapter/frame-capture.ts +0 -80
- package/src/adapter/ingest/contract-system-slots.ts +0 -28
- package/src/adapter/ingest/game-contract-seams.ts +0 -86
- package/src/adapter/ingest/game-contract.ts +0 -506
- package/src/adapter/ingest/mount-readiness.ts +0 -140
- package/src/adapter/loop-gate-report.ts +0 -53
- package/src/adapter/native-entry-surface.ts +0 -100
- package/src/adapter/render-audio.ts +0 -20
- package/src/adapter/render-memory.ts +0 -34
- package/src/adapter/renderer-config.ts +0 -84
- package/src/adapter/system-slot.ts +0 -301
- package/src/core/system-phase.ts +0 -52
- package/src/inspection.ts +0 -281
- package/src/manifest/configuration-kinds.ts +0 -241
- package/src/manifest/kind-modules.ts +0 -58
- package/src/manifest/runtime-environment.ts +0 -48
package/src/adapter/binding.ts
DELETED
|
@@ -1,445 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* THE ROOT BINDING — a game's declaration of itself, bound, as ONE host-side
|
|
3
|
-
* value.
|
|
4
|
-
*
|
|
5
|
-
* A game is a native program plus a declaration of itself; the editor is a
|
|
6
|
-
* universal client of that declaration; the host must not know what it is
|
|
7
|
-
* hosting. Today that declaration arrives at the host as a scatter — a
|
|
8
|
-
* `RootInstance`, a `MountedRoot`, an `AuthoringAdapter` provider bag, a
|
|
9
|
-
* `SystemAdapters` slot map, a `ResolvedAdapterRoot`, a parsed
|
|
10
|
-
* `AdapterDefinition` — and every consumer re-assembles its own subset by
|
|
11
|
-
* hand. `RootBinding` is that same material REGROUPED under one name, by the
|
|
12
|
-
* FIVE protocol families a host actually talks in.
|
|
13
|
-
*
|
|
14
|
-
* ## This file declares the vocabulary AND performs the regrouping
|
|
15
|
-
*
|
|
16
|
-
* {@link createRootBinding} is the one place the five families are assembled,
|
|
17
|
-
* and it is a pure re-address of values it is HANDED — it loads nothing,
|
|
18
|
-
* fetches nothing, and constructs no provider. The editor's
|
|
19
|
-
* `binding-resolver.ts` (`resolveRootBinding(root, realm, adapterDef)`) is what
|
|
20
|
-
* gathers those values per realm and calls this; `RootInstance.binding`
|
|
21
|
-
* (`runtime/game.ts`) is where the result lives for the life of the mount.
|
|
22
|
-
* Keeping the assembly here rather than in the resolver is what makes the
|
|
23
|
-
* reference-equality rule below checkable in ONE function instead of once per
|
|
24
|
-
* realm.
|
|
25
|
-
*
|
|
26
|
-
* ## The one rule that makes this a regrouping and not an abstraction
|
|
27
|
-
*
|
|
28
|
-
* **Every member is a REFERENCE to the thing that already exists — never a
|
|
29
|
-
* facade, never a copy, never a wrapper.** `substrate.mounted` IS the
|
|
30
|
-
* `MountedRoot` the adapter returned. `observation.debugRegistry` IS the ONE
|
|
31
|
-
* game-scoped registry every root of that game shares (this binding neither
|
|
32
|
-
* owns it nor tears it down). And the providers that are read AND written
|
|
33
|
-
* through — `selection`, `transforms`, `inspector`, `instances`,
|
|
34
|
-
* `spatialHandles`, `boxEdit`, `text` — appear in BOTH
|
|
35
|
-
* {@link ProjectionBinding} and {@link TruthBinding} as literally the same
|
|
36
|
-
* object, so `binding.projection.selection === binding.truth.selection`. A
|
|
37
|
-
* facade at either address would make the two views disagree the first time
|
|
38
|
-
* anything stateful moved through one of them; reference equality is what
|
|
39
|
-
* makes "regrouping" a checkable claim instead of a promise.
|
|
40
|
-
*/
|
|
41
|
-
|
|
42
|
-
import type { ResolvedAdapterRoot } from '../manifest/load';
|
|
43
|
-
import type { AdapterDefinition } from './adapter-module';
|
|
44
|
-
import type {
|
|
45
|
-
AssetDropProvider,
|
|
46
|
-
AssetSubjectProvider,
|
|
47
|
-
AuthoringCapabilities,
|
|
48
|
-
AuthoringProvenance,
|
|
49
|
-
BoxEditProvider,
|
|
50
|
-
ColorSampleProvider,
|
|
51
|
-
ComponentInstancesProvider,
|
|
52
|
-
HierarchyProvider,
|
|
53
|
-
InspectorProvider,
|
|
54
|
-
PersistenceProvider,
|
|
55
|
-
PickProvider,
|
|
56
|
-
RectProvider,
|
|
57
|
-
RelatedSubjectsProvider,
|
|
58
|
-
SelectionProvider,
|
|
59
|
-
SpatialHandlesProvider,
|
|
60
|
-
StoriesProvider,
|
|
61
|
-
StructureProvider,
|
|
62
|
-
TextProvider,
|
|
63
|
-
TransformProvider,
|
|
64
|
-
TruthProvider,
|
|
65
|
-
} from './authoring';
|
|
66
|
-
import type { DebugRegistryRef } from './debug-registry-ref';
|
|
67
|
-
import type { NativeDebugBinding, NativeSystemsBinding } from './native-entry-surface';
|
|
68
|
-
import type { MountedRoot, RootStateObserver, SurfaceAdapter } from './root-adapter';
|
|
69
|
-
import type { SystemAdapters } from './system-adapter';
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* THE PROTOCOL VOCABULARY — the five families a host talks to a root in, and
|
|
73
|
-
* the ONLY place they are enumerated.
|
|
74
|
-
*
|
|
75
|
-
* This union is the single enumeration on purpose: `RootBinding`'s keys are
|
|
76
|
-
* pinned to it by {@link RootBindingKeysAreExactlyTheProtocolFamilies} below,
|
|
77
|
-
* so a sixth family cannot be added at one address and forgotten at the
|
|
78
|
-
* other, and no second list of these names may exist anywhere in the repo
|
|
79
|
-
* (`adapter-binding-protocol-families.test.ts` is the tripwire).
|
|
80
|
-
*/
|
|
81
|
-
export type ProtocolFamily = 'substrate' | 'projection' | 'truth' | 'observation' | 'project';
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* WHAT MOUNTED, AND HOW IT RUNS.
|
|
85
|
-
*
|
|
86
|
-
* The adapter that produced the mount, the mount itself, and the two
|
|
87
|
-
* lifecycle facts that are properties of the ROOT rather than of the mounted
|
|
88
|
-
* handle (`pausable` is the manifest's per-world play/pause semantics;
|
|
89
|
-
* `loop` is the declared loop model the loop gate reports against). Every
|
|
90
|
-
* other lifecycle member — `update`, `fixedUpdate`, `setPaused`, `step`,
|
|
91
|
-
* `resize`, `dispose`, `disposeComplete`, `drivesOwnLoop` — is reached
|
|
92
|
-
* through `mounted`, unrepeated, because repeating them here would be the
|
|
93
|
-
* facade this binding exists not to be.
|
|
94
|
-
*/
|
|
95
|
-
export interface SubstrateBinding {
|
|
96
|
-
/** The surface-tagged adapter the resolver produced for this root. */
|
|
97
|
-
readonly adapter: SurfaceAdapter;
|
|
98
|
-
/** The handle the adapter's `mount` returned — the same object, not a view. */
|
|
99
|
-
readonly mounted: MountedRoot;
|
|
100
|
-
/** Per-world play/pause semantics (D10's per-world default is `true`). */
|
|
101
|
-
readonly pausable: boolean;
|
|
102
|
-
/** The declared loop model: host-ticked, or the game owns its own rAF. */
|
|
103
|
-
readonly loop: ResolvedAdapterRoot['loop'];
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* READ VIEWS of the provider set — what the editor's panels ASK this root.
|
|
108
|
-
*
|
|
109
|
-
* `capabilities` and `hierarchy` are required because an `AuthoringAdapter`
|
|
110
|
-
* cannot exist without them; every other member is optional and absent means
|
|
111
|
-
* "this root does not support that", never a fabricated empty.
|
|
112
|
-
*
|
|
113
|
-
* The seven members marked STRADDLER also appear on {@link TruthBinding}, as
|
|
114
|
-
* the same object (see this module's header).
|
|
115
|
-
*/
|
|
116
|
-
export interface ProjectionBinding {
|
|
117
|
-
readonly capabilities: AuthoringCapabilities;
|
|
118
|
-
readonly hierarchy: HierarchyProvider;
|
|
119
|
-
readonly provenance?: AuthoringProvenance | undefined;
|
|
120
|
-
/** STRADDLER. */
|
|
121
|
-
readonly selection?: SelectionProvider | undefined;
|
|
122
|
-
/** STRADDLER. */
|
|
123
|
-
readonly transforms?: TransformProvider | undefined;
|
|
124
|
-
/** STRADDLER. */
|
|
125
|
-
readonly inspector?: InspectorProvider | undefined;
|
|
126
|
-
/** STRADDLER. */
|
|
127
|
-
readonly instances?: ComponentInstancesProvider | undefined;
|
|
128
|
-
/** STRADDLER. */
|
|
129
|
-
readonly spatialHandles?: SpatialHandlesProvider | undefined;
|
|
130
|
-
/** STRADDLER. */
|
|
131
|
-
readonly boxEdit?: BoxEditProvider | undefined;
|
|
132
|
-
/** STRADDLER. */
|
|
133
|
-
readonly text?: TextProvider | undefined;
|
|
134
|
-
readonly assetSubject?: AssetSubjectProvider | undefined;
|
|
135
|
-
readonly related?: RelatedSubjectsProvider | undefined;
|
|
136
|
-
readonly rects?: RectProvider | undefined;
|
|
137
|
-
readonly pickable?: PickProvider | undefined;
|
|
138
|
-
readonly stories?: StoriesProvider | undefined;
|
|
139
|
-
readonly colorSample?: ColorSampleProvider | undefined;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* WRITE VIEWS of the provider set — what an authored edit goes THROUGH.
|
|
144
|
-
*
|
|
145
|
-
* The write-only members (`structure`, `persistence`, `truth`, `assetDrop`)
|
|
146
|
-
* plus the seven straddlers, which are the same objects the projection holds.
|
|
147
|
-
*/
|
|
148
|
-
export interface TruthBinding {
|
|
149
|
-
readonly structure?: StructureProvider | undefined;
|
|
150
|
-
readonly persistence?: PersistenceProvider | undefined;
|
|
151
|
-
/** Projection subject → source/data anchor and write lane, resolved together. */
|
|
152
|
-
readonly truth?: TruthProvider | undefined;
|
|
153
|
-
readonly assetDrop?: AssetDropProvider | undefined;
|
|
154
|
-
/** STRADDLER. */
|
|
155
|
-
readonly selection?: SelectionProvider | undefined;
|
|
156
|
-
/** STRADDLER. */
|
|
157
|
-
readonly transforms?: TransformProvider | undefined;
|
|
158
|
-
/** STRADDLER. */
|
|
159
|
-
readonly inspector?: InspectorProvider | undefined;
|
|
160
|
-
/** STRADDLER. */
|
|
161
|
-
readonly instances?: ComponentInstancesProvider | undefined;
|
|
162
|
-
/** STRADDLER. */
|
|
163
|
-
readonly spatialHandles?: SpatialHandlesProvider | undefined;
|
|
164
|
-
/** STRADDLER. */
|
|
165
|
-
readonly boxEdit?: BoxEditProvider | undefined;
|
|
166
|
-
/** STRADDLER. */
|
|
167
|
-
readonly text?: TextProvider | undefined;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
/**
|
|
171
|
-
* WHAT THIS ROOT LETS ANYONE WATCH — references only.
|
|
172
|
-
*
|
|
173
|
-
* `debugRegistry` is the ONE registry the whole Game shares. This binding
|
|
174
|
-
* holds a reference to it and nothing more: it never creates it, never
|
|
175
|
-
* disposes it, and per-root teardown must not end it (a game-scoped resource
|
|
176
|
-
* destroyed by a root-scoped teardown is a bug this repo has already paid
|
|
177
|
-
* for once).
|
|
178
|
-
*
|
|
179
|
-
* `entryDebug`/`entrySystems` are the entry module's own statically declared
|
|
180
|
-
* bindings, harvested at resolve time and INSTALLED post-mount by
|
|
181
|
-
* `adapter-runtime-bindings` — they ride here rather than being re-read from
|
|
182
|
-
* the module a second time.
|
|
183
|
-
*/
|
|
184
|
-
export interface ObservationBinding {
|
|
185
|
-
/** The root's system-adapter slots (physics/networking/navigation/audio/debug). */
|
|
186
|
-
readonly systems?: SystemAdapters | undefined;
|
|
187
|
-
/** Reference to the game-scoped registry. Never owned, never disposed here. */
|
|
188
|
-
readonly debugRegistry: DebugRegistryRef | null;
|
|
189
|
-
/** The ingested-world observation contract, when the adapter has one. */
|
|
190
|
-
readonly observe?: RootStateObserver | undefined;
|
|
191
|
-
/** Change notification → UI refresh. */
|
|
192
|
-
readonly subscribe?: ((listener: () => void) => () => void) | undefined;
|
|
193
|
-
/** The entry module's `debug` export, already validated. */
|
|
194
|
-
readonly entryDebug?: NativeDebugBinding | undefined;
|
|
195
|
-
/** The entry module's `systems` export, already validated. */
|
|
196
|
-
readonly entrySystems?: NativeSystemsBinding | undefined;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* The entry module's static surface, WITH the realm's reach stated.
|
|
201
|
-
*
|
|
202
|
-
* The host holds the entry module's WHOLE namespace: a project module is
|
|
203
|
-
* served by the session's own dev server, so there is nothing between the
|
|
204
|
-
* module and the host. `reach` is stated rather than assumed because the
|
|
205
|
-
* shape once had a second member, and a consumer that reaches for an export
|
|
206
|
-
* must be able to see in the TYPE whether it can be there.
|
|
207
|
-
*/
|
|
208
|
-
export interface EntryStaticSurface {
|
|
209
|
-
readonly reach: 'full';
|
|
210
|
-
/** The entry module's own namespace object. */
|
|
211
|
-
readonly module: Record<string, unknown>;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
/**
|
|
215
|
-
* WHAT THE PROJECT DECLARED — the manifest root, the parsed `editor/volter.adapter.ts`
|
|
216
|
-
* definition, and the entry's static surface.
|
|
217
|
-
*
|
|
218
|
-
* `editor/volter.adapter.ts` LOADING stays where it is (`project-adapter.ts`); its
|
|
219
|
-
* parsed result is an INPUT to `resolveRootBinding`, not something this
|
|
220
|
-
* binding goes and fetches. That is deliberate: the binding is the hand-off's
|
|
221
|
-
* shape, never a second loader.
|
|
222
|
-
*/
|
|
223
|
-
export interface ProjectBinding {
|
|
224
|
-
/** The manifest's own resolved root record. */
|
|
225
|
-
readonly root: ResolvedAdapterRoot;
|
|
226
|
-
/**
|
|
227
|
-
* The project's parsed `editor/volter.adapter.ts`, or `null` when it declares none.
|
|
228
|
-
*
|
|
229
|
-
* `project-adapter.ts` is still the only thing that LOADS it; the editor's
|
|
230
|
-
* `resolveComposition` asks that owner once per composition — waiting on the
|
|
231
|
-
* load in flight rather than reading past it — and hands the answer to
|
|
232
|
-
* `resolveRootBinding`, so every root of one game carries the same
|
|
233
|
-
* declaration. `null` is therefore a fact about the PROJECT: it shipped no
|
|
234
|
-
* declaration file and runs on the declared native default. Which table
|
|
235
|
-
* stood in (project, registry, or native) is a separate question, answered
|
|
236
|
-
* by `ProjectAdapterFacet.source`.
|
|
237
|
-
*/
|
|
238
|
-
readonly definition: AdapterDefinition | null;
|
|
239
|
-
/** The entry module's static surface, realm-honest about its reach. */
|
|
240
|
-
readonly entry: EntryStaticSurface;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
/**
|
|
244
|
-
* One root's whole declaration, bound.
|
|
245
|
-
*
|
|
246
|
-
* The keys ARE {@link ProtocolFamily} — pinned below, so the vocabulary and
|
|
247
|
-
* the value can never drift apart.
|
|
248
|
-
*/
|
|
249
|
-
export interface RootBinding {
|
|
250
|
-
readonly substrate: SubstrateBinding;
|
|
251
|
-
/**
|
|
252
|
-
* Present only when this root's mount exposes an `AuthoringAdapter`.
|
|
253
|
-
*
|
|
254
|
-
* A `ProjectionBinding` cannot be fabricated — `capabilities`/`hierarchy`
|
|
255
|
-
* are required — so a mount with no authoring gets no projection. It gets
|
|
256
|
-
* the other four families, which are constructible from the declaration and
|
|
257
|
-
* the mount alone, because withholding those too would answer "what root is
|
|
258
|
-
* this, what did the project declare, what can be watched" with silence for
|
|
259
|
-
* a question the mount's authoring has nothing to do with.
|
|
260
|
-
*
|
|
261
|
-
* Absent is a REAL state, not a rare one: the editor supplies live authoring
|
|
262
|
-
* for native TSX roots itself (`play-mode.ts`'s per-root live adapters,
|
|
263
|
-
* composed into one `CompositeAuthoringAdapter`) rather than through the
|
|
264
|
-
* mount, so today every first-party three/canvas/dom root lands here. Moving
|
|
265
|
-
* that projection into the mount is its own program item; until it does, the
|
|
266
|
-
* absence is the honest report of where authoring lives.
|
|
267
|
-
*/
|
|
268
|
-
readonly projection?: ProjectionBinding | undefined;
|
|
269
|
-
/** Present exactly when {@link projection} is — same authoring adapter, same
|
|
270
|
-
* condition; see there. */
|
|
271
|
-
readonly truth?: TruthBinding | undefined;
|
|
272
|
-
readonly observation: ObservationBinding;
|
|
273
|
-
readonly project: ProjectBinding;
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
/**
|
|
277
|
-
* Compile-time pin: `keyof RootBinding` and `ProtocolFamily` are the same set
|
|
278
|
-
* of names, in both directions. Adding a family to one address and not the
|
|
279
|
-
* other is a type error HERE, at the vocabulary, rather than a silent
|
|
280
|
-
* asymmetry every consumer inherits.
|
|
281
|
-
*/
|
|
282
|
-
type MutuallyAssignable<A, B> = [A] extends [B] ? ([B] extends [A] ? true : false) : false;
|
|
283
|
-
type AssertTrue<T extends true> = T;
|
|
284
|
-
export type RootBindingKeysAreExactlyTheProtocolFamilies = AssertTrue<
|
|
285
|
-
MutuallyAssignable<keyof RootBinding, ProtocolFamily>
|
|
286
|
-
>;
|
|
287
|
-
|
|
288
|
-
/**
|
|
289
|
-
* Everything {@link createRootBinding} needs, and nothing it could go and get
|
|
290
|
-
* for itself.
|
|
291
|
-
*
|
|
292
|
-
* Each member is a value some OTHER owner already produced: the resolver
|
|
293
|
-
* mounted the adapter, the manifest loader resolved the root, `project-adapter`
|
|
294
|
-
* parsed the definition, the realm loaded the entry namespace, `createGame`
|
|
295
|
-
* owns the debug registry. This shape exists so that list is stated once, at
|
|
296
|
-
* the seam, instead of being re-derived per realm.
|
|
297
|
-
*/
|
|
298
|
-
export interface RootBindingParts extends RootDeclaration {
|
|
299
|
-
readonly adapter: SurfaceAdapter;
|
|
300
|
-
readonly mounted: MountedRoot;
|
|
301
|
-
readonly pausable: boolean;
|
|
302
|
-
/** The GAME-scoped registry, borrowed. Never created or disposed here. */
|
|
303
|
-
readonly debugRegistry: DebugRegistryRef | null;
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
/**
|
|
307
|
-
* The DECLARATION half — everything a resolver knows BEFORE anything mounts.
|
|
308
|
-
*
|
|
309
|
-
* This is the half that travels: `binding-resolver.ts` produces one per root
|
|
310
|
-
* while it is resolving adapters, hands it to the host on the root's mount
|
|
311
|
-
* spec, and the host completes the binding at REGISTRATION — the first moment
|
|
312
|
-
* `mounted` exists at all. Splitting it here is what keeps the resolver from
|
|
313
|
-
* having to be present at mount time, and the host from having to know how an
|
|
314
|
-
* entry module was loaded.
|
|
315
|
-
*/
|
|
316
|
-
export interface RootDeclaration {
|
|
317
|
-
/** The manifest's own resolved root record. `loop` rides on it. */
|
|
318
|
-
readonly root: ResolvedAdapterRoot;
|
|
319
|
-
/** The project's parsed `editor/volter.adapter.ts`, or `null` when it declares none —
|
|
320
|
-
* see {@link ProjectBinding.definition} for the current wiring truth. */
|
|
321
|
-
readonly definition: AdapterDefinition | null;
|
|
322
|
-
/** The entry module's static surface, realm-honest about its reach. */
|
|
323
|
-
readonly entry: EntryStaticSurface;
|
|
324
|
-
/** The entry module's validated `debug` export, harvested at resolve. */
|
|
325
|
-
readonly entryDebug?: NativeDebugBinding | undefined;
|
|
326
|
-
/** The entry module's validated `systems` export, harvested at resolve. */
|
|
327
|
-
readonly entrySystems?: NativeSystemsBinding | undefined;
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
/**
|
|
331
|
-
* REGROUP the parts into the five families. No loading, no defaulting, no
|
|
332
|
-
* fabrication: every member of the result is one of `parts`' own values or one
|
|
333
|
-
* of `parts.mounted.authoring`'s own provider objects, read straight off it.
|
|
334
|
-
*
|
|
335
|
-
* The straddlers are read ONCE into locals and written to both bindings, which
|
|
336
|
-
* is what makes `binding.projection.selection === binding.truth.selection` true
|
|
337
|
-
* by construction rather than by care —
|
|
338
|
-
* `adapter-binding-protocol-families.test.ts` asserts it over a value this
|
|
339
|
-
* function built.
|
|
340
|
-
*
|
|
341
|
-
* `subscribe` is the one exception to "the same reference", and deliberately:
|
|
342
|
-
* it is a METHOD on its adapter (`three-authoring-adapter` reads `this.store`
|
|
343
|
-
* inside it), so a bare property read would hand the caller a function whose
|
|
344
|
-
* `this` is the observation binding. It is bound to the authoring adapter that
|
|
345
|
-
* owns it — the same function over the same receiver, with nothing interposed.
|
|
346
|
-
* It is not a straddler and carries no equality claim.
|
|
347
|
-
*
|
|
348
|
-
* An absent `mounted.authoring` costs this root its `projection` and `truth`
|
|
349
|
-
* and NOTHING ELSE. There is no such thing as an empty `ProjectionBinding` —
|
|
350
|
-
* `capabilities`/`hierarchy` are required — so those two families are simply
|
|
351
|
-
* not there, which is the honest report. The other three are built from the
|
|
352
|
-
* declaration and the mount, neither of which the authoring adapter has
|
|
353
|
-
* anything to do with; refusing them as well would answer "which root is
|
|
354
|
-
* this, what did the project declare, what can be watched" with silence, and
|
|
355
|
-
* that is what made `binding` unreadable for every native TSX root the editor
|
|
356
|
-
* plays (the editor supplies their authoring itself — see
|
|
357
|
-
* {@link RootBinding.projection}).
|
|
358
|
-
*/
|
|
359
|
-
export function createRootBinding(parts: RootBindingParts): RootBinding {
|
|
360
|
-
const authoring = parts.mounted.authoring;
|
|
361
|
-
|
|
362
|
-
// Read each straddler ONCE — the two bindings below then hold these exact
|
|
363
|
-
// objects, not two reads of the same key.
|
|
364
|
-
const { selection, transforms, inspector, instances, spatialHandles, boxEdit, text } =
|
|
365
|
-
authoring ?? {};
|
|
366
|
-
|
|
367
|
-
return {
|
|
368
|
-
substrate: {
|
|
369
|
-
adapter: parts.adapter,
|
|
370
|
-
mounted: parts.mounted,
|
|
371
|
-
pausable: parts.pausable,
|
|
372
|
-
loop: parts.root.loop,
|
|
373
|
-
},
|
|
374
|
-
...(authoring === undefined
|
|
375
|
-
? {}
|
|
376
|
-
: projectionAndTruth(authoring, {
|
|
377
|
-
selection,
|
|
378
|
-
transforms,
|
|
379
|
-
inspector,
|
|
380
|
-
instances,
|
|
381
|
-
spatialHandles,
|
|
382
|
-
boxEdit,
|
|
383
|
-
text,
|
|
384
|
-
})),
|
|
385
|
-
observation: {
|
|
386
|
-
systems: parts.mounted.systems,
|
|
387
|
-
debugRegistry: parts.debugRegistry,
|
|
388
|
-
observe: parts.mounted.observe,
|
|
389
|
-
subscribe: authoring?.subscribe?.bind(authoring),
|
|
390
|
-
entryDebug: parts.entryDebug,
|
|
391
|
-
entrySystems: parts.entrySystems,
|
|
392
|
-
},
|
|
393
|
-
project: {
|
|
394
|
-
root: parts.root,
|
|
395
|
-
definition: parts.definition,
|
|
396
|
-
entry: parts.entry,
|
|
397
|
-
},
|
|
398
|
-
};
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
/** The two authoring-dependent families, built together from the ONE adapter
|
|
402
|
-
* and the straddlers already read off it — so the reference-equality rule is
|
|
403
|
-
* still decided in a single place. */
|
|
404
|
-
function projectionAndTruth(
|
|
405
|
-
authoring: NonNullable<MountedRoot['authoring']>,
|
|
406
|
-
straddlers: Pick<
|
|
407
|
-
ProjectionBinding,
|
|
408
|
-
'selection' | 'transforms' | 'inspector' | 'instances' | 'spatialHandles' | 'boxEdit' | 'text'
|
|
409
|
-
>,
|
|
410
|
-
): { projection: ProjectionBinding; truth: TruthBinding } {
|
|
411
|
-
const { selection, transforms, inspector, instances, spatialHandles, boxEdit, text } = straddlers;
|
|
412
|
-
return {
|
|
413
|
-
projection: {
|
|
414
|
-
capabilities: authoring.capabilities,
|
|
415
|
-
hierarchy: authoring.hierarchy,
|
|
416
|
-
provenance: authoring.provenance,
|
|
417
|
-
selection,
|
|
418
|
-
transforms,
|
|
419
|
-
inspector,
|
|
420
|
-
instances,
|
|
421
|
-
spatialHandles,
|
|
422
|
-
boxEdit,
|
|
423
|
-
text,
|
|
424
|
-
assetSubject: authoring.assetSubject,
|
|
425
|
-
related: authoring.related,
|
|
426
|
-
rects: authoring.rects,
|
|
427
|
-
pickable: authoring.pickable,
|
|
428
|
-
stories: authoring.stories,
|
|
429
|
-
colorSample: authoring.colorSample,
|
|
430
|
-
},
|
|
431
|
-
truth: {
|
|
432
|
-
structure: authoring.structure,
|
|
433
|
-
persistence: authoring.persistence,
|
|
434
|
-
truth: authoring.truth,
|
|
435
|
-
assetDrop: authoring.assetDrop,
|
|
436
|
-
selection,
|
|
437
|
-
transforms,
|
|
438
|
-
inspector,
|
|
439
|
-
instances,
|
|
440
|
-
spatialHandles,
|
|
441
|
-
boxEdit,
|
|
442
|
-
text,
|
|
443
|
-
},
|
|
444
|
-
};
|
|
445
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The game-scoped debug registry AS THE SEAM SEES IT — a reference a binding
|
|
3
|
-
* carries, and the one member the seam reads off it.
|
|
4
|
-
*
|
|
5
|
-
* The contract does not restate `@volter/editor-game/runtime/debug-registry`'s
|
|
6
|
-
* `DebugRegistry`: that interface names the game runtime's own vocabulary
|
|
7
|
-
* (`DebugCtxSurface`, `Game`, the input doors, the run-ticks target), and
|
|
8
|
-
* moving it here would put the game host's debugger inside the project
|
|
9
|
-
* contract. Nothing across this seam calls the registry — the binding holds
|
|
10
|
-
* the reference so the host can hand it back to whoever created it — so the
|
|
11
|
-
* structural shape is the adapter it seeds, and `DebugRegistry` satisfies it.
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
import type { DebugAdapter } from './system-adapter';
|
|
15
|
-
|
|
16
|
-
export interface DebugRegistryRef {
|
|
17
|
-
/** The `SystemAdapters.debug` implementer this registry seeds. */
|
|
18
|
-
readonly adapter: DebugAdapter;
|
|
19
|
-
}
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* What a WebGL frame capture IS — the reading `SystemAdapters`'s frame-capture
|
|
3
|
-
* door answers with. The contract owns the shape; the instrument that records
|
|
4
|
-
* it shadow-patches a live WebGL2 context and is the game runtime's
|
|
5
|
-
* (`@volter/editor-game/runtime/dev/webgl-frame-capture`).
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
/** The five WebGL2 draw entry points this instrument wraps. */
|
|
9
|
-
export type FrameCaptureEntryPoint =
|
|
10
|
-
| 'drawArrays'
|
|
11
|
-
| 'drawElements'
|
|
12
|
-
| 'drawArraysInstanced'
|
|
13
|
-
| 'drawElementsInstanced'
|
|
14
|
-
| 'drawRangeElements';
|
|
15
|
-
|
|
16
|
-
/** Per-draw attribution supplied by {@link WebGLFrameCapture.annotateNextDraw}
|
|
17
|
-
* (the render adapter derives it from the three.js object about to draw). */
|
|
18
|
-
export interface DrawAnnotation {
|
|
19
|
-
object: { name: string; type: string; entityId?: string };
|
|
20
|
-
geometry: { type: string; name: string; attributes: string[]; indexed: boolean };
|
|
21
|
-
material: { type: string; name: string };
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/** Where a draw rendered: the default framebuffer (canvas) or a bound FBO. */
|
|
25
|
-
export type DrawTarget =
|
|
26
|
-
| { kind: 'canvas' }
|
|
27
|
-
| {
|
|
28
|
-
kind: 'framebuffer';
|
|
29
|
-
/** Color-attachment width, or `null` when not cheaply queryable
|
|
30
|
-
* (texture attachment — raw WebGL2 has no size query). */
|
|
31
|
-
width: number | null;
|
|
32
|
-
height: number | null;
|
|
33
|
-
/** Capture-local identity tag (`framebuffer#N`), not a GL debug name. */
|
|
34
|
-
label: string | null;
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
export interface FrameCaptureDrawCall {
|
|
38
|
-
readonly index: number;
|
|
39
|
-
readonly entryPoint: FrameCaptureEntryPoint;
|
|
40
|
-
/** Decoded primitive mode, e.g. `'TRIANGLES'`, `'LINES'` (raw enum when
|
|
41
|
-
* unrecognised). */
|
|
42
|
-
readonly mode: string;
|
|
43
|
-
/** Vertex/index count passed to the draw. */
|
|
44
|
-
readonly count: number;
|
|
45
|
-
/** Instance count for the instanced entry points, else `null` (not 0 —
|
|
46
|
-
* a non-instanced draw has no instance count to report). */
|
|
47
|
-
readonly instanceCount: number | null;
|
|
48
|
-
/** Capture-local program identity (`program#N`), or `null` when no program
|
|
49
|
-
* was bound via `useProgram`. */
|
|
50
|
-
readonly programLabel: string | null;
|
|
51
|
-
readonly target: DrawTarget;
|
|
52
|
-
/** Shadow-tracked viewport `[x, y, w, h]` at draw time. */
|
|
53
|
-
readonly viewport: readonly [number, number, number, number];
|
|
54
|
-
readonly state: {
|
|
55
|
-
readonly blend: boolean;
|
|
56
|
-
readonly depthTest: boolean;
|
|
57
|
-
readonly depthWrite: boolean;
|
|
58
|
-
readonly cull: 'front' | 'back' | 'none';
|
|
59
|
-
readonly scissor: boolean;
|
|
60
|
-
};
|
|
61
|
-
/** The annotation this draw consumed, or `null` when none was pending
|
|
62
|
-
* (unattributed — e.g. a shadow/composer pass draw). */
|
|
63
|
-
readonly annotation: DrawAnnotation | null;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export interface FrameCapture {
|
|
67
|
-
readonly id: number;
|
|
68
|
-
/** Injected capture timestamp (ms) — see `createWebGLFrameCapture` options. */
|
|
69
|
-
readonly capturedAt: number;
|
|
70
|
-
readonly drawCalls: readonly FrameCaptureDrawCall[];
|
|
71
|
-
readonly totals: {
|
|
72
|
-
/** Draws RECORDED (excludes any dropped past the cap). */
|
|
73
|
-
readonly drawCalls: number;
|
|
74
|
-
/** Recorded draws with `annotation: null`. */
|
|
75
|
-
readonly unattributed: number;
|
|
76
|
-
/** Draws dropped because the cap was hit (0 when nothing was dropped). */
|
|
77
|
-
readonly truncated: number;
|
|
78
|
-
};
|
|
79
|
-
readonly notes: readonly string[];
|
|
80
|
-
}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* THE TWO VERDICTS a declared system slot can carry besides an adapter: a
|
|
3
|
-
* positive ABSENCE with the game's own evidence, and a MALFORMED declaration
|
|
4
|
-
* with the reason it could not be honoured.
|
|
5
|
-
*
|
|
6
|
-
* They are the contract's because the entry-module surface names them
|
|
7
|
-
* (`./native-entry-surface.ts`'s `NativeSystemsBinding.absent`) and the
|
|
8
|
-
* coverage report reads them; the projection that produces them is the game
|
|
9
|
-
* runtime's (`@volter/editor-game/runtime/adapter/ingest/contract-system-adapters`).
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import type { VolterGameSystemAdapters } from './game-contract';
|
|
13
|
-
|
|
14
|
-
/** One system slot of the game contract, by name. */
|
|
15
|
-
export type ContractSystemSlot = keyof VolterGameSystemAdapters;
|
|
16
|
-
|
|
17
|
-
/** One slot the game positively answered as having nothing behind it. */
|
|
18
|
-
export interface ContractSystemEmptySlot {
|
|
19
|
-
readonly slot: ContractSystemSlot;
|
|
20
|
-
/** The game's own source-level evidence, verbatim. */
|
|
21
|
-
readonly evidence: string;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/** One slot whose declaration could not be honoured, and why. */
|
|
25
|
-
export interface ContractSystemMalformedSlot {
|
|
26
|
-
readonly slot: ContractSystemSlot;
|
|
27
|
-
readonly reason: string;
|
|
28
|
-
}
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
/** Exhaustive proof requirements for the game→host contract. Declarations are
|
|
2
|
-
* intentionally insufficient for lifecycle, navigation, commands, state, and
|
|
3
|
-
* system carriers: their consumers must produce stronger receipts. */
|
|
4
|
-
|
|
5
|
-
import { defineSeamShape } from '../seam-evidence';
|
|
6
|
-
import type {
|
|
7
|
-
VolterGameCommand,
|
|
8
|
-
VolterGameContract,
|
|
9
|
-
VolterGameHierarchyGroup,
|
|
10
|
-
VolterGameLifecycle,
|
|
11
|
-
VolterGameScene,
|
|
12
|
-
VolterGameScenes,
|
|
13
|
-
VolterGameStateProvider,
|
|
14
|
-
VolterGameSystemAdapters,
|
|
15
|
-
VolterGameSystemEmpty,
|
|
16
|
-
VolterGameSystems,
|
|
17
|
-
} from './game-contract';
|
|
18
|
-
|
|
19
|
-
export const GAME_CONTRACT_SHAPE = defineSeamShape<VolterGameContract>()({
|
|
20
|
-
contractVersion: { optional: false, kind: 'value', required: 'shape' },
|
|
21
|
-
root: { optional: true, kind: 'value', required: 'effect' },
|
|
22
|
-
presentation: { optional: true, kind: 'value', required: 'effect' },
|
|
23
|
-
world: { optional: true, kind: 'value', required: 'effect' },
|
|
24
|
-
ready: { optional: true, kind: 'value', required: 'effect' },
|
|
25
|
-
lifecycle: { optional: true, kind: 'value', required: 'effect' },
|
|
26
|
-
scenes: { optional: true, kind: 'value', required: 'effect' },
|
|
27
|
-
systems: { optional: true, kind: 'value', required: 'operation' },
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
export const GAME_LIFECYCLE_SHAPE = defineSeamShape<VolterGameLifecycle>()({
|
|
31
|
-
start: { optional: true, kind: 'function', required: 'effect' },
|
|
32
|
-
pause: { optional: true, kind: 'function', required: 'effect' },
|
|
33
|
-
resume: { optional: true, kind: 'function', required: 'effect' },
|
|
34
|
-
dispose: { optional: true, kind: 'function', required: 'effect' },
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
export const GAME_SCENES_SHAPE = defineSeamShape<VolterGameScenes>()({
|
|
38
|
-
list: { optional: false, kind: 'function', required: 'operation' },
|
|
39
|
-
current: { optional: false, kind: 'function', required: 'operation' },
|
|
40
|
-
goTo: { optional: false, kind: 'function', required: 'effect' },
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
export const GAME_SCENE_SHAPE = defineSeamShape<VolterGameScene>()({
|
|
44
|
-
id: { optional: false, kind: 'value', required: 'shape' },
|
|
45
|
-
label: { optional: false, kind: 'value', required: 'shape' },
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
export const GAME_COMMAND_SHAPE = defineSeamShape<VolterGameCommand>()({
|
|
49
|
-
name: { optional: false, kind: 'value', required: 'shape' },
|
|
50
|
-
description: { optional: true, kind: 'value', required: 'shape' },
|
|
51
|
-
argsJsonSchema: { optional: true, kind: 'value', required: 'shape' },
|
|
52
|
-
run: { optional: false, kind: 'function', required: 'effect' },
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
export const GAME_STATE_PROVIDER_SHAPE = defineSeamShape<VolterGameStateProvider>()({
|
|
56
|
-
name: { optional: false, kind: 'value', required: 'shape' },
|
|
57
|
-
tier: { optional: true, kind: 'value', required: 'shape' },
|
|
58
|
-
read: { optional: false, kind: 'function', required: 'operation' },
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
export const GAME_HIERARCHY_GROUP_SHAPE = defineSeamShape<VolterGameHierarchyGroup>()({
|
|
62
|
-
id: { optional: false, kind: 'value', required: 'shape' },
|
|
63
|
-
label: { optional: false, kind: 'value', required: 'shape' },
|
|
64
|
-
count: { optional: false, kind: 'value', required: 'operation' },
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
export const GAME_SYSTEMS_SHAPE = defineSeamShape<VolterGameSystems>()({
|
|
68
|
-
commands: { optional: true, kind: 'value', required: 'operation' },
|
|
69
|
-
state: { optional: true, kind: 'value', required: 'operation' },
|
|
70
|
-
hierarchy: { optional: true, kind: 'function', required: 'operation' },
|
|
71
|
-
systemAdapters: { optional: true, kind: 'value', required: 'operation' },
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
export const GAME_SYSTEM_ADAPTERS_SHAPE = defineSeamShape<VolterGameSystemAdapters>()({
|
|
75
|
-
physics: { optional: true, kind: 'value', required: 'effect' },
|
|
76
|
-
networking: { optional: true, kind: 'value', required: 'operation' },
|
|
77
|
-
navigation: { optional: true, kind: 'value', required: 'operation' },
|
|
78
|
-
audio: { optional: true, kind: 'value', required: 'effect' },
|
|
79
|
-
camera: { optional: true, kind: 'value', required: 'effect' },
|
|
80
|
-
renderDebug: { optional: true, kind: 'value', required: 'effect' },
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
export const GAME_SYSTEM_EMPTY_SHAPE = defineSeamShape<VolterGameSystemEmpty>()({
|
|
84
|
-
present: { optional: false, kind: 'value', required: 'shape' },
|
|
85
|
-
evidence: { optional: false, kind: 'value', required: 'claim' },
|
|
86
|
-
});
|