@pascal-app/viewer 0.8.0 → 0.9.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.
Files changed (284) hide show
  1. package/dist/components/error-boundary.d.ts +6 -0
  2. package/dist/components/error-boundary.d.ts.map +1 -1
  3. package/dist/components/error-boundary.js +6 -0
  4. package/dist/components/renderers/node-renderer.d.ts +6 -2
  5. package/dist/components/renderers/node-renderer.d.ts.map +1 -1
  6. package/dist/components/renderers/node-renderer.js +41 -22
  7. package/dist/components/renderers/parametric-node-renderer.d.ts +5 -0
  8. package/dist/components/renderers/parametric-node-renderer.d.ts.map +1 -0
  9. package/dist/components/renderers/parametric-node-renderer.js +37 -0
  10. package/dist/components/renderers/scene-renderer.d.ts +1 -1
  11. package/dist/components/renderers/scene-renderer.d.ts.map +1 -1
  12. package/dist/components/viewer/bvh-ecctrl.d.ts +77 -0
  13. package/dist/components/viewer/bvh-ecctrl.d.ts.map +1 -0
  14. package/dist/components/viewer/bvh-ecctrl.js +552 -0
  15. package/dist/components/viewer/frame-limiter.d.ts.map +1 -1
  16. package/dist/components/viewer/frame-limiter.js +39 -4
  17. package/dist/components/viewer/glb-interactive.d.ts +41 -0
  18. package/dist/components/viewer/glb-interactive.d.ts.map +1 -0
  19. package/dist/components/viewer/glb-interactive.js +394 -0
  20. package/dist/components/viewer/glb-reference-nodes.d.ts +29 -0
  21. package/dist/components/viewer/glb-reference-nodes.d.ts.map +1 -0
  22. package/dist/components/viewer/glb-reference-nodes.js +80 -0
  23. package/dist/components/viewer/glb-replace-instances.d.ts +18 -0
  24. package/dist/components/viewer/glb-replace-instances.d.ts.map +1 -0
  25. package/dist/components/viewer/glb-replace-instances.js +61 -0
  26. package/dist/components/viewer/glb-scene.d.ts +54 -0
  27. package/dist/components/viewer/glb-scene.d.ts.map +1 -0
  28. package/dist/components/viewer/glb-scene.js +920 -0
  29. package/dist/components/viewer/glb-walkthrough-controller.d.ts +12 -0
  30. package/dist/components/viewer/glb-walkthrough-controller.d.ts.map +1 -0
  31. package/dist/components/viewer/glb-walkthrough-controller.js +357 -0
  32. package/dist/components/viewer/index.d.ts +56 -3
  33. package/dist/components/viewer/index.d.ts.map +1 -1
  34. package/dist/components/viewer/index.js +280 -65
  35. package/dist/components/viewer/lights.d.ts +1 -1
  36. package/dist/components/viewer/lights.d.ts.map +1 -1
  37. package/dist/components/viewer/lights.js +201 -43
  38. package/dist/components/viewer/perf-monitor.d.ts +1 -1
  39. package/dist/components/viewer/perf-monitor.d.ts.map +1 -1
  40. package/dist/components/viewer/perf-monitor.js +115 -12
  41. package/dist/components/viewer/post-processing.d.ts +7 -1
  42. package/dist/components/viewer/post-processing.d.ts.map +1 -1
  43. package/dist/components/viewer/post-processing.js +395 -63
  44. package/dist/components/viewer/registered-systems.d.ts +12 -0
  45. package/dist/components/viewer/registered-systems.d.ts.map +1 -0
  46. package/dist/components/viewer/registered-systems.js +49 -0
  47. package/dist/components/viewer/scene-bvh.d.ts +18 -0
  48. package/dist/components/viewer/scene-bvh.d.ts.map +1 -0
  49. package/dist/components/viewer/scene-bvh.js +97 -0
  50. package/dist/components/viewer/scene-bvh.test.d.ts +2 -0
  51. package/dist/components/viewer/scene-bvh.test.d.ts.map +1 -0
  52. package/dist/components/viewer/scene-bvh.test.js +13 -0
  53. package/dist/components/viewer/scene-environment.d.ts +2 -0
  54. package/dist/components/viewer/scene-environment.d.ts.map +1 -0
  55. package/dist/components/viewer/scene-environment.js +79 -0
  56. package/dist/components/viewer/selection-manager.d.ts +1 -1
  57. package/dist/components/viewer/selection-manager.d.ts.map +1 -1
  58. package/dist/components/viewer/selection-manager.js +37 -14
  59. package/dist/components/viewer/viewer-camera.d.ts +1 -1
  60. package/dist/components/viewer/viewer-camera.d.ts.map +1 -1
  61. package/dist/components/viewer/walkthrough-controls.d.ts +2 -1
  62. package/dist/components/viewer/walkthrough-controls.d.ts.map +1 -1
  63. package/dist/components/viewer/walkthrough-controls.js +20 -0
  64. package/dist/hooks/use-gltf-ktx2.d.ts.map +1 -1
  65. package/dist/hooks/use-gltf-ktx2.js +3 -22
  66. package/dist/hooks/use-node-events.d.ts +6 -74
  67. package/dist/hooks/use-node-events.d.ts.map +1 -1
  68. package/dist/hooks/use-node-events.js +28 -8
  69. package/dist/index.d.ts +48 -5
  70. package/dist/index.d.ts.map +1 -1
  71. package/dist/index.js +82 -4
  72. package/dist/lib/backdrop.d.ts +33 -0
  73. package/dist/lib/backdrop.d.ts.map +1 -0
  74. package/dist/lib/backdrop.js +92 -0
  75. package/dist/lib/box-uv.d.ts +13 -0
  76. package/dist/lib/box-uv.d.ts.map +1 -0
  77. package/dist/lib/box-uv.js +32 -0
  78. package/dist/lib/csg-utils.d.ts +10 -0
  79. package/dist/lib/csg-utils.d.ts.map +1 -0
  80. package/dist/lib/csg-utils.js +93 -0
  81. package/dist/lib/csg-utils.test.d.ts +2 -0
  82. package/dist/lib/csg-utils.test.d.ts.map +1 -0
  83. package/dist/lib/csg-utils.test.js +45 -0
  84. package/dist/lib/drawable-geometry.d.ts +21 -0
  85. package/dist/lib/drawable-geometry.d.ts.map +1 -0
  86. package/dist/lib/drawable-geometry.js +22 -0
  87. package/dist/lib/edge-style.d.ts +4 -0
  88. package/dist/lib/edge-style.d.ts.map +1 -0
  89. package/dist/lib/edge-style.js +31 -0
  90. package/dist/lib/gpu-perf.d.ts +4 -0
  91. package/dist/lib/gpu-perf.d.ts.map +1 -0
  92. package/dist/lib/gpu-perf.js +23 -0
  93. package/dist/lib/ink-edges.d.ts +9 -0
  94. package/dist/lib/ink-edges.d.ts.map +1 -0
  95. package/dist/lib/ink-edges.js +49 -0
  96. package/dist/lib/isolation.d.ts +39 -0
  97. package/dist/lib/isolation.d.ts.map +1 -0
  98. package/dist/lib/isolation.js +103 -0
  99. package/dist/lib/ktx2-loader.d.ts +43 -0
  100. package/dist/lib/ktx2-loader.d.ts.map +1 -0
  101. package/dist/lib/ktx2-loader.js +136 -0
  102. package/dist/lib/layers.d.ts +28 -0
  103. package/dist/lib/layers.d.ts.map +1 -1
  104. package/dist/lib/layers.js +28 -0
  105. package/dist/lib/materials.d.ts +38 -15
  106. package/dist/lib/materials.d.ts.map +1 -1
  107. package/dist/lib/materials.js +364 -72
  108. package/dist/lib/merged-outline-node.d.ts.map +1 -1
  109. package/dist/lib/merged-outline-node.js +7 -0
  110. package/dist/lib/polygon-union.d.ts +4 -0
  111. package/dist/lib/polygon-union.d.ts.map +1 -0
  112. package/dist/lib/polygon-union.js +289 -0
  113. package/dist/lib/polygon-union.test.d.ts +2 -0
  114. package/dist/lib/polygon-union.test.d.ts.map +1 -0
  115. package/dist/lib/polygon-union.test.js +105 -0
  116. package/dist/lib/scene-themes.d.ts +30 -0
  117. package/dist/lib/scene-themes.d.ts.map +1 -0
  118. package/dist/lib/scene-themes.js +202 -0
  119. package/dist/lib/shadow-only.d.ts +4 -0
  120. package/dist/lib/shadow-only.d.ts.map +1 -0
  121. package/dist/lib/shadow-only.js +36 -0
  122. package/dist/lib/tsl-compat.d.ts +12 -0
  123. package/dist/lib/tsl-compat.d.ts.map +1 -0
  124. package/dist/lib/tsl-compat.js +13 -0
  125. package/dist/store/use-viewer.d.ts +92 -12
  126. package/dist/store/use-viewer.d.ts.map +1 -1
  127. package/dist/store/use-viewer.js +201 -6
  128. package/dist/store/use-viewer.test.d.ts +2 -0
  129. package/dist/store/use-viewer.test.d.ts.map +1 -0
  130. package/dist/store/use-viewer.test.js +42 -0
  131. package/dist/systems/ceiling/ceiling-system.d.ts +6 -2
  132. package/dist/systems/ceiling/ceiling-system.d.ts.map +1 -1
  133. package/dist/systems/ceiling/ceiling-system.js +66 -13
  134. package/dist/systems/door/door-animation.test.d.ts +2 -0
  135. package/dist/systems/door/door-animation.test.d.ts.map +1 -0
  136. package/dist/systems/door/door-animation.test.js +51 -0
  137. package/dist/systems/door/door-floor-alignment.test.d.ts +2 -0
  138. package/dist/systems/door/door-floor-alignment.test.d.ts.map +1 -0
  139. package/dist/systems/door/door-floor-alignment.test.js +50 -0
  140. package/dist/systems/door/door-system.d.ts +24 -0
  141. package/dist/systems/door/door-system.d.ts.map +1 -1
  142. package/dist/systems/door/door-system.js +864 -180
  143. package/dist/systems/elevator/elevator-interaction-system.d.ts +2 -0
  144. package/dist/systems/elevator/elevator-interaction-system.d.ts.map +1 -0
  145. package/dist/systems/elevator/elevator-interaction-system.js +62 -0
  146. package/dist/systems/fence/fence-system.d.ts +20 -0
  147. package/dist/systems/fence/fence-system.d.ts.map +1 -1
  148. package/dist/systems/fence/fence-system.js +229 -57
  149. package/dist/systems/floor-elevation/floor-elevation-system.d.ts +20 -0
  150. package/dist/systems/floor-elevation/floor-elevation-system.d.ts.map +1 -0
  151. package/dist/systems/floor-elevation/floor-elevation-system.js +78 -0
  152. package/dist/systems/geometry/geometry-system.d.ts +41 -0
  153. package/dist/systems/geometry/geometry-system.d.ts.map +1 -0
  154. package/dist/systems/geometry/geometry-system.js +348 -0
  155. package/dist/systems/geometry/geometry-system.test.d.ts +2 -0
  156. package/dist/systems/geometry/geometry-system.test.d.ts.map +1 -0
  157. package/dist/systems/geometry/geometry-system.test.js +30 -0
  158. package/dist/systems/interactive/control-widget.d.ts +10 -0
  159. package/dist/systems/interactive/control-widget.d.ts.map +1 -0
  160. package/dist/systems/interactive/control-widget.js +35 -0
  161. package/dist/systems/interactive/interactive-system.d.ts +1 -1
  162. package/dist/systems/interactive/interactive-system.d.ts.map +1 -1
  163. package/dist/systems/interactive/interactive-system.js +55 -56
  164. package/dist/systems/item/item-system.d.ts +7 -0
  165. package/dist/systems/item/item-system.d.ts.map +1 -1
  166. package/dist/systems/item/item-system.js +28 -17
  167. package/dist/systems/item-light/item-light-system.d.ts +1 -1
  168. package/dist/systems/item-light/item-light-system.d.ts.map +1 -1
  169. package/dist/systems/item-light/item-light-system.js +18 -5
  170. package/dist/systems/level/level-system.d.ts.map +1 -1
  171. package/dist/systems/level/level-system.js +28 -4
  172. package/dist/systems/level/level-utils.d.ts +0 -3
  173. package/dist/systems/level/level-utils.d.ts.map +1 -1
  174. package/dist/systems/level/level-utils.js +2 -41
  175. package/dist/systems/roof/roof-materials.d.ts +3 -2
  176. package/dist/systems/roof/roof-materials.d.ts.map +1 -1
  177. package/dist/systems/roof/roof-materials.js +59 -14
  178. package/dist/systems/roof/roof-system.d.ts +46 -6
  179. package/dist/systems/roof/roof-system.d.ts.map +1 -1
  180. package/dist/systems/roof/roof-system.js +1365 -170
  181. package/dist/systems/slab/slab-system.d.ts +5 -3
  182. package/dist/systems/slab/slab-system.d.ts.map +1 -1
  183. package/dist/systems/slab/slab-system.js +204 -68
  184. package/dist/systems/slab/slab-system.test.d.ts +2 -0
  185. package/dist/systems/slab/slab-system.test.d.ts.map +1 -0
  186. package/dist/systems/slab/slab-system.test.js +63 -0
  187. package/dist/systems/stair/stair-materials.d.ts +4 -3
  188. package/dist/systems/stair/stair-materials.d.ts.map +1 -1
  189. package/dist/systems/stair/stair-materials.js +30 -15
  190. package/dist/systems/stair/stair-system.d.ts.map +1 -1
  191. package/dist/systems/stair/stair-system.js +55 -63
  192. package/dist/systems/surface-hole-geometry.d.ts +3 -0
  193. package/dist/systems/surface-hole-geometry.d.ts.map +1 -0
  194. package/dist/systems/surface-hole-geometry.js +4 -0
  195. package/dist/systems/wall/opening-cutout-geometry.d.ts +31 -0
  196. package/dist/systems/wall/opening-cutout-geometry.d.ts.map +1 -0
  197. package/dist/systems/wall/opening-cutout-geometry.js +167 -0
  198. package/dist/systems/wall/opening-cutout-geometry.test.d.ts +2 -0
  199. package/dist/systems/wall/opening-cutout-geometry.test.d.ts.map +1 -0
  200. package/dist/systems/wall/opening-cutout-geometry.test.js +172 -0
  201. package/dist/systems/wall/wall-cutout.d.ts.map +1 -1
  202. package/dist/systems/wall/wall-cutout.js +62 -17
  203. package/dist/systems/wall/wall-materials.d.ts +12 -7
  204. package/dist/systems/wall/wall-materials.d.ts.map +1 -1
  205. package/dist/systems/wall/wall-materials.js +279 -46
  206. package/dist/systems/wall/wall-opening-cutout.test.d.ts +2 -0
  207. package/dist/systems/wall/wall-opening-cutout.test.d.ts.map +1 -0
  208. package/dist/systems/wall/wall-opening-cutout.test.js +59 -0
  209. package/dist/systems/wall/wall-support-extension.test.d.ts +2 -0
  210. package/dist/systems/wall/wall-support-extension.test.d.ts.map +1 -0
  211. package/dist/systems/wall/wall-support-extension.test.js +48 -0
  212. package/dist/systems/wall/wall-system.d.ts +2 -2
  213. package/dist/systems/wall/wall-system.d.ts.map +1 -1
  214. package/dist/systems/wall/wall-system.js +493 -193
  215. package/dist/systems/window/window-animation-system.d.ts +12 -0
  216. package/dist/systems/window/window-animation-system.d.ts.map +1 -1
  217. package/dist/systems/window/window-animation-system.js +16 -5
  218. package/dist/systems/window/window-system.d.ts +7 -0
  219. package/dist/systems/window/window-system.d.ts.map +1 -1
  220. package/dist/systems/window/window-system.js +308 -18
  221. package/package.json +5 -6
  222. package/dist/components/renderers/building/building-renderer.d.ts +0 -5
  223. package/dist/components/renderers/building/building-renderer.d.ts.map +0 -1
  224. package/dist/components/renderers/building/building-renderer.js +0 -11
  225. package/dist/components/renderers/ceiling/ceiling-renderer.d.ts +0 -5
  226. package/dist/components/renderers/ceiling/ceiling-renderer.d.ts.map +0 -1
  227. package/dist/components/renderers/ceiling/ceiling-renderer.js +0 -58
  228. package/dist/components/renderers/column/column-renderer.d.ts +0 -5
  229. package/dist/components/renderers/column/column-renderer.d.ts.map +0 -1
  230. package/dist/components/renderers/column/column-renderer.js +0 -597
  231. package/dist/components/renderers/door/door-renderer.d.ts +0 -5
  232. package/dist/components/renderers/door/door-renderer.d.ts.map +0 -1
  233. package/dist/components/renderers/door/door-renderer.js +0 -16
  234. package/dist/components/renderers/fence/fence-renderer.d.ts +0 -5
  235. package/dist/components/renderers/fence/fence-renderer.d.ts.map +0 -1
  236. package/dist/components/renderers/fence/fence-renderer.js +0 -15
  237. package/dist/components/renderers/guide/guide-renderer.d.ts +0 -5
  238. package/dist/components/renderers/guide/guide-renderer.d.ts.map +0 -1
  239. package/dist/components/renderers/guide/guide-renderer.js +0 -38
  240. package/dist/components/renderers/item/item-renderer.d.ts +0 -5
  241. package/dist/components/renderers/item/item-renderer.d.ts.map +0 -1
  242. package/dist/components/renderers/item/item-renderer.js +0 -172
  243. package/dist/components/renderers/level/level-renderer.d.ts +0 -5
  244. package/dist/components/renderers/level/level-renderer.d.ts.map +0 -1
  245. package/dist/components/renderers/level/level-renderer.js +0 -11
  246. package/dist/components/renderers/roof/roof-materials.d.ts +0 -4
  247. package/dist/components/renderers/roof/roof-materials.d.ts.map +0 -1
  248. package/dist/components/renderers/roof/roof-materials.js +0 -16
  249. package/dist/components/renderers/roof/roof-renderer.d.ts +0 -5
  250. package/dist/components/renderers/roof/roof-renderer.d.ts.map +0 -1
  251. package/dist/components/renderers/roof/roof-renderer.js +0 -32
  252. package/dist/components/renderers/roof-segment/roof-segment-renderer.d.ts +0 -5
  253. package/dist/components/renderers/roof-segment/roof-segment-renderer.d.ts.map +0 -1
  254. package/dist/components/renderers/roof-segment/roof-segment-renderer.js +0 -40
  255. package/dist/components/renderers/scan/scan-renderer.d.ts +0 -5
  256. package/dist/components/renderers/scan/scan-renderer.d.ts.map +0 -1
  257. package/dist/components/renderers/scan/scan-renderer.js +0 -54
  258. package/dist/components/renderers/site/site-renderer.d.ts +0 -5
  259. package/dist/components/renderers/site/site-renderer.d.ts.map +0 -1
  260. package/dist/components/renderers/site/site-renderer.js +0 -106
  261. package/dist/components/renderers/slab/slab-renderer.d.ts +0 -5
  262. package/dist/components/renderers/slab/slab-renderer.d.ts.map +0 -1
  263. package/dist/components/renderers/slab/slab-renderer.js +0 -58
  264. package/dist/components/renderers/spawn/spawn-renderer.d.ts +0 -5
  265. package/dist/components/renderers/spawn/spawn-renderer.d.ts.map +0 -1
  266. package/dist/components/renderers/spawn/spawn-renderer.js +0 -32
  267. package/dist/components/renderers/stair/stair-renderer.d.ts +0 -5
  268. package/dist/components/renderers/stair/stair-renderer.d.ts.map +0 -1
  269. package/dist/components/renderers/stair/stair-renderer.js +0 -603
  270. package/dist/components/renderers/stair-segment/stair-segment-renderer.d.ts +0 -5
  271. package/dist/components/renderers/stair-segment/stair-segment-renderer.d.ts.map +0 -1
  272. package/dist/components/renderers/stair-segment/stair-segment-renderer.js +0 -51
  273. package/dist/components/renderers/wall/wall-renderer.d.ts +0 -5
  274. package/dist/components/renderers/wall/wall-renderer.d.ts.map +0 -1
  275. package/dist/components/renderers/wall/wall-renderer.js +0 -16
  276. package/dist/components/renderers/window/window-renderer.d.ts +0 -5
  277. package/dist/components/renderers/window/window-renderer.d.ts.map +0 -1
  278. package/dist/components/renderers/window/window-renderer.js +0 -21
  279. package/dist/components/renderers/zone/zone-renderer.d.ts +0 -5
  280. package/dist/components/renderers/zone/zone-renderer.d.ts.map +0 -1
  281. package/dist/components/renderers/zone/zone-renderer.js +0 -181
  282. package/dist/components/viewer/ground-occluder.d.ts +0 -2
  283. package/dist/components/viewer/ground-occluder.d.ts.map +0 -1
  284. package/dist/components/viewer/ground-occluder.js +0 -79
@@ -0,0 +1,12 @@
1
+ /**
2
+ * three runs at 0.185 but @types/three is pinned at 0.184: the 0.185 typings
3
+ * make tsgo's type inference allocate unboundedly (microsoft/typescript-go
4
+ * #2125 class) and OOM the machine. r185 renamed directionToColor /
5
+ * colorToDirection to packNormalToRGB / unpackRGBToNormal — re-export the new
6
+ * runtime names under the old names' signatures. Delete this file (and the
7
+ * @types/three pin) once tsgo handles the 0.185 types; the `typeof` references
8
+ * to the removed old names will fail the build as a reminder.
9
+ */
10
+ export declare const packNormalToRGB: (node: import("three/webgpu").Node) => import("three/webgpu").Node<"vec3">;
11
+ export declare const unpackRGBToNormal: (node: import("three/webgpu").Node) => import("three/webgpu").Node<"vec3">;
12
+ //# sourceMappingURL=tsl-compat.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tsl-compat.d.ts","sourceRoot":"","sources":["../../src/lib/tsl-compat.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AACH,eAAO,MAAM,eAAe,4EACV,CAAA;AAClB,eAAO,MAAM,iBAAiB,4EAEX,CAAA"}
@@ -0,0 +1,13 @@
1
+ import * as TSL from 'three/tsl';
2
+ /**
3
+ * three runs at 0.185 but @types/three is pinned at 0.184: the 0.185 typings
4
+ * make tsgo's type inference allocate unboundedly (microsoft/typescript-go
5
+ * #2125 class) and OOM the machine. r185 renamed directionToColor /
6
+ * colorToDirection to packNormalToRGB / unpackRGBToNormal — re-export the new
7
+ * runtime names under the old names' signatures. Delete this file (and the
8
+ * @types/three pin) once tsgo handles the 0.185 types; the `typeof` references
9
+ * to the removed old names will fail the build as a reminder.
10
+ */
11
+ export const packNormalToRGB = TSL
12
+ .packNormalToRGB;
13
+ export const unpackRGBToNormal = TSL.unpackRGBToNormal;
@@ -1,5 +1,8 @@
1
1
  import type { AnyNode, BaseNode, BuildingNode, LevelNode, ZoneNode } from '@pascal-app/core';
2
2
  import type { Object3D } from 'three';
3
+ import type { EdgeMode } from '../lib/edge-style';
4
+ import type { ColorPreset, RenderShading } from '../lib/materials';
5
+ export type RenderContext = 'editor' | 'viewer';
3
6
  type SelectionPath = {
4
7
  buildingId: BuildingNode['id'] | null;
5
8
  levelId: LevelNode['id'] | null;
@@ -20,30 +23,77 @@ type ViewerState = {
20
23
  setHoveredId: (id: AnyNode['id'] | ZoneNode['id'] | null) => void;
21
24
  cameraMode: 'perspective' | 'orthographic';
22
25
  setCameraMode: (mode: 'perspective' | 'orthographic') => void;
23
- theme: 'light' | 'dark';
24
- setTheme: (theme: 'light' | 'dark') => void;
26
+ sceneTheme: string;
27
+ setSceneTheme: (id: string) => void;
28
+ renderContext: RenderContext;
29
+ setRenderContext: (context: RenderContext) => void;
30
+ /** True during a GLB bake/export pass. Renderers that normally draw via a
31
+ * collective InstancedMesh (`def.system`) and mount only an invisible per-node
32
+ * proxy can watch this to emit real, visible geometry so the exporter — which
33
+ * clones only the `scene-renderer` subtree — captures them. Transient (never
34
+ * persisted). */
35
+ isExporting: boolean;
36
+ setExporting: (value: boolean) => void;
37
+ /** Item model loads that exhausted their retries — nodeId → asset URL. The
38
+ * scene renders without these items (they settle as skipped); a bake host
39
+ * can persist the map onto the artifact's metadata so a missing item is
40
+ * queryable instead of silently absent. Transient (never persisted). */
41
+ itemLoadFailures: Record<string, string>;
42
+ reportItemLoadFailure: (nodeId: string, url: string) => void;
43
+ clearItemLoadFailure: (nodeId: string) => void;
44
+ /** Suspend the render loop while the canvas is fully covered (e.g. studio gallery). */
45
+ renderPaused: boolean;
46
+ setRenderPaused: (value: boolean) => void;
47
+ shading: RenderShading;
48
+ shadingByContext: Partial<Record<RenderContext, RenderShading>>;
49
+ setShading: (shading: RenderShading) => void;
50
+ textures: boolean;
51
+ setTextures: (textures: boolean) => void;
52
+ colorPreset: ColorPreset;
53
+ setColorPreset: (preset: ColorPreset) => void;
54
+ edges: EdgeMode;
55
+ setEdges: (edges: EdgeMode) => void;
56
+ shadows: boolean;
57
+ setShadows: (shadows: boolean) => void;
25
58
  unit: 'metric' | 'imperial';
26
59
  setUnit: (unit: 'metric' | 'imperial') => void;
60
+ /** True once the user explicitly picked a unit. Until then `unit` is a
61
+ * locale-derived default and is not persisted, so the default can keep
62
+ * tracking the browser locale across sessions. */
63
+ unitExplicit: boolean;
27
64
  levelMode: 'stacked' | 'exploded' | 'solo' | 'manual';
28
65
  setLevelMode: (mode: 'stacked' | 'exploded' | 'solo' | 'manual') => void;
29
- wallMode: 'up' | 'cutaway' | 'down';
30
- setWallMode: (mode: 'up' | 'cutaway' | 'down') => void;
66
+ wallMode: 'up' | 'cutaway' | 'down' | 'translucent';
67
+ setWallMode: (mode: 'up' | 'cutaway' | 'down' | 'translucent') => void;
31
68
  showScans: boolean;
32
69
  setShowScans: (show: boolean) => void;
33
70
  showGuides: boolean;
34
71
  setShowGuides: (show: boolean) => void;
35
72
  showGrid: boolean;
36
73
  setShowGrid: (show: boolean) => void;
74
+ showMeasurements: boolean;
75
+ setShowMeasurements: (show: boolean) => void;
76
+ showZones: boolean;
77
+ setShowZones: (show: boolean) => void;
78
+ transparentBackground: boolean;
79
+ setTransparentBackground: (transparent: boolean) => void;
80
+ inkOpacity: number | null;
81
+ setInkOpacity: (opacity: number | null) => void;
37
82
  projectId: string | null;
38
83
  setProjectId: (id: string | null) => void;
39
84
  projectPreferences: Record<string, {
40
85
  showScans?: boolean;
41
86
  showGuides?: boolean;
42
87
  showGrid?: boolean;
88
+ showMeasurements?: boolean;
43
89
  }>;
44
90
  setSelection: (updates: Partial<SelectionPath>) => void;
45
91
  resetSelection: () => void;
46
92
  outliner: Outliner;
93
+ /** Bumped by GeometrySystem after each rebuild pass so selection/outline
94
+ * effects can re-apply to the freshly swapped meshes. */
95
+ geometryRevision: number;
96
+ bumpGeometryRevision: () => void;
47
97
  exportScene: ((format?: 'glb' | 'stl' | 'obj') => Promise<void>) | null;
48
98
  setExportScene: (fn: ((format?: 'glb' | 'stl' | 'obj') => Promise<void>) | null) => void;
49
99
  debugColors: boolean;
@@ -52,22 +102,40 @@ type ViewerState = {
52
102
  setWalkthroughMode: (mode: boolean) => void;
53
103
  cameraDragging: boolean;
54
104
  setCameraDragging: (dragging: boolean) => void;
105
+ /**
106
+ * True while a host-driven drag is in progress (editor handles —
107
+ * height arrow, width arrow, etc.). Suppresses node pointer event
108
+ * routing so the synthetic click on pointerup doesn't reroute
109
+ * selection to whatever mesh the cursor lands on at release.
110
+ * Conceptually a sibling of `cameraDragging` — both mean "user is
111
+ * dragging; don't treat the next pointerup as a click on the
112
+ * scene." Set by the host (e.g. `NodeArrowHandles` in the editor);
113
+ * the viewer only reads it.
114
+ */
115
+ inputDragging: boolean;
116
+ setInputDragging: (dragging: boolean) => void;
55
117
  };
56
118
  declare const useViewer: import("zustand").UseBoundStore<Omit<import("zustand").StoreApi<ViewerState>, "setState" | "persist"> & {
57
119
  setState(partial: ViewerState | Partial<ViewerState> | ((state: ViewerState) => ViewerState | Partial<ViewerState>), replace?: false | undefined): unknown;
58
120
  setState(state: ViewerState | ((state: ViewerState) => ViewerState), replace: true): unknown;
59
121
  persist: {
60
122
  setOptions: (options: Partial<import("zustand/middleware").PersistOptions<ViewerState, {
61
- cameraMode: "perspective" | "orthographic";
62
- theme: "light" | "dark";
63
- unit: "metric" | "imperial";
64
123
  levelMode: "manual" | "stacked" | "exploded" | "solo";
65
- wallMode: "up" | "down" | "cutaway";
124
+ wallMode: "up" | "down" | "cutaway" | "translucent";
66
125
  projectPreferences: Record<string, {
67
126
  showScans?: boolean;
68
127
  showGuides?: boolean;
69
128
  showGrid?: boolean;
129
+ showMeasurements?: boolean;
70
130
  }>;
131
+ unit?: "metric" | "imperial" | undefined;
132
+ cameraMode: "perspective" | "orthographic";
133
+ sceneTheme: string;
134
+ shadingByContext: Partial<Record<RenderContext, RenderShading>>;
135
+ textures: boolean;
136
+ colorPreset: ColorPreset;
137
+ edges: EdgeMode;
138
+ shadows: boolean;
71
139
  }, unknown>>) => void;
72
140
  clearStorage: () => void;
73
141
  rehydrate: () => Promise<void> | void;
@@ -75,18 +143,30 @@ declare const useViewer: import("zustand").UseBoundStore<Omit<import("zustand").
75
143
  onHydrate: (fn: (state: ViewerState) => void) => () => void;
76
144
  onFinishHydration: (fn: (state: ViewerState) => void) => () => void;
77
145
  getOptions: () => Partial<import("zustand/middleware").PersistOptions<ViewerState, {
78
- cameraMode: "perspective" | "orthographic";
79
- theme: "light" | "dark";
80
- unit: "metric" | "imperial";
81
146
  levelMode: "manual" | "stacked" | "exploded" | "solo";
82
- wallMode: "up" | "down" | "cutaway";
147
+ wallMode: "up" | "down" | "cutaway" | "translucent";
83
148
  projectPreferences: Record<string, {
84
149
  showScans?: boolean;
85
150
  showGuides?: boolean;
86
151
  showGrid?: boolean;
152
+ showMeasurements?: boolean;
87
153
  }>;
154
+ unit?: "metric" | "imperial" | undefined;
155
+ cameraMode: "perspective" | "orthographic";
156
+ sceneTheme: string;
157
+ shadingByContext: Partial<Record<RenderContext, RenderShading>>;
158
+ textures: boolean;
159
+ colorPreset: ColorPreset;
160
+ edges: EdgeMode;
161
+ shadows: boolean;
88
162
  }, unknown>>;
89
163
  };
90
164
  }>;
165
+ /** Apply an authoritative country code (e.g. IP-derived by the host app) as
166
+ * the unit default. Stronger signal than the timezone heuristic used at store
167
+ * creation, but still a default: it never overrides an explicit user choice
168
+ * and is not persisted (the unit only sticks once the user touches the
169
+ * toggle). */
170
+ export declare function applyCountryUnitDefault(country: string | null | undefined): void;
91
171
  export default useViewer;
92
172
  //# sourceMappingURL=use-viewer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-viewer.d.ts","sourceRoot":"","sources":["../../src/store/use-viewer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"use-viewer.d.ts","sourceRoot":"","sources":["../../src/store/use-viewer.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,123 @@
1
1
  'use client';
2
2
  import { create } from 'zustand';
3
3
  import { persist } from 'zustand/middleware';
4
+ import { SCENE_THEME_IDS } from '../lib/scene-themes';
5
+ const CAMERA_MODES = ['perspective', 'orthographic'];
6
+ const RENDER_SHADINGS = ['solid', 'rendered'];
7
+ const COLOR_PRESETS = ['clay', 'white', 'mono', 'blueprint'];
8
+ const EDGE_MODES = ['off', 'soft', 'strong'];
9
+ const UNITS = ['metric', 'imperial'];
10
+ const LEVEL_MODES = ['stacked', 'exploded', 'solo', 'manual'];
11
+ const WALL_MODES = ['up', 'cutaway', 'down', 'translucent'];
12
+ // Countries still on imperial/US customary units: United States, Liberia, Myanmar.
13
+ const IMPERIAL_REGIONS = ['US', 'LR', 'MM'];
14
+ // IANA zones for those countries. The timezone tracks the OS clock (actual
15
+ // location), unlike navigator.language where en-US is a common default for
16
+ // users far outside the US.
17
+ const IMPERIAL_TIMEZONES = new Set([
18
+ 'America/New_York',
19
+ 'America/Detroit',
20
+ 'America/Kentucky/Louisville',
21
+ 'America/Kentucky/Monticello',
22
+ 'America/Indiana/Indianapolis',
23
+ 'America/Indiana/Vincennes',
24
+ 'America/Indiana/Winamac',
25
+ 'America/Indiana/Marengo',
26
+ 'America/Indiana/Petersburg',
27
+ 'America/Indiana/Vevay',
28
+ 'America/Indiana/Tell_City',
29
+ 'America/Indiana/Knox',
30
+ 'America/Chicago',
31
+ 'America/Menominee',
32
+ 'America/North_Dakota/Center',
33
+ 'America/North_Dakota/New_Salem',
34
+ 'America/North_Dakota/Beulah',
35
+ 'America/Denver',
36
+ 'America/Boise',
37
+ 'America/Phoenix',
38
+ 'America/Los_Angeles',
39
+ 'America/Anchorage',
40
+ 'America/Juneau',
41
+ 'America/Sitka',
42
+ 'America/Metlakatla',
43
+ 'America/Yakutat',
44
+ 'America/Nome',
45
+ 'America/Adak',
46
+ 'Pacific/Honolulu',
47
+ 'America/Puerto_Rico',
48
+ 'Pacific/Guam',
49
+ 'Africa/Monrovia', // Liberia
50
+ 'Asia/Yangon', // Myanmar
51
+ 'Asia/Rangoon', // Myanmar (legacy alias)
52
+ ]);
53
+ function detectDefaultUnit() {
54
+ if (typeof navigator === 'undefined')
55
+ return 'metric';
56
+ try {
57
+ const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
58
+ if (timeZone)
59
+ return IMPERIAL_TIMEZONES.has(timeZone) ? 'imperial' : 'metric';
60
+ // No timezone available: fall back to an explicit locale region subtag
61
+ // only (never maximize() — it turns a bare "en" into region US).
62
+ const region = new Intl.Locale(navigator.language).region;
63
+ return region && IMPERIAL_REGIONS.includes(region) ? 'imperial' : 'metric';
64
+ }
65
+ catch {
66
+ return 'metric';
67
+ }
68
+ }
69
+ function pickString(value, allowed, fallback) {
70
+ return typeof value === 'string' && allowed.includes(value) ? value : fallback;
71
+ }
72
+ function normalizeShadingByContext(value) {
73
+ if (!value || typeof value !== 'object' || Array.isArray(value))
74
+ return {};
75
+ const next = {};
76
+ for (const [context, shading] of Object.entries(value)) {
77
+ if (context !== 'editor' && context !== 'viewer')
78
+ continue;
79
+ next[context] = pickString(shading, RENDER_SHADINGS, 'rendered');
80
+ }
81
+ return next;
82
+ }
83
+ function normalizeProjectPreferences(value) {
84
+ if (!value || typeof value !== 'object' || Array.isArray(value))
85
+ return {};
86
+ const next = {};
87
+ for (const [projectId, preferences] of Object.entries(value)) {
88
+ if (!preferences || typeof preferences !== 'object' || Array.isArray(preferences))
89
+ continue;
90
+ const record = preferences;
91
+ next[projectId] = {
92
+ ...(typeof record.showScans === 'boolean' ? { showScans: record.showScans } : {}),
93
+ ...(typeof record.showGuides === 'boolean' ? { showGuides: record.showGuides } : {}),
94
+ ...(typeof record.showGrid === 'boolean' ? { showGrid: record.showGrid } : {}),
95
+ ...(typeof record.showMeasurements === 'boolean'
96
+ ? { showMeasurements: record.showMeasurements }
97
+ : {}),
98
+ };
99
+ }
100
+ return next;
101
+ }
102
+ function normalizePersistedViewerState(value) {
103
+ if (!value || typeof value !== 'object' || Array.isArray(value))
104
+ return {};
105
+ const state = value;
106
+ return {
107
+ cameraMode: pickString(state.cameraMode, CAMERA_MODES, 'perspective'),
108
+ sceneTheme: pickString(state.sceneTheme, SCENE_THEME_IDS, 'studio'),
109
+ shadingByContext: normalizeShadingByContext(state.shadingByContext),
110
+ textures: typeof state.textures === 'boolean' ? state.textures : true,
111
+ colorPreset: pickString(state.colorPreset, COLOR_PRESETS, 'clay'),
112
+ edges: pickString(state.edges, EDGE_MODES, 'soft'),
113
+ shadows: typeof state.shadows === 'boolean' ? state.shadows : true,
114
+ unit: pickString(state.unit, UNITS, detectDefaultUnit()),
115
+ unitExplicit: typeof state.unit === 'string' && UNITS.includes(state.unit),
116
+ levelMode: pickString(state.levelMode, LEVEL_MODES, 'stacked'),
117
+ wallMode: pickString(state.wallMode, WALL_MODES, 'up'),
118
+ projectPreferences: normalizeProjectPreferences(state.projectPreferences),
119
+ };
120
+ }
4
121
  const useViewer = create()(persist((set) => ({
5
122
  selection: { buildingId: null, levelId: null, zoneId: null, selectedIds: [] },
6
123
  previewSelectedIds: [],
@@ -11,10 +128,42 @@ const useViewer = create()(persist((set) => ({
11
128
  setHoveredId: (id) => set((state) => (state.hoveredId === id ? state : { hoveredId: id })),
12
129
  cameraMode: 'perspective',
13
130
  setCameraMode: (mode) => set({ cameraMode: mode }),
14
- theme: 'light',
15
- setTheme: (theme) => set({ theme }),
16
- unit: 'metric',
17
- setUnit: (unit) => set({ unit }),
131
+ sceneTheme: 'studio',
132
+ setSceneTheme: (id) => set({ sceneTheme: id }),
133
+ renderContext: 'editor',
134
+ setRenderContext: (context) => set({ renderContext: context }),
135
+ isExporting: false,
136
+ setExporting: (value) => set({ isExporting: value }),
137
+ itemLoadFailures: {},
138
+ reportItemLoadFailure: (nodeId, url) => set((state) => state.itemLoadFailures[nodeId] === url
139
+ ? state
140
+ : { itemLoadFailures: { ...state.itemLoadFailures, [nodeId]: url } }),
141
+ clearItemLoadFailure: (nodeId) => set((state) => {
142
+ if (!(nodeId in state.itemLoadFailures))
143
+ return state;
144
+ const next = { ...state.itemLoadFailures };
145
+ delete next[nodeId];
146
+ return { itemLoadFailures: next };
147
+ }),
148
+ renderPaused: false,
149
+ setRenderPaused: (value) => set({ renderPaused: value }),
150
+ shading: 'rendered',
151
+ shadingByContext: {},
152
+ setShading: (shading) => set((state) => ({
153
+ shading,
154
+ shadingByContext: { ...state.shadingByContext, [state.renderContext]: shading },
155
+ })),
156
+ textures: true,
157
+ setTextures: (textures) => set({ textures }),
158
+ colorPreset: 'clay',
159
+ setColorPreset: (preset) => set({ colorPreset: preset }),
160
+ edges: 'soft',
161
+ setEdges: (edges) => set({ edges }),
162
+ shadows: true,
163
+ setShadows: (shadows) => set({ shadows }),
164
+ unit: detectDefaultUnit(),
165
+ unitExplicit: false,
166
+ setUnit: (unit) => set({ unit, unitExplicit: true }),
18
167
  levelMode: 'stacked',
19
168
  setLevelMode: (mode) => set({ levelMode: mode }),
20
169
  wallMode: 'up',
@@ -52,6 +201,23 @@ const useViewer = create()(persist((set) => ({
52
201
  }
53
202
  return { showGrid: show, projectPreferences };
54
203
  }),
204
+ showMeasurements: true,
205
+ setShowMeasurements: (show) => set((state) => {
206
+ const projectPreferences = { ...(state.projectPreferences || {}) };
207
+ if (state.projectId) {
208
+ projectPreferences[state.projectId] = {
209
+ ...(projectPreferences[state.projectId] || {}),
210
+ showMeasurements: show,
211
+ };
212
+ }
213
+ return { showMeasurements: show, projectPreferences };
214
+ }),
215
+ showZones: true,
216
+ setShowZones: (show) => set({ showZones: show }),
217
+ transparentBackground: false,
218
+ setTransparentBackground: (transparent) => set({ transparentBackground: transparent }),
219
+ inkOpacity: null,
220
+ setInkOpacity: (opacity) => set({ inkOpacity: opacity }),
55
221
  projectId: null,
56
222
  setProjectId: (id) => set((state) => {
57
223
  if (!id)
@@ -62,6 +228,7 @@ const useViewer = create()(persist((set) => ({
62
228
  showScans: prefs.showScans ?? true,
63
229
  showGuides: prefs.showGuides ?? true,
64
230
  showGrid: prefs.showGrid ?? true,
231
+ showMeasurements: prefs.showMeasurements ?? true,
65
232
  };
66
233
  }),
67
234
  projectPreferences: {},
@@ -98,6 +265,8 @@ const useViewer = create()(persist((set) => ({
98
265
  previewSelectedIds: [],
99
266
  }),
100
267
  outliner: { selectedObjects: [], hoveredObjects: [] },
268
+ geometryRevision: 0,
269
+ bumpGeometryRevision: () => set((state) => ({ geometryRevision: state.geometryRevision + 1 })),
101
270
  exportScene: null,
102
271
  setExportScene: (fn) => set({ exportScene: fn }),
103
272
  debugColors: false,
@@ -106,15 +275,41 @@ const useViewer = create()(persist((set) => ({
106
275
  setWalkthroughMode: (mode) => set({ walkthroughMode: mode }),
107
276
  cameraDragging: false,
108
277
  setCameraDragging: (dragging) => set({ cameraDragging: dragging }),
278
+ inputDragging: false,
279
+ setInputDragging: (dragging) => set({ inputDragging: dragging }),
109
280
  }), {
110
281
  name: 'viewer-preferences',
282
+ merge: (persistedState, currentState) => ({
283
+ ...currentState,
284
+ ...normalizePersistedViewerState(persistedState),
285
+ }),
111
286
  partialize: (state) => ({
112
287
  cameraMode: state.cameraMode,
113
- theme: state.theme,
114
- unit: state.unit,
288
+ sceneTheme: state.sceneTheme,
289
+ shadingByContext: state.shadingByContext,
290
+ textures: state.textures,
291
+ colorPreset: state.colorPreset,
292
+ edges: state.edges,
293
+ shadows: state.shadows,
294
+ ...(state.unitExplicit ? { unit: state.unit } : {}),
115
295
  levelMode: state.levelMode,
116
296
  wallMode: state.wallMode,
117
297
  projectPreferences: state.projectPreferences,
118
298
  }),
119
299
  }));
300
+ /** Apply an authoritative country code (e.g. IP-derived by the host app) as
301
+ * the unit default. Stronger signal than the timezone heuristic used at store
302
+ * creation, but still a default: it never overrides an explicit user choice
303
+ * and is not persisted (the unit only sticks once the user touches the
304
+ * toggle). */
305
+ export function applyCountryUnitDefault(country) {
306
+ if (!country)
307
+ return;
308
+ const state = useViewer.getState();
309
+ if (state.unitExplicit)
310
+ return;
311
+ const unit = IMPERIAL_REGIONS.includes(country.toUpperCase()) ? 'imperial' : 'metric';
312
+ if (state.unit !== unit)
313
+ useViewer.setState({ unit });
314
+ }
120
315
  export default useViewer;
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=use-viewer.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-viewer.test.d.ts","sourceRoot":"","sources":["../../src/store/use-viewer.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,42 @@
1
+ // @ts-expect-error — bun:test is provided by the Bun runtime; viewer does not
2
+ // include Bun ambient types in its production declaration build.
3
+ import { afterEach, beforeEach, describe, expect, test } from 'bun:test';
4
+ import useViewer from './use-viewer';
5
+ const resetMeasurementPreferences = () => {
6
+ useViewer.setState({
7
+ projectId: null,
8
+ projectPreferences: {},
9
+ showMeasurements: true,
10
+ unit: 'metric',
11
+ });
12
+ };
13
+ beforeEach(resetMeasurementPreferences);
14
+ afterEach(resetMeasurementPreferences);
15
+ describe('measurement display preferences', () => {
16
+ test('stores global visibility per project and defaults new projects to visible', () => {
17
+ const viewer = useViewer.getState();
18
+ viewer.setProjectId('project-a');
19
+ viewer.setShowMeasurements(false);
20
+ expect(useViewer.getState()).toMatchObject({
21
+ projectId: 'project-a',
22
+ showMeasurements: false,
23
+ projectPreferences: {
24
+ 'project-a': { showMeasurements: false },
25
+ },
26
+ });
27
+ useViewer.getState().setProjectId('project-b');
28
+ expect(useViewer.getState().showMeasurements).toBe(true);
29
+ useViewer.getState().setProjectId('project-a');
30
+ expect(useViewer.getState().showMeasurements).toBe(false);
31
+ });
32
+ test('changes display units without changing measurement visibility preferences', () => {
33
+ const viewer = useViewer.getState();
34
+ viewer.setProjectId('project-a');
35
+ viewer.setShowMeasurements(false);
36
+ const preferences = useViewer.getState().projectPreferences;
37
+ useViewer.getState().setUnit('imperial');
38
+ expect(useViewer.getState().unit).toBe('imperial');
39
+ expect(useViewer.getState().projectPreferences).toEqual(preferences);
40
+ expect(useViewer.getState().showMeasurements).toBe(false);
41
+ });
42
+ });
@@ -2,7 +2,11 @@ import { type CeilingNode } from '@pascal-app/core';
2
2
  import * as THREE from 'three';
3
3
  export declare const CeilingSystem: () => null;
4
4
  /**
5
- * Generates flat ceiling geometry from polygon (no extrusion)
5
+ * Generates flat ceiling geometry from polygon (no extrusion).
6
+ *
7
+ * `extraHoles` are transient, derived cutouts (e.g. recessed-fixture
8
+ * footprints) that are cut alongside the node's persisted `holes` but never
9
+ * stored on the node — they are recomputed on every rebuild.
6
10
  */
7
- export declare function generateCeilingGeometry(ceilingNode: CeilingNode): THREE.BufferGeometry;
11
+ export declare function generateCeilingGeometry(ceilingNode: CeilingNode, extraHoles?: Array<Array<[number, number]>>): THREE.BufferGeometry;
8
12
  //# sourceMappingURL=ceiling-system.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ceiling-system.d.ts","sourceRoot":"","sources":["../../../src/systems/ceiling/ceiling-system.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,WAAW,EAA2B,MAAM,kBAAkB,CAAA;AAE5F,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAa9B,eAAO,MAAM,aAAa,YAuBzB,CAAA;AAqBD;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,WAAW,EAAE,WAAW,GAAG,KAAK,CAAC,cAAc,CAgDtF"}
1
+ {"version":3,"file":"ceiling-system.d.ts","sourceRoot":"","sources":["../../../src/systems/ceiling/ceiling-system.tsx"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,WAAW,EAMjB,MAAM,kBAAkB,CAAA;AAEzB,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAgB9B,eAAO,MAAM,aAAa,YA4BzB,CAAA;AA2DD;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,WAAW,EAAE,WAAW,EACxB,UAAU,GAAE,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAM,GAC9C,KAAK,CAAC,cAAc,CA6DtB"}