@pascal-app/viewer 1.0.7 → 1.1.1
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 +209 -19
- package/dist/components/viewer/drone-controller.d.ts.map +1 -1
- package/dist/components/viewer/drone-controller.js +1 -5
- package/dist/components/viewer/first-person/build-collider-world.d.ts +14 -0
- package/dist/components/viewer/first-person/build-collider-world.d.ts.map +1 -0
- package/dist/components/viewer/first-person/build-collider-world.js +426 -0
- package/dist/components/viewer/first-person/ground-holes.d.ts +22 -0
- package/dist/components/viewer/first-person/ground-holes.d.ts.map +1 -0
- package/dist/components/viewer/first-person/ground-holes.js +116 -0
- package/dist/components/viewer/first-person/mechanism-targets.d.ts +27 -0
- package/dist/components/viewer/first-person/mechanism-targets.d.ts.map +1 -0
- package/dist/components/viewer/first-person/mechanism-targets.js +79 -0
- package/dist/components/viewer/first-person/terrain-collider.d.ts +32 -0
- package/dist/components/viewer/first-person/terrain-collider.d.ts.map +1 -0
- package/dist/components/viewer/first-person/terrain-collider.js +175 -0
- package/dist/components/viewer/glb-replace-instances.d.ts +6 -3
- package/dist/components/viewer/glb-replace-instances.d.ts.map +1 -1
- package/dist/components/viewer/glb-replace-instances.js +5 -4
- package/dist/components/viewer/glb-scene.d.ts +3 -1
- package/dist/components/viewer/glb-scene.d.ts.map +1 -1
- package/dist/components/viewer/glb-scene.js +2 -1
- package/dist/components/viewer/glb-walkthrough-controller.d.ts +1 -1
- package/dist/components/viewer/glb-walkthrough-controller.d.ts.map +1 -1
- package/dist/components/viewer/glb-walkthrough-controller.js +3 -4
- package/dist/components/viewer/index.d.ts.map +1 -1
- package/dist/components/viewer/index.js +8 -4
- package/dist/components/viewer/live-walkthrough-controller.d.ts +17 -0
- package/dist/components/viewer/live-walkthrough-controller.d.ts.map +1 -0
- package/dist/components/viewer/live-walkthrough-controller.js +1449 -0
- package/dist/components/viewer/post-processing.d.ts.map +1 -1
- package/dist/components/viewer/post-processing.js +22 -1
- package/dist/components/viewer/registered-systems.d.ts.map +1 -1
- package/dist/components/viewer/registered-systems.js +2 -2
- package/dist/components/viewer/unsupported-gpu-fallback.d.ts.map +1 -1
- package/dist/components/viewer/unsupported-gpu-fallback.js +21 -1
- package/dist/components/viewer/use-daylight-rooms.d.ts.map +1 -1
- package/dist/components/viewer/use-daylight-rooms.js +75 -33
- package/dist/hooks/use-gltf-ktx2.d.ts.map +1 -1
- package/dist/hooks/use-gltf-ktx2.js +2 -1
- package/dist/index.d.ts +8 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -1
- package/dist/lib/asset-url.d.ts +0 -1
- package/dist/lib/asset-url.d.ts.map +1 -1
- package/dist/lib/asset-url.js +3 -3
- package/dist/lib/daylight/room-context.d.ts.map +1 -1
- package/dist/lib/daylight/room-context.js +3 -2
- package/dist/lib/daylight/room-map.d.ts +149 -0
- package/dist/lib/daylight/room-map.d.ts.map +1 -0
- package/dist/lib/daylight/room-map.js +813 -0
- package/dist/lib/daylight/room-scene.d.ts +4 -2
- package/dist/lib/daylight/room-scene.d.ts.map +1 -1
- package/dist/lib/daylight/room-scene.js +81 -40
- package/dist/lib/daylight/rooms.d.ts +71 -32
- package/dist/lib/daylight/rooms.d.ts.map +1 -1
- package/dist/lib/daylight/rooms.js +371 -286
- package/dist/lib/ktx2-loader.d.ts.map +1 -1
- package/dist/lib/ktx2-loader.js +2 -1
- package/dist/lib/measurement-label.d.ts +4 -0
- package/dist/lib/measurement-label.d.ts.map +1 -0
- package/dist/lib/measurement-label.js +54 -0
- package/dist/lib/measurement-presentation.d.ts +7 -0
- package/dist/lib/measurement-presentation.d.ts.map +1 -0
- package/dist/lib/measurement-presentation.js +14 -0
- package/dist/lib/pointer-events.d.ts.map +1 -1
- package/dist/lib/pointer-events.js +3 -3
- package/dist/lib/texture-reference.d.ts.map +1 -1
- package/dist/lib/texture-reference.js +4 -3
- package/dist/lib/typing-target.d.ts +2 -0
- package/dist/lib/typing-target.d.ts.map +1 -0
- package/dist/lib/typing-target.js +7 -0
- package/dist/lib/viewer-config.d.ts +27 -0
- package/dist/lib/viewer-config.d.ts.map +1 -0
- package/dist/lib/viewer-config.js +23 -0
- package/dist/lib/viewer-preference-storage.d.ts +7 -0
- package/dist/lib/viewer-preference-storage.d.ts.map +1 -0
- package/dist/lib/viewer-preference-storage.js +23 -0
- package/dist/sfx/audio-settings.d.ts +81 -0
- package/dist/sfx/audio-settings.d.ts.map +1 -0
- package/dist/sfx/audio-settings.js +166 -0
- package/dist/sfx/index.d.ts +6 -0
- package/dist/sfx/index.d.ts.map +1 -0
- package/dist/sfx/index.js +5 -0
- package/dist/sfx/interaction-sounds.d.ts +7 -0
- package/dist/sfx/interaction-sounds.d.ts.map +1 -0
- package/dist/sfx/interaction-sounds.js +39 -0
- package/dist/sfx/player.d.ts +31 -0
- package/dist/sfx/player.d.ts.map +1 -0
- package/dist/sfx/player.js +255 -0
- package/dist/sfx/sounds.d.ts +60 -0
- package/dist/sfx/sounds.d.ts.map +1 -0
- package/dist/sfx/sounds.js +25 -0
- package/dist/sfx/use-viewer-ui-sounds.d.ts +8 -0
- package/dist/sfx/use-viewer-ui-sounds.d.ts.map +1 -0
- package/dist/sfx/use-viewer-ui-sounds.js +42 -0
- package/dist/store/use-first-person-hud.d.ts +13 -0
- package/dist/store/use-first-person-hud.d.ts.map +1 -0
- package/dist/store/use-first-person-hud.js +21 -0
- package/dist/store/use-viewer.d.ts +2 -56
- package/dist/store/use-viewer.d.ts.map +1 -1
- package/dist/store/use-viewer.js +3 -1
- package/dist/systems/elevator/elevator-interaction-system.d.ts +16 -2
- package/dist/systems/elevator/elevator-interaction-system.d.ts.map +1 -1
- package/dist/systems/elevator/elevator-interaction-system.js +41 -8
- package/dist/systems/geometry/geometry-status.d.ts +8 -0
- package/dist/systems/geometry/geometry-status.d.ts.map +1 -0
- package/dist/systems/geometry/geometry-status.js +24 -0
- package/dist/systems/roof/roof-system.d.ts.map +1 -1
- package/dist/systems/roof/roof-system.js +134 -78
- package/dist/systems/wall/wall-system.d.ts +11 -0
- package/dist/systems/wall/wall-system.d.ts.map +1 -1
- package/dist/systems/wall/wall-system.js +56 -10
- package/dist/ui/components/action-button.d.ts +14 -0
- package/dist/ui/components/action-button.d.ts.map +1 -0
- package/dist/ui/components/action-button.js +21 -0
- package/dist/ui/components/action-menu-placement.d.ts +7 -0
- package/dist/ui/components/action-menu-placement.d.ts.map +1 -0
- package/dist/ui/components/action-menu-placement.js +10 -0
- package/dist/ui/components/floorplan-compass-button.d.ts +10 -0
- package/dist/ui/components/floorplan-compass-button.d.ts.map +1 -0
- package/dist/ui/components/floorplan-compass-button.js +22 -0
- package/dist/ui/components/follow-pascal-toggle.d.ts +6 -0
- package/dist/ui/components/follow-pascal-toggle.d.ts.map +1 -0
- package/dist/ui/components/follow-pascal-toggle.js +21 -0
- package/dist/ui/components/localized-html.d.ts +9 -0
- package/dist/ui/components/localized-html.d.ts.map +1 -0
- package/dist/ui/components/localized-html.js +16 -0
- package/dist/ui/components/render-settings-menu.d.ts +9 -0
- package/dist/ui/components/render-settings-menu.d.ts.map +1 -0
- package/dist/ui/components/render-settings-menu.js +145 -0
- package/dist/ui/components/rooms/room-highlight.d.ts +10 -0
- package/dist/ui/components/rooms/room-highlight.d.ts.map +1 -0
- package/dist/ui/components/rooms/room-highlight.js +56 -0
- package/dist/ui/components/rooms/room-labels.d.ts +278 -0
- package/dist/ui/components/rooms/room-labels.d.ts.map +1 -0
- package/dist/ui/components/rooms/room-labels.js +1295 -0
- package/dist/ui/components/rooms/viewer-rooms.d.ts +14 -0
- package/dist/ui/components/rooms/viewer-rooms.d.ts.map +1 -0
- package/dist/ui/components/rooms/viewer-rooms.js +123 -0
- package/dist/ui/components/scene-loader.d.ts +18 -0
- package/dist/ui/components/scene-loader.d.ts.map +1 -0
- package/dist/ui/components/scene-loader.js +29 -0
- package/dist/ui/components/sky-control.d.ts +37 -0
- package/dist/ui/components/sky-control.d.ts.map +1 -0
- package/dist/ui/components/sky-control.js +382 -0
- package/dist/ui/components/use-viewer-camera-navigation-sync.d.ts +4 -0
- package/dist/ui/components/use-viewer-camera-navigation-sync.d.ts.map +1 -0
- package/dist/ui/components/use-viewer-camera-navigation-sync.js +117 -0
- package/dist/ui/components/viewer-controls-bar.d.ts +20 -0
- package/dist/ui/components/viewer-controls-bar.d.ts.map +1 -0
- package/dist/ui/components/viewer-controls-bar.js +130 -0
- package/dist/ui/components/viewer-hover-label.d.ts +14 -0
- package/dist/ui/components/viewer-hover-label.d.ts.map +1 -0
- package/dist/ui/components/viewer-hover-label.js +28 -0
- package/dist/ui/components/viewer-scene-header.d.ts +34 -0
- package/dist/ui/components/viewer-scene-header.d.ts.map +1 -0
- package/dist/ui/components/viewer-scene-header.js +92 -0
- package/dist/ui/components/viewer-selection-manager.d.ts +7 -0
- package/dist/ui/components/viewer-selection-manager.d.ts.map +1 -0
- package/dist/ui/components/viewer-selection-manager.js +116 -0
- package/dist/ui/components/viewer-stage-modes.d.ts +7 -0
- package/dist/ui/components/viewer-stage-modes.d.ts.map +1 -0
- package/dist/ui/components/viewer-stage-modes.js +42 -0
- package/dist/ui/components/viewer-stage-switcher.d.ts +10 -0
- package/dist/ui/components/viewer-stage-switcher.d.ts.map +1 -0
- package/dist/ui/components/viewer-stage-switcher.js +16 -0
- package/dist/ui/components/viewer-stage.d.ts +25 -0
- package/dist/ui/components/viewer-stage.d.ts.map +1 -0
- package/dist/ui/components/viewer-stage.js +107 -0
- package/dist/ui/components/walkthrough-hud.d.ts +29 -0
- package/dist/ui/components/walkthrough-hud.d.ts.map +1 -0
- package/dist/ui/components/walkthrough-hud.js +55 -0
- package/dist/ui/floorplan/floorplan-camera-sync.d.ts +22 -0
- package/dist/ui/floorplan/floorplan-camera-sync.d.ts.map +1 -0
- package/dist/ui/floorplan/floorplan-camera-sync.js +157 -0
- package/dist/ui/floorplan/floorplan-dimension-renderer.d.ts +61 -0
- package/dist/ui/floorplan/floorplan-dimension-renderer.d.ts.map +1 -0
- package/dist/ui/floorplan/floorplan-dimension-renderer.js +280 -0
- package/dist/ui/floorplan/floorplan-geometry-renderer.d.ts +54 -0
- package/dist/ui/floorplan/floorplan-geometry-renderer.d.ts.map +1 -0
- package/dist/ui/floorplan/floorplan-geometry-renderer.js +317 -0
- package/dist/ui/floorplan/floorplan-label-angle.d.ts +24 -0
- package/dist/ui/floorplan/floorplan-label-angle.d.ts.map +1 -0
- package/dist/ui/floorplan/floorplan-label-angle.js +60 -0
- package/dist/ui/floorplan/floorplan-navigation-sync.d.ts +18 -0
- package/dist/ui/floorplan/floorplan-navigation-sync.d.ts.map +1 -0
- package/dist/ui/floorplan/floorplan-navigation-sync.js +41 -0
- package/dist/ui/floorplan/floorplan-preview-geometry.d.ts +26 -0
- package/dist/ui/floorplan/floorplan-preview-geometry.d.ts.map +1 -0
- package/dist/ui/floorplan/floorplan-preview-geometry.js +173 -0
- package/dist/ui/floorplan/floorplan-preview-navigation.d.ts +22 -0
- package/dist/ui/floorplan/floorplan-preview-navigation.d.ts.map +1 -0
- package/dist/ui/floorplan/floorplan-preview-navigation.js +41 -0
- package/dist/ui/floorplan/floorplan-preview-visibility.d.ts +8 -0
- package/dist/ui/floorplan/floorplan-preview-visibility.d.ts.map +1 -0
- package/dist/ui/floorplan/floorplan-preview-visibility.js +21 -0
- package/dist/ui/floorplan/floorplan-preview.d.ts +19 -0
- package/dist/ui/floorplan/floorplan-preview.d.ts.map +1 -0
- package/dist/ui/floorplan/floorplan-preview.js +700 -0
- package/dist/ui/hooks/use-mobile.d.ts +2 -0
- package/dist/ui/hooks/use-mobile.d.ts.map +1 -0
- package/dist/ui/hooks/use-mobile.js +14 -0
- package/dist/ui/index.d.ts +49 -0
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +48 -0
- package/dist/ui/lib/below-grade.d.ts +38 -0
- package/dist/ui/lib/below-grade.d.ts.map +1 -0
- package/dist/ui/lib/below-grade.js +102 -0
- package/dist/ui/lib/camera-pose.d.ts +19 -0
- package/dist/ui/lib/camera-pose.d.ts.map +1 -0
- package/dist/ui/lib/camera-pose.js +113 -0
- package/dist/ui/lib/cn.d.ts +3 -0
- package/dist/ui/lib/cn.d.ts.map +1 -0
- package/dist/ui/lib/cn.js +5 -0
- package/dist/ui/lib/level-name.d.ts +10 -0
- package/dist/ui/lib/level-name.d.ts.map +1 -0
- package/dist/ui/lib/level-name.js +33 -0
- package/dist/ui/lib/node-display-label.d.ts +8 -0
- package/dist/ui/lib/node-display-label.d.ts.map +1 -0
- package/dist/ui/lib/node-display-label.js +36 -0
- package/dist/ui/lib/room-area.d.ts +3 -0
- package/dist/ui/lib/room-area.d.ts.map +1 -0
- package/dist/ui/lib/room-area.js +8 -0
- package/dist/ui/lib/room-assembly-overlay.d.ts +46 -0
- package/dist/ui/lib/room-assembly-overlay.d.ts.map +1 -0
- package/dist/ui/lib/room-assembly-overlay.js +222 -0
- package/dist/ui/lib/room-name-messages.d.ts +28 -0
- package/dist/ui/lib/room-name-messages.d.ts.map +1 -0
- package/dist/ui/lib/room-name-messages.js +112 -0
- package/dist/ui/lib/room-selection.d.ts +58 -0
- package/dist/ui/lib/room-selection.d.ts.map +1 -0
- package/dist/ui/lib/room-selection.js +297 -0
- package/dist/ui/lib/scene-theme-name.d.ts +4 -0
- package/dist/ui/lib/scene-theme-name.d.ts.map +1 -0
- package/dist/ui/lib/scene-theme-name.js +22 -0
- package/dist/ui/lib/selection-modifiers.d.ts +20 -0
- package/dist/ui/lib/selection-modifiers.d.ts.map +1 -0
- package/dist/ui/lib/selection-modifiers.js +15 -0
- package/dist/ui/lib/viewer-selection.d.ts +132 -0
- package/dist/ui/lib/viewer-selection.d.ts.map +1 -0
- package/dist/ui/lib/viewer-selection.js +462 -0
- package/dist/ui/lib/zone-content.d.ts +6 -0
- package/dist/ui/lib/zone-content.d.ts.map +1 -0
- package/dist/ui/lib/zone-content.js +96 -0
- package/dist/ui/primitives/button.d.ts +11 -0
- package/dist/ui/primitives/button.d.ts.map +1 -0
- package/dist/ui/primitives/button.js +35 -0
- package/dist/ui/primitives/dropdown-menu.d.ts +26 -0
- package/dist/ui/primitives/dropdown-menu.d.ts.map +1 -0
- package/dist/ui/primitives/dropdown-menu.js +53 -0
- package/dist/ui/primitives/popover.d.ts +8 -0
- package/dist/ui/primitives/popover.d.ts.map +1 -0
- package/dist/ui/primitives/popover.js +17 -0
- package/dist/ui/primitives/switch.d.ts +5 -0
- package/dist/ui/primitives/switch.d.ts.map +1 -0
- package/dist/ui/primitives/switch.js +8 -0
- package/dist/ui/primitives/tooltip.d.ts +8 -0
- package/dist/ui/primitives/tooltip.d.ts.map +1 -0
- package/dist/ui/primitives/tooltip.js +17 -0
- package/dist/ui/store/camera-pose-store.d.ts +17 -0
- package/dist/ui/store/camera-pose-store.d.ts.map +1 -0
- package/dist/ui/store/camera-pose-store.js +15 -0
- package/dist/ui/store/navigation-sync-pose-store.d.ts +26 -0
- package/dist/ui/store/navigation-sync-pose-store.d.ts.map +1 -0
- package/dist/ui/store/navigation-sync-pose-store.js +16 -0
- package/dist/ui/store/use-follow-pascal.d.ts +30 -0
- package/dist/ui/store/use-follow-pascal.d.ts.map +1 -0
- package/dist/ui/store/use-follow-pascal.js +28 -0
- package/dist/ui/theme.css +339 -0
- package/package.json +34 -7
package/README.md
CHANGED
|
@@ -5,13 +5,13 @@
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
npm install @pascal-app/core @pascal-app/viewer @pascal-app/
|
|
8
|
+
npm install @pascal-app/core @pascal-app/viewer @pascal-app/nodes
|
|
9
9
|
```
|
|
10
10
|
|
|
11
11
|
## Peer Dependencies
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
|
-
npm install
|
|
14
|
+
npm install react react-dom three @react-three/fiber @react-three/drei lucide-react zustand
|
|
15
15
|
```
|
|
16
16
|
|
|
17
17
|
## What's Included
|
|
@@ -25,33 +25,119 @@ npm install next react react-dom three @react-three/fiber @react-three/drei luci
|
|
|
25
25
|
|
|
26
26
|
## Usage
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
import { builtinPlugin } from '@pascal-app/nodes'
|
|
31
|
-
import { Viewer } from '@pascal-app/viewer'
|
|
32
|
-
import { useEffect, useState } from 'react'
|
|
28
|
+
The live render entry rebuilds geometry from a scene graph in ordinary React applications,
|
|
29
|
+
including Vite. It requires neither Next.js, Tailwind, nor `@pascal-app/editor`.
|
|
33
30
|
|
|
34
|
-
|
|
31
|
+
```tsx
|
|
32
|
+
import { acquireSceneReadOnlyLease, loadPlugin, useScene } from '@pascal-app/core'
|
|
33
|
+
import { renderPlugin } from '@pascal-app/nodes/render'
|
|
34
|
+
import { configureViewer, Viewer } from '@pascal-app/viewer'
|
|
35
|
+
import { OrbitControls } from '@react-three/drei'
|
|
36
|
+
import scene from './scene.json'
|
|
37
|
+
|
|
38
|
+
configureViewer({
|
|
39
|
+
assetsBaseUrl: 'https://editor.pascal.app',
|
|
40
|
+
storageUrl: 'https://your-storage.example',
|
|
41
|
+
// Optional self-hosted decoder directories (include the trailing slash):
|
|
42
|
+
// decoders: { dracoPath: '/decoders/draco/', basisPath: '/decoders/basis/' },
|
|
43
|
+
})
|
|
44
|
+
await loadPlugin(renderPlugin)
|
|
45
|
+
const releaseReadOnly = acquireSceneReadOnlyLease()
|
|
46
|
+
useScene.getState().setScene(scene.nodes, scene.rootNodeIds, {
|
|
47
|
+
materials: scene.materials,
|
|
48
|
+
collections: scene.collections,
|
|
49
|
+
installedPlugins: scene.installedPlugins,
|
|
50
|
+
})
|
|
35
51
|
|
|
36
52
|
function App() {
|
|
37
|
-
|
|
53
|
+
return (
|
|
54
|
+
<div style={{ width: '100vw', height: '100vh' }}>
|
|
55
|
+
<Viewer>
|
|
56
|
+
<OrbitControls makeDefault target={[0, 1, 0]} />
|
|
57
|
+
</Viewer>
|
|
58
|
+
</div>
|
|
59
|
+
)
|
|
60
|
+
}
|
|
38
61
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
62
|
+
// On teardown, unmount App before releasing the lease:
|
|
63
|
+
// releaseReadOnly()
|
|
64
|
+
```
|
|
42
65
|
|
|
43
|
-
|
|
66
|
+
Load exactly one built-in plugin per runtime: `renderPlugin` for a viewer, or the full
|
|
67
|
+
`builtinPlugin` from `@pascal-app/nodes` for an editor. Without registration, nodes cannot render.
|
|
68
|
+
The read-only lease suppresses document-writing systems while the live geometry systems rebuild
|
|
69
|
+
from the supplied graph. Keep it until the viewer unmounts.
|
|
70
|
+
|
|
71
|
+
**One active scene per page/package instance.** `useScene`, `useViewer`, the node registry,
|
|
72
|
+
`sceneRegistry`, loader caches and viewer systems are shared singletons. Concurrent viewers cannot
|
|
73
|
+
own independent graphs. Unmount the previous viewer and release its read-only lease and host
|
|
74
|
+
subscriptions before switching projects; hydrate the new graph and reset the host's viewer
|
|
75
|
+
selection/project presentation before remounting. Use a separate page/iframe for independent graphs.
|
|
76
|
+
|
|
77
|
+
`configureViewer` resolves asset and storage origins at call time. Without configuration, assets
|
|
78
|
+
use `https://editor.pascal.app`, with the existing `NEXT_PUBLIC_ASSETS_CDN_URL` and
|
|
79
|
+
`NEXT_PUBLIC_SUPABASE_URL` environments used when available. Next hosts should pass those values
|
|
80
|
+
explicitly at bootstrap. Draco defaults to version 1.5.5 and Basis to the Three.js 0.187.0
|
|
81
|
+
transcoder. Configure before loading assets: changing paths does not unload cached models or
|
|
82
|
+
already initialized decoder workers. KTX2 support is detected per renderer and misaligned textures
|
|
83
|
+
retain the RGBA fallback. Denied browser storage disables preference persistence without blocking
|
|
84
|
+
rendering.
|
|
85
|
+
|
|
86
|
+
See [`fixtures/viewer-live`](../../fixtures/viewer-live) for a complete small graph and the
|
|
87
|
+
isolated packed-package dev/production smoke test.
|
|
88
|
+
|
|
89
|
+
## Walkthrough for live scenes
|
|
90
|
+
|
|
91
|
+
`LiveWalkthroughController` is a 3D controller from the main `@pascal-app/viewer` entry.
|
|
92
|
+
Mount it inside `Viewer` alongside your live graph rendered with `renderPlugin`. It is dormant
|
|
93
|
+
until `useViewer.walkthroughMode` is true. `walkthroughMovement` chooses `walk` (gravity,
|
|
94
|
+
BVH collision, crouch, jump and door/window/item/elevator interaction) or `drone` (free flight).
|
|
95
|
+
No editor state, editing plugin or baked asset is required.
|
|
44
96
|
|
|
97
|
+
```tsx
|
|
98
|
+
import { LiveWalkthroughController, useFirstPersonHud, useViewer, Viewer } from '@pascal-app/viewer'
|
|
99
|
+
import { WalkthroughHud } from '@pascal-app/viewer/ui'
|
|
100
|
+
import { OrbitControls } from '@react-three/drei'
|
|
101
|
+
|
|
102
|
+
function LiveViewer() {
|
|
103
|
+
const walking = useViewer(s => s.walkthroughMode)
|
|
104
|
+
const suspended = useViewer(s => s.walkthroughSuspended)
|
|
105
|
+
const floorLabel = useFirstPersonHud(s => s.floorLabel)
|
|
106
|
+
const zoneLabel = useFirstPersonHud(s => s.zoneLabel)
|
|
107
|
+
const interact = useFirstPersonHud(s => s.interact)
|
|
108
|
+
const exit = () => useViewer.getState().setWalkthroughMode(false)
|
|
45
109
|
return (
|
|
46
|
-
<div style={{ width: '100vw', height: '100vh' }}>
|
|
47
|
-
<Viewer
|
|
110
|
+
<div style={{ position: 'relative', width: '100vw', height: '100vh' }}>
|
|
111
|
+
<Viewer>
|
|
112
|
+
<OrbitControls enabled={!walking} makeDefault />
|
|
113
|
+
<LiveWalkthroughController />
|
|
114
|
+
</Viewer>
|
|
115
|
+
<button onClick={() => useViewer.getState().setWalkthroughMode(!walking)}>Walkthrough</button>
|
|
116
|
+
{walking && <WalkthroughHud floorLabel={floorLabel} zoneLabel={zoneLabel}
|
|
117
|
+
interact={interact} suspended={suspended} onExit={exit} />}
|
|
48
118
|
</div>
|
|
49
119
|
)
|
|
50
120
|
}
|
|
51
121
|
```
|
|
52
122
|
|
|
53
|
-
|
|
54
|
-
|
|
123
|
+
Use the UI styling setup below for the HUD. Click the canvas to lock the pointer; WASD/arrows move,
|
|
124
|
+
Space jumps, Shift runs, Ctrl crouches, E/R or a locked-pointer click operates the targeted object,
|
|
125
|
+
and T closes it. P frees the cursor and click/P resumes. Escape or losing pointer lock exits.
|
|
126
|
+
A placed spawn controls entry position and heading; otherwise the controller derives a grounded
|
|
127
|
+
spawn from the camera and live collider world. Disable other camera controls while walking.
|
|
128
|
+
|
|
129
|
+
The controller publishes floor, room and interaction prompts to `useFirstPersonHud`. Its main and
|
|
130
|
+
`viewer/ui` exports reference the same store. Mount the HUD outside the canvas and pass those
|
|
131
|
+
values explicitly. Door and drawer cues emit core `interaction:sound`; opt into playback with
|
|
132
|
+
`initInteractionSounds` from `viewer/sfx`. Movement and interaction do not persist document edits.
|
|
133
|
+
|
|
134
|
+
Optional `LiveWalkthroughControllerProps` let a host own framing: `paused` freezes movement/look,
|
|
135
|
+
`externalFov` (a function, read when walkthrough starts and ends) leaves FOV application/restoration to the host while it returns true, `pointerInteraction={false}` reserves
|
|
136
|
+
locked-pointer clicks for the host, and `suspendOnUnlock` keeps walkthrough active when pointer lock
|
|
137
|
+
is lost (Escape with a free cursor exits). `onExit` runs after the controller clears
|
|
138
|
+
`walkthroughMode`. Props remain current during a session without releasing pointer lock.
|
|
139
|
+
For baked scenes, continue using `GlbWalkthroughController`; `DroneController` also works with
|
|
140
|
+
either scene source when only free flight is needed.
|
|
55
141
|
|
|
56
142
|
## Custom Camera Controls
|
|
57
143
|
|
|
@@ -209,14 +295,118 @@ function ViewerControls() {
|
|
|
209
295
|
}
|
|
210
296
|
```
|
|
211
297
|
|
|
298
|
+
## Sound effects (`@pascal-app/viewer/sfx`)
|
|
299
|
+
|
|
300
|
+
Opt in to building interactions and selection/hover cues from any viewer or custom UI.
|
|
301
|
+
The default files come from `https://editor.pascal.app/audios/sfx`; hosts serving the files
|
|
302
|
+
locally should configure their own base URL before preloading. Importing the entry creates no
|
|
303
|
+
Howl instances or interaction subscriptions. Playback starts after the browser allows audio;
|
|
304
|
+
selection/hover cues stay silent until user activation and during walkthrough.
|
|
305
|
+
|
|
306
|
+
```tsx
|
|
307
|
+
import { useEffect } from 'react'
|
|
308
|
+
import { configureViewer } from '@pascal-app/viewer'
|
|
309
|
+
import { initInteractionSounds, playSound, useAudioSettings, useViewerUiSounds } from '@pascal-app/viewer/sfx'
|
|
310
|
+
configureViewer({ sfxBaseUrl: '/audios/sfx' })
|
|
311
|
+
function SoundControls() {
|
|
312
|
+
useEffect(() => initInteractionSounds(), [])
|
|
313
|
+
useViewerUiSounds()
|
|
314
|
+
const toggleMute = useAudioSettings(s => s.toggleMute)
|
|
315
|
+
return <button onPointerEnter={() => playSound('menuHover')} onClick={() => { playSound('menuClick'); toggleMute() }}>Toggle sound</button>
|
|
316
|
+
}
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
`SOUNDS` lists the built-in cue definitions. `playSound(name, options?)` supports gain
|
|
320
|
+
(`volumeMultiplier`) and stereo positioning. `preloadSounds()` warms files without playing;
|
|
321
|
+
`disposeSounds()` releases the shared cache when the host runtime shuts down. Host cues can use
|
|
322
|
+
`SoundDefinition` objects with the same player, including `startSoundLoop` / `stopSoundLoop`.
|
|
323
|
+
`useAudioSettings` shares master/effects volumes across tabs and keeps mute per tab, preserving
|
|
324
|
+
existing Pascal storage keys. Denied storage falls back to memory. Existing radio preferences
|
|
325
|
+
remain in the same settings record so editor consumers continue to share one store.
|
|
326
|
+
|
|
327
|
+
## Viewer UI (`@pascal-app/viewer/ui`)
|
|
328
|
+
|
|
329
|
+
Pascal's read-only viewer chrome as React components: the 3D / 2D / Split stage (`ViewerStage`)
|
|
330
|
+
with its read-only floor plan (`FloorplanPreview`, kept in step with the 3D camera, with its compass
|
|
331
|
+
and floor picker), the controls bar (levels, walls, display, daylight, sky, walkthrough), the scene
|
|
332
|
+
header (project card, breadcrumb, floor list), the hover label, the room pills, room highlight and
|
|
333
|
+
selected-room callout (`ViewerRooms`), the walkthrough and drone HUDs, the loader, the selection
|
|
334
|
+
model behind them
|
|
335
|
+
(`applyViewerClick`, `ViewerSelectionManager`) and the primitives they are built from (`Button`,
|
|
336
|
+
`DropdownMenu*`, `Popover*`, `Tooltip*`, `Switch`). The entry never imports the editor or Next.
|
|
337
|
+
|
|
338
|
+
The components are styled with Tailwind v4 classes. Point Tailwind at the built entry and import
|
|
339
|
+
the theme (tokens, `shadow-elevation-*`, `corner-smooth`, the loader animations):
|
|
340
|
+
|
|
341
|
+
```css
|
|
342
|
+
@import "tailwindcss";
|
|
343
|
+
@import "@pascal-app/viewer/ui/theme.css";
|
|
344
|
+
@source "../node_modules/@pascal-app/viewer/dist/ui";
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
Override any token after the import (`:root { --radius: 0.5rem }`). The docks and menus scope
|
|
348
|
+
themselves with a `dark` class. Control icons load from `configureViewer({ iconsBaseUrl })` (default
|
|
349
|
+
`https://editor.pascal.app/icons`); button sounds play through `@pascal-app/viewer/sfx`.
|
|
350
|
+
|
|
351
|
+
```tsx
|
|
352
|
+
import { LiveWalkthroughController, useViewer, Viewer } from '@pascal-app/viewer'
|
|
353
|
+
import {
|
|
354
|
+
ParametricViewerRooms,
|
|
355
|
+
SceneLoader,
|
|
356
|
+
ViewerControlsBar,
|
|
357
|
+
ViewerSceneHeader,
|
|
358
|
+
ViewerSelectionManager,
|
|
359
|
+
ViewerStage,
|
|
360
|
+
WalkthroughHud,
|
|
361
|
+
} from '@pascal-app/viewer/ui'
|
|
362
|
+
|
|
363
|
+
function ProjectViewer({ ready, name }: { ready: boolean; name: string }) {
|
|
364
|
+
const walking = useViewer((s) => s.walkthroughMode)
|
|
365
|
+
const toggleWalk = () => useViewer.getState().setWalkthroughMode(!walking)
|
|
366
|
+
return (
|
|
367
|
+
<div className="relative h-full w-full">
|
|
368
|
+
<ViewerStage>
|
|
369
|
+
<Viewer selectionManager="custom">
|
|
370
|
+
<LiveWalkthroughController />
|
|
371
|
+
<ViewerSelectionManager />
|
|
372
|
+
<ParametricViewerRooms />
|
|
373
|
+
</Viewer>
|
|
374
|
+
</ViewerStage>
|
|
375
|
+
<ViewerSceneHeader backHref={null} linkComponent={MyLink} projectName={name} />
|
|
376
|
+
<ViewerControlsBar onWalkthroughToggle={toggleWalk} walkthroughActive={walking} />
|
|
377
|
+
{walking && <WalkthroughHud onExit={toggleWalk} />}
|
|
378
|
+
{!ready && <SceneLoader />}
|
|
379
|
+
</div>
|
|
380
|
+
)
|
|
381
|
+
}
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
`ViewerStage` shows its children (the 3D canvas) in 3D, the floor plan in 2D, and both side by side
|
|
385
|
+
in Split; the switcher picks among `modes` (all three by default) and Split falls back to 2D on
|
|
386
|
+
narrow screens. Panning, zooming or turning the plan moves the 3D camera and the reverse, through the
|
|
387
|
+
navigation pose store (`navigationSyncPoseStore`); on the 3D side, drive your drei `CameraControls`
|
|
388
|
+
through `useViewerCameraNavigationSync(controlsRef)`, as Pascal's camera does
|
|
389
|
+
(`synchronizeNavigation={false}` turns the link off). The plan draws each kind's `def.floorplan`,
|
|
390
|
+
which `renderPlugin` carries; without a `scene` prop it reads the live scene store, and a host with
|
|
391
|
+
another node source passes `scene={{ nodes, installedPlugins }}`. Picking a floor in 2D selects that
|
|
392
|
+
level in the viewer. Room names show as the plan's drawn tags. Control the mode with `mode` /
|
|
393
|
+
`onModeChange` or let the stage hold it (`defaultMode`).
|
|
394
|
+
|
|
395
|
+
`linkComponent` renders the header's links (a plain `<a>` by default); pass your router's link,
|
|
396
|
+
e.g. Next's `Link`. `ParametricViewerRooms` is `ViewerRooms` over the live scene store; a host with
|
|
397
|
+
another node source (a baked scene) passes `<ViewerRooms source={{ nodes, objectFor }} />`. While
|
|
398
|
+
mounted, zones draw no tinted volume: a room shows through its pill and highlight instead. The walkthrough toggle flips `walkthroughMode`; the mounted
|
|
399
|
+
`LiveWalkthroughController` moves the camera. Read `useFirstPersonHud` for the HUD's room and
|
|
400
|
+
interaction props, as in the live walkthrough example above.
|
|
401
|
+
|
|
212
402
|
## Asset CDN Helpers
|
|
213
403
|
|
|
214
404
|
```typescript
|
|
215
|
-
import { resolveCdnUrl
|
|
405
|
+
import { resolveCdnUrl } from '@pascal-app/viewer'
|
|
216
406
|
|
|
217
407
|
// Resolves relative paths to CDN URLs
|
|
218
408
|
const url = resolveCdnUrl('/items/chair/model.glb')
|
|
219
|
-
// → 'https://pascal
|
|
409
|
+
// → 'https://editor.pascal.app/items/chair/model.glb'
|
|
220
410
|
|
|
221
411
|
// Handles external URLs and asset:// protocol
|
|
222
412
|
const externalUrl = resolveCdnUrl('https://example.com/model.glb')
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"drone-controller.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/drone-controller.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"drone-controller.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/drone-controller.tsx"],"names":[],"mappings":"AA+BA,MAAM,MAAM,oBAAoB,GAAG;IACjC,oEAAoE;IACpE,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,kGAAkG;IAClG,MAAM,CAAC,EAAE,MAAM,IAAI,CAAA;CACpB,CAAA;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,EAAE,MAAc,EAAE,MAAM,EAAE,EAAE,oBAAoB,QAyK/E"}
|
|
@@ -3,14 +3,10 @@ import { useFrame, useThree } from '@react-three/fiber';
|
|
|
3
3
|
import { useEffect, useRef } from 'react';
|
|
4
4
|
import { Vector3 } from 'three';
|
|
5
5
|
import { createDroneInput, DRONE_SLOW_MULTIPLIER, droneInputForKey, readDroneInput, seedDroneLook, stepDroneFlight, turnFirstPersonLook, } from '../../lib/drone-flight';
|
|
6
|
+
import { isTypingTarget } from '../../lib/typing-target';
|
|
6
7
|
import useViewer from '../../store/use-viewer';
|
|
7
8
|
import { WALKTHROUGH_FOV } from './glb-walkthrough-controller';
|
|
8
9
|
import { applyWalkthroughCameraClipping } from './viewer-camera';
|
|
9
|
-
const TYPING_TARGET = 'input, textarea, select, [contenteditable]:not([contenteditable="false"]), [role="combobox"], [role="textbox"], [role="dialog"], [role="alertdialog"]';
|
|
10
|
-
function isTypingTarget(target) {
|
|
11
|
-
const element = target;
|
|
12
|
-
return !!element && (element.isContentEditable === true || !!element.closest?.(TYPING_TARGET));
|
|
13
|
-
}
|
|
14
10
|
function requestLock(canvas) {
|
|
15
11
|
// The request can reject asynchronously (the browser's re-lock cooldown);
|
|
16
12
|
// clicking the canvas asks again.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
export declare const FIRST_PERSON_SPAWN_EYE_HEIGHT = 1.65;
|
|
3
|
+
export type FirstPersonColliderWorld = {
|
|
4
|
+
mesh: THREE.Mesh;
|
|
5
|
+
bounds: THREE.Box3 | null;
|
|
6
|
+
dispose: () => void;
|
|
7
|
+
};
|
|
8
|
+
export type FirstPersonSpawn = {
|
|
9
|
+
position: [number, number, number];
|
|
10
|
+
yaw: number;
|
|
11
|
+
};
|
|
12
|
+
export declare function buildFirstPersonColliderWorldFromRegistry(): FirstPersonColliderWorld | null;
|
|
13
|
+
export declare function deriveFirstPersonSpawn(camera: THREE.Camera, world: FirstPersonColliderWorld): FirstPersonSpawn;
|
|
14
|
+
//# sourceMappingURL=build-collider-world.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build-collider-world.d.ts","sourceRoot":"","sources":["../../../../src/components/viewer/first-person/build-collider-world.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAqB9B,eAAO,MAAM,6BAA6B,OAAmB,CAAA;AAE7D,MAAM,MAAM,wBAAwB,GAAG;IACrC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAA;IAChB,MAAM,EAAE,KAAK,CAAC,IAAI,GAAG,IAAI,CAAA;IACzB,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IAClC,GAAG,EAAE,MAAM,CAAA;CACZ,CAAA;AAwWD,wBAAgB,yCAAyC,IAAI,wBAAwB,GAAG,IAAI,CA6F3F;AAED,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,KAAK,CAAC,MAAM,EACpB,KAAK,EAAE,wBAAwB,GAC9B,gBAAgB,CA0ClB"}
|