@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.
- package/contributions/animation-timeline.utility.tsx +44 -0
- package/contributions/three-integration.service.ts +13 -0
- package/package.json +96 -6
- package/src/adapter/renderer-config.ts +3 -4
- package/src/adapter/three-contract.ts +72 -0
- package/src/ecs/object-marks.ts +1 -1
- package/src/ecs/user-data.ts +0 -9
- package/src/host-hierarchy-objects.ts +31 -0
- package/src/kit/animation/three-clips-subject.ts +190 -0
- package/src/kit/asset-compare.ts +294 -0
- package/src/kit/asset-preview-command.ts +265 -0
- package/src/kit/asset-preview-framing.ts +357 -0
- package/src/kit/asset-preview.ts +2802 -0
- package/src/kit/asset-workflow/model-inspection.ts +830 -0
- package/src/kit/authoring/component-instance-root.ts +171 -0
- package/src/kit/authoring/design-time-settle.ts +343 -0
- package/src/kit/authoring/live-object-transform.ts +62 -0
- package/src/kit/authoring/object3d-document-session-registry.ts +154 -0
- package/src/kit/authoring/object3d-document-session.ts +1965 -0
- package/src/kit/authoring/object3d-gesture-controller.ts +113 -0
- package/src/kit/authoring/quarks-particle-systems.ts +19 -0
- package/src/kit/authoring/shell-viewport-policy.ts +48 -0
- package/src/kit/authoring/source-object3d-authoring-adapter.ts +526 -0
- package/src/kit/authoring/three-projection-core.ts +226 -0
- package/src/kit/authoring/viewport-pick-context.ts +39 -0
- package/src/kit/authoring/viewport-raycast.ts +240 -0
- package/src/kit/authoring/world-hidden-viewport.ts +95 -0
- package/src/kit/camera-authoring.ts +175 -0
- package/src/kit/components/CameraInfo.tsx +56 -0
- package/src/kit/components/InspectorObjectPreview.tsx +57 -0
- package/src/kit/components/Object3DDocumentToolbar.tsx +549 -0
- package/src/kit/components/Object3DDocumentViewport.tsx +58 -0
- package/src/kit/components/StageHost.tsx +2547 -0
- package/src/kit/components/StageOverlays.tsx +21 -0
- package/src/kit/components/StatsOverlay.tsx +78 -0
- package/src/kit/components/ToolObject3DPreview.tsx +39 -0
- package/src/kit/components/ViewportFurniture.tsx +655 -0
- package/src/kit/components/ViewportOverlay.tsx +215 -0
- package/src/kit/components/ViewportShadingMenu.tsx +340 -0
- package/src/kit/components/ViewportViewMenu.tsx +155 -0
- package/src/kit/components/asset-viewers/EntityModelDocument.tsx +121 -0
- package/src/kit/components/asset-viewers/EnvironmentAssetDocument.tsx +440 -0
- package/src/kit/components/asset-viewers/LiveModuleDocument.tsx +395 -0
- package/src/kit/components/asset-viewers/LutAssetDocument.tsx +444 -0
- package/src/kit/components/asset-viewers/ModelAssetDocument.tsx +105 -0
- package/src/kit/components/asset-viewers/Object3DPreview.tsx +356 -0
- package/src/kit/components/asset-viewers/QuarksAssetDocument.tsx +527 -0
- package/src/kit/components/asset-viewers/ShaderAssetDocument.tsx +743 -0
- package/src/kit/components/asset-viewers/three-asset-viewers.tsx +132 -0
- package/src/kit/components/object3d-contribution-surfaces.tsx +33 -0
- package/src/kit/components/stage-keyboard.tsx +40 -0
- package/src/kit/components/stage-overlay-set.tsx +105 -0
- package/src/kit/components/stage-presence-markers.ts +482 -0
- package/src/kit/components/stage-transform-chrome.ts +30 -0
- package/src/kit/components/stage-transform-tools.tsx +73 -0
- package/src/kit/components/stage-view-name.ts +30 -0
- package/src/kit/components/standard-viewport-dressing.ts +1042 -0
- package/src/kit/components/world-root-binding.ts +64 -0
- package/src/kit/constraint-helper.ts +338 -0
- package/src/kit/editor-shell-store.ts +814 -0
- package/src/kit/editor-viewport.ts +6621 -0
- package/src/kit/entity-lod.ts +31 -0
- package/src/kit/entity-object.ts +92 -0
- package/src/kit/hierarchy-mark-reader.ts +74 -0
- package/src/kit/instanced-presentation.ts +164 -0
- package/src/kit/live-module-source.ts +230 -0
- package/src/kit/model-thumbnail.ts +539 -0
- package/src/kit/play-camera-flight.ts +300 -0
- package/src/kit/projection/three.ts +898 -0
- package/src/kit/reflection-probe-helper.ts +142 -0
- package/src/kit/scene-document-viewport.ts +51 -0
- package/src/kit/scene-framing.ts +315 -0
- package/src/kit/scene-view-fog.ts +89 -0
- package/src/kit/spatial-handle-visuals.ts +332 -0
- package/src/kit/stories/three-story-model.ts +66 -0
- package/src/kit/three-canvas-render.ts +44 -0
- package/src/kit/three-hierarchy-row-media.ts +26 -0
- package/src/kit/three-inspection-media.ts +73 -0
- package/src/kit/three-integration.ts +86 -0
- package/src/kit/three-state.ts +33 -0
- package/src/kit/three-viewport/bone-selection-highlight.ts +119 -0
- package/src/kit/three-viewport/camera-fit.ts +41 -0
- package/src/kit/three-viewport/interactive-renderer.ts +132 -0
- package/src/kit/three-viewport/selection-brackets.ts +355 -0
- package/src/kit/three-viewport/selection-outline.ts +333 -0
- package/src/kit/three-viewport/skeleton-helper.ts +61 -0
- package/src/kit/three-viewport/source-color.ts +197 -0
- package/src/kit/three-viewport/studio-environment.ts +96 -0
- package/src/kit/trigger-volume-helper.ts +116 -0
- package/src/kit/viewport-actions.ts +128 -0
- package/src/kit/viewport-authoring-policy.ts +154 -0
- package/src/kit/viewport-commands.ts +318 -0
- package/src/kit/viewport-hotkeys.ts +119 -0
- package/src/kit/viewport-shading-boundary.ts +12 -0
- package/src/kit/viewport-status-facet.ts +53 -0
- package/src/object3d-contributions.ts +494 -0
- package/src/render/viewport-shading.ts +6 -2
- package/src/viewport-api.ts +92 -0
- package/src/viewport-door.ts +237 -0
|
@@ -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
|
+
}
|