@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
@@ -8,17 +8,24 @@ export declare function pointInPolygon(px: number, pz: number, polygon: Array<[n
8
8
  * Checks: any item corner inside polygon, or any polygon vertex inside item AABB, or edges intersect.
9
9
  */
10
10
  export declare function itemOverlapsPolygon(position: [number, number, number], dimensions: [number, number, number], rotation: [number, number, number], polygon: Array<[number, number]>, inset?: number): boolean;
11
+ type WallOverlapInput = {
12
+ start: [number, number];
13
+ end: [number, number];
14
+ curveOffset?: number;
15
+ thickness?: number;
16
+ };
11
17
  /**
12
18
  * Test if a wall segment overlaps with a polygon.
13
19
  * A wall is considered to overlap if:
14
20
  * - Its midpoint is inside the polygon (wall crosses through)
15
21
  * - At least one endpoint is inside (wall partially or fully in slab)
16
22
  * - It's collinear with and overlaps a polygon edge (wall on slab boundary)
23
+ * - (curved walls) any sample along the centerline is inside
17
24
  *
18
25
  * Note: A wall with just one endpoint touching the edge but the rest outside
19
26
  * is NOT considered overlapping (adjacent only).
20
27
  */
21
- export declare function wallOverlapsPolygon(start: [number, number], end: [number, number], polygon: Array<[number, number]>): boolean;
28
+ export declare function wallOverlapsPolygon(startOrWall: [number, number] | WallOverlapInput, endOrPolygon: [number, number] | Array<[number, number]>, polygonArg?: Array<[number, number]>): boolean;
22
29
  export declare class SpatialGridManager {
23
30
  private readonly floorGrids;
24
31
  private readonly wallGrids;
@@ -78,8 +85,11 @@ export declare class SpatialGridManager {
78
85
  * Get the slab elevation for a wall by checking if it overlaps with any slab polygon (excluding holes).
79
86
  * Uses wallOverlapsPolygon which handles edge cases (points on boundary, collinear segments).
80
87
  * Returns the highest slab elevation found, or 0 if none.
88
+ *
89
+ * Accepts an optional `curveOffset` so curved walls evaluate overlap
90
+ * against their actual centerline samples, not just the chord.
81
91
  */
82
- getSlabElevationForWall(levelId: string, start: [number, number], end: [number, number]): number;
92
+ getSlabElevationForWall(levelId: string, start: [number, number], end: [number, number], curveOffset?: number, thickness?: number): number;
83
93
  /**
84
94
  * Check if an item can be placed on a ceiling.
85
95
  * Validates that the footprint is within the ceiling polygon (but not in any holes) and doesn't overlap other ceiling items.
@@ -92,4 +102,5 @@ export declare class SpatialGridManager {
92
102
  clear(): void;
93
103
  }
94
104
  export declare const spatialGridManager: SpatialGridManager;
105
+ export {};
95
106
  //# sourceMappingURL=spatial-grid-manager.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"spatial-grid-manager.d.ts","sourceRoot":"","sources":["../../../src/hooks/spatial-grid/spatial-grid-manager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"spatial-grid-manager.d.ts","sourceRoot":"","sources":["../../../src/hooks/spatial-grid/spatial-grid-manager.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,7 @@
1
1
  import { getScaledDimensions, isLowProfileItemSurface } from '../../schema';
2
2
  import useScene from '../../store/use-scene';
3
+ import { isCurvedWall, sampleWallCenterline } from '../../systems/wall/wall-curve';
4
+ import { DEFAULT_WALL_THICKNESS } from '../../systems/wall/wall-footprint';
3
5
  import { SpatialGrid } from './spatial-grid';
4
6
  import { WallSpatialGrid } from './wall-spatial-grid';
5
7
  // ============================================================================
@@ -191,11 +193,67 @@ function segmentsCollinearAndOverlap(ax1, az1, ax2, az2, bx1, bz1, bx2, bz2) {
191
193
  * - Its midpoint is inside the polygon (wall crosses through)
192
194
  * - At least one endpoint is inside (wall partially or fully in slab)
193
195
  * - It's collinear with and overlaps a polygon edge (wall on slab boundary)
196
+ * - (curved walls) any sample along the centerline is inside
194
197
  *
195
198
  * Note: A wall with just one endpoint touching the edge but the rest outside
196
199
  * is NOT considered overlapping (adjacent only).
197
200
  */
198
- export function wallOverlapsPolygon(start, end, polygon) {
201
+ export function wallOverlapsPolygon(startOrWall, endOrPolygon, polygonArg) {
202
+ // Two call shapes:
203
+ // wallOverlapsPolygon(wallLike, polygon) — preferred; curve-aware
204
+ // wallOverlapsPolygon(start, end, polygon) — legacy chord-only
205
+ let start;
206
+ let end;
207
+ let polygon;
208
+ let curveOffset = 0;
209
+ let thickness = DEFAULT_WALL_THICKNESS;
210
+ if (Array.isArray(startOrWall)) {
211
+ start = startOrWall;
212
+ end = endOrPolygon;
213
+ polygon = polygonArg;
214
+ }
215
+ else {
216
+ start = startOrWall.start;
217
+ end = startOrWall.end;
218
+ curveOffset = startOrWall.curveOffset ?? 0;
219
+ thickness = startOrWall.thickness ?? DEFAULT_WALL_THICKNESS;
220
+ polygon = endOrPolygon;
221
+ }
222
+ const halfThickness = Math.max(thickness / 2, 0);
223
+ // Curved walls: sample the centerline. The chord-based checks below miss
224
+ // walls that bow into/out of the slab — e.g. endpoints on the slab
225
+ // boundary with the curve arcing inward through the slab interior. Without
226
+ // this, `getSlabElevationForWall` returns 0 (wall drops to floor) and
227
+ // `markNodesOverlappingSlab` never re-dirties the wall when the slab Y
228
+ // moves.
229
+ if (curveOffset !== 0) {
230
+ const wallLike = { start, end, curveOffset };
231
+ if (isCurvedWall(wallLike)) {
232
+ const samples = sampleWallCenterline(wallLike, 16);
233
+ for (let i = 0; i < samples.length; i++) {
234
+ const point = samples[i];
235
+ if (pointInPolygon(point.x, point.y, polygon))
236
+ return true;
237
+ // Also test ±halfThickness perpendicular at each sample so a curve
238
+ // skirting the slab edge with its centerline just outside still
239
+ // registers — its body sits inside the slab.
240
+ if (halfThickness > 0 && i > 0) {
241
+ const prev = samples[i - 1];
242
+ const sx = point.x - prev.x;
243
+ const sz = point.y - prev.y;
244
+ const sl = Math.sqrt(sx * sx + sz * sz);
245
+ if (sl > 1e-10) {
246
+ const tnx = (-sz / sl) * halfThickness;
247
+ const tnz = (sx / sl) * halfThickness;
248
+ if (pointInPolygon(point.x + tnx, point.y + tnz, polygon))
249
+ return true;
250
+ if (pointInPolygon(point.x - tnx, point.y - tnz, polygon))
251
+ return true;
252
+ }
253
+ }
254
+ }
255
+ }
256
+ }
199
257
  const dx = end[0] - start[0];
200
258
  const dz = end[1] - start[1];
201
259
  const len = Math.sqrt(dx * dx + dz * dz);
@@ -230,6 +288,27 @@ export function wallOverlapsPolygon(start, end, polygon) {
230
288
  if (pointInPolygon(bx - pnx, bz - pnz, polygon))
231
289
  return true;
232
290
  }
291
+ // Wall-thickness perpendicular test. Walls aren't infinitely thin lines;
292
+ // a wall whose centerline sits just outside the slab boundary still has
293
+ // half its body inside the slab and should follow the slab elevation.
294
+ // Without this, the perimeter walls of a room often miss the slab-overlap
295
+ // detection (the slab polygon is the room's interior, the wall centerline
296
+ // sits on or just outside its edge) and stay at Y=0 while the slab moves
297
+ // up.
298
+ if (halfThickness > 0) {
299
+ const ux = dx / len;
300
+ const uz = dz / len;
301
+ const tnx = -uz * halfThickness;
302
+ const tnz = ux * halfThickness;
303
+ for (const t of [0, 0.25, 0.5, 0.75, 1]) {
304
+ const bx = start[0] + dx * t;
305
+ const bz = start[1] + dz * t;
306
+ if (pointInPolygon(bx + tnx, bz + tnz, polygon))
307
+ return true;
308
+ if (pointInPolygon(bx - tnx, bz - tnz, polygon))
309
+ return true;
310
+ }
311
+ }
233
312
  }
234
313
  // Check if midpoint is inside (catches walls crossing through)
235
314
  const midX = (start[0] + end[0]) / 2;
@@ -597,16 +676,27 @@ export class SpatialGridManager {
597
676
  * Get the slab elevation for a wall by checking if it overlaps with any slab polygon (excluding holes).
598
677
  * Uses wallOverlapsPolygon which handles edge cases (points on boundary, collinear segments).
599
678
  * Returns the highest slab elevation found, or 0 if none.
679
+ *
680
+ * Accepts an optional `curveOffset` so curved walls evaluate overlap
681
+ * against their actual centerline samples, not just the chord.
600
682
  */
601
- getSlabElevationForWall(levelId, start, end) {
683
+ getSlabElevationForWall(levelId, start, end, curveOffset = 0, thickness = DEFAULT_WALL_THICKNESS) {
602
684
  const slabMap = this.slabsByLevel.get(levelId);
603
685
  if (!slabMap)
604
686
  return 0;
687
+ const wallLike = { start, end, curveOffset, thickness };
688
+ const isCurved = curveOffset !== 0 && isCurvedWall(wallLike);
689
+ const holeSamplePoints = isCurved
690
+ ? sampleWallCenterline(wallLike, 8)
691
+ : [0, 0.25, 0.5, 0.75, 1].map((t) => ({
692
+ x: start[0] + (end[0] - start[0]) * t,
693
+ y: start[1] + (end[1] - start[1]) * t,
694
+ }));
605
695
  let maxElevation = Number.NEGATIVE_INFINITY;
606
696
  for (const slab of slabMap.values()) {
607
697
  if (slab.polygon.length < 3)
608
698
  continue;
609
- if (!wallOverlapsPolygon(start, end, slab.polygon))
699
+ if (!wallOverlapsPolygon(wallLike, slab.polygon))
610
700
  continue;
611
701
  const holes = slab.holes || [];
612
702
  if (holes.length === 0) {
@@ -619,15 +709,11 @@ export class SpatialGridManager {
619
709
  // Sample multiple points along the wall to check whether any portion lies on
620
710
  // solid slab (not inside any hole). Checking only the midpoint fails when the
621
711
  // midpoint falls in a staircase hole but the wall's endpoints are on solid slab.
622
- const dx = end[0] - start[0];
623
- const dz = end[1] - start[1];
624
712
  let hasValidPoint = false;
625
- for (const t of [0, 0.25, 0.5, 0.75, 1]) {
626
- const px = start[0] + dx * t;
627
- const pz = start[1] + dz * t;
713
+ for (const sample of holeSamplePoints) {
628
714
  let inHole = false;
629
715
  for (const hole of holes) {
630
- if (hole.length >= 3 && pointInPolygon(px, pz, hole)) {
716
+ if (hole.length >= 3 && pointInPolygon(sample.x, sample.y, hole)) {
631
717
  inHole = true;
632
718
  break;
633
719
  }
@@ -1,4 +1,31 @@
1
- import { type AnyNode } from '../../schema';
1
+ import type { AnyNode, AnyNodeId } from '../../schema';
2
2
  export declare function resolveLevelId(node: AnyNode, nodes: Record<string, AnyNode>): string;
3
+ /**
4
+ * Walks the parent chain of `nodeId` and returns the id of the first ancestor
5
+ * whose `type` is `'level'`, or `null` when no level ancestor exists (orphaned
6
+ * node, top-level building node, etc.). Unlike `resolveLevelId`, this variant:
7
+ *
8
+ * - accepts a node **id** rather than a resolved node, saving the caller a
9
+ * `nodes[id]` lookup when only the id is at hand.
10
+ * - returns `null` instead of the `'default'` fallback, which lets callers
11
+ * distinguish "genuinely has no level" from "is a level".
12
+ * - has a loop guard (16 iterations) so a corrupt parent-chain cycle cannot
13
+ * hang the frame loop.
14
+ */
15
+ export declare function findLevelAncestorId(nodeId: AnyNodeId, nodes: Record<string, AnyNode>): string | null;
16
+ /**
17
+ * Returns the building id that contains the given level, or `null` if
18
+ * the level is unparented or no enclosing building exists.
19
+ *
20
+ * Most scenes record the relationship via `level.parentId →
21
+ * building.id`, but older serialisations occasionally drop `parentId`
22
+ * even though the building's `children` array still references the
23
+ * level. The fallback scan covers that case.
24
+ *
25
+ * Used by `FloorplanRegistryLayer` to discover building-scoped kinds
26
+ * (`def.floorplanScope === 'building'`) without hardcoding any kind
27
+ * name in the editor layer.
28
+ */
29
+ export declare function resolveBuildingForLevel(levelId: AnyNodeId, nodes: Record<AnyNodeId, AnyNode>): AnyNodeId | null;
3
30
  export declare function initSpatialGridSync(): () => void;
4
31
  //# sourceMappingURL=spatial-grid-sync.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"spatial-grid-sync.d.ts","sourceRoot":"","sources":["../../../src/hooks/spatial-grid/spatial-grid-sync.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,OAAO,EAMb,MAAM,cAAc,CAAA;AAQrB,wBAAgB,cAAc,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAmBpF;AAKD,wBAAgB,mBAAmB,IAAI,MAAM,IAAI,CAgFhD"}
1
+ {"version":3,"file":"spatial-grid-sync.d.ts","sourceRoot":"","sources":["../../../src/hooks/spatial-grid/spatial-grid-sync.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAsB,MAAM,cAAc,CAAA;AAS1E,wBAAgB,cAAc,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAmBpF;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,MAAM,GAAG,IAAI,CASf;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,SAAS,EAClB,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,GAChC,SAAS,GAAG,IAAI,CAgBlB;AAKD,wBAAgB,mBAAmB,IAAI,MAAM,IAAI,CAgFhD"}
@@ -1,5 +1,6 @@
1
- import { getScaledDimensions, } from '../../schema';
1
+ import { nodeRegistry } from '../../registry';
2
2
  import useScene from '../../store/use-scene';
3
+ import { getFloorPlacedFootprints } from './floor-placed-elevation';
3
4
  import { itemOverlapsPolygon, spatialGridManager, wallOverlapsPolygon, } from './spatial-grid-manager';
4
5
  export function resolveLevelId(node, nodes) {
5
6
  // If the node itself is a level
@@ -21,6 +22,62 @@ export function resolveLevelId(node, nodes) {
21
22
  }
22
23
  return 'default'; // fallback for orphaned items
23
24
  }
25
+ /**
26
+ * Walks the parent chain of `nodeId` and returns the id of the first ancestor
27
+ * whose `type` is `'level'`, or `null` when no level ancestor exists (orphaned
28
+ * node, top-level building node, etc.). Unlike `resolveLevelId`, this variant:
29
+ *
30
+ * - accepts a node **id** rather than a resolved node, saving the caller a
31
+ * `nodes[id]` lookup when only the id is at hand.
32
+ * - returns `null` instead of the `'default'` fallback, which lets callers
33
+ * distinguish "genuinely has no level" from "is a level".
34
+ * - has a loop guard (16 iterations) so a corrupt parent-chain cycle cannot
35
+ * hang the frame loop.
36
+ */
37
+ export function findLevelAncestorId(nodeId, nodes) {
38
+ let current = nodes[nodeId];
39
+ let guard = 0;
40
+ while (current && guard < 16) {
41
+ if (current.type === 'level')
42
+ return current.id;
43
+ current = current.parentId ? nodes[current.parentId] : undefined;
44
+ guard += 1;
45
+ }
46
+ return null;
47
+ }
48
+ /**
49
+ * Returns the building id that contains the given level, or `null` if
50
+ * the level is unparented or no enclosing building exists.
51
+ *
52
+ * Most scenes record the relationship via `level.parentId →
53
+ * building.id`, but older serialisations occasionally drop `parentId`
54
+ * even though the building's `children` array still references the
55
+ * level. The fallback scan covers that case.
56
+ *
57
+ * Used by `FloorplanRegistryLayer` to discover building-scoped kinds
58
+ * (`def.floorplanScope === 'building'`) without hardcoding any kind
59
+ * name in the editor layer.
60
+ */
61
+ export function resolveBuildingForLevel(levelId, nodes) {
62
+ const level = nodes[levelId];
63
+ if (!level)
64
+ return null;
65
+ const directParent = level.parentId ?? null;
66
+ if (directParent) {
67
+ const candidate = nodes[directParent];
68
+ if (candidate?.type === 'building')
69
+ return candidate.id;
70
+ }
71
+ for (const candidate of Object.values(nodes)) {
72
+ if (candidate?.type !== 'building')
73
+ continue;
74
+ const children = candidate.children;
75
+ if (Array.isArray(children) && children.includes(levelId)) {
76
+ return candidate.id;
77
+ }
78
+ }
79
+ return null;
80
+ }
24
81
  // Call this once at app initialization. Returns an unsubscribe function that
25
82
  // detaches the scene-store listener (useful when the editor is unmounted so
26
83
  // the spatial grid singleton does not hold stale references to old scenes).
@@ -96,36 +153,52 @@ function arraysEqual(a, b) {
96
153
  return a.length === b.length && a.every((v, i) => v === b[i]);
97
154
  }
98
155
  /**
99
- * Mark all floor items, walls, and stairs that may be affected by a slab change as dirty.
156
+ * Mark all floor items and walls that may be affected by a slab change as dirty.
100
157
  */
101
158
  function markNodesOverlappingSlab(slab, nodes, markDirty) {
102
159
  if (slab.polygon.length < 3)
103
160
  return;
104
161
  const slabLevelId = resolveLevelId(slab, nodes);
105
162
  for (const node of Object.values(nodes)) {
106
- if (node.type === 'item') {
107
- const item = node;
108
- // Only floor items are affected by slabs
109
- if (item.asset.attachTo)
110
- continue;
163
+ if (node.type === 'wall') {
164
+ const wall = node;
111
165
  if (resolveLevelId(node, nodes) !== slabLevelId)
112
166
  continue;
113
- if (itemOverlapsPolygon(item.position, getScaledDimensions(item), item.rotation, slab.polygon, 0.01)) {
167
+ if (wallOverlapsPolygon({
168
+ start: wall.start,
169
+ end: wall.end,
170
+ curveOffset: wall.curveOffset ?? 0,
171
+ thickness: wall.thickness,
172
+ }, slab.polygon)) {
114
173
  markDirty(node.id);
115
174
  }
175
+ continue;
116
176
  }
117
- else if (node.type === 'wall') {
118
- const wall = node;
119
- if (resolveLevelId(node, nodes) !== slabLevelId)
120
- continue;
121
- if (wallOverlapsPolygon(wall.start, wall.end, slab.polygon)) {
177
+ // Generic floor-placed sweep: any registry kind that opts in via
178
+ // `capabilities.floorPlaced` (item / shelf / column / spawn / …)
179
+ // re-elevates through `<FloorElevationSystem>` when a slab below
180
+ // changes. We dirty-mark when the kind's footprint overlaps the
181
+ // changed slab so the system picks it up next frame.
182
+ const def = nodeRegistry.get(node.type);
183
+ const floorPlaced = def?.capabilities?.floorPlaced;
184
+ if (!floorPlaced)
185
+ continue;
186
+ if (floorPlaced.applies && !floorPlaced.applies(node))
187
+ continue;
188
+ const parentId = node.parentId;
189
+ const parent = parentId ? nodes[parentId] : null;
190
+ if (parent && parent.type !== 'level')
191
+ continue;
192
+ if (resolveLevelId(node, nodes) !== slabLevelId)
193
+ continue;
194
+ const position = node.position;
195
+ if (!position)
196
+ continue;
197
+ for (const footprint of getFloorPlacedFootprints(floorPlaced, node, { nodes })) {
198
+ if (itemOverlapsPolygon(footprint.position ?? position, footprint.dimensions, footprint.rotation, slab.polygon, 0.01)) {
122
199
  markDirty(node.id);
200
+ break;
123
201
  }
124
202
  }
125
- else if (node.type === 'stair') {
126
- if (resolveLevelId(node, nodes) !== slabLevelId)
127
- continue;
128
- markDirty(node.id);
129
- }
130
203
  }
131
204
  }
package/dist/index.d.ts CHANGED
@@ -1,24 +1,42 @@
1
- export type { BuildingEvent, CameraControlEvent, CameraControlFitSceneEvent, CeilingEvent, ColumnEvent, DoorEvent, EventSuffix, FenceEvent, GridEvent, ItemEvent, LevelEvent, NodeEvent, RoofEvent, RoofSegmentEvent, SiteEvent, SlabEvent, SpawnEvent, StairEvent, StairSegmentEvent, WallEvent, WindowEvent, ZoneEvent, } from './events/bus';
1
+ export type { BoxVentEvent, BuildingEvent, CameraControlEvent, CameraControlFitSceneEvent, CeilingEvent, ChimneyEvent, ColumnEvent, DoorEvent, DormerEvent, ElevatorEvent, EventSuffix, FenceEvent, GridEvent, GuideEvent, GutterEvent, ItemEvent, LevelEvent, NodeEvent, RidgeVentEvent, RoofEvent, RoofSegmentEvent, RoomPresetCreateEvent, ScanEvent, ShelfEvent, SiteEvent, SkylightEvent, SlabEvent, SolarPanelEvent, SpawnEvent, StairEvent, StairSegmentEvent, WallEvent, WindowEvent, ZoneEvent, } from './events/bus';
2
2
  export { emitter, eventSuffixes } from './events/bus';
3
3
  export { sceneRegistry, useRegistry, } from './hooks/scene-registry/scene-registry';
4
+ export { type FloorPlacedElevationArgs, getFloorPlacedElevation, getFloorPlacedFootprints, getFloorStackedPosition, } from './hooks/spatial-grid/floor-placed-elevation';
4
5
  export { pointInPolygon, spatialGridManager } from './hooks/spatial-grid/spatial-grid-manager';
5
- export { initSpatialGridSync, resolveLevelId, } from './hooks/spatial-grid/spatial-grid-sync';
6
+ export { findLevelAncestorId, initSpatialGridSync, resolveBuildingForLevel, resolveLevelId, } from './hooks/spatial-grid/spatial-grid-sync';
6
7
  export { useSpatialQuery } from './hooks/spatial-grid/use-spatial-query';
7
8
  export { loadAssetUrl, saveAsset } from './lib/asset-storage';
8
9
  export { clampDoorOperationState, getDoorRenderOpenAmount, getGarageVisibleOpeningRatio, isOperationDoorType, SECTIONAL_GARAGE_RENDER_OPEN_SCALE, } from './lib/door-operation';
10
+ export { type Point2D as PolygonPoint2D, pointInPolygon as pointInPolygon2D, pointOnSegment, polygonContainsPolygon, polygonsIntersect, polygonsOverlap, segmentsIntersect, } from './lib/polygon-relations';
9
11
  export { getRenderableSlabPolygon } from './lib/slab-polygon';
10
- export { detectSpacesForLevel, initSpaceDetectionSync, type Space, wallTouchesOthers, } from './lib/space-detection';
12
+ export { type AutoCeilingPlanningContext, type AutoCeilingSyncPlan, type AutoSlabSyncPlan, detectSpacesForLevel, initSpaceDetectionSync, isSpaceDetectionPaused, pauseSpaceDetection, planAutoCeilingsForLevel, planAutoSlabsForLevel, projectAutoSlabsForPlan, resumeSpaceDetection, type Space, wallTouchesOthers, } from './lib/space-detection';
11
13
  export { getCatalogMaterialById, getLibraryMaterialIdFromRef, getMaterialPresetByRef, getMaterialsForCategory, LIBRARY_MATERIAL_REF_PREFIX, MATERIAL_CATALOG, MATERIAL_CATEGORIES, type MaterialCatalogItem, type MaterialCategory, toLibraryMaterialRef, } from './material-library';
14
+ export type { FloorPlacedFootprint, FloorPlacedFootprintContext, FloorPlacedFootprintResolver, FloorPlacedFootprintsResolver, } from './registry';
15
+ export * from './registry';
12
16
  export * from './schema';
17
+ export * from './services';
13
18
  export { getSceneHistoryPauseDepth, pauseSceneHistory, resetSceneHistoryPauseDepth, resumeSceneHistory, } from './store/history-control';
14
- export { type ControlValue, type DoorAnimationState, type DoorInteractiveState, type ItemInteractiveState, useInteractive, type WindowAnimationState, type WindowInteractiveState, } from './store/use-interactive';
19
+ export { type ControlValue, type DoorAnimationState, type DoorInteractiveState, type ElevatorInteractiveState, type ElevatorPhase, type ItemInteractiveState, type SkylightAnimationState, type SkylightInteractiveState, useInteractive, type WindowAnimationState, type WindowInteractiveState, } from './store/use-interactive';
20
+ export { default as useLiveNodeOverrides, getEffectiveNode, type LiveNodeOverrides, } from './store/use-live-node-overrides';
15
21
  export { default as useLiveTransforms, type LiveTransform } from './store/use-live-transforms';
16
22
  export { clearSceneHistory, default as useScene } from './store/use-scene';
23
+ export { resolveElevatorDispatchTarget } from './systems/elevator/elevator-dispatch';
24
+ export { type ElevatorDoorSide, getElevatorCabCenterZ, getElevatorCabDepth, getElevatorCabWidth, getElevatorDoorLeafSides, getElevatorDoorLeafWidth, getElevatorDoorLeafX, getElevatorShaftDepth, getElevatorShaftWallThickness, getElevatorShaftWidth, getResolvedElevatorDoorPanelStyle, getResolvedElevatorDoorStyle, getResolvedElevatorShaftStyle, } from './systems/elevator/elevator-geometry';
25
+ export { syncAutoElevatorOpenings } from './systems/elevator/elevator-opening-sync';
26
+ export { ElevatorOpeningSystem } from './systems/elevator/elevator-opening-system';
27
+ export { createElevatorInteractiveState, openElevatorDoor, openElevatorDoorState, queueElevatorRequest, requestElevatorLevel, stepElevatorRuntimeState, stepElevatorRuntimes, } from './systems/elevator/elevator-runtime';
28
+ export { ElevatorRuntimeSystem } from './systems/elevator/elevator-runtime-system';
29
+ export { DEFAULT_ELEVATOR_LEVEL_HEIGHT, type ElevatorLevelEntry, getElevatorLevelHeight, resolveElevatorBuildingLevels, resolveElevatorLevels, resolveElevatorServiceLevelIds, resolveElevatorServiceLevels, } from './systems/elevator/elevator-service';
30
+ export { type StairFootprintAABB, stairFootprintAABB } from './systems/stair/stair-footprint';
31
+ export { createSurfaceOpeningPreviewController } from './systems/stair/stair-opening-preview';
17
32
  export { syncAutoStairOpenings } from './systems/stair/stair-opening-sync';
33
+ export { StairOpeningSystem } from './systems/stair/stair-opening-system';
18
34
  export { getClampedWallCurveOffset, getMaxWallCurveOffset, getWallChordFrame, getWallCurveFrameAt, getWallCurveLength, getWallMidpointHandlePoint, getWallStraightSnapOffset, getWallSurfacePolygon, isCurvedWall, normalizeWallCurveOffset, sampleWallCenterline, } from './systems/wall/wall-curve';
19
35
  export { DEFAULT_WALL_HEIGHT, DEFAULT_WALL_THICKNESS, getWallPlanFootprint, getWallThickness, } from './systems/wall/wall-footprint';
20
36
  export { calculateLevelMiters, getAdjacentWallIds, getWallMiterBoundaryPoints, type Point2D, pointToKey, type WallMiterBoundaryPoints, type WallMiterData, } from './systems/wall/wall-mitering';
37
+ export { constrainWallMoveDeltaToAxis, getLinkedWallUpdates, getPerpendicularWallMoveAxis, getPlannedLinkedWallUpdates, planWallMoveJunctions, type WallMoveAxis, type WallMoveBridgePlan, type WallMoveJunctionPlan, type WallMoveLinkedWallTargetPlan, type WallPlanPoint, } from './systems/wall/wall-move';
21
38
  export type { SceneGraph } from './utils/clone-scene-graph';
22
39
  export { cloneLevelSubtree, cloneSceneGraph, forkSceneGraph } from './utils/clone-scene-graph';
23
40
  export { isObject } from './utils/types';
41
+ export { type BuildStats, type ParsedBuildJson, type SchemaIssue, type ValidateBuildJsonResult, type ValidationIssue, type ValidationSeverity, validateBuildJson, } from './validation/validate-build-json';
24
42
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,aAAa,EACb,kBAAkB,EAClB,0BAA0B,EAC1B,YAAY,EACZ,WAAW,EACX,SAAS,EACT,WAAW,EACX,UAAU,EACV,SAAS,EACT,SAAS,EACT,UAAU,EACV,SAAS,EACT,SAAS,EACT,gBAAgB,EAChB,SAAS,EACT,SAAS,EACT,UAAU,EACV,UAAU,EACV,iBAAiB,EACjB,SAAS,EACT,WAAW,EACX,SAAS,GACV,MAAM,cAAc,CAAA;AACrB,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AACrD,OAAO,EACL,aAAa,EACb,WAAW,GACZ,MAAM,uCAAuC,CAAA;AAC9C,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,2CAA2C,CAAA;AAC9F,OAAO,EACL,mBAAmB,EACnB,cAAc,GACf,MAAM,wCAAwC,CAAA;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,wCAAwC,CAAA;AACxE,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAC7D,OAAO,EACL,uBAAuB,EACvB,uBAAuB,EACvB,4BAA4B,EAC5B,mBAAmB,EACnB,kCAAkC,GACnC,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAA;AAC7D,OAAO,EACL,oBAAoB,EACpB,sBAAsB,EACtB,KAAK,KAAK,EACV,iBAAiB,GAClB,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EACL,sBAAsB,EACtB,2BAA2B,EAC3B,sBAAsB,EACtB,uBAAuB,EACvB,2BAA2B,EAC3B,gBAAgB,EAChB,mBAAmB,EACnB,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EACrB,oBAAoB,GACrB,MAAM,oBAAoB,CAAA;AAC3B,cAAc,UAAU,CAAA;AACxB,OAAO,EACL,yBAAyB,EACzB,iBAAiB,EACjB,2BAA2B,EAC3B,kBAAkB,GACnB,MAAM,yBAAyB,CAAA;AAChC,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,EACzB,cAAc,EACd,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,GAC5B,MAAM,yBAAyB,CAAA;AAChC,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,KAAK,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAC9F,OAAO,EAAE,iBAAiB,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAC1E,OAAO,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAA;AAC1E,OAAO,EACL,yBAAyB,EACzB,qBAAqB,EACrB,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,0BAA0B,EAC1B,yBAAyB,EACzB,qBAAqB,EACrB,YAAY,EACZ,wBAAwB,EACxB,oBAAoB,GACrB,MAAM,2BAA2B,CAAA;AAClC,OAAO,EACL,mBAAmB,EACnB,sBAAsB,EACtB,oBAAoB,EACpB,gBAAgB,GACjB,MAAM,+BAA+B,CAAA;AACtC,OAAO,EACL,oBAAoB,EACpB,kBAAkB,EAClB,0BAA0B,EAC1B,KAAK,OAAO,EACZ,UAAU,EACV,KAAK,uBAAuB,EAC5B,KAAK,aAAa,GACnB,MAAM,8BAA8B,CAAA;AACrC,YAAY,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAA;AAC3D,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAA;AAC9F,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,21 +1,38 @@
1
1
  export { emitter, eventSuffixes } from './events/bus';
2
2
  export { sceneRegistry, useRegistry, } from './hooks/scene-registry/scene-registry';
3
+ export { getFloorPlacedElevation, getFloorPlacedFootprints, getFloorStackedPosition, } from './hooks/spatial-grid/floor-placed-elevation';
3
4
  export { pointInPolygon, spatialGridManager } from './hooks/spatial-grid/spatial-grid-manager';
4
- export { initSpatialGridSync, resolveLevelId, } from './hooks/spatial-grid/spatial-grid-sync';
5
+ export { findLevelAncestorId, initSpatialGridSync, resolveBuildingForLevel, resolveLevelId, } from './hooks/spatial-grid/spatial-grid-sync';
5
6
  export { useSpatialQuery } from './hooks/spatial-grid/use-spatial-query';
6
7
  export { loadAssetUrl, saveAsset } from './lib/asset-storage';
7
8
  export { clampDoorOperationState, getDoorRenderOpenAmount, getGarageVisibleOpeningRatio, isOperationDoorType, SECTIONAL_GARAGE_RENDER_OPEN_SCALE, } from './lib/door-operation';
9
+ export { pointInPolygon as pointInPolygon2D, pointOnSegment, polygonContainsPolygon, polygonsIntersect, polygonsOverlap, segmentsIntersect, } from './lib/polygon-relations';
8
10
  export { getRenderableSlabPolygon } from './lib/slab-polygon';
9
- export { detectSpacesForLevel, initSpaceDetectionSync, wallTouchesOthers, } from './lib/space-detection';
11
+ export { detectSpacesForLevel, initSpaceDetectionSync, isSpaceDetectionPaused, pauseSpaceDetection, planAutoCeilingsForLevel, planAutoSlabsForLevel, projectAutoSlabsForPlan, resumeSpaceDetection, wallTouchesOthers, } from './lib/space-detection';
10
12
  export { getCatalogMaterialById, getLibraryMaterialIdFromRef, getMaterialPresetByRef, getMaterialsForCategory, LIBRARY_MATERIAL_REF_PREFIX, MATERIAL_CATALOG, MATERIAL_CATEGORIES, toLibraryMaterialRef, } from './material-library';
13
+ export * from './registry';
11
14
  export * from './schema';
15
+ export * from './services';
12
16
  export { getSceneHistoryPauseDepth, pauseSceneHistory, resetSceneHistoryPauseDepth, resumeSceneHistory, } from './store/history-control';
13
17
  export { useInteractive, } from './store/use-interactive';
18
+ export { default as useLiveNodeOverrides, getEffectiveNode, } from './store/use-live-node-overrides';
14
19
  export { default as useLiveTransforms } from './store/use-live-transforms';
15
20
  export { clearSceneHistory, default as useScene } from './store/use-scene';
21
+ export { resolveElevatorDispatchTarget } from './systems/elevator/elevator-dispatch';
22
+ export { getElevatorCabCenterZ, getElevatorCabDepth, getElevatorCabWidth, getElevatorDoorLeafSides, getElevatorDoorLeafWidth, getElevatorDoorLeafX, getElevatorShaftDepth, getElevatorShaftWallThickness, getElevatorShaftWidth, getResolvedElevatorDoorPanelStyle, getResolvedElevatorDoorStyle, getResolvedElevatorShaftStyle, } from './systems/elevator/elevator-geometry';
23
+ export { syncAutoElevatorOpenings } from './systems/elevator/elevator-opening-sync';
24
+ export { ElevatorOpeningSystem } from './systems/elevator/elevator-opening-system';
25
+ export { createElevatorInteractiveState, openElevatorDoor, openElevatorDoorState, queueElevatorRequest, requestElevatorLevel, stepElevatorRuntimeState, stepElevatorRuntimes, } from './systems/elevator/elevator-runtime';
26
+ export { ElevatorRuntimeSystem } from './systems/elevator/elevator-runtime-system';
27
+ export { DEFAULT_ELEVATOR_LEVEL_HEIGHT, getElevatorLevelHeight, resolveElevatorBuildingLevels, resolveElevatorLevels, resolveElevatorServiceLevelIds, resolveElevatorServiceLevels, } from './systems/elevator/elevator-service';
28
+ export { stairFootprintAABB } from './systems/stair/stair-footprint';
29
+ export { createSurfaceOpeningPreviewController } from './systems/stair/stair-opening-preview';
16
30
  export { syncAutoStairOpenings } from './systems/stair/stair-opening-sync';
31
+ export { StairOpeningSystem } from './systems/stair/stair-opening-system';
17
32
  export { getClampedWallCurveOffset, getMaxWallCurveOffset, getWallChordFrame, getWallCurveFrameAt, getWallCurveLength, getWallMidpointHandlePoint, getWallStraightSnapOffset, getWallSurfacePolygon, isCurvedWall, normalizeWallCurveOffset, sampleWallCenterline, } from './systems/wall/wall-curve';
18
33
  export { DEFAULT_WALL_HEIGHT, DEFAULT_WALL_THICKNESS, getWallPlanFootprint, getWallThickness, } from './systems/wall/wall-footprint';
19
34
  export { calculateLevelMiters, getAdjacentWallIds, getWallMiterBoundaryPoints, pointToKey, } from './systems/wall/wall-mitering';
35
+ export { constrainWallMoveDeltaToAxis, getLinkedWallUpdates, getPerpendicularWallMoveAxis, getPlannedLinkedWallUpdates, planWallMoveJunctions, } from './systems/wall/wall-move';
20
36
  export { cloneLevelSubtree, cloneSceneGraph, forkSceneGraph } from './utils/clone-scene-graph';
21
37
  export { isObject } from './utils/types';
38
+ export { validateBuildJson, } from './validation/validate-build-json';
@@ -1 +1 @@
1
- {"version":3,"file":"polygon-geometry.d.ts","sourceRoot":"","sources":["../../src/lib/polygon-geometry.ts"],"names":[],"mappings":"AAAA,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAChC,KAAK,EAAE,MAAM,GACZ,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAuBzB;AAuED,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAChC,SAAS,EAAE,MAAM,GAChB,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAiCzB"}
1
+ {"version":3,"file":"polygon-geometry.d.ts","sourceRoot":"","sources":["../../src/lib/polygon-geometry.ts"],"names":[],"mappings":"AAAA,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAChC,KAAK,EAAE,MAAM,GACZ,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAoBzB;AA0ED,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAChC,SAAS,EAAE,MAAM,GAChB,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAiCzB"}
@@ -0,0 +1,10 @@
1
+ export type Point2D = [number, number];
2
+ export declare function pointOnSegment(point: Point2D, start: Point2D, end: Point2D, tolerance?: number): boolean;
3
+ export declare function pointInPolygon(point: Point2D, polygon: Point2D[], options?: {
4
+ includeBoundary?: boolean;
5
+ }): boolean;
6
+ export declare function segmentsIntersect(a: Point2D, b: Point2D, c: Point2D, d: Point2D): boolean;
7
+ export declare function polygonsIntersect(left: Point2D[], right: Point2D[]): boolean;
8
+ export declare function polygonContainsPolygon(outer: Point2D[], inner: Point2D[]): boolean;
9
+ export declare function polygonsOverlap(left: Point2D[], right: Point2D[]): boolean;
10
+ //# sourceMappingURL=polygon-relations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"polygon-relations.d.ts","sourceRoot":"","sources":["../../src/lib/polygon-relations.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,OAAO,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;AAEtC,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,SAAS,SAAO,WAS5F;AAED,wBAAgB,cAAc,CAC5B,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,OAAO,EAAE,EAClB,OAAO,CAAC,EAAE;IAAE,eAAe,CAAC,EAAE,OAAO,CAAA;CAAE,WAuBxC;AAED,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,WA2B/E;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,WAmBlE;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,WAExE;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,WAMhE"}
@@ -0,0 +1,73 @@
1
+ export function pointOnSegment(point, start, end, tolerance = 1e-6) {
2
+ const dx = end[0] - start[0];
3
+ const dz = end[1] - start[1];
4
+ const cross = (point[0] - start[0]) * dz - (point[1] - start[1]) * dx;
5
+ if (Math.abs(cross) > tolerance)
6
+ return false;
7
+ const dot = (point[0] - start[0]) * (point[0] - end[0]) + (point[1] - start[1]) * (point[1] - end[1]);
8
+ return dot <= tolerance;
9
+ }
10
+ export function pointInPolygon(point, polygon, options) {
11
+ if (polygon.length < 3)
12
+ return false;
13
+ const includeBoundary = options?.includeBoundary ?? true;
14
+ if (polygon.some((start, index) => pointOnSegment(point, start, polygon[(index + 1) % polygon.length]))) {
15
+ return includeBoundary;
16
+ }
17
+ let inside = false;
18
+ const [x, z] = point;
19
+ for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
20
+ const current = polygon[i];
21
+ const previous = polygon[j];
22
+ const intersects = current[1] > z !== previous[1] > z &&
23
+ x < ((previous[0] - current[0]) * (z - current[1])) / (previous[1] - current[1]) + current[0];
24
+ if (intersects)
25
+ inside = !inside;
26
+ }
27
+ return inside;
28
+ }
29
+ export function segmentsIntersect(a, b, c, d) {
30
+ const cross = (ux, uz, vx, vz) => ux * vz - uz * vx;
31
+ const abx = b[0] - a[0];
32
+ const abz = b[1] - a[1];
33
+ const acx = c[0] - a[0];
34
+ const acz = c[1] - a[1];
35
+ const adx = d[0] - a[0];
36
+ const adz = d[1] - a[1];
37
+ const cdx = d[0] - c[0];
38
+ const cdz = d[1] - c[1];
39
+ const cax = a[0] - c[0];
40
+ const caz = a[1] - c[1];
41
+ const cbx = b[0] - c[0];
42
+ const cbz = b[1] - c[1];
43
+ const o1 = cross(abx, abz, acx, acz);
44
+ const o2 = cross(abx, abz, adx, adz);
45
+ const o3 = cross(cdx, cdz, cax, caz);
46
+ const o4 = cross(cdx, cdz, cbx, cbz);
47
+ if (Math.sign(o1) !== Math.sign(o2) && Math.sign(o3) !== Math.sign(o4))
48
+ return true;
49
+ return (pointOnSegment(c, a, b) ||
50
+ pointOnSegment(d, a, b) ||
51
+ pointOnSegment(a, c, d) ||
52
+ pointOnSegment(b, c, d));
53
+ }
54
+ export function polygonsIntersect(left, right) {
55
+ for (let leftIndex = 0; leftIndex < left.length; leftIndex++) {
56
+ const leftStart = left[leftIndex];
57
+ const leftEnd = left[(leftIndex + 1) % left.length];
58
+ for (let rightIndex = 0; rightIndex < right.length; rightIndex++) {
59
+ if (segmentsIntersect(leftStart, leftEnd, right[rightIndex], right[(rightIndex + 1) % right.length])) {
60
+ return true;
61
+ }
62
+ }
63
+ }
64
+ return false;
65
+ }
66
+ export function polygonContainsPolygon(outer, inner) {
67
+ return inner.every((point) => pointInPolygon(point, outer));
68
+ }
69
+ export function polygonsOverlap(left, right) {
70
+ return (polygonsIntersect(left, right) ||
71
+ left.some((point) => pointInPolygon(point, right)) ||
72
+ right.some((point) => pointInPolygon(point, left)));
73
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=space-detection-pause.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"space-detection-pause.test.d.ts","sourceRoot":"","sources":["../../src/lib/space-detection-pause.test.ts"],"names":[],"mappings":""}