@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.
package/src/types.ts CHANGED
@@ -11,6 +11,16 @@ export type ViewportTab = 'edit' | 'play';
11
11
 
12
12
  export type AssetKind = 'model' | 'image' | 'audio' | 'animation' | 'json' | 'prefab' | 'source';
13
13
 
14
+ /**
15
+ * The editor's NAMED WORKSPACES — task-named layout memories over the one
16
+ * physical dock (ARCHITECTURE-CORE §Editor chrome). Named for the TASK, each
17
+ * borrowing the arrangement of the tool that does it best; `game` is the
18
+ * default and is the editor's standing arrangement. Restated here (rather than
19
+ * imported from the editor) for the same reason every other id union in this
20
+ * file is: the SDK is a wire client and must not depend on the editor bundle.
21
+ */
22
+ export type EditorWorkspaceName = 'game' | 'model' | 'sculpt' | 'texture' | 'animate' | 'look';
23
+
14
24
  export interface HelperVisibility {
15
25
  bounds: boolean;
16
26
  lights: boolean;
@@ -50,6 +60,30 @@ export interface ViewportCapture {
50
60
  mimeType: 'image/png';
51
61
  }
52
62
 
63
+ /**
64
+ * How an animated look move on the open Object3D document ended. Never an
65
+ * error: the camera is SHARED with the person watching, so "they grabbed it
66
+ * mid-orbit" is an outcome to read, not a failure to handle.
67
+ */
68
+ export interface DocumentLookOutcome {
69
+ /** True only when the whole move was drawn. */
70
+ completed: boolean;
71
+ /** Why it stopped early: a human drag, a later look verb, or a closed document. */
72
+ cancelledBy?: 'human' | 'superseded' | 'closed';
73
+ /** Where the camera ended up, radians around the framed subject. */
74
+ azimuth: number;
75
+ /** Radians above the subject's horizon. */
76
+ elevation: number;
77
+ /** Seconds of the move that were actually drawn. */
78
+ seconds: number;
79
+ }
80
+
81
+ /** Where the open document's camera is standing and what it is aimed at. */
82
+ export interface DocumentCameraPose {
83
+ position: [number, number, number];
84
+ target: [number, number, number];
85
+ }
86
+
53
87
  /** Result of the editor's native Asset Lab ragdoll-generation operation. */
54
88
  export interface RagdollGenerationResult {
55
89
  capability: 'added' | 'present';
@@ -98,6 +132,15 @@ export interface GameCapture {
98
132
  /** True when the host loop was starved and the runtime rendered one
99
133
  * deterministic tick to produce this frame. */
100
134
  loopRecoveryFrame?: boolean;
135
+ /** Present when this frame came out of a RECORDED run (every `vgai play`
136
+ * records). The still is delivered either way; `notice` is the sentence
137
+ * naming the clip, its offset-0 wall clock, and what a still cannot answer —
138
+ * shown verbatim, never re-derived by the caller. */
139
+ recording?: {
140
+ path: string;
141
+ startedAt: string;
142
+ notice: string;
143
+ };
101
144
  }
102
145
 
103
146
  /** Options for recording the clean running-game composite. */
@@ -141,11 +184,30 @@ export interface GameplayRecordingCapture extends GameplayRecordingStarted {
141
184
  hidden: boolean;
142
185
  }
143
186
 
187
+ /** A position on the active recorder's authoritative monotonic timeline.
188
+ * `startedAt` identifies the recording; `elapsedMs` shares the exact origin
189
+ * used to calculate the finalized capture's `durationMs`. */
190
+ export interface GameplayRecordingTimeline {
191
+ startedAt: string;
192
+ elapsedMs: number;
193
+ }
194
+
195
+ /** What Play can report while its recording is still open. Geometry, layers, media cadence, and
196
+ * final health are deliberately absent: those facts are only authoritative after Stop finalizes
197
+ * the capture. */
198
+ export interface PlayRecordingStatus {
199
+ path: string;
200
+ startedAt: string;
201
+ rotates: boolean;
202
+ logFile: string | null;
203
+ idleAutoStopMs: number;
204
+ }
205
+
144
206
  /** What `play` reports back once the run is up and recording. */
145
207
  export interface PlayStarted {
146
208
  /** Absent only when the recorder could not start; play is up either way and
147
209
  * the editor console carries the reason. */
148
- recording?: GameplayRecordingStarted;
210
+ recording?: PlayRecordingStatus;
149
211
  }
150
212
 
151
213
  export type AssetPreviewView = 'front' | 'right' | 'top' | 'perspective';
@@ -185,16 +247,61 @@ export type AssetPreviewSource =
185
247
  */
186
248
  export type AssetPreviewStage = 'lab' | 'scene';
187
249
 
250
+ /**
251
+ * A free capture camera for the Asset Lab legs (`vgai screenshot`'s
252
+ * `--azimuth/--elevation/--distance`): ONE view from a chosen angle instead
253
+ * of the fixed four. Angles are relative to the subject's AUTHORED front —
254
+ * azimuth 0 photographs the declared front, 90 walks toward the side the
255
+ * turntable's yaw-90 shot shows; elevation raises the camera (degrees above
256
+ * level); `distance` is meters from the framing center, auto-fit when
257
+ * omitted.
258
+ */
259
+ export interface AssetPreviewCameraChoice {
260
+ azimuthDegrees: number;
261
+ elevationDegrees: number;
262
+ distance?: number;
263
+ }
264
+
265
+ /**
266
+ * Pose an animated subject before capturing (`vgai screenshot`'s
267
+ * `--clip <name> --time <t>`): the named clip is sampled at `timeSeconds`
268
+ * on the capture's disposable snapshot — the source is never mutated. The
269
+ * capture fails loudly (naming the clips that DO exist) when the subject
270
+ * carries no clip by this name.
271
+ */
272
+ export interface AssetPreviewPose {
273
+ clip: string;
274
+ timeSeconds: number;
275
+ }
276
+
188
277
  export interface AssetPreviewOptions {
189
278
  width?: number;
190
279
  height?: number;
191
280
  background?: AssetPreviewBackground;
192
281
  stage?: AssetPreviewStage;
282
+ camera?: AssetPreviewCameraChoice;
283
+ pose?: AssetPreviewPose;
284
+ }
285
+
286
+ /**
287
+ * How the captured subject was oriented relative to its AUTHORED coordinates.
288
+ * The editor yaw-normalizes a subject so the front camera photographs its
289
+ * declared front; a 180-degree yaw maps authored +X to screen-LEFT in the
290
+ * front view. The yaw is reported here (and stamped onto the images' own
291
+ * pixels as `+X>` / `<+X` markers) so it is never applied silently.
292
+ */
293
+ export interface AssetPreviewOrientation {
294
+ /** The subject's declared forward, `[0,0,1]` when it declares none. */
295
+ forward: [number, number, number];
296
+ /** Yaw applied to face the front camera; 0 means authored axes = world axes. */
297
+ yawDegrees: number;
193
298
  }
194
299
 
195
300
  export interface AssetPreviewCapture {
196
301
  width: number;
197
302
  height: number;
303
+ /** Absent from editors that predate orientation reporting. */
304
+ orientation?: AssetPreviewOrientation;
198
305
  views: Array<ViewportCapture & { view: AssetPreviewView }>;
199
306
  contactSheet: ViewportCapture & { width: number; height: number };
200
307
  }
@@ -212,6 +319,13 @@ export interface StoryCaptureOptions {
212
319
  * because a UI story is not the Asset Lab's square 3D view. */
213
320
  width?: number;
214
321
  height?: number;
322
+ /** Free capture camera for THREE stories (same contract as the Asset Lab's
323
+ * {@link AssetPreviewCameraChoice}). A selected story that renders on the
324
+ * DOM leg refuses these BY NAME rather than silently ignoring them. */
325
+ camera?: AssetPreviewCameraChoice;
326
+ /** Clip pose for THREE stories (same contract as the Asset Lab's
327
+ * {@link AssetPreviewPose}); DOM-leg stories refuse it by name. */
328
+ pose?: AssetPreviewPose;
215
329
  }
216
330
 
217
331
  export interface StoryVariantImage extends ViewportCapture {
@@ -313,11 +427,27 @@ export interface ShotSetPoseMorph {
313
427
  influence: number;
314
428
  }
315
429
 
316
- /** One step of a named pose. A flat union rather than two parallel lists: a
430
+ /** The TRANSLATION channel of a pose: a joint displaced along its own local
431
+ * axis. Rotations alone cannot state a gait's vertical truth — a crouch, a
432
+ * jump apex, the hip dip that makes a walk read as weighted — because those
433
+ * are the root/hips MOVING, not a joint bending (round-4 finding: shot sets
434
+ * could not photograph a gait). Same delta semantics as the rotation: the
435
+ * capture engine applies `bone.translateX/Y/Z(meters)`, composing onto
436
+ * whatever local position the GLB baked. */
437
+ export interface ShotSetPoseTranslation {
438
+ bone: string;
439
+ axis: 'x' | 'y' | 'z';
440
+ /** A DELTA along the bone's own local axis, in meters, relative to the
441
+ * loaded GLB's baked rest position. */
442
+ meters: number;
443
+ }
444
+
445
+ /** One step of a named pose. A flat union rather than parallel lists: a
317
446
  * single expression is normally one rotation AND one morph (a jaw ROTATION
318
447
  * plus a brow MORPH), so keeping them in one ordered list means a definition
319
- * never has to zip them. */
320
- export type ShotSetPoseStep = ShotSetPoseRotation | ShotSetPoseMorph;
448
+ * never has to zip them. Discriminated by field name: `radians` is a
449
+ * rotation, `meters` a translation, `influence` a morph. */
450
+ export type ShotSetPoseStep = ShotSetPoseRotation | ShotSetPoseMorph | ShotSetPoseTranslation;
321
451
 
322
452
  export type ShotSetShot =
323
453
  | { label: string; view: 'turntable'; yaw: number; pose?: string | undefined }
@@ -717,7 +847,14 @@ export interface EditorState {
717
847
  }
718
848
 
719
849
  export type ViewPreset = 'top' | 'front' | 'right' | 'perspective';
720
- export type ShadingMode = 'solid' | 'clay' | 'unlit' | 'wireframe' | 'normals' | 'overdraw';
850
+ export type ShadingMode =
851
+ | 'solid'
852
+ | 'clay'
853
+ | 'unlit'
854
+ | 'wireframe'
855
+ | 'matcap'
856
+ | 'normals'
857
+ | 'overdraw';
721
858
 
722
859
  /** One operation on the active native animation document's recorder. */
723
860
  export type AnimationCaptureAction = 'start' | 'stop' | 'review' | 'commit' | 'discard';
@@ -822,6 +959,9 @@ export type EditorViewDocument =
822
959
  | { kind: 'asset'; path: string; entityId?: never; assetKind?: AssetKind }
823
960
  | { kind: 'asset'; entityId: string; path?: never; assetKind?: 'model' }
824
961
  | { kind: 'tool'; id: string }
962
+ /** A document the adapter's table lists (a model, a page) — `id` is the
963
+ * table entry's id — opened in the editor registered for its kind. */
964
+ | { kind: 'document'; id: string }
825
965
  | { kind: 'world'; id: string }
826
966
  | { kind: 'story'; modulePath: string; storyName: string; mode?: 'preview' | 'docs' }
827
967
  | { kind: 'project-tool'; name: string }
@@ -829,6 +969,15 @@ export type EditorViewDocument =
829
969
  | {
830
970
  kind: 'workspace';
831
971
  id: EditorViewWorkspaceDocumentId;
972
+ /**
973
+ * For a COMPONENT BOARD document: the portable story frame to open on
974
+ * — a story id, or a unique CSF export name or label (an ambiguous or
975
+ * unknown value refuses loudly, listing candidates). Emitted back by
976
+ * the board's own presentation so a captured view round-trips. This is
977
+ * the design ledger's "board story selector": without it only the
978
+ * derived default story could ever be addressed.
979
+ */
980
+ story?: string;
832
981
  };
833
982
 
834
983
  export interface EditorView {
@@ -852,9 +1001,36 @@ export interface PresentedEditorView {
852
1001
  warnings: string[];
853
1002
  }
854
1003
 
1004
+ /**
1005
+ * How big a capture comes back.
1006
+ *
1007
+ * A NUMBER is a square of that size, and square stays the default — an
1008
+ * unstaged look at a model is a square question. `{width, height}` is for the
1009
+ * shaped answer: a video-aspect frame that needs no crop afterwards, which is
1010
+ * what the model/module lanes' looks are actually for.
1011
+ *
1012
+ * Both are bounded by the EDITOR's own ceiling — 64..1024 per side, plus a
1013
+ * total no larger than a 1024 square. That is the relay budget, not a taste:
1014
+ * the pixels cross the editor relay as base64 JSON, and 1024 is where even
1015
+ * incompressible RGBA still fits its 50 MB request limit (`asset-preview.ts`'s
1016
+ * `MIN_SIZE`/`MAX_SIZE`). For more picture, take more views, not bigger ones.
1017
+ */
1018
+ export type CaptureDimensions = number | { readonly width: number; readonly height: number };
1019
+
855
1020
  /** The pixels of the active center document, with enough provenance for an
856
1021
  * agent to prove which user-visible subject it captured. Editor chrome is
857
1022
  * deliberately excluded. */
1023
+ /** A photograph of the editor PAGE — every panel as the person sees it
1024
+ * (`capture-editor-chrome`; the door that lets a skin, a workspace or a
1025
+ * contributed panel be judged sighted through the product). */
1026
+ export interface EditorChromeCapture extends ViewportCapture {
1027
+ view: EditorView;
1028
+ /** The page's on-screen size in CSS pixels — the frame's own size. */
1029
+ size: { width: number; height: number };
1030
+ layers: { canvases: number; domOverlays: number };
1031
+ flatness?: { degenerate: boolean; warning?: string };
1032
+ }
1033
+
858
1034
  export interface ActiveDocumentCapture extends ViewportCapture {
859
1035
  document: {
860
1036
  id: string;
@@ -921,8 +1097,9 @@ export type {
921
1097
  export type InspectionSurface = 'three' | 'canvas' | 'dom' | 'asset-lab';
922
1098
 
923
1099
  /** Which LAYOUT the one inspector box is in: the compact box over the
924
- * viewport, or the same sections stacked in the dock column. */
925
- export type InspectionPresentationKind = 'card' | 'column';
1100
+ * viewport, the same sections stacked in the dock column, or that column
1101
+ * with the sections tabbed behind a vertical rail (`properties`). */
1102
+ export type InspectionPresentationKind = 'card' | 'column' | 'properties';
926
1103
 
927
1104
  /** One inspected field: a stable scriptable `path` and the value at it. */
928
1105
  export interface InspectedField {
@@ -946,10 +1123,15 @@ export interface InspectedField {
946
1123
 
947
1124
  /** A section's content. Custom RENDERING remains opaque — the wire never
948
1125
  * introspects React — while any ordinary descriptor channel that chrome owns
949
- * remains visible as `fields`, including its write-refusal reasons. The two
950
- * opaque kinds are distinguished because "this subject has a live preview"
951
- * is a real fact about it: `custom` is a contributed block, `preview` is the
952
- * subject's own square view of itself.
1126
+ * IS a `fields` body here, including its write-refusal reasons: nothing is
1127
+ * rendered on this wire, so naming chrome a reader cannot see while hiding
1128
+ * the fields it can use is the wrong half. (Measured: the whole react/DOM
1129
+ * lane draws its own widgets over the style descriptors, so every one of its
1130
+ * sections reported `custom` and `inspect()` enumerated zero fields for a DOM
1131
+ * element.) The two opaque kinds are distinguished because "this subject has
1132
+ * a live preview" is a real fact about it: `custom` is a contributed block
1133
+ * with no descriptor channel of its own, `preview` is the subject's own
1134
+ * square view of itself.
953
1135
  *
954
1136
  * A custom body carries `data` when it can say what it DISPLAYS — the keys
955
1137
  * are the section's own vocabulary, not a shared schema. The shipped case is
@@ -963,7 +1145,6 @@ export type InspectedSectionBody =
963
1145
  id: string;
964
1146
  title: string;
965
1147
  data?: Record<string, unknown>;
966
- fields?: readonly InspectedField[];
967
1148
  }
968
1149
  | { kind: 'preview'; id: string; title: string };
969
1150
 
@@ -1057,6 +1238,54 @@ export interface InspectedFieldWrite {
1057
1238
  write: InspectedWriteDestination;
1058
1239
  }
1059
1240
 
1241
+ /**
1242
+ * The STRUCTURE verbs — the hierarchy context menu's own ops, addressable.
1243
+ *
1244
+ * The names are the menu's, not the provider's, because the menu is the
1245
+ * surface a human uses and an agent is doing the same thing through a
1246
+ * different door (`delete` covers the provider's `remove`/`removeMany`: a
1247
+ * multi-id delete is ONE undoable op when the adapter can batch it).
1248
+ */
1249
+ export type StructureOp =
1250
+ | 'create'
1251
+ | 'delete'
1252
+ | 'duplicate'
1253
+ | 'reparent'
1254
+ | 'reorder'
1255
+ | 'wrap'
1256
+ | 'unwrap'
1257
+ | 'group'
1258
+ | 'ungroup'
1259
+ | 'copy'
1260
+ | 'cut'
1261
+ | 'paste';
1262
+
1263
+ /** Arguments for one {@link StructureOp}. Everything is optional: `id`/`ids`
1264
+ * default to the current selection, the menu's own subject. */
1265
+ export interface StructureOpOptions {
1266
+ id?: string;
1267
+ ids?: readonly string[];
1268
+ /** `create`: which creatable kind (see the adapter's `creatableKinds`). */
1269
+ kind?: string;
1270
+ /** `create`/`reparent`/`paste`: the destination; `null`/absent = document root. */
1271
+ parentId?: string;
1272
+ /** `reorder`: move immediately before this sibling; absent = to the end. */
1273
+ beforeSiblingId?: string;
1274
+ /** `wrap`: the wrapper tag; absent = the adapter's own default. */
1275
+ tag?: string;
1276
+ }
1277
+
1278
+ /** What one structure op answers. `write` is the same per-edit ack
1279
+ * `editor.setField()` carries — `persisted: false` means the tree moved and
1280
+ * no byte did. `id`/`ids` name what the op produced, when it produces one. */
1281
+ export interface StructureOpResult {
1282
+ id?: string | null;
1283
+ ids?: readonly string[];
1284
+ write?: InspectedWriteDestination;
1285
+ /** `copy` only: whether the clipboard actually took the payload. */
1286
+ copied?: boolean;
1287
+ }
1288
+
1060
1289
  // ---------------------------------------------------------------- hierarchy
1061
1290
  //
1062
1291
  // The wire mirror of the editor's own `SerializedHierarchyPanel`