@vgai/editor-sdk 0.5.10 → 0.5.12
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/README.md +4 -3
- package/package.json +4 -2
- package/src/client.ts +88 -0
- package/src/contributions.ts +137 -0
- package/src/document-probe.ts +80 -0
- package/src/editor-view.ts +8 -5
- package/src/extension.ts +6 -5
- package/src/index.ts +13 -2
- package/src/types.ts +66 -7
package/README.md
CHANGED
|
@@ -42,8 +42,9 @@ One export, `EditorClient`, plus its types (`EditorState`, `ProjectInfo`,
|
|
|
42
42
|
- Panels: `showViewport('scene'|'game')`, `showInspector`, `openAsset`,
|
|
43
43
|
`closeAsset`, `toggleConsole`, `toggleCommandPalette`, `showBuild`, and
|
|
44
44
|
`present(EditorView)` for an atomic human-visible view plus share URL
|
|
45
|
-
- Display: `setGrid`, `setHelpers`, `setStats`, `setShadingMode` (`solid
|
|
46
|
-
|
|
45
|
+
- Display: `setGrid`, `setHelpers`, `setStats`, `setShadingMode` (`solid` for
|
|
46
|
+
authored materials, `clay` for neutral flat shading, `unlit`, `wireframe`,
|
|
47
|
+
`normals`, or `overdraw`), `setHelperType` (including
|
|
47
48
|
the independent `bounds` category). Shading targets the active Scene/Game
|
|
48
49
|
viewport and remains render-only, session-local state.
|
|
49
50
|
- Transform tools: `setTransformMode`, `setTransformSpace`, `setSnap`
|
|
@@ -99,7 +100,7 @@ utilities. Badges are for short statuses and counts, not headings.
|
|
|
99
100
|
### Extension contract (`@vgai/editor-sdk/extension`)
|
|
100
101
|
|
|
101
102
|
The typed contract for everything a game project contributes TO the editor —
|
|
102
|
-
three surfaces, one
|
|
103
|
+
three surfaces, one outcome vocabulary (`ExtensionContributionState`:
|
|
103
104
|
`active` / `absent` / `failed`). An absent contribution hides its surface
|
|
104
105
|
(the editor never fabricates placeholder data); a failing one is contained
|
|
105
106
|
per-contribution and reported loudly on the editor console — never a crashed
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@vgai/editor-sdk",
|
|
3
3
|
"author": "Volter AI, Inc.",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
|
-
"version": "0.5.
|
|
5
|
+
"version": "0.5.12",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
@@ -18,13 +18,15 @@
|
|
|
18
18
|
"exports": {
|
|
19
19
|
".": "./src/index.ts",
|
|
20
20
|
"./contributions": "./src/contributions.ts",
|
|
21
|
+
"./document-probe": "./src/document-probe.ts",
|
|
21
22
|
"./extension": "./src/extension.ts"
|
|
22
23
|
},
|
|
23
24
|
"dependencies": {
|
|
24
25
|
"@types/three": "^0.180.0",
|
|
25
|
-
"@vgai/sdk": "0.5.
|
|
26
|
+
"@vgai/sdk": "0.5.12"
|
|
26
27
|
},
|
|
27
28
|
"peerDependencies": {
|
|
29
|
+
"@vgai/engine": "*",
|
|
28
30
|
"react": "^19.0.0",
|
|
29
31
|
"three": "^0.180.0"
|
|
30
32
|
}
|
package/src/client.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { GenerationJobsDocument } from '@vgai/sdk/generations';
|
|
2
|
+
import type { DocumentProbeResult, DocumentProbeStep } from './document-probe.js';
|
|
2
3
|
import type {
|
|
3
4
|
ActiveDocumentCapture,
|
|
4
5
|
AssetCompareCapture,
|
|
@@ -12,6 +13,7 @@ import type {
|
|
|
12
13
|
EditorView,
|
|
13
14
|
GameCapture,
|
|
14
15
|
HelperVisibility,
|
|
16
|
+
InspectedHierarchy,
|
|
15
17
|
InspectedInspection,
|
|
16
18
|
LabeledShotSetCapture,
|
|
17
19
|
PresentedEditorView,
|
|
@@ -113,6 +115,16 @@ const COMMAND_DEADLINE_MS = 150_000;
|
|
|
113
115
|
* `code: 'DEBUG_COMMAND_NOT_REGISTERED'`. A panel decides what to show for
|
|
114
116
|
* those; the client never invents one.
|
|
115
117
|
*/
|
|
118
|
+
/** What one undo/redo step reports back — `moved` is false when there was
|
|
119
|
+
* nothing left in that direction, which is an answer, not an error. */
|
|
120
|
+
export interface HistoryStep {
|
|
121
|
+
readonly moved: boolean;
|
|
122
|
+
readonly canUndo: boolean;
|
|
123
|
+
readonly canRedo: boolean;
|
|
124
|
+
readonly undoLabel: string | null;
|
|
125
|
+
readonly redoLabel: string | null;
|
|
126
|
+
}
|
|
127
|
+
|
|
116
128
|
export interface GameDebugDoor {
|
|
117
129
|
/**
|
|
118
130
|
* Read ONE registered state provider by name (`'bot.tester'`). `undefined`
|
|
@@ -533,6 +545,55 @@ export class EditorClient {
|
|
|
533
545
|
return data.subject;
|
|
534
546
|
}
|
|
535
547
|
|
|
548
|
+
/**
|
|
549
|
+
* The HIERARCHY PANEL's actual rendered row tree, as data.
|
|
550
|
+
*
|
|
551
|
+
* The same rows a human is looking at: the adapter's tree after the component
|
|
552
|
+
* marks fold implementation subtrees, after the internals reveal, after the
|
|
553
|
+
* document promotion, the child cap, the collapse state, the search filter
|
|
554
|
+
* and the selection scope. Works in play mode and edit mode alike — the
|
|
555
|
+
* answer reports which (`playState`, `activeViewportTab`), because a
|
|
556
|
+
* play-mode tree and an edit-mode tree come from different adapters.
|
|
557
|
+
*
|
|
558
|
+
* Deliberately NOT `status().entities`, which walks the raw adapter tree and
|
|
559
|
+
* therefore answers a different question: a panel defect is invisible in it.
|
|
560
|
+
*
|
|
561
|
+
* Each row carries `childCount` (what its caret opens), `internalChildCount`
|
|
562
|
+
* (what is folded behind "Reveal Internals") and `expandable` (whether the
|
|
563
|
+
* panel draws a caret at all) — so "this subtree exists but the UI offers no
|
|
564
|
+
* way to open it" is a readable fact rather than something only a human
|
|
565
|
+
* squinting at the panel can notice.
|
|
566
|
+
*
|
|
567
|
+
* Rejects, naming the panel, when no hierarchy panel is mounted: an empty
|
|
568
|
+
* tree would be a fabricated answer about a surface nobody is being shown.
|
|
569
|
+
*/
|
|
570
|
+
async hierarchy(): Promise<InspectedHierarchy> {
|
|
571
|
+
const data = await this.command<{ hierarchy: InspectedHierarchy }>({ type: 'hierarchy' });
|
|
572
|
+
return data.hierarchy;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
/** Write one editable path through the active Inspector's own IO. */
|
|
576
|
+
async setInspectionField(path: string, value: unknown): Promise<InspectedInspection> {
|
|
577
|
+
const data = await this.command<{ subject: InspectedInspection }>({
|
|
578
|
+
type: 'set-inspection-field',
|
|
579
|
+
path,
|
|
580
|
+
value,
|
|
581
|
+
});
|
|
582
|
+
return data.subject;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
/**
|
|
586
|
+
* Undo / redo one project transaction — the same queue the keyboard shortcut
|
|
587
|
+
* drives. `moved` is false when there was nothing left in that direction.
|
|
588
|
+
*/
|
|
589
|
+
async undo(): Promise<HistoryStep> {
|
|
590
|
+
return this.command<HistoryStep>({ type: 'undo' });
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
async redo(): Promise<HistoryStep> {
|
|
594
|
+
return this.command<HistoryStep>({ type: 'redo' });
|
|
595
|
+
}
|
|
596
|
+
|
|
536
597
|
/** Read the editor's actual current durable projection. */
|
|
537
598
|
async currentView(): Promise<EditorView> {
|
|
538
599
|
const data = await this.command<{ view: EditorView }>({ type: 'current-view' });
|
|
@@ -547,8 +608,35 @@ export class EditorClient {
|
|
|
547
608
|
});
|
|
548
609
|
}
|
|
549
610
|
|
|
611
|
+
/**
|
|
612
|
+
* Read or drive the ACTIVE center document's own DOM — the scoped
|
|
613
|
+
* editor-chrome door, and the read/gesture half of the same subject
|
|
614
|
+
* {@link captureActiveDocument} photographs. NOT play-mode gated, and NOT
|
|
615
|
+
* page automation: a target outside the active document's container is
|
|
616
|
+
* refused by name. Design and scope contract:
|
|
617
|
+
* `packages/editor/src/editor-document-probe.ts`.
|
|
618
|
+
*/
|
|
619
|
+
async documentProbe(step: DocumentProbeStep): Promise<DocumentProbeResult> {
|
|
620
|
+
return this.command<DocumentProbeResult>({ type: 'document-probe', step });
|
|
621
|
+
}
|
|
622
|
+
|
|
550
623
|
// --- Display (set semantics) ---
|
|
551
624
|
|
|
625
|
+
/**
|
|
626
|
+
* The Game document's "Persist to game source" consent, over the relay —
|
|
627
|
+
* the same session-scoped switch the checkbox flips, refused for the same
|
|
628
|
+
* reasons (it answers with the server's own words when the base cannot be
|
|
629
|
+
* written). `recorder` names who accounts for the diff a write produces.
|
|
630
|
+
*/
|
|
631
|
+
async setSourcePersistConsent(
|
|
632
|
+
enabled: boolean,
|
|
633
|
+
): Promise<{ enabled: boolean; recorder: string | null }> {
|
|
634
|
+
return this.command<{ enabled: boolean; recorder: string | null }>({
|
|
635
|
+
type: 'set-source-persist-consent',
|
|
636
|
+
enabled,
|
|
637
|
+
});
|
|
638
|
+
}
|
|
639
|
+
|
|
552
640
|
async setGrid(enabled: boolean): Promise<void> {
|
|
553
641
|
await this.command({ type: 'set-grid', enabled });
|
|
554
642
|
}
|
package/src/contributions.ts
CHANGED
|
@@ -4,13 +4,17 @@
|
|
|
4
4
|
* metadata names a module and the editor renders its default export.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import type { AuthoringAdapter } from '@vgai/engine/adapter';
|
|
7
8
|
import type { GenerationAccountProjection } from '@vgai/sdk/account';
|
|
8
9
|
import type { GenerationJob } from '@vgai/sdk/generations';
|
|
9
10
|
import type {
|
|
10
11
|
AnimationClip,
|
|
11
12
|
Camera,
|
|
12
13
|
ColorRepresentation,
|
|
14
|
+
Group,
|
|
15
|
+
Intersection,
|
|
13
16
|
Object3D,
|
|
17
|
+
Ray,
|
|
14
18
|
Scene,
|
|
15
19
|
WebGLRenderer,
|
|
16
20
|
} from 'three';
|
|
@@ -128,9 +132,142 @@ export interface ToolObject3DAuthoringProps {
|
|
|
128
132
|
* Without this binding the animation workspace remains honestly read-only.
|
|
129
133
|
*/
|
|
130
134
|
readonly animationSource?: ToolAnimationSourceBinding;
|
|
135
|
+
/**
|
|
136
|
+
* Project-owned serialization for this authored document. Each serializer
|
|
137
|
+
* returns the exact bytes of one ordinary project file; the host writes all
|
|
138
|
+
* resources as one checksum-guarded, failure-atomic history transaction.
|
|
139
|
+
* The project owns the format and the host never interprets its contents.
|
|
140
|
+
*/
|
|
141
|
+
readonly persistence?: ToolObject3DDocumentPersistence;
|
|
142
|
+
/** Replace the default native-tree projection with a semantic adapter. The
|
|
143
|
+
* default adapter is provided for delegation, so a project can add terrain
|
|
144
|
+
* layers, bones, or mesh elements without rebuilding Object3D projection. */
|
|
145
|
+
readonly authoring?: ToolObject3DDocumentAuthoringFactory;
|
|
146
|
+
/** Project-owned direct manipulation hosted by the editor's input and
|
|
147
|
+
* transient-overlay lifecycle. Completed gestures commit `persistence`; an
|
|
148
|
+
* Escape, unmount, thrown callback, or failed write calls `cancel`. */
|
|
149
|
+
readonly interaction?: ToolObject3DDocumentInteraction;
|
|
131
150
|
readonly active?: boolean;
|
|
132
151
|
}
|
|
133
152
|
|
|
153
|
+
/** The native document state handed back to project-owned serializers. */
|
|
154
|
+
export interface ToolObject3DDocumentState {
|
|
155
|
+
readonly root: Object3D;
|
|
156
|
+
readonly animations: readonly AnimationClip[];
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/** One project-owned artifact participating in an Asset Lab commit. */
|
|
160
|
+
export interface ToolObject3DDocumentResource {
|
|
161
|
+
/** Project-root-relative destination. */
|
|
162
|
+
readonly path: string;
|
|
163
|
+
/** MIME type recorded in canonical history. */
|
|
164
|
+
readonly contentType?: string;
|
|
165
|
+
/** `null` removes the file in the same atomic transaction. */
|
|
166
|
+
readonly serialize: (
|
|
167
|
+
document: ToolObject3DDocumentState,
|
|
168
|
+
) => string | Uint8Array | null | Promise<string | Uint8Array | null>;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export interface ToolObject3DDocumentPersistence {
|
|
172
|
+
/** Default undo/redo label. A completed gesture may supply a narrower one. */
|
|
173
|
+
readonly label?: string;
|
|
174
|
+
/**
|
|
175
|
+
* True only when these resources serialize mutations to `document.animations`.
|
|
176
|
+
* Sidecar-only bindings still make direct manipulation writable, but must
|
|
177
|
+
* leave animation keys read-only rather than pretending to save them.
|
|
178
|
+
*/
|
|
179
|
+
readonly persistsAnimations?: boolean;
|
|
180
|
+
/** Non-empty, path-unique set of files owned by this document. */
|
|
181
|
+
readonly resources: readonly ToolObject3DDocumentResource[];
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export interface ToolObject3DDocumentAuthoringContext extends ToolObject3DDocumentState {
|
|
185
|
+
readonly documentId: string;
|
|
186
|
+
readonly sourcePath: string;
|
|
187
|
+
readonly scene: Scene;
|
|
188
|
+
readonly defaultAdapter: AuthoringAdapter;
|
|
189
|
+
/**
|
|
190
|
+
* Serialize this project-owned document through its declared persistence
|
|
191
|
+
* resources and record the change in canonical history. Rejects when the
|
|
192
|
+
* document is read-only or the atomic write fails.
|
|
193
|
+
*/
|
|
194
|
+
readonly commit: (label?: string) => Promise<boolean>;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
export interface ToolObject3DDocumentAuthoring {
|
|
198
|
+
readonly adapter: AuthoringAdapter;
|
|
199
|
+
dispose?(): void;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export type ToolObject3DDocumentAuthoringFactory = (
|
|
203
|
+
context: ToolObject3DDocumentAuthoringContext,
|
|
204
|
+
) => ToolObject3DDocumentAuthoring;
|
|
205
|
+
|
|
206
|
+
/** Adapter-native hit data for a project-owned Asset Lab gesture. */
|
|
207
|
+
export interface ToolObject3DPointerEvent {
|
|
208
|
+
readonly pointerId: number;
|
|
209
|
+
readonly button: number;
|
|
210
|
+
readonly buttons: number;
|
|
211
|
+
readonly clientX: number;
|
|
212
|
+
readonly clientY: number;
|
|
213
|
+
readonly altKey: boolean;
|
|
214
|
+
readonly ctrlKey: boolean;
|
|
215
|
+
readonly metaKey: boolean;
|
|
216
|
+
readonly shiftKey: boolean;
|
|
217
|
+
readonly ray: Ray;
|
|
218
|
+
readonly hits: readonly Intersection<Object3D>[];
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/** One gesture owns exact rollback to its pre-begin document state. */
|
|
222
|
+
export interface ToolObject3DGesture {
|
|
223
|
+
readonly label?: string;
|
|
224
|
+
update(event: ToolObject3DPointerEvent): void;
|
|
225
|
+
/** Finalize the project-owned native state before the host serializes it. */
|
|
226
|
+
commit(event: ToolObject3DPointerEvent): void | Promise<void>;
|
|
227
|
+
/** Restore exact pre-begin native state. Must be safe after partial commit. */
|
|
228
|
+
cancel(): void | Promise<void>;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export interface ToolObject3DInteractionContext {
|
|
232
|
+
readonly root: Object3D;
|
|
233
|
+
readonly scene: Scene;
|
|
234
|
+
readonly renderer: WebGLRenderer;
|
|
235
|
+
/** Host-owned group removed on document teardown. Project code owns GPU
|
|
236
|
+
* resources it adds and releases them from the extension's `dispose`. */
|
|
237
|
+
readonly overlay: Group;
|
|
238
|
+
/** Live camera getter; projection can change while the document is open. */
|
|
239
|
+
readonly camera: () => Camera;
|
|
240
|
+
/** False means gestures will not begin because no persistence binding exists. */
|
|
241
|
+
readonly writable: boolean;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
export interface ToolObject3DInteractionExtension {
|
|
245
|
+
/** Return null to yield this pointer to the ordinary viewport controls. */
|
|
246
|
+
begin(event: ToolObject3DPointerEvent): ToolObject3DGesture | null;
|
|
247
|
+
/**
|
|
248
|
+
* Optional pre-sample phase. Restore any transforms changed by the previous
|
|
249
|
+
* frame's refinement here; the host samples animation after this call and
|
|
250
|
+
* invokes {@link update} with the resulting native pose.
|
|
251
|
+
*/
|
|
252
|
+
prepareFrame?(deltaSeconds: number, context: ToolObject3DFrameContext): void;
|
|
253
|
+
/**
|
|
254
|
+
* Optional per-frame refinement after the host samples the active animation
|
|
255
|
+
* clip. Use this for project-owned constraints and overlay presentation.
|
|
256
|
+
*/
|
|
257
|
+
update?(deltaSeconds: number, context: ToolObject3DFrameContext): void;
|
|
258
|
+
dispose(): void;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
export interface ToolObject3DFrameContext {
|
|
262
|
+
/** For `prepareFrame`, true when the host will sample animation next. For
|
|
263
|
+
* `update`, true when it sampled an animation clip immediately beforehand. */
|
|
264
|
+
readonly animationSampled: boolean;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
export interface ToolObject3DDocumentInteraction {
|
|
268
|
+
setup(context: ToolObject3DInteractionContext): ToolObject3DInteractionExtension;
|
|
269
|
+
}
|
|
270
|
+
|
|
134
271
|
export interface ToolAnimationSourceBinding {
|
|
135
272
|
/** Project-relative TypeScript file below src/. */
|
|
136
273
|
readonly path: string;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The wire vocabulary of the ACTIVE-DOCUMENT probe — the scoped editor-chrome
|
|
3
|
+
* door (`packages/editor/src/editor-document-probe.ts` implements it,
|
|
4
|
+
* `@vgai/live`'s `editor.document` binds it, and that module's header carries
|
|
5
|
+
* the design decision and the scope contract).
|
|
6
|
+
*
|
|
7
|
+
* Deliberately NOT a page-automation vocabulary: there is no navigation, no
|
|
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
|
|
10
|
+
* an agent cannot otherwise perform through the product.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/** One element as the probe reports it — everything a caller needs to assert
|
|
14
|
+
* on, and nothing that requires a second round trip. */
|
|
15
|
+
export interface ProbedElement {
|
|
16
|
+
/** Position within the match list this element came from. */
|
|
17
|
+
index: number;
|
|
18
|
+
tag: string;
|
|
19
|
+
/** `innerText`, trimmed and capped. */
|
|
20
|
+
text: string;
|
|
21
|
+
attributes: Record<string, string>;
|
|
22
|
+
rect: { x: number; y: number; width: number; height: number };
|
|
23
|
+
/** Present for form controls. */
|
|
24
|
+
value?: string;
|
|
25
|
+
checked?: boolean;
|
|
26
|
+
disabled?: boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface DocumentProbeResult {
|
|
30
|
+
/** The scope the step ran in — echoed so a transcript proves WHICH document
|
|
31
|
+
* was driven, not merely that something was. */
|
|
32
|
+
document: { id: string; title: string };
|
|
33
|
+
/** Total matches inside the scope, before any `limit`. */
|
|
34
|
+
matched: number;
|
|
35
|
+
elements: ProbedElement[];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Read what the active document rendered. */
|
|
39
|
+
export interface DocumentQueryStep {
|
|
40
|
+
action: 'query';
|
|
41
|
+
selector: string;
|
|
42
|
+
/** Cap on returned elements (default 25); `matched` still reports the total. */
|
|
43
|
+
limit?: number;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** A real pointer gesture on one matched element. */
|
|
47
|
+
export interface DocumentClickStep {
|
|
48
|
+
action: 'click';
|
|
49
|
+
selector: string;
|
|
50
|
+
/** Which match (default 0). */
|
|
51
|
+
index?: number;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** A real key on the explicit target, else whatever inside the document has focus. */
|
|
55
|
+
export interface DocumentKeyStep {
|
|
56
|
+
action: 'key';
|
|
57
|
+
key: string;
|
|
58
|
+
code?: string;
|
|
59
|
+
selector?: string;
|
|
60
|
+
index?: number;
|
|
61
|
+
ctrlKey?: boolean;
|
|
62
|
+
metaKey?: boolean;
|
|
63
|
+
shiftKey?: boolean;
|
|
64
|
+
altKey?: boolean;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** A real `ClipboardEvent` carrying `text/plain` — the only way to exercise a
|
|
68
|
+
* paste handler, and the gesture the Sheets build could not verify. */
|
|
69
|
+
export interface DocumentPasteStep {
|
|
70
|
+
action: 'paste';
|
|
71
|
+
text: string;
|
|
72
|
+
selector?: string;
|
|
73
|
+
index?: number;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export type DocumentProbeStep =
|
|
77
|
+
| DocumentQueryStep
|
|
78
|
+
| DocumentClickStep
|
|
79
|
+
| DocumentKeyStep
|
|
80
|
+
| DocumentPasteStep;
|
package/src/editor-view.ts
CHANGED
|
@@ -8,9 +8,9 @@ const ASSET_KINDS = new Set<AssetKind>([
|
|
|
8
8
|
'audio',
|
|
9
9
|
'animation',
|
|
10
10
|
'json',
|
|
11
|
-
'scene',
|
|
12
11
|
'prefab',
|
|
13
12
|
'material',
|
|
13
|
+
'source',
|
|
14
14
|
]);
|
|
15
15
|
const CAMERAS = new Set<ViewPreset | 'isometric'>([
|
|
16
16
|
'top',
|
|
@@ -32,7 +32,12 @@ const DIAGNOSTICS = new Set<EditorViewDiagnostic>([
|
|
|
32
32
|
'bounds',
|
|
33
33
|
'skeleton',
|
|
34
34
|
]);
|
|
35
|
-
const UTILITIES = new Set<EditorViewUtility>([
|
|
35
|
+
const UTILITIES = new Set<EditorViewUtility>([
|
|
36
|
+
'profiler',
|
|
37
|
+
'console',
|
|
38
|
+
'animation',
|
|
39
|
+
'light-explorer',
|
|
40
|
+
]);
|
|
36
41
|
|
|
37
42
|
function nonEmpty(value: string | null): string | null {
|
|
38
43
|
const trimmed = value?.trim();
|
|
@@ -47,7 +52,7 @@ function writeDocument(params: URLSearchParams, document: EditorView['document']
|
|
|
47
52
|
params.set(`${PREFIX}assetSource`, 'entity');
|
|
48
53
|
} else if (document.kind === 'asset') {
|
|
49
54
|
params.set(`${PREFIX}doc`, document.path!);
|
|
50
|
-
} else if (document.kind === 'scene'
|
|
55
|
+
} else if (document.kind === 'scene') {
|
|
51
56
|
params.set(`${PREFIX}doc`, document.path);
|
|
52
57
|
} else if (document.kind === 'story') {
|
|
53
58
|
params.set(`${PREFIX}doc`, document.modulePath);
|
|
@@ -139,7 +144,6 @@ function parseDocument(params: URLSearchParams): EditorView['document'] {
|
|
|
139
144
|
if (kind === 'scene') return { kind, path: value };
|
|
140
145
|
if (kind === 'tool') return { kind, id: value };
|
|
141
146
|
if (kind === 'world') return { kind, id: value };
|
|
142
|
-
if (kind === 'data') return { kind, path: value };
|
|
143
147
|
if (kind === 'project-tool') return { kind, name: value };
|
|
144
148
|
if (kind === 'generation') return { kind, id: value };
|
|
145
149
|
if (kind === 'story') return parseStoryDocument(params, value);
|
|
@@ -148,7 +152,6 @@ function parseDocument(params: URLSearchParams): EditorView['document'] {
|
|
|
148
152
|
[
|
|
149
153
|
'workspace:scene',
|
|
150
154
|
'workspace:game',
|
|
151
|
-
'workspace:data-assets',
|
|
152
155
|
'workspace:build-profiles',
|
|
153
156
|
'account',
|
|
154
157
|
'project-tools',
|
package/src/extension.ts
CHANGED
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
* engine already publishes that seam and every consumer of it also
|
|
20
20
|
* imports the engine — an alias would be a dead surface.
|
|
21
21
|
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
22
|
+
* Outcomes (the anti-shim rule, as API): every contribution resolves to an
|
|
23
|
+
* {@link ExtensionContributionState} —
|
|
24
24
|
*
|
|
25
25
|
* - `'active'` — the contribution loaded and produced its surface.
|
|
26
26
|
* - `'absent'` — nothing was contributed. The editor HIDES the surface
|
|
@@ -33,7 +33,8 @@
|
|
|
33
33
|
*/
|
|
34
34
|
|
|
35
35
|
/**
|
|
36
|
-
*
|
|
37
|
-
*
|
|
36
|
+
* The terminal state of a single extension contribution (see the module doc
|
|
37
|
+
* above for the exact semantics). Not a grade and not an ordering: `absent`
|
|
38
|
+
* and `failed` both hide the surface, and `failed` is reported loudly.
|
|
38
39
|
*/
|
|
39
|
-
export type
|
|
40
|
+
export type ExtensionContributionState = 'active' | 'absent' | 'failed';
|
package/src/index.ts
CHANGED
|
@@ -4,7 +4,7 @@ export type {
|
|
|
4
4
|
GenerationJobStatus,
|
|
5
5
|
GenerationJobsDocument,
|
|
6
6
|
} from '@vgai/sdk/generations';
|
|
7
|
-
export type { GameDebugDoor } from './client.js';
|
|
7
|
+
export type { GameDebugDoor, HistoryStep } from './client.js';
|
|
8
8
|
export { EditorClient, EditorCommandError } from './client.js';
|
|
9
9
|
export type {
|
|
10
10
|
ToolAssetInspectorContributionMatch,
|
|
@@ -16,8 +16,17 @@ export type {
|
|
|
16
16
|
ToolInspectorContributionMatch,
|
|
17
17
|
ToolInspectorContributionProps,
|
|
18
18
|
} from './contributions.js';
|
|
19
|
+
export type {
|
|
20
|
+
DocumentClickStep,
|
|
21
|
+
DocumentKeyStep,
|
|
22
|
+
DocumentPasteStep,
|
|
23
|
+
DocumentProbeResult,
|
|
24
|
+
DocumentProbeStep,
|
|
25
|
+
DocumentQueryStep,
|
|
26
|
+
ProbedElement,
|
|
27
|
+
} from './document-probe.js';
|
|
19
28
|
export { editorViewFromUrl, editorViewUrl } from './editor-view.js';
|
|
20
|
-
export type {
|
|
29
|
+
export type { ExtensionContributionState } from './extension.js';
|
|
21
30
|
export type {
|
|
22
31
|
ActiveDocumentCapture,
|
|
23
32
|
AssetCompareCapture,
|
|
@@ -41,6 +50,8 @@ export type {
|
|
|
41
50
|
HelperVisibility,
|
|
42
51
|
InspectedAction,
|
|
43
52
|
InspectedField,
|
|
53
|
+
InspectedHierarchy,
|
|
54
|
+
InspectedHierarchyRow,
|
|
44
55
|
InspectedInspection,
|
|
45
56
|
InspectedNothing,
|
|
46
57
|
InspectedSection,
|
package/src/types.ts
CHANGED
|
@@ -15,9 +15,9 @@ export type AssetKind =
|
|
|
15
15
|
| 'audio'
|
|
16
16
|
| 'animation'
|
|
17
17
|
| 'json'
|
|
18
|
-
| 'scene'
|
|
19
18
|
| 'prefab'
|
|
20
|
-
| 'material'
|
|
19
|
+
| 'material'
|
|
20
|
+
| 'source';
|
|
21
21
|
|
|
22
22
|
export interface HelperVisibility {
|
|
23
23
|
bounds: boolean;
|
|
@@ -29,6 +29,8 @@ export interface HelperVisibility {
|
|
|
29
29
|
audio: boolean;
|
|
30
30
|
splines: boolean;
|
|
31
31
|
navmesh: boolean;
|
|
32
|
+
constraints: boolean;
|
|
33
|
+
reflectionProbes: boolean;
|
|
32
34
|
skeletons: boolean;
|
|
33
35
|
}
|
|
34
36
|
|
|
@@ -397,7 +399,9 @@ export interface EditorState {
|
|
|
397
399
|
* would otherwise leave unexplained. `heapUsedMB`/`heapLimitMB` are null off
|
|
398
400
|
* Chromium (`performance.memory` is non-standard); the renderer counts are
|
|
399
401
|
* absent, never zero, when no game has registered a render-debug adapter.
|
|
400
|
-
* `
|
|
402
|
+
* `mountEpochs` counts the project module generations accumulated in this
|
|
403
|
+
* document; it is absent against an older server. `censusAgeMs` says how
|
|
404
|
+
* stale the profile is — a hidden tab is not sampled.
|
|
401
405
|
*/
|
|
402
406
|
tabs?: Array<{
|
|
403
407
|
tabId8: string;
|
|
@@ -413,6 +417,7 @@ export interface EditorState {
|
|
|
413
417
|
census?: {
|
|
414
418
|
heapUsedMB: number | null;
|
|
415
419
|
heapLimitMB: number | null;
|
|
420
|
+
mountEpochs?: number;
|
|
416
421
|
canvases: number;
|
|
417
422
|
canvasMB: number;
|
|
418
423
|
textures?: number;
|
|
@@ -513,7 +518,7 @@ export interface EditorState {
|
|
|
513
518
|
}
|
|
514
519
|
|
|
515
520
|
export type ViewPreset = 'top' | 'front' | 'right' | 'perspective';
|
|
516
|
-
export type ShadingMode = 'solid' | 'unlit' | 'wireframe' | 'normals' | 'overdraw';
|
|
521
|
+
export type ShadingMode = 'solid' | 'clay' | 'unlit' | 'wireframe' | 'normals' | 'overdraw';
|
|
517
522
|
export type TransformMode = 'translate' | 'rotate' | 'scale';
|
|
518
523
|
export type TransformSpace = 'world' | 'local';
|
|
519
524
|
|
|
@@ -529,7 +534,6 @@ export type EditorViewDocument =
|
|
|
529
534
|
| { kind: 'tool'; id: string }
|
|
530
535
|
| { kind: 'world'; id: string }
|
|
531
536
|
| { kind: 'story'; modulePath: string; storyName: string; mode?: 'preview' | 'docs' }
|
|
532
|
-
| { kind: 'data'; path: string }
|
|
533
537
|
| { kind: 'project-tool'; name: string }
|
|
534
538
|
| { kind: 'generation'; id: string }
|
|
535
539
|
| {
|
|
@@ -537,7 +541,6 @@ export type EditorViewDocument =
|
|
|
537
541
|
id:
|
|
538
542
|
| 'workspace:scene'
|
|
539
543
|
| 'workspace:game'
|
|
540
|
-
| 'workspace:data-assets'
|
|
541
544
|
| 'workspace:build-profiles'
|
|
542
545
|
| 'account'
|
|
543
546
|
| 'project-tools';
|
|
@@ -553,7 +556,7 @@ export interface EditorView {
|
|
|
553
556
|
frame?: 'document' | 'selection';
|
|
554
557
|
grid?: boolean;
|
|
555
558
|
};
|
|
556
|
-
utility?: 'profiler' | 'console' | 'animation';
|
|
559
|
+
utility?: 'profiler' | 'console' | 'animation' | 'light-explorer';
|
|
557
560
|
}
|
|
558
561
|
|
|
559
562
|
export interface PresentedEditorView {
|
|
@@ -687,6 +690,11 @@ export interface InspectedAction {
|
|
|
687
690
|
disabled?: boolean;
|
|
688
691
|
}
|
|
689
692
|
|
|
693
|
+
export interface InspectedSubjectLink {
|
|
694
|
+
id: string;
|
|
695
|
+
title: string;
|
|
696
|
+
}
|
|
697
|
+
|
|
690
698
|
/** The whole inspection subject, as data — what a human sees in the
|
|
691
699
|
* inspector, for an agent (`vgai eval 'editor.inspect()'`). */
|
|
692
700
|
export interface InspectedSubject {
|
|
@@ -701,6 +709,8 @@ export interface InspectedSubject {
|
|
|
701
709
|
surface?: InspectionSurface;
|
|
702
710
|
};
|
|
703
711
|
quickActions: readonly InspectedAction[];
|
|
712
|
+
/** Agent-visible counterparts of the inspector's related-document buttons. */
|
|
713
|
+
related: readonly InspectedSubjectLink[];
|
|
704
714
|
/** Already in display order. */
|
|
705
715
|
sections: readonly InspectedSection[];
|
|
706
716
|
}
|
|
@@ -716,3 +726,52 @@ export interface InspectedNothing {
|
|
|
716
726
|
/** What `editor.inspect()` answers: the subject showing, or nothing at all.
|
|
717
727
|
* Narrow with `'none' in result`. */
|
|
718
728
|
export type InspectedInspection = InspectedSubject | InspectedNothing;
|
|
729
|
+
|
|
730
|
+
// ---------------------------------------------------------------- hierarchy
|
|
731
|
+
//
|
|
732
|
+
// The wire mirror of the editor's own `SerializedHierarchyPanel`
|
|
733
|
+
// (`packages/editor/src/hierarchy-panel-view.ts`, which owns the contract and
|
|
734
|
+
// carries the reasoning). `command-listener.ts` annotates its `hierarchy`
|
|
735
|
+
// payload with this type, so `tsc` checks the two sides against each other on
|
|
736
|
+
// every build.
|
|
737
|
+
//
|
|
738
|
+
// This is NOT `EditorState.entities`: that facet is the raw adapter tree, with
|
|
739
|
+
// no marks, no internals folding and no document promotion. This one is what
|
|
740
|
+
// the hierarchy PANEL rendered — the rows a human is looking at.
|
|
741
|
+
|
|
742
|
+
/** One row of the hierarchy panel, as data. */
|
|
743
|
+
export interface InspectedHierarchyRow {
|
|
744
|
+
id: string;
|
|
745
|
+
label: string;
|
|
746
|
+
/** The dim type suffix the row prints (`Coin1 ·Coin`). */
|
|
747
|
+
typeLabel?: string;
|
|
748
|
+
role?: string;
|
|
749
|
+
depth: number;
|
|
750
|
+
/** Children the row's view has — what opening the caret reveals. Folded
|
|
751
|
+
* implementation children are NOT counted here. */
|
|
752
|
+
childCount: number;
|
|
753
|
+
/** Children folded away as implementation, behind "Reveal Internals". */
|
|
754
|
+
internalChildCount: number;
|
|
755
|
+
/** Whether the panel renders a disclosure control. A row with children of
|
|
756
|
+
* any kind and `expandable: false` is a subtree the UI cannot reach. */
|
|
757
|
+
expandable: boolean;
|
|
758
|
+
expanded?: boolean;
|
|
759
|
+
internal?: true;
|
|
760
|
+
componentRoot?: true;
|
|
761
|
+
/** A synthetic "… N more" cap stub rather than a real node. */
|
|
762
|
+
more?: { hidden: number };
|
|
763
|
+
children?: readonly InspectedHierarchyRow[];
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
/** What `editor.hierarchy()` answers. */
|
|
767
|
+
export interface InspectedHierarchy {
|
|
768
|
+
rowCount: number;
|
|
769
|
+
/** The slice in the DOM; a smaller span than `rowCount` means the rest is
|
|
770
|
+
* scrolled out, not absent. */
|
|
771
|
+
window: { start: number; end: number };
|
|
772
|
+
search?: string;
|
|
773
|
+
scopeId?: string;
|
|
774
|
+
playState: string;
|
|
775
|
+
activeViewportTab: string;
|
|
776
|
+
roots: readonly InspectedHierarchyRow[];
|
|
777
|
+
}
|