@volter/editor-threejs 0.5.66 → 0.5.68

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.
Files changed (99) hide show
  1. package/contributions/animation-timeline.utility.tsx +44 -0
  2. package/contributions/three-integration.service.ts +13 -0
  3. package/package.json +96 -6
  4. package/src/adapter/renderer-config.ts +3 -4
  5. package/src/adapter/three-contract.ts +72 -0
  6. package/src/ecs/object-marks.ts +1 -1
  7. package/src/ecs/user-data.ts +0 -9
  8. package/src/host-hierarchy-objects.ts +31 -0
  9. package/src/kit/animation/three-clips-subject.ts +190 -0
  10. package/src/kit/asset-compare.ts +294 -0
  11. package/src/kit/asset-preview-command.ts +265 -0
  12. package/src/kit/asset-preview-framing.ts +357 -0
  13. package/src/kit/asset-preview.ts +2802 -0
  14. package/src/kit/asset-workflow/model-inspection.ts +830 -0
  15. package/src/kit/authoring/component-instance-root.ts +171 -0
  16. package/src/kit/authoring/design-time-settle.ts +343 -0
  17. package/src/kit/authoring/live-object-transform.ts +62 -0
  18. package/src/kit/authoring/object3d-document-session-registry.ts +154 -0
  19. package/src/kit/authoring/object3d-document-session.ts +1965 -0
  20. package/src/kit/authoring/object3d-gesture-controller.ts +113 -0
  21. package/src/kit/authoring/quarks-particle-systems.ts +19 -0
  22. package/src/kit/authoring/shell-viewport-policy.ts +48 -0
  23. package/src/kit/authoring/source-object3d-authoring-adapter.ts +526 -0
  24. package/src/kit/authoring/three-projection-core.ts +226 -0
  25. package/src/kit/authoring/viewport-pick-context.ts +39 -0
  26. package/src/kit/authoring/viewport-raycast.ts +240 -0
  27. package/src/kit/authoring/world-hidden-viewport.ts +95 -0
  28. package/src/kit/camera-authoring.ts +175 -0
  29. package/src/kit/components/CameraInfo.tsx +56 -0
  30. package/src/kit/components/InspectorObjectPreview.tsx +57 -0
  31. package/src/kit/components/Object3DDocumentToolbar.tsx +549 -0
  32. package/src/kit/components/Object3DDocumentViewport.tsx +58 -0
  33. package/src/kit/components/StageHost.tsx +2547 -0
  34. package/src/kit/components/StageOverlays.tsx +21 -0
  35. package/src/kit/components/StatsOverlay.tsx +78 -0
  36. package/src/kit/components/ToolObject3DPreview.tsx +39 -0
  37. package/src/kit/components/ViewportFurniture.tsx +655 -0
  38. package/src/kit/components/ViewportOverlay.tsx +215 -0
  39. package/src/kit/components/ViewportShadingMenu.tsx +340 -0
  40. package/src/kit/components/ViewportViewMenu.tsx +155 -0
  41. package/src/kit/components/asset-viewers/EntityModelDocument.tsx +121 -0
  42. package/src/kit/components/asset-viewers/EnvironmentAssetDocument.tsx +440 -0
  43. package/src/kit/components/asset-viewers/LiveModuleDocument.tsx +395 -0
  44. package/src/kit/components/asset-viewers/LutAssetDocument.tsx +444 -0
  45. package/src/kit/components/asset-viewers/ModelAssetDocument.tsx +105 -0
  46. package/src/kit/components/asset-viewers/Object3DPreview.tsx +356 -0
  47. package/src/kit/components/asset-viewers/QuarksAssetDocument.tsx +527 -0
  48. package/src/kit/components/asset-viewers/ShaderAssetDocument.tsx +743 -0
  49. package/src/kit/components/asset-viewers/three-asset-viewers.tsx +132 -0
  50. package/src/kit/components/object3d-contribution-surfaces.tsx +33 -0
  51. package/src/kit/components/stage-keyboard.tsx +40 -0
  52. package/src/kit/components/stage-overlay-set.tsx +105 -0
  53. package/src/kit/components/stage-presence-markers.ts +482 -0
  54. package/src/kit/components/stage-transform-chrome.ts +30 -0
  55. package/src/kit/components/stage-transform-tools.tsx +73 -0
  56. package/src/kit/components/stage-view-name.ts +30 -0
  57. package/src/kit/components/standard-viewport-dressing.ts +1042 -0
  58. package/src/kit/components/world-root-binding.ts +64 -0
  59. package/src/kit/constraint-helper.ts +338 -0
  60. package/src/kit/editor-shell-store.ts +814 -0
  61. package/src/kit/editor-viewport.ts +6621 -0
  62. package/src/kit/entity-lod.ts +31 -0
  63. package/src/kit/entity-object.ts +92 -0
  64. package/src/kit/hierarchy-mark-reader.ts +74 -0
  65. package/src/kit/instanced-presentation.ts +164 -0
  66. package/src/kit/live-module-source.ts +230 -0
  67. package/src/kit/model-thumbnail.ts +539 -0
  68. package/src/kit/play-camera-flight.ts +300 -0
  69. package/src/kit/projection/three.ts +898 -0
  70. package/src/kit/reflection-probe-helper.ts +142 -0
  71. package/src/kit/scene-document-viewport.ts +51 -0
  72. package/src/kit/scene-framing.ts +315 -0
  73. package/src/kit/scene-view-fog.ts +89 -0
  74. package/src/kit/spatial-handle-visuals.ts +332 -0
  75. package/src/kit/stories/three-story-model.ts +66 -0
  76. package/src/kit/three-canvas-render.ts +44 -0
  77. package/src/kit/three-hierarchy-row-media.ts +26 -0
  78. package/src/kit/three-inspection-media.ts +73 -0
  79. package/src/kit/three-integration.ts +86 -0
  80. package/src/kit/three-state.ts +33 -0
  81. package/src/kit/three-viewport/bone-selection-highlight.ts +119 -0
  82. package/src/kit/three-viewport/camera-fit.ts +41 -0
  83. package/src/kit/three-viewport/interactive-renderer.ts +132 -0
  84. package/src/kit/three-viewport/selection-brackets.ts +355 -0
  85. package/src/kit/three-viewport/selection-outline.ts +333 -0
  86. package/src/kit/three-viewport/skeleton-helper.ts +61 -0
  87. package/src/kit/three-viewport/source-color.ts +197 -0
  88. package/src/kit/three-viewport/studio-environment.ts +96 -0
  89. package/src/kit/trigger-volume-helper.ts +116 -0
  90. package/src/kit/viewport-actions.ts +128 -0
  91. package/src/kit/viewport-authoring-policy.ts +154 -0
  92. package/src/kit/viewport-commands.ts +318 -0
  93. package/src/kit/viewport-hotkeys.ts +119 -0
  94. package/src/kit/viewport-shading-boundary.ts +12 -0
  95. package/src/kit/viewport-status-facet.ts +53 -0
  96. package/src/object3d-contributions.ts +494 -0
  97. package/src/render/viewport-shading.ts +6 -2
  98. package/src/viewport-api.ts +92 -0
  99. package/src/viewport-door.ts +237 -0
@@ -0,0 +1,175 @@
1
+ import type * as THREE from 'three';
2
+
3
+ /**
4
+ * Transient camera-authoring presentation for the Scene viewport.
5
+ *
6
+ * Cameras remain ordinary native Three.js objects owned by the active
7
+ * AuthoringAdapter. This module carries only viewport presentation (pin,
8
+ * view-through, pilot) and delegates every authored mutation to the host's
9
+ * canonical transform gesture path. There is no camera document or sidecar.
10
+ */
11
+
12
+ export type CameraViewMode = 'view' | 'pilot';
13
+
14
+ export interface CameraAuthoringSubject {
15
+ readonly id: string;
16
+ readonly name: string;
17
+ readonly camera: THREE.Camera;
18
+ readonly lens: string;
19
+ /** Position and rotation can both enter the adapter's normal edit gesture. */
20
+ readonly canAuthorPose: boolean;
21
+ readonly poseRefusal?: string;
22
+ }
23
+
24
+ export interface CameraAuthoringPresentation {
25
+ readonly preview: CameraAuthoringSubject | null;
26
+ readonly previewPinned: boolean;
27
+ readonly view: {
28
+ readonly mode: CameraViewMode;
29
+ readonly subject: CameraAuthoringSubject;
30
+ } | null;
31
+ readonly guidesVisible: boolean;
32
+ }
33
+
34
+ export interface CameraAuthoringHost {
35
+ /** Camera authoring is an Edit/Scene affordance, never a Play overlay. */
36
+ readonly active: () => boolean;
37
+ readonly selected: () => CameraAuthoringSubject | null;
38
+ readonly resolve: (id: string) => CameraAuthoringSubject | null;
39
+ readonly showView: (subject: CameraAuthoringSubject, mode: CameraViewMode) => void;
40
+ readonly leaveView: () => void;
41
+ readonly alignToViewport: (subject: CameraAuthoringSubject) => void;
42
+ readonly subscribe: (listener: () => void) => () => void;
43
+ }
44
+
45
+ let host: CameraAuthoringHost | null = null;
46
+ let disposeHostSubscription: (() => void) | null = null;
47
+ let pinnedId: string | null = null;
48
+ let viewState: { id: string; mode: CameraViewMode; camera: THREE.Camera } | null = null;
49
+ let guidesVisible = true;
50
+ let version = 0;
51
+ const listeners = new Set<() => void>();
52
+
53
+ function notify(): void {
54
+ version++;
55
+ for (const listener of listeners) listener();
56
+ }
57
+
58
+ function syncHostState(): void {
59
+ if (!host) return;
60
+ if (!host.active()) {
61
+ if (viewState) host.leaveView();
62
+ viewState = null;
63
+ notify();
64
+ return;
65
+ }
66
+ if (pinnedId && !host.resolve(pinnedId)) pinnedId = null;
67
+ if (viewState) {
68
+ const subject = host.resolve(viewState.id);
69
+ if (!subject) {
70
+ viewState = null;
71
+ host.leaveView();
72
+ } else if (subject.camera !== viewState.camera) {
73
+ // HMR may replace the native camera while preserving its semantic id.
74
+ // Rebind the transient view to the fresh object rather than retaining a
75
+ // dead Three.js reference.
76
+ viewState = { ...viewState, camera: subject.camera };
77
+ host.showView(subject, viewState.mode);
78
+ }
79
+ }
80
+ notify();
81
+ }
82
+
83
+ /** Install the one live Scene viewport host. The returned disposer is
84
+ * identity-guarded so a stale unmount cannot clear a newer viewport. */
85
+ export function installCameraAuthoringHost(next: CameraAuthoringHost): () => void {
86
+ disposeHostSubscription?.();
87
+ host?.leaveView();
88
+ host = next;
89
+ pinnedId = null;
90
+ viewState = null;
91
+ guidesVisible = true;
92
+ disposeHostSubscription = next.subscribe(syncHostState);
93
+ notify();
94
+ return () => {
95
+ if (host !== next) return;
96
+ disposeHostSubscription?.();
97
+ disposeHostSubscription = null;
98
+ next.leaveView();
99
+ host = null;
100
+ pinnedId = null;
101
+ viewState = null;
102
+ guidesVisible = true;
103
+ notify();
104
+ };
105
+ }
106
+
107
+ export function subscribeCameraAuthoring(listener: () => void): () => void {
108
+ listeners.add(listener);
109
+ return () => listeners.delete(listener);
110
+ }
111
+
112
+ export function cameraAuthoringVersion(): number {
113
+ return version;
114
+ }
115
+
116
+ export function cameraAuthoringPresentation(): CameraAuthoringPresentation {
117
+ if (!host?.active()) {
118
+ return { preview: null, previewPinned: false, view: null, guidesVisible };
119
+ }
120
+ const selected = host?.selected() ?? null;
121
+ const pinned = pinnedId ? (host?.resolve(pinnedId) ?? null) : null;
122
+ const viewSubject = viewState ? (host?.resolve(viewState.id) ?? null) : null;
123
+ return {
124
+ preview: viewSubject ? null : (pinned ?? selected),
125
+ previewPinned: Boolean(pinned),
126
+ view: viewState && viewSubject ? { mode: viewState.mode, subject: viewSubject } : null,
127
+ guidesVisible,
128
+ };
129
+ }
130
+
131
+ export function currentCameraAuthoringSubject(): CameraAuthoringSubject | null {
132
+ const presentation = cameraAuthoringPresentation();
133
+ return presentation.view?.subject ?? presentation.preview;
134
+ }
135
+
136
+ export function toggleCameraPreviewPin(): void {
137
+ const presentation = cameraAuthoringPresentation();
138
+ const subject = presentation.preview;
139
+ if (!subject) return;
140
+ pinnedId = presentation.previewPinned ? null : subject.id;
141
+ notify();
142
+ }
143
+
144
+ export function viewThroughCamera(subject = currentCameraAuthoringSubject()): void {
145
+ if (!host || !subject) return;
146
+ if (viewState) host.leaveView();
147
+ viewState = { id: subject.id, mode: 'view', camera: subject.camera };
148
+ host.showView(subject, 'view');
149
+ notify();
150
+ }
151
+
152
+ export function pilotCamera(subject = currentCameraAuthoringSubject()): void {
153
+ if (!host || !subject || !subject.canAuthorPose) return;
154
+ if (viewState) host.leaveView();
155
+ viewState = { id: subject.id, mode: 'pilot', camera: subject.camera };
156
+ host.showView(subject, 'pilot');
157
+ notify();
158
+ }
159
+
160
+ export function alignCameraToViewport(subject = currentCameraAuthoringSubject()): void {
161
+ if (!host || !subject || !subject.canAuthorPose) return;
162
+ host.alignToViewport(subject);
163
+ }
164
+
165
+ export function leaveCameraView(): void {
166
+ if (!host || !viewState) return;
167
+ viewState = null;
168
+ host.leaveView();
169
+ notify();
170
+ }
171
+
172
+ export function toggleCameraCompositionGuides(): void {
173
+ guidesVisible = !guidesVisible;
174
+ notify();
175
+ }
@@ -0,0 +1,56 @@
1
+ import { EditorSurface, Inline, Text } from '@volter/editor-sdk/widgets';
2
+ import { useEffect, useRef, useState } from 'react';
3
+ import { useEditorStats } from '@volter/editor-sdk/kit/editor-runtime';
4
+
5
+ function fmt(n: number): string {
6
+ return n.toFixed(2);
7
+ }
8
+
9
+ export function CameraInfo() {
10
+ const stats = useEditorStats();
11
+ const [pos, setPos] = useState({ x: 0, y: 0, z: 0 });
12
+ const [target, setTarget] = useState({ x: 0, y: 0, z: 0 });
13
+ const rafRef = useRef(0);
14
+
15
+ useEffect(() => {
16
+ function tick() {
17
+ const cam = stats.cameraPosition;
18
+ const tgt = stats.cameraTarget;
19
+ setPos((prev) =>
20
+ prev.x !== cam.x || prev.y !== cam.y || prev.z !== cam.z
21
+ ? { x: cam.x, y: cam.y, z: cam.z }
22
+ : prev,
23
+ );
24
+ setTarget((prev) =>
25
+ prev.x !== tgt.x || prev.y !== tgt.y || prev.z !== tgt.z
26
+ ? { x: tgt.x, y: tgt.y, z: tgt.z }
27
+ : prev,
28
+ );
29
+ rafRef.current = requestAnimationFrame(tick);
30
+ }
31
+ rafRef.current = requestAnimationFrame(tick);
32
+ return () => cancelAnimationFrame(rafRef.current);
33
+ }, [stats]);
34
+
35
+ return (
36
+ // P6-U6 (owner taste decision 3: HUD overlays → real islands): under
37
+ // islands chrome the pill wears the shared glass-island material
38
+ // (compact tier; pointer-events stays none — it is a readout, not a
39
+ // control). Bars chrome keeps the pre-U6 overlay surface + blur.
40
+ <EditorSurface
41
+ variant="overlay"
42
+ border
43
+ className="vgai-camera-info vgai-chrome-island vgai-glass-island"
44
+ data-island-scale="compact"
45
+ >
46
+ <Inline gap={8} align="center" style={{ whiteSpace: 'nowrap' }}>
47
+ <Text variant="code">
48
+ Pos {fmt(pos.x)} {fmt(pos.y)} {fmt(pos.z)}
49
+ </Text>
50
+ <Text variant="code">
51
+ Target {fmt(target.x)} {fmt(target.y)} {fmt(target.z)}
52
+ </Text>
53
+ </Inline>
54
+ </EditorSurface>
55
+ );
56
+ }
@@ -0,0 +1,57 @@
1
+ import type * as THREE from 'three';
2
+ import { Object3DSnapshotDocument } from './asset-viewers/EntityModelDocument';
3
+
4
+ /**
5
+ * Inspector-sized projection of the canonical Asset Lab viewport, over a live
6
+ * `Object3D` the caller already has in hand.
7
+ *
8
+ * It takes the OBJECT, not an id to look one up by: a subject's preview is
9
+ * composed only when the thing is genuinely previewable
10
+ * (`inspection/compose.ts`), and the object the composer proved exists is the
11
+ * one rendered here. A scene node and a part inside an asset document are
12
+ * therefore the same case — the part is not in the shell's object map, and
13
+ * with an id this component could only have shown a "no longer available"
14
+ * alert for a thing that is right there on screen.
15
+ *
16
+ * Every host passes `fill`: the section body's square box, the compact card's
17
+ * round disc, and the minimized card's round thumb all own their own geometry
18
+ * and this component just fills it.
19
+ */
20
+ export function InspectorObjectPreview({
21
+ previewKey,
22
+ object,
23
+ displayName,
24
+ fill = false,
25
+ }: {
26
+ /** Stable identity for the isolated preview document. */
27
+ previewKey: string;
28
+ object: THREE.Object3D;
29
+ displayName: string;
30
+ fill?: boolean;
31
+ }) {
32
+ return (
33
+ <div
34
+ data-testid="inspector-object-preview"
35
+ style={
36
+ fill
37
+ ? { position: 'absolute', inset: 0, overflow: 'hidden' }
38
+ : {
39
+ width: '100%',
40
+ height: 220,
41
+ minHeight: 220,
42
+ borderBottom: '1px solid var(--vgai-structural-divider)',
43
+ overflow: 'hidden',
44
+ position: 'relative',
45
+ }
46
+ }
47
+ >
48
+ <Object3DSnapshotDocument
49
+ documentId={`inspector-preview:${previewKey}`}
50
+ source={object}
51
+ displayName={displayName}
52
+ active
53
+ chromeless
54
+ />
55
+ </div>
56
+ );
57
+ }