@pascal-app/core 0.9.1 → 1.0.0-beta.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 (378) hide show
  1. package/README.md +17 -10
  2. package/dist/events/bus.d.ts +49 -2
  3. package/dist/events/bus.d.ts.map +1 -1
  4. package/dist/hooks/scene-registry/item-clip-registry.d.ts +18 -0
  5. package/dist/hooks/scene-registry/item-clip-registry.d.ts.map +1 -0
  6. package/dist/hooks/scene-registry/item-clip-registry.js +10 -0
  7. package/dist/hooks/scene-registry/scene-registry.d.ts +8 -1
  8. package/dist/hooks/scene-registry/scene-registry.d.ts.map +1 -1
  9. package/dist/hooks/scene-registry/scene-registry.js +27 -1
  10. package/dist/hooks/spatial-grid/floor-placed-elevation.d.ts +17 -1
  11. package/dist/hooks/spatial-grid/floor-placed-elevation.d.ts.map +1 -1
  12. package/dist/hooks/spatial-grid/floor-placed-elevation.js +61 -8
  13. package/dist/hooks/spatial-grid/spatial-grid-manager.d.ts +135 -28
  14. package/dist/hooks/spatial-grid/spatial-grid-manager.d.ts.map +1 -1
  15. package/dist/hooks/spatial-grid/spatial-grid-manager.js +427 -271
  16. package/dist/hooks/spatial-grid/spatial-grid-sync.d.ts +46 -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 +208 -9
  19. package/dist/hooks/spatial-grid/support-host-id.d.ts +3 -0
  20. package/dist/hooks/spatial-grid/support-host-id.d.ts.map +1 -0
  21. package/dist/hooks/spatial-grid/support-host-id.js +2 -0
  22. package/dist/hooks/spatial-grid/support-host-patch.d.ts +51 -0
  23. package/dist/hooks/spatial-grid/support-host-patch.d.ts.map +1 -0
  24. package/dist/hooks/spatial-grid/support-host-patch.js +164 -0
  25. package/dist/index.d.ts +33 -11
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +32 -10
  28. package/dist/lib/level-name.d.ts +4 -0
  29. package/dist/lib/level-name.d.ts.map +1 -0
  30. package/dist/lib/level-name.js +10 -0
  31. package/dist/lib/measurement-geometry.d.ts +23 -0
  32. package/dist/lib/measurement-geometry.d.ts.map +1 -0
  33. package/dist/lib/measurement-geometry.js +249 -0
  34. package/dist/lib/polygon-geometry.d.ts +0 -1
  35. package/dist/lib/polygon-geometry.d.ts.map +1 -1
  36. package/dist/lib/polygon-geometry.js +0 -18
  37. package/dist/lib/selection-proxy.d.ts +4 -0
  38. package/dist/lib/selection-proxy.d.ts.map +1 -0
  39. package/dist/lib/selection-proxy.js +12 -0
  40. package/dist/lib/slab-polygon.d.ts +31 -2
  41. package/dist/lib/slab-polygon.d.ts.map +1 -1
  42. package/dist/lib/slab-polygon.js +557 -31
  43. package/dist/lib/slots.d.ts +14 -0
  44. package/dist/lib/slots.d.ts.map +1 -0
  45. package/dist/lib/slots.js +26 -0
  46. package/dist/lib/space-detection.d.ts +40 -6
  47. package/dist/lib/space-detection.d.ts.map +1 -1
  48. package/dist/lib/space-detection.js +574 -192
  49. package/dist/lib/terrain-brush.d.ts +163 -0
  50. package/dist/lib/terrain-brush.d.ts.map +1 -0
  51. package/dist/lib/terrain-brush.js +359 -0
  52. package/dist/lib/terrain-codec.d.ts +51 -0
  53. package/dist/lib/terrain-codec.d.ts.map +1 -0
  54. package/dist/lib/terrain-codec.js +167 -0
  55. package/dist/lib/terrain-field.d.ts +150 -0
  56. package/dist/lib/terrain-field.d.ts.map +1 -0
  57. package/dist/lib/terrain-field.js +248 -0
  58. package/dist/lib/terrain-raycast.d.ts +44 -0
  59. package/dist/lib/terrain-raycast.d.ts.map +1 -0
  60. package/dist/lib/terrain-raycast.js +188 -0
  61. package/dist/lib/terrain-source.d.ts +60 -0
  62. package/dist/lib/terrain-source.d.ts.map +1 -0
  63. package/dist/lib/terrain-source.js +90 -0
  64. package/dist/lib/terrain-support.d.ts +60 -0
  65. package/dist/lib/terrain-support.d.ts.map +1 -0
  66. package/dist/lib/terrain-support.js +150 -0
  67. package/dist/lib/wall-distance.d.ts +60 -0
  68. package/dist/lib/wall-distance.d.ts.map +1 -0
  69. package/dist/lib/wall-distance.js +85 -0
  70. package/dist/lib/zone-quantities.d.ts +21 -0
  71. package/dist/lib/zone-quantities.d.ts.map +1 -0
  72. package/dist/lib/zone-quantities.js +428 -0
  73. package/dist/material-library.d.ts +28 -1
  74. package/dist/material-library.d.ts.map +1 -1
  75. package/dist/material-library.js +2233 -441
  76. package/dist/registry/handles.d.ts +91 -3
  77. package/dist/registry/handles.d.ts.map +1 -1
  78. package/dist/registry/index.d.ts +3 -3
  79. package/dist/registry/index.d.ts.map +1 -1
  80. package/dist/registry/index.js +1 -1
  81. package/dist/registry/registry.d.ts +46 -3
  82. package/dist/registry/registry.d.ts.map +1 -1
  83. package/dist/registry/registry.js +82 -1
  84. package/dist/registry/subtree.d.ts.map +1 -1
  85. package/dist/registry/subtree.js +8 -1
  86. package/dist/registry/types.d.ts +781 -39
  87. package/dist/registry/types.d.ts.map +1 -1
  88. package/dist/schema/index.d.ts +27 -8
  89. package/dist/schema/index.d.ts.map +1 -1
  90. package/dist/schema/index.js +23 -6
  91. package/dist/schema/material.d.ts +3 -2
  92. package/dist/schema/material.d.ts.map +1 -1
  93. package/dist/schema/material.js +7 -5
  94. package/dist/schema/nodes/box-vent.d.ts +2 -2
  95. package/dist/schema/nodes/cabinet.d.ts +536 -0
  96. package/dist/schema/nodes/cabinet.d.ts.map +1 -0
  97. package/dist/schema/nodes/cabinet.js +139 -0
  98. package/dist/schema/nodes/ceiling.d.ts +4 -3
  99. package/dist/schema/nodes/ceiling.d.ts.map +1 -1
  100. package/dist/schema/nodes/ceiling.js +11 -1
  101. package/dist/schema/nodes/chimney.d.ts +4 -4
  102. package/dist/schema/nodes/column.d.ts +4 -2
  103. package/dist/schema/nodes/column.d.ts.map +1 -1
  104. package/dist/schema/nodes/column.js +5 -0
  105. package/dist/schema/nodes/construction-dimension.d.ts +195 -0
  106. package/dist/schema/nodes/construction-dimension.d.ts.map +1 -0
  107. package/dist/schema/nodes/construction-dimension.js +151 -0
  108. package/dist/schema/nodes/cupola.d.ts +2 -2
  109. package/dist/schema/nodes/door.d.ts +42 -5
  110. package/dist/schema/nodes/door.d.ts.map +1 -1
  111. package/dist/schema/nodes/door.js +32 -0
  112. package/dist/schema/nodes/dormer.d.ts +8 -8
  113. package/dist/schema/nodes/dormer.js +1 -1
  114. package/dist/schema/nodes/downspout.d.ts +2 -2
  115. package/dist/schema/nodes/duct-fitting.d.ts +91 -0
  116. package/dist/schema/nodes/duct-fitting.d.ts.map +1 -0
  117. package/dist/schema/nodes/duct-fitting.js +92 -0
  118. package/dist/schema/nodes/duct-segment.d.ts +61 -0
  119. package/dist/schema/nodes/duct-segment.d.ts.map +1 -0
  120. package/dist/schema/nodes/duct-segment.js +73 -0
  121. package/dist/schema/nodes/duct-terminal.d.ts +58 -0
  122. package/dist/schema/nodes/duct-terminal.d.ts.map +1 -0
  123. package/dist/schema/nodes/duct-terminal.js +53 -0
  124. package/dist/schema/nodes/elevator.d.ts +3 -2
  125. package/dist/schema/nodes/elevator.d.ts.map +1 -1
  126. package/dist/schema/nodes/elevator.js +3 -0
  127. package/dist/schema/nodes/eyebrow-vent.d.ts +2 -2
  128. package/dist/schema/nodes/fence.d.ts +20 -2
  129. package/dist/schema/nodes/fence.d.ts.map +1 -1
  130. package/dist/schema/nodes/fence.js +33 -2
  131. package/dist/schema/nodes/gutter.d.ts +2 -2
  132. package/dist/schema/nodes/hvac-equipment.d.ts +64 -0
  133. package/dist/schema/nodes/hvac-equipment.d.ts.map +1 -0
  134. package/dist/schema/nodes/hvac-equipment.js +57 -0
  135. package/dist/schema/nodes/item.d.ts +9 -0
  136. package/dist/schema/nodes/item.d.ts.map +1 -1
  137. package/dist/schema/nodes/item.js +24 -0
  138. package/dist/schema/nodes/level.d.ts +2 -1
  139. package/dist/schema/nodes/level.d.ts.map +1 -1
  140. package/dist/schema/nodes/level.js +12 -31
  141. package/dist/schema/nodes/lineset.d.ts +42 -0
  142. package/dist/schema/nodes/lineset.d.ts.map +1 -0
  143. package/dist/schema/nodes/lineset.js +38 -0
  144. package/dist/schema/nodes/liquid-line.d.ts +34 -0
  145. package/dist/schema/nodes/liquid-line.d.ts.map +1 -0
  146. package/dist/schema/nodes/liquid-line.js +24 -0
  147. package/dist/schema/nodes/measurement.d.ts +306 -0
  148. package/dist/schema/nodes/measurement.d.ts.map +1 -0
  149. package/dist/schema/nodes/measurement.js +87 -0
  150. package/dist/schema/nodes/pipe-fitting.d.ts +56 -0
  151. package/dist/schema/nodes/pipe-fitting.d.ts.map +1 -0
  152. package/dist/schema/nodes/pipe-fitting.js +45 -0
  153. package/dist/schema/nodes/pipe-segment.d.ts +48 -0
  154. package/dist/schema/nodes/pipe-segment.d.ts.map +1 -0
  155. package/dist/schema/nodes/pipe-segment.js +36 -0
  156. package/dist/schema/nodes/pipe-trap.d.ts +43 -0
  157. package/dist/schema/nodes/pipe-trap.d.ts.map +1 -0
  158. package/dist/schema/nodes/pipe-trap.js +36 -0
  159. package/dist/schema/nodes/ridge-vent.d.ts +18 -3
  160. package/dist/schema/nodes/ridge-vent.d.ts.map +1 -1
  161. package/dist/schema/nodes/ridge-vent.js +221 -3
  162. package/dist/schema/nodes/roof-segment-shape.d.ts +90 -0
  163. package/dist/schema/nodes/roof-segment-shape.d.ts.map +1 -0
  164. package/dist/schema/nodes/roof-segment-shape.js +318 -0
  165. package/dist/schema/nodes/roof-segment-walls.d.ts +101 -0
  166. package/dist/schema/nodes/roof-segment-walls.d.ts.map +1 -0
  167. package/dist/schema/nodes/roof-segment-walls.js +330 -0
  168. package/dist/schema/nodes/roof-segment.d.ts +84 -8
  169. package/dist/schema/nodes/roof-segment.d.ts.map +1 -1
  170. package/dist/schema/nodes/roof-segment.js +290 -5
  171. package/dist/schema/nodes/roof.d.ts +8 -8
  172. package/dist/schema/nodes/shelf.d.ts +4 -2
  173. package/dist/schema/nodes/shelf.d.ts.map +1 -1
  174. package/dist/schema/nodes/shelf.js +8 -0
  175. package/dist/schema/nodes/site.d.ts +9 -0
  176. package/dist/schema/nodes/site.d.ts.map +1 -1
  177. package/dist/schema/nodes/site.js +8 -6
  178. package/dist/schema/nodes/skylight.d.ts +10 -10
  179. package/dist/schema/nodes/slab.d.ts +8 -2
  180. package/dist/schema/nodes/slab.d.ts.map +1 -1
  181. package/dist/schema/nodes/slab.js +18 -2
  182. package/dist/schema/nodes/solar-panel.d.ts +4 -4
  183. package/dist/schema/nodes/spawn.d.ts +1 -0
  184. package/dist/schema/nodes/spawn.d.ts.map +1 -1
  185. package/dist/schema/nodes/spawn.js +2 -0
  186. package/dist/schema/nodes/stair-segment.d.ts +4 -4
  187. package/dist/schema/nodes/stair.d.ts +16 -13
  188. package/dist/schema/nodes/stair.d.ts.map +1 -1
  189. package/dist/schema/nodes/stair.js +11 -1
  190. package/dist/schema/nodes/structural-grid.d.ts +27 -0
  191. package/dist/schema/nodes/structural-grid.d.ts.map +1 -0
  192. package/dist/schema/nodes/structural-grid.js +17 -0
  193. package/dist/schema/nodes/turbine-vent.d.ts +2 -2
  194. package/dist/schema/nodes/wall.d.ts +248 -6
  195. package/dist/schema/nodes/wall.d.ts.map +1 -1
  196. package/dist/schema/nodes/wall.js +266 -0
  197. package/dist/schema/nodes/window.d.ts +40 -3
  198. package/dist/schema/nodes/window.d.ts.map +1 -1
  199. package/dist/schema/nodes/window.js +30 -0
  200. package/dist/schema/nodes/zone.d.ts +22 -0
  201. package/dist/schema/nodes/zone.d.ts.map +1 -1
  202. package/dist/schema/nodes/zone.js +21 -0
  203. package/dist/schema/scene-material.d.ts +41 -0
  204. package/dist/schema/scene-material.d.ts.map +1 -0
  205. package/dist/schema/scene-material.js +9 -0
  206. package/dist/schema/terrain.d.ts +28 -0
  207. package/dist/schema/terrain.d.ts.map +1 -0
  208. package/dist/schema/terrain.js +30 -0
  209. package/dist/schema/types.d.ts +1300 -97
  210. package/dist/schema/types.d.ts.map +1 -1
  211. package/dist/schema/types.js +27 -0
  212. package/dist/services/__fixtures__/wall-plane-top-boundary-repro.d.ts +80 -0
  213. package/dist/services/__fixtures__/wall-plane-top-boundary-repro.d.ts.map +1 -0
  214. package/dist/services/__fixtures__/wall-plane-top-boundary-repro.js +89 -0
  215. package/dist/services/alignment-anchors.d.ts.map +1 -1
  216. package/dist/services/alignment-anchors.js +30 -1
  217. package/dist/services/alignment.d.ts +5 -0
  218. package/dist/services/alignment.d.ts.map +1 -1
  219. package/dist/services/alignment.js +2 -0
  220. package/dist/services/hosting.d.ts +8 -0
  221. package/dist/services/hosting.d.ts.map +1 -1
  222. package/dist/services/hosting.js +13 -4
  223. package/dist/services/index.d.ts +9 -2
  224. package/dist/services/index.d.ts.map +1 -1
  225. package/dist/services/index.js +9 -2
  226. package/dist/services/level-height.d.ts +27 -0
  227. package/dist/services/level-height.d.ts.map +1 -0
  228. package/dist/services/level-height.js +94 -0
  229. package/dist/services/opening-guides.d.ts +141 -0
  230. package/dist/services/opening-guides.d.ts.map +1 -0
  231. package/dist/services/opening-guides.js +267 -0
  232. package/dist/services/port-connectivity.d.ts +115 -0
  233. package/dist/services/port-connectivity.d.ts.map +1 -0
  234. package/dist/services/port-connectivity.js +300 -0
  235. package/dist/services/riser-diagram.d.ts +40 -0
  236. package/dist/services/riser-diagram.d.ts.map +1 -0
  237. package/dist/services/riser-diagram.js +110 -0
  238. package/dist/services/snap.d.ts +9 -1
  239. package/dist/services/snap.d.ts.map +1 -1
  240. package/dist/services/snap.js +21 -1
  241. package/dist/services/storey.d.ts +103 -0
  242. package/dist/services/storey.d.ts.map +1 -0
  243. package/dist/services/storey.js +296 -0
  244. package/dist/services/system-graph.d.ts +30 -0
  245. package/dist/services/system-graph.d.ts.map +1 -0
  246. package/dist/services/system-graph.js +164 -0
  247. package/dist/services/validate-dwv.d.ts +32 -0
  248. package/dist/services/validate-dwv.d.ts.map +1 -0
  249. package/dist/services/validate-dwv.js +118 -0
  250. package/dist/store/actions/node-actions.d.ts.map +1 -1
  251. package/dist/store/actions/node-actions.js +141 -4
  252. package/dist/store/history-control.d.ts +31 -0
  253. package/dist/store/history-control.d.ts.map +1 -1
  254. package/dist/store/history-control.js +130 -0
  255. package/dist/store/use-live-terrain.d.ts +65 -0
  256. package/dist/store/use-live-terrain.d.ts.map +1 -0
  257. package/dist/store/use-live-terrain.js +31 -0
  258. package/dist/store/use-live-transforms.d.ts +8 -0
  259. package/dist/store/use-live-transforms.d.ts.map +1 -1
  260. package/dist/store/use-scene.d.ts +47 -3
  261. package/dist/store/use-scene.d.ts.map +1 -1
  262. package/dist/store/use-scene.js +992 -55
  263. package/dist/systems/elevator/elevator-opening-system.d.ts +1 -0
  264. package/dist/systems/elevator/elevator-opening-system.d.ts.map +1 -1
  265. package/dist/systems/elevator/elevator-opening-system.js +27 -21
  266. package/dist/systems/elevator/elevator-service.d.ts +0 -2
  267. package/dist/systems/elevator/elevator-service.d.ts.map +1 -1
  268. package/dist/systems/elevator/elevator-service.js +2 -24
  269. package/dist/systems/fence/fence-centerline.d.ts +12 -0
  270. package/dist/systems/fence/fence-centerline.d.ts.map +1 -0
  271. package/dist/systems/fence/fence-centerline.js +37 -0
  272. package/dist/systems/fence/fence-spline.d.ts +39 -0
  273. package/dist/systems/fence/fence-spline.d.ts.map +1 -0
  274. package/dist/systems/fence/fence-spline.js +196 -0
  275. package/dist/systems/slab/slab-placement.d.ts +11 -0
  276. package/dist/systems/slab/slab-placement.d.ts.map +1 -0
  277. package/dist/systems/slab/slab-placement.js +14 -0
  278. package/dist/systems/slab/slab-support.d.ts +137 -0
  279. package/dist/systems/slab/slab-support.d.ts.map +1 -0
  280. package/dist/systems/slab/slab-support.js +557 -0
  281. package/dist/systems/stair/stair-footprint.d.ts.map +1 -1
  282. package/dist/systems/stair/stair-footprint.js +21 -11
  283. package/dist/systems/stair/stair-opening-preview.d.ts +1300 -505
  284. package/dist/systems/stair/stair-opening-preview.d.ts.map +1 -1
  285. package/dist/systems/stair/stair-opening-sync.d.ts.map +1 -1
  286. package/dist/systems/stair/stair-opening-sync.js +19 -33
  287. package/dist/systems/stair/stair-opening-system.d.ts.map +1 -1
  288. package/dist/systems/stair/stair-opening-system.js +32 -4
  289. package/dist/systems/stair/stair-rise.d.ts +22 -0
  290. package/dist/systems/stair/stair-rise.d.ts.map +1 -0
  291. package/dist/systems/stair/stair-rise.js +79 -0
  292. package/dist/systems/wall/wall-curve.d.ts +10 -0
  293. package/dist/systems/wall/wall-curve.d.ts.map +1 -1
  294. package/dist/systems/wall/wall-curve.js +1 -1
  295. package/dist/systems/wall/wall-mitering.d.ts.map +1 -1
  296. package/dist/systems/wall/wall-mitering.js +44 -8
  297. package/dist/systems/wall/wall-top.d.ts +40 -0
  298. package/dist/systems/wall/wall-top.d.ts.map +1 -0
  299. package/dist/systems/wall/wall-top.js +46 -0
  300. package/dist/utils/clone-scene-graph.d.ts +1 -0
  301. package/dist/utils/clone-scene-graph.d.ts.map +1 -1
  302. package/dist/utils/clone-scene-graph.js +56 -5
  303. package/dist/utils/heal-scene-graph.d.ts +18 -0
  304. package/dist/utils/heal-scene-graph.d.ts.map +1 -0
  305. package/dist/utils/heal-scene-graph.js +106 -0
  306. package/dist/validation/validate-build-json.d.ts +3 -0
  307. package/dist/validation/validate-build-json.d.ts.map +1 -1
  308. package/dist/validation/validate-build-json.js +90 -5
  309. package/package.json +4 -4
  310. package/dist/hooks/spatial-grid/floor-placed-elevation.test.d.ts +0 -2
  311. package/dist/hooks/spatial-grid/floor-placed-elevation.test.d.ts.map +0 -1
  312. package/dist/hooks/spatial-grid/floor-placed-elevation.test.js +0 -273
  313. package/dist/lib/space-detection-pause.test.d.ts +0 -2
  314. package/dist/lib/space-detection-pause.test.d.ts.map +0 -1
  315. package/dist/lib/space-detection-pause.test.js +0 -42
  316. package/dist/lib/space-detection.test.d.ts +0 -2
  317. package/dist/lib/space-detection.test.d.ts.map +0 -1
  318. package/dist/lib/space-detection.test.js +0 -77
  319. package/dist/registry/registry.test.d.ts +0 -2
  320. package/dist/registry/registry.test.d.ts.map +0 -1
  321. package/dist/registry/registry.test.js +0 -183
  322. package/dist/registry/relations-resolver.test.d.ts +0 -2
  323. package/dist/registry/relations-resolver.test.d.ts.map +0 -1
  324. package/dist/registry/relations-resolver.test.js +0 -183
  325. package/dist/registry/scene-api.test.d.ts +0 -2
  326. package/dist/registry/scene-api.test.d.ts.map +0 -1
  327. package/dist/registry/scene-api.test.js +0 -183
  328. package/dist/registry/subtree.test.d.ts +0 -2
  329. package/dist/registry/subtree.test.d.ts.map +0 -1
  330. package/dist/registry/subtree.test.js +0 -133
  331. package/dist/schema/asset-url.test.d.ts +0 -2
  332. package/dist/schema/asset-url.test.d.ts.map +0 -1
  333. package/dist/schema/asset-url.test.js +0 -134
  334. package/dist/services/alignment-anchors.test.d.ts +0 -2
  335. package/dist/services/alignment-anchors.test.d.ts.map +0 -1
  336. package/dist/services/alignment-anchors.test.js +0 -383
  337. package/dist/services/alignment.test.d.ts +0 -2
  338. package/dist/services/alignment.test.d.ts.map +0 -1
  339. package/dist/services/alignment.test.js +0 -92
  340. package/dist/services/drag-session.test.d.ts +0 -2
  341. package/dist/services/drag-session.test.d.ts.map +0 -1
  342. package/dist/services/drag-session.test.js +0 -219
  343. package/dist/services/hosting.test.d.ts +0 -2
  344. package/dist/services/hosting.test.d.ts.map +0 -1
  345. package/dist/services/hosting.test.js +0 -199
  346. package/dist/services/movement.test.d.ts +0 -2
  347. package/dist/services/movement.test.d.ts.map +0 -1
  348. package/dist/services/movement.test.js +0 -133
  349. package/dist/services/single-undo-dance.test.d.ts +0 -2
  350. package/dist/services/single-undo-dance.test.d.ts.map +0 -1
  351. package/dist/services/single-undo-dance.test.js +0 -210
  352. package/dist/services/snap.test.d.ts +0 -2
  353. package/dist/services/snap.test.d.ts.map +0 -1
  354. package/dist/services/snap.test.js +0 -95
  355. package/dist/store/actions/node-mutation-sanitize.test.d.ts +0 -2
  356. package/dist/store/actions/node-mutation-sanitize.test.d.ts.map +0 -1
  357. package/dist/store/actions/node-mutation-sanitize.test.js +0 -147
  358. package/dist/store/actions/reparent.test.d.ts +0 -2
  359. package/dist/store/actions/reparent.test.d.ts.map +0 -1
  360. package/dist/store/actions/reparent.test.js +0 -212
  361. package/dist/store/use-scene-elevator-migration.test.d.ts +0 -2
  362. package/dist/store/use-scene-elevator-migration.test.d.ts.map +0 -1
  363. package/dist/store/use-scene-elevator-migration.test.js +0 -109
  364. package/dist/systems/elevator/elevator-opening-sync.test.d.ts +0 -2
  365. package/dist/systems/elevator/elevator-opening-sync.test.d.ts.map +0 -1
  366. package/dist/systems/elevator/elevator-opening-sync.test.js +0 -146
  367. package/dist/systems/elevator/elevator-runtime.test.d.ts +0 -2
  368. package/dist/systems/elevator/elevator-runtime.test.d.ts.map +0 -1
  369. package/dist/systems/elevator/elevator-runtime.test.js +0 -64
  370. package/dist/systems/stair/stair-opening-preview.test.d.ts +0 -2
  371. package/dist/systems/stair/stair-opening-preview.test.d.ts.map +0 -1
  372. package/dist/systems/stair/stair-opening-preview.test.js +0 -80
  373. package/dist/systems/stair/stair-opening-sync.test.d.ts +0 -2
  374. package/dist/systems/stair/stair-opening-sync.test.d.ts.map +0 -1
  375. package/dist/systems/stair/stair-opening-sync.test.js +0 -446
  376. package/dist/utils/clone-scene-graph.test.d.ts +0 -2
  377. package/dist/utils/clone-scene-graph.test.d.ts.map +0 -1
  378. package/dist/utils/clone-scene-graph.test.js +0 -59
@@ -1,3 +1,5 @@
1
+ import { GROUND_SUPPORT_ID } from '../hooks/spatial-grid/floor-placed-elevation';
2
+ import { remapConstructionDimensionReferences, remapMeasurementReferences, } from '../lib/measurement-geometry';
1
3
  import { generateId } from '../schema/base';
2
4
  /**
3
5
  * Extracts the type prefix from a node ID (e.g., "wall_abc123" -> "wall")
@@ -16,7 +18,7 @@ function extractIdPrefix(id) {
16
18
  * - Multi-scene in-memory scenarios
17
19
  */
18
20
  export function cloneSceneGraph(sceneGraph) {
19
- const { nodes, rootNodeIds, collections } = sceneGraph;
21
+ const { nodes, rootNodeIds, collections, installedPlugins } = sceneGraph;
20
22
  // Build ID mapping: old ID -> new ID
21
23
  const idMap = new Map();
22
24
  // Pass 1: Generate new IDs for all nodes
@@ -28,7 +30,7 @@ export function cloneSceneGraph(sceneGraph) {
28
30
  const clonedNodes = {};
29
31
  for (const [oldId, node] of Object.entries(nodes)) {
30
32
  const newId = idMap.get(oldId);
31
- const clonedNode = structuredClone({ ...node, id: newId });
33
+ let clonedNode = structuredClone({ ...node, id: newId });
32
34
  // Remap parentId
33
35
  if (clonedNode.parentId && typeof clonedNode.parentId === 'string') {
34
36
  clonedNode.parentId = (idMap.get(clonedNode.parentId) ?? null);
@@ -57,6 +59,29 @@ export function cloneSceneGraph(sceneGraph) {
57
59
  ;
58
60
  clonedNode.wallId = idMap.get(clonedNode.wallId);
59
61
  }
62
+ // Remap roofSegmentId (doors/windows/items hosted on roof wall faces)
63
+ if ('roofSegmentId' in clonedNode && typeof clonedNode.roofSegmentId === 'string') {
64
+ ;
65
+ clonedNode.roofSegmentId = idMap.get(clonedNode.roofSegmentId);
66
+ }
67
+ // Remap supportSlabId (persisted slab-support hosts). The 'ground'
68
+ // sentinel is not a node id — keep it as-is.
69
+ if ('supportSlabId' in clonedNode &&
70
+ typeof clonedNode.supportSlabId === 'string' &&
71
+ clonedNode.supportSlabId !== GROUND_SUPPORT_ID) {
72
+ ;
73
+ clonedNode.supportSlabId = idMap.get(clonedNode.supportSlabId);
74
+ }
75
+ if ('deckSlabId' in clonedNode && typeof clonedNode.deckSlabId === 'string') {
76
+ ;
77
+ clonedNode.deckSlabId = idMap.get(clonedNode.deckSlabId);
78
+ }
79
+ if (clonedNode.type === 'measurement') {
80
+ clonedNode.measurement = remapMeasurementReferences(clonedNode.measurement, idMap);
81
+ }
82
+ if (clonedNode.type === 'construction-dimension') {
83
+ clonedNode = remapConstructionDimensionReferences(clonedNode, idMap);
84
+ }
60
85
  clonedNodes[newId] = clonedNode;
61
86
  }
62
87
  // Remap root node IDs
@@ -102,6 +127,7 @@ export function cloneSceneGraph(sceneGraph) {
102
127
  nodes: clonedNodes,
103
128
  rootNodeIds: clonedRootNodeIds,
104
129
  ...(clonedCollections && { collections: clonedCollections }),
130
+ ...(installedPlugins && { installedPlugins: [...installedPlugins] }),
105
131
  };
106
132
  }
107
133
  /**
@@ -119,7 +145,7 @@ export function cloneSceneGraph(sceneGraph) {
119
145
  */
120
146
  export function cloneLevelSubtree(nodes, levelId) {
121
147
  const levelNode = nodes[levelId];
122
- if (!levelNode || levelNode.type !== 'level') {
148
+ if (levelNode?.type !== 'level') {
123
149
  throw new Error(`Node "${levelId}" is not a level`);
124
150
  }
125
151
  // Recursively collect the level node + all descendants via children arrays
@@ -156,7 +182,7 @@ export function cloneLevelSubtree(nodes, levelId) {
156
182
  continue;
157
183
  const newId = idMap.get(oldId);
158
184
  // JSON roundtrip: safely strips functions, Object3D, circular refs, etc.
159
- const cloned = JSON.parse(JSON.stringify(node));
185
+ let cloned = JSON.parse(JSON.stringify(node));
160
186
  cloned.id = newId;
161
187
  // Remap parentId — but only for descendants, not the level node itself
162
188
  // (the level's parentId points to the building, which is outside the subtree)
@@ -185,6 +211,30 @@ export function cloneLevelSubtree(nodes, levelId) {
185
211
  ;
186
212
  cloned.wallId = idMap.get(cloned.wallId) ?? cloned.wallId;
187
213
  }
214
+ // Remap roofSegmentId (doors/windows/items hosted on roof wall faces)
215
+ if ('roofSegmentId' in cloned && typeof cloned.roofSegmentId === 'string') {
216
+ ;
217
+ cloned.roofSegmentId =
218
+ idMap.get(cloned.roofSegmentId) ?? cloned.roofSegmentId;
219
+ }
220
+ // Remap supportSlabId when the host slab is inside the cloned subtree;
221
+ // preserve it otherwise (like wallId, the reference may point outside).
222
+ if ('supportSlabId' in cloned && typeof cloned.supportSlabId === 'string') {
223
+ ;
224
+ cloned.supportSlabId =
225
+ idMap.get(cloned.supportSlabId) ?? cloned.supportSlabId;
226
+ }
227
+ if ('deckSlabId' in cloned && typeof cloned.deckSlabId === 'string') {
228
+ ;
229
+ cloned.deckSlabId =
230
+ idMap.get(cloned.deckSlabId) ?? cloned.deckSlabId;
231
+ }
232
+ if (cloned.type === 'measurement') {
233
+ cloned.measurement = remapMeasurementReferences(cloned.measurement, idMap);
234
+ }
235
+ if (cloned.type === 'construction-dimension') {
236
+ cloned = remapConstructionDimensionReferences(cloned, idMap);
237
+ }
188
238
  clonedNodes.push(cloned);
189
239
  }
190
240
  return { clonedNodes, newLevelId, idMap };
@@ -197,7 +247,7 @@ export function forkSceneGraph(sceneGraph, options = {}) {
197
247
  if (options.preserveScans) {
198
248
  return cloneSceneGraph(sceneGraph);
199
249
  }
200
- const { nodes, rootNodeIds, collections } = sceneGraph;
250
+ const { nodes, rootNodeIds, collections, installedPlugins } = sceneGraph;
201
251
  // First, identify scan and guide node IDs to exclude (user-uploaded imagery)
202
252
  const excludedNodeIds = new Set();
203
253
  for (const [nodeId, node] of Object.entries(nodes)) {
@@ -249,5 +299,6 @@ export function forkSceneGraph(sceneGraph, options = {}) {
249
299
  nodes: filteredNodes,
250
300
  rootNodeIds: filteredRootNodeIds,
251
301
  ...(filteredCollections && { collections: filteredCollections }),
302
+ ...(installedPlugins && { installedPlugins }),
252
303
  });
253
304
  }
@@ -0,0 +1,18 @@
1
+ export interface HealSceneResult {
2
+ nodes: Record<string, unknown>;
3
+ /** Ids of zero-length walls that were dropped. */
4
+ droppedWallIds: string[];
5
+ /** Count of invalid non-string (e.g. null) entries removed from `children` arrays. */
6
+ strippedChildRefs: number;
7
+ /**
8
+ * Count of child references removed because the child's `parentId` points at
9
+ * a different node (stale reparent leftovers), plus same-array duplicates.
10
+ */
11
+ strippedStaleChildRefs: number;
12
+ }
13
+ /**
14
+ * Returns a healed copy of a `nodes` map. Pure — does not mutate `input`.
15
+ * Nodes that need no repair are passed through by reference.
16
+ */
17
+ export declare function healSceneNodes(input: Record<string, unknown>): HealSceneResult;
18
+ //# sourceMappingURL=heal-scene-graph.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"heal-scene-graph.d.ts","sourceRoot":"","sources":["../../src/utils/heal-scene-graph.ts"],"names":[],"mappings":"AAqBA,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC9B,kDAAkD;IAClD,cAAc,EAAE,MAAM,EAAE,CAAA;IACxB,sFAAsF;IACtF,iBAAiB,EAAE,MAAM,CAAA;IACzB;;;OAGG;IACH,sBAAsB,EAAE,MAAM,CAAA;CAC/B;AAgBD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,eAAe,CA2E9E"}
@@ -0,0 +1,106 @@
1
+ // Repairs scene-graph corruption that pre-dates the source fixes, so existing
2
+ // saved scenes still load. Known kinds of damage:
3
+ //
4
+ // 1. A `children` array containing a non-string entry. The capture wall-merge
5
+ // re-attached a wall-hosted item without minting an id, so `undefined` was
6
+ // pushed into the wall's children — which serializes to `[null]`. The wall
7
+ // schema rejects `null` children, so the whole scene fails to load.
8
+ // 2. A zero-length wall (start === end). It renders nothing, but lingers as a
9
+ // junk node and is a foot-gun for snapping/mitering.
10
+ // 3. A child referenced by a parent it no longer belongs to: the child's
11
+ // `parentId` points at node B while node A's `children` still lists it
12
+ // (stale leftover from a reparent that didn't clean the old parent). The
13
+ // duplicate reference renders the child twice (duplicate React keys in the
14
+ // 2D plan, doubled hosted geometry in 3D). Same-array duplicates are
15
+ // collapsed too.
16
+ //
17
+ // All are also prevented at the source now; this is the load-time safety net
18
+ // for already-saved scenes.
19
+ const ZERO_LENGTH_EPS = 1e-6;
20
+ function isWallLike(node) {
21
+ if (!node || typeof node !== 'object')
22
+ return false;
23
+ const n = node;
24
+ return (n.type === 'wall' &&
25
+ Array.isArray(n.start) &&
26
+ Array.isArray(n.end) &&
27
+ typeof n.start[0] === 'number' &&
28
+ typeof n.start[1] === 'number' &&
29
+ typeof n.end[0] === 'number' &&
30
+ typeof n.end[1] === 'number');
31
+ }
32
+ /**
33
+ * Returns a healed copy of a `nodes` map. Pure — does not mutate `input`.
34
+ * Nodes that need no repair are passed through by reference.
35
+ */
36
+ export function healSceneNodes(input) {
37
+ const droppedWallIds = [];
38
+ // Pass 1: drop childless zero-length walls. (Only childless ones — a wall
39
+ // carrying a door/window must keep its hosts, degenerate or not.)
40
+ const kept = {};
41
+ for (const [id, node] of Object.entries(input)) {
42
+ if (isWallLike(node)) {
43
+ const children = node.children;
44
+ const childless = !Array.isArray(children) || children.length === 0;
45
+ const dx = node.end[0] - node.start[0];
46
+ const dz = node.end[1] - node.start[1];
47
+ if (childless && Math.hypot(dx, dz) <= ZERO_LENGTH_EPS) {
48
+ droppedWallIds.push(id);
49
+ continue;
50
+ }
51
+ }
52
+ kept[id] = node;
53
+ }
54
+ const dropped = new Set(droppedWallIds);
55
+ let strippedChildRefs = 0;
56
+ let strippedStaleChildRefs = 0;
57
+ // Pass 2: clean `children` arrays — drop invalid non-string entries (the
58
+ // `[null]` bug), references to walls we just removed, same-array duplicates,
59
+ // and stale references whose child's `parentId` names a different parent.
60
+ // Legacy sites embedded full child objects; keep those for migrateNodes to
61
+ // flatten after healing instead of disconnecting the entire building.
62
+ const nodes = {};
63
+ for (const [id, node] of Object.entries(kept)) {
64
+ const children = node?.children;
65
+ if (Array.isArray(children)) {
66
+ const seen = new Set();
67
+ const cleaned = children.filter((child) => {
68
+ const embeddedSiteChildId = node.type === 'site' &&
69
+ child &&
70
+ typeof child === 'object' &&
71
+ typeof child.id === 'string'
72
+ ? child.id
73
+ : null;
74
+ if (embeddedSiteChildId) {
75
+ if (seen.has(embeddedSiteChildId)) {
76
+ strippedStaleChildRefs++;
77
+ return false;
78
+ }
79
+ seen.add(embeddedSiteChildId);
80
+ return true;
81
+ }
82
+ if (typeof child !== 'string' || dropped.has(child)) {
83
+ strippedChildRefs++;
84
+ return false;
85
+ }
86
+ if (seen.has(child)) {
87
+ strippedStaleChildRefs++;
88
+ return false;
89
+ }
90
+ seen.add(child);
91
+ const childNode = kept[child];
92
+ if (childNode && typeof childNode.parentId === 'string' && childNode.parentId !== id) {
93
+ strippedStaleChildRefs++;
94
+ return false;
95
+ }
96
+ return true;
97
+ });
98
+ if (cleaned.length !== children.length) {
99
+ nodes[id] = { ...node, children: cleaned };
100
+ continue;
101
+ }
102
+ }
103
+ nodes[id] = node;
104
+ }
105
+ return { nodes, droppedWallIds, strippedChildRefs, strippedStaleChildRefs };
106
+ }
@@ -9,12 +9,15 @@ export type ValidationIssue = {
9
9
  export type BuildStats = {
10
10
  total: number;
11
11
  byType: Partial<Record<AnyNodeType, number>>;
12
+ /** Kinds outside the static schema union but registered at runtime (plugins). */
13
+ pluginTypes: Record<string, number>;
12
14
  unknownTypes: Record<string, number>;
13
15
  floorAreaM2: number;
14
16
  };
15
17
  export type ParsedBuildJson = {
16
18
  nodes: Record<string, unknown>;
17
19
  rootNodeIds: string[];
20
+ installedPlugins?: string[];
18
21
  };
19
22
  export type SchemaIssue = {
20
23
  nodeId: string;
@@ -1 +1 @@
1
- {"version":3,"file":"validate-build-json.d.ts","sourceRoot":"","sources":["../../src/validation/validate-build-json.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,KAAK,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAE3D,MAAM,MAAM,kBAAkB,GAAG,OAAO,GAAG,SAAS,CAAA;AAEpD,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,EAAE,kBAAkB,CAAA;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAA;IAC5C,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACpC,WAAW,EAAE,MAAM,CAAA;CACpB,CAAA;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC9B,WAAW,EAAE,MAAM,EAAE,CAAA;CACtB,CAAA;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,MAAM,MAAM,uBAAuB,GAAG;IACpC,EAAE,EAAE,OAAO,CAAA;IACX,MAAM,EAAE,eAAe,GAAG,IAAI,CAAA;IAC9B,KAAK,EAAE,UAAU,CAAA;IACjB,MAAM,EAAE,eAAe,EAAE,CAAA;IACzB,QAAQ,EAAE,eAAe,EAAE,CAAA;IAC3B,YAAY,EAAE,WAAW,EAAE,CAAA;IAC3B,gBAAgB,EAAE,MAAM,CAAA;CACzB,CAAA;AA8BD;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,uBAAuB,CAuNzE"}
1
+ {"version":3,"file":"validate-build-json.d.ts","sourceRoot":"","sources":["../../src/validation/validate-build-json.ts"],"names":[],"mappings":"AACA,OAAO,EAAW,KAAK,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAG3D,MAAM,MAAM,kBAAkB,GAAG,OAAO,GAAG,SAAS,CAAA;AAEpD,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,EAAE,kBAAkB,CAAA;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAA;IAC5C,iFAAiF;IACjF,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACnC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACpC,WAAW,EAAE,MAAM,CAAA;CACpB,CAAA;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC9B,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAA;CAC5B,CAAA;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,MAAM,MAAM,uBAAuB,GAAG;IACpC,EAAE,EAAE,OAAO,CAAA;IACX,MAAM,EAAE,eAAe,GAAG,IAAI,CAAA;IAC9B,KAAK,EAAE,UAAU,CAAA;IACjB,MAAM,EAAE,eAAe,EAAE,CAAA;IACzB,QAAQ,EAAE,eAAe,EAAE,CAAA;IAC3B,YAAY,EAAE,WAAW,EAAE,CAAA;IAC3B,gBAAgB,EAAE,MAAM,CAAA;CACzB,CAAA;AA8BD;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,uBAAuB,CA8SzE"}
@@ -1,4 +1,6 @@
1
+ import { nodeRegistry } from '../registry';
1
2
  import { AnyNode } from '../schema/types';
3
+ import { healSceneNodes } from '../utils/heal-scene-graph';
2
4
  const KNOWN_TYPES = new Set(AnyNode.options.map((o) => o.shape.type.parse(undefined)));
3
5
  function isPlainObject(value) {
4
6
  return typeof value === 'object' && value !== null && !Array.isArray(value);
@@ -33,7 +35,13 @@ export function validateBuildJson(input) {
33
35
  const errors = [];
34
36
  const warnings = [];
35
37
  const schemaIssues = [];
36
- const stats = { total: 0, byType: {}, unknownTypes: {}, floorAreaM2: 0 };
38
+ const stats = {
39
+ total: 0,
40
+ byType: {},
41
+ pluginTypes: {},
42
+ unknownTypes: {},
43
+ floorAreaM2: 0,
44
+ };
37
45
  if (!isPlainObject(input)) {
38
46
  errors.push({
39
47
  severity: 'error',
@@ -52,6 +60,7 @@ export function validateBuildJson(input) {
52
60
  }
53
61
  const nodesRaw = input.nodes;
54
62
  const rootNodeIdsRaw = input.rootNodeIds;
63
+ const installedPluginsRaw = input.installedPlugins;
55
64
  if (!isPlainObject(nodesRaw)) {
56
65
  errors.push({
57
66
  severity: 'error',
@@ -77,8 +86,29 @@ export function validateBuildJson(input) {
77
86
  schemaIssueCount: 0,
78
87
  };
79
88
  }
80
- const nodes = nodesRaw;
89
+ // Heal known pre-existing corruption (null children, zero-length walls) up
90
+ // front, so a scene saved before the source fixes still imports instead of
91
+ // hard-failing schema validation. `parsed` below carries the repaired nodes.
92
+ const { nodes, droppedWallIds, strippedChildRefs } = healSceneNodes(nodesRaw);
81
93
  const rootNodeIds = rootNodeIdsRaw;
94
+ const installedPlugins = Array.isArray(installedPluginsRaw) &&
95
+ installedPluginsRaw.every((pluginId) => typeof pluginId === 'string')
96
+ ? Array.from(new Set(installedPluginsRaw))
97
+ : undefined;
98
+ if (installedPluginsRaw !== undefined && installedPlugins === undefined) {
99
+ warnings.push({
100
+ severity: 'warning',
101
+ code: 'invalid_installed_plugins',
102
+ message: 'Ignored invalid "installedPlugins" — expected an array of plugin IDs.',
103
+ });
104
+ }
105
+ if (strippedChildRefs > 0 || droppedWallIds.length > 0) {
106
+ warnings.push({
107
+ severity: 'warning',
108
+ code: 'auto_repaired',
109
+ message: `Repaired on import: removed ${strippedChildRefs} invalid child reference${strippedChildRefs === 1 ? '' : 's'} and ${droppedWallIds.length} zero-length wall${droppedWallIds.length === 1 ? '' : 's'}.`,
110
+ });
111
+ }
82
112
  if (rootNodeIds.length === 0) {
83
113
  errors.push({
84
114
  severity: 'error',
@@ -86,6 +116,33 @@ export function validateBuildJson(input) {
86
116
  message: '"rootNodeIds" is empty — no entry point into the scene.',
87
117
  });
88
118
  }
119
+ // Ids of nodes whose type falls outside the static schema union — plugin
120
+ // kinds (`trees:tree`) or genuinely unknown types. The scene store accepts
121
+ // them on load (they already round-trip through the DB fine) and they're
122
+ // surfaced by the unknown-types warning, but a parent's strict `children`
123
+ // id union would hard-fail over them: validate parents against a copy with
124
+ // those ids filtered out. The imported data itself keeps them.
125
+ const nonSchemaNodeIds = new Set();
126
+ for (const [key, value] of Object.entries(nodes)) {
127
+ if (!isPlainObject(value))
128
+ continue;
129
+ const type = typeof value.type === 'string' ? value.type : null;
130
+ if (type && KNOWN_TYPES.has(type))
131
+ continue;
132
+ nonSchemaNodeIds.add(typeof value.id === 'string' ? value.id : key);
133
+ }
134
+ const withoutNonSchemaChildren = (value) => {
135
+ const children = value.children;
136
+ if (!Array.isArray(children))
137
+ return value;
138
+ if (!children.some((child) => typeof child === 'string' && nonSchemaNodeIds.has(child))) {
139
+ return value;
140
+ }
141
+ return {
142
+ ...value,
143
+ children: children.filter((child) => !(typeof child === 'string' && nonSchemaNodeIds.has(child))),
144
+ };
145
+ };
89
146
  let validRootCount = 0;
90
147
  let mismatchedKeyCount = 0;
91
148
  let schemaFailureCount = 0;
@@ -118,7 +175,7 @@ export function validateBuildJson(input) {
118
175
  if (KNOWN_TYPES.has(type)) {
119
176
  const t = type;
120
177
  stats.byType[t] = (stats.byType[t] ?? 0) + 1;
121
- const parseResult = AnyNode.safeParse(value);
178
+ const parseResult = AnyNode.safeParse(withoutNonSchemaChildren(value));
122
179
  if (!parseResult.success) {
123
180
  schemaFailureCount += 1;
124
181
  const issue = parseResult.error.issues[0];
@@ -145,7 +202,29 @@ export function validateBuildJson(input) {
145
202
  }
146
203
  }
147
204
  else {
148
- stats.unknownTypes[type] = (stats.unknownTypes[type] ?? 0) + 1;
205
+ const registered = nodeRegistry.get(type);
206
+ if (registered) {
207
+ // A runtime-registered plugin kind (e.g. `trees:tree`) is a
208
+ // first-class citizen: validate it with its own registered schema
209
+ // instead of flagging it unknown. Files from projects whose plugin
210
+ // is NOT loaded here still fall through to the unknown-types
211
+ // warning below.
212
+ stats.pluginTypes[type] = (stats.pluginTypes[type] ?? 0) + 1;
213
+ const parseResult = registered.schema.safeParse(value);
214
+ if (!parseResult.success) {
215
+ schemaFailureCount += 1;
216
+ const issue = parseResult.error.issues[0];
217
+ schemaIssues.push({
218
+ nodeId: key,
219
+ nodeType: type,
220
+ path: issue ? issue.path.join('.') : '',
221
+ message: issue ? issue.message : 'schema mismatch',
222
+ });
223
+ }
224
+ }
225
+ else {
226
+ stats.unknownTypes[type] = (stats.unknownTypes[type] ?? 0) + 1;
227
+ }
149
228
  }
150
229
  if (parentId && !(parentId in nodes)) {
151
230
  warnings.push({
@@ -217,7 +296,13 @@ export function validateBuildJson(input) {
217
296
  const ok = errors.length === 0;
218
297
  return {
219
298
  ok,
220
- parsed: ok ? { nodes, rootNodeIds } : null,
299
+ parsed: ok
300
+ ? {
301
+ nodes,
302
+ rootNodeIds,
303
+ ...(installedPlugins ? { installedPlugins } : {}),
304
+ }
305
+ : null,
221
306
  stats,
222
307
  errors,
223
308
  warnings,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pascal-app/core",
3
- "version": "0.9.1",
3
+ "version": "1.0.0-beta.1",
4
4
  "description": "Core library for Pascal 3D building editor",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -58,8 +58,8 @@
58
58
  ],
59
59
  "scripts": {
60
60
  "build": "tsc --build",
61
- "dev": "tsc --build --watch",
62
- "test": "bun test",
61
+ "dev": "tsgo --build --watch",
62
+ "test": "bun test src",
63
63
  "bench:registry": "bun run src/registry/__bench__/relations-resolver.bench.ts",
64
64
  "prepublishOnly": "npm run build"
65
65
  },
@@ -67,7 +67,7 @@
67
67
  "@react-three/drei": "^10",
68
68
  "@react-three/fiber": "^9",
69
69
  "react": "^18 || ^19",
70
- "three": "^0.184"
70
+ "three": "^0.185"
71
71
  },
72
72
  "dependencies": {
73
73
  "dedent": "^1.7.1",
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=floor-placed-elevation.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"floor-placed-elevation.test.d.ts","sourceRoot":"","sources":["../../../src/hooks/spatial-grid/floor-placed-elevation.test.ts"],"names":[],"mappings":""}