@pascal-app/viewer 1.1.0 → 1.1.2
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 +157 -0
- 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-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/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/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/lib/daylight/room-map.d.ts +29 -4
- package/dist/lib/daylight/room-map.d.ts.map +1 -1
- package/dist/lib/daylight/room-map.js +219 -36
- package/dist/lib/daylight/room-scene.d.ts.map +1 -1
- package/dist/lib/daylight/room-scene.js +9 -3
- package/dist/lib/daylight/rooms.d.ts +15 -6
- package/dist/lib/daylight/rooms.d.ts.map +1 -1
- package/dist/lib/daylight/rooms.js +49 -9
- package/dist/lib/measurement-presentation.d.ts +2 -0
- package/dist/lib/measurement-presentation.d.ts.map +1 -1
- package/dist/lib/measurement-presentation.js +6 -0
- 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 +6 -0
- package/dist/lib/viewer-config.d.ts.map +1 -1
- package/dist/lib/viewer-config.js +2 -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/systems/roof/roof-system.d.ts.map +1 -1
- package/dist/systems/roof/roof-system.js +27 -13
- 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":"room-scene.d.ts","sourceRoot":"","sources":["../../../src/lib/daylight/room-scene.ts"],"names":[],"mappings":"AAQA,OAAO,EAAoD,KAAK,QAAQ,EAAE,OAAO,EAAE,MAAM,OAAO,CAAA;AAMhG,OAAO,KAAK,EAAE,QAAQ,EAAmB,cAAc,EAAY,MAAM,SAAS,CAAA;AAGlF;;;GAGG;AAEH,mGAAmG;AACnG,MAAM,MAAM,aAAa,GAAG;IAC1B,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,0BAA0B;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,gBAAgB,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAA;IAC3C,6DAA6D;IAC7D,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,QAAQ,CAAA;IACjB,yFAAyF;IACzF,IAAI,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAC3F,iBAAiB,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAA;CAC3C,CAAA;AAED,KAAK,QAAQ,GAAG;IACd,MAAM,EAAE,MAAM,QAAQ,CAAC,aAAa,CAAC,CAAA;IACrC,SAAS,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,MAAM,CAAA;CAC5C,CAAA;AAED,8FAA8F;AAC9F,eAAO,MAAM,SAAS,eAAsB,CAAA;AAU5C,oEAAoE;AACpE,wBAAgB,SAAS,IAAI,QAAQ,EAAE,CAuBtC;AAeD,6CAA6C;AAC7C,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAK3D;AAkCD,uFAAuF;AACvF,wBAAgB,aAAa,CAAC,cAAc,EAAE,OAAO,GAAG,cAAc,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"room-scene.d.ts","sourceRoot":"","sources":["../../../src/lib/daylight/room-scene.ts"],"names":[],"mappings":"AAQA,OAAO,EAAoD,KAAK,QAAQ,EAAE,OAAO,EAAE,MAAM,OAAO,CAAA;AAMhG,OAAO,KAAK,EAAE,QAAQ,EAAmB,cAAc,EAAY,MAAM,SAAS,CAAA;AAGlF;;;GAGG;AAEH,mGAAmG;AACnG,MAAM,MAAM,aAAa,GAAG;IAC1B,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,0BAA0B;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,gBAAgB,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAA;IAC3C,6DAA6D;IAC7D,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,QAAQ,CAAA;IACjB,yFAAyF;IACzF,IAAI,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAC3F,iBAAiB,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAA;CAC3C,CAAA;AAED,KAAK,QAAQ,GAAG;IACd,MAAM,EAAE,MAAM,QAAQ,CAAC,aAAa,CAAC,CAAA;IACrC,SAAS,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,MAAM,CAAA;CAC5C,CAAA;AAED,8FAA8F;AAC9F,eAAO,MAAM,SAAS,eAAsB,CAAA;AAU5C,oEAAoE;AACpE,wBAAgB,SAAS,IAAI,QAAQ,EAAE,CAuBtC;AAeD,6CAA6C;AAC7C,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAK3D;AAkCD,uFAAuF;AACvF,wBAAgB,aAAa,CAAC,cAAc,EAAE,OAAO,GAAG,cAAc,GAAG,IAAI,CA0E5E;AAED,gGAAgG;AAChG,wBAAgB,gBAAgB,IAAI,CAAC,QAAQ,GAAG,SAAS,CAAC,EAAE,CAE3D;AAqBD,yEAAyE;AACzE,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI,GAAG,QAAQ,EAAE,CAEnE;AAED,oFAAoF;AACpF,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAanD;AASD,0FAA0F;AAC1F,wBAAgB,cAAc,CAAC,IAAI,EAAE,QAAQ,EAAE,cAAc,EAAE,OAAO,GAAG,cAAc,GAAG,IAAI,CA8E7F;AAiED;;;;;GAKG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CA2CvC;AAED,8DAA8D;AAC9D,wBAAgB,mBAAmB,IAAI,IAAI,CAM1C"}
|
|
@@ -138,9 +138,12 @@ export function liveRoomScene(virtualLampsOn) {
|
|
|
138
138
|
const walls = [];
|
|
139
139
|
for (const id of sceneRegistry.byType.wall ?? []) {
|
|
140
140
|
const object = sceneRegistry.nodes.get(id);
|
|
141
|
+
if (!object)
|
|
142
|
+
continue;
|
|
143
|
+
const wallLevel = levelIndex.get(nodes[id]?.parentId ?? '') ?? 0;
|
|
141
144
|
// Doors, windows and items hang under their wall: a closed leaf mustn't close its doorway.
|
|
142
|
-
|
|
143
|
-
walls.push(
|
|
145
|
+
for (const mesh of meshesOf(object, (child) => registered.has(child)))
|
|
146
|
+
walls.push({ object: mesh, levelIndex: wallLevel });
|
|
144
147
|
}
|
|
145
148
|
const openings = [];
|
|
146
149
|
for (const kind of OPENING_TYPES) {
|
|
@@ -266,7 +269,10 @@ export function bakedRoomScene(root, virtualLampsOn) {
|
|
|
266
269
|
const kind = object.userData.kind;
|
|
267
270
|
return kind === 'door' || kind === 'window' || kind === 'item';
|
|
268
271
|
};
|
|
269
|
-
const walls = wallRoots.flatMap((object) =>
|
|
272
|
+
const walls = wallRoots.flatMap((object) => {
|
|
273
|
+
const levelIndex = levelOf(object).index;
|
|
274
|
+
return meshesOf(object, isIdentity).map((mesh) => ({ object: mesh, levelIndex }));
|
|
275
|
+
});
|
|
270
276
|
const bounds = new Box3();
|
|
271
277
|
for (const zone of zones)
|
|
272
278
|
for (const [x, z] of zone.polygon)
|
|
@@ -4,8 +4,8 @@ import { type MapLevel, RoomMap } from './room-map';
|
|
|
4
4
|
* "Room-aware" interior light, the game-engine way (ported from the enhanced viewer):
|
|
5
5
|
*
|
|
6
6
|
* - Zone polygons are rasterized per level into a top-down room-id map (10 cm cells). A fragment
|
|
7
|
-
* finds its room
|
|
8
|
-
* light never leaks through walls and there are no shadow maps to pay for.
|
|
7
|
+
* finds its room a step off itself along its normal — a wall face looks *into* the room it
|
|
8
|
+
* faces, so light never leaks through walls and there are no shadow maps to pay for.
|
|
9
9
|
* - Each room owns its lamps and window "portals": glass rectangles that emit sky (+ ground
|
|
10
10
|
* bounce) radiance inwards with an analytic rectangle form factor, plus the internally
|
|
11
11
|
* reflected component (split-flux) and the sky patch on the floor. Enclosed rooms see only
|
|
@@ -65,8 +65,14 @@ export type RoomSceneInput = {
|
|
|
65
65
|
object: Object3D;
|
|
66
66
|
kind: 'ceiling' | 'roof' | 'slab';
|
|
67
67
|
}[];
|
|
68
|
-
/**
|
|
69
|
-
|
|
68
|
+
/**
|
|
69
|
+
* Wall meshes only (openings and their parts excluded), each with its level: walkable-opening
|
|
70
|
+
* rays test them, and their footprints keep rooms from reaching past a wall's far face.
|
|
71
|
+
*/
|
|
72
|
+
walls: {
|
|
73
|
+
object: Object3D;
|
|
74
|
+
levelIndex: number;
|
|
75
|
+
}[];
|
|
70
76
|
openings: RoomOpeningRoot[];
|
|
71
77
|
lamps: RoomLamp[];
|
|
72
78
|
/** Whether rooms without lamps of their own get their virtual ceiling lamp lit. */
|
|
@@ -235,8 +241,11 @@ export declare class RoomLighting {
|
|
|
235
241
|
/** Room index (−1 outside) at a world-space position (live heights). */
|
|
236
242
|
roomAtNode: import("three/tsl").FnNode<[any], import("three/webgpu").VarNode<"int", import("three/webgpu").ConstNode<"int", number>>>;
|
|
237
243
|
/**
|
|
238
|
-
* The room a surface faces
|
|
239
|
-
*
|
|
244
|
+
* The room a surface faces, probed off it along its normal: 30 cm sideways, 18 cm up or down.
|
|
245
|
+
* Sideways it must clear a wall from inside it: a shutter, a door leaf or a pane set half-way
|
|
246
|
+
* into a 30 cm wall looks out past the wall's face, not into the cells along it, where a wall
|
|
247
|
+
* off the grid axes reads as room and outside in turn. One node per material: its lighting and
|
|
248
|
+
* its exterior mask share the lookup.
|
|
240
249
|
*/
|
|
241
250
|
probeRoomNode(): N;
|
|
242
251
|
/** E' = Emax·(1 − e^(−E/Emax)), on luminance, hue kept — near-field hot spots compress, never blow out. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rooms.d.ts","sourceRoot":"","sources":["../../../src/lib/daylight/rooms.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,IAAI,EAEJ,KAAK,MAAM,EACX,KAAK,EASL,KAAK,QAAQ,EAGb,SAAS,EAGT,OAAO,EACP,OAAO,EACR,MAAM,OAAO,CAAA;AAsBd,OAAO,EAAQ,KAAK,QAAQ,
|
|
1
|
+
{"version":3,"file":"rooms.d.ts","sourceRoot":"","sources":["../../../src/lib/daylight/rooms.ts"],"names":[],"mappings":"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"}
|
|
@@ -131,7 +131,7 @@ export class RoomLighting {
|
|
|
131
131
|
level: room.levelIndex,
|
|
132
132
|
polygon: room.zone.polygon,
|
|
133
133
|
holes: room.zone.holes,
|
|
134
|
-
})), openings.walk);
|
|
134
|
+
})), openings.walk, wallFootprints(input.walls));
|
|
135
135
|
this.openings = openings.finish();
|
|
136
136
|
// ---- lamps ---------------------------------------------------------------------------
|
|
137
137
|
for (const lamp of input.lamps) {
|
|
@@ -676,12 +676,14 @@ export class RoomLighting {
|
|
|
676
676
|
.map((o) => ({ id: o.id, box: new Box3().setFromObject(o.object) }));
|
|
677
677
|
const doorHoles = doors.map((door) => door.box.clone().expandByScalar(0.05));
|
|
678
678
|
ray.far = 0.9;
|
|
679
|
-
const wallGrid = new MeshGrid(input.walls);
|
|
679
|
+
const wallGrid = new MeshGrid(input.walls.map((wall) => wall.object));
|
|
680
680
|
const samples = new Map();
|
|
681
681
|
const v = new Vector3();
|
|
682
682
|
const dirV = new Vector3();
|
|
683
683
|
const walk = (tile) => {
|
|
684
684
|
const { cells, stride, i0, j0, x0, z0, ci0, cj0, level: l } = tile;
|
|
685
|
+
// The tile lies in its building's turned frame: points and directions go back to the world.
|
|
686
|
+
const [cos, sin] = tile.turn;
|
|
685
687
|
const floorY = this.levels[l]?.y ?? 0;
|
|
686
688
|
const visit = (i, j, axis) => {
|
|
687
689
|
const di = axis === 'x' ? 1 : 0;
|
|
@@ -699,9 +701,11 @@ export class RoomLighting {
|
|
|
699
701
|
return;
|
|
700
702
|
if (b < 0 && !this.rooms[a].enclosed)
|
|
701
703
|
return;
|
|
702
|
-
const
|
|
703
|
-
const
|
|
704
|
-
|
|
704
|
+
const mx = x0 + (i + 0.5 + di * 0.5) * CELL;
|
|
705
|
+
const mz = z0 + (j + 0.5 + dj * 0.5) * CELL;
|
|
706
|
+
const x = mx * cos - mz * sin;
|
|
707
|
+
const z = mx * sin + mz * cos;
|
|
708
|
+
dirV.set(di * cos - dj * sin, 0, di * sin + dj * cos);
|
|
705
709
|
for (const h of [0.35, 1.6]) {
|
|
706
710
|
v.set(x, floorY + h, z).addScaledVector(dirV, -0.45);
|
|
707
711
|
ray.set(v, dirV);
|
|
@@ -722,7 +726,7 @@ export class RoomLighting {
|
|
|
722
726
|
samples.set(key, s);
|
|
723
727
|
}
|
|
724
728
|
s.pts.push(new Vector3(x, floorY, z));
|
|
725
|
-
s.facing.push(
|
|
729
|
+
s.facing.push(dirV.clone().multiplyScalar(dir));
|
|
726
730
|
};
|
|
727
731
|
// Each edge belongs to the tile of the cell before it. A uniform tile has none inside: only
|
|
728
732
|
// its borders with the next tiles can hold one.
|
|
@@ -836,11 +840,14 @@ export class RoomLighting {
|
|
|
836
840
|
/** Room index (−1 outside) at a world-space position (live heights). */
|
|
837
841
|
roomAtNode = Fn(([p]) => this.map.roomAtNode(p));
|
|
838
842
|
/**
|
|
839
|
-
* The room a surface faces
|
|
840
|
-
*
|
|
843
|
+
* The room a surface faces, probed off it along its normal: 30 cm sideways, 18 cm up or down.
|
|
844
|
+
* Sideways it must clear a wall from inside it: a shutter, a door leaf or a pane set half-way
|
|
845
|
+
* into a 30 cm wall looks out past the wall's face, not into the cells along it, where a wall
|
|
846
|
+
* off the grid axes reads as room and outside in turn. One node per material: its lighting and
|
|
847
|
+
* its exterior mask share the lookup.
|
|
841
848
|
*/
|
|
842
849
|
probeRoomNode() {
|
|
843
|
-
return this.roomAtNode(positionWorld.add(normalWorld.mul(0.18)));
|
|
850
|
+
return this.roomAtNode(positionWorld.add(normalWorld.mul(vec3(0.3, 0.18, 0.3))));
|
|
844
851
|
}
|
|
845
852
|
/** E' = Emax·(1 − e^(−E/Emax)), on luminance, hue kept — near-field hot spots compress, never blow out. */
|
|
846
853
|
softClampLamps(e) {
|
|
@@ -1107,6 +1114,39 @@ export class RoomLighting {
|
|
|
1107
1114
|
});
|
|
1108
1115
|
}
|
|
1109
1116
|
// ---- helpers -------------------------------------------------------------------------------
|
|
1117
|
+
/**
|
|
1118
|
+
* The walls' footprints per level: every triangle that has an area seen from above (tops,
|
|
1119
|
+
* bottoms, lintels, sills), in world XZ. Read from the vertices as they are now, like `MeshGrid`.
|
|
1120
|
+
*/
|
|
1121
|
+
function wallFootprints(walls) {
|
|
1122
|
+
const byLevel = new Map();
|
|
1123
|
+
const a = new Vector3();
|
|
1124
|
+
const b = new Vector3();
|
|
1125
|
+
const c = new Vector3();
|
|
1126
|
+
for (const { object, levelIndex } of walls) {
|
|
1127
|
+
const mesh = object;
|
|
1128
|
+
const position = mesh.isMesh ? mesh.geometry?.getAttribute('position') : undefined;
|
|
1129
|
+
if (!position || position.count === 0)
|
|
1130
|
+
continue;
|
|
1131
|
+
let triangles = byLevel.get(levelIndex);
|
|
1132
|
+
if (!triangles) {
|
|
1133
|
+
triangles = [];
|
|
1134
|
+
byLevel.set(levelIndex, triangles);
|
|
1135
|
+
}
|
|
1136
|
+
const index = mesh.geometry.getIndex();
|
|
1137
|
+
const count = index ? index.count : position.count;
|
|
1138
|
+
for (let k = 0; k + 2 < count; k += 3) {
|
|
1139
|
+
a.fromBufferAttribute(position, index ? index.getX(k) : k).applyMatrix4(mesh.matrixWorld);
|
|
1140
|
+
b.fromBufferAttribute(position, index ? index.getX(k + 1) : k + 1).applyMatrix4(mesh.matrixWorld);
|
|
1141
|
+
c.fromBufferAttribute(position, index ? index.getX(k + 2) : k + 2).applyMatrix4(mesh.matrixWorld);
|
|
1142
|
+
// Faces seen edge-on from above (the wall's sides) add nothing to its footprint.
|
|
1143
|
+
if (Math.abs((b.x - a.x) * (c.z - a.z) - (c.x - a.x) * (b.z - a.z)) < 1e-6)
|
|
1144
|
+
continue;
|
|
1145
|
+
triangles.push(a.x, a.z, b.x, b.z, c.x, c.z);
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
return [...byLevel].map(([level, triangles]) => ({ level, triangles }));
|
|
1149
|
+
}
|
|
1110
1150
|
/**
|
|
1111
1151
|
* Ray hits against the meshes' geometry itself, nearest first. Picking overrides (walls hidden
|
|
1112
1152
|
* by the cutaway, ceiling caps, batched originals) mustn't open rooms to the sky or invent
|
|
@@ -2,4 +2,6 @@ export declare const MEASUREMENT_ACTIVE_COLOR = "#6366f1";
|
|
|
2
2
|
export declare const MEASUREMENT_DANGLING_COLOR = "#dc2626";
|
|
3
3
|
export declare const MEASUREMENT_PERSISTENT_COLOR = "#111827";
|
|
4
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;
|
|
5
7
|
//# sourceMappingURL=measurement-presentation.d.ts.map
|
|
@@ -1 +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"}
|
|
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"}
|
|
@@ -6,3 +6,9 @@ export function measurementPresentationColor(dangling, active) {
|
|
|
6
6
|
return MEASUREMENT_DANGLING_COLOR;
|
|
7
7
|
return active ? MEASUREMENT_ACTIVE_COLOR : MEASUREMENT_PERSISTENT_COLOR;
|
|
8
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
|
+
}
|
|
@@ -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
|
+
}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
export type ViewerConfig = {
|
|
2
2
|
assetsBaseUrl?: string;
|
|
3
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;
|
|
4
8
|
decoders?: {
|
|
5
9
|
dracoPath?: string;
|
|
6
10
|
basisPath?: string;
|
|
@@ -13,6 +17,8 @@ export declare function configureViewer(options: ViewerConfig): void;
|
|
|
13
17
|
export declare function getViewerConfig(): {
|
|
14
18
|
assetsBaseUrl: string;
|
|
15
19
|
storageUrl: string | undefined;
|
|
20
|
+
sfxBaseUrl: string;
|
|
21
|
+
iconsBaseUrl: string;
|
|
16
22
|
decoders: {
|
|
17
23
|
dracoPath: string;
|
|
18
24
|
basisPath: string;
|
|
@@ -1 +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,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,QAAQ;QACN,SAAS;QAET,SAAS;;EAKd"}
|
|
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"}
|
|
@@ -12,6 +12,8 @@ export function getViewerConfig() {
|
|
|
12
12
|
ASSETS_CDN_URL),
|
|
13
13
|
storageUrl: config.storageUrl ??
|
|
14
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`,
|
|
15
17
|
decoders: {
|
|
16
18
|
dracoPath: config.decoders?.dracoPath ?? 'https://www.gstatic.com/draco/versioned/decoders/1.5.5/',
|
|
17
19
|
basisPath: config.decoders?.basisPath ??
|
|
@@ -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
|
+
}
|