@vgai/engine 0.5.13 → 0.5.14
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/dist/adapter/adapter-module.d.ts +447 -0
- package/dist/adapter/adapter-module.d.ts.map +1 -0
- package/dist/adapter/adapter-module.js +308 -0
- package/dist/adapter/authoring.d.ts +357 -10
- package/dist/adapter/authoring.d.ts.map +1 -1
- package/dist/adapter/authoring.js +87 -1
- package/dist/adapter/constraint.d.ts +9 -3
- package/dist/adapter/constraint.d.ts.map +1 -1
- package/dist/adapter/finders/finder-result.d.ts +28 -0
- package/dist/adapter/finders/finder-result.d.ts.map +1 -0
- package/dist/adapter/finders/finder-result.js +10 -0
- package/dist/adapter/finders/index.d.ts +38 -0
- package/dist/adapter/finders/index.d.ts.map +1 -0
- package/dist/adapter/finders/index.js +41 -0
- package/dist/adapter/finders/prefabs-from-stories.d.ts +64 -0
- package/dist/adapter/finders/prefabs-from-stories.d.ts.map +1 -0
- package/dist/adapter/finders/prefabs-from-stories.js +92 -0
- package/dist/adapter/finders/scenes-from-entrypoint-selection.d.ts +67 -0
- package/dist/adapter/finders/scenes-from-entrypoint-selection.d.ts.map +1 -0
- package/dist/adapter/finders/scenes-from-entrypoint-selection.js +226 -0
- package/dist/adapter/first-party-systems.d.ts.map +1 -1
- package/dist/adapter/first-party-systems.js +29 -0
- package/dist/adapter/index.d.ts +7 -3
- package/dist/adapter/index.d.ts.map +1 -1
- package/dist/adapter/index.js +5 -2
- package/dist/adapter/ingest/contract-system-adapters.d.ts +24 -1
- package/dist/adapter/ingest/contract-system-adapters.d.ts.map +1 -1
- package/dist/adapter/ingest/contract-system-adapters.js +100 -34
- package/dist/adapter/ingest/game-contract.d.ts +188 -2
- package/dist/adapter/ingest/game-contract.d.ts.map +1 -1
- package/dist/adapter/ingest/game-contract.js +107 -0
- package/dist/adapter/ingest/mount-readiness.d.ts +84 -0
- package/dist/adapter/ingest/mount-readiness.d.ts.map +1 -0
- package/dist/adapter/ingest/mount-readiness.js +81 -0
- package/dist/adapter/ingest/scene-capture.d.ts +91 -2
- package/dist/adapter/ingest/scene-capture.d.ts.map +1 -1
- package/dist/adapter/ingest/scene-capture.js +110 -18
- package/dist/adapter/ingest/structural-ids.d.ts +11 -5
- package/dist/adapter/ingest/structural-ids.d.ts.map +1 -1
- package/dist/adapter/ingest/structural-ids.js +18 -9
- package/dist/adapter/ingest/upstream-pin.d.ts +4 -2
- package/dist/adapter/ingest/upstream-pin.d.ts.map +1 -1
- package/dist/adapter/ingest/upstream-pin.js +4 -2
- package/dist/adapter/ingest/visible-capture-window.d.ts +116 -0
- package/dist/adapter/ingest/visible-capture-window.d.ts.map +1 -0
- package/dist/adapter/ingest/visible-capture-window.js +141 -0
- package/dist/adapter/loop-gate-report.d.ts +3 -4
- package/dist/adapter/loop-gate-report.d.ts.map +1 -1
- package/dist/adapter/loop-gate-report.js +3 -4
- package/dist/adapter/root-adapter.d.ts +22 -2
- package/dist/adapter/root-adapter.d.ts.map +1 -1
- package/dist/adapter/setup-three-root-adapter.d.ts.map +1 -1
- package/dist/adapter/setup-three-root-adapter.js +15 -0
- package/dist/adapter/system-adapter.d.ts +161 -2
- package/dist/adapter/system-adapter.d.ts.map +1 -1
- package/dist/adapter/system-adapter.js +18 -1
- package/dist/animation/camera-ownership.d.ts +4 -2
- package/dist/animation/camera-ownership.d.ts.map +1 -1
- package/dist/animation/camera-ownership.js +58 -1
- package/dist/animation/runtime-inspection.d.ts +70 -0
- package/dist/animation/runtime-inspection.d.ts.map +1 -0
- package/dist/animation/runtime-inspection.js +25 -0
- package/dist/animation/xstate-animation-binding.d.ts +9 -1
- package/dist/animation/xstate-animation-binding.d.ts.map +1 -1
- package/dist/animation/xstate-animation-binding.js +48 -1
- package/dist/asset-formats/material.d.ts +1 -1
- package/dist/asset-formats/mesh.d.ts +1 -1
- package/dist/asset-formats/particles.d.ts +13 -0
- package/dist/asset-formats/particles.d.ts.map +1 -1
- package/dist/asset-formats/particles.js +28 -0
- package/dist/behavior/xstate-inspection.d.ts +24 -0
- package/dist/behavior/xstate-inspection.d.ts.map +1 -0
- package/dist/behavior/xstate-inspection.js +25 -0
- package/dist/core/game-loop.d.ts +7 -5
- package/dist/core/game-loop.d.ts.map +1 -1
- package/dist/core/game-loop.js +39 -18
- package/dist/core/types.d.ts +11 -12
- package/dist/core/types.d.ts.map +1 -1
- package/dist/data/data-asset.js +1 -1
- package/dist/dev/instruments.d.ts.map +1 -1
- package/dist/dev/instruments.js +5 -1
- package/dist/dev/render-debug-adapter.d.ts +19 -2
- package/dist/dev/render-debug-adapter.d.ts.map +1 -1
- package/dist/dev/render-debug-adapter.js +10 -0
- package/dist/ecs/user-data.d.ts +10 -2
- package/dist/ecs/user-data.d.ts.map +1 -1
- package/dist/ecs/user-data.js +6 -2
- package/dist/input/binding-identity.d.ts +10 -0
- package/dist/input/binding-identity.d.ts.map +1 -0
- package/dist/input/binding-identity.js +36 -0
- package/dist/input/input-manager.d.ts +18 -185
- package/dist/input/input-manager.d.ts.map +1 -1
- package/dist/input/input-manager.js +78 -68
- package/dist/manifest/load.d.ts +14 -0
- package/dist/manifest/load.d.ts.map +1 -1
- package/dist/manifest/load.js +6 -1
- package/dist/manifest/schema.d.ts +18 -0
- package/dist/manifest/schema.d.ts.map +1 -1
- package/dist/manifest/schema.js +64 -7
- package/dist/pixi/authoring.d.ts +27 -0
- package/dist/pixi/authoring.d.ts.map +1 -1
- package/dist/pixi/authoring.js +10 -3
- package/dist/pixi/index.d.ts +1 -1
- package/dist/pixi/index.d.ts.map +1 -1
- package/dist/pixi/index.js +1 -1
- package/dist/pixi/ingest.d.ts +8 -0
- package/dist/pixi/ingest.d.ts.map +1 -1
- package/dist/pixi/ingest.js +10 -1
- package/dist/pixi/render-pass-bracket.d.ts +56 -0
- package/dist/pixi/render-pass-bracket.d.ts.map +1 -0
- package/dist/pixi/render-pass-bracket.js +98 -0
- package/dist/pixi/scene-capture.d.ts +32 -1
- package/dist/pixi/scene-capture.d.ts.map +1 -1
- package/dist/pixi/scene-capture.js +21 -9
- package/dist/pixi/system-adapters.d.ts +29 -0
- package/dist/pixi/system-adapters.d.ts.map +1 -1
- package/dist/pixi/system-adapters.js +27 -0
- package/dist/render/particles-factory.d.ts +16 -2
- package/dist/render/particles-factory.d.ts.map +1 -1
- package/dist/render/particles-factory.js +88 -5
- package/dist/render/soft-particle-depth.d.ts +149 -0
- package/dist/render/soft-particle-depth.d.ts.map +1 -0
- package/dist/render/soft-particle-depth.js +305 -0
- package/dist/render/voxel-surface.d.ts +117 -0
- package/dist/render/voxel-surface.d.ts.map +1 -0
- package/dist/render/voxel-surface.js +263 -0
- package/dist/runtime/create-runtime.js +7 -0
- package/dist/runtime/debug-bridge.d.ts +15 -15
- package/dist/runtime/debug-bridge.d.ts.map +1 -1
- package/dist/runtime/debug-bridge.js +27 -26
- package/dist/runtime/game.d.ts.map +1 -1
- package/dist/runtime/game.js +1 -2
- package/dist/setup/setup-particles.d.ts.map +1 -1
- package/dist/setup/setup-particles.js +9 -0
- package/dist/world3d-react/r3f-adapter.d.ts.map +1 -1
- package/dist/world3d-react/r3f-adapter.js +42 -3
- package/dist/world3d-react/rapier-physics-bridge.d.ts.map +1 -1
- package/dist/world3d-react/rapier-physics-bridge.js +201 -11
- package/dist-config/config.js.map +1 -1
- package/package.json +4 -2
- package/schemas/engine-capabilities.json +12 -12
- package/schemas/vgai-project.schema.json +41 -2
- package/src/adapter/adapter-module.ts +607 -0
- package/src/adapter/authoring.ts +440 -10
- package/src/adapter/constraint.ts +10 -3
- package/src/adapter/finders/finder-result.ts +29 -0
- package/src/adapter/finders/index.ts +62 -0
- package/src/adapter/finders/prefabs-from-stories.ts +142 -0
- package/src/adapter/finders/scenes-from-entrypoint-selection.ts +304 -0
- package/src/adapter/first-party-systems.ts +30 -0
- package/src/adapter/index.ts +32 -1
- package/src/adapter/ingest/contract-system-adapters.ts +116 -32
- package/src/adapter/ingest/game-contract.ts +265 -2
- package/src/adapter/ingest/mount-readiness.ts +140 -0
- package/src/adapter/ingest/scene-capture.ts +199 -22
- package/src/adapter/ingest/structural-ids.ts +21 -9
- package/src/adapter/ingest/upstream-pin.ts +4 -2
- package/src/adapter/ingest/visible-capture-window.ts +213 -0
- package/src/adapter/loop-gate-report.ts +3 -4
- package/src/adapter/root-adapter.ts +22 -2
- package/src/adapter/setup-three-root-adapter.ts +16 -0
- package/src/adapter/system-adapter.ts +188 -2
- package/src/animation/camera-ownership.ts +68 -3
- package/src/animation/runtime-inspection.ts +104 -0
- package/src/animation/xstate-animation-binding.ts +53 -1
- package/src/asset-formats/particles.ts +31 -0
- package/src/behavior/xstate-inspection.ts +51 -0
- package/src/core/game-loop.ts +39 -17
- package/src/core/types.ts +11 -12
- package/src/data/data-asset.ts +1 -1
- package/src/dev/instruments.ts +5 -1
- package/src/dev/render-debug-adapter.ts +22 -2
- package/src/ecs/user-data.ts +10 -2
- package/src/input/binding-identity.ts +37 -0
- package/src/input/input-manager.ts +93 -68
- package/src/manifest/load.ts +23 -2
- package/src/manifest/schema.ts +76 -7
- package/src/pixi/authoring.ts +37 -5
- package/src/pixi/index.ts +2 -0
- package/src/pixi/ingest.ts +15 -2
- package/src/pixi/render-pass-bracket.ts +117 -0
- package/src/pixi/scene-capture.ts +63 -13
- package/src/pixi/system-adapters.ts +41 -0
- package/src/render/particles-factory.ts +89 -6
- package/src/render/soft-particle-depth.ts +336 -0
- package/src/render/voxel-surface.ts +358 -0
- package/src/runtime/create-runtime.ts +7 -0
- package/src/runtime/debug-bridge.ts +32 -31
- package/src/runtime/game.ts +1 -2
- package/src/setup/setup-particles.ts +9 -0
- package/src/world3d-react/r3f-adapter.tsx +48 -2
- package/src/world3d-react/rapier-physics-bridge.tsx +249 -11
package/src/adapter/authoring.ts
CHANGED
|
@@ -182,7 +182,10 @@ export interface HierarchyProvider {
|
|
|
182
182
|
|
|
183
183
|
export interface SelectionProvider {
|
|
184
184
|
get(): string[];
|
|
185
|
-
|
|
185
|
+
/** Set the selected authoring subjects. `exact` is for projections that
|
|
186
|
+
* already name a real node (for example a folded-internal light inventory);
|
|
187
|
+
* the default keeps the adapter's normal semantic component resolution. */
|
|
188
|
+
set(ids: string[], options?: { intent?: 'semantic' | 'exact' }): void;
|
|
186
189
|
/** Resolve a raw native/render hit to the semantic authoring subject. The
|
|
187
190
|
* shell must not infer ownership from ancestry or substrate-specific kinds.
|
|
188
191
|
* Older adapters may omit this; raw ids then remain the selection ids. */
|
|
@@ -220,7 +223,14 @@ export interface TransformProvider {
|
|
|
220
223
|
/** Pause whatever controller fights the gizmo (physics/script) for editing. */
|
|
221
224
|
beginEdit(id: string): void;
|
|
222
225
|
apply(id: string, t: Transform): void;
|
|
223
|
-
|
|
226
|
+
/**
|
|
227
|
+
* Close the gesture — and, for an adapter that persists, ANSWER FOR IT: the
|
|
228
|
+
* returned {@link WriteAck} is this edit's own outcome, produced after the
|
|
229
|
+
* write it triggered has settled. Returning nothing is the honest report of
|
|
230
|
+
* an adapter that performed no write, and the shell then reports the
|
|
231
|
+
* live-only floor rather than borrowing an answer from somewhere else.
|
|
232
|
+
*/
|
|
233
|
+
endEdit(id: string): void | WriteAck | Promise<void | WriteAck>;
|
|
224
234
|
}
|
|
225
235
|
|
|
226
236
|
/**
|
|
@@ -238,7 +248,18 @@ export interface InspectorProvider {
|
|
|
238
248
|
/** Schema-driven — NOT fixed to `SceneEntity`. */
|
|
239
249
|
properties(id: string): PropertyDescriptor[];
|
|
240
250
|
get(id: string, path: string): unknown;
|
|
241
|
-
|
|
251
|
+
/**
|
|
252
|
+
* Write one property — and, for an adapter that persists, ANSWER FOR IT: the
|
|
253
|
+
* returned {@link WriteAck} is this edit's own outcome (same contract as
|
|
254
|
+
* {@link TransformProvider.endEdit}). Returning nothing means no write was
|
|
255
|
+
* performed by this provider, and the shell reports the live-only floor.
|
|
256
|
+
*/
|
|
257
|
+
set(id: string, path: string, value: unknown): void | WriteAck | Promise<void | WriteAck>;
|
|
258
|
+
/** Optional per-subject write preflight for shell affordances outside the
|
|
259
|
+
* Inspector field grid (notably hierarchy eye/lock controls). The property
|
|
260
|
+
* descriptor remains the Inspector's source of `readonly`; this gives other
|
|
261
|
+
* generic surfaces the same answer and its adapter-authored reason. */
|
|
262
|
+
editability?(id: string, path: string): { writable: boolean; reason?: string };
|
|
242
263
|
/**
|
|
243
264
|
* Optional — REMOVE a property's authored override entirely (not "set to a
|
|
244
265
|
* value"), letting whatever governs it in its absence take over. The one
|
|
@@ -294,6 +315,47 @@ export interface RelatedSubjectsProvider {
|
|
|
294
315
|
links(id: string): readonly RelatedSubjectLink[];
|
|
295
316
|
}
|
|
296
317
|
|
|
318
|
+
/** One source-owned prop that differs from its component's declared default. */
|
|
319
|
+
export interface ComponentInstanceOverride {
|
|
320
|
+
/** The owning Inspector field path; stable and agent-addressable. */
|
|
321
|
+
readonly path: string;
|
|
322
|
+
readonly label: string;
|
|
323
|
+
readonly value: unknown;
|
|
324
|
+
/** Source text of the component default, when the declaration exposes one. */
|
|
325
|
+
readonly defaultText?: string;
|
|
326
|
+
/** Applying requires a literal callsite value and a literal declared default. */
|
|
327
|
+
readonly canApplyToComponent: boolean;
|
|
328
|
+
readonly applyUnavailableReason?: string;
|
|
329
|
+
/** Placed instances that will inherit this default after the apply. */
|
|
330
|
+
readonly affectedInstanceCount: number;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/** Derived prefab-instance facts. Nothing in this shape is persisted separately. */
|
|
334
|
+
export interface ComponentInstanceDescription {
|
|
335
|
+
readonly componentName: string;
|
|
336
|
+
readonly sourcePath?: string;
|
|
337
|
+
readonly overrides: readonly ComponentInstanceOverride[];
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
export interface ComponentInstanceApplyResult {
|
|
341
|
+
readonly changed: boolean;
|
|
342
|
+
readonly message: string;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Source-derived component-instance operations. A provider exists only when an
|
|
347
|
+
* adapter can prove component identity and write the component's native source.
|
|
348
|
+
* No override store is implied: describe is a diff, revert removes callsite
|
|
349
|
+
* props, and apply edits the component declaration itself.
|
|
350
|
+
*/
|
|
351
|
+
export interface ComponentInstancesProvider {
|
|
352
|
+
describe(id: string): ComponentInstanceDescription | null;
|
|
353
|
+
/** Open the native component/prefab board for this instance's surface. */
|
|
354
|
+
openComponent?(id: string): void;
|
|
355
|
+
revert(id: string, paths: readonly string[]): Promise<void>;
|
|
356
|
+
applyToComponent(id: string, path: string): Promise<ComponentInstanceApplyResult>;
|
|
357
|
+
}
|
|
358
|
+
|
|
297
359
|
export interface StructureProvider {
|
|
298
360
|
create(kind: string, parentId?: string): string;
|
|
299
361
|
/**
|
|
@@ -357,6 +419,23 @@ export interface StructureProvider {
|
|
|
357
419
|
* is a harmless no-op.
|
|
358
420
|
*/
|
|
359
421
|
removeMany?(ids: readonly string[]): void | Promise<void>;
|
|
422
|
+
/** Copy authored entities through the host clipboard. The adapter owns the
|
|
423
|
+
* native payload (JSX for a source-backed Three/Canvas world, native records
|
|
424
|
+
* for a data-backed adapter); the shell never serializes an engine-private
|
|
425
|
+
* shape. */
|
|
426
|
+
copy?(ids: readonly string[]): boolean | Promise<boolean>;
|
|
427
|
+
/** Honest affordance preflight. Omit when copy is never offered. */
|
|
428
|
+
canCopy?(ids: readonly string[]): boolean;
|
|
429
|
+
/** Copy, then remove the same authored entities only after the clipboard
|
|
430
|
+
* write succeeds. One adapter operation owns that ordering. */
|
|
431
|
+
cut?(ids: readonly string[]): boolean | Promise<boolean>;
|
|
432
|
+
/** Paste as children of `parentId`; `null` means the adapter document root.
|
|
433
|
+
* The shell derives the current selection's parent so ordinary Paste creates
|
|
434
|
+
* siblings, matching scene-hierarchy editors. */
|
|
435
|
+
paste?(parentId: string | null): boolean | Promise<boolean>;
|
|
436
|
+
/** Honest affordance preflight. It need only cover adapter/session state;
|
|
437
|
+
* the actual paste still validates the live system clipboard. */
|
|
438
|
+
canPaste?(parentId: string | null): boolean;
|
|
360
439
|
}
|
|
361
440
|
|
|
362
441
|
/**
|
|
@@ -367,6 +446,10 @@ export interface StructureProvider {
|
|
|
367
446
|
*/
|
|
368
447
|
export interface PersistenceProvider {
|
|
369
448
|
isDirty(): boolean;
|
|
449
|
+
/** The last persistence failure that still requires attention. Successful
|
|
450
|
+
* subsequent persistence clears it. Auto-saving source adapters use this to
|
|
451
|
+
* report a rolled-back source write without inventing a dirty document. */
|
|
452
|
+
lastError?(): string | null;
|
|
370
453
|
/** Save to the adapter's OWN source of truth (.vscn / overlay file / …). */
|
|
371
454
|
save(): Promise<void>;
|
|
372
455
|
/**
|
|
@@ -400,6 +483,13 @@ export interface PersistenceProvider {
|
|
|
400
483
|
/** D12 — per-layer viewport picking. Coordinates are client (browser) px. */
|
|
401
484
|
export interface PickProvider {
|
|
402
485
|
pick(clientX: number, clientY: number): string | null;
|
|
486
|
+
/**
|
|
487
|
+
* Every authorable subject below the point, frontmost first. The shell uses
|
|
488
|
+
* this for the ordinary scene-editor "pick from overlap" menu; adapters
|
|
489
|
+
* that cannot enumerate an overlap may omit it and still provide the
|
|
490
|
+
* single-hit floor through {@link pick}.
|
|
491
|
+
*/
|
|
492
|
+
candidates?(clientX: number, clientY: number): readonly string[];
|
|
403
493
|
}
|
|
404
494
|
|
|
405
495
|
/** D4 — storybook stories. */
|
|
@@ -413,6 +503,14 @@ export interface StoriesProvider {
|
|
|
413
503
|
apply(nodeId: string, storyId: string | null): void; // null clears
|
|
414
504
|
/** Render ONLY this node against the story (storybook canvas); null exits. */
|
|
415
505
|
isolate?(nodeId: string | null, storyId?: string): void;
|
|
506
|
+
/**
|
|
507
|
+
* Display vocabulary for this provider's section — e.g. an ingested game's
|
|
508
|
+
* contract scenes say "Scenes"; absent means the default "Stories". The
|
|
509
|
+
* states are the same seam either way; only the word the human reads
|
|
510
|
+
* changes, so a game's own screens are never labelled with a design-time
|
|
511
|
+
* term the game never uses.
|
|
512
|
+
*/
|
|
513
|
+
readonly title?: string;
|
|
416
514
|
}
|
|
417
515
|
|
|
418
516
|
/**
|
|
@@ -424,11 +522,22 @@ export interface StoriesProvider {
|
|
|
424
522
|
*/
|
|
425
523
|
export interface AssetDropContext {
|
|
426
524
|
readonly position?: readonly [number, number, number];
|
|
525
|
+
/** Transient drag metadata. The project's native source remains truth; this
|
|
526
|
+
* only tells an adapter whether the path names a file or a source component. */
|
|
527
|
+
readonly item?:
|
|
528
|
+
| { readonly kind: 'file'; readonly name: string }
|
|
529
|
+
| {
|
|
530
|
+
readonly kind: 'component';
|
|
531
|
+
readonly name: string;
|
|
532
|
+
readonly sourcePath: string;
|
|
533
|
+
readonly exportKind: 'default' | 'named';
|
|
534
|
+
readonly surface: 'three' | 'canvas' | 'dom' | 'unknown';
|
|
535
|
+
};
|
|
427
536
|
}
|
|
428
537
|
|
|
429
538
|
/** Asset drop (hierarchy + viewport). */
|
|
430
539
|
export interface AssetDropProvider {
|
|
431
|
-
accepts(nodeId: string, assetPath: string): boolean;
|
|
540
|
+
accepts(nodeId: string, assetPath: string, context?: AssetDropContext): boolean;
|
|
432
541
|
drop(nodeId: string, assetPath: string, context?: AssetDropContext): void | Promise<void>;
|
|
433
542
|
}
|
|
434
543
|
|
|
@@ -488,8 +597,9 @@ export interface BoxEditReferencePoint {
|
|
|
488
597
|
y: number;
|
|
489
598
|
}
|
|
490
599
|
|
|
491
|
-
/** Spatial gesture → source/data write
|
|
492
|
-
*
|
|
600
|
+
/** Spatial gesture → source/data write for native 2D boxes (DOM or canvas).
|
|
601
|
+
* Distinct from the 3D TransformProvider. begin/apply/end bracket a single
|
|
602
|
+
* undo step; apply is live-preview. */
|
|
493
603
|
export interface BoxEditProvider {
|
|
494
604
|
begin(id: string): void;
|
|
495
605
|
/** patch: any of x,y,width,height,marginTop… paddingLeft… — px deltas or absolutes.
|
|
@@ -499,6 +609,11 @@ export interface BoxEditProvider {
|
|
|
499
609
|
* source units and any placement-preserving compensation. */
|
|
500
610
|
apply(id: string, patch: Record<string, number>): void;
|
|
501
611
|
end(id: string): void;
|
|
612
|
+
/** Native transform origin for the viewport gizmo, in the same host-space
|
|
613
|
+
* frame as {@link RectProvider}. A 2D scene uses this instead of guessing
|
|
614
|
+
* from the visual bounds: sprites can have anchors, containers can have
|
|
615
|
+
* pivots, and neither necessarily sits at the box center. */
|
|
616
|
+
gizmoOrigin?(id: string): { x: number; y: number } | null;
|
|
502
617
|
/** Optional single native anchor/pivot affordance for this node. */
|
|
503
618
|
referencePoint?(id: string): BoxEditReferencePoint | null;
|
|
504
619
|
}
|
|
@@ -547,10 +662,10 @@ export interface ColorSampleProvider {
|
|
|
547
662
|
* - `source` is the original: a `new` expression at a `file:line:col` in the
|
|
548
663
|
* game's own code, which is where an edit to a constructor literal has to be
|
|
549
664
|
* written.
|
|
550
|
-
* - `data` is the sibling a level-based game needs.
|
|
551
|
-
*
|
|
552
|
-
* it is binary records inside
|
|
553
|
-
* authored move of
|
|
665
|
+
* - `data` is the sibling a level-based game needs. Its placed cargo — the
|
|
666
|
+
* enemies, the pickups, the objectives — reaches no source literal at all;
|
|
667
|
+
* it is binary records inside a level file that the game parses at load. An
|
|
668
|
+
* authored move of one is therefore an edit to THE GAME'S OWN DATA, and
|
|
554
669
|
* the honest anchor is the data file plus the index of the record that
|
|
555
670
|
* addresses the object inside it.
|
|
556
671
|
*
|
|
@@ -576,6 +691,134 @@ export type NodeCreationSite =
|
|
|
576
691
|
}
|
|
577
692
|
| { anchored: false; reason: string };
|
|
578
693
|
|
|
694
|
+
/**
|
|
695
|
+
* WHERE AN AUTHORED WRITE LANDS — the vocabulary of anchor KINDS, and the
|
|
696
|
+
* closed set of them.
|
|
697
|
+
*
|
|
698
|
+
* {@link NodeCreationSite} answers "where did this object come from"; a kind
|
|
699
|
+
* answers the write-side question beside it: WHICH LANE would carry an edit to
|
|
700
|
+
* this node, and therefore WHAT has to be true for that edit to be correct. The
|
|
701
|
+
* two are not the same fact — two nodes can both be `{ kind: 'source' }` at a
|
|
702
|
+
* `file:line` and still be written by different lanes with different gates.
|
|
703
|
+
*
|
|
704
|
+
* Each kind's CORRECTNESS CONTRACT, and the named test that proves it:
|
|
705
|
+
*
|
|
706
|
+
* - `source-prop` — the value is a literal PROP on an element of the game's own
|
|
707
|
+
* source (a JSX attribute the serve-time authoring stamp addresses). Lands at
|
|
708
|
+
* the anchor; survives a cold remount, because the file is truth and the next
|
|
709
|
+
* mount re-derives from it.
|
|
710
|
+
* Proof: `packages/editor/test/oid-source-persistence.test.ts`.
|
|
711
|
+
* - `construction-literal` — the value is a literal in the CONSTRUCTION
|
|
712
|
+
* EXPRESSION that built the object (`new THREE.Mesh(…)` in the game's own
|
|
713
|
+
* served module). Same landing/remount contract, plus one gate the prop lane
|
|
714
|
+
* does not have: a site that constructed more than one object is refused,
|
|
715
|
+
* because rewriting its literal would move all of them.
|
|
716
|
+
* Proof: `packages/editor/test/ingest-source-persistence.test.ts`.
|
|
717
|
+
* - `physics-binding` — the node's own transform props are DEAD: a simulated
|
|
718
|
+
* body writes its matrix every frame from a spawn it reads elsewhere, so the
|
|
719
|
+
* write lands at the literal that binding reads (the component callsite whose
|
|
720
|
+
* props the `useBox(…)`/`<RigidBody>` hook takes). It carries the two
|
|
721
|
+
* contracts above AND ONE MORE: the authored value must SURVIVE RE-SETTLE —
|
|
722
|
+
* after the world re-derives from source and the design-time settle runs, the
|
|
723
|
+
* body must have re-spawned at the AUTHORED pose, not at the old one. Being
|
|
724
|
+
* silently re-posed by the owner is this kind's whole failure mode, and the
|
|
725
|
+
* reason it is a kind rather than a flavour of `source-prop`.
|
|
726
|
+
* Proof: `packages/editor/test/r3f-physics-binding.test.ts`.
|
|
727
|
+
* - `data-record` — the value is a field of a RECORD in the game's own data
|
|
728
|
+
* file, addressed by index; no source literal mentions it. Lands in that
|
|
729
|
+
* file through the game's own declared writer; survives a cold remount for
|
|
730
|
+
* the same reason source does.
|
|
731
|
+
* Proof: `packages/editor/test/ingest-source-persistence.test.ts`
|
|
732
|
+
* ("a level-data record is an anchor too").
|
|
733
|
+
* - `live-only` — there is no anchor. The edit lands on the running object for
|
|
734
|
+
* the session and NOTHING else, and the contract is that the surface SAYS SO:
|
|
735
|
+
* a write ack that claims a destination it did not reach is the lie this kind
|
|
736
|
+
* exists to keep nameable.
|
|
737
|
+
* Proof: `packages/editor/test/oid-source-persistence.test.ts`
|
|
738
|
+
* ("an object with no source stamp is refused by name")
|
|
739
|
+
* + `packages/editor/test/inspection-write-destination.test.ts`.
|
|
740
|
+
*/
|
|
741
|
+
export type WriteAnchorKind =
|
|
742
|
+
| 'source-prop'
|
|
743
|
+
| 'construction-literal'
|
|
744
|
+
| 'physics-binding'
|
|
745
|
+
| 'data-record'
|
|
746
|
+
| 'live-only';
|
|
747
|
+
|
|
748
|
+
/**
|
|
749
|
+
* WHAT ONE EDIT DID — the ack the persistence pipe returns for THAT edit, from
|
|
750
|
+
* the component that actually performed the write.
|
|
751
|
+
*
|
|
752
|
+
* It is deliberately NOT a property of an adapter, a session or a surface. The
|
|
753
|
+
* fact it carries is per-edit, because that is the only granularity at which it
|
|
754
|
+
* can be true: one composite may hold a source-backed three root beside a
|
|
755
|
+
* live-only DOM root, and one three root holds body-placed nodes beside
|
|
756
|
+
* ordinary JSX props. An answer computed from the SURFACE rather than from the
|
|
757
|
+
* edit reports whichever child happened to be persist-capable — measured on the
|
|
758
|
+
* vendored racing game, where a three-root edit acked the other root's
|
|
759
|
+
* destination with `persisted: true`.
|
|
760
|
+
*
|
|
761
|
+
* `persisted: false` is an ANSWER, never a failure: `live-only` is a real
|
|
762
|
+
* anchor kind and the contract of that kind is that the surface SAYS SO. What
|
|
763
|
+
* is forbidden is a `destination` no byte reached being reported with
|
|
764
|
+
* `persisted: true`.
|
|
765
|
+
*
|
|
766
|
+
* A provider that performs a write returns this; one that has no write to
|
|
767
|
+
* perform returns nothing and the shell reports the live-only floor. There is
|
|
768
|
+
* no third answer, and in particular there is no adapter-wide blanket
|
|
769
|
+
* destination standing in for one — {@link PersistenceProvider.destination}
|
|
770
|
+
* answers the different question "where do this surface's SAVES go", for the
|
|
771
|
+
* save-status chrome.
|
|
772
|
+
*/
|
|
773
|
+
export interface WriteAck {
|
|
774
|
+
/** Where THIS edit's bytes landed, in the writer's own words — or the
|
|
775
|
+
* live-only/ephemeral floor when none did. */
|
|
776
|
+
readonly destination: string;
|
|
777
|
+
/** Whether a byte actually moved for THIS edit. */
|
|
778
|
+
readonly persisted: boolean;
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
/**
|
|
782
|
+
* The exhaustiveness pin, the same shape and for the same reason as
|
|
783
|
+
* {@link AUTHORING_PROVIDER_PRESENCE}: a `Record` over the union, so a lane that
|
|
784
|
+
* starts producing a new kind of anchor cannot ship without joining the
|
|
785
|
+
* vocabulary (the `Record` would be missing a key) and cannot invent a key the
|
|
786
|
+
* union does not have (excess-property error). The values are `true` and carry
|
|
787
|
+
* no meaning — the KEYS are the payload.
|
|
788
|
+
*
|
|
789
|
+
* What this buys downstream: the per-kind write-reach counts and `vgai doctor`'s
|
|
790
|
+
* edit-write walk both enumerate {@link WRITE_ANCHOR_KINDS} rather than a
|
|
791
|
+
* hand-written list, so a new kind arrives already measured and already walked
|
|
792
|
+
* instead of silently untested.
|
|
793
|
+
*/
|
|
794
|
+
const WRITE_ANCHOR_KIND_PRESENCE: Readonly<Record<WriteAnchorKind, true>> = {
|
|
795
|
+
'source-prop': true,
|
|
796
|
+
'construction-literal': true,
|
|
797
|
+
'physics-binding': true,
|
|
798
|
+
'data-record': true,
|
|
799
|
+
'live-only': true,
|
|
800
|
+
};
|
|
801
|
+
|
|
802
|
+
/**
|
|
803
|
+
* The vocabulary as an ordered list — most-addressable first, `live-only` last,
|
|
804
|
+
* so two reports of the same world are diffable line for line.
|
|
805
|
+
*
|
|
806
|
+
* Derived from {@link WRITE_ANCHOR_KIND_PRESENCE} rather than spelled a second
|
|
807
|
+
* time: one list the compiler pins to the union, and nothing downstream can
|
|
808
|
+
* enumerate a different set.
|
|
809
|
+
*/
|
|
810
|
+
export const WRITE_ANCHOR_KINDS: readonly WriteAnchorKind[] = Object.keys(
|
|
811
|
+
WRITE_ANCHOR_KIND_PRESENCE,
|
|
812
|
+
) as WriteAnchorKind[];
|
|
813
|
+
|
|
814
|
+
/** Zero counts for every kind — the starting point of any per-kind tally, so a
|
|
815
|
+
* tally can never omit a kind by forgetting to initialize it. */
|
|
816
|
+
export function emptyWriteAnchorKindCounts(): Record<WriteAnchorKind, number> {
|
|
817
|
+
const counts = {} as Record<WriteAnchorKind, number>;
|
|
818
|
+
for (const kind of WRITE_ANCHOR_KINDS) counts[kind] = 0;
|
|
819
|
+
return counts;
|
|
820
|
+
}
|
|
821
|
+
|
|
579
822
|
/**
|
|
580
823
|
* Absent ⇒ this adapter's substrate has no creation-site index at all (a
|
|
581
824
|
* document-backed world's truth is the document, not a construction site).
|
|
@@ -583,6 +826,112 @@ export type NodeCreationSite =
|
|
|
583
826
|
*/
|
|
584
827
|
export interface CreationSiteProvider {
|
|
585
828
|
anchor(id: string): NodeCreationSite;
|
|
829
|
+
/**
|
|
830
|
+
* The write-side sibling of {@link anchor}: which LANE would carry an edit to
|
|
831
|
+
* this node's transform, in the closed vocabulary above. Exposed beside the
|
|
832
|
+
* anchor because that is where every reader already looks, and because a
|
|
833
|
+
* caller sweeping a hierarchy needs it to find a representative node per kind
|
|
834
|
+
* (`vgai doctor`'s edit-write walk is that caller).
|
|
835
|
+
*
|
|
836
|
+
* Absent ⇒ this adapter plans no lanes it can distinguish; the reader has only
|
|
837
|
+
* the anchor's own shape, which cannot tell two source lanes apart.
|
|
838
|
+
* `undefined` for a particular id ⇒ this adapter plans no write for THAT id
|
|
839
|
+
* (a synthetic hierarchy row, an id no child of a composite owns) — which is
|
|
840
|
+
* not the same as `live-only`, a lane that really does land on a live object.
|
|
841
|
+
*/
|
|
842
|
+
writeAnchorKind?(id: string): WriteAnchorKind | undefined;
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
/** A plain world-space point. Component handles cross the authoring seam as
|
|
846
|
+
* data; a substrate object or renderer handle never does. */
|
|
847
|
+
export type SpatialPoint3 = readonly [x: number, y: number, z: number];
|
|
848
|
+
|
|
849
|
+
/** Non-interactive geometry an adapter asks the viewport to draw for one
|
|
850
|
+
* spatial component. The vocabulary is intentionally geometric rather than
|
|
851
|
+
* domain-shaped: audio attenuation, light range and a collider radius can all
|
|
852
|
+
* use the same sphere without teaching the shell any of those concepts. */
|
|
853
|
+
export type SpatialHandleGuide =
|
|
854
|
+
| {
|
|
855
|
+
readonly kind: 'line';
|
|
856
|
+
readonly points: readonly SpatialPoint3[];
|
|
857
|
+
readonly color: string;
|
|
858
|
+
readonly opacity?: number;
|
|
859
|
+
readonly dashed?: boolean;
|
|
860
|
+
}
|
|
861
|
+
| {
|
|
862
|
+
readonly kind: 'sphere';
|
|
863
|
+
readonly center: SpatialPoint3;
|
|
864
|
+
readonly radius: number;
|
|
865
|
+
readonly color: string;
|
|
866
|
+
readonly opacity?: number;
|
|
867
|
+
readonly dashed?: boolean;
|
|
868
|
+
}
|
|
869
|
+
| {
|
|
870
|
+
readonly kind: 'cone';
|
|
871
|
+
readonly origin: SpatialPoint3;
|
|
872
|
+
readonly direction: SpatialPoint3;
|
|
873
|
+
readonly length: number;
|
|
874
|
+
/** Full opening angle in degrees, matching Web Audio and authoring UIs. */
|
|
875
|
+
readonly angle: number;
|
|
876
|
+
readonly color: string;
|
|
877
|
+
readonly opacity?: number;
|
|
878
|
+
readonly dashed?: boolean;
|
|
879
|
+
}
|
|
880
|
+
| {
|
|
881
|
+
readonly kind: 'box';
|
|
882
|
+
readonly center: SpatialPoint3;
|
|
883
|
+
readonly rotation: readonly [x: number, y: number, z: number, w: number];
|
|
884
|
+
readonly halfExtents: SpatialPoint3;
|
|
885
|
+
readonly color: string;
|
|
886
|
+
readonly opacity?: number;
|
|
887
|
+
readonly dashed?: boolean;
|
|
888
|
+
}
|
|
889
|
+
| {
|
|
890
|
+
readonly kind: 'capsule';
|
|
891
|
+
readonly center: SpatialPoint3;
|
|
892
|
+
readonly rotation: readonly [x: number, y: number, z: number, w: number];
|
|
893
|
+
readonly radius: number;
|
|
894
|
+
readonly halfHeight: number;
|
|
895
|
+
readonly color: string;
|
|
896
|
+
readonly opacity?: number;
|
|
897
|
+
readonly dashed?: boolean;
|
|
898
|
+
};
|
|
899
|
+
|
|
900
|
+
/** One draggable point. `id` is stable only within its owning node; `label`
|
|
901
|
+
* feeds accessible/editor hints rather than becoming a persisted name. */
|
|
902
|
+
export interface SpatialDragHandle {
|
|
903
|
+
readonly id: string;
|
|
904
|
+
readonly label: string;
|
|
905
|
+
readonly position: SpatialPoint3;
|
|
906
|
+
readonly color: string;
|
|
907
|
+
readonly writable: boolean;
|
|
908
|
+
readonly reason?: string;
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
/** One adapter-owned component projection. `category` is a viewport overlay
|
|
912
|
+
* channel (for example `audio`), not a game-object kind; unknown categories
|
|
913
|
+
* obey the master Helpers toggle instead of being rejected. */
|
|
914
|
+
export interface SpatialHandleLayer {
|
|
915
|
+
readonly id: string;
|
|
916
|
+
readonly category: string;
|
|
917
|
+
readonly guides: readonly SpatialHandleGuide[];
|
|
918
|
+
readonly handles: readonly SpatialDragHandle[];
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
/**
|
|
922
|
+
* Format-neutral direct-manipulation seam for component-owned spatial values.
|
|
923
|
+
*
|
|
924
|
+
* The viewport draws only the returned geometry. During a drag it returns a
|
|
925
|
+
* world-space point to the adapter; the adapter alone knows whether that means
|
|
926
|
+
* an AudioSource distance, a light cone, a collider extent, or something else,
|
|
927
|
+
* and the adapter alone owns live preview + source persistence. `commit` runs
|
|
928
|
+
* once at gesture end, so source/HMR/history are never hammered per pointer
|
|
929
|
+
* move. Absent means this adapter has no spatial component handles.
|
|
930
|
+
*/
|
|
931
|
+
export interface SpatialHandlesProvider {
|
|
932
|
+
layers(id: string): readonly SpatialHandleLayer[];
|
|
933
|
+
preview(id: string, handleId: string, worldPosition: SpatialPoint3): void;
|
|
934
|
+
commit(id: string, handleId: string, worldPosition: SpatialPoint3): void | Promise<void>;
|
|
586
935
|
}
|
|
587
936
|
|
|
588
937
|
export interface AuthoringAdapter {
|
|
@@ -598,6 +947,8 @@ export interface AuthoringAdapter {
|
|
|
598
947
|
/** The selected node is an atomic asset that can open in the Asset Editor. */
|
|
599
948
|
readonly assetSubject?: AssetSubjectProvider;
|
|
600
949
|
readonly related?: RelatedSubjectsProvider;
|
|
950
|
+
/** Source-derived prefab/component instance overrides and native writes. */
|
|
951
|
+
readonly instances?: ComponentInstancesProvider;
|
|
601
952
|
readonly structure?: StructureProvider;
|
|
602
953
|
readonly persistence?: PersistenceProvider;
|
|
603
954
|
/** D12 — per-layer viewport picking. Absent ⇒ this adapter is not pickable. */
|
|
@@ -619,6 +970,8 @@ export interface AuthoringAdapter {
|
|
|
619
970
|
/** WO-IDX1 — the source location that constructed a node's live object.
|
|
620
971
|
* Absent ⇒ this adapter indexes no creation sites. */
|
|
621
972
|
readonly creationSite?: CreationSiteProvider;
|
|
973
|
+
/** Adapter-owned component guides and direct-manipulation points. */
|
|
974
|
+
readonly spatialHandles?: SpatialHandlesProvider;
|
|
622
975
|
/** Asset drop (hierarchy + viewport). Absent ⇒ this adapter accepts no drops. */
|
|
623
976
|
readonly assetDrop?: AssetDropProvider;
|
|
624
977
|
/** Change notification → UI refresh. */
|
|
@@ -634,3 +987,80 @@ export interface AuthoringAdapter {
|
|
|
634
987
|
*/
|
|
635
988
|
observeTransforms?(listener: (event: TransformObservation) => void): () => void;
|
|
636
989
|
}
|
|
990
|
+
|
|
991
|
+
/**
|
|
992
|
+
* THE PROVIDER VOCABULARY — every member of {@link AuthoringAdapter} beyond the
|
|
993
|
+
* two an adapter cannot exist without.
|
|
994
|
+
*
|
|
995
|
+
* Why this exists: the editor's coverage warnings are supposed to make stopping
|
|
996
|
+
* short of a native root IMPOSSIBLE, and they cannot do that while the row
|
|
997
|
+
* vocabulary is a hand-written list frozen at what its author happened to know.
|
|
998
|
+
* A list like that goes quiet at "all warnings closed" while whole capabilities
|
|
999
|
+
* — stories, asset drop, related subjects, structure — were never enumerated at
|
|
1000
|
+
* all, so nothing ever warned about them. So the vocabulary IS the type: adding
|
|
1001
|
+
* a provider to `AuthoringAdapter` and forgetting it here is a COMPILE ERROR
|
|
1002
|
+
* (the `Record` below is missing a key), and inventing a key the type does not
|
|
1003
|
+
* have is an excess-property error. There is no third way to add a provider.
|
|
1004
|
+
*
|
|
1005
|
+
* `capabilities` and `hierarchy` are excluded because they are required members
|
|
1006
|
+
* — every adapter has them by construction, so "absent" is not a state they can
|
|
1007
|
+
* be in and a row about them could never say anything.
|
|
1008
|
+
*/
|
|
1009
|
+
export type AuthoringProviderKey = Exclude<keyof AuthoringAdapter, 'capabilities' | 'hierarchy'>;
|
|
1010
|
+
|
|
1011
|
+
/**
|
|
1012
|
+
* The exhaustiveness pin. A `Record` over the key union, so the compiler — not
|
|
1013
|
+
* a scan, not a reviewer — is what refuses a vocabulary that has drifted from
|
|
1014
|
+
* the interface above. The values are `true` and carry no meaning: the KEYS are
|
|
1015
|
+
* the payload.
|
|
1016
|
+
*/
|
|
1017
|
+
const AUTHORING_PROVIDER_PRESENCE: Readonly<Record<AuthoringProviderKey, true>> = {
|
|
1018
|
+
provenance: true,
|
|
1019
|
+
selection: true,
|
|
1020
|
+
transforms: true,
|
|
1021
|
+
inspector: true,
|
|
1022
|
+
assetSubject: true,
|
|
1023
|
+
related: true,
|
|
1024
|
+
instances: true,
|
|
1025
|
+
structure: true,
|
|
1026
|
+
persistence: true,
|
|
1027
|
+
pickable: true,
|
|
1028
|
+
rects: true,
|
|
1029
|
+
boxEdit: true,
|
|
1030
|
+
text: true,
|
|
1031
|
+
colorSample: true,
|
|
1032
|
+
stories: true,
|
|
1033
|
+
creationSite: true,
|
|
1034
|
+
spatialHandles: true,
|
|
1035
|
+
assetDrop: true,
|
|
1036
|
+
subscribe: true,
|
|
1037
|
+
observeTransforms: true,
|
|
1038
|
+
};
|
|
1039
|
+
|
|
1040
|
+
/**
|
|
1041
|
+
* The vocabulary as an ordered list — declaration order of the interface, so
|
|
1042
|
+
* two reports of the same root are diffable line for line.
|
|
1043
|
+
*
|
|
1044
|
+
* Derived from {@link AUTHORING_PROVIDER_PRESENCE} rather than spelled a second
|
|
1045
|
+
* time: one list that the compiler pins to the type, and nothing downstream can
|
|
1046
|
+
* enumerate a different set.
|
|
1047
|
+
*/
|
|
1048
|
+
export const AUTHORING_PROVIDER_KEYS: readonly AuthoringProviderKey[] = Object.keys(
|
|
1049
|
+
AUTHORING_PROVIDER_PRESENCE,
|
|
1050
|
+
) as AuthoringProviderKey[];
|
|
1051
|
+
|
|
1052
|
+
/**
|
|
1053
|
+
* Which providers this adapter actually exposes — PRESENCE, measured off the
|
|
1054
|
+
* object itself. Nothing here consults `capabilities`, the adapter's class, the
|
|
1055
|
+
* route that built it, or the game's id: an adapter this function has never
|
|
1056
|
+
* heard of gets the same answer as one it has.
|
|
1057
|
+
*/
|
|
1058
|
+
export function measureAuthoringProviders(
|
|
1059
|
+
adapter: AuthoringAdapter,
|
|
1060
|
+
): Readonly<Record<AuthoringProviderKey, boolean>> {
|
|
1061
|
+
const measured = {} as Record<AuthoringProviderKey, boolean>;
|
|
1062
|
+
for (const key of AUTHORING_PROVIDER_KEYS) {
|
|
1063
|
+
measured[key] = (adapter as unknown as Record<string, unknown>)[key] !== undefined;
|
|
1064
|
+
}
|
|
1065
|
+
return measured;
|
|
1066
|
+
}
|
|
@@ -15,7 +15,7 @@ export type ConstraintStatus = 'ready' | 'disabled' | 'unresolved' | 'error';
|
|
|
15
15
|
export interface ConstraintConfig {
|
|
16
16
|
/** Stable only within this mounted owner. */
|
|
17
17
|
readonly id: string;
|
|
18
|
-
readonly type: 'two-bone-ik' | 'ccd-ik' | (string & {});
|
|
18
|
+
readonly type: 'two-bone-ik' | 'ccd-ik' | 'aim' | 'rotation' | (string & {});
|
|
19
19
|
readonly label: string;
|
|
20
20
|
readonly enabled: boolean;
|
|
21
21
|
readonly weight: number;
|
|
@@ -23,15 +23,22 @@ export interface ConstraintConfig {
|
|
|
23
23
|
readonly order: number;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
export interface ConstraintError {
|
|
27
|
+
readonly value: number;
|
|
28
|
+
readonly unit: 'metres' | 'degrees';
|
|
29
|
+
}
|
|
30
|
+
|
|
26
31
|
export interface ConstraintSnapshot {
|
|
27
32
|
readonly status: ConstraintStatus;
|
|
28
33
|
readonly message?: string;
|
|
29
34
|
/** Root → effector, using the real bones from the live skeleton. */
|
|
30
35
|
readonly chain: readonly THREE.Object3D[];
|
|
36
|
+
/** The ordinary object whose transform the constraint affects. */
|
|
37
|
+
readonly constrained: THREE.Object3D | null;
|
|
31
38
|
readonly target: THREE.Object3D | null;
|
|
32
39
|
readonly pole: THREE.Object3D | null;
|
|
33
|
-
/**
|
|
34
|
-
readonly error:
|
|
40
|
+
/** Residual after the latest solve, in the constraint's native unit. */
|
|
41
|
+
readonly error: ConstraintError | null;
|
|
35
42
|
}
|
|
36
43
|
|
|
37
44
|
export interface ConstraintMark {
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What every finder answers with.
|
|
3
|
+
*
|
|
4
|
+
* A finder is a PURE function over project source/files with explicit inputs
|
|
5
|
+
* and outputs — it never reads a filesystem, never fetches, and never consults
|
|
6
|
+
* ambient state. What it cannot answer it says so in {@link FinderResult.notes}
|
|
7
|
+
* rather than degrading silently: "has none" and "nobody could look" are
|
|
8
|
+
* different facts, and only the second is a defect.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { SceneEntry } from '../adapter-module';
|
|
12
|
+
|
|
13
|
+
export interface FinderResult {
|
|
14
|
+
/** Scene-table entries this finder produced, in discovery order. */
|
|
15
|
+
readonly entries: readonly SceneEntry[];
|
|
16
|
+
/**
|
|
17
|
+
* The entry this finder's own answer makes the default, when its answer
|
|
18
|
+
* settles it UNAMBIGUOUSLY (one candidate). A finder never picks between
|
|
19
|
+
* candidates — that is the adapter author's declaration to make, and an
|
|
20
|
+
* absent default stays the honest fact that none was declared.
|
|
21
|
+
*/
|
|
22
|
+
readonly default?: string;
|
|
23
|
+
/**
|
|
24
|
+
* Loud, non-fatal diagnostics: a selection identifier that is not in the
|
|
25
|
+
* source, an entrypoint whose bytes could not be read. Every note names the
|
|
26
|
+
* file it is about. The host surfaces these; it never swallows them.
|
|
27
|
+
*/
|
|
28
|
+
readonly notes: readonly string[];
|
|
29
|
+
}
|