@pascal-app/core 0.7.0 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (318) hide show
  1. package/dist/events/bus.d.ts +47 -18
  2. package/dist/events/bus.d.ts.map +1 -1
  3. package/dist/events/bus.js +1 -1
  4. package/dist/hooks/scene-registry/scene-registry.d.ts +6 -22
  5. package/dist/hooks/scene-registry/scene-registry.d.ts.map +1 -1
  6. package/dist/hooks/scene-registry/scene-registry.js +33 -26
  7. package/dist/hooks/spatial-grid/floor-placed-elevation.d.ts +14 -0
  8. package/dist/hooks/spatial-grid/floor-placed-elevation.d.ts.map +1 -0
  9. package/dist/hooks/spatial-grid/floor-placed-elevation.js +51 -0
  10. package/dist/hooks/spatial-grid/floor-placed-elevation.test.d.ts +2 -0
  11. package/dist/hooks/spatial-grid/floor-placed-elevation.test.d.ts.map +1 -0
  12. package/dist/hooks/spatial-grid/floor-placed-elevation.test.js +273 -0
  13. package/dist/hooks/spatial-grid/spatial-grid-manager.d.ts +13 -2
  14. package/dist/hooks/spatial-grid/spatial-grid-manager.d.ts.map +1 -1
  15. package/dist/hooks/spatial-grid/spatial-grid-manager.js +95 -9
  16. package/dist/hooks/spatial-grid/spatial-grid-sync.d.ts +28 -1
  17. package/dist/hooks/spatial-grid/spatial-grid-sync.d.ts.map +1 -1
  18. package/dist/hooks/spatial-grid/spatial-grid-sync.js +91 -18
  19. package/dist/index.d.ts +22 -4
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +19 -2
  22. package/dist/lib/polygon-geometry.d.ts.map +1 -1
  23. package/dist/lib/polygon-relations.d.ts +10 -0
  24. package/dist/lib/polygon-relations.d.ts.map +1 -0
  25. package/dist/lib/polygon-relations.js +73 -0
  26. package/dist/lib/space-detection-pause.test.d.ts +2 -0
  27. package/dist/lib/space-detection-pause.test.d.ts.map +1 -0
  28. package/dist/lib/space-detection-pause.test.js +42 -0
  29. package/dist/lib/space-detection.d.ts +30 -1
  30. package/dist/lib/space-detection.d.ts.map +1 -1
  31. package/dist/lib/space-detection.js +222 -41
  32. package/dist/lib/space-detection.test.d.ts +2 -0
  33. package/dist/lib/space-detection.test.d.ts.map +1 -0
  34. package/dist/lib/space-detection.test.js +77 -0
  35. package/dist/material-library.d.ts +1 -1
  36. package/dist/material-library.d.ts.map +1 -1
  37. package/dist/material-library.js +1957 -141
  38. package/dist/registry/__bench__/relations-resolver.bench.d.ts +15 -0
  39. package/dist/registry/__bench__/relations-resolver.bench.d.ts.map +1 -0
  40. package/dist/registry/__bench__/relations-resolver.bench.js +170 -0
  41. package/dist/registry/handles.d.ts +321 -0
  42. package/dist/registry/handles.d.ts.map +1 -0
  43. package/dist/registry/handles.js +24 -0
  44. package/dist/registry/index.d.ts +7 -0
  45. package/dist/registry/index.d.ts.map +1 -0
  46. package/dist/registry/index.js +4 -0
  47. package/dist/registry/registry.d.ts +93 -0
  48. package/dist/registry/registry.d.ts.map +1 -0
  49. package/dist/registry/registry.js +201 -0
  50. package/dist/registry/registry.test.d.ts +2 -0
  51. package/dist/registry/registry.test.d.ts.map +1 -0
  52. package/dist/registry/registry.test.js +183 -0
  53. package/dist/registry/relations-resolver.d.ts +42 -0
  54. package/dist/registry/relations-resolver.d.ts.map +1 -0
  55. package/dist/registry/relations-resolver.js +77 -0
  56. package/dist/registry/relations-resolver.test.d.ts +2 -0
  57. package/dist/registry/relations-resolver.test.d.ts.map +1 -0
  58. package/dist/registry/relations-resolver.test.js +183 -0
  59. package/dist/registry/scene-api.d.ts +44 -0
  60. package/dist/registry/scene-api.d.ts.map +1 -0
  61. package/dist/registry/scene-api.js +111 -0
  62. package/dist/registry/scene-api.test.d.ts +2 -0
  63. package/dist/registry/scene-api.test.d.ts.map +1 -0
  64. package/dist/registry/scene-api.test.js +183 -0
  65. package/dist/registry/subtree.d.ts +67 -0
  66. package/dist/registry/subtree.d.ts.map +1 -0
  67. package/dist/registry/subtree.js +119 -0
  68. package/dist/registry/subtree.test.d.ts +2 -0
  69. package/dist/registry/subtree.test.d.ts.map +1 -0
  70. package/dist/registry/subtree.test.js +133 -0
  71. package/dist/registry/types.d.ts +1420 -0
  72. package/dist/registry/types.d.ts.map +1 -0
  73. package/dist/registry/types.js +1 -0
  74. package/dist/schema/asset-url.test.js +0 -4
  75. package/dist/schema/index.d.ts +17 -2
  76. package/dist/schema/index.d.ts.map +1 -1
  77. package/dist/schema/index.js +17 -3
  78. package/dist/schema/material.d.ts +12 -2
  79. package/dist/schema/material.d.ts.map +1 -1
  80. package/dist/schema/material.js +10 -0
  81. package/dist/schema/nodes/box-vent.d.ts +74 -0
  82. package/dist/schema/nodes/box-vent.d.ts.map +1 -0
  83. package/dist/schema/nodes/box-vent.js +63 -0
  84. package/dist/schema/nodes/building.d.ts +1 -1
  85. package/dist/schema/nodes/building.d.ts.map +1 -1
  86. package/dist/schema/nodes/building.js +3 -2
  87. package/dist/schema/nodes/ceiling.d.ts +3 -1
  88. package/dist/schema/nodes/ceiling.d.ts.map +1 -1
  89. package/dist/schema/nodes/ceiling.js +1 -1
  90. package/dist/schema/nodes/chimney.d.ts +158 -0
  91. package/dist/schema/nodes/chimney.d.ts.map +1 -0
  92. package/dist/schema/nodes/chimney.js +67 -0
  93. package/dist/schema/nodes/column.d.ts +598 -6
  94. package/dist/schema/nodes/column.d.ts.map +1 -1
  95. package/dist/schema/nodes/column.js +586 -6
  96. package/dist/schema/nodes/cupola.d.ts +66 -0
  97. package/dist/schema/nodes/cupola.d.ts.map +1 -0
  98. package/dist/schema/nodes/cupola.js +28 -0
  99. package/dist/schema/nodes/door.d.ts +1 -1
  100. package/dist/schema/nodes/dormer.d.ts +228 -0
  101. package/dist/schema/nodes/dormer.d.ts.map +1 -0
  102. package/dist/schema/nodes/dormer.js +119 -0
  103. package/dist/schema/nodes/downspout.d.ts +75 -0
  104. package/dist/schema/nodes/downspout.d.ts.map +1 -0
  105. package/dist/schema/nodes/downspout.js +63 -0
  106. package/dist/schema/nodes/elevator.d.ts +105 -0
  107. package/dist/schema/nodes/elevator.d.ts.map +1 -0
  108. package/dist/schema/nodes/elevator.js +54 -0
  109. package/dist/schema/nodes/eyebrow-vent.d.ts +68 -0
  110. package/dist/schema/nodes/eyebrow-vent.d.ts.map +1 -0
  111. package/dist/schema/nodes/eyebrow-vent.js +40 -0
  112. package/dist/schema/nodes/fence.d.ts +3 -2
  113. package/dist/schema/nodes/fence.d.ts.map +1 -1
  114. package/dist/schema/nodes/fence.js +4 -2
  115. package/dist/schema/nodes/gutter.d.ts +84 -0
  116. package/dist/schema/nodes/gutter.d.ts.map +1 -0
  117. package/dist/schema/nodes/gutter.js +76 -0
  118. package/dist/schema/nodes/item.d.ts +16 -0
  119. package/dist/schema/nodes/item.d.ts.map +1 -1
  120. package/dist/schema/nodes/item.js +21 -0
  121. package/dist/schema/nodes/level.d.ts +1 -1
  122. package/dist/schema/nodes/level.d.ts.map +1 -1
  123. package/dist/schema/nodes/level.js +2 -0
  124. package/dist/schema/nodes/ridge-vent.d.ts +67 -0
  125. package/dist/schema/nodes/ridge-vent.d.ts.map +1 -0
  126. package/dist/schema/nodes/ridge-vent.js +30 -0
  127. package/dist/schema/nodes/roof-segment.d.ts +198 -4
  128. package/dist/schema/nodes/roof-segment.d.ts.map +1 -1
  129. package/dist/schema/nodes/roof-segment.js +254 -3
  130. package/dist/schema/nodes/roof.d.ts +6 -6
  131. package/dist/schema/nodes/roof.d.ts.map +1 -1
  132. package/dist/schema/nodes/roof.js +9 -21
  133. package/dist/schema/nodes/shelf.d.ts +105 -0
  134. package/dist/schema/nodes/shelf.d.ts.map +1 -0
  135. package/dist/schema/nodes/shelf.js +84 -0
  136. package/dist/schema/nodes/site.d.ts +1 -116
  137. package/dist/schema/nodes/site.d.ts.map +1 -1
  138. package/dist/schema/nodes/site.js +2 -6
  139. package/dist/schema/nodes/skylight.d.ts +279 -0
  140. package/dist/schema/nodes/skylight.d.ts.map +1 -0
  141. package/dist/schema/nodes/skylight.js +152 -0
  142. package/dist/schema/nodes/slab.d.ts +3 -1
  143. package/dist/schema/nodes/slab.d.ts.map +1 -1
  144. package/dist/schema/nodes/slab.js +1 -1
  145. package/dist/schema/nodes/solar-panel.d.ts +117 -0
  146. package/dist/schema/nodes/solar-panel.d.ts.map +1 -0
  147. package/dist/schema/nodes/solar-panel.js +47 -0
  148. package/dist/schema/nodes/stair-segment.d.ts +1 -1
  149. package/dist/schema/nodes/stair.d.ts +6 -6
  150. package/dist/schema/nodes/stair.d.ts.map +1 -1
  151. package/dist/schema/nodes/stair.js +9 -7
  152. package/dist/schema/nodes/surface-hole-metadata.d.ts +2 -0
  153. package/dist/schema/nodes/surface-hole-metadata.d.ts.map +1 -1
  154. package/dist/schema/nodes/surface-hole-metadata.js +3 -1
  155. package/dist/schema/nodes/turbine-vent.d.ts +68 -0
  156. package/dist/schema/nodes/turbine-vent.d.ts.map +1 -0
  157. package/dist/schema/nodes/turbine-vent.js +41 -0
  158. package/dist/schema/nodes/wall.d.ts +3 -3
  159. package/dist/schema/nodes/window.d.ts +1 -1
  160. package/dist/schema/types.d.ts +1448 -236
  161. package/dist/schema/types.d.ts.map +1 -1
  162. package/dist/schema/types.js +26 -0
  163. package/dist/services/alignment-anchors.d.ts +100 -0
  164. package/dist/services/alignment-anchors.d.ts.map +1 -0
  165. package/dist/services/alignment-anchors.js +283 -0
  166. package/dist/services/alignment-anchors.test.d.ts +2 -0
  167. package/dist/services/alignment-anchors.test.d.ts.map +1 -0
  168. package/dist/services/alignment-anchors.test.js +383 -0
  169. package/dist/services/alignment.d.ts +126 -0
  170. package/dist/services/alignment.d.ts.map +1 -0
  171. package/dist/services/alignment.js +169 -0
  172. package/dist/services/alignment.test.d.ts +2 -0
  173. package/dist/services/alignment.test.d.ts.map +1 -0
  174. package/dist/services/alignment.test.js +92 -0
  175. package/dist/services/drag-session.d.ts +47 -0
  176. package/dist/services/drag-session.d.ts.map +1 -0
  177. package/dist/services/drag-session.js +100 -0
  178. package/dist/services/drag-session.test.d.ts +2 -0
  179. package/dist/services/drag-session.test.d.ts.map +1 -0
  180. package/dist/services/drag-session.test.js +219 -0
  181. package/dist/services/hosting.d.ts +80 -0
  182. package/dist/services/hosting.d.ts.map +1 -0
  183. package/dist/services/hosting.js +122 -0
  184. package/dist/services/hosting.test.d.ts +2 -0
  185. package/dist/services/hosting.test.d.ts.map +1 -0
  186. package/dist/services/hosting.test.js +199 -0
  187. package/dist/services/index.d.ts +7 -0
  188. package/dist/services/index.d.ts.map +1 -0
  189. package/dist/services/index.js +6 -0
  190. package/dist/services/movement.d.ts +48 -0
  191. package/dist/services/movement.d.ts.map +1 -0
  192. package/dist/services/movement.js +65 -0
  193. package/dist/services/movement.test.d.ts +2 -0
  194. package/dist/services/movement.test.d.ts.map +1 -0
  195. package/dist/services/movement.test.js +133 -0
  196. package/dist/services/single-undo-dance.test.d.ts +2 -0
  197. package/dist/services/single-undo-dance.test.d.ts.map +1 -0
  198. package/dist/services/single-undo-dance.test.js +210 -0
  199. package/dist/services/snap.d.ts +72 -0
  200. package/dist/services/snap.d.ts.map +1 -0
  201. package/dist/services/snap.js +120 -0
  202. package/dist/services/snap.test.d.ts +2 -0
  203. package/dist/services/snap.test.d.ts.map +1 -0
  204. package/dist/services/snap.test.js +95 -0
  205. package/dist/solar-panel-presets.d.ts +17 -0
  206. package/dist/solar-panel-presets.d.ts.map +1 -0
  207. package/dist/solar-panel-presets.js +43 -0
  208. package/dist/store/actions/node-actions.d.ts +14 -2
  209. package/dist/store/actions/node-actions.d.ts.map +1 -1
  210. package/dist/store/actions/node-actions.js +499 -20
  211. package/dist/store/actions/node-mutation-sanitize.test.d.ts +2 -0
  212. package/dist/store/actions/node-mutation-sanitize.test.d.ts.map +1 -0
  213. package/dist/store/actions/node-mutation-sanitize.test.js +147 -0
  214. package/dist/store/actions/reparent.test.d.ts +2 -0
  215. package/dist/store/actions/reparent.test.d.ts.map +1 -0
  216. package/dist/store/actions/reparent.test.js +212 -0
  217. package/dist/store/use-interactive.d.ts +39 -0
  218. package/dist/store/use-interactive.d.ts.map +1 -1
  219. package/dist/store/use-interactive.js +75 -0
  220. package/dist/store/use-live-node-overrides.d.ts +22 -0
  221. package/dist/store/use-live-node-overrides.d.ts.map +1 -0
  222. package/dist/store/use-live-node-overrides.js +59 -0
  223. package/dist/store/use-scene-elevator-migration.test.d.ts +2 -0
  224. package/dist/store/use-scene-elevator-migration.test.d.ts.map +1 -0
  225. package/dist/store/use-scene-elevator-migration.test.js +109 -0
  226. package/dist/store/use-scene.d.ts +11 -0
  227. package/dist/store/use-scene.d.ts.map +1 -1
  228. package/dist/store/use-scene.js +207 -11
  229. package/dist/systems/elevator/elevator-dispatch.d.ts +12 -0
  230. package/dist/systems/elevator/elevator-dispatch.d.ts.map +1 -0
  231. package/dist/systems/elevator/elevator-dispatch.js +57 -0
  232. package/dist/systems/elevator/elevator-geometry.d.ts +15 -0
  233. package/dist/systems/elevator/elevator-geometry.d.ts.map +1 -0
  234. package/dist/systems/elevator/elevator-geometry.js +50 -0
  235. package/dist/systems/elevator/elevator-opening-sync.d.ts +6 -0
  236. package/dist/systems/elevator/elevator-opening-sync.d.ts.map +1 -0
  237. package/dist/systems/elevator/elevator-opening-sync.js +218 -0
  238. package/dist/systems/elevator/elevator-opening-sync.test.d.ts +2 -0
  239. package/dist/systems/elevator/elevator-opening-sync.test.d.ts.map +1 -0
  240. package/dist/systems/elevator/elevator-opening-sync.test.js +146 -0
  241. package/dist/systems/elevator/elevator-opening-system.d.ts +2 -0
  242. package/dist/systems/elevator/elevator-opening-system.d.ts.map +1 -0
  243. package/dist/systems/elevator/elevator-opening-system.js +48 -0
  244. package/dist/systems/elevator/elevator-runtime-system.d.ts +2 -0
  245. package/dist/systems/elevator/elevator-runtime-system.d.ts.map +1 -0
  246. package/dist/systems/elevator/elevator-runtime-system.js +8 -0
  247. package/dist/systems/elevator/elevator-runtime.d.ts +18 -0
  248. package/dist/systems/elevator/elevator-runtime.d.ts.map +1 -0
  249. package/dist/systems/elevator/elevator-runtime.js +225 -0
  250. package/dist/systems/elevator/elevator-runtime.test.d.ts +2 -0
  251. package/dist/systems/elevator/elevator-runtime.test.d.ts.map +1 -0
  252. package/dist/systems/elevator/elevator-runtime.test.js +64 -0
  253. package/dist/systems/elevator/elevator-service.d.ts +19 -0
  254. package/dist/systems/elevator/elevator-service.d.ts.map +1 -0
  255. package/dist/systems/elevator/elevator-service.js +111 -0
  256. package/dist/systems/stair/stair-footprint.d.ts +44 -0
  257. package/dist/systems/stair/stair-footprint.d.ts.map +1 -0
  258. package/dist/systems/stair/stair-footprint.js +168 -0
  259. package/dist/systems/stair/stair-opening-preview.d.ts +1777 -0
  260. package/dist/systems/stair/stair-opening-preview.d.ts.map +1 -0
  261. package/dist/systems/stair/stair-opening-preview.js +93 -0
  262. package/dist/systems/stair/stair-opening-preview.test.d.ts +2 -0
  263. package/dist/systems/stair/stair-opening-preview.test.d.ts.map +1 -0
  264. package/dist/systems/stair/stair-opening-preview.test.js +80 -0
  265. package/dist/systems/stair/stair-opening-sync.d.ts.map +1 -1
  266. package/dist/systems/stair/stair-opening-sync.js +183 -185
  267. package/dist/systems/stair/stair-opening-sync.test.js +385 -4
  268. package/dist/systems/stair/stair-opening-system.d.ts +2 -0
  269. package/dist/systems/stair/stair-opening-system.d.ts.map +1 -0
  270. package/dist/systems/stair/stair-opening-system.js +104 -0
  271. package/dist/systems/wall/wall-curve.d.ts +1 -1
  272. package/dist/systems/wall/wall-curve.d.ts.map +1 -1
  273. package/dist/systems/wall/wall-curve.js +1 -1
  274. package/dist/systems/wall/wall-mitering.d.ts.map +1 -1
  275. package/dist/systems/wall/wall-mitering.js +2 -6
  276. package/dist/systems/wall/wall-move.d.ts +48 -0
  277. package/dist/systems/wall/wall-move.d.ts.map +1 -0
  278. package/dist/systems/wall/wall-move.js +193 -0
  279. package/dist/utils/clone-scene-graph.d.ts +6 -4
  280. package/dist/utils/clone-scene-graph.d.ts.map +1 -1
  281. package/dist/utils/clone-scene-graph.js +6 -4
  282. package/dist/utils/clone-scene-graph.test.d.ts +2 -0
  283. package/dist/utils/clone-scene-graph.test.d.ts.map +1 -0
  284. package/dist/utils/clone-scene-graph.test.js +59 -0
  285. package/dist/validation/validate-build-json.d.ts +43 -0
  286. package/dist/validation/validate-build-json.d.ts.map +1 -0
  287. package/dist/validation/validate-build-json.js +227 -0
  288. package/package.json +11 -3
  289. package/dist/materials.d.ts +0 -10
  290. package/dist/materials.d.ts.map +0 -1
  291. package/dist/materials.js +0 -22
  292. package/dist/systems/ceiling/ceiling-system.d.ts +0 -8
  293. package/dist/systems/ceiling/ceiling-system.d.ts.map +0 -1
  294. package/dist/systems/ceiling/ceiling-system.js +0 -92
  295. package/dist/systems/door/door-system.d.ts +0 -2
  296. package/dist/systems/door/door-system.d.ts.map +0 -1
  297. package/dist/systems/door/door-system.js +0 -195
  298. package/dist/systems/fence/fence-system.d.ts +0 -2
  299. package/dist/systems/fence/fence-system.d.ts.map +0 -1
  300. package/dist/systems/fence/fence-system.js +0 -187
  301. package/dist/systems/item/item-system.d.ts +0 -2
  302. package/dist/systems/item/item-system.d.ts.map +0 -1
  303. package/dist/systems/item/item-system.js +0 -48
  304. package/dist/systems/roof/roof-system.d.ts +0 -16
  305. package/dist/systems/roof/roof-system.d.ts.map +0 -1
  306. package/dist/systems/roof/roof-system.js +0 -797
  307. package/dist/systems/slab/slab-system.d.ts +0 -8
  308. package/dist/systems/slab/slab-system.d.ts.map +0 -1
  309. package/dist/systems/slab/slab-system.js +0 -214
  310. package/dist/systems/stair/stair-system.d.ts +0 -2
  311. package/dist/systems/stair/stair-system.d.ts.map +0 -1
  312. package/dist/systems/stair/stair-system.js +0 -776
  313. package/dist/systems/wall/wall-system.d.ts +0 -12
  314. package/dist/systems/wall/wall-system.d.ts.map +0 -1
  315. package/dist/systems/wall/wall-system.js +0 -455
  316. package/dist/systems/window/window-system.d.ts +0 -2
  317. package/dist/systems/window/window-system.d.ts.map +0 -1
  318. package/dist/systems/window/window-system.js +0 -131
@@ -1,17 +1,25 @@
1
1
  import type { ThreeEvent } from '@react-three/fiber';
2
2
  import type { Object3D } from 'three';
3
- import type { BuildingNode, CeilingNode, ColumnNode, DoorNode, FenceNode, GuideNode, ItemNode, LevelNode, RoofNode, RoofSegmentNode, SiteNode, SlabNode, SpawnNode, StairNode, StairSegmentNode, WallNode, WindowNode, ZoneNode } from '../schema';
3
+ import type { BoxVentNode, BuildingNode, CeilingNode, ChimneyNode, ColumnNode, CupolaNode, DoorNode, DormerNode, DownspoutNode, ElevatorNode, EyebrowVentNode, FenceNode, GuideNode, GutterNode, ItemNode, LevelNode, RidgeVentNode, RoofNode, RoofSegmentNode, ScanNode, ShelfNode, SiteNode, SkylightNode, SlabNode, SolarPanelNode, SpawnNode, StairNode, StairSegmentNode, TurbineVentNode, WallNode, WindowNode, ZoneNode } from '../schema';
4
4
  import type { AnyNode } from '../schema/types';
5
5
  export interface GridEvent {
6
6
  /** World-space intersection point on the grid plane. */
7
7
  position: [number, number, number];
8
8
  /**
9
- * Building-local intersection point, relative to the currently selected building.
9
+ * Building-local intersection point relative to the currently selected building.
10
10
  * Equals `position` when no building is selected.
11
- * Use this for placing or committing anything that lives inside a building
12
- * (walls, slabs, items, etc.).
11
+ * Use this for placing/committing anything that lives inside a building (walls, slabs, items, etc.).
13
12
  */
14
13
  localPosition: [number, number, number];
14
+ faceIndex?: number;
15
+ /**
16
+ * Optional: the hit Three.js object. Present when the grid event was
17
+ * synthesized from a R3F mesh hit (the legacy grid-plane mesh path);
18
+ * absent when emitted by the canvas-level raycaster in
19
+ * `use-grid-events.ts`, where there is no specific mesh to attribute
20
+ * the intersection to.
21
+ */
22
+ object?: Object3D;
15
23
  nativeEvent: ThreeEvent<PointerEvent>;
16
24
  }
17
25
  export interface NodeEvent<T extends AnyNode = AnyNode> {
@@ -23,6 +31,7 @@ export interface NodeEvent<T extends AnyNode = AnyNode> {
23
31
  object: Object3D;
24
32
  stopPropagation: () => void;
25
33
  nativeEvent: ThreeEvent<PointerEvent>;
34
+ viaHandle?: boolean;
26
35
  }
27
36
  export type WallEvent = NodeEvent<WallNode>;
28
37
  export type FenceEvent = NodeEvent<FenceNode>;
@@ -31,6 +40,7 @@ export type SiteEvent = NodeEvent<SiteNode>;
31
40
  export type BuildingEvent = NodeEvent<BuildingNode>;
32
41
  export type LevelEvent = NodeEvent<LevelNode>;
33
42
  export type ZoneEvent = NodeEvent<ZoneNode>;
43
+ export type ShelfEvent = NodeEvent<ShelfNode>;
34
44
  export type SlabEvent = NodeEvent<SlabNode>;
35
45
  export type SpawnEvent = NodeEvent<SpawnNode>;
36
46
  export type CeilingEvent = NodeEvent<CeilingNode>;
@@ -41,6 +51,20 @@ export type StairEvent = NodeEvent<StairNode>;
41
51
  export type StairSegmentEvent = NodeEvent<StairSegmentNode>;
42
52
  export type WindowEvent = NodeEvent<WindowNode>;
43
53
  export type DoorEvent = NodeEvent<DoorNode>;
54
+ export type ElevatorEvent = NodeEvent<ElevatorNode>;
55
+ export type ScanEvent = NodeEvent<ScanNode>;
56
+ export type GuideEvent = NodeEvent<GuideNode>;
57
+ export type BoxVentEvent = NodeEvent<BoxVentNode>;
58
+ export type RidgeVentEvent = NodeEvent<RidgeVentNode>;
59
+ export type TurbineVentEvent = NodeEvent<TurbineVentNode>;
60
+ export type CupolaEvent = NodeEvent<CupolaNode>;
61
+ export type EyebrowVentEvent = NodeEvent<EyebrowVentNode>;
62
+ export type GutterEvent = NodeEvent<GutterNode>;
63
+ export type ChimneyEvent = NodeEvent<ChimneyNode>;
64
+ export type SolarPanelEvent = NodeEvent<SolarPanelNode>;
65
+ export type SkylightEvent = NodeEvent<SkylightNode>;
66
+ export type DormerEvent = NodeEvent<DormerNode>;
67
+ export type DownspoutEvent = NodeEvent<DownspoutNode>;
44
68
  export declare const eventSuffixes: readonly ["click", "move", "enter", "leave", "pointerdown", "pointerup", "context-menu", "double-click"];
45
69
  export type EventSuffix = (typeof eventSuffixes)[number];
46
70
  type NodeEvents<T extends string, E> = {
@@ -64,15 +88,24 @@ export interface ThumbnailGenerateEvent {
64
88
  /**
65
89
  * When true, snap levels to their true positions before capturing (for a
66
90
  * consistent auto-thumbnail angle) and defer the capture if the tab is
67
- * hidden, the background auto-save path. Omit for user-driven captures
91
+ * hidden the background auto-save path. Omit for user-driven captures
68
92
  * that should fire immediately from the current camera pose.
69
93
  */
70
94
  snapLevels?: boolean;
95
+ /**
96
+ * When true, keep the rendered alpha channel — emits a transparent PNG
97
+ * without baking the scene background into the output. Used by the
98
+ * preset capture flow so saved preset thumbnails composite cleanly on
99
+ * any palette background.
100
+ */
101
+ transparent?: boolean;
71
102
  }
72
103
  export interface CameraControlFitSceneEvent {
73
104
  /**
74
- * XZ-plane axis-aligned bounds for camera framing. Omitted values let the
75
- * listener choose its default framing pose.
105
+ * XZ-plane axis-aligned bounds of the scene's geometry, computed from the
106
+ * scene graph (see `@pascal-app/editor`'s `computeSceneBoundsXZ`). The
107
+ * viewer's camera-controls listener frames the camera onto this box.
108
+ * Omitted values fall back to the camera's default pose.
76
109
  */
77
110
  bounds?: {
78
111
  min: [number, number];
@@ -115,16 +148,6 @@ type WindowAnimationEvents = {
115
148
  field: 'operationState';
116
149
  };
117
150
  };
118
- type PresetEvents = {
119
- 'preset:generate-thumbnail': {
120
- presetId: string;
121
- nodeId: string;
122
- };
123
- 'preset:thumbnail-updated': {
124
- presetId: string;
125
- thumbnailUrl: string;
126
- };
127
- };
128
151
  type ThumbnailEvents = {
129
152
  'thumbnail:before-capture': undefined;
130
153
  'thumbnail:after-capture': undefined;
@@ -145,7 +168,13 @@ type AIChatEvents = {
145
168
  }[];
146
169
  };
147
170
  };
148
- type EditorEvents = GridEvents & NodeEvents<'wall', WallEvent> & NodeEvents<'fence', FenceEvent> & NodeEvents<'item', ItemEvent> & NodeEvents<'site', SiteEvent> & NodeEvents<'building', BuildingEvent> & NodeEvents<'level', LevelEvent> & NodeEvents<'zone', ZoneEvent> & NodeEvents<'slab', SlabEvent> & NodeEvents<'spawn', SpawnEvent> & NodeEvents<'ceiling', CeilingEvent> & NodeEvents<'column', ColumnEvent> & NodeEvents<'roof', RoofEvent> & NodeEvents<'roof-segment', RoofSegmentEvent> & NodeEvents<'stair', StairEvent> & NodeEvents<'stair-segment', StairSegmentEvent> & NodeEvents<'window', WindowEvent> & NodeEvents<'door', DoorEvent> & CameraControlEvents & ToolEvents & GuideEvents & DoorAnimationEvents & WindowAnimationEvents & PresetEvents & ThumbnailEvents & SnapshotEvents & AIChatEvents;
171
+ export interface RoomPresetCreateEvent {
172
+ zoneId: ZoneNode['id'];
173
+ }
174
+ type RoomPresetEvents = {
175
+ 'room-preset:create': RoomPresetCreateEvent;
176
+ };
177
+ type EditorEvents = GridEvents & NodeEvents<'wall', WallEvent> & NodeEvents<'fence', FenceEvent> & NodeEvents<'item', ItemEvent> & NodeEvents<'site', SiteEvent> & NodeEvents<'building', BuildingEvent> & NodeEvents<'elevator', ElevatorEvent> & NodeEvents<'level', LevelEvent> & NodeEvents<'zone', ZoneEvent> & NodeEvents<'slab', SlabEvent> & NodeEvents<'shelf', ShelfEvent> & NodeEvents<'spawn', SpawnEvent> & NodeEvents<'ceiling', CeilingEvent> & NodeEvents<'column', ColumnEvent> & NodeEvents<'roof', RoofEvent> & NodeEvents<'roof-segment', RoofSegmentEvent> & NodeEvents<'stair', StairEvent> & NodeEvents<'stair-segment', StairSegmentEvent> & NodeEvents<'window', WindowEvent> & NodeEvents<'door', DoorEvent> & NodeEvents<'scan', ScanEvent> & NodeEvents<'guide', GuideEvent> & NodeEvents<'box-vent', BoxVentEvent> & NodeEvents<'ridge-vent', RidgeVentEvent> & NodeEvents<'turbine-vent', TurbineVentEvent> & NodeEvents<'cupola', CupolaEvent> & NodeEvents<'eyebrow-vent', EyebrowVentEvent> & NodeEvents<'gutter', GutterEvent> & NodeEvents<'chimney', ChimneyEvent> & NodeEvents<'solar-panel', SolarPanelEvent> & NodeEvents<'skylight', SkylightEvent> & NodeEvents<'dormer', DormerEvent> & NodeEvents<'downspout', DownspoutEvent> & CameraControlEvents & ToolEvents & GuideEvents & DoorAnimationEvents & WindowAnimationEvents & ThumbnailEvents & SnapshotEvents & AIChatEvents & RoomPresetEvents;
149
178
  export declare const emitter: import("mitt").Emitter<EditorEvents>;
150
179
  export {};
151
180
  //# sourceMappingURL=bus.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"bus.d.ts","sourceRoot":"","sources":["../../src/events/bus.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"bus.d.ts","sourceRoot":"","sources":["../../src/events/bus.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import mitt from 'mitt';
2
- // Event suffixes, exported for use in hooks
2
+ // Event suffixes - exported for use in hooks
3
3
  export const eventSuffixes = [
4
4
  'click',
5
5
  'move',
@@ -1,29 +1,13 @@
1
1
  import type * as THREE from 'three';
2
+ type ByTypeMap = {
3
+ [kind: string]: Set<string>;
4
+ };
2
5
  export declare const sceneRegistry: {
3
6
  nodes: Map<string, THREE.Object3D<THREE.Object3DEventMap>>;
4
- byType: {
5
- site: Set<string>;
6
- building: Set<string>;
7
- ceiling: Set<string>;
8
- column: Set<string>;
9
- level: Set<string>;
10
- wall: Set<string>;
11
- fence: Set<string>;
12
- item: Set<string>;
13
- slab: Set<string>;
14
- spawn: Set<string>;
15
- zone: Set<string>;
16
- roof: Set<string>;
17
- 'roof-segment': Set<string>;
18
- stair: Set<string>;
19
- 'stair-segment': Set<string>;
20
- scan: Set<string>;
21
- guide: Set<string>;
22
- window: Set<string>;
23
- door: Set<string>;
24
- };
7
+ byType: ByTypeMap;
25
8
  /** Remove all entries. Call when unloading a scene to prevent stale 3D refs. */
26
9
  clear(): void;
27
10
  };
28
- export declare function useRegistry(id: string, type: keyof typeof sceneRegistry.byType, ref: React.RefObject<THREE.Object3D>): void;
11
+ export declare function useRegistry(id: string, type: string, ref: React.RefObject<THREE.Object3D>): void;
12
+ export {};
29
13
  //# sourceMappingURL=scene-registry.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"scene-registry.d.ts","sourceRoot":"","sources":["../../../src/hooks/scene-registry/scene-registry.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAA;AAEnC,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;IA4BxB,gFAAgF;;CAOjF,CAAA;AAED,wBAAgB,WAAW,CACzB,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,MAAM,OAAO,aAAa,CAAC,MAAM,EACvC,GAAG,EAAE,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,QAAQ,CAAC,QAkBrC"}
1
+ {"version":3,"file":"scene-registry.d.ts","sourceRoot":"","sources":["../../../src/hooks/scene-registry/scene-registry.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAA;AAYnC,KAAK,SAAS,GAAG;IAAE,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAAA;CAAE,CAAA;AA2BhD,eAAO,MAAM,aAAa;;;IAQxB,gFAAgF;;CAOjF,CAAA;AAED,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,QAAQ,CAAC,QAiBzF"}
@@ -1,35 +1,42 @@
1
1
  'use client';
2
2
  import { useLayoutEffect } from 'react';
3
+ const byTypeStore = new Map();
4
+ const byTypeProxy = new Proxy({}, {
5
+ get(_target, key) {
6
+ if (typeof key !== 'string')
7
+ return undefined;
8
+ let set = byTypeStore.get(key);
9
+ if (!set) {
10
+ set = new Set();
11
+ byTypeStore.set(key, set);
12
+ }
13
+ return set;
14
+ },
15
+ ownKeys() {
16
+ return Array.from(byTypeStore.keys());
17
+ },
18
+ has(_target, key) {
19
+ return typeof key === 'string' && byTypeStore.has(key);
20
+ },
21
+ getOwnPropertyDescriptor(_target, key) {
22
+ if (typeof key !== 'string')
23
+ return undefined;
24
+ const set = byTypeStore.get(key);
25
+ if (!set)
26
+ return undefined;
27
+ return { configurable: true, enumerable: true, value: set, writable: false };
28
+ },
29
+ });
3
30
  export const sceneRegistry = {
4
31
  // Master lookup: ID -> Object3D
5
32
  nodes: new Map(),
6
- // Categorized lookups: Type -> Set of IDs
7
- // Using a Set is faster for adding/deleting than an Array
8
- byType: {
9
- site: new Set(),
10
- building: new Set(),
11
- ceiling: new Set(),
12
- column: new Set(),
13
- level: new Set(),
14
- wall: new Set(),
15
- fence: new Set(),
16
- item: new Set(),
17
- slab: new Set(),
18
- spawn: new Set(),
19
- zone: new Set(),
20
- roof: new Set(),
21
- 'roof-segment': new Set(),
22
- stair: new Set(),
23
- 'stair-segment': new Set(),
24
- scan: new Set(),
25
- guide: new Set(),
26
- window: new Set(),
27
- door: new Set(),
28
- },
33
+ // Categorized lookups: Kind -> Set of IDs. Backed by a Proxy so any kind
34
+ // gets a Set on first touch no hardcoded list.
35
+ byType: byTypeProxy,
29
36
  /** Remove all entries. Call when unloading a scene to prevent stale 3D refs. */
30
37
  clear() {
31
38
  this.nodes.clear();
32
- for (const set of Object.values(this.byType)) {
39
+ for (const set of byTypeStore.values()) {
33
40
  set.clear();
34
41
  }
35
42
  },
@@ -41,9 +48,9 @@ export function useRegistry(id, type, ref) {
41
48
  return;
42
49
  // 1. Add to master map
43
50
  sceneRegistry.nodes.set(id, obj);
44
- // 2. Add to type-specific set
51
+ // 2. Add to type-specific set — Proxy auto-creates on first access.
45
52
  sceneRegistry.byType[type].add(id);
46
- // 4. Cleanup when component unmounts
53
+ // 3. Cleanup when component unmounts
47
54
  return () => {
48
55
  sceneRegistry.nodes.delete(id);
49
56
  sceneRegistry.byType[type].delete(id);
@@ -0,0 +1,14 @@
1
+ import type { FloorPlacedConfig, FloorPlacedFootprint, FloorPlacedFootprintContext, FloorPlacedFootprintsResolver } from '../../registry/types';
2
+ import type { AnyNode } from '../../schema';
3
+ export type FloorPlacedElevationArgs = {
4
+ node: AnyNode;
5
+ nodes: Record<string, AnyNode>;
6
+ position: [number, number, number];
7
+ rotation?: unknown;
8
+ levelId?: string | null;
9
+ };
10
+ export declare function getFloorPlacedFootprints(floorPlaced: FloorPlacedConfig, node: AnyNode, ctx?: FloorPlacedFootprintContext): FloorPlacedFootprint[];
11
+ export declare function getFloorPlacedElevation({ node, nodes, position, rotation, levelId, }: FloorPlacedElevationArgs): number;
12
+ export declare function getFloorStackedPosition(args: FloorPlacedElevationArgs): [number, number, number];
13
+ export type { FloorPlacedFootprint, FloorPlacedFootprintContext, FloorPlacedFootprintsResolver };
14
+ //# sourceMappingURL=floor-placed-elevation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"floor-placed-elevation.d.ts","sourceRoot":"","sources":["../../../src/hooks/spatial-grid/floor-placed-elevation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,iBAAiB,EACjB,oBAAoB,EACpB,2BAA2B,EAC3B,6BAA6B,EAC9B,MAAM,sBAAsB,CAAA;AAC7B,OAAO,KAAK,EAAE,OAAO,EAAa,MAAM,cAAc,CAAA;AAGtD,MAAM,MAAM,wBAAwB,GAAG;IACrC,IAAI,EAAE,OAAO,CAAA;IACb,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC9B,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IAClC,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACxB,CAAA;AAkBD,wBAAgB,wBAAwB,CACtC,WAAW,EAAE,iBAAiB,EAC9B,IAAI,EAAE,OAAO,EACb,GAAG,CAAC,EAAE,2BAA2B,GAChC,oBAAoB,EAAE,CAMxB;AAED,wBAAgB,uBAAuB,CAAC,EACtC,IAAI,EACJ,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,OAAO,GACR,EAAE,wBAAwB,GAAG,MAAM,CAiCnC;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,wBAAwB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAGhG;AAED,YAAY,EAAE,oBAAoB,EAAE,2BAA2B,EAAE,6BAA6B,EAAE,CAAA"}
@@ -0,0 +1,51 @@
1
+ import { nodeRegistry } from '../../registry';
2
+ import { spatialGridManager } from './spatial-grid-manager';
3
+ function finiteSlabElevation(elevation) {
4
+ return Number.isFinite(elevation) ? elevation : 0;
5
+ }
6
+ function withPositionAndRotation({ node, position, rotation, }) {
7
+ return {
8
+ ...node,
9
+ position,
10
+ ...(rotation !== undefined ? { rotation } : {}),
11
+ };
12
+ }
13
+ export function getFloorPlacedFootprints(floorPlaced, node, ctx) {
14
+ const rawFootprints = floorPlaced.footprints?.(node, ctx);
15
+ if (rawFootprints)
16
+ return [...rawFootprints];
17
+ const footprint = floorPlaced.footprint?.(node, ctx);
18
+ return footprint ? [footprint] : [];
19
+ }
20
+ export function getFloorPlacedElevation({ node, nodes, position, rotation, levelId, }) {
21
+ const floorPlaced = nodeRegistry.get(node.type)?.capabilities?.floorPlaced;
22
+ if (!floorPlaced)
23
+ return 0;
24
+ const effectiveNode = withPositionAndRotation({ node, position, rotation });
25
+ if (floorPlaced.applies && !floorPlaced.applies(effectiveNode))
26
+ return 0;
27
+ const parentId = effectiveNode.parentId ?? null;
28
+ const parent = parentId ? nodes[parentId] : null;
29
+ if (parentId && !parent)
30
+ return 0;
31
+ if (parent && parent.type !== 'level')
32
+ return 0;
33
+ if (!parent && !levelId)
34
+ return 0;
35
+ const resolvedLevelId = parent?.type === 'level' ? parent.id : levelId;
36
+ if (!resolvedLevelId)
37
+ return 0;
38
+ let maxElevation = Number.NEGATIVE_INFINITY;
39
+ for (const footprint of getFloorPlacedFootprints(floorPlaced, effectiveNode, { nodes })) {
40
+ const footprintPosition = footprint.position ?? position;
41
+ const elevation = finiteSlabElevation(spatialGridManager.getSlabElevationForItem(resolvedLevelId, footprintPosition, footprint.dimensions, footprint.rotation));
42
+ if (elevation > maxElevation) {
43
+ maxElevation = elevation;
44
+ }
45
+ }
46
+ return maxElevation === Number.NEGATIVE_INFINITY ? 0 : maxElevation;
47
+ }
48
+ export function getFloorStackedPosition(args) {
49
+ const [x, y, z] = args.position;
50
+ return [x, y + getFloorPlacedElevation(args), z];
51
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=floor-placed-elevation.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"floor-placed-elevation.test.d.ts","sourceRoot":"","sources":["../../../src/hooks/spatial-grid/floor-placed-elevation.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,273 @@
1
+ import { beforeEach, describe, expect, test } from 'bun:test';
2
+ import { z } from 'zod';
3
+ import { nodeRegistry, registerNode } from '../../registry';
4
+ import { getFloorPlacedElevation, getFloorStackedPosition } from './floor-placed-elevation';
5
+ import { spatialGridManager } from './spatial-grid-manager';
6
+ const LEVEL_ID = 'level_test';
7
+ function makeDefinition(kind, capabilities = {}) {
8
+ return {
9
+ kind,
10
+ schemaVersion: 1,
11
+ schema: z.object({ type: z.literal(kind) }),
12
+ category: 'utility',
13
+ defaults: () => ({}),
14
+ capabilities,
15
+ };
16
+ }
17
+ function makeLevel() {
18
+ return {
19
+ id: LEVEL_ID,
20
+ type: 'level',
21
+ object: 'node',
22
+ parentId: null,
23
+ visible: true,
24
+ metadata: {},
25
+ children: [],
26
+ level: 0,
27
+ };
28
+ }
29
+ function makeFloorNode(overrides = {}) {
30
+ return {
31
+ id: 'item_test',
32
+ type: 'item',
33
+ object: 'node',
34
+ parentId: LEVEL_ID,
35
+ visible: true,
36
+ metadata: {},
37
+ children: [],
38
+ position: [0, 0, 0],
39
+ rotation: [0, 0, 0],
40
+ scale: [1, 1, 1],
41
+ asset: {
42
+ id: 'asset_test',
43
+ category: 'test',
44
+ name: 'Test',
45
+ thumbnail: '',
46
+ src: 'asset:test',
47
+ dimensions: [1, 1, 1],
48
+ source: 'library',
49
+ },
50
+ ...overrides,
51
+ };
52
+ }
53
+ function addSlab(polygon, elevation, id = `slab_${elevation}`) {
54
+ const slab = {
55
+ id,
56
+ type: 'slab',
57
+ object: 'node',
58
+ parentId: LEVEL_ID,
59
+ visible: true,
60
+ metadata: {},
61
+ children: [],
62
+ polygon,
63
+ holes: [],
64
+ holeMetadata: [],
65
+ elevation,
66
+ autoFromWalls: false,
67
+ };
68
+ spatialGridManager.handleNodeCreated(slab, LEVEL_ID);
69
+ }
70
+ function nodesFor(...nodes) {
71
+ return Object.fromEntries(nodes.map((node) => [node.id, node]));
72
+ }
73
+ describe('floor-placed elevation resolver', () => {
74
+ beforeEach(() => {
75
+ nodeRegistry._reset();
76
+ spatialGridManager.clear();
77
+ });
78
+ test('returns 0 without a floorPlaced capability', () => {
79
+ registerNode(makeDefinition('item'));
80
+ addSlab([
81
+ [-1, -1],
82
+ [1, -1],
83
+ [1, 1],
84
+ [-1, 1],
85
+ ], 0.4);
86
+ const level = makeLevel();
87
+ const node = makeFloorNode();
88
+ expect(getFloorPlacedElevation({
89
+ node,
90
+ nodes: nodesFor(level, node),
91
+ position: [0, 0, 0],
92
+ rotation: [0, 0, 0],
93
+ })).toBe(0);
94
+ });
95
+ test('returns 0 when applies returns false', () => {
96
+ registerNode(makeDefinition('item', {
97
+ floorPlaced: {
98
+ footprint: () => ({ dimensions: [1, 1, 1], rotation: [0, 0, 0] }),
99
+ applies: () => false,
100
+ },
101
+ }));
102
+ addSlab([
103
+ [-1, -1],
104
+ [1, -1],
105
+ [1, 1],
106
+ [-1, 1],
107
+ ], 0.4);
108
+ const level = makeLevel();
109
+ const node = makeFloorNode();
110
+ expect(getFloorPlacedElevation({
111
+ node,
112
+ nodes: nodesFor(level, node),
113
+ position: [0, 0, 0],
114
+ rotation: [0, 0, 0],
115
+ })).toBe(0);
116
+ });
117
+ test('clamps non-finite slab elevation to 0', () => {
118
+ registerNode(makeDefinition('item', {
119
+ floorPlaced: {
120
+ footprint: () => ({ dimensions: [1, 1, 1], rotation: [0, 0, 0] }),
121
+ },
122
+ }));
123
+ const original = spatialGridManager.getSlabElevationForItem;
124
+ spatialGridManager.getSlabElevationForItem = (() => Number.NaN);
125
+ try {
126
+ const level = makeLevel();
127
+ const node = makeFloorNode();
128
+ expect(getFloorPlacedElevation({
129
+ node,
130
+ nodes: nodesFor(level, node),
131
+ position: [0, 0, 0],
132
+ rotation: [0, 0, 0],
133
+ })).toBe(0);
134
+ }
135
+ finally {
136
+ spatialGridManager.getSlabElevationForItem = original;
137
+ }
138
+ });
139
+ test('returns 0 for a non-level direct parent', () => {
140
+ registerNode(makeDefinition('item', {
141
+ floorPlaced: {
142
+ footprint: () => ({ dimensions: [1, 1, 1], rotation: [0, 0, 0] }),
143
+ },
144
+ }));
145
+ addSlab([
146
+ [-1, -1],
147
+ [1, -1],
148
+ [1, 1],
149
+ [-1, 1],
150
+ ], 0.4);
151
+ const level = makeLevel();
152
+ const shelf = {
153
+ id: 'shelf_test',
154
+ type: 'shelf',
155
+ parentId: LEVEL_ID,
156
+ };
157
+ const node = makeFloorNode({ parentId: shelf.id });
158
+ expect(getFloorPlacedElevation({
159
+ node,
160
+ nodes: nodesFor(level, shelf, node),
161
+ position: [0, 0, 0],
162
+ rotation: [0, 0, 0],
163
+ })).toBe(0);
164
+ });
165
+ test('returns 0 when the declared parent is missing', () => {
166
+ registerNode(makeDefinition('item', {
167
+ floorPlaced: {
168
+ footprint: () => ({ dimensions: [1, 1, 1], rotation: [0, 0, 0] }),
169
+ },
170
+ }));
171
+ addSlab([
172
+ [-1, -1],
173
+ [1, -1],
174
+ [1, 1],
175
+ [-1, 1],
176
+ ], 0.4);
177
+ const node = makeFloorNode({ parentId: 'missing_level' });
178
+ expect(getFloorPlacedElevation({
179
+ node,
180
+ nodes: nodesFor(node),
181
+ position: [0, 0, 0],
182
+ rotation: [0, 0, 0],
183
+ levelId: LEVEL_ID,
184
+ })).toBe(0);
185
+ });
186
+ test('uses the pending rotated footprint', () => {
187
+ registerNode(makeDefinition('item', {
188
+ floorPlaced: {
189
+ footprint: (node) => ({
190
+ dimensions: [4, 1, 1],
191
+ rotation: node.rotation,
192
+ }),
193
+ },
194
+ }));
195
+ addSlab([
196
+ [-0.2, 1.2],
197
+ [0.2, 1.2],
198
+ [0.2, 1.8],
199
+ [-0.2, 1.8],
200
+ ], 0.45);
201
+ const level = makeLevel();
202
+ const node = makeFloorNode();
203
+ expect(getFloorPlacedElevation({
204
+ node,
205
+ nodes: nodesFor(level, node),
206
+ position: [0, 0, 0],
207
+ rotation: [0, Math.PI / 2, 0],
208
+ })).toBeCloseTo(0.45);
209
+ });
210
+ test('returns slab overlap elevation and stacks Y onto canonical position', () => {
211
+ registerNode(makeDefinition('item', {
212
+ floorPlaced: {
213
+ footprint: (node) => ({
214
+ dimensions: [1, 1, 1],
215
+ rotation: node.rotation,
216
+ }),
217
+ },
218
+ }));
219
+ addSlab([
220
+ [-1, -1],
221
+ [1, -1],
222
+ [1, 1],
223
+ [-1, 1],
224
+ ], 0.35);
225
+ const level = makeLevel();
226
+ const node = makeFloorNode();
227
+ expect(getFloorPlacedElevation({
228
+ node,
229
+ nodes: nodesFor(level, node),
230
+ position: [0, 0.1, 0],
231
+ rotation: [0, 0, 0],
232
+ })).toBeCloseTo(0.35);
233
+ const stacked = getFloorStackedPosition({
234
+ node,
235
+ nodes: nodesFor(level, node),
236
+ position: [0, 0.1, 0],
237
+ rotation: [0, 0, 0],
238
+ });
239
+ expect(stacked[0]).toBe(0);
240
+ expect(stacked[1]).toBeCloseTo(0.45);
241
+ expect(stacked[2]).toBe(0);
242
+ });
243
+ test('takes the max elevation across composite footprints', () => {
244
+ registerNode(makeDefinition('item', {
245
+ floorPlaced: {
246
+ footprints: () => [
247
+ { position: [0, 0, 0], dimensions: [1, 1, 1], rotation: [0, 0, 0] },
248
+ { position: [3, 0, 0], dimensions: [1, 1, 1], rotation: [0, 0, 0] },
249
+ ],
250
+ },
251
+ }));
252
+ addSlab([
253
+ [-1, -1],
254
+ [1, -1],
255
+ [1, 1],
256
+ [-1, 1],
257
+ ], 0.2, 'slab_low');
258
+ addSlab([
259
+ [2.5, -0.5],
260
+ [3.5, -0.5],
261
+ [3.5, 0.5],
262
+ [2.5, 0.5],
263
+ ], 0.8, 'slab_high');
264
+ const level = makeLevel();
265
+ const node = makeFloorNode();
266
+ expect(getFloorPlacedElevation({
267
+ node,
268
+ nodes: nodesFor(level, node),
269
+ position: [0, 0, 0],
270
+ rotation: [0, 0, 0],
271
+ })).toBeCloseTo(0.8);
272
+ });
273
+ });