@volter/project 0.5.210 → 0.5.212
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 +204 -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 +96 -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 +29 -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 +6 -29
- 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
|
@@ -1,20 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* System adapters — optional subsystem capability providers hung off a mounted
|
|
3
|
-
*
|
|
4
|
-
* coordinate with WITHOUT owning the implementation.
|
|
5
|
-
* implementers wrap Rapier / Colyseus / recast; an external game supplies its
|
|
3
|
+
* project (`MountedStageRoot.systems`). Each is a thin capability boundary the editor can
|
|
4
|
+
* coordinate with WITHOUT owning the implementation. A project supplies its
|
|
6
5
|
* own or none, and the editor degrades per `capabilities`.
|
|
7
6
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* edit it".
|
|
7
|
+
* Physics providers expose ownership and edit coordination; camera providers
|
|
8
|
+
* expose the runtime controller's current state. Implementations stay with
|
|
9
|
+
* their native libraries.
|
|
12
10
|
*/
|
|
13
11
|
|
|
14
|
-
import type { FrameCapture } from './frame-capture';
|
|
15
12
|
import type { PhysicsAdapter2D } from './physics-adapter-2d';
|
|
16
|
-
import type { OfflineAudioRenderer } from './render-audio';
|
|
17
|
-
import type { RenderMemorySnapshot } from './render-memory';
|
|
18
13
|
import type { Transform, TransformOwner } from './transform';
|
|
19
14
|
|
|
20
15
|
export type PhysicsColliderShape =
|
|
@@ -25,9 +20,9 @@ export type PhysicsColliderShape =
|
|
|
25
20
|
* A collider this seam has no plain-data projection for — a trimesh,
|
|
26
21
|
* heightfield, convex hull, cylinder, cone, …
|
|
27
22
|
*
|
|
28
|
-
* IT IS STILL A COLLIDER, and the body still has it
|
|
29
|
-
*
|
|
30
|
-
*
|
|
23
|
+
* IT IS STILL A COLLIDER, and the body still has it: dropping it from
|
|
24
|
+
* `colliders()` would inspect a trimesh-only body as one with NO physics at
|
|
25
|
+
* all. `kind` is the native
|
|
31
26
|
* shape's own name, so the inspector can say WHICH shape it cannot draw
|
|
32
27
|
* rather than implying nothing is there. Nothing may synthesize dimensions
|
|
33
28
|
* for one, and `previewCollider` refuses it.
|
|
@@ -43,7 +38,7 @@ export interface PhysicsColliderSnapshot {
|
|
|
43
38
|
readonly position: readonly [number, number, number];
|
|
44
39
|
readonly rotation: readonly [number, number, number, number];
|
|
45
40
|
/** Absolute world scale used when the native shape was created. Source
|
|
46
|
-
* dimensions divide by this to recover
|
|
41
|
+
* dimensions divide by this to recover the physics library's local args. */
|
|
47
42
|
readonly scale: readonly [number, number, number];
|
|
48
43
|
readonly sensor: boolean;
|
|
49
44
|
}
|
|
@@ -80,40 +75,12 @@ export interface PhysicsJointSnapshot {
|
|
|
80
75
|
readonly contactsEnabled: boolean;
|
|
81
76
|
}
|
|
82
77
|
|
|
83
|
-
/**
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
* world: a Pixi or React world could never expose a physics inspector, because
|
|
90
|
-
* the seam spoke a vocabulary it has no values in — which is why the Pixi
|
|
91
|
-
* surface grew a parallel {@link PhysicsAdapter2D} (`pixi/system-adapters.ts`)
|
|
92
|
-
* instead of implementing this. Substrate-specific resolution (id → the native
|
|
93
|
-
* object) is the IMPLEMENTER's job, done once at its own boundary.
|
|
94
|
-
*
|
|
95
|
-
* ## `keyedBy`, and why the physics slot's union is TAGGED
|
|
96
|
-
*
|
|
97
|
-
* `SystemAdapters['physics']` holds EITHER shape ({@link PhysicsCarrier}),
|
|
98
|
-
* because a carrier addresses the thing being edited in its surface's own
|
|
99
|
-
* vocabulary and the canvas lane's is the display object itself. But the two
|
|
100
|
-
* shapes carry the SAME four member names and are otherwise indistinguishable
|
|
101
|
-
* at runtime, while the registry that holds them
|
|
102
|
-
* (`editor/src/authoring/active-systems.ts`) is GAME-scoped and surface-blind —
|
|
103
|
-
* one object every editor panel reads. An untagged union would therefore be one
|
|
104
|
-
* nothing could narrow, and every three-lane consumer
|
|
105
|
-
* (`getActivePhysics()?.freeze(nodeId)`, `play-mode.ts`'s `physics.commit(id,
|
|
106
|
-
* transform)`) would have to reach it through a cast asserting a fact nobody
|
|
107
|
-
* checked.
|
|
108
|
-
*
|
|
109
|
-
* So `keyedBy` is a real discriminant, and it is REQUIRED on
|
|
110
|
-
* {@link PhysicsAdapter2D} while OPTIONAL here on purpose: node-id keying is
|
|
111
|
-
* this seam's original and — until the canvas lane — only vocabulary, so every
|
|
112
|
-
* existing implementer stays valid untouched, and the shape that needs telling
|
|
113
|
-
* apart is the one obliged to say so. {@link nodeKeyedPhysics} /
|
|
114
|
-
* {@link displayKeyedPhysics} are the two narrowings; nothing else should test
|
|
115
|
-
* the tag by hand.
|
|
116
|
-
*/
|
|
78
|
+
/** Coordinate simulation-owned physics edits through freeze, apply and
|
|
79
|
+
* unfreeze. This interface addresses EditorNode ids; the implementer resolves
|
|
80
|
+
* each id to its native body. PhysicsAdapter2D addresses display objects.
|
|
81
|
+
* PhysicsCarrier distinguishes the two shapes through keyedBy, with omitted
|
|
82
|
+
* keyedBy denoting node ids. Use nodeKeyedPhysics or displayKeyedPhysics to
|
|
83
|
+
* narrow the carrier. */
|
|
117
84
|
export interface PhysicsAdapter {
|
|
118
85
|
/** Optional tag; see the interface comment. `'node-id'` is the only value,
|
|
119
86
|
* and omitting it means the same thing. */
|
|
@@ -131,9 +98,8 @@ export interface PhysicsAdapter {
|
|
|
131
98
|
debugDraw?(): unknown;
|
|
132
99
|
/**
|
|
133
100
|
* Optional: turn the engine's per-frame physics debug rendering on/off —
|
|
134
|
-
* the
|
|
135
|
-
*
|
|
136
|
-
* overlay toggle costs the editor zero per-frame work (W2a §2.3c).
|
|
101
|
+
* the implementation fills the `debugDraw()` object inside the project's own
|
|
102
|
+
* render system, so an overlay toggle costs the editor zero per-frame work.
|
|
137
103
|
*/
|
|
138
104
|
setDebugDrawEnabled?(enabled: boolean): void;
|
|
139
105
|
/**
|
|
@@ -160,518 +126,14 @@ export interface PhysicsAdapter {
|
|
|
160
126
|
): void;
|
|
161
127
|
}
|
|
162
128
|
|
|
163
|
-
export interface NetPeer {
|
|
164
|
-
id: string;
|
|
165
|
-
label?: string;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/** The project's declared multiplayer server, readable with the game NOT
|
|
169
|
-
* running. `null` from `getServerConfig` means no server is declared. */
|
|
170
|
-
export interface NetServerConfig {
|
|
171
|
-
endpoint: string;
|
|
172
|
-
/** Known once the game's own networking adapter reports it; in edit mode
|
|
173
|
-
* the declared `process` gives only the endpoint. */
|
|
174
|
-
roomName?: string;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
/** The signed-in player's authored identity, used as the connect default. */
|
|
178
|
-
export interface NetPlayerIdentity {
|
|
179
|
-
name?: string;
|
|
180
|
-
id?: string;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
/** The live connection lifecycle, for the editor's network inspector. */
|
|
184
|
-
export type ConnectionState = 'disconnected' | 'connecting' | 'connected' | 'error';
|
|
185
|
-
|
|
186
|
-
/** Identity of the room the local peer is currently in, or `null` when not connected. */
|
|
187
|
-
export interface RoomInfo {
|
|
188
|
-
roomId: string;
|
|
189
|
-
sessionId: string;
|
|
190
|
-
roomName: string;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
/** Lightweight replication counters for the editor's network inspector. */
|
|
194
|
-
export interface ReplicationStats {
|
|
195
|
-
/** Number of replicated entities currently known (e.g. players + NPCs). */
|
|
196
|
-
entities: number;
|
|
197
|
-
/** Approximate inbound replication activity (state changes observed per second). */
|
|
198
|
-
msgsInPerSec: number;
|
|
199
|
-
/** Approximate outbound message rate (client → server sends per second). */
|
|
200
|
-
msgsOutPerSec: number;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
129
|
export type Unsubscribe = () => void;
|
|
204
130
|
|
|
205
|
-
/** One captured network message, for the inspector's message log (W3b).
|
|
206
|
-
* `seq` is an adapter-lifetime MONOTONIC counter — the ring-buffer fence a
|
|
207
|
-
* consumer polls with (`messageEvents(sinceSeq)`), mirroring
|
|
208
|
-
* `DebugAdapter.events`' seq discipline. `time` is a `performance.now()`-
|
|
209
|
-
* domain ms timestamp at capture. */
|
|
210
|
-
export interface NetMessageEvent {
|
|
211
|
-
seq: number;
|
|
212
|
-
time: number;
|
|
213
|
-
direction: 'in' | 'out';
|
|
214
|
-
/** Message type/channel (e.g. `'input'`, `'players.add'`, `'state.phase'`). */
|
|
215
|
-
type: string;
|
|
216
|
-
/** Approximate payload size in bytes, when measurable. OMITTED — never
|
|
217
|
-
* fabricated — when the transport doesn't expose it (e.g. Colyseus schema
|
|
218
|
-
* patches observed via the Callbacks API carry no byte count). */
|
|
219
|
-
size?: number;
|
|
220
|
-
/** `true` when the link conditioner (`setConditioning`) dropped this
|
|
221
|
-
* outbound message instead of sending it — logged so the inspector can
|
|
222
|
-
* show the drop honestly rather than silently losing it. */
|
|
223
|
-
dropped?: boolean;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
/** Send/receive rates for the inspector's sparklines (W3b). The byte fields
|
|
227
|
-
* are OPTIONAL capabilities-within-the-capability: an implementer omits a
|
|
228
|
-
* direction it cannot measure (never reports a fabricated 0). */
|
|
229
|
-
/** One message type's traffic, both directions. */
|
|
230
|
-
export interface NetTypeTraffic {
|
|
231
|
-
type: string;
|
|
232
|
-
countIn: number;
|
|
233
|
-
countOut: number;
|
|
234
|
-
bytesIn: number;
|
|
235
|
-
bytesOut: number;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
/** One replicated entity's traffic (Godot's synchronizer table): the state patches that changed
|
|
239
|
-
* it, the field changes they carried, and the size range of those patches, which carried other
|
|
240
|
-
* entities too. `path` is the entity's place in the state (`players.abc`, `orbs.orb_1`). */
|
|
241
|
-
export interface NetEntityTraffic {
|
|
242
|
-
path: string;
|
|
243
|
-
syncs: number;
|
|
244
|
-
changes: number;
|
|
245
|
-
patchBytesMin: number;
|
|
246
|
-
patchBytesMax: number;
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
export interface NetServerRoom {
|
|
250
|
-
roomId: string;
|
|
251
|
-
name: string;
|
|
252
|
-
clients: number;
|
|
253
|
-
/** `null` when the room admits any number. */
|
|
254
|
-
maxClients: number | null;
|
|
255
|
-
locked: boolean;
|
|
256
|
-
elapsedMs: number;
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
export interface NetServerClient {
|
|
260
|
-
sessionId: string;
|
|
261
|
-
elapsedMs: number;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
export interface NetServerInspection {
|
|
265
|
-
rooms: NetServerRoom[];
|
|
266
|
-
connections: number;
|
|
267
|
-
/** The server machine's CPU use in percent, when it reports one. */
|
|
268
|
-
cpuPercent: number | null;
|
|
269
|
-
memory: { usedMb: number; totalMb: number } | null;
|
|
270
|
-
/** The current room's clients and its full state's size, when the room is still hosted. */
|
|
271
|
-
room: { roomId: string; clients: NetServerClient[]; stateBytes: number; state?: unknown } | null;
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
export interface NetConditioningLimits {
|
|
275
|
-
latencyMs?: string;
|
|
276
|
-
jitterMs?: string;
|
|
277
|
-
packetLoss?: string;
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
export interface NetRates {
|
|
281
|
-
msgsInPerSec: number;
|
|
282
|
-
msgsOutPerSec: number;
|
|
283
|
-
bytesInPerSec?: number;
|
|
284
|
-
bytesOutPerSec?: number;
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
/** Client-side link-conditioning parameters, applied AT THE ADAPTER SEAM
|
|
288
|
-
* (W3b M3) — the implementer wraps its own transport calls (e.g. delaying/
|
|
289
|
-
* dropping around `room.send`); nobody patches transport internals. */
|
|
290
|
-
export interface NetConditioning {
|
|
291
|
-
/** Fixed added delay per outbound message, ms. */
|
|
292
|
-
latencyMs: number;
|
|
293
|
-
/** Uniform random extra delay in `[0, jitterMs)`, ms. */
|
|
294
|
-
jitterMs: number;
|
|
295
|
-
/** Probability in `[0, 1]` that an outbound message is dropped. */
|
|
296
|
-
packetLoss: number;
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
/**
|
|
300
|
-
* INTROSPECTION over replication state — NOT a networking transport.
|
|
301
|
-
*
|
|
302
|
-
* The optional members are CAPABILITIES in the `SystemAdapters` sense
|
|
303
|
-
* (absence means "not supported" and the editor's Network inspector marks
|
|
304
|
-
* that section absent — it never fabricates data): `getStateSnapshot` feeds
|
|
305
|
-
* the replicated-state tree, `messageEvents` the message log, `getRates` the
|
|
306
|
-
* rate sparklines, and `getConditioning`/`setConditioning` the latency/loss
|
|
307
|
-
* conditioner. The first-party Colyseus factory
|
|
308
|
-
* (`createColyseusNetworkingAdapter`) only attaches each one when its config
|
|
309
|
-
* supplies the accessor, so partial implementers degrade honestly.
|
|
310
|
-
*/
|
|
311
|
-
export interface NetworkingAdapter {
|
|
312
|
-
peers(): NetPeer[];
|
|
313
|
-
/** Keyed by NODE ID, not `THREE.Object3D` — see {@link PhysicsAdapter} (P-4). */
|
|
314
|
-
networkId(nodeId: string): string | null;
|
|
315
|
-
authority(nodeId: string): 'local' | 'remote' | 'server';
|
|
316
|
-
/** Remote/server-authoritative nodes → inspect-only in the editor. */
|
|
317
|
-
editable(nodeId: string): boolean;
|
|
318
|
-
/**
|
|
319
|
-
* Optional capability: current connection lifecycle state.
|
|
320
|
-
*
|
|
321
|
-
* OPTIONAL for the same reason every other member here is — `'disconnected'`
|
|
322
|
-
* is a POSITIVE CLAIM about the link, and an implementer that never taught
|
|
323
|
-
* this adapter to read connection state has not made it. Absent ⇒ the
|
|
324
|
-
* inspector marks the section unsupported; it does not report a game as
|
|
325
|
-
* disconnected on the strength of nobody having looked.
|
|
326
|
-
*/
|
|
327
|
-
getConnectionState?(): ConnectionState;
|
|
328
|
-
/**
|
|
329
|
-
* Optional capability: the active room's identity, or `null` when connected
|
|
330
|
-
* to no room. `null` is the ANSWER "there is no room", so absence of the
|
|
331
|
-
* accessor — "nothing here can tell you" — has to be a different thing.
|
|
332
|
-
*/
|
|
333
|
-
getRoomInfo?(): RoomInfo | null;
|
|
334
|
-
/**
|
|
335
|
-
* Optional capability: replication activity snapshot, for a live network
|
|
336
|
-
* inspector panel. Zeroes are a measurement, not a default; an adapter with
|
|
337
|
-
* no counters omits this rather than reporting a quiet link.
|
|
338
|
-
*/
|
|
339
|
-
getReplicationStats?(): ReplicationStats;
|
|
340
|
-
/** Subscribe to changes in connection state / room / replication stats. */
|
|
341
|
-
subscribe(cb: () => void): Unsubscribe;
|
|
342
|
-
/** Optional capability: one plain-data (JSON-safe) snapshot of the
|
|
343
|
-
* replicated room state, or `null` when not connected. Colyseus schema is
|
|
344
|
-
* self-describing (`state.toJSON()`), so the first-party implementation
|
|
345
|
-
* is one call — the inspector renders whatever tree comes back. */
|
|
346
|
-
getStateSnapshot?(): unknown;
|
|
347
|
-
/** Optional capability: captured message events with `seq > sinceSeq`
|
|
348
|
-
* (whole ring when omitted). Implementations ring-buffer (drop oldest);
|
|
349
|
-
* the inspector keeps its own consumer-side ring and fences on `seq`. */
|
|
350
|
-
messageEvents?(sinceSeq?: number): NetMessageEvent[];
|
|
351
|
-
/** Optional capability: msg + byte rates for the inspector's sparklines. */
|
|
352
|
-
getRates?(): NetRates;
|
|
353
|
-
/** Optional capability (paired with `setConditioning`): current
|
|
354
|
-
* conditioning parameters. */
|
|
355
|
-
getConditioning?(): NetConditioning;
|
|
356
|
-
/** Optional capability: apply link conditioning at the adapter seam. */
|
|
357
|
-
setConditioning?(c: NetConditioning): void;
|
|
358
|
-
/** Optional edit-time capability: the project's declared server, readable
|
|
359
|
-
* with the game NOT running (`null` = no server declared). Hides on
|
|
360
|
-
* absence, like the other optionals. */
|
|
361
|
-
getServerConfig?(): NetServerConfig | null;
|
|
362
|
-
/** Optional capability: the local player's identity, as the GAME defines it
|
|
363
|
-
* (e.g. read off its own room state). The editor consumes this for display —
|
|
364
|
-
* a seat label — ONLY when a real implementer provides it, falling back to a
|
|
365
|
-
* generic label otherwise. */
|
|
366
|
-
getPlayerIdentity?(): NetPlayerIdentity | undefined;
|
|
367
|
-
/** Traffic per message type since the connection opened, both directions — state and patches
|
|
368
|
-
* included as their own rows (Godot's network profiler tables). */
|
|
369
|
-
getTrafficByType?(): NetTypeTraffic[];
|
|
370
|
-
/** Incoming state traffic per replicated entity since the connection opened (or the last
|
|
371
|
-
* clear), ordered by syncs. */
|
|
372
|
-
getTrafficByEntity?(): NetEntityTraffic[];
|
|
373
|
-
/** Whether the traffic totals and the message log are counting (Godot's profiler Start/Stop);
|
|
374
|
-
* stopped, frames still pass and the state still updates, but nothing is tallied. */
|
|
375
|
-
isRecording?(): boolean;
|
|
376
|
-
setRecording?(on: boolean): void;
|
|
377
|
-
/** Send `payload` to the room as this client, under message type `type` (Colyseus Monitor's
|
|
378
|
-
* Send), so a server handler can be exercised from the inspector. */
|
|
379
|
-
sendMessage?(type: string, payload: unknown): void;
|
|
380
|
-
/** Which conditioning fields this adapter cannot apply, each with the reason (a reliable
|
|
381
|
-
* WebSocket loses nothing, so it cannot simulate loss). Omitted means every field applies. */
|
|
382
|
-
getConditioningLimits?(): NetConditioningLimits;
|
|
383
|
-
/** Measure one round trip to the server now, in milliseconds. */
|
|
384
|
-
ping?(): Promise<number>;
|
|
385
|
-
/** The room server's own view — every room it hosts, and the current room's clients (Colyseus
|
|
386
|
-
* Monitor's). `null` when the server serves no such view. */
|
|
387
|
-
inspectServer?(roomId?: string): Promise<NetServerInspection | null>;
|
|
388
|
-
/** Disconnect one client of the current room from the server's side (Monitor's Disconnect). */
|
|
389
|
-
disconnectClient?(sessionId: string, roomId?: string): Promise<void>;
|
|
390
|
-
/** Set one value of the room's authoritative state on the server (Monitor's State edit);
|
|
391
|
-
* `path` is the keys from the state's root. */
|
|
392
|
-
editServerState?(path: readonly (string | number)[], value: unknown, roomId?: string): Promise<void>;
|
|
393
|
-
/** Remove one key of the room's authoritative state on the server (Monitor's State delete). */
|
|
394
|
-
deleteServerState?(path: readonly (string | number)[], roomId?: string): Promise<void>;
|
|
395
|
-
/** From the server, send `payload` under `type` to one client of the room (Monitor's Send). */
|
|
396
|
-
sendToClient?(sessionId: string, type: string, payload: unknown, roomId?: string): Promise<void>;
|
|
397
|
-
/** From the server, send `payload` under `type` to every client of the room (Monitor's
|
|
398
|
-
* Broadcast). */
|
|
399
|
-
broadcast?(type: string, payload: unknown, roomId?: string): Promise<void>;
|
|
400
|
-
/** Dispose a room on the server (Monitor's Dispose); its clients are disconnected. */
|
|
401
|
-
disposeRoom?(roomId?: string): Promise<void>;
|
|
402
|
-
/** The replicated type of the state field at `path` (`float32`, `map<schema>`), from the
|
|
403
|
-
* schema the server declared — what Godot's Replication panel shows of a synchronizer. */
|
|
404
|
-
stateFieldType?(path: readonly (string | number)[]): string | null;
|
|
405
|
-
/** Start the traffic totals from zero (Godot's profiler Clear resets its tables). */
|
|
406
|
-
clearTraffic?(): void;
|
|
407
|
-
/** Optional capability, PAIRED with {@link getPlayerIdentity}: set the local
|
|
408
|
-
* player's identity through the game's OWN multiplayer mechanism. The editor
|
|
409
|
-
* renders an editable name field ONLY when a real implementer provides this
|
|
410
|
-
* (consume-by-presence, exactly like {@link setConditioning}); its absence
|
|
411
|
-
* means the game does not support an author-settable name and no field shows.
|
|
412
|
-
*
|
|
413
|
-
* This is NOT the editor imposing a name: whether a name is settable, and how
|
|
414
|
-
* it reaches the server, is entirely the game's decision — a game that names
|
|
415
|
-
* players by join order simply never provides this member. When it does, the
|
|
416
|
-
* implementation drives the game's real path (a join option honoured by the
|
|
417
|
-
* server, a rename message, …), so what the editor sets is the same value the
|
|
418
|
-
* multiplayer build actually uses — never a placeholder the server discards. */
|
|
419
|
-
setPlayerIdentity?(identity: NetPlayerIdentity): void | Promise<void>;
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
export interface NavPoint {
|
|
423
|
-
x: number;
|
|
424
|
-
y: number;
|
|
425
|
-
z: number;
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
/**
|
|
429
|
-
* Navmesh bake parameters — the recast `rcConfig` vocabulary the scene schema
|
|
430
|
-
* (`SceneNavigationSchema`) also mirrors. All optional; an implementation
|
|
431
|
-
* applies its own defaults. `walkableHeight`/`walkableClimb`/`walkableRadius`
|
|
432
|
-
* are in VOXEL units (multiples of `cellHeight`/`cellSize`), per recast.
|
|
433
|
-
*/
|
|
434
|
-
export interface NavBakeParams {
|
|
435
|
-
cellSize?: number | undefined;
|
|
436
|
-
cellHeight?: number | undefined;
|
|
437
|
-
walkableSlopeAngle?: number | undefined;
|
|
438
|
-
walkableHeight?: number | undefined;
|
|
439
|
-
walkableClimb?: number | undefined;
|
|
440
|
-
walkableRadius?: number | undefined;
|
|
441
|
-
maxEdgeLen?: number | undefined;
|
|
442
|
-
maxSimplificationError?: number | undefined;
|
|
443
|
-
minRegionArea?: number | undefined;
|
|
444
|
-
mergeRegionArea?: number | undefined;
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
/** One crowd agent's live state — plain data (no engine/WASM handles), for the
|
|
448
|
-
* editor's play-mode crowd debug draw. */
|
|
449
|
-
export interface NavCrowdAgentState {
|
|
450
|
-
position: NavPoint;
|
|
451
|
-
velocity: NavPoint;
|
|
452
|
-
radius: number;
|
|
453
|
-
height: number;
|
|
454
|
-
/** The crowd's own agent state. `invalid` is the expressible FAILURE — the
|
|
455
|
-
* agent is off the navmesh (a bad spawn or teleport) and will not move;
|
|
456
|
-
* `offmesh` is an off-mesh connection traversal. Absent on an adapter that
|
|
457
|
-
* predates this field — the editor draws such agents as walking. */
|
|
458
|
-
state?: 'invalid' | 'walking' | 'offmesh';
|
|
459
|
-
/** The agent's current move target, when the implementation reports one. */
|
|
460
|
-
target?: NavPoint;
|
|
461
|
-
/** The local path-corridor corners the agent is steering along — the
|
|
462
|
-
* REQUESTED PATH the debug draw projects. Empty or absent when idle. */
|
|
463
|
-
corners?: NavPoint[];
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
/**
|
|
467
|
-
* Inspect a game's navigation mesh: whether one is built, query a path, and get a
|
|
468
|
-
* debug overlay. Coordination/introspection only — the editor doesn't own the build.
|
|
469
|
-
*
|
|
470
|
-
* The optional members are CAPABILITIES in the `SystemAdapters` sense (absence
|
|
471
|
-
* means "not supported", the editor degrades): `bake`/`exportData` let the
|
|
472
|
-
* editor's Navigation panel (re)build and persist a navmesh through the seam —
|
|
473
|
-
* the first-party recast implementation (`createNavigationAdapter`) is the
|
|
474
|
-
* blessed implementer — while an external game that owns its build simply
|
|
475
|
-
* omits them. `clear` lets that same owner release its navmesh; the editor never
|
|
476
|
-
* disposes implementation handles itself. `crowdAgents` feeds the play-mode
|
|
477
|
-
* crowd debug draw.
|
|
478
|
-
*
|
|
479
|
-
* `debugMesh`/`bake`/`clear` trade in the surface's own scene, objects and
|
|
480
|
-
* meshes, which this neutral contract leaves opaque; `@volter/editor-threejs`
|
|
481
|
-
* names the Three-typed view (`threeNavigation`).
|
|
482
|
-
*/
|
|
483
|
-
export interface NavigationAdapter {
|
|
484
|
-
hasNavMesh(): boolean;
|
|
485
|
-
/**
|
|
486
|
-
* `[]` means SEARCHED AND FOUND NO ROUTE — a fact about the level. An
|
|
487
|
-
* implementer with no navmesh to search, or whose query FAILED, THROWS
|
|
488
|
-
* instead; those are facts about the implementer, and collapsing all three
|
|
489
|
-
* into `[]` tells a caller the level is impassable when nobody looked.
|
|
490
|
-
* Gate on {@link hasNavMesh} where the first case is reachable.
|
|
491
|
-
*/
|
|
492
|
-
findPath(start: NavPoint, end: NavPoint): NavPoint[];
|
|
493
|
-
debugMesh(scene: unknown): unknown;
|
|
494
|
-
/** (Re)build the navmesh from source meshes. Synchronous in the blessed
|
|
495
|
-
* recast/WASM implementation; returns `false` on a failed bake. */
|
|
496
|
-
bake?(meshes: readonly unknown[], params?: NavBakeParams): boolean;
|
|
497
|
-
/** Serialize the current navmesh to a binary blob (the editor persists it
|
|
498
|
-
* as the scene's `.navmesh` sidecar). Throws when nothing is built. */
|
|
499
|
-
exportData?(): Uint8Array;
|
|
500
|
-
/** Release the current navmesh and any debug object it attached to `scene`.
|
|
501
|
-
* Optional because an external game's navigation may be inspect-only. */
|
|
502
|
-
clear?(scene: unknown): void;
|
|
503
|
-
/** Live crowd-agent snapshots for debug draw. Empty when no crowd. */
|
|
504
|
-
crowdAgents?(): NavCrowdAgentState[];
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
/** One node in an audio-graph snapshot (W3c, the Audio debugger tab). Edges
|
|
508
|
-
* point DOWNSTREAM: `outputs` holds the ids of nodes this node's output
|
|
509
|
-
* feeds (ultimately reaching the `destination` node). */
|
|
510
|
-
export interface AudioGraphNode {
|
|
511
|
-
id: string;
|
|
512
|
-
/** Node class/constructor name (`'GainNode'`, `'Gain'` for a Tone node,
|
|
513
|
-
* `'AudioDestinationNode'`, …) — whatever the implementation truthfully
|
|
514
|
-
* knows, never a prettified fabrication. */
|
|
515
|
-
type: string;
|
|
516
|
-
/** Human-facing label (`'Master'`, `'Music bus'`) when one exists. */
|
|
517
|
-
label?: string;
|
|
518
|
-
/** ids of downstream nodes this node's output connects to. */
|
|
519
|
-
outputs: string[];
|
|
520
|
-
/** Lifecycle/playback state when truthfully known (`'running'`,
|
|
521
|
-
* `'suspended'`, `'started'`…). OMITTED — never fabricated — otherwise. */
|
|
522
|
-
state?: string;
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
/** Musical-transport snapshot for the Audio debugger's transport strip
|
|
526
|
-
* (W3c). The first-party implementation reads Tone's real transport. */
|
|
527
|
-
export interface AudioTransportState {
|
|
528
|
-
state: 'started' | 'stopped' | 'paused';
|
|
529
|
-
/** Playback position along the transport's timeline, seconds. */
|
|
530
|
-
seconds: number;
|
|
531
|
-
bpm: number;
|
|
532
|
-
/** Musical position (`Bars:Beats:Sixteenths`) when a musical grid exists. */
|
|
533
|
-
position?: string;
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
/** One bus level sample: `level` is linear RMS over the implementation's most
|
|
537
|
-
* recent analysis window (0 = silence; ~1 = full-scale). */
|
|
538
|
-
export interface AudioMeterFrame {
|
|
539
|
-
id: string;
|
|
540
|
-
label: string;
|
|
541
|
-
level: number;
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
/** A live metering session. Metering costs real audio nodes (Tone.Meter /
|
|
545
|
-
* AnalyserNode taps), so it is ACQUIRED for exactly as long as a meter UI is
|
|
546
|
-
* visible and MUST be released via `dispose()` — the first-party handle
|
|
547
|
-
* disconnects its analyser taps there (no leaked nodes after Stop). */
|
|
548
|
-
export interface AudioMeterHandle {
|
|
549
|
-
/** Current level per bus. Cheap enough to poll at UI rate (~10 Hz). */
|
|
550
|
-
read(): AudioMeterFrame[];
|
|
551
|
-
/** Release the metering nodes. Idempotent. */
|
|
552
|
-
dispose(): void;
|
|
553
|
-
}
|
|
554
|
-
|
|
555
|
-
/** One entry in the audio event ring (W3c). `seq` is an adapter-lifetime
|
|
556
|
-
* MONOTONIC counter — the same ring-buffer fence discipline as
|
|
557
|
-
* `NetMessageEvent.seq` / `DebugAdapter.events`. `time` is a
|
|
558
|
-
* `performance.now()`-domain ms timestamp at capture. `'error'` is reserved
|
|
559
|
-
* for implementations that can truthfully report one (the first-party
|
|
560
|
-
* adapter has no honest audio-error source today and never emits it). */
|
|
561
|
-
export interface AudioDebugEvent {
|
|
562
|
-
seq: number;
|
|
563
|
-
time: number;
|
|
564
|
-
kind:
|
|
565
|
-
| 'transport-start'
|
|
566
|
-
| 'transport-stop'
|
|
567
|
-
| 'transport-pause'
|
|
568
|
-
| 'context-statechange'
|
|
569
|
-
| 'mute'
|
|
570
|
-
| 'unmute'
|
|
571
|
-
| 'error';
|
|
572
|
-
detail?: string;
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
/**
|
|
576
|
-
* Silence/restore a world's own audio (D10, T7.6) — NOT a mixer/bus API. This
|
|
577
|
-
* is the seam `Game.play.pause()` calls so a paused world's audio goes quiet
|
|
578
|
-
* too ("an audio seam in `SystemAdapters` so pause can silence game audio
|
|
579
|
-
* (howler et al.) or explicitly report it cannot"). Absence on a world's
|
|
580
|
-
* `mounted.systems` means exactly that: `Game.play.pause()` reports it loudly
|
|
581
|
-
* once per world rather than silently leaving that world's audio playing under
|
|
582
|
-
* a "paused" game.
|
|
583
|
-
*
|
|
584
|
-
* The OPTIONAL methods below are the W3c read-only INTROSPECTION capabilities
|
|
585
|
-
* feeding the editor's Audio debugger tab (graph / transport / meters /
|
|
586
|
-
* events). They follow the W3a degradation ladder: an implementer omits what
|
|
587
|
-
* it cannot truthfully provide, and the editor marks that section absent —
|
|
588
|
-
* never fabricated. The full MIXER (sends/effects/gain editing) is SQ-4-gated
|
|
589
|
-
* and deliberately NOT part of this seam. The first-party implementation over
|
|
590
|
-
* the engine's own Tone/Web-Audio stack is
|
|
591
|
-
* `packages/game-runtime/src/audio/audio-introspection.ts`; pre-existing
|
|
592
|
-
* mute-only registrants keep compiling untouched (every addition is
|
|
593
|
-
* optional).
|
|
594
|
-
*/
|
|
595
|
-
export interface AudioAdapter {
|
|
596
|
-
/** Resume/unlock this adapter's real audio context from a user gesture.
|
|
597
|
-
* Optional for external adapters that do not own a resumable Web Audio
|
|
598
|
-
* context; first-party edit and play adapters both provide it. */
|
|
599
|
-
resume?(): void;
|
|
600
|
-
/** `true` silences this world's audio; `false` restores it to whatever
|
|
601
|
-
* level it was at before silencing (an implementer's own concern — the
|
|
602
|
-
* first-party adapter restores its master-gain value, not a hardcoded 1). */
|
|
603
|
-
setMuted(muted: boolean): void;
|
|
604
|
-
/** Current muted state, for inspection (editor mute UI, proofs). */
|
|
605
|
-
isMuted(): boolean;
|
|
606
|
-
/** Optional: current audio-graph snapshot (active nodes + downstream
|
|
607
|
-
* edges). The first-party adapter reports the engine bus hierarchy plus
|
|
608
|
-
* every Tone node routed through `connectToneBusToMasterGain` — it cannot
|
|
609
|
-
* see a game's private Tone-internal wiring and does not pretend to. */
|
|
610
|
-
graphSnapshot?(): AudioGraphNode[];
|
|
611
|
-
/** Optional: musical-transport snapshot. Returns `null` — an honest
|
|
612
|
-
* "this world has no musical transport" — when none is active (e.g. the
|
|
613
|
-
* first-party adapter when the game never bridged Tone onto this world's
|
|
614
|
-
* context). Method ABSENT means the capability itself is unsupported. */
|
|
615
|
-
transportState?(): AudioTransportState | null;
|
|
616
|
-
/** Optional: begin a per-bus metering session. Returns `null` when the
|
|
617
|
-
* environment cannot meter (headless world with no real AudioContext) —
|
|
618
|
-
* the UI says so rather than showing frozen zeros. */
|
|
619
|
-
acquireMeters?(): AudioMeterHandle | null;
|
|
620
|
-
/** Optional: tap the real mixed output for a gameplay recording. The
|
|
621
|
-
* returned stream is the implementation's native browser audio stream; the
|
|
622
|
-
* caller must dispose the tap when recording ends. Absence means video can
|
|
623
|
-
* still be recorded, honestly without an audio track. */
|
|
624
|
-
acquireRecordingStream?(): AudioRecordingHandle | null;
|
|
625
|
-
/**
|
|
626
|
-
* Optional: render this world's audio for the ABSOLUTE/canonical sim range
|
|
627
|
-
* `[start, end)` OFFLINE and deterministically — the fixed-step sibling of
|
|
628
|
-
* `acquireRecordingStream` above. That one taps the speakers in WALL time,
|
|
629
|
-
* which is exactly what the editor's fixed-step video export
|
|
630
|
-
* (`packages/editor-game/src/host/gameplay-export.ts`) may not do: a paused run that
|
|
631
|
-
* is stepped frame by frame emits no real-time audio at all, and anything
|
|
632
|
-
* captured from a live context would vary run to run. This returns PCM for
|
|
633
|
-
* a sim window instead, so identical `(start, end)` on an unchanged score
|
|
634
|
-
* must return identical samples.
|
|
635
|
-
*
|
|
636
|
-
* THE OFFSET TRAP (the gameplay export states it at its call site; quoted
|
|
637
|
-
* here because this is the other place implementers read):
|
|
638
|
-
* an offline render of `[10, 10.72)` schedules its first event at LOCAL
|
|
639
|
-
* time 0, not absolute 10. The caller reasons in canonical time, so the
|
|
640
|
-
* implementation must subtract `start` from every scheduled event time.
|
|
641
|
-
* The export places the returned buffer at local timestamp 0 of the clip.
|
|
642
|
-
*
|
|
643
|
-
* CLAMP THE SUBTRACTION AT ZERO. Measured 2026-09-19 against a working
|
|
644
|
-
* implementation: a sim clock ACCUMULATES its fixed step, so `start` for
|
|
645
|
-
* tick 900 arrives as 15.000000000000036, not 15. An event authored at
|
|
646
|
-
* exactly 15 then schedules at -3.6e-14 and Web Audio throws outright
|
|
647
|
-
* ("Time must be a finite non-negative number"). An event at or
|
|
648
|
-
* infinitesimally before the window start belongs at local 0.
|
|
649
|
-
*
|
|
650
|
-
* Absent — the honest default, and what the first-party master-gain adapter
|
|
651
|
-
* reports — means the export writes a video-only file and says `audio:
|
|
652
|
-
* false` in its result. A live Web Audio graph cannot be re-rendered
|
|
653
|
-
* offline by a bus wrapper; a world that wants export audio owns a
|
|
654
|
-
* deterministic score and binds this through `editor/volter.adapter.ts` (with the
|
|
655
|
-
* `music` capability that is one line over `renderToneOffline`).
|
|
656
|
-
*/
|
|
657
|
-
renderOffline?: OfflineAudioRenderer;
|
|
658
|
-
/** Optional: the audio event ring (bounded, drops oldest). `sinceSeq`
|
|
659
|
-
* filters to `seq > sinceSeq` — the consumer's fence. */
|
|
660
|
-
audioEvents?(sinceSeq?: number): AudioDebugEvent[];
|
|
661
|
-
}
|
|
662
|
-
|
|
663
|
-
/** One temporary tap of an audio adapter's mixed output. */
|
|
664
|
-
export interface AudioRecordingHandle {
|
|
665
|
-
readonly stream: MediaStream;
|
|
666
|
-
dispose(): void;
|
|
667
|
-
}
|
|
668
|
-
|
|
669
131
|
/** One native camera known to a runtime camera controller.
|
|
670
132
|
*
|
|
671
133
|
* `id` is the controller's own stable key (a shot name, virtual-camera id,
|
|
672
134
|
* etc.). `nativeId` is OPTIONAL identity from the underlying scene object —
|
|
673
|
-
*
|
|
674
|
-
*
|
|
135
|
+
* e.g. the 3D integration's scene object's uuid; another adapter may use its
|
|
136
|
+
* renderer's equivalent. The editor uses it only to correlate an
|
|
675
137
|
* already-selected native camera with this read-only runtime projection. */
|
|
676
138
|
export interface CameraRuntimeCamera {
|
|
677
139
|
id: string;
|
|
@@ -708,7 +170,7 @@ export interface CameraRuntimeSnapshot {
|
|
|
708
170
|
|
|
709
171
|
/** Camera-controller INTROSPECTION — not a camera graph or controller API.
|
|
710
172
|
*
|
|
711
|
-
*
|
|
173
|
+
* Projects continue to author ordinary native cameras and drive them with their
|
|
712
174
|
* own TS/TSX. A controller registers this adapter only when it can truthfully
|
|
713
175
|
* expose its active camera, priority and blend state. Absence hides the
|
|
714
176
|
* runtime UI; the editor never infers a brain from scene structure. */
|
|
@@ -717,98 +179,9 @@ export interface CameraAdapter {
|
|
|
717
179
|
subscribe(listener: () => void): Unsubscribe;
|
|
718
180
|
}
|
|
719
181
|
|
|
720
|
-
/** One tick-stamped debug event (`ctx.debug.emit`, spec §3.3): `tick`/`simT`
|
|
721
|
-
* are the engine's own counters AT EMISSION, so events and state reads
|
|
722
|
-
* correlate frame-exactly across every door (in-page bridge, relay, panels).
|
|
723
|
-
*
|
|
724
|
-
* `seq` (run-4 friction #5 fix) is a registry-lifetime MONOTONIC counter,
|
|
725
|
-
* strictly increasing by one per `emit()` call regardless of `tick` —
|
|
726
|
-
* unlike `tick`, it is never shared by two events, which is what makes it
|
|
727
|
-
* safe to fence on. A debug command handler runs BETWEEN ticks (its
|
|
728
|
-
* emissions carry whatever `tick` is current at that instant, same as every
|
|
729
|
-
* other emission at that instant would), so two DIFFERENT events — or an
|
|
730
|
-
* event and a consumer's fence point — can legitimately share one `tick`;
|
|
731
|
-
* `seq` never collides the same way, so "everything after what I've already
|
|
732
|
-
* observed" is unambiguous. See `events(sinceSeq)` below. */
|
|
733
|
-
export interface TickStampedEvent {
|
|
734
|
-
tick: number;
|
|
735
|
-
simT: number;
|
|
736
|
-
event: string;
|
|
737
|
-
detail?: unknown;
|
|
738
|
-
seq: number;
|
|
739
|
-
}
|
|
740
|
-
|
|
741
|
-
/** One registered debug command's listing shape — `locus` is always present
|
|
742
|
-
* (defaults to `'client'` when a command didn't declare one) so every
|
|
743
|
-
* listing surface can print it without a fallback of its own. */
|
|
744
|
-
export interface DebugCommandInfo {
|
|
745
|
-
name: string;
|
|
746
|
-
description?: string | undefined;
|
|
747
|
-
/** JSON-Schema projection of the command's Zod args tuple, when declared. */
|
|
748
|
-
argsJsonSchema?: unknown;
|
|
749
|
-
locus: 'client' | 'server';
|
|
750
|
-
}
|
|
751
|
-
|
|
752
|
-
/**
|
|
753
|
-
* The debug/synthetic-player seam: game-scoped introspection + actuation
|
|
754
|
-
* over whatever a game registers via `ctx.debug`
|
|
755
|
-
* (`registerStateProvider`/`registerCommand`/`emit`). NOT a gameplay API —
|
|
756
|
-
* this is the one seam the debug bridge, the editor's Debug Console/State
|
|
757
|
-
* Watch panels, and `@volter/game-live` all read/drive through.
|
|
758
|
-
*/
|
|
759
|
-
export interface DebugAdapter {
|
|
760
|
-
providers(): { name: string; tier: 'observable' | 'assisted' }[];
|
|
761
|
-
/** One provider's current value. Throws `DebugError` code
|
|
762
|
-
* `STATE_PROVIDER_NOT_FOUND` (`data.registered`) for an unknown name. */
|
|
763
|
-
state(name: string): unknown;
|
|
764
|
-
/** One coherent snapshot of every registered provider — a throwing
|
|
765
|
-
* provider contributes `{ __error: String(err) }` for its own key rather
|
|
766
|
-
* than failing the whole snapshot. */
|
|
767
|
-
stateAll(): Record<string, unknown>;
|
|
768
|
-
commands(): DebugCommandInfo[];
|
|
769
|
-
/** Validates `args` against the command's declared Zod tuple (when
|
|
770
|
-
* present), then awaits the registered fn. Throws `DebugError` code
|
|
771
|
-
* `DEBUG_COMMAND_NOT_REGISTERED` for an unknown name,
|
|
772
|
-
* `DEBUG_COMMAND_ARGS_INVALID` for a validation failure, or
|
|
773
|
-
* `DEBUG_COMMAND_FAILED` wrapping anything the command itself threw. */
|
|
774
|
-
invoke(name: string, args: unknown[]): Promise<unknown>;
|
|
775
|
-
/** The tick-stamped event ring (cap 500, drops oldest).
|
|
776
|
-
*
|
|
777
|
-
* - `sinceSeq` given (run-4 friction #5 fix): filters to `seq > sinceSeq`
|
|
778
|
-
* — the unambiguous fence for "everything emitted after what I've
|
|
779
|
-
* already observed" (see `TickStampedEvent.seq`'s doc comment for why
|
|
780
|
-
* `tick` alone can't do this: a debug-command emission and a consumer's
|
|
781
|
-
* fence point can share one tick).
|
|
782
|
-
* - Omitted: the whole ring.
|
|
783
|
-
*
|
|
784
|
-
* There was a second, KNOWN-DEFECTIVE `sinceTick` parameter (`tick >
|
|
785
|
-
* sinceTick`, which silently dropped same-tick events) kept for
|
|
786
|
-
* back-compat after the seq fix. It is REMOVED — a fence is `seq` or
|
|
787
|
-
* nothing. */
|
|
788
|
-
events(sinceSeq?: number): TickStampedEvent[];
|
|
789
|
-
}
|
|
790
|
-
|
|
791
|
-
/**
|
|
792
|
-
* Read-only render-debugging introspection (W4b, F11 frame debugger +
|
|
793
|
-
* profiler) — NOT a renderer. `captureFrame` arms the first-party WebGL2
|
|
794
|
-
* capture (`dev/webgl-frame-capture.ts`) and resolves with the NEXT rendered
|
|
795
|
-
* frame's draw list, attributed by wrapping each renderable's `onBeforeRender`
|
|
796
|
-
* (three calls it immediately before that object's main-pass draw; shadow/
|
|
797
|
-
* composer-pass draws stay unattributed BY CONSTRUCTION — an honest gap, not a
|
|
798
|
-
* guess). It REJECTS — never fabricates — if no frame renders within a bounded
|
|
799
|
-
* timeout (a paused/stopped world). `memorySnapshot` is the W3a-style OPTIONAL
|
|
800
|
-
* capability: present only when the mount can supply `renderer.info` (a
|
|
801
|
-
* headless mount omits it, and the editor marks the section absent).
|
|
802
|
-
*/
|
|
803
|
-
export interface RenderDebugAdapter {
|
|
804
|
-
captureFrame(): Promise<FrameCapture>;
|
|
805
|
-
memorySnapshot?(): RenderMemorySnapshot;
|
|
806
|
-
}
|
|
807
|
-
|
|
808
182
|
/**
|
|
809
|
-
* A physics carrier in EITHER surface's vocabulary — node-id keyed for a
|
|
810
|
-
* world, display-object keyed for a canvas one. Tagged by `keyedBy`;
|
|
811
|
-
* {@link PhysicsAdapter}'s comment for why, and use the two narrowings below
|
|
183
|
+
* A physics carrier in EITHER surface's vocabulary — node-id keyed for a stage
|
|
184
|
+
* world, display-object keyed for a canvas one. Tagged by `keyedBy`; use the two narrowings below
|
|
812
185
|
* rather than reading the tag directly.
|
|
813
186
|
*/
|
|
814
187
|
export type PhysicsCarrier = PhysicsAdapter | PhysicsAdapter2D;
|
|
@@ -824,7 +197,7 @@ export function nodeKeyedPhysics(
|
|
|
824
197
|
}
|
|
825
198
|
|
|
826
199
|
/**
|
|
827
|
-
* Who drives `key`, asked of the
|
|
200
|
+
* Who drives `key`, asked of the project's own physics carrier by an editor surface that renders the
|
|
828
201
|
* answer. A declared system slot with nothing attached yet (a world whose `<Physics>` mounts late)
|
|
829
202
|
* refuses by name, and a refusal read from an outliner row would take the editor's chrome down with
|
|
830
203
|
* it: to the editor a carrier that cannot answer does not know the node, which `'unresolved'` says.
|
|
@@ -851,15 +224,10 @@ function isDisplayKeyedPhysics(carrier: PhysicsCarrier): carrier is PhysicsAdapt
|
|
|
851
224
|
}
|
|
852
225
|
|
|
853
226
|
/**
|
|
854
|
-
* The set of optional subsystem providers a mounted
|
|
227
|
+
* The set of optional subsystem providers a mounted project may expose. Absence of
|
|
855
228
|
* a provider means "capability not supported" — the editor degrades gracefully.
|
|
856
229
|
*/
|
|
857
230
|
export interface SystemAdapters {
|
|
858
231
|
physics?: PhysicsCarrier;
|
|
859
|
-
networking?: NetworkingAdapter;
|
|
860
|
-
navigation?: NavigationAdapter;
|
|
861
|
-
audio?: AudioAdapter;
|
|
862
232
|
camera?: CameraAdapter;
|
|
863
|
-
debug?: DebugAdapter;
|
|
864
|
-
renderDebug?: RenderDebugAdapter;
|
|
865
233
|
}
|