@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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ktx2-loader.d.ts","sourceRoot":"","sources":["../../src/lib/ktx2-loader.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,iBAAiB,EAMvB,MAAM,OAAO,CAAA;AAId,OAAO,EAAE,UAAU,EAAE,MAAM,0CAA0C,CAAA;
|
|
1
|
+
{"version":3,"file":"ktx2-loader.d.ts","sourceRoot":"","sources":["../../src/lib/ktx2-loader.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,iBAAiB,EAMvB,MAAM,OAAO,CAAA;AAId,OAAO,EAAE,UAAU,EAAE,MAAM,0CAA0C,CAAA;AA4BrE,oFAAoF;AACpF,wBAAgB,oBAAoB,IAAI;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAE1E;AAED;;;;;;;;;;GAUG;AACH,cAAM,uBAAwB,SAAQ,UAAU;IAC9C,OAAO,CAAC,YAAY,CAA0B;IAErC,IAAI,CACX,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,CAAC,OAAO,EAAE,iBAAiB,KAAK,IAAI,EAC5C,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,EAC3C,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,GACjC,IAAI,CA8BN;IAED,OAAO,CAAC,cAAc;IAkBtB;kEAC8D;IACxD,cAAc,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAiC5F;IAED,OAAO,IAAI,IAAI,CAKd;CACF;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,UAAU,yBAAgC,CAAA;AAUvD;;;;;;GAMG;AACH,wBAAgB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAE7C;AAED,yFAAyF;AACzF,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,OAAO,GAAG,OAAO,CAmB5D;AAED,wBAAgB,oBAAoB,CAAC,CAAC,EACpC,MAAM,EAAE;IAAE,aAAa,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAA;CAAE,EAC/C,QAAQ,EAAE,OAAO,GAChB,OAAO,CAIT;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAE9C"}
|
package/dist/lib/ktx2-loader.js
CHANGED
|
@@ -3,6 +3,7 @@ import { DataTexture, LinearFilter, LinearMipmapLinearFilter, RGBAFormat, Unsign
|
|
|
3
3
|
// LottieLoader/TTFLoader, whose CDN URL imports (`lottie-web`, `opentype.js`)
|
|
4
4
|
// crash bun's test runtime for every consumer of the viewer barrel.
|
|
5
5
|
import { KTX2Loader } from 'three/examples/jsm/loaders/KTX2Loader.js';
|
|
6
|
+
import { getViewerConfig } from './viewer-config';
|
|
6
7
|
/** Base width/height of a Basis-supercompressed KTX2 payload needing transcode
|
|
7
8
|
* (vkFormat 0 = ETC1S/UASTC) whose dimensions aren't block-aligned, or null
|
|
8
9
|
* for anything safe. Little-endian u32s: vkFormat at byte 12, pixelWidth at
|
|
@@ -125,7 +126,6 @@ class AlignmentSafeKTX2Loader extends KTX2Loader {
|
|
|
125
126
|
* the scene, so catalog `.ktx2` finishes still load).
|
|
126
127
|
*/
|
|
127
128
|
export const ktx2Loader = new AlignmentSafeKTX2Loader();
|
|
128
|
-
ktx2Loader.setTranscoderPath('https://cdn.jsdelivr.net/gh/pmndrs/drei-assets@master/basis/');
|
|
129
129
|
const configuredRenderers = new WeakSet();
|
|
130
130
|
const warnedRenderers = new WeakSet();
|
|
131
131
|
let resolveKtx2Ready;
|
|
@@ -144,6 +144,7 @@ export function whenKtx2Ready() {
|
|
|
144
144
|
}
|
|
145
145
|
/** Returns true once support has been detected for this renderer (KTX2 safe to load). */
|
|
146
146
|
export function ensureKtx2Support(renderer) {
|
|
147
|
+
ktx2Loader.setTranscoderPath(getViewerConfig().decoders.basisPath);
|
|
147
148
|
const key = renderer;
|
|
148
149
|
if (!key)
|
|
149
150
|
return false;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type MeasurementPoint } from '@pascal-app/core';
|
|
2
|
+
export declare function triangulateMeasurementPolygon(points: readonly MeasurementPoint[]): number[][];
|
|
3
|
+
export declare function measurementPolygonLabelAnchor(points: readonly MeasurementPoint[]): MeasurementPoint | null;
|
|
4
|
+
//# sourceMappingURL=measurement-label.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"measurement-label.d.ts","sourceRoot":"","sources":["../../src/lib/measurement-label.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,gBAAgB,EAA0C,MAAM,kBAAkB,CAAA;AA4BhG,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,SAAS,gBAAgB,EAAE,GAAG,MAAM,EAAE,EAAE,CAE7F;AAED,wBAAgB,6BAA6B,CAC3C,MAAM,EAAE,SAAS,gBAAgB,EAAE,GAClC,gBAAgB,GAAG,IAAI,CAiCzB"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { measurementCentroid, measurementNormal } from '@pascal-app/core';
|
|
2
|
+
import { ShapeUtils, Vector2, Vector3 } from 'three';
|
|
3
|
+
function projectMeasurementPolygon(points) {
|
|
4
|
+
const normalValue = measurementNormal(points);
|
|
5
|
+
const originValue = points[0];
|
|
6
|
+
if (!(normalValue && originValue))
|
|
7
|
+
return null;
|
|
8
|
+
const normal = new Vector3(...normalValue);
|
|
9
|
+
const reference = Math.abs(normal.y) < 0.9 ? new Vector3(0, 1, 0) : new Vector3(1, 0, 0);
|
|
10
|
+
const tangent = new Vector3().crossVectors(reference, normal).normalize();
|
|
11
|
+
const bitangent = new Vector3().crossVectors(normal, tangent).normalize();
|
|
12
|
+
const origin = new Vector3(...originValue);
|
|
13
|
+
const contour = points.map((point) => {
|
|
14
|
+
const relative = new Vector3(...point).sub(origin);
|
|
15
|
+
return new Vector2(relative.dot(tangent), relative.dot(bitangent));
|
|
16
|
+
});
|
|
17
|
+
return { contour, triangles: ShapeUtils.triangulateShape(contour, []) };
|
|
18
|
+
}
|
|
19
|
+
export function triangulateMeasurementPolygon(points) {
|
|
20
|
+
return projectMeasurementPolygon(points)?.triangles ?? [];
|
|
21
|
+
}
|
|
22
|
+
export function measurementPolygonLabelAnchor(points) {
|
|
23
|
+
const projection = projectMeasurementPolygon(points);
|
|
24
|
+
if (!projection || projection.triangles.length === 0)
|
|
25
|
+
return measurementCentroid(points);
|
|
26
|
+
let largestTriangle = null;
|
|
27
|
+
let largestArea = Number.NEGATIVE_INFINITY;
|
|
28
|
+
for (const triangle of projection.triangles) {
|
|
29
|
+
const [firstIndex, secondIndex, thirdIndex] = triangle;
|
|
30
|
+
const first = firstIndex === undefined ? null : projection.contour[firstIndex];
|
|
31
|
+
const second = secondIndex === undefined ? null : projection.contour[secondIndex];
|
|
32
|
+
const third = thirdIndex === undefined ? null : projection.contour[thirdIndex];
|
|
33
|
+
if (!(first && second && third))
|
|
34
|
+
continue;
|
|
35
|
+
const area = Math.abs((second.x - first.x) * (third.y - first.y) - (second.y - first.y) * (third.x - first.x));
|
|
36
|
+
if (area > largestArea) {
|
|
37
|
+
largestArea = area;
|
|
38
|
+
largestTriangle = triangle;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (!largestTriangle)
|
|
42
|
+
return measurementCentroid(points);
|
|
43
|
+
const [firstIndex, secondIndex, thirdIndex] = largestTriangle;
|
|
44
|
+
const first = firstIndex === undefined ? null : points[firstIndex];
|
|
45
|
+
const second = secondIndex === undefined ? null : points[secondIndex];
|
|
46
|
+
const third = thirdIndex === undefined ? null : points[thirdIndex];
|
|
47
|
+
if (!(first && second && third))
|
|
48
|
+
return measurementCentroid(points);
|
|
49
|
+
return [
|
|
50
|
+
(first[0] + second[0] + third[0]) / 3,
|
|
51
|
+
(first[1] + second[1] + third[1]) / 3,
|
|
52
|
+
(first[2] + second[2] + third[2]) / 3,
|
|
53
|
+
];
|
|
54
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const MEASUREMENT_ACTIVE_COLOR = "#6366f1";
|
|
2
|
+
export declare const MEASUREMENT_DANGLING_COLOR = "#dc2626";
|
|
3
|
+
export declare const MEASUREMENT_PERSISTENT_COLOR = "#111827";
|
|
4
|
+
export declare function measurementPresentationColor(dangling: boolean, active: boolean): string;
|
|
5
|
+
export declare const MEASUREMENT_FLOORPLAN_COLOR = "#4f46e5";
|
|
6
|
+
export declare function measurementFloorplanPresentationColor(dangling: boolean, active: boolean): string;
|
|
7
|
+
//# sourceMappingURL=measurement-presentation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"measurement-presentation.d.ts","sourceRoot":"","sources":["../../src/lib/measurement-presentation.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,wBAAwB,YAAY,CAAA;AACjD,eAAO,MAAM,0BAA0B,YAAY,CAAA;AAEnD,eAAO,MAAM,4BAA4B,YAAY,CAAA;AAErD,wBAAgB,4BAA4B,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,GAAG,MAAM,CAGvF;AAED,eAAO,MAAM,2BAA2B,YAAY,CAAA;AAEpD,wBAAgB,qCAAqC,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,GAAG,MAAM,CAGhG"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export const MEASUREMENT_ACTIVE_COLOR = '#6366f1';
|
|
2
|
+
export const MEASUREMENT_DANGLING_COLOR = '#dc2626';
|
|
3
|
+
export const MEASUREMENT_PERSISTENT_COLOR = '#111827';
|
|
4
|
+
export function measurementPresentationColor(dangling, active) {
|
|
5
|
+
if (dangling)
|
|
6
|
+
return MEASUREMENT_DANGLING_COLOR;
|
|
7
|
+
return active ? MEASUREMENT_ACTIVE_COLOR : MEASUREMENT_PERSISTENT_COLOR;
|
|
8
|
+
}
|
|
9
|
+
export const MEASUREMENT_FLOORPLAN_COLOR = '#4f46e5';
|
|
10
|
+
export function measurementFloorplanPresentationColor(dangling, active) {
|
|
11
|
+
if (dangling)
|
|
12
|
+
return MEASUREMENT_DANGLING_COLOR;
|
|
13
|
+
return active ? MEASUREMENT_ACTIVE_COLOR : MEASUREMENT_FLOORPLAN_COLOR;
|
|
14
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pointer-events.d.ts","sourceRoot":"","sources":["../../src/lib/pointer-events.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"pointer-events.d.ts","sourceRoot":"","sources":["../../src/lib/pointer-events.ts"],"names":[],"mappings":"AAmCA,OAAO,EACL,MAAM,IAAI,eAAe,EAGzB,KAAK,YAAY,EAMjB,KAAK,SAAS,EAEf,MAAM,oBAAoB,CAAA;AAC3B,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAI9B,+FAA+F;AAC/F,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,GAAG,SAAS,CAAA;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAC/B,CAAA;AAED,MAAM,MAAM,uBAAuB,GAAG,CAAC,UAAU,EAAE,gBAAgB,KAAK,IAAI,CAAA;AAmC5E,0GAA0G;AAC1G,wBAAgB,eAAe,CAAC,CAAC,SAAS,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,CAAC,GAAG,CAAC,CAGlF;AAYD,wBAAgB,mBAAmB,CACjC,MAAM,SAA8D,EACpE,YAAY,CAAC,EAAE,uBAAuB,GACrC,OAAO,eAAe,CAIxB;AAiED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,KAAK,CAAC,QAAQ,EACtB,QAAQ,GAAE,KAAK,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAQ,EAAE,GAAG,SAA2C,GACxF,OAAO,CAST;AAMD,KAAK,mBAAmB,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,QAAQ,KAAK,IAAI,CAAA;AAmC3D;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,KAAK,CAAC,SAAS,EAC1B,MAAM,EAAE,KAAK,CAAC,QAAQ,EACtB,IAAI,EAAE,mBAAmB,GACxB,KAAK,CAAC,YAAY,EAAE,CAiBtB;AA+GD,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,SAAS,EAChB,YAAY,CAAC,EAAE,uBAAuB,GACrC,YAAY,CAAC,WAAW,CAAC,CAmB3B"}
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
* Ray collection is cached; camera-drag moves are throttled before stock dispatch.
|
|
27
27
|
* The throttle is a vendored-manager policy; dev ?stockEvents uses untouched R3F.
|
|
28
28
|
*/
|
|
29
|
-
import { sceneRegistry, useScene } from '@pascal-app/core';
|
|
29
|
+
import { isDevelopmentBuild, isDevelopmentOutsideTests, sceneRegistry, useScene, } from '@pascal-app/core';
|
|
30
30
|
import { events as createWebEvents, getRootState, } from '@react-three/fiber';
|
|
31
31
|
import * as THREE from 'three';
|
|
32
32
|
import { acceleratedRaycast } from 'three-mesh-bvh';
|
|
@@ -63,7 +63,7 @@ function isSupportedRaycast(raycast) {
|
|
|
63
63
|
raycast[pureRaycast] === true);
|
|
64
64
|
}
|
|
65
65
|
export function choosePointerEvents(search = typeof window !== 'undefined' ? window.location.search : '', onBreadcrumb) {
|
|
66
|
-
return
|
|
66
|
+
return isDevelopmentBuild() && new URLSearchParams(search).has('stockEvents')
|
|
67
67
|
? createWebEvents
|
|
68
68
|
: (store) => createPascalPointerEvents(store, onBreadcrumb);
|
|
69
69
|
}
|
|
@@ -443,7 +443,7 @@ function createEvents(store, onBreadcrumb) {
|
|
|
443
443
|
stats.fallbackEvents++;
|
|
444
444
|
stats.lastFallbackReason = reason;
|
|
445
445
|
if (unsupported &&
|
|
446
|
-
|
|
446
|
+
isDevelopmentOutsideTests() &&
|
|
447
447
|
!warnedRaycastNames.has(reason.fnName)) {
|
|
448
448
|
warnedRaycastNames.add(reason.fnName);
|
|
449
449
|
console.warn(`[pointer-events] Stock fallback for raycast "${reason.fnName}" on ${reason.objectType} "${reason.objectName}". Use markPureRaycast only after verifying it appends hits without reading prior hits or mutating scene/query state.`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"texture-reference.d.ts","sourceRoot":"","sources":["../../src/lib/texture-reference.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAA;AAGnC,MAAM,MAAM,gBAAgB,GACxB,WAAW,GACX,QAAQ,GACR,WAAW,GACX,WAAW,GACX,QAAQ,GACR,OAAO,CAAA;AAEX,MAAM,MAAM,uBAAuB,GAAG,MAAM,GAAG,QAAQ,CAAA;AAEvD,KAAK,oBAAoB,GAAG;IAC1B,CAAC,EAAE,CAAC,CAAA;IACJ,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,gBAAgB,CAAA;IACrB,UAAU,EAAE,uBAAuB,CAAA;CACpC,CAAA;AAED,MAAM,MAAM,gBAAgB,GACxB,CAAC,oBAAoB,GAAG;IACtB,IAAI,EAAE,kBAAkB,GAAG,cAAc,GAAG,eAAe,CAAA;CAC5D,CAAC,GACF,CAAC,oBAAoB,GAAG;IACtB,IAAI,EAAE,UAAU,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;CACnB,CAAC,CAAA;
|
|
1
|
+
{"version":3,"file":"texture-reference.d.ts","sourceRoot":"","sources":["../../src/lib/texture-reference.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAA;AAGnC,MAAM,MAAM,gBAAgB,GACxB,WAAW,GACX,QAAQ,GACR,WAAW,GACX,WAAW,GACX,QAAQ,GACR,OAAO,CAAA;AAEX,MAAM,MAAM,uBAAuB,GAAG,MAAM,GAAG,QAAQ,CAAA;AAEvD,KAAK,oBAAoB,GAAG;IAC1B,CAAC,EAAE,CAAC,CAAA;IACJ,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,gBAAgB,CAAA;IACrB,UAAU,EAAE,uBAAuB,CAAA;CACpC,CAAA;AAED,MAAM,MAAM,gBAAgB,GACxB,CAAC,oBAAoB,GAAG;IACtB,IAAI,EAAE,kBAAkB,GAAG,cAAc,GAAG,eAAe,CAAA;CAC5D,CAAC,GACF,CAAC,oBAAoB,GAAG;IACtB,IAAI,EAAE,UAAU,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;CACnB,CAAC,CAAA;AA0DN,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,CAgBhE;AAMD,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,KAAK,CAAC,OAAO,EACtB,KAAK,EACD;IACE;wEACoE;IACpE,IAAI,EAAE,UAAU,GAAG,eAAe,CAAA;IAClC,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,MAAM,CAAA;CACb,GACD;IACE,IAAI,EAAE,UAAU,CAAA;IAChB,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,MAAM,CAAA;CACnB,GACJ,gBAAgB,GAAG,IAAI,CA6BzB;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,KAAK,CAAC,OAAO,GAAG,gBAAgB,GAAG,IAAI,CAmCnF"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getViewerConfig } from './viewer-config';
|
|
2
2
|
const STORAGE_BUCKET_BY_KIND = {
|
|
3
3
|
'library-material': 'materials',
|
|
4
4
|
'item-glb': 'items',
|
|
@@ -8,7 +8,7 @@ const STORAGE_BUCKET_BY_KIND = {
|
|
|
8
8
|
// null origin for the rest of the process.
|
|
9
9
|
let cachedStorageOrigin;
|
|
10
10
|
function pascalStorageOrigin() {
|
|
11
|
-
const url =
|
|
11
|
+
const url = getViewerConfig().storageUrl;
|
|
12
12
|
if (cachedStorageOrigin && cachedStorageOrigin.url === url)
|
|
13
13
|
return cachedStorageOrigin.origin;
|
|
14
14
|
let origin = null;
|
|
@@ -25,7 +25,8 @@ function pascalStorageOrigin() {
|
|
|
25
25
|
function isAppMaterialUrl(src) {
|
|
26
26
|
try {
|
|
27
27
|
const url = new URL(src);
|
|
28
|
-
return url.origin === new URL(
|
|
28
|
+
return (url.origin === new URL(getViewerConfig().assetsBaseUrl).origin &&
|
|
29
|
+
url.pathname.startsWith('/material/'));
|
|
29
30
|
}
|
|
30
31
|
catch {
|
|
31
32
|
return false;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typing-target.d.ts","sourceRoot":"","sources":["../../src/lib/typing-target.ts"],"names":[],"mappings":"AAKA,wBAAgB,cAAc,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,WAGxD"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// Keys typed into a field (the room-name combobox, any input, an open dialog)
|
|
2
|
+
// belong to that field, never to a canvas gesture.
|
|
3
|
+
const TYPING_TARGET = 'input, textarea, select, [contenteditable]:not([contenteditable="false"]), [role="combobox"], [role="textbox"], [role="dialog"], [role="alertdialog"]';
|
|
4
|
+
export function isTypingTarget(target) {
|
|
5
|
+
const element = target;
|
|
6
|
+
return !!element && (element.isContentEditable === true || !!element.closest?.(TYPING_TARGET));
|
|
7
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export type ViewerConfig = {
|
|
2
|
+
assetsBaseUrl?: string;
|
|
3
|
+
storageUrl?: string;
|
|
4
|
+
/** Base URL for interaction and UI sound files, resolved when played or preloaded. */
|
|
5
|
+
sfxBaseUrl?: string;
|
|
6
|
+
/** Base URL for the viewer UI's icons (`viewer/ui`), resolved per render. */
|
|
7
|
+
iconsBaseUrl?: string;
|
|
8
|
+
decoders?: {
|
|
9
|
+
dracoPath?: string;
|
|
10
|
+
basisPath?: string;
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
export declare const ASSETS_CDN_URL = "https://editor.pascal.app";
|
|
14
|
+
/** Configure the page's viewer runtime before hydrating or loading assets. */
|
|
15
|
+
export declare function configureViewer(options: ViewerConfig): void;
|
|
16
|
+
/** Resolve at use time so browser hosts need neither Next nor a process polyfill. */
|
|
17
|
+
export declare function getViewerConfig(): {
|
|
18
|
+
assetsBaseUrl: string;
|
|
19
|
+
storageUrl: string | undefined;
|
|
20
|
+
sfxBaseUrl: string;
|
|
21
|
+
iconsBaseUrl: string;
|
|
22
|
+
decoders: {
|
|
23
|
+
dracoPath: string;
|
|
24
|
+
basisPath: string;
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
//# sourceMappingURL=viewer-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"viewer-config.d.ts","sourceRoot":"","sources":["../../src/lib/viewer-config.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GAAG;IACzB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,sFAAsF;IACtF,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,6EAA6E;IAC7E,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,EAAE;QACT,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,SAAS,CAAC,EAAE,MAAM,CAAA;KACnB,CAAA;CACF,CAAA;AAED,eAAO,MAAM,cAAc,8BAA8B,CAAA;AAIzD,8EAA8E;AAC9E,wBAAgB,eAAe,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI,CAE3D;AAED,qFAAqF;AACrF,wBAAgB,eAAe;IAE3B,aAAa;IAIb,UAAU;IAGV,UAAU;IACV,YAAY;IACZ,QAAQ;QACN,SAAS;QAET,SAAS;;EAKd"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export const ASSETS_CDN_URL = 'https://editor.pascal.app';
|
|
2
|
+
let config = {};
|
|
3
|
+
/** Configure the page's viewer runtime before hydrating or loading assets. */
|
|
4
|
+
export function configureViewer(options) {
|
|
5
|
+
config = { ...options, decoders: { ...options.decoders } };
|
|
6
|
+
}
|
|
7
|
+
/** Resolve at use time so browser hosts need neither Next nor a process polyfill. */
|
|
8
|
+
export function getViewerConfig() {
|
|
9
|
+
return {
|
|
10
|
+
assetsBaseUrl: config.assetsBaseUrl ??
|
|
11
|
+
((typeof process !== 'undefined' ? process.env.NEXT_PUBLIC_ASSETS_CDN_URL : undefined) ||
|
|
12
|
+
ASSETS_CDN_URL),
|
|
13
|
+
storageUrl: config.storageUrl ??
|
|
14
|
+
(typeof process !== 'undefined' ? process.env.NEXT_PUBLIC_SUPABASE_URL : undefined),
|
|
15
|
+
sfxBaseUrl: config.sfxBaseUrl ?? `${ASSETS_CDN_URL}/audios/sfx`,
|
|
16
|
+
iconsBaseUrl: config.iconsBaseUrl ?? `${ASSETS_CDN_URL}/icons`,
|
|
17
|
+
decoders: {
|
|
18
|
+
dracoPath: config.decoders?.dracoPath ?? 'https://www.gstatic.com/draco/versioned/decoders/1.5.5/',
|
|
19
|
+
basisPath: config.decoders?.basisPath ??
|
|
20
|
+
'https://cdn.jsdelivr.net/npm/three@0.187.0/examples/jsm/libs/basis/',
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Browser privacy settings can deny even access to the localStorage property. */
|
|
2
|
+
export declare const viewerPreferenceStorage: {
|
|
3
|
+
getItem(name: string): string | null;
|
|
4
|
+
setItem(name: string, value: string): void;
|
|
5
|
+
removeItem(name: string): void;
|
|
6
|
+
};
|
|
7
|
+
//# sourceMappingURL=viewer-preference-storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"viewer-preference-storage.d.ts","sourceRoot":"","sources":["../../src/lib/viewer-preference-storage.ts"],"names":[],"mappings":"AAEA,kFAAkF;AAClF,eAAO,MAAM,uBAAuB;;;;CAkBZ,CAAA"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** Browser privacy settings can deny even access to the localStorage property. */
|
|
2
|
+
export const viewerPreferenceStorage = {
|
|
3
|
+
getItem(name) {
|
|
4
|
+
try {
|
|
5
|
+
return window.localStorage.getItem(name);
|
|
6
|
+
}
|
|
7
|
+
catch {
|
|
8
|
+
return null;
|
|
9
|
+
}
|
|
10
|
+
},
|
|
11
|
+
setItem(name, value) {
|
|
12
|
+
try {
|
|
13
|
+
window.localStorage.setItem(name, value);
|
|
14
|
+
}
|
|
15
|
+
catch { }
|
|
16
|
+
},
|
|
17
|
+
removeItem(name) {
|
|
18
|
+
try {
|
|
19
|
+
window.localStorage.removeItem(name);
|
|
20
|
+
}
|
|
21
|
+
catch { }
|
|
22
|
+
},
|
|
23
|
+
};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/** Persisted volume and playback preferences shared across tabs. */
|
|
2
|
+
export declare const AUDIO_SETTINGS_STORAGE_KEY = "pascal-audio-settings";
|
|
3
|
+
/** Per-tab session mute and the local preference inherited by new tabs. */
|
|
4
|
+
export declare const AUDIO_MUTED_STORAGE_KEY = "pascal-audio-muted";
|
|
5
|
+
interface AudioState {
|
|
6
|
+
masterVolume: number;
|
|
7
|
+
sfxVolume: number;
|
|
8
|
+
radioVolume: number;
|
|
9
|
+
isRadioPlaying: boolean;
|
|
10
|
+
/** This tab's mute; the volumes are every tab's. */
|
|
11
|
+
muted: boolean;
|
|
12
|
+
autoplay: boolean;
|
|
13
|
+
setMasterVolume: (v: number) => void;
|
|
14
|
+
setSfxVolume: (v: number) => void;
|
|
15
|
+
setRadioVolume: (v: number) => void;
|
|
16
|
+
setRadioPlaying: (v: boolean) => void;
|
|
17
|
+
toggleRadioPlaying: () => void;
|
|
18
|
+
setMuted: (muted: boolean) => void;
|
|
19
|
+
toggleMute: () => void;
|
|
20
|
+
setAutoplay: (v: boolean) => void;
|
|
21
|
+
}
|
|
22
|
+
declare const audioStore: import("zustand").UseBoundStore<Omit<import("zustand").StoreApi<AudioState>, "persist" | "setState"> & {
|
|
23
|
+
setState(partial: AudioState | Partial<AudioState> | ((state: AudioState) => AudioState | Partial<AudioState>), replace?: false | undefined): unknown;
|
|
24
|
+
setState(state: AudioState | ((state: AudioState) => AudioState), replace: true): unknown;
|
|
25
|
+
persist: {
|
|
26
|
+
setOptions: (options: Partial<import("zustand/middleware").PersistOptions<AudioState, {
|
|
27
|
+
masterVolume: number;
|
|
28
|
+
sfxVolume: number;
|
|
29
|
+
radioVolume: number;
|
|
30
|
+
isRadioPlaying: boolean;
|
|
31
|
+
autoplay: boolean;
|
|
32
|
+
}, unknown>>) => void;
|
|
33
|
+
clearStorage: () => void;
|
|
34
|
+
rehydrate: () => Promise<void> | void;
|
|
35
|
+
hasHydrated: () => boolean;
|
|
36
|
+
onHydrate: (fn: (state: AudioState) => void) => () => void;
|
|
37
|
+
onFinishHydration: (fn: (state: AudioState) => void) => () => void;
|
|
38
|
+
getOptions: () => Partial<import("zustand/middleware").PersistOptions<AudioState, {
|
|
39
|
+
masterVolume: number;
|
|
40
|
+
sfxVolume: number;
|
|
41
|
+
radioVolume: number;
|
|
42
|
+
isRadioPlaying: boolean;
|
|
43
|
+
autoplay: boolean;
|
|
44
|
+
}, unknown>>;
|
|
45
|
+
};
|
|
46
|
+
}>;
|
|
47
|
+
/** Shared audio preferences; storage is read lazily and denied storage stays in memory. */
|
|
48
|
+
export declare const useAudioSettings: (<T = AudioState>(selector?: (state: AudioState) => T) => T) & {
|
|
49
|
+
(): AudioState;
|
|
50
|
+
<U>(selector: (state: AudioState) => U): U;
|
|
51
|
+
} & Omit<import("zustand").StoreApi<AudioState>, "persist" | "setState"> & {
|
|
52
|
+
setState(partial: AudioState | Partial<AudioState> | ((state: AudioState) => AudioState | Partial<AudioState>), replace?: false | undefined): unknown;
|
|
53
|
+
setState(state: AudioState | ((state: AudioState) => AudioState), replace: true): unknown;
|
|
54
|
+
persist: {
|
|
55
|
+
setOptions: (options: Partial<import("zustand/middleware").PersistOptions<AudioState, {
|
|
56
|
+
masterVolume: number;
|
|
57
|
+
sfxVolume: number;
|
|
58
|
+
radioVolume: number;
|
|
59
|
+
isRadioPlaying: boolean;
|
|
60
|
+
autoplay: boolean;
|
|
61
|
+
}, unknown>>) => void;
|
|
62
|
+
clearStorage: () => void;
|
|
63
|
+
rehydrate: () => Promise<void> | void;
|
|
64
|
+
hasHydrated: () => boolean;
|
|
65
|
+
onHydrate: (fn: (state: AudioState) => void) => () => void;
|
|
66
|
+
onFinishHydration: (fn: (state: AudioState) => void) => () => void;
|
|
67
|
+
getOptions: () => Partial<import("zustand/middleware").PersistOptions<AudioState, {
|
|
68
|
+
masterVolume: number;
|
|
69
|
+
sfxVolume: number;
|
|
70
|
+
radioVolume: number;
|
|
71
|
+
isRadioPlaying: boolean;
|
|
72
|
+
autoplay: boolean;
|
|
73
|
+
}, unknown>>;
|
|
74
|
+
};
|
|
75
|
+
} & {
|
|
76
|
+
getState: () => AudioState;
|
|
77
|
+
setState: typeof audioStore.setState;
|
|
78
|
+
subscribe: (...args: Parameters<typeof audioStore.subscribe>) => () => void;
|
|
79
|
+
};
|
|
80
|
+
export {};
|
|
81
|
+
//# sourceMappingURL=audio-settings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audio-settings.d.ts","sourceRoot":"","sources":["../../src/sfx/audio-settings.ts"],"names":[],"mappings":"AAKA,oEAAoE;AACpE,eAAO,MAAM,0BAA0B,0BAA0B,CAAA;AACjE,2EAA2E;AAC3E,eAAO,MAAM,uBAAuB,uBAAuB,CAAA;AAE3D,UAAU,UAAU;IAClB,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,CAAA;IACnB,cAAc,EAAE,OAAO,CAAA;IACvB,oDAAoD;IACpD,KAAK,EAAE,OAAO,CAAA;IACd,QAAQ,EAAE,OAAO,CAAA;IACjB,eAAe,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;IACpC,YAAY,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;IACjC,cAAc,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;IACnC,eAAe,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC,kBAAkB,EAAE,MAAM,IAAI,CAAA;IAC9B,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;IAClC,UAAU,EAAE,MAAM,IAAI,CAAA;IACtB,WAAW,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,IAAI,CAAA;CAClC;AAgED,QAAA,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;EAiDf,CAAA;AA2CD,2FAA2F;AAC3F,eAAO,MAAM,gBAAgB,IAC1B,CAAC,0BAAyB,CAAC,KAAK,EAAE,UAAU,KAAK,CAAC,KAAsC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAalF,OAAO,UAAU,CAAC,QAAQ;yBACX,UAAU,CAAC,OAAO,UAAU,CAAC,SAAS,CAAC;CAK/D,CAAA"}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { create } from 'zustand';
|
|
3
|
+
import { createJSONStorage, persist } from 'zustand/middleware';
|
|
4
|
+
/** Persisted volume and playback preferences shared across tabs. */
|
|
5
|
+
export const AUDIO_SETTINGS_STORAGE_KEY = 'pascal-audio-settings';
|
|
6
|
+
/** Per-tab session mute and the local preference inherited by new tabs. */
|
|
7
|
+
export const AUDIO_MUTED_STORAGE_KEY = 'pascal-audio-muted';
|
|
8
|
+
// Storage can be missing (a test, a server render) or refuse access (site data blocked): the page
|
|
9
|
+
// then keeps its choices in memory only.
|
|
10
|
+
function readStored(storage, key) {
|
|
11
|
+
try {
|
|
12
|
+
return globalThis[storage]?.getItem(key) ?? null;
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function writeStored(storage, key, value) {
|
|
19
|
+
try {
|
|
20
|
+
globalThis[storage]?.setItem(key, value);
|
|
21
|
+
}
|
|
22
|
+
catch { }
|
|
23
|
+
}
|
|
24
|
+
/** This tab's mute. A tab without one takes the last choice made in any tab, and keeps it. */
|
|
25
|
+
function tabMuted() {
|
|
26
|
+
const own = readStored('sessionStorage', AUDIO_MUTED_STORAGE_KEY);
|
|
27
|
+
if (own !== null)
|
|
28
|
+
return own === 'true';
|
|
29
|
+
const muted = readStored('localStorage', AUDIO_MUTED_STORAGE_KEY) === 'true';
|
|
30
|
+
writeStored('sessionStorage', AUDIO_MUTED_STORAGE_KEY, String(muted));
|
|
31
|
+
return muted;
|
|
32
|
+
}
|
|
33
|
+
/** A mute chosen in this tab: this tab's, and where the next new tab starts. Open tabs keep theirs. */
|
|
34
|
+
function chooseMuted(muted) {
|
|
35
|
+
writeStored('sessionStorage', AUDIO_MUTED_STORAGE_KEY, String(muted));
|
|
36
|
+
writeStored('localStorage', AUDIO_MUTED_STORAGE_KEY, String(muted));
|
|
37
|
+
return { muted };
|
|
38
|
+
}
|
|
39
|
+
// The settings as this tab last read, wrote or took from another tab. A save carries every
|
|
40
|
+
// setting, so a save that changes none (a mute, which is this tab's own) is skipped.
|
|
41
|
+
let heldSettings = null;
|
|
42
|
+
// Set while this tab takes another tab's volumes: that is no choice of its own to save back.
|
|
43
|
+
let adopting = false;
|
|
44
|
+
const settingsStorage = createJSONStorage(() => ({
|
|
45
|
+
getItem: (key) => {
|
|
46
|
+
heldSettings = readStored('localStorage', key);
|
|
47
|
+
return heldSettings;
|
|
48
|
+
},
|
|
49
|
+
setItem: (key, value) => {
|
|
50
|
+
if (value === heldSettings)
|
|
51
|
+
return;
|
|
52
|
+
heldSettings = value;
|
|
53
|
+
if (!adopting)
|
|
54
|
+
writeStored('localStorage', key, value);
|
|
55
|
+
},
|
|
56
|
+
removeItem: (key) => {
|
|
57
|
+
try {
|
|
58
|
+
globalThis.localStorage?.removeItem(key);
|
|
59
|
+
}
|
|
60
|
+
catch { }
|
|
61
|
+
},
|
|
62
|
+
}));
|
|
63
|
+
const audioStore = create()(persist((set) => ({
|
|
64
|
+
masterVolume: 70,
|
|
65
|
+
sfxVolume: 50,
|
|
66
|
+
radioVolume: 25,
|
|
67
|
+
isRadioPlaying: false,
|
|
68
|
+
muted: false,
|
|
69
|
+
autoplay: true,
|
|
70
|
+
setMasterVolume: (v) => set({ masterVolume: v }),
|
|
71
|
+
setSfxVolume: (v) => set({ sfxVolume: v }),
|
|
72
|
+
setRadioVolume: (v) => set({ radioVolume: v }),
|
|
73
|
+
setRadioPlaying: (v) => set({ isRadioPlaying: v }),
|
|
74
|
+
toggleRadioPlaying: () => set((state) => ({ isRadioPlaying: !state.isRadioPlaying })),
|
|
75
|
+
setMuted: (muted) => set(chooseMuted(muted)),
|
|
76
|
+
toggleMute: () => set((state) => chooseMuted(!state.muted)),
|
|
77
|
+
setAutoplay: (v) => set({ autoplay: v }),
|
|
78
|
+
}), {
|
|
79
|
+
name: AUDIO_SETTINGS_STORAGE_KEY,
|
|
80
|
+
skipHydration: true,
|
|
81
|
+
onRehydrateStorage: () => {
|
|
82
|
+
attachStorageListener();
|
|
83
|
+
},
|
|
84
|
+
storage: settingsStorage,
|
|
85
|
+
partialize: ({ masterVolume, sfxVolume, radioVolume, isRadioPlaying, autoplay }) => ({
|
|
86
|
+
masterVolume,
|
|
87
|
+
sfxVolume,
|
|
88
|
+
radioVolume,
|
|
89
|
+
isRadioPlaying,
|
|
90
|
+
autoplay,
|
|
91
|
+
}),
|
|
92
|
+
// The settings once held one mute for every tab: whoever had muted stays muted, unless a tab
|
|
93
|
+
// has chosen since (a tab still on that build can write it again). The format is unchanged,
|
|
94
|
+
// so that build reads these settings back with only the mute gone.
|
|
95
|
+
merge: (persisted, current) => {
|
|
96
|
+
const { muted, ...settings } = (persisted ?? {});
|
|
97
|
+
if (typeof muted === 'boolean' &&
|
|
98
|
+
readStored('localStorage', AUDIO_MUTED_STORAGE_KEY) === null) {
|
|
99
|
+
writeStored('localStorage', AUDIO_MUTED_STORAGE_KEY, String(muted));
|
|
100
|
+
}
|
|
101
|
+
return { ...current, ...settings, muted: tabMuted() };
|
|
102
|
+
},
|
|
103
|
+
}));
|
|
104
|
+
/**
|
|
105
|
+
* Another tab saved the settings: the volumes are every tab's, so this tab takes them at once, and
|
|
106
|
+
* a later save of its own carries them. Its mute and whether its radio plays stay its own.
|
|
107
|
+
*/
|
|
108
|
+
function adoptOtherTabSettings(event) {
|
|
109
|
+
if (event.key !== AUDIO_SETTINGS_STORAGE_KEY || event.newValue === null)
|
|
110
|
+
return;
|
|
111
|
+
let stored;
|
|
112
|
+
try {
|
|
113
|
+
stored = JSON.parse(event.newValue)?.state;
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
const shared = {};
|
|
119
|
+
for (const key of ['masterVolume', 'sfxVolume', 'radioVolume']) {
|
|
120
|
+
const value = stored?.[key];
|
|
121
|
+
if (typeof value === 'number')
|
|
122
|
+
shared[key] = value;
|
|
123
|
+
}
|
|
124
|
+
if (typeof stored?.autoplay === 'boolean')
|
|
125
|
+
shared.autoplay = stored.autoplay;
|
|
126
|
+
adopting = true;
|
|
127
|
+
try {
|
|
128
|
+
audioStore.setState(shared);
|
|
129
|
+
}
|
|
130
|
+
finally {
|
|
131
|
+
adopting = false;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
let initialized = false;
|
|
135
|
+
let listening = false;
|
|
136
|
+
function attachStorageListener() {
|
|
137
|
+
initialized = true;
|
|
138
|
+
if (listening || !globalThis.addEventListener)
|
|
139
|
+
return;
|
|
140
|
+
globalThis.addEventListener('storage', adoptOtherTabSettings);
|
|
141
|
+
listening = true;
|
|
142
|
+
}
|
|
143
|
+
function initializeSettings() {
|
|
144
|
+
if (initialized)
|
|
145
|
+
return;
|
|
146
|
+
initialized = true;
|
|
147
|
+
void audioStore.persist.rehydrate();
|
|
148
|
+
}
|
|
149
|
+
/** Shared audio preferences; storage is read lazily and denied storage stays in memory. */
|
|
150
|
+
export const useAudioSettings = Object.assign((selector = (state) => state) => {
|
|
151
|
+
initializeSettings();
|
|
152
|
+
return audioStore(selector);
|
|
153
|
+
}, audioStore, {
|
|
154
|
+
getState: () => {
|
|
155
|
+
initializeSettings();
|
|
156
|
+
return audioStore.getState();
|
|
157
|
+
},
|
|
158
|
+
setState: ((...args) => {
|
|
159
|
+
initializeSettings();
|
|
160
|
+
return audioStore.setState(...args);
|
|
161
|
+
}),
|
|
162
|
+
subscribe: (...args) => {
|
|
163
|
+
initializeSettings();
|
|
164
|
+
return audioStore.subscribe(...args);
|
|
165
|
+
},
|
|
166
|
+
});
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { AUDIO_MUTED_STORAGE_KEY, AUDIO_SETTINGS_STORAGE_KEY, useAudioSettings, } from './audio-settings';
|
|
2
|
+
export { INTERACTION_SOUNDS, initInteractionSounds } from './interaction-sounds';
|
|
3
|
+
export { disposeSounds, playSound, preloadSounds, type SoundDefinition, type SoundPlaybackOptions, startSoundLoop, stopSoundLoop, updateSoundVolumes, } from './player';
|
|
4
|
+
export { SOUNDS, type SoundName } from './sounds';
|
|
5
|
+
export { useViewerUiSounds } from './use-viewer-ui-sounds';
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sfx/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EACvB,0BAA0B,EAC1B,gBAAgB,GACjB,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAA;AAChF,OAAO,EACL,aAAa,EACb,SAAS,EACT,aAAa,EACb,KAAK,eAAe,EACpB,KAAK,oBAAoB,EACzB,cAAc,EACd,aAAa,EACb,kBAAkB,GACnB,MAAM,UAAU,CAAA;AACjB,OAAO,EAAE,MAAM,EAAE,KAAK,SAAS,EAAE,MAAM,UAAU,CAAA;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { AUDIO_MUTED_STORAGE_KEY, AUDIO_SETTINGS_STORAGE_KEY, useAudioSettings, } from './audio-settings';
|
|
2
|
+
export { INTERACTION_SOUNDS, initInteractionSounds } from './interaction-sounds';
|
|
3
|
+
export { disposeSounds, playSound, preloadSounds, startSoundLoop, stopSoundLoop, updateSoundVolumes, } from './player';
|
|
4
|
+
export { SOUNDS } from './sounds';
|
|
5
|
+
export { useViewerUiSounds } from './use-viewer-ui-sounds';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type InteractionSound } from '@pascal-app/core';
|
|
2
|
+
import type { SoundName } from './sounds';
|
|
3
|
+
/** Core interaction cues and their playback gain; windows use softer door recordings. */
|
|
4
|
+
export declare const INTERACTION_SOUNDS: Record<InteractionSound, [SoundName, number]>;
|
|
5
|
+
/** Connect core interaction cues to playback; call the returned cleanup on unmount. */
|
|
6
|
+
export declare function initInteractionSounds(): () => void;
|
|
7
|
+
//# sourceMappingURL=interaction-sounds.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interaction-sounds.d.ts","sourceRoot":"","sources":["../../src/sfx/interaction-sounds.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,KAAK,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AAEjE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAEzC,yFAAyF;AACzF,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,gBAAgB,EAAE,CAAC,SAAS,EAAE,MAAM,CAAC,CAgB5E,CAAA;AAOD,uFAAuF;AACvF,wBAAgB,qBAAqB,IAAI,MAAM,IAAI,CASlD"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { emitter } from '@pascal-app/core';
|
|
2
|
+
import { playSound, preloadSounds } from './player';
|
|
3
|
+
/** Core interaction cues and their playback gain; windows use softer door recordings. */
|
|
4
|
+
export const INTERACTION_SOUNDS = {
|
|
5
|
+
'door-open': ['doorOpen', 1],
|
|
6
|
+
'door-swing': ['doorSwing', 1],
|
|
7
|
+
'door-close': ['doorClose', 1],
|
|
8
|
+
'window-open': ['doorOpen', 0.6],
|
|
9
|
+
'window-swing': ['doorSwing', 0.6],
|
|
10
|
+
'window-close': ['doorClose', 0.6],
|
|
11
|
+
garage: ['garageDoor', 1],
|
|
12
|
+
'shutters-open': ['shuttersOpen', 1],
|
|
13
|
+
'shutters-close': ['shuttersClose', 1],
|
|
14
|
+
// Cabinet doors and drawers: the panel recordings, as the marketing house plays its cabinets.
|
|
15
|
+
'panel-open': ['shuttersOpen', 0.75],
|
|
16
|
+
'panel-swing': ['doorSwing', 0.45],
|
|
17
|
+
'panel-close': ['shuttersClose', 0.75],
|
|
18
|
+
'switch-on': ['switchOn', 1],
|
|
19
|
+
'switch-off': ['switchOff', 1],
|
|
20
|
+
};
|
|
21
|
+
let subscribers = 0;
|
|
22
|
+
const handleInteractionSound = (sound) => {
|
|
23
|
+
const [name, volumeMultiplier] = INTERACTION_SOUNDS[sound];
|
|
24
|
+
playSound(name, { volumeMultiplier });
|
|
25
|
+
};
|
|
26
|
+
/** Connect core interaction cues to playback; call the returned cleanup on unmount. */
|
|
27
|
+
export function initInteractionSounds() {
|
|
28
|
+
preloadSounds();
|
|
29
|
+
if (subscribers++ === 0)
|
|
30
|
+
emitter.on('interaction:sound', handleInteractionSound);
|
|
31
|
+
let active = true;
|
|
32
|
+
return () => {
|
|
33
|
+
if (!active)
|
|
34
|
+
return;
|
|
35
|
+
active = false;
|
|
36
|
+
if (--subscribers === 0)
|
|
37
|
+
emitter.off('interaction:sound', handleInteractionSound);
|
|
38
|
+
};
|
|
39
|
+
}
|