@vgai/editor-sdk 0.5.41 → 0.5.44

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.
@@ -138,6 +138,15 @@ export interface ToolObject3DAuthoringProps {
138
138
  /** Explicit flat scene background. Omit it to inherit the editor's standard
139
139
  * viewport dressing (environment, gradient backdrop, key light). */
140
140
  readonly background?: ColorRepresentation;
141
+ /**
142
+ * The Asset Lab's IMPORT AUDIT on this document's inspector — the Geometry
143
+ * block (triangle counts, GPU estimate, LODs, collision, invalid values)
144
+ * and the Source row. Default on: it is what an imported model's inspector
145
+ * is for. A modeling document that carries its own data panel (the mesh
146
+ * document's Data / Modifiers sections) passes `false`, the way Blender's
147
+ * Object Data tab is the mesh's own, not an importer's report.
148
+ */
149
+ readonly audit?: boolean;
141
150
  readonly cameraDirection?: readonly [number, number, number];
142
151
  /**
143
152
  * Optional binding from live native clips back to ordinary project source.
@@ -153,6 +162,9 @@ export interface ToolObject3DAuthoringProps {
153
162
  * The project owns the format and the host never interprets its contents.
154
163
  */
155
164
  readonly persistence?: ToolObject3DDocumentPersistence;
165
+ /** Project-owned serialization of this document into ONE source module,
166
+ * written through the editor's source seam (see the binding's docs). */
167
+ readonly documentSource?: ToolDocumentSourceBinding;
156
168
  /** Replace the default native-tree projection with a semantic adapter. The
157
169
  * default adapter is provided for delegation, so a project can add terrain
158
170
  * layers, bones, or mesh elements without rebuilding Object3D projection. */
@@ -282,6 +294,27 @@ export interface ToolObject3DDocumentInteraction {
282
294
  setup(context: ToolObject3DInteractionContext): ToolObject3DInteractionExtension;
283
295
  }
284
296
 
297
+ /**
298
+ * Project-owned serialization of a WHOLE Asset Lab document into one ordinary
299
+ * source file — what {@link ToolAnimationSourceBinding} is for clips, for a
300
+ * document whose truth is a TypeScript module (a modeling session's mesh
301
+ * module). The editor owns the checksum-guarded whole-file write through the
302
+ * source seam and records it in canonical history; executable source never
303
+ * travels through {@link ToolObject3DAuthoringProps.persistence}'s resource
304
+ * route, which the server refuses by rule. A document declares either this or
305
+ * `persistence`, never both. MUST be referentially stable across renders.
306
+ */
307
+ export interface ToolDocumentSourceBinding {
308
+ /** Project-relative source file below src/. */
309
+ readonly path: string;
310
+ /** Undo/redo label shown by the editor history. */
311
+ readonly label?: string;
312
+ /** The exact bytes of the module for this document state — or `null` for
313
+ * "nothing changed, write nothing", so a gesture that ended without an
314
+ * edit leaves the file byte-for-byte alone. */
315
+ readonly serialize: (document: ToolObject3DDocumentState) => string | null;
316
+ }
317
+
285
318
  export interface ToolAnimationSourceBinding {
286
319
  /** Project-relative TypeScript file below src/. */
287
320
  readonly path: string;
@@ -443,9 +476,56 @@ export interface ToolContributionPlay {
443
476
  readonly recording: ToolContributionRecording;
444
477
  }
445
478
 
479
+ /**
480
+ * THE DOCUMENT HEADER REGION, as a project contribution sees it.
481
+ *
482
+ * A `workspace.document` module may `export const Toolbar` beside its default
483
+ * component. The editor renders it in the host-owned header strip above the
484
+ * document — the same strip the Game and Story documents use — with the SAME
485
+ * props the content receives, so a header and its body read one state. The
486
+ * host draws the strip identically for every document (height, divider,
487
+ * island treatment under the floating composition); the contribution supplies
488
+ * only what goes in it. A document that hand-draws a bar inside its own body
489
+ * instead is a document whose header no skin, preset or region rule can
490
+ * reach — which is the whole reason the strip is the host's.
491
+ */
492
+ export type ToolDocumentToolbar = import('react').ComponentType<ToolContributionProps>;
493
+
494
+ /**
495
+ * THE DOCUMENT SHELF REGION — Blender's tool shelf — as a project sees it:
496
+ * `export const Shelf` on a `workspace.document` module. The editor draws it
497
+ * as a vertical rail over the leading edge of the document's content box,
498
+ * with the same props as the body. Same contract as {@link ToolDocumentToolbar}.
499
+ */
500
+ export type ToolDocumentShelf = import('react').ComponentType<ToolContributionProps>;
501
+
502
+ /**
503
+ * A document the adapter's table lists — a model, a page — as handed to the
504
+ * editor registered for its kind (ARCHITECTURE-CORE §The project model,
505
+ * "Documents, not scenes"). A `workspace.document` contribution declares the
506
+ * kind it edits with `export const documentKind = 'model'`; the host then
507
+ * opens every table entry of that kind as its OWN document — titled by the
508
+ * entry's label, one per entry, restored across reloads by the entry's id —
509
+ * and mounts the contribution with the entry here. Nothing else is looked
510
+ * up: the entry names the module (`source`) and the contribution does the
511
+ * rest through `importProjectModule`.
512
+ */
513
+ export interface ToolDocumentEntry {
514
+ /** The table entry's id (`model:src/models/cage.ts`). */
515
+ readonly id: string;
516
+ readonly kind: string;
517
+ /** The entry's display label — the document's title (`cage`). */
518
+ readonly label: string;
519
+ /** The module that IS the document, when the entry has one. */
520
+ readonly source?: { readonly path: string; readonly export?: string };
521
+ }
522
+
446
523
  export interface ToolContributionProps {
447
524
  /** The exact registered callable this contribution presents. */
448
525
  readonly tool: ProjectToolCatalogEntry;
526
+ /** Present when mounted as the editor of a table document of the kind this
527
+ * contribution declared (`export const documentKind`). */
528
+ readonly document?: ToolDocumentEntry;
449
529
  /** Stable id of this presentation within the registered callable. */
450
530
  readonly contributionId?: string;
451
531
  /** Direct editor SDK client; invoke with `client.runProjectTool(tool.name, ...)`. */
@@ -460,6 +540,39 @@ export interface ToolContributionProps {
460
540
  readonly documentId?: string;
461
541
  /** Whether that workspace document is the active center subject. */
462
542
  readonly active?: boolean;
543
+ /**
544
+ * Present with `documentId`. Hand the host the ONE object this document
545
+ * edits through — its live session — and `editor.document.run(ctx => …)`
546
+ * (`vgai eval`) runs a step against it in Edit mode, without play: the
547
+ * agent's REPL over the document. Re-publish whenever that object changes
548
+ * (a reload that swaps a session); the return value unpublishes.
549
+ */
550
+ readonly publishContext?: (context: unknown) => () => void;
551
+ /**
552
+ * Raise a card on the editor's bottom-right notification stack — the ONE
553
+ * shape an event takes (ARCHITECTURE-CORE §Editor chrome, "Notices take
554
+ * VS Code's shape"): a refusal, a failed write, a no-op the user should
555
+ * hear about. Never paint these into a document's own chrome. Plain
556
+ * `info` hides itself; warnings and errors stay until dismissed. The
557
+ * return value dismisses the card early.
558
+ */
559
+ readonly notify?: (notice: ToolNotice) => () => void;
560
+ /**
561
+ * Tell the host what this contribution is about to do on the page's main
562
+ * thread — `work('building src/models/x.ts')` before running a module's
563
+ * `build()`, `work(null)` after. A command that times out meanwhile is
564
+ * refused naming that work instead of "the page never answered".
565
+ */
566
+ readonly work?: (label: string | null) => void;
567
+ }
568
+
569
+ /** A card for {@link ToolContributionProps.notify}. */
570
+ export interface ToolNotice {
571
+ readonly tone: 'info' | 'warning' | 'error';
572
+ /** One line, bold — what happened. */
573
+ readonly title: string;
574
+ /** The rest, plain — what it means, what to do. */
575
+ readonly detail?: string;
463
576
  }
464
577
 
465
578
  /**
@@ -518,8 +631,46 @@ export interface ToolContributionAsset {
518
631
  readonly sourcePath?: string;
519
632
  }
520
633
 
521
- export interface ToolAssetInspectorContributionProps extends ToolContributionProps {
634
+ /** An `asset.inspector`'s props the same relaxation as the two other
635
+ * PRESENTING points ({@link ToolUtilityContributionProps},
636
+ * {@link ToolInspectorContributionProps}): it presents what an ASSET is, not
637
+ * one callable's output, so `tool` may be absent — and a section that
638
+ * declares none also loads on the browser tier, whose callable catalog is
639
+ * empty by design. */
640
+ /**
641
+ * A verb an `asset.inspector` contribution offers for the asset it is
642
+ * showing — the SAME thing a built-in Inspector button is: it appears in the
643
+ * panel's identity row, `editor.inspect().quickActions` lists it, and
644
+ * `editor.runAction(id)` runs exactly this `run`. A section publishes its
645
+ * verbs with {@link ToolAssetInspectorContributionProps.setActions} when it
646
+ * knows them, which is what gives a project's own Inspector door a place in
647
+ * the control API instead of a mouse only.
648
+ */
649
+ export interface ToolAssetInspectorAction {
650
+ /** Stable id, unique within the contribution (`mesh-edit.open`). */
651
+ readonly id: string;
652
+ /** Accessible name and tooltip. */
653
+ readonly title: string;
654
+ /** Visible button text. */
655
+ readonly label?: string;
656
+ readonly disabled?: boolean;
657
+ readonly run: () => void | Promise<void>;
658
+ }
659
+
660
+ export interface ToolAssetInspectorContributionProps extends Omit<ToolContributionProps, 'tool'> {
661
+ readonly tool?: ProjectToolCatalogEntry;
522
662
  readonly asset: ToolContributionAsset | null;
663
+ /**
664
+ * Publish the verbs this section offers for the asset it is showing — see
665
+ * {@link ToolAssetInspectorAction}. Call it with the list when the answer
666
+ * is known (a section that probes asynchronously calls it from the effect
667
+ * that resolves), and with `[]` when the answer is no. The editor renders
668
+ * them in the identity row and serves them to
669
+ * `editor.inspect().quickActions` / `editor.runAction(id)`, so the panel
670
+ * and the control API always show one list. Not calling it means "no
671
+ * verbs", which is what a section that only displays should do.
672
+ */
673
+ readonly setActions: (actions: readonly ToolAssetInspectorAction[]) => void;
523
674
  }
524
675
 
525
676
  /** Optional named export required by `asset.inspector` contributions. */
@@ -574,3 +725,59 @@ export type ToolInspectorContributionMatch = (
574
725
  adapter: unknown,
575
726
  context: ToolInspectorContributionMatchContext,
576
727
  ) => boolean;
728
+
729
+ // ---------------------------------------------------------------------------
730
+ // Project modules, through the host's own door
731
+ // ---------------------------------------------------------------------------
732
+
733
+ /**
734
+ * How THIS tier loads a project module for a contribution: the dev/packaged
735
+ * host serves it through its own Vite (`/@fs/…`, with a URL a live re-import
736
+ * can stamp); the browser tier bundles it from storage and has no URL for it.
737
+ * The host registers one loader per project (`tool-loader.ts`); a
738
+ * contribution that needs a project module — a model's Edit Mesh door
739
+ * importing `build()` — asks {@link importProjectModule} and never spells a
740
+ * tier's mechanics itself.
741
+ */
742
+ export interface ProjectModuleLoader {
743
+ readonly import: (path: string) => Promise<Record<string, unknown>>;
744
+ /** The module's servable URL, or `null` on a tier that serves none. */
745
+ readonly url: (path: string) => URL | null;
746
+ /** The module's SOURCE TEXT as it is on disk (or in storage) right now —
747
+ * what a contribution that writes the module back (a model's mesh
748
+ * editor appending a line) patches. */
749
+ readonly source: (path: string) => Promise<string>;
750
+ }
751
+
752
+ let projectModuleLoader: ProjectModuleLoader | null = null;
753
+
754
+ /** Host side: install (or clear) the active project's module loader. */
755
+ export function registerProjectModuleLoader(loader: ProjectModuleLoader | null): void {
756
+ projectModuleLoader = loader;
757
+ }
758
+
759
+ /** Contribution side: a project module (`src/models/cage.ts`), loaded the
760
+ * way this tier loads project modules. Refuses by name with no host. */
761
+ export function importProjectModule(path: string): Promise<Record<string, unknown>> {
762
+ if (!projectModuleLoader) {
763
+ return Promise.reject(
764
+ new Error(`importProjectModule(${path}): no host has registered a project module loader`),
765
+ );
766
+ }
767
+ return projectModuleLoader.import(path);
768
+ }
769
+
770
+ /** The module's servable URL on this tier, or `null` (the browser tier). */
771
+ export function projectModuleUrl(path: string): URL | null {
772
+ return projectModuleLoader?.url(path) ?? null;
773
+ }
774
+
775
+ /** Contribution side: the module's current source text. Refuses by name with no host. */
776
+ export function readProjectModuleSource(path: string): Promise<string> {
777
+ if (!projectModuleLoader) {
778
+ return Promise.reject(
779
+ new Error(`readProjectModuleSource(${path}): no host has registered a project module loader`),
780
+ );
781
+ }
782
+ return projectModuleLoader.source(path);
783
+ }
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * Deliberately NOT a page-automation vocabulary: there is no navigation, no
8
8
  * waiting, no frame/window addressing and no selector rooted anywhere but the
9
- * active document's own container. Four actions, each one a gesture or a read
9
+ * active document's own container. Five actions, each one a gesture or a read
10
10
  * an agent cannot otherwise perform through the product.
11
11
  */
12
12
 
@@ -51,6 +51,35 @@ export interface DocumentClickStep {
51
51
  index?: number;
52
52
  }
53
53
 
54
+ /**
55
+ * A real pointer DRAG across one matched element: `pointerdown` at `from`,
56
+ * `steps` `pointermove`s along the way, `pointerup` at `to` — the sequence a
57
+ * mouse produces, so a canvas that begins a gesture on press and previews on
58
+ * move (an Asset Lab document's direct manipulation) sees the whole gesture.
59
+ * `from`/`to` are FRACTIONS of the element's box (`[0.5, 0.5]` is its
60
+ * center), so a caller reasons in the element's own space, not the screen's.
61
+ * A zero-length drag is a click at that fraction.
62
+ */
63
+ export interface DocumentDragStep {
64
+ action: 'drag';
65
+ selector: string;
66
+ /** Which match (default 0). */
67
+ index?: number;
68
+ from: [number, number];
69
+ to: [number, number];
70
+ /** Waypoints the pointer passes through between `from` and `to`, in
71
+ * order — what a lasso or a knife stroke needs, since a straight drag
72
+ * encloses nothing. Each leg gets `steps` moves. */
73
+ via?: [number, number][];
74
+ /** Intermediate `pointermove`s between consecutive points (default 8). */
75
+ steps?: number;
76
+ /** Modifier keys held for the whole gesture (a Shift-extend, an Alt-click). */
77
+ altKey?: boolean;
78
+ ctrlKey?: boolean;
79
+ metaKey?: boolean;
80
+ shiftKey?: boolean;
81
+ }
82
+
54
83
  /** A real key on the explicit target, else whatever inside the document has focus. */
55
84
  export interface DocumentKeyStep {
56
85
  action: 'key';
@@ -73,8 +102,32 @@ export interface DocumentPasteStep {
73
102
  index?: number;
74
103
  }
75
104
 
105
+ /**
106
+ * Choose a value on a `<select>` — the gesture `click` cannot make.
107
+ *
108
+ * A native dropdown's option list is rendered by the OS, not by the DOM, so
109
+ * there is nothing inside the document's container for a pointer gesture to
110
+ * resolve against: `click` on the `<select>` opens a menu no synthetic event
111
+ * can reach. Assigning `element.value` is equally useless on a React
112
+ * controlled component — React caches the last value it wrote on the node, so
113
+ * a direct write is not seen as a change and the next render puts the old
114
+ * value straight back. The implementation goes through the prototype's own
115
+ * value setter and then dispatches `input`/`change`, which is the ONE spelling
116
+ * React's synthetic-event layer honours.
117
+ */
118
+ export interface DocumentSelectStep {
119
+ action: 'select';
120
+ selector: string;
121
+ /** The option's `value` (not its label). */
122
+ value: string;
123
+ /** Which match (default 0). */
124
+ index?: number;
125
+ }
126
+
76
127
  export type DocumentProbeStep =
77
128
  | DocumentQueryStep
78
129
  | DocumentClickStep
130
+ | DocumentDragStep
79
131
  | DocumentKeyStep
80
- | DocumentPasteStep;
132
+ | DocumentPasteStep
133
+ | DocumentSelectStep;
@@ -136,6 +136,7 @@ function parseDocument(params: URLSearchParams): EditorView['document'] {
136
136
  if (!value) return undefined;
137
137
  if (kind === 'scene') return { kind, path: value };
138
138
  if (kind === 'tool') return { kind, id: value };
139
+ if (kind === 'document') return { kind, id: value };
139
140
  if (kind === 'world') return { kind, id: value };
140
141
  if (kind === 'project-tool') return { kind, name: value };
141
142
  if (kind === 'generation') return { kind, id: value };
package/src/index.ts CHANGED
@@ -28,25 +28,33 @@ export type {
28
28
  DocumentProbeResult,
29
29
  DocumentProbeStep,
30
30
  DocumentQueryStep,
31
+ DocumentSelectStep,
31
32
  ProbedElement,
32
33
  } from './document-probe.js';
33
34
  export { editorViewFromUrl, editorViewUrl } from './editor-view.js';
34
35
  export type { ExtensionContributionState } from './extension.js';
35
36
  export type {
36
37
  ActiveDocumentCapture,
38
+ EditorChromeCapture,
37
39
  AnimationCaptureAction,
38
40
  AssetCompareCapture,
39
41
  AssetCompareOptions,
40
42
  AssetCompareView,
41
43
  AssetKind,
42
44
  AssetPreviewBackground,
45
+ AssetPreviewCameraChoice,
43
46
  AssetPreviewCapture,
44
47
  AssetPreviewOptions,
48
+ AssetPreviewOrientation,
49
+ AssetPreviewPose,
45
50
  AssetPreviewShotSetDefinition,
46
51
  AssetPreviewShotWarning,
47
52
  AssetPreviewSource,
48
53
  AssetPreviewStage,
49
54
  AssetPreviewView,
55
+ CaptureDimensions,
56
+ DocumentCameraPose,
57
+ DocumentLookOutcome,
50
58
  EditorCameraState,
51
59
  EditorEntitySummary,
52
60
  EditorState,
@@ -54,10 +62,12 @@ export type {
54
62
  EditorViewBuiltInUtilityId,
55
63
  EditorViewDocument,
56
64
  EditorViewUtility,
65
+ EditorWorkspaceName,
57
66
  GameCapture,
58
67
  GameplayRecordingCapture,
59
68
  GameplayRecordingOptions,
60
69
  GameplayRecordingStarted,
70
+ GameplayRecordingTimeline,
61
71
  HelperVisibility,
62
72
  InspectedAction,
63
73
  InspectedField,
@@ -73,6 +83,7 @@ export type {
73
83
  InspectionPresentationKind,
74
84
  InspectionSurface,
75
85
  LabeledShotSetCapture,
86
+ PlayRecordingStatus,
76
87
  PlayStarted,
77
88
  PresentedEditorView,
78
89
  ProjectInfo,
@@ -87,10 +98,14 @@ export type {
87
98
  ShotSetPoseMorph,
88
99
  ShotSetPoseRotation,
89
100
  ShotSetPoseStep,
101
+ ShotSetPoseTranslation,
90
102
  ShotSetShot,
91
103
  StoryCaptureOptions,
92
104
  StoryVariantCapture,
93
105
  StoryVariantImage,
106
+ StructureOp,
107
+ StructureOpOptions,
108
+ StructureOpResult,
94
109
  TransformMode,
95
110
  TransformSpace,
96
111
  Vec3Value,