@volter/editor-threejs 0.5.65 → 0.5.67

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 (112) hide show
  1. package/NOTICE +2 -0
  2. package/contributions/animation-mixers.service.ts +20 -0
  3. package/contributions/animation-timeline.utility.tsx +44 -0
  4. package/contributions/three-integration.service.ts +13 -0
  5. package/dist-node/serving.mjs +405 -0
  6. package/package.json +113 -5
  7. package/serving/animation-live-module.ts +70 -0
  8. package/serving/animation-stamp.ts +88 -0
  9. package/serving/index.ts +14 -0
  10. package/serving/model-import-conversion.ts +344 -0
  11. package/src/adapter/ingest/scene-capture.ts +1 -23
  12. package/src/adapter/renderer-config.ts +3 -4
  13. package/src/adapter/three-contract.ts +72 -0
  14. package/src/animation/live-mixers.ts +55 -0
  15. package/src/ecs/object-marks.ts +1 -1
  16. package/src/ecs/user-data.ts +0 -16
  17. package/src/host-hierarchy-objects.ts +31 -0
  18. package/src/kit/animation/three-clips-subject.ts +190 -0
  19. package/src/kit/asset-compare.ts +294 -0
  20. package/src/kit/asset-preview-command.ts +265 -0
  21. package/src/kit/asset-preview-framing.ts +357 -0
  22. package/src/kit/asset-preview.ts +2802 -0
  23. package/src/kit/asset-workflow/model-inspection.ts +830 -0
  24. package/src/kit/authoring/component-instance-root.ts +171 -0
  25. package/src/kit/authoring/design-time-settle.ts +343 -0
  26. package/src/kit/authoring/live-object-transform.ts +62 -0
  27. package/src/kit/authoring/object3d-document-session-registry.ts +154 -0
  28. package/src/kit/authoring/object3d-document-session.ts +1965 -0
  29. package/src/kit/authoring/object3d-gesture-controller.ts +113 -0
  30. package/src/kit/authoring/quarks-particle-systems.ts +19 -0
  31. package/src/kit/authoring/shell-viewport-policy.ts +48 -0
  32. package/src/kit/authoring/source-object3d-authoring-adapter.ts +526 -0
  33. package/src/kit/authoring/three-projection-core.ts +226 -0
  34. package/src/kit/authoring/viewport-pick-context.ts +39 -0
  35. package/src/kit/authoring/viewport-raycast.ts +240 -0
  36. package/src/kit/authoring/world-hidden-viewport.ts +95 -0
  37. package/src/kit/camera-authoring.ts +175 -0
  38. package/src/kit/components/CameraInfo.tsx +56 -0
  39. package/src/kit/components/InspectorObjectPreview.tsx +57 -0
  40. package/src/kit/components/Object3DDocumentToolbar.tsx +549 -0
  41. package/src/kit/components/Object3DDocumentViewport.tsx +58 -0
  42. package/src/kit/components/StageHost.tsx +2547 -0
  43. package/src/kit/components/StageOverlays.tsx +21 -0
  44. package/src/kit/components/StatsOverlay.tsx +78 -0
  45. package/src/kit/components/ToolObject3DPreview.tsx +39 -0
  46. package/src/kit/components/ViewportFurniture.tsx +655 -0
  47. package/src/kit/components/ViewportOverlay.tsx +215 -0
  48. package/src/kit/components/ViewportShadingMenu.tsx +340 -0
  49. package/src/kit/components/ViewportViewMenu.tsx +155 -0
  50. package/src/kit/components/asset-viewers/EntityModelDocument.tsx +121 -0
  51. package/src/kit/components/asset-viewers/EnvironmentAssetDocument.tsx +440 -0
  52. package/src/kit/components/asset-viewers/LiveModuleDocument.tsx +395 -0
  53. package/src/kit/components/asset-viewers/LutAssetDocument.tsx +444 -0
  54. package/src/kit/components/asset-viewers/ModelAssetDocument.tsx +105 -0
  55. package/src/kit/components/asset-viewers/Object3DPreview.tsx +356 -0
  56. package/src/kit/components/asset-viewers/QuarksAssetDocument.tsx +527 -0
  57. package/src/kit/components/asset-viewers/ShaderAssetDocument.tsx +743 -0
  58. package/src/kit/components/asset-viewers/three-asset-viewers.tsx +132 -0
  59. package/src/kit/components/object3d-contribution-surfaces.tsx +33 -0
  60. package/src/kit/components/stage-keyboard.tsx +40 -0
  61. package/src/kit/components/stage-overlay-set.tsx +105 -0
  62. package/src/kit/components/stage-presence-markers.ts +482 -0
  63. package/src/kit/components/stage-transform-chrome.ts +30 -0
  64. package/src/kit/components/stage-transform-tools.tsx +73 -0
  65. package/src/kit/components/stage-view-name.ts +30 -0
  66. package/src/kit/components/standard-viewport-dressing.ts +1042 -0
  67. package/src/kit/components/world-root-binding.ts +64 -0
  68. package/src/kit/constraint-helper.ts +338 -0
  69. package/src/kit/editor-shell-store.ts +814 -0
  70. package/src/kit/editor-viewport.ts +6621 -0
  71. package/src/kit/entity-lod.ts +31 -0
  72. package/src/kit/entity-object.ts +92 -0
  73. package/src/kit/hierarchy-mark-reader.ts +74 -0
  74. package/src/kit/instanced-presentation.ts +164 -0
  75. package/src/kit/live-module-source.ts +230 -0
  76. package/src/kit/model-thumbnail.ts +539 -0
  77. package/src/kit/play-camera-flight.ts +300 -0
  78. package/src/kit/projection/three.ts +898 -0
  79. package/src/kit/reflection-probe-helper.ts +142 -0
  80. package/src/kit/scene-document-viewport.ts +51 -0
  81. package/src/kit/scene-framing.ts +315 -0
  82. package/src/kit/scene-view-fog.ts +89 -0
  83. package/src/kit/spatial-handle-visuals.ts +332 -0
  84. package/src/kit/stories/three-story-model.ts +66 -0
  85. package/src/kit/three-canvas-render.ts +44 -0
  86. package/src/kit/three-hierarchy-row-media.ts +26 -0
  87. package/src/kit/three-inspection-media.ts +73 -0
  88. package/src/kit/three-integration.ts +86 -0
  89. package/src/kit/three-state.ts +33 -0
  90. package/src/kit/three-viewport/bone-selection-highlight.ts +119 -0
  91. package/src/kit/three-viewport/camera-fit.ts +41 -0
  92. package/src/kit/three-viewport/interactive-renderer.ts +132 -0
  93. package/src/kit/three-viewport/selection-brackets.ts +355 -0
  94. package/src/kit/three-viewport/selection-outline.ts +333 -0
  95. package/src/kit/three-viewport/skeleton-helper.ts +61 -0
  96. package/src/kit/three-viewport/source-color.ts +197 -0
  97. package/src/kit/three-viewport/studio-environment.ts +96 -0
  98. package/src/kit/trigger-volume-helper.ts +116 -0
  99. package/src/kit/viewport-actions.ts +128 -0
  100. package/src/kit/viewport-authoring-policy.ts +154 -0
  101. package/src/kit/viewport-commands.ts +318 -0
  102. package/src/kit/viewport-hotkeys.ts +119 -0
  103. package/src/kit/viewport-shading-boundary.ts +12 -0
  104. package/src/kit/viewport-status-facet.ts +53 -0
  105. package/src/object3d-contributions.ts +494 -0
  106. package/src/render/viewport-shading.ts +6 -2
  107. package/src/viewport/content-bounds.ts +38 -4
  108. package/src/viewport/environment.ts +16 -0
  109. package/src/viewport-api.ts +92 -0
  110. package/src/viewport-door.ts +237 -0
  111. package/src/animation/animation-clock.ts +0 -479
  112. package/src/animation/runtime-inspection.ts +0 -45
@@ -0,0 +1,132 @@
1
+ /**
2
+ * THE THREE.JS ASSET LAB VIEWERS, registered by route
3
+ * (`@volter/editor-sdk/kit/asset-viewers`): a glTF model, an environment map, a
4
+ * LUT, a shader, a live modeling module and a live entity's model. Each loads on
5
+ * first use, so a document that never opens one never pays for three.js.
6
+ */
7
+ import {
8
+ type AssetViewerProps,
9
+ type AssetViewerRoute,
10
+ type JsonContentViewer,
11
+ registerAssetViewer,
12
+ registerJsonContentViewer,
13
+ } from '@volter/editor-sdk/kit/asset-viewers';
14
+ import { type ComponentType, lazy } from 'react';
15
+
16
+ const viewers: Readonly<Record<AssetViewerRoute, ComponentType<AssetViewerProps>>> = {
17
+ model: lazy(async () => {
18
+ const { ModelAssetDocument } = await import('./ModelAssetDocument');
19
+ return {
20
+ default: (props: AssetViewerProps) => (
21
+ <ModelAssetDocument
22
+ documentId={props.documentId}
23
+ assetPath={props.assetPath}
24
+ displayName={props.displayName}
25
+ active={props.active}
26
+ />
27
+ ),
28
+ };
29
+ }),
30
+ 'entity-model': lazy(async () => {
31
+ const { EntityModelDocument } = await import('./EntityModelDocument');
32
+ return {
33
+ default: (props: AssetViewerProps) => (
34
+ <EntityModelDocument
35
+ documentId={props.documentId}
36
+ entityId={props.entityId ?? ''}
37
+ displayName={props.displayName}
38
+ active={props.active}
39
+ />
40
+ ),
41
+ };
42
+ }),
43
+ environment: lazy(async () => {
44
+ const { EnvironmentAssetDocument } = await import('./EnvironmentAssetDocument');
45
+ return {
46
+ default: (props: AssetViewerProps) => (
47
+ <EnvironmentAssetDocument documentId={props.documentId} assetPath={props.assetPath} active={props.active} />
48
+ ),
49
+ };
50
+ }),
51
+ lut: lazy(async () => {
52
+ const { LutAssetDocument } = await import('./LutAssetDocument');
53
+ return {
54
+ default: (props: AssetViewerProps) => (
55
+ <LutAssetDocument documentId={props.documentId} assetPath={props.assetPath} active={props.active} />
56
+ ),
57
+ };
58
+ }),
59
+ shader: lazy(async () => {
60
+ const { ShaderAssetDocument } = await import('./ShaderAssetDocument');
61
+ return {
62
+ default: (props: AssetViewerProps) => (
63
+ <ShaderAssetDocument documentId={props.documentId} assetPath={props.assetPath} active={props.active} />
64
+ ),
65
+ };
66
+ }),
67
+ 'model-preview': lazy(async () => {
68
+ const { Object3DPreview } = await import('./Object3DPreview');
69
+ return {
70
+ default: (props: AssetViewerProps) => (
71
+ <Object3DPreview
72
+ assetPath={props.assetPath}
73
+ {...(props.materialPath ? { materialPath: props.materialPath } : {})}
74
+ displayName={props.displayName}
75
+ />
76
+ ),
77
+ };
78
+ }),
79
+ // A project script that BUILDS an Object3D opens as the live modeling
80
+ // document; anything else keeps the text preview it is handed as `fallback`.
81
+ module: lazy(async () => {
82
+ const { LiveModuleDocument } = await import('./LiveModuleDocument');
83
+ return {
84
+ default: (props: AssetViewerProps) =>
85
+ props.projectRoot ? (
86
+ <LiveModuleDocument
87
+ documentId={props.documentId}
88
+ projectRoot={props.projectRoot}
89
+ modulePath={(props.assetPath.split(/[?#]/, 1)[0] ?? props.assetPath).replace(/^\//, '')}
90
+ displayName={props.displayName}
91
+ active={props.active}
92
+ fallback={props.fallback}
93
+ />
94
+ ) : (
95
+ props.fallback
96
+ ),
97
+ };
98
+ }),
99
+ };
100
+
101
+ // A three.quarks particle system is plain Object3D JSON: recognized by its
102
+ // structure, shown as the particle editor.
103
+ const quarksJson: JsonContentViewer = {
104
+ recognize: async (assetPath, signal) =>
105
+ (await import('./QuarksAssetDocument')).loadNativeQuarksJsonSource(assetPath, signal),
106
+ Viewer: lazy(async () => {
107
+ const { QuarksAssetDocument } = await import('./QuarksAssetDocument');
108
+ return {
109
+ default: (props: AssetViewerProps & { readonly content: unknown }) => (
110
+ <QuarksAssetDocument
111
+ documentId={props.documentId}
112
+ assetPath={props.assetPath}
113
+ displayName={props.displayName}
114
+ active={props.active}
115
+ source={props.content as Parameters<typeof QuarksAssetDocument>[0]['source']}
116
+ />
117
+ ),
118
+ };
119
+ }),
120
+ };
121
+
122
+ export function registerThreeAssetViewers(): () => void {
123
+ const removals = [
124
+ ...(Object.keys(viewers) as AssetViewerRoute[]).map((route) =>
125
+ registerAssetViewer(route, viewers[route]),
126
+ ),
127
+ registerJsonContentViewer(quarksJson),
128
+ ];
129
+ return () => {
130
+ for (const remove of removals) remove();
131
+ };
132
+ }
@@ -0,0 +1,33 @@
1
+ import { announceDocumentStage } from '@volter/editor-sdk/kit/document-viewports';
2
+ import { lazy, Suspense, useEffect } from 'react';
3
+ import type { ToolObject3DAuthoringProps, ToolObject3DPreviewProps } from '../../object3d-contributions';
4
+
5
+ /**
6
+ * The Object3D surfaces a contribution mounts from its `surfaces` prop, as the Three integration
7
+ * registers them. Each loads its viewport on first use, so installing the integration pulls no
8
+ * WebGL modules until a document asks for one.
9
+ */
10
+ const Preview = lazy(async () => ({ default: (await import('./ToolObject3DPreview')).ToolObject3DPreview }));
11
+ const Authoring = lazy(async () => ({ default: (await import('./StageHost')).ToolObject3DAuthoring }));
12
+
13
+ export function Object3DPreviewSurface(props: ToolObject3DPreviewProps) {
14
+ return (
15
+ <Suspense fallback={<div style={{ minHeight: 240 }}>Loading 3D preview…</div>}>
16
+ <Preview {...props} />
17
+ </Suspense>
18
+ );
19
+ }
20
+
21
+ export function Object3DAuthoringSurface(props: ToolObject3DAuthoringProps) {
22
+ // A CONTRIBUTED DOCUMENT'S STAGE ANNOUNCES ITSELF HERE, the moment the contribution renders it —
23
+ // long before the lazy implementation resolves and registers a session. This is what lets the
24
+ // `tool` and `document` addresses declare a readiness without the host knowing which
25
+ // contributions mount a stage: the capability catalog's Builder documents do and other
26
+ // `workspace.document` contributions do not, and which is which belongs to the PROJECT.
27
+ useEffect(() => announceDocumentStage(props.documentId), [props.documentId]);
28
+ return (
29
+ <Suspense fallback={<div style={{ minHeight: 240 }}>Loading 3D authoring surface…</div>}>
30
+ <Authoring {...props} />
31
+ </Suspense>
32
+ );
33
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * A STAGE'S OWN KEYBOARD ACTIONS — the transform modes, the view presets,
3
+ * Frame, pivot, snap and the vertex-snap hold, bound for the stage whose
4
+ * document is ACTIVE.
5
+ *
6
+ * They belong to the STAGE, and until 2026-09-19 they were mounted from
7
+ * `stage-overlay-set.tsx`, which a stage only reaches when it has the shell
8
+ * above it (`StageHost.tsx`'s `shellStore && !chromeless`). A document
9
+ * contributed by a PACKAGE mounts outside `EditorProvider`, so the Model
10
+ * document reached NONE of them: measured live in the Code-OSS frame on a
11
+ * models project, the editor's action table held 29 entries — the shell set
12
+ * alone — and the stage's nine (`transform.combined/translate/rotate/scale`,
13
+ * `viewport.toggleSnap/frameSelection/cyclePivot/snapToFloor`, the four view
14
+ * presets) were absent, so G/R/S on the Model stage answered nothing at all.
15
+ * The overlay set is an OVERLAY condition (a bounded host must not pay for
16
+ * the collaboration client it reaches); which keys a stage answers is not,
17
+ * and the two were one line by accident.
18
+ *
19
+ * The ONE registry still means ONE holder (`hotkeys.ts`'s scope table, and
20
+ * `key-actions.ts`'s action table under the frame): the active
21
+ * document's stage, which is exactly the condition below.
22
+ *
23
+ * Lazily imported by `StageHost.tsx` so a bounded host neither loads nor pays
24
+ * for `editor-hotkeys.ts`'s closure — the same boundary, and the same reason,
25
+ * as `StageOverlays.tsx`.
26
+ */
27
+ import { useEffect } from 'react';
28
+ import { registerViewportActions } from '../viewport-actions';
29
+ import { registerViewportHotkeys } from '../viewport-hotkeys';
30
+ import type { StageHandle } from './stage-overlay-set';
31
+
32
+ export function StageKeyboardBinding({ stage }: { readonly stage: StageHandle }): null {
33
+ useEffect(
34
+ () => registerViewportHotkeys(stage.store, stage.viewport, stage.canvas),
35
+ [stage.store, stage.viewport, stage.canvas],
36
+ );
37
+ // The same stage's palette entries (`viewport-actions.ts`).
38
+ useEffect(() => registerViewportActions(stage.store), [stage.store]);
39
+ return null;
40
+ }
@@ -0,0 +1,105 @@
1
+ /** Shell overlays for document stages: selection controls, camera readout,
2
+ * hints and statistics. Package documents supply their own chrome. */
3
+
4
+ import { useSyncExternalStore } from 'react';
5
+ import { activeAuthoringVersion, subscribeActiveAuthoring } from '@volter/editor-sdk/kit/authoring/active-adapter';
6
+ import {
7
+ object3DDocumentSessionsVersion,
8
+ subscribeObject3DDocumentSessions,
9
+ } from '../authoring/object3d-document-session-registry';
10
+ import type { EditorShellStore } from '../editor-shell-store';
11
+ import type { EditorViewport } from '../editor-viewport';
12
+ import { documentStageContext, type StageChrome, threeSelectionToolsApply } from '@volter/editor-sdk/kit/stage-context';
13
+ import {
14
+ subscribeWorkspaceDocuments,
15
+ workspaceDocumentRegistryVersion,
16
+ } from '@volter/editor-sdk/kit/workspace-document-registry';
17
+ import {
18
+ subscribeViewportPresentation,
19
+ viewPresentation,
20
+ viewportPresentationVersion,
21
+ } from '@volter/editor-sdk/kit/viewport-presentation';
22
+ import { CameraInfo } from './CameraInfo';
23
+ import { StatsOverlay } from './StatsOverlay';
24
+ import { TransientHintOverlay } from '@volter/editor-sdk/kit/components/TransientHint';
25
+ import { ViewportOverlay } from './ViewportOverlay';
26
+
27
+ /** What the HOST hands over about the stage itself — its own store, the
28
+ * viewport the hotkeys drive and the canvas that claims their scope. Null
29
+ * until the stage has finished building. */
30
+ export interface StageHandle {
31
+ readonly store: EditorShellStore;
32
+ readonly viewport: EditorViewport;
33
+ readonly canvas: HTMLCanvasElement;
34
+ }
35
+
36
+ export interface StageOverlaySetProps {
37
+ readonly store: EditorShellStore;
38
+ readonly documentId: string;
39
+ /** This stage's own handle; `null` while it is still building. */
40
+ readonly stage: StageHandle | null;
41
+ /** Whether this stage's document is the ACTIVE centre tab. */
42
+ readonly active: boolean;
43
+ /** The host's own answer to `StageContext.chrome`. */
44
+ readonly chrome: StageChrome;
45
+
46
+ }
47
+
48
+ export function StageOverlaySet({
49
+ store,
50
+ documentId,
51
+ stage,
52
+ active,
53
+ chrome,
54
+ }: StageOverlaySetProps) {
55
+ /** THIS stage's own store — the shell's until the stage has finished
56
+ * building, which is the same store every overlay read before unit 4. */
57
+ const stageStore = stage?.store ?? store;
58
+ useSyncExternalStore(store.shell.subscribe, store.shell.getShellSnapshot ?? store.shell.getSnapshot);
59
+ // The stage's own state (its grid, helpers, stats, tool mode) lives on ITS
60
+ // store, so the overlays that read it subscribe there too.
61
+ useSyncExternalStore(stageStore.shell.subscribe, stageStore.shell.getShellSnapshot ?? stageStore.shell.getSnapshot);
62
+ useSyncExternalStore(subscribeActiveAuthoring, activeAuthoringVersion);
63
+ useSyncExternalStore(subscribeObject3DDocumentSessions, object3DDocumentSessionsVersion);
64
+ useSyncExternalStore(subscribeWorkspaceDocuments, workspaceDocumentRegistryVersion);
65
+ // THIS stage's context — not the focused one. A capability is present where
66
+ // its condition holds, and the condition is asked of the stage that would
67
+ // draw it (ARCHITECTURE-CORE §One stage).
68
+ const ctx = documentStageContext(store.shell, documentId, chrome);
69
+ /** Whether the selection tools draw here — and that is the WHOLE condition:
70
+ * they read THIS stage's own store (`stage.store`, the one the shared
71
+ * panels reach through `focusedStageStore()`), so a prefab's grid button
72
+ * toggles the prefab's grid and its readout reports the camera its reader
73
+ * is looking through. */
74
+ const showsSelectionTools = threeSelectionToolsApply(ctx);
75
+ // The camera readout is the editor's own; a view whose target draws none leaves it off
76
+ // (`overlays.cameraReadout`).
77
+ useSyncExternalStore(subscribeViewportPresentation, viewportPresentationVersion, viewportPresentationVersion);
78
+ const cameraReadout = viewPresentation(documentId).overlays.cameraReadout;
79
+ return (
80
+ <>
81
+ {/* THE STAGE'S OWN KEYBOARD is no longer mounted here: this module is
82
+ reached only by a stage that has the shell above it, and a
83
+ package-contributed document (the Model document) has none — so it
84
+ answered no stage key at all. It is `StageHost.tsx`'s now, beside
85
+ the stage handle, under the same activation condition
86
+ (`stage-keyboard.tsx` carries the measurement). */}
87
+ {showsSelectionTools ? (
88
+ <>
89
+ <ViewportOverlay store={stageStore} documentId={documentId} />
90
+ {cameraReadout ? <CameraInfo /> : null}
91
+ </>
92
+ ) : null}
93
+ {ctx.surface === 'three' && stageStore.showStats && <StatsOverlay />}
94
+ {/* H2 — the ONE transient hint channel. Lives here because a refused
95
+ transform is a viewport gesture; the overlay is absent from the DOM
96
+ entirely until something has a reason to say. ONE channel means one
97
+ mount — the ACTIVE stage's — so a hint never draws twice. */}
98
+ {active ? <TransientHintOverlay /> : null}
99
+ {/* W4 (inventory row V9): the scene document mounts NO network overlay.
100
+ Compact connection state lives in the status bar
101
+ (`status-contributions.tsx`); the detailed surface is the `network`
102
+ workspace utility (`NetworkInspectorPanel`), revealed from there. */}
103
+ </>
104
+ );
105
+ }