@pascal-app/viewer 1.0.0-beta.4 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (265) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +107 -0
  3. package/dist/capture/asset-url.d.ts +2 -0
  4. package/dist/capture/asset-url.d.ts.map +1 -0
  5. package/dist/capture/asset-url.js +13 -0
  6. package/dist/capture/capture-runtime.d.ts +43 -0
  7. package/dist/capture/capture-runtime.d.ts.map +1 -0
  8. package/dist/capture/capture-runtime.js +228 -0
  9. package/dist/capture/frame.d.ts +4 -0
  10. package/dist/capture/frame.d.ts.map +1 -0
  11. package/dist/capture/frame.js +21 -0
  12. package/dist/capture/index.d.ts +12 -0
  13. package/dist/capture/index.d.ts.map +1 -0
  14. package/dist/capture/index.js +11 -0
  15. package/dist/capture/layer-visibility.d.ts +5 -0
  16. package/dist/capture/layer-visibility.d.ts.map +1 -0
  17. package/dist/capture/layer-visibility.js +11 -0
  18. package/dist/capture/layers/clay-matcap.d.ts +3 -0
  19. package/dist/capture/layers/clay-matcap.d.ts.map +1 -0
  20. package/dist/capture/layers/clay-matcap.js +26 -0
  21. package/dist/capture/layers/device-motion-layer.d.ts +7 -0
  22. package/dist/capture/layers/device-motion-layer.d.ts.map +1 -0
  23. package/dist/capture/layers/device-motion-layer.js +78 -0
  24. package/dist/capture/layers/point-cloud-layer.d.ts +15 -0
  25. package/dist/capture/layers/point-cloud-layer.d.ts.map +1 -0
  26. package/dist/capture/layers/point-cloud-layer.js +106 -0
  27. package/dist/capture/layers/room-model-layer.d.ts +9 -0
  28. package/dist/capture/layers/room-model-layer.d.ts.map +1 -0
  29. package/dist/capture/layers/room-model-layer.js +71 -0
  30. package/dist/capture/layers/surface-mesh-data.d.ts +9 -0
  31. package/dist/capture/layers/surface-mesh-data.d.ts.map +1 -0
  32. package/dist/capture/layers/surface-mesh-data.js +74 -0
  33. package/dist/capture/layers/surface-mesh-layer.d.ts +7 -0
  34. package/dist/capture/layers/surface-mesh-layer.d.ts.map +1 -0
  35. package/dist/capture/layers/surface-mesh-layer.js +16 -0
  36. package/dist/capture/preview.d.ts +3 -0
  37. package/dist/capture/preview.d.ts.map +1 -0
  38. package/dist/capture/preview.js +2 -0
  39. package/dist/capture/source-state.d.ts +22 -0
  40. package/dist/capture/source-state.d.ts.map +1 -0
  41. package/dist/capture/source-state.js +182 -0
  42. package/dist/capture/stream-rendering.d.ts +14 -0
  43. package/dist/capture/stream-rendering.d.ts.map +1 -0
  44. package/dist/capture/stream-rendering.js +69 -0
  45. package/dist/capture/trajectory.d.ts +20 -0
  46. package/dist/capture/trajectory.d.ts.map +1 -0
  47. package/dist/capture/trajectory.js +77 -0
  48. package/dist/components/viewer/batched-mesh-spike.d.ts +14 -0
  49. package/dist/components/viewer/batched-mesh-spike.d.ts.map +1 -0
  50. package/dist/components/viewer/batched-mesh-spike.js +64 -0
  51. package/dist/components/viewer/frame-limiter.d.ts +11 -0
  52. package/dist/components/viewer/frame-limiter.d.ts.map +1 -1
  53. package/dist/components/viewer/frame-limiter.js +59 -18
  54. package/dist/components/viewer/index.d.ts +15 -0
  55. package/dist/components/viewer/index.d.ts.map +1 -1
  56. package/dist/components/viewer/index.js +74 -82
  57. package/dist/components/viewer/lights.d.ts.map +1 -1
  58. package/dist/components/viewer/lights.js +123 -89
  59. package/dist/components/viewer/perf-monitor.d.ts +6 -1
  60. package/dist/components/viewer/perf-monitor.d.ts.map +1 -1
  61. package/dist/components/viewer/perf-monitor.js +306 -115
  62. package/dist/components/viewer/perf-panel.d.ts +3 -0
  63. package/dist/components/viewer/perf-panel.d.ts.map +1 -0
  64. package/dist/components/viewer/perf-panel.js +178 -0
  65. package/dist/components/viewer/pointer-raycast-layers.d.ts +15 -0
  66. package/dist/components/viewer/pointer-raycast-layers.d.ts.map +1 -0
  67. package/dist/components/viewer/pointer-raycast-layers.js +28 -0
  68. package/dist/components/viewer/post-processing.d.ts.map +1 -1
  69. package/dist/components/viewer/post-processing.js +124 -83
  70. package/dist/components/viewer/registered-systems.d.ts +14 -5
  71. package/dist/components/viewer/registered-systems.d.ts.map +1 -1
  72. package/dist/components/viewer/registered-systems.js +22 -10
  73. package/dist/components/viewer/scene-atmosphere.d.ts +30 -0
  74. package/dist/components/viewer/scene-atmosphere.d.ts.map +1 -0
  75. package/dist/components/viewer/scene-atmosphere.js +89 -0
  76. package/dist/components/viewer/scene-environment.d.ts.map +1 -1
  77. package/dist/components/viewer/scene-environment.js +19 -5
  78. package/dist/components/viewer/scene-ground-replacement.d.ts +5 -0
  79. package/dist/components/viewer/scene-ground-replacement.d.ts.map +1 -0
  80. package/dist/components/viewer/scene-ground-replacement.js +35 -0
  81. package/dist/components/viewer/selection-manager.d.ts.map +1 -1
  82. package/dist/components/viewer/selection-manager.js +7 -2
  83. package/dist/components/viewer/unsupported-gpu-fallback.d.ts +2 -0
  84. package/dist/components/viewer/unsupported-gpu-fallback.d.ts.map +1 -0
  85. package/dist/components/viewer/unsupported-gpu-fallback.js +4 -0
  86. package/dist/components/viewer/viewer-camera.d.ts.map +1 -1
  87. package/dist/components/viewer/viewer-camera.js +4 -1
  88. package/dist/components/viewer/viewer-presentations.d.ts +67 -0
  89. package/dist/components/viewer/viewer-presentations.d.ts.map +1 -0
  90. package/dist/components/viewer/viewer-presentations.js +120 -0
  91. package/dist/hooks/use-library-materials-version.d.ts +7 -0
  92. package/dist/hooks/use-library-materials-version.d.ts.map +1 -0
  93. package/dist/hooks/use-library-materials-version.js +10 -0
  94. package/dist/hooks/use-node-events.d.ts.map +1 -1
  95. package/dist/hooks/use-node-events.js +1 -0
  96. package/dist/index.d.ts +20 -8
  97. package/dist/index.d.ts.map +1 -1
  98. package/dist/index.js +19 -7
  99. package/dist/lib/csg-utils.d.ts +1 -0
  100. package/dist/lib/csg-utils.d.ts.map +1 -1
  101. package/dist/lib/csg-utils.js +6 -1
  102. package/dist/lib/dispose-object3d.d.ts +4 -0
  103. package/dist/lib/dispose-object3d.d.ts.map +1 -0
  104. package/dist/lib/dispose-object3d.js +27 -0
  105. package/dist/lib/geometry-groups.d.ts +17 -0
  106. package/dist/lib/geometry-groups.d.ts.map +1 -0
  107. package/dist/lib/geometry-groups.js +53 -0
  108. package/dist/lib/gpu-perf.d.ts +0 -2
  109. package/dist/lib/gpu-perf.d.ts.map +1 -1
  110. package/dist/lib/gpu-perf.js +7 -21
  111. package/dist/lib/isolation.d.ts +8 -8
  112. package/dist/lib/isolation.d.ts.map +1 -1
  113. package/dist/lib/isolation.js +18 -30
  114. package/dist/lib/layer-pass.d.ts +28 -0
  115. package/dist/lib/layer-pass.d.ts.map +1 -0
  116. package/dist/lib/layer-pass.js +254 -0
  117. package/dist/lib/layers.d.ts +16 -0
  118. package/dist/lib/layers.d.ts.map +1 -1
  119. package/dist/lib/layers.js +18 -0
  120. package/dist/lib/materials.d.ts +12 -0
  121. package/dist/lib/materials.d.ts.map +1 -1
  122. package/dist/lib/materials.js +51 -17
  123. package/dist/lib/merged-outline-node.d.ts +17 -8
  124. package/dist/lib/merged-outline-node.d.ts.map +1 -1
  125. package/dist/lib/merged-outline-node.js +194 -52
  126. package/dist/lib/perf-actions.d.ts +55 -0
  127. package/dist/lib/perf-actions.d.ts.map +1 -0
  128. package/dist/lib/perf-actions.js +211 -0
  129. package/dist/lib/perf-observers.d.ts +2 -0
  130. package/dist/lib/perf-observers.d.ts.map +1 -0
  131. package/dist/lib/perf-observers.js +17 -0
  132. package/dist/lib/perf-panel-store.d.ts +71 -0
  133. package/dist/lib/perf-panel-store.d.ts.map +1 -0
  134. package/dist/lib/perf-panel-store.js +29 -0
  135. package/dist/lib/perf-tracks.d.ts +43 -0
  136. package/dist/lib/perf-tracks.d.ts.map +1 -0
  137. package/dist/lib/perf-tracks.js +113 -0
  138. package/dist/lib/pointer-events.d.ts +7 -0
  139. package/dist/lib/pointer-events.d.ts.map +1 -0
  140. package/dist/lib/pointer-events.js +680 -0
  141. package/dist/lib/post-processing-resources.d.ts +12 -0
  142. package/dist/lib/post-processing-resources.d.ts.map +1 -0
  143. package/dist/lib/post-processing-resources.js +19 -0
  144. package/dist/lib/renderer-capability.d.ts +56 -0
  145. package/dist/lib/renderer-capability.d.ts.map +1 -0
  146. package/dist/lib/renderer-capability.js +116 -0
  147. package/dist/lib/scene-visibility.d.ts +15 -0
  148. package/dist/lib/scene-visibility.d.ts.map +1 -0
  149. package/dist/lib/scene-visibility.js +69 -0
  150. package/dist/lib/shadow-only.d.ts +16 -0
  151. package/dist/lib/shadow-only.d.ts.map +1 -1
  152. package/dist/lib/shadow-only.js +8 -17
  153. package/dist/lib/snapshot-pipeline.d.ts +9 -0
  154. package/dist/lib/snapshot-pipeline.d.ts.map +1 -1
  155. package/dist/lib/snapshot-pipeline.js +33 -9
  156. package/dist/store/use-viewer.d.ts +7 -6
  157. package/dist/store/use-viewer.d.ts.map +1 -1
  158. package/dist/systems/ceiling/ceiling-system.js +1 -1
  159. package/dist/systems/door/door-animation-system.d.ts.map +1 -1
  160. package/dist/systems/door/door-animation-system.js +6 -9
  161. package/dist/systems/door/door-system.d.ts.map +1 -1
  162. package/dist/systems/door/door-system.js +13 -2
  163. package/dist/systems/floor-elevation/floor-elevation-system.d.ts.map +1 -1
  164. package/dist/systems/floor-elevation/floor-elevation-system.js +9 -0
  165. package/dist/systems/geometry/geometry-system.d.ts.map +1 -1
  166. package/dist/systems/geometry/geometry-system.js +5 -28
  167. package/dist/systems/level/level-system.d.ts.map +1 -1
  168. package/dist/systems/level/level-system.js +8 -2
  169. package/dist/systems/level/level-utils.d.ts +9 -0
  170. package/dist/systems/level/level-utils.d.ts.map +1 -1
  171. package/dist/systems/level/level-utils.js +14 -0
  172. package/dist/systems/perf-action-settle/perf-action-settle-system.d.ts +8 -0
  173. package/dist/systems/perf-action-settle/perf-action-settle-system.d.ts.map +1 -0
  174. package/dist/systems/perf-action-settle/perf-action-settle-system.js +32 -0
  175. package/dist/systems/roof/roof-system.d.ts.map +1 -1
  176. package/dist/systems/roof/roof-system.js +1196 -58
  177. package/dist/systems/scan/scan-system.js +6 -5
  178. package/dist/systems/slab/slab-system.d.ts.map +1 -1
  179. package/dist/systems/slab/slab-system.js +1 -2
  180. package/dist/systems/stair/stair-system.d.ts.map +1 -1
  181. package/dist/systems/stair/stair-system.js +9 -8
  182. package/dist/systems/surface-hole-geometry.d.ts +1 -1
  183. package/dist/systems/surface-hole-geometry.d.ts.map +1 -1
  184. package/dist/systems/surface-hole-geometry.js +1 -1
  185. package/dist/systems/wall/level-miter-cache.d.ts +10 -0
  186. package/dist/systems/wall/level-miter-cache.d.ts.map +1 -0
  187. package/dist/systems/wall/level-miter-cache.js +40 -0
  188. package/dist/systems/wall/wall-build-lifecycle.d.ts +9 -0
  189. package/dist/systems/wall/wall-build-lifecycle.d.ts.map +1 -0
  190. package/dist/systems/wall/wall-build-lifecycle.js +74 -0
  191. package/dist/systems/wall/wall-cutout-cache.d.ts +57 -0
  192. package/dist/systems/wall/wall-cutout-cache.d.ts.map +1 -0
  193. package/dist/systems/wall/wall-cutout-cache.js +304 -0
  194. package/dist/systems/wall/wall-cutout.d.ts +24 -1
  195. package/dist/systems/wall/wall-cutout.d.ts.map +1 -1
  196. package/dist/systems/wall/wall-cutout.js +33 -140
  197. package/dist/systems/wall/wall-material-variant.d.ts +31 -0
  198. package/dist/systems/wall/wall-material-variant.d.ts.map +1 -0
  199. package/dist/systems/wall/wall-material-variant.js +10 -0
  200. package/dist/systems/wall/wall-materials.d.ts +6 -0
  201. package/dist/systems/wall/wall-materials.d.ts.map +1 -1
  202. package/dist/systems/wall/wall-materials.js +29 -13
  203. package/dist/systems/wall/wall-placeholder-sweep.d.ts +50 -0
  204. package/dist/systems/wall/wall-placeholder-sweep.d.ts.map +1 -0
  205. package/dist/systems/wall/wall-placeholder-sweep.js +51 -0
  206. package/dist/systems/wall/wall-rebuild-notifications.d.ts +5 -0
  207. package/dist/systems/wall/wall-rebuild-notifications.d.ts.map +1 -0
  208. package/dist/systems/wall/wall-rebuild-notifications.js +23 -0
  209. package/dist/systems/wall/wall-system.d.ts +13 -2
  210. package/dist/systems/wall/wall-system.d.ts.map +1 -1
  211. package/dist/systems/wall/wall-system.js +413 -148
  212. package/dist/systems/window/window-animation-system.d.ts.map +1 -1
  213. package/dist/systems/window/window-animation-system.js +9 -8
  214. package/dist/systems/window/window-system.d.ts +1 -0
  215. package/dist/systems/window/window-system.d.ts.map +1 -1
  216. package/dist/systems/window/window-system.js +16 -2
  217. package/package.json +18 -3
  218. package/dist/components/viewer/scene-bvh.test.d.ts +0 -2
  219. package/dist/components/viewer/scene-bvh.test.d.ts.map +0 -1
  220. package/dist/components/viewer/scene-bvh.test.js +0 -13
  221. package/dist/lib/csg-utils.test.d.ts +0 -2
  222. package/dist/lib/csg-utils.test.d.ts.map +0 -1
  223. package/dist/lib/csg-utils.test.js +0 -45
  224. package/dist/lib/materials.test.d.ts +0 -2
  225. package/dist/lib/materials.test.d.ts.map +0 -1
  226. package/dist/lib/materials.test.js +0 -25
  227. package/dist/lib/merged-outline-node.test.d.ts +0 -2
  228. package/dist/lib/merged-outline-node.test.d.ts.map +0 -1
  229. package/dist/lib/merged-outline-node.test.js +0 -22
  230. package/dist/lib/polygon-union.d.ts +0 -4
  231. package/dist/lib/polygon-union.d.ts.map +0 -1
  232. package/dist/lib/polygon-union.js +0 -289
  233. package/dist/lib/polygon-union.test.d.ts +0 -2
  234. package/dist/lib/polygon-union.test.d.ts.map +0 -1
  235. package/dist/lib/polygon-union.test.js +0 -105
  236. package/dist/lib/texture-reference.test.d.ts +0 -2
  237. package/dist/lib/texture-reference.test.d.ts.map +0 -1
  238. package/dist/lib/texture-reference.test.js +0 -86
  239. package/dist/store/use-viewer.test.d.ts +0 -2
  240. package/dist/store/use-viewer.test.d.ts.map +0 -1
  241. package/dist/store/use-viewer.test.js +0 -61
  242. package/dist/systems/door/door-animation.test.d.ts +0 -2
  243. package/dist/systems/door/door-animation.test.d.ts.map +0 -1
  244. package/dist/systems/door/door-animation.test.js +0 -51
  245. package/dist/systems/door/door-floor-alignment.test.d.ts +0 -2
  246. package/dist/systems/door/door-floor-alignment.test.d.ts.map +0 -1
  247. package/dist/systems/door/door-floor-alignment.test.js +0 -50
  248. package/dist/systems/geometry/geometry-system.test.d.ts +0 -2
  249. package/dist/systems/geometry/geometry-system.test.d.ts.map +0 -1
  250. package/dist/systems/geometry/geometry-system.test.js +0 -30
  251. package/dist/systems/slab/slab-system.test.d.ts +0 -2
  252. package/dist/systems/slab/slab-system.test.d.ts.map +0 -1
  253. package/dist/systems/slab/slab-system.test.js +0 -102
  254. package/dist/systems/wall/opening-cutout-geometry.test.d.ts +0 -2
  255. package/dist/systems/wall/opening-cutout-geometry.test.d.ts.map +0 -1
  256. package/dist/systems/wall/opening-cutout-geometry.test.js +0 -172
  257. package/dist/systems/wall/wall-opening-cutout.test.d.ts +0 -2
  258. package/dist/systems/wall/wall-opening-cutout.test.d.ts.map +0 -1
  259. package/dist/systems/wall/wall-opening-cutout.test.js +0 -59
  260. package/dist/systems/wall/wall-support-extension.test.d.ts +0 -2
  261. package/dist/systems/wall/wall-support-extension.test.d.ts.map +0 -1
  262. package/dist/systems/wall/wall-support-extension.test.js +0 -116
  263. package/dist/systems/wall/wall-terrain-bottom.test.d.ts +0 -2
  264. package/dist/systems/wall/wall-terrain-bottom.test.d.ts.map +0 -1
  265. package/dist/systems/wall/wall-terrain-bottom.test.js +0 -34
@@ -1,16 +1,17 @@
1
- import { sceneRegistry } from '@pascal-app/core';
1
+ import { sceneRegistry, useScene } from '@pascal-app/core';
2
2
  import { useEffect } from 'react';
3
3
  import useViewer from '../../store/use-viewer';
4
4
  export const ScanSystem = () => {
5
5
  const showScans = useViewer((state) => state.showScans);
6
+ const nodes = useScene((state) => state.nodes);
6
7
  useEffect(() => {
7
8
  const scans = sceneRegistry.byType.scan || new Set();
8
9
  scans.forEach((scanId) => {
9
10
  const node = sceneRegistry.nodes.get(scanId);
10
- if (node) {
11
- node.visible = showScans;
12
- }
11
+ const scan = nodes[scanId];
12
+ if (node && scan?.type === 'scan')
13
+ node.visible = showScans && scan.visible;
13
14
  });
14
- }, [showScans]);
15
+ }, [nodes, showScans]);
15
16
  return null;
16
17
  };
@@ -1 +1 @@
1
- {"version":3,"file":"slab-system.d.ts","sourceRoot":"","sources":["../../../src/systems/slab/slab-system.tsx"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,QAAQ,EACb,KAAK,kBAAkB,EACxB,MAAM,kBAAkB,CAAA;AACzB,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAQ9B;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,kBAAkB,GAC1B,KAAK,CAAC,cAAc,CAItB"}
1
+ {"version":3,"file":"slab-system.d.ts","sourceRoot":"","sources":["../../../src/systems/slab/slab-system.tsx"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,QAAQ,EACb,KAAK,kBAAkB,EAExB,MAAM,kBAAkB,CAAA;AACzB,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAO9B;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,kBAAkB,GAC1B,KAAK,CAAC,cAAc,CAItB"}
@@ -1,6 +1,5 @@
1
- import { getRenderableSlabPolygon, pointInPolygon2D, polygonsIntersect, } from '@pascal-app/core';
1
+ import { getRenderableSlabPolygon, pointInPolygon2D, polygonsIntersect, subtractPolygonsFromPolygon, } from '@pascal-app/core';
2
2
  import * as THREE from 'three';
3
- import { subtractPolygonsFromPolygon } from '../../lib/polygon-union';
4
3
  import { mergeSurfaceHolePolygons } from '../surface-hole-geometry';
5
4
  // ============================================================================
6
5
  // SLAB GEOMETRY GENERATORS
@@ -1 +1 @@
1
- {"version":3,"file":"stair-system.d.ts","sourceRoot":"","sources":["../../../src/systems/stair/stair-system.tsx"],"names":[],"mappings":"AA0BA,eAAO,MAAM,WAAW,YAuGvB,CAAA"}
1
+ {"version":3,"file":"stair-system.d.ts","sourceRoot":"","sources":["../../../src/systems/stair/stair-system.tsx"],"names":[],"mappings":"AA2BA,eAAO,MAAM,WAAW,YAuGvB,CAAA"}
@@ -1,4 +1,4 @@
1
- import { getEffectiveNode, getFloorStackedPosition, sceneRegistry, useScene, } from '@pascal-app/core';
1
+ import { createStairFlightFromStair, getEffectiveNode, getFloorStackedPosition, sceneRegistry, useScene, } from '@pascal-app/core';
2
2
  import { useFrame } from '@react-three/fiber';
3
3
  import * as THREE from 'three';
4
4
  import { mergeGeometries } from 'three/examples/jsm/utils/BufferGeometryUtils.js';
@@ -269,15 +269,16 @@ function updateMergedStairGeometry(stairNode, group, nodes) {
269
269
  .map((childId) => nodes[childId])
270
270
  .filter((n) => n?.type === 'stair-segment')
271
271
  .map((n) => getEffectiveNode(n));
272
- if (segments.length === 0) {
273
- replaceMeshGeometry(mergedMesh, createEmptyGeometry());
274
- return;
275
- }
272
+ // A straight stair with no segments has nothing to merge and would render as
273
+ // nothing at all — the state a stair authored as curved lands in the moment
274
+ // it is switched to straight. Draw the flight its own fields describe
275
+ // instead of vanishing; it is the same flight the panel materializes.
276
+ const bodySegments = segments.length > 0 ? segments : [createStairFlightFromStair(stairNode, nodes)];
276
277
  // Compute chained transforms for segments
277
- const transforms = computeSegmentTransforms(segments);
278
+ const transforms = computeSegmentTransforms(bodySegments);
278
279
  const geometries = [];
279
- for (let i = 0; i < segments.length; i++) {
280
- const segment = segments[i];
280
+ for (let i = 0; i < bodySegments.length; i++) {
281
+ const segment = bodySegments[i];
281
282
  const transform = transforms[i];
282
283
  const absoluteHeight = transform.position[1];
283
284
  const geo = generateStairSegmentGeometry(segment, absoluteHeight);
@@ -1,3 +1,3 @@
1
- import { type Point2D } from '../lib/polygon-union';
1
+ import { type PolygonBooleanPoint2D as Point2D } from '@pascal-app/core';
2
2
  export declare function mergeSurfaceHolePolygons(holes: Point2D[][]): Point2D[][];
3
3
  //# sourceMappingURL=surface-hole-geometry.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"surface-hole-geometry.d.ts","sourceRoot":"","sources":["../../src/systems/surface-hole-geometry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,OAAO,EAAiB,MAAM,sBAAsB,CAAA;AAElE,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,GAAG,OAAO,EAAE,EAAE,CAExE"}
1
+ {"version":3,"file":"surface-hole-geometry.d.ts","sourceRoot":"","sources":["../../src/systems/surface-hole-geometry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,qBAAqB,IAAI,OAAO,EAAiB,MAAM,kBAAkB,CAAA;AAEvF,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,GAAG,OAAO,EAAE,EAAE,CAExE"}
@@ -1,4 +1,4 @@
1
- import { unionPolygons } from '../lib/polygon-union';
1
+ import { unionPolygons } from '@pascal-app/core';
2
2
  export function mergeSurfaceHolePolygons(holes) {
3
3
  return unionPolygons(holes);
4
4
  }
@@ -0,0 +1,10 @@
1
+ import { type WallMiterData, type WallNode } from '@pascal-app/core';
2
+ export declare function sameMiterInputs(a: WallNode[], b: WallNode[]): boolean;
3
+ export declare function getCachedLevelMiters(levelId: string, levelWalls: WallNode[]): WallMiterData;
4
+ /**
5
+ * The cache is module-level, so it outlives any single mount. Editor teardown
6
+ * resets the other shared singletons; without the same reset a remount in the
7
+ * same tab keeps every previous level's walls reachable.
8
+ */
9
+ export declare function clearLevelMiterCache(): void;
10
+ //# sourceMappingURL=level-miter-cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"level-miter-cache.d.ts","sourceRoot":"","sources":["../../../src/systems/wall/level-miter-cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,KAAK,aAAa,EAAE,KAAK,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAY1F,wBAAgB,eAAe,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,CAAC,EAAE,QAAQ,EAAE,GAAG,OAAO,CAoBrE;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,aAAa,CAO3F;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,IAAI,IAAI,CAE3C"}
@@ -0,0 +1,40 @@
1
+ import { calculateLevelMiters } from '@pascal-app/core';
2
+ const levelMiterCache = new Map();
3
+ export function sameMiterInputs(a, b) {
4
+ if (a.length !== b.length)
5
+ return false;
6
+ for (let i = 0; i < a.length; i++) {
7
+ const x = a[i];
8
+ const y = b[i];
9
+ if (x === y)
10
+ continue;
11
+ if (!x || !y)
12
+ return false;
13
+ if (x.id !== y.id ||
14
+ x.start[0] !== y.start[0] ||
15
+ x.start[1] !== y.start[1] ||
16
+ x.end[0] !== y.end[0] ||
17
+ x.end[1] !== y.end[1] ||
18
+ x.thickness !== y.thickness ||
19
+ x.curveOffset !== y.curveOffset) {
20
+ return false;
21
+ }
22
+ }
23
+ return true;
24
+ }
25
+ export function getCachedLevelMiters(levelId, levelWalls) {
26
+ const cached = levelMiterCache.get(levelId);
27
+ if (cached && sameMiterInputs(cached.walls, levelWalls))
28
+ return cached.data;
29
+ const data = calculateLevelMiters(levelWalls);
30
+ levelMiterCache.set(levelId, { walls: levelWalls, data });
31
+ return data;
32
+ }
33
+ /**
34
+ * The cache is module-level, so it outlives any single mount. Editor teardown
35
+ * resets the other shared singletons; without the same reset a remount in the
36
+ * same tab keeps every previous level's walls reachable.
37
+ */
38
+ export function clearLevelMiterCache() {
39
+ levelMiterCache.clear();
40
+ }
@@ -0,0 +1,9 @@
1
+ import { type PerfBatchStats } from '../../lib/perf-panel-store';
2
+ export declare const pendingAdjacentByLevel: Map<string, Set<string>>;
3
+ export declare const initiallyBuiltWalls: Set<string>;
4
+ export declare const drainStats: NonNullable<PerfBatchStats['wallDrain']>;
5
+ export declare function publishWallDrainStats(): void;
6
+ export declare function endInitialBuild(): void;
7
+ export declare function isWallInitialBuildActive(): boolean;
8
+ export declare function subscribeWallBuildInteractions(target: EventTarget | null): (() => void) | undefined;
9
+ //# sourceMappingURL=wall-build-lifecycle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wall-build-lifecycle.d.ts","sourceRoot":"","sources":["../../../src/systems/wall/wall-build-lifecycle.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,cAAc,EAA6B,MAAM,4BAA4B,CAAA;AAG3F,eAAO,MAAM,sBAAsB,0BAAiC,CAAA;AAKpE,eAAO,MAAM,mBAAmB,aAAoB,CAAA;AACpD,eAAO,MAAM,UAAU,EAAE,WAAW,CAAC,cAAc,CAAC,WAAW,CAAC,CAW/D,CAAA;AAED,wBAAgB,qBAAqB,SAGpC;AAED,wBAAgB,eAAe,SAM9B;AAED,wBAAgB,wBAAwB,IAAI,OAAO,CAuBlD;AAID,wBAAgB,8BAA8B,CAC5C,MAAM,EAAE,WAAW,GAAG,IAAI,GACzB,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAU1B"}
@@ -0,0 +1,74 @@
1
+ import { useScene } from '@pascal-app/core';
2
+ import { PERF_OVERLAY_ENABLED } from '../../lib/gpu-perf';
3
+ import { publishPerfWallDrainStats } from '../../lib/perf-panel-store';
4
+ import { beginSpan, endSpan } from '../../lib/perf-tracks';
5
+ export const pendingAdjacentByLevel = new Map();
6
+ let hydrationId = null;
7
+ let hydrationToken = null;
8
+ let initialBuildActive = false;
9
+ let initialBuildSpan = null;
10
+ export const initiallyBuiltWalls = new Set();
11
+ export const drainStats = {
12
+ initialBuildActive: false,
13
+ wallsConsumedThisFrame: 0,
14
+ budgetExits: 0,
15
+ heavyExits: 0,
16
+ drainedExits: 0,
17
+ capExits: 0,
18
+ pendingNeighbours: 0,
19
+ firstBuilds: 0,
20
+ reinvalidationBuilds: 0,
21
+ neighbourEnqueues: 0,
22
+ };
23
+ export function publishWallDrainStats() {
24
+ drainStats.initialBuildActive = initialBuildActive;
25
+ if (PERF_OVERLAY_ENABLED)
26
+ publishPerfWallDrainStats(drainStats);
27
+ }
28
+ export function endInitialBuild() {
29
+ if (!initialBuildActive)
30
+ return;
31
+ initialBuildActive = false;
32
+ endSpan(initialBuildSpan);
33
+ initialBuildSpan = null;
34
+ publishWallDrainStats();
35
+ }
36
+ export function isWallInitialBuildActive() {
37
+ const state = useScene.getState();
38
+ if (state.hydrationId !== hydrationId) {
39
+ endInitialBuild();
40
+ hydrationId = state.hydrationId;
41
+ initiallyBuiltWalls.clear();
42
+ pendingAdjacentByLevel.clear();
43
+ for (const key of Object.keys(drainStats)) {
44
+ if (key !== 'initialBuildActive')
45
+ drainStats[key] = 0;
46
+ }
47
+ publishWallDrainStats();
48
+ }
49
+ const token = state.hydrationToken;
50
+ if (token !== hydrationToken) {
51
+ endInitialBuild();
52
+ hydrationToken = token;
53
+ if (token) {
54
+ initialBuildActive = true;
55
+ initialBuildSpan = beginSpan('wall-initial-build');
56
+ publishWallDrainStats();
57
+ }
58
+ }
59
+ return initialBuildActive;
60
+ }
61
+ useScene.subscribe(() => isWallInitialBuildActive());
62
+ export function subscribeWallBuildInteractions(target) {
63
+ if (!target)
64
+ return;
65
+ const interrupt = () => useScene.getState().invalidateHydration();
66
+ const events = ['pointerdown', 'pointermove', 'wheel'];
67
+ for (const event of events)
68
+ target.addEventListener(event, interrupt, { capture: true, passive: true });
69
+ isWallInitialBuildActive();
70
+ return () => {
71
+ for (const event of events)
72
+ target.removeEventListener(event, interrupt, true);
73
+ };
74
+ }
@@ -0,0 +1,57 @@
1
+ import { type WallNode } from '@pascal-app/core';
2
+ import { type Camera, type Material, Matrix4, type Mesh, Vector3 } from 'three';
3
+ import useViewer, { type WallMode } from '../../store/use-viewer';
4
+ import { type WallMaterialVariant } from './wall-material-variant';
5
+ export declare function sameMaterialArray(a: Material | Material[], b: Material[]): boolean;
6
+ type Variant = {
7
+ key: WallMaterialVariant;
8
+ materials: Material[];
9
+ };
10
+ type CachedWall = {
11
+ mesh: Mesh;
12
+ node: WallNode;
13
+ normal: Vector3;
14
+ matrix: Matrix4;
15
+ geometry: Mesh['geometry'];
16
+ negativeFacing: boolean | undefined;
17
+ hidden: boolean | undefined;
18
+ variantKey: WallMaterialVariant | undefined;
19
+ assignedMaterials: Material | Material[] | undefined;
20
+ visibleVariant: Variant;
21
+ hiddenVariant: Variant;
22
+ };
23
+ export declare const WALL_FACING_HYSTERESIS = 0.001;
24
+ export declare function wallHiddenFromFacing(node: Pick<WallNode, 'frontSide' | 'backSide'>, mode: WallMode, negativeFacing: boolean): boolean;
25
+ export declare function wallFacingNegative(dot: number, previous: boolean | undefined): boolean;
26
+ export type WallCutoutViewerState = Pick<ReturnType<typeof useViewer.getState>, 'wallMode' | 'shading' | 'textures' | 'colorPreset' | 'sceneTheme' | 'selection' | 'previewSelectedIds' | 'hoveredId' | 'hoverHighlightMode'>;
27
+ export type WallCutoutViewerStore = {
28
+ getState: () => WallCutoutViewerState;
29
+ };
30
+ export declare class WallCutoutCache {
31
+ private readonly viewerStore;
32
+ readonly walls: Map<string, CachedWall>;
33
+ readonly rebuilt: Set<string>;
34
+ private viewer;
35
+ private nodes;
36
+ private materials;
37
+ private registryRevision;
38
+ private wallCount;
39
+ private libraryVersion;
40
+ private lastCameraPosition;
41
+ private lastCameraTarget;
42
+ private cameraDirection;
43
+ private cameraTarget;
44
+ private lastUpdateTime;
45
+ private textureVersion;
46
+ private selected;
47
+ private highlightKey;
48
+ private transformed;
49
+ constructor(viewerStore?: WallCutoutViewerStore);
50
+ subscribeLiveTransforms(): () => void;
51
+ update(camera: Camera, time: number): void;
52
+ private refreshAppearance;
53
+ private refreshNormal;
54
+ private apply;
55
+ }
56
+ export {};
57
+ //# sourceMappingURL=wall-cutout-cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wall-cutout-cache.d.ts","sourceRoot":"","sources":["../../../src/systems/wall/wall-cutout-cache.ts"],"names":[],"mappings":"AAEA,OAAO,EAWL,KAAK,QAAQ,EACd,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAE,KAAK,MAAM,EAAE,KAAK,QAAQ,EAAE,OAAO,EAAE,KAAK,IAAI,EAAiB,OAAO,EAAE,MAAM,OAAO,CAAA;AAE9F,OAAO,SAAS,EAAE,EAAE,KAAK,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AACjE,OAAO,EAA8B,KAAK,mBAAmB,EAAE,MAAM,yBAAyB,CAAA;AAQ9F,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,QAAQ,GAAG,QAAQ,EAAE,EAAE,CAAC,EAAE,QAAQ,EAAE,GAAG,OAAO,CAElF;AAgCD,KAAK,OAAO,GAAG;IAAE,GAAG,EAAE,mBAAmB,CAAC;IAAC,SAAS,EAAE,QAAQ,EAAE,CAAA;CAAE,CAAA;AAClE,KAAK,UAAU,GAAG;IAChB,IAAI,EAAE,IAAI,CAAA;IACV,IAAI,EAAE,QAAQ,CAAA;IACd,MAAM,EAAE,OAAO,CAAA;IACf,MAAM,EAAE,OAAO,CAAA;IACf,QAAQ,EAAE,IAAI,CAAC,UAAU,CAAC,CAAA;IAC1B,cAAc,EAAE,OAAO,GAAG,SAAS,CAAA;IACnC,MAAM,EAAE,OAAO,GAAG,SAAS,CAAA;IAC3B,UAAU,EAAE,mBAAmB,GAAG,SAAS,CAAA;IAC3C,iBAAiB,EAAE,QAAQ,GAAG,QAAQ,EAAE,GAAG,SAAS,CAAA;IACpD,cAAc,EAAE,OAAO,CAAA;IACvB,aAAa,EAAE,OAAO,CAAA;CACvB,CAAA;AAID,eAAO,MAAM,sBAAsB,QAAQ,CAAA;AAE3C,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,WAAW,GAAG,UAAU,CAAC,EAC9C,IAAI,EAAE,QAAQ,EACd,cAAc,EAAE,OAAO,GACtB,OAAO,CAOT;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,SAAS,GAAG,OAAO,CAGtF;AAED,MAAM,MAAM,qBAAqB,GAAG,IAAI,CACtC,UAAU,CAAC,OAAO,SAAS,CAAC,QAAQ,CAAC,EACnC,UAAU,GACV,SAAS,GACT,UAAU,GACV,aAAa,GACb,YAAY,GACZ,WAAW,GACX,oBAAoB,GACpB,WAAW,GACX,oBAAoB,CACvB,CAAA;AAED,MAAM,MAAM,qBAAqB,GAAG;IAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;CAAE,CAAA;AAE7E,qBAAa,eAAe;IAmBd,OAAO,CAAC,QAAQ,CAAC,WAAW;IAlBxC,QAAQ,CAAC,KAAK,0BAAgC;IAC9C,QAAQ,CAAC,OAAO,cAAoB;IACpC,OAAO,CAAC,MAAM,CAAmC;IACjD,OAAO,CAAC,KAAK,CAA2D;IACxE,OAAO,CAAC,SAAS,CAA+D;IAChF,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,kBAAkB,CAAgB;IAC1C,OAAO,CAAC,gBAAgB,CAAgB;IACxC,OAAO,CAAC,eAAe,CAAgB;IACvC,OAAO,CAAC,YAAY,CAAgB;IACpC,OAAO,CAAC,cAAc,CAAI;IAC1B,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,QAAQ,CAAoB;IACpC,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,WAAW,CAAoB;gBAEV,WAAW,GAAE,qBAAiC;IAE3E,uBAAuB,IAAI,MAAM,IAAI;IAWrC,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAoJ1C,OAAO,CAAC,iBAAiB;IA6CzB,OAAO,CAAC,aAAa;IAcrB,OAAO,CAAC,KAAK;CAqCd"}
@@ -0,0 +1,304 @@
1
+ // New kind-specific modules belong in nodes; viewer must not depend on nodes.
2
+ // This extends the existing viewer-owned wall cutout and material implementation.
3
+ import { getLibraryMaterialsVersion, getWallFaceBandConfig, getWallPlaneTop, resolveLevelId, resolveWallEffectiveHeight, sceneRegistry, spatialGridManager, useLiveTransforms, useScene, } from '@pascal-app/core';
4
+ import { Matrix4, Vector3 } from 'three';
5
+ import { getMaterialTextureVersion } from '../../lib/materials';
6
+ import useViewer, {} from '../../store/use-viewer';
7
+ import { resolveWallMaterialVariant } from './wall-material-variant';
8
+ import { getHoverHighlightMaterials, getMaterialsForWall, getSelectionHighlightMaterials, } from './wall-materials';
9
+ export function sameMaterialArray(a, b) {
10
+ return Array.isArray(a) && a.length === b.length && a.every((material, i) => material === b[i]);
11
+ }
12
+ /** Materialize a resolved variant from the wall's cached material set. */
13
+ function materialsForVariant(variant, materials) {
14
+ switch (variant) {
15
+ case 'visible':
16
+ return materials.visible;
17
+ case 'invisible':
18
+ return materials.invisible;
19
+ case 'translucent':
20
+ return materials.translucent;
21
+ case 'delete-visible':
22
+ return materials.deleteVisible;
23
+ case 'delete-invisible':
24
+ return materials.deleteInvisible;
25
+ case 'delete-translucent':
26
+ return materials.deleteTranslucent;
27
+ case 'selection-visible':
28
+ return getSelectionHighlightMaterials(materials.visible);
29
+ case 'selection-invisible':
30
+ return getSelectionHighlightMaterials(materials.invisible);
31
+ case 'selection-translucent':
32
+ return getSelectionHighlightMaterials(materials.translucent);
33
+ case 'hover-invisible':
34
+ return getHoverHighlightMaterials(materials.invisible);
35
+ default: {
36
+ const exhaustive = variant;
37
+ return exhaustive;
38
+ }
39
+ }
40
+ }
41
+ // About 0.06 degrees: retain the previous side at edge-on poses without
42
+ // introducing a perceptible delay when an orbit crosses a wall's plane.
43
+ export const WALL_FACING_HYSTERESIS = 0.001;
44
+ export function wallHiddenFromFacing(node, mode, negativeFacing) {
45
+ if (mode === 'up')
46
+ return false;
47
+ if (mode === 'down')
48
+ return true;
49
+ if (node.frontSide === 'interior' && node.backSide === 'interior')
50
+ return true;
51
+ return negativeFacing
52
+ ? node.frontSide === 'exterior' && node.backSide !== 'exterior'
53
+ : node.backSide === 'exterior' && node.frontSide !== 'exterior';
54
+ }
55
+ export function wallFacingNegative(dot, previous) {
56
+ if (previous === undefined)
57
+ return dot < 0;
58
+ return previous ? dot < WALL_FACING_HYSTERESIS : dot < -WALL_FACING_HYSTERESIS;
59
+ }
60
+ export class WallCutoutCache {
61
+ viewerStore;
62
+ walls = new Map();
63
+ rebuilt = new Set();
64
+ viewer;
65
+ nodes;
66
+ materials;
67
+ registryRevision = -1;
68
+ wallCount = -1;
69
+ libraryVersion = -1;
70
+ lastCameraPosition = new Vector3();
71
+ lastCameraTarget = new Vector3();
72
+ cameraDirection = new Vector3();
73
+ cameraTarget = new Vector3();
74
+ lastUpdateTime = 0;
75
+ textureVersion = -1;
76
+ selected = new Set();
77
+ highlightKey = '';
78
+ transformed = new Set();
79
+ constructor(viewerStore = useViewer) {
80
+ this.viewerStore = viewerStore;
81
+ }
82
+ subscribeLiveTransforms() {
83
+ return useLiveTransforms.subscribe((state, previous) => {
84
+ for (const [id, transform] of state.transforms) {
85
+ if (transform !== previous.transforms.get(id))
86
+ this.transformed.add(id);
87
+ }
88
+ for (const id of previous.transforms.keys()) {
89
+ if (!state.transforms.has(id))
90
+ this.transformed.add(id);
91
+ }
92
+ });
93
+ }
94
+ update(camera, time) {
95
+ const viewer = this.viewerStore.getState();
96
+ const scene = useScene.getState();
97
+ const wallIds = sceneRegistry.byType.wall;
98
+ const libraryVersion = getLibraryMaterialsVersion();
99
+ const textureVersion = getMaterialTextureVersion();
100
+ const previous = this.viewer;
101
+ const nodesChanged = this.nodes !== scene.nodes;
102
+ const registryChanged = this.registryRevision !== sceneRegistry.revision || this.wallCount !== wallIds.size;
103
+ let highlightChanged = false;
104
+ if (!previous ||
105
+ nodesChanged ||
106
+ previous.selection.selectedIds !== viewer.selection.selectedIds ||
107
+ previous.previewSelectedIds !== viewer.previewSelectedIds ||
108
+ previous.hoveredId !== viewer.hoveredId ||
109
+ previous.hoverHighlightMode !== viewer.hoverHighlightMode) {
110
+ this.selected = new Set([...viewer.selection.selectedIds, ...viewer.previewSelectedIds].filter((id) => scene.nodes[id]?.type === 'wall'));
111
+ const hovered = scene.nodes[viewer.hoveredId]?.type === 'wall' ? viewer.hoveredId : null;
112
+ const key = `${Array.from(this.selected).sort().join('|')}::${viewer.hoverHighlightMode === 'delete' ? (hovered ?? '') : ''}::${viewer.hoverHighlightMode === 'default' ? (hovered ?? '') : ''}`;
113
+ highlightChanged = key !== this.highlightKey;
114
+ this.highlightKey = key;
115
+ }
116
+ const appearanceChanged = !previous ||
117
+ highlightChanged ||
118
+ this.materials !== scene.materials ||
119
+ this.libraryVersion !== libraryVersion ||
120
+ (this.textureVersion !== textureVersion && this.selected.size > 0) ||
121
+ previous.wallMode !== viewer.wallMode ||
122
+ previous.shading !== viewer.shading ||
123
+ previous.textures !== viewer.textures ||
124
+ previous.colorPreset !== viewer.colorPreset ||
125
+ previous.sceneTheme !== viewer.sceneTheme;
126
+ const previewId = (state) => state && state.hoverHighlightMode !== 'default' && state.hoverHighlightMode !== 'delete'
127
+ ? state.hoveredId
128
+ : null;
129
+ const releasedPreview = previewId(previous) !== previewId(viewer) ? previewId(previous) : null;
130
+ this.viewer = viewer;
131
+ const invalidated = appearanceChanged ||
132
+ nodesChanged ||
133
+ registryChanged ||
134
+ this.rebuilt.size > 0 ||
135
+ this.transformed.size > 0 ||
136
+ releasedPreview !== null;
137
+ if (!invalidated && viewer.wallMode !== 'cutaway')
138
+ return;
139
+ camera.getWorldDirection(this.cameraDirection);
140
+ this.cameraTarget.copy(this.cameraDirection).add(camera.position);
141
+ const cameraChanged = viewer.wallMode === 'cutaway' &&
142
+ time - this.lastUpdateTime > 0.1 &&
143
+ (camera.position.distanceTo(this.lastCameraPosition) > 0.5 ||
144
+ this.cameraTarget.distanceTo(this.lastCameraTarget) > 0.3);
145
+ if (!invalidated && !cameraChanged)
146
+ return;
147
+ if (registryChanged || nodesChanged) {
148
+ for (const [id, wall] of this.walls) {
149
+ if (!wallIds.has(id) ||
150
+ sceneRegistry.nodes.get(id) !== wall.mesh ||
151
+ scene.nodes[id]?.type !== 'wall')
152
+ this.walls.delete(id);
153
+ }
154
+ }
155
+ if (invalidated) {
156
+ const changedPaths = new Map();
157
+ const pathChanged = (id) => {
158
+ const cached = changedPaths.get(id);
159
+ if (cached !== undefined)
160
+ return cached;
161
+ const node = scene.nodes[id];
162
+ const changed = this.transformed.has(id) ||
163
+ (nodesChanged && this.nodes?.[id] !== node) ||
164
+ !!(node?.parentId && pathChanged(node.parentId));
165
+ changedPaths.set(id, changed);
166
+ return changed;
167
+ };
168
+ const visited = new Set();
169
+ for (const id of wallIds) {
170
+ const node = scene.nodes[id];
171
+ if (node?.type !== 'wall')
172
+ continue;
173
+ let wall = this.walls.get(id);
174
+ const added = !wall;
175
+ if (!wall) {
176
+ const mesh = sceneRegistry.nodes.get(id);
177
+ if (!mesh)
178
+ continue;
179
+ wall = {
180
+ mesh,
181
+ node,
182
+ normal: new Vector3(),
183
+ matrix: new Matrix4().makeScale(0, 0, 0),
184
+ geometry: mesh.geometry,
185
+ negativeFacing: undefined,
186
+ hidden: undefined,
187
+ variantKey: undefined,
188
+ assignedMaterials: undefined,
189
+ visibleVariant: { key: 'visible', materials: [] },
190
+ hiddenVariant: { key: 'invisible', materials: [] },
191
+ };
192
+ this.walls.set(id, wall);
193
+ }
194
+ const changed = pathChanged(id);
195
+ const rebuilt = this.rebuilt.has(id);
196
+ if (added || changed || rebuilt)
197
+ this.refreshNormal(wall, visited);
198
+ wall.node = node;
199
+ if (added || appearanceChanged || (nodesChanged && changed))
200
+ this.refreshAppearance(wall);
201
+ if (added ||
202
+ appearanceChanged ||
203
+ changed ||
204
+ rebuilt ||
205
+ releasedPreview === id ||
206
+ cameraChanged) {
207
+ this.apply(wall, viewer.wallMode, added || appearanceChanged || (nodesChanged && changed));
208
+ }
209
+ }
210
+ }
211
+ else {
212
+ for (const wall of this.walls.values())
213
+ this.apply(wall, viewer.wallMode, false);
214
+ }
215
+ this.rebuilt.clear();
216
+ this.transformed.clear();
217
+ this.nodes = scene.nodes;
218
+ this.materials = scene.materials;
219
+ this.registryRevision = sceneRegistry.revision;
220
+ this.wallCount = wallIds.size;
221
+ this.libraryVersion = libraryVersion;
222
+ this.textureVersion = getMaterialTextureVersion();
223
+ if (appearanceChanged || cameraChanged) {
224
+ this.lastCameraPosition.copy(camera.position);
225
+ this.lastCameraTarget.copy(this.cameraTarget);
226
+ this.lastUpdateTime = time;
227
+ }
228
+ }
229
+ refreshAppearance(wall) {
230
+ const viewer = this.viewer;
231
+ const scene = useScene.getState();
232
+ const node = wall.node;
233
+ const deleted = viewer.hoverHighlightMode === 'delete' && viewer.hoveredId === node.id;
234
+ let selectionHighlighted = !deleted && this.selected.has(node.id);
235
+ if (selectionHighlighted) {
236
+ const levelId = resolveLevelId(node, scene.nodes);
237
+ const support = spatialGridManager.getSlabSupportForWall(levelId, node.start, node.end, node.curveOffset ?? 0, node.thickness, node.supportSlabId);
238
+ const height = resolveWallEffectiveHeight(node, getWallPlaneTop(node, levelId, scene.nodes), support.elevation);
239
+ selectionHighlighted = !getWallFaceBandConfig(node, height).enabled;
240
+ }
241
+ const materials = getMaterialsForWall(node, viewer.shading, viewer.textures, viewer.colorPreset, viewer.sceneTheme, scene.materials);
242
+ const variant = (hidden) => {
243
+ const key = resolveWallMaterialVariant({
244
+ translucentMode: viewer.wallMode === 'translucent',
245
+ hidden,
246
+ deleteHighlighted: deleted,
247
+ selectionHighlighted,
248
+ hoverHighlighted: viewer.hoverHighlightMode === 'default' && viewer.hoveredId === node.id,
249
+ });
250
+ return { key, materials: materialsForVariant(key, materials) };
251
+ };
252
+ wall.visibleVariant = variant(false);
253
+ wall.hiddenVariant = variant(true);
254
+ }
255
+ refreshNormal(wall, visited) {
256
+ const update = (object) => {
257
+ if (visited.has(object))
258
+ return;
259
+ if (object.parent)
260
+ update(object.parent);
261
+ object.updateWorldMatrix(false, false);
262
+ visited.add(object);
263
+ };
264
+ update(wall.mesh);
265
+ if (wall.matrix.equals(wall.mesh.matrixWorld) && wall.geometry === wall.mesh.geometry)
266
+ return;
267
+ wall.matrix.copy(wall.mesh.matrixWorld);
268
+ wall.geometry = wall.mesh.geometry;
269
+ wall.normal.setFromMatrixColumn(wall.matrix, 2).normalize();
270
+ }
271
+ apply(wall, mode, refresh) {
272
+ if (mode === 'cutaway') {
273
+ wall.negativeFacing = wallFacingNegative(wall.normal.dot(this.cameraDirection), wall.negativeFacing);
274
+ }
275
+ const hidden = wallHiddenFromFacing(wall.node, mode, wall.negativeFacing ?? false);
276
+ wall.hidden = hidden;
277
+ // The wall batch and pointer handlers consume this boolean, including
278
+ // false on stamp lift; translucent walls must continue receiving events.
279
+ const stamp = mode !== 'translucent' && hidden;
280
+ if (wall.mesh.userData.wallHidden !== stamp)
281
+ wall.mesh.userData.wallHidden = stamp;
282
+ const variant = hidden ? wall.hiddenVariant : wall.visibleVariant;
283
+ // Non-highlight hover owns a temporary material until its restore callback runs.
284
+ const viewer = this.viewer;
285
+ if (viewer.hoveredId === wall.node.id &&
286
+ viewer.hoverHighlightMode !== 'default' &&
287
+ viewer.hoverHighlightMode !== 'delete') {
288
+ if (refresh)
289
+ wall.variantKey = undefined;
290
+ return;
291
+ }
292
+ if (wall.variantKey !== variant.key || refresh) {
293
+ if (wall.mesh.material !== variant.materials &&
294
+ !sameMaterialArray(wall.mesh.material, variant.materials)) {
295
+ wall.mesh.material = variant.materials;
296
+ }
297
+ wall.variantKey = variant.key;
298
+ wall.assignedMaterials = wall.mesh.material;
299
+ }
300
+ else if (wall.mesh.material !== wall.assignedMaterials) {
301
+ wall.mesh.material = wall.assignedMaterials;
302
+ }
303
+ }
304
+ }
@@ -1,2 +1,25 @@
1
- export declare const WallCutout: () => null;
1
+ import { type WallNode } from '@pascal-app/core';
2
+ import type { Camera } from 'three';
3
+ import { type Mesh, Vector3 } from 'three/webgpu';
4
+ import { type WallMode } from '../../store/use-viewer';
5
+ import { WallCutoutCache, type WallCutoutViewerStore } from './wall-cutout-cache';
6
+ export declare const WALL_CUTOUT_FRAME_PRIORITY = 0;
7
+ export declare function runWallCutoutFrame(cache: WallCutoutCache, { camera, clock }: {
8
+ camera: Camera;
9
+ clock: {
10
+ elapsedTime: number;
11
+ };
12
+ }): void;
13
+ /**
14
+ * Whether a wall should be hidden or see-through for the current camera and
15
+ * wall mode. Pure: reads only its arguments and the mesh's world direction.
16
+ *
17
+ * Exported so hosts rendering their own layers inside `<Viewer>` can match
18
+ * these semantics instead of re-deriving the facing test or inferring state
19
+ * from the assigned material variant.
20
+ */
21
+ export declare function getWallHideState(wallNode: WallNode, wallMesh: Mesh, wallMode: WallMode, cameraDir: Vector3): boolean;
22
+ export declare const WallCutout: ({ viewerStore, }: {
23
+ viewerStore?: WallCutoutViewerStore;
24
+ }) => null;
2
25
  //# sourceMappingURL=wall-cutout.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"wall-cutout.d.ts","sourceRoot":"","sources":["../../../src/systems/wall/wall-cutout.tsx"],"names":[],"mappings":"AAyDA,eAAO,MAAM,UAAU,YAuLtB,CAAA"}
1
+ {"version":3,"file":"wall-cutout.d.ts","sourceRoot":"","sources":["../../../src/systems/wall/wall-cutout.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAoD,KAAK,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAGlG,OAAO,KAAK,EAAE,MAAM,EAAY,MAAM,OAAO,CAAA;AAC7C,OAAO,EAAE,KAAK,IAAI,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACjD,OAAkB,EAAE,KAAK,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AACjE,OAAO,EAEL,eAAe,EACf,KAAK,qBAAqB,EAE3B,MAAM,qBAAqB,CAAA;AAM5B,eAAO,MAAM,0BAA0B,IAAI,CAAA;AAE3C,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,eAAe,EACtB,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,QAGtE;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,IAAI,EACd,QAAQ,EAAE,QAAQ,EAClB,SAAS,EAAE,OAAO,GACjB,OAAO,CAKT;AAED,eAAO,MAAM,UAAU,GAAI,kBAExB;IACD,WAAW,CAAC,EAAE,qBAAqB,CAAA;CACpC,SA2DA,CAAA"}