@pascal-app/core 1.0.3 → 1.0.4

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 (1098) hide show
  1. package/dist/agent-operations/__fixtures__/add-object-cases.d.ts +235 -0
  2. package/dist/agent-operations/__fixtures__/add-object-cases.d.ts.map +1 -0
  3. package/dist/agent-operations/__fixtures__/add-object-cases.js +129 -0
  4. package/dist/agent-operations/__fixtures__/build-room-cases.d.ts +4 -0
  5. package/dist/agent-operations/__fixtures__/build-room-cases.d.ts.map +1 -0
  6. package/dist/agent-operations/__fixtures__/build-room-cases.js +635 -0
  7. package/dist/agent-operations/__fixtures__/cases.d.ts +52 -0
  8. package/dist/agent-operations/__fixtures__/cases.d.ts.map +1 -0
  9. package/dist/agent-operations/__fixtures__/cases.js +689 -0
  10. package/dist/agent-operations/__fixtures__/find-by-type-cases.d.ts +7 -0
  11. package/dist/agent-operations/__fixtures__/find-by-type-cases.d.ts.map +1 -0
  12. package/dist/agent-operations/__fixtures__/find-by-type-cases.js +21 -0
  13. package/dist/agent-operations/__fixtures__/place-items-cases.d.ts +17 -0
  14. package/dist/agent-operations/__fixtures__/place-items-cases.d.ts.map +1 -0
  15. package/dist/agent-operations/__fixtures__/place-items-cases.js +506 -0
  16. package/dist/agent-operations/__fixtures__/room-cases.d.ts +3 -0
  17. package/dist/agent-operations/__fixtures__/room-cases.d.ts.map +1 -0
  18. package/dist/agent-operations/__fixtures__/room-cases.js +338 -0
  19. package/dist/agent-operations/__fixtures__/search-assets-cases.d.ts +5 -0
  20. package/dist/agent-operations/__fixtures__/search-assets-cases.d.ts.map +1 -0
  21. package/dist/agent-operations/__fixtures__/search-assets-cases.js +137 -0
  22. package/dist/agent-operations/__fixtures__/structure-cases.d.ts +6 -0
  23. package/dist/agent-operations/__fixtures__/structure-cases.d.ts.map +1 -0
  24. package/dist/agent-operations/__fixtures__/structure-cases.js +588 -0
  25. package/dist/agent-operations/__fixtures__/verify-scene-cases.d.ts +3 -0
  26. package/dist/agent-operations/__fixtures__/verify-scene-cases.d.ts.map +1 -0
  27. package/dist/agent-operations/__fixtures__/verify-scene-cases.js +302 -0
  28. package/dist/agent-operations/achieved.d.ts +16 -0
  29. package/dist/agent-operations/achieved.d.ts.map +1 -0
  30. package/dist/agent-operations/achieved.js +28 -0
  31. package/dist/agent-operations/add-column.d.ts +23 -0
  32. package/dist/agent-operations/add-column.d.ts.map +1 -0
  33. package/dist/agent-operations/add-column.js +97 -0
  34. package/dist/agent-operations/add-level.d.ts +14 -0
  35. package/dist/agent-operations/add-level.d.ts.map +1 -0
  36. package/dist/agent-operations/add-level.js +94 -0
  37. package/dist/agent-operations/add-object.d.ts +114 -0
  38. package/dist/agent-operations/add-object.d.ts.map +1 -0
  39. package/dist/agent-operations/add-object.js +361 -0
  40. package/dist/agent-operations/add-wall.d.ts +15 -0
  41. package/dist/agent-operations/add-wall.d.ts.map +1 -0
  42. package/dist/agent-operations/add-wall.js +47 -0
  43. package/dist/agent-operations/apply-changes.d.ts +16 -0
  44. package/dist/agent-operations/apply-changes.d.ts.map +1 -0
  45. package/dist/agent-operations/apply-changes.js +93 -0
  46. package/dist/agent-operations/apply-outcome.d.ts +15 -0
  47. package/dist/agent-operations/apply-outcome.d.ts.map +1 -0
  48. package/dist/agent-operations/apply-outcome.js +18 -0
  49. package/dist/agent-operations/collections.d.ts +28 -0
  50. package/dist/agent-operations/collections.d.ts.map +1 -0
  51. package/dist/agent-operations/collections.js +130 -0
  52. package/dist/agent-operations/create-room.d.ts +36 -0
  53. package/dist/agent-operations/create-room.d.ts.map +1 -0
  54. package/dist/agent-operations/create-room.js +177 -0
  55. package/dist/agent-operations/create-stair.d.ts +33 -0
  56. package/dist/agent-operations/create-stair.d.ts.map +1 -0
  57. package/dist/agent-operations/create-stair.js +247 -0
  58. package/dist/agent-operations/delete-node.d.ts +6 -0
  59. package/dist/agent-operations/delete-node.d.ts.map +1 -0
  60. package/dist/agent-operations/delete-node.js +9 -0
  61. package/dist/agent-operations/door-clearance.d.ts +135 -0
  62. package/dist/agent-operations/door-clearance.d.ts.map +1 -0
  63. package/dist/agent-operations/door-clearance.js +334 -0
  64. package/dist/agent-operations/duplicate-level.d.ts +12 -0
  65. package/dist/agent-operations/duplicate-level.d.ts.map +1 -0
  66. package/dist/agent-operations/duplicate-level.js +54 -0
  67. package/dist/agent-operations/find-by-type.d.ts +11 -0
  68. package/dist/agent-operations/find-by-type.d.ts.map +1 -0
  69. package/dist/agent-operations/find-by-type.js +94 -0
  70. package/dist/agent-operations/furnish-room.d.ts +18 -0
  71. package/dist/agent-operations/furnish-room.d.ts.map +1 -0
  72. package/dist/agent-operations/furnish-room.js +259 -0
  73. package/dist/agent-operations/get-node.d.ts +9 -0
  74. package/dist/agent-operations/get-node.d.ts.map +1 -0
  75. package/dist/agent-operations/get-node.js +33 -0
  76. package/dist/agent-operations/hosted-services.d.ts +13 -0
  77. package/dist/agent-operations/hosted-services.d.ts.map +1 -0
  78. package/dist/agent-operations/hosted-services.js +22 -0
  79. package/dist/agent-operations/index.d.ts +277 -0
  80. package/dist/agent-operations/index.d.ts.map +1 -0
  81. package/dist/agent-operations/index.js +80 -0
  82. package/dist/agent-operations/layout-clearance.d.ts +108 -0
  83. package/dist/agent-operations/layout-clearance.d.ts.map +1 -0
  84. package/dist/agent-operations/layout-clearance.js +190 -0
  85. package/dist/agent-operations/level-reads.d.ts +33 -0
  86. package/dist/agent-operations/level-reads.d.ts.map +1 -0
  87. package/dist/agent-operations/level-reads.js +161 -0
  88. package/dist/agent-operations/level-target.d.ts +11 -0
  89. package/dist/agent-operations/level-target.d.ts.map +1 -0
  90. package/dist/agent-operations/level-target.js +29 -0
  91. package/dist/agent-operations/list-levels.d.ts +4 -0
  92. package/dist/agent-operations/list-levels.d.ts.map +1 -0
  93. package/dist/agent-operations/list-levels.js +31 -0
  94. package/dist/agent-operations/material-preset.d.ts +11 -0
  95. package/dist/agent-operations/material-preset.d.ts.map +1 -0
  96. package/dist/agent-operations/material-preset.js +74 -0
  97. package/dist/agent-operations/material-refs.d.ts +24 -0
  98. package/dist/agent-operations/material-refs.d.ts.map +1 -0
  99. package/dist/agent-operations/material-refs.js +100 -0
  100. package/dist/agent-operations/node-patch.d.ts +3 -0
  101. package/dist/agent-operations/node-patch.d.ts.map +1 -0
  102. package/dist/agent-operations/node-patch.js +114 -0
  103. package/dist/agent-operations/paint.d.ts +21 -0
  104. package/dist/agent-operations/paint.d.ts.map +1 -0
  105. package/dist/agent-operations/paint.js +219 -0
  106. package/dist/agent-operations/place-items.d.ts +20 -0
  107. package/dist/agent-operations/place-items.d.ts.map +1 -0
  108. package/dist/agent-operations/place-items.js +226 -0
  109. package/dist/agent-operations/plan-geometry.d.ts +24 -0
  110. package/dist/agent-operations/plan-geometry.d.ts.map +1 -0
  111. package/dist/agent-operations/plan-geometry.js +94 -0
  112. package/dist/agent-operations/room-structure.d.ts +87 -0
  113. package/dist/agent-operations/room-structure.d.ts.map +1 -0
  114. package/dist/agent-operations/room-structure.js +144 -0
  115. package/dist/agent-operations/scene-materials.d.ts +15 -0
  116. package/dist/agent-operations/scene-materials.d.ts.map +1 -0
  117. package/dist/agent-operations/scene-materials.js +62 -0
  118. package/dist/agent-operations/scene-measure.d.ts +73 -0
  119. package/dist/agent-operations/scene-measure.d.ts.map +1 -0
  120. package/dist/agent-operations/scene-measure.js +73 -0
  121. package/dist/agent-operations/scene-queries.d.ts +4510 -0
  122. package/dist/agent-operations/scene-queries.d.ts.map +1 -0
  123. package/dist/agent-operations/scene-queries.js +84 -0
  124. package/dist/agent-operations/scene-view.d.ts +98 -0
  125. package/dist/agent-operations/scene-view.d.ts.map +1 -0
  126. package/dist/agent-operations/scene-view.js +559 -0
  127. package/dist/agent-operations/search-assets.d.ts +14 -0
  128. package/dist/agent-operations/search-assets.d.ts.map +1 -0
  129. package/dist/agent-operations/search-assets.js +42 -0
  130. package/dist/agent-operations/search-materials.d.ts +12 -0
  131. package/dist/agent-operations/search-materials.d.ts.map +1 -0
  132. package/dist/agent-operations/search-materials.js +111 -0
  133. package/dist/agent-operations/stairs.d.ts +5 -0
  134. package/dist/agent-operations/stairs.d.ts.map +1 -0
  135. package/dist/agent-operations/stairs.js +70 -0
  136. package/dist/agent-operations/types.d.ts +59 -0
  137. package/dist/agent-operations/types.d.ts.map +1 -0
  138. package/dist/agent-operations/types.js +1 -0
  139. package/dist/agent-operations/verify-scene.d.ts +50 -0
  140. package/dist/agent-operations/verify-scene.d.ts.map +1 -0
  141. package/dist/agent-operations/verify-scene.js +369 -0
  142. package/dist/agent-operations/wall-opening.d.ts +65 -0
  143. package/dist/agent-operations/wall-opening.d.ts.map +1 -0
  144. package/dist/agent-operations/wall-opening.js +55 -0
  145. package/dist/agent-tools/achieved.d.ts +9 -0
  146. package/dist/agent-tools/achieved.d.ts.map +1 -0
  147. package/dist/agent-tools/achieved.js +8 -0
  148. package/dist/agent-tools/add-object.d.ts +43 -0
  149. package/dist/agent-tools/add-object.d.ts.map +1 -0
  150. package/dist/agent-tools/add-object.js +86 -0
  151. package/dist/agent-tools/assets.d.ts +13 -0
  152. package/dist/agent-tools/assets.d.ts.map +1 -0
  153. package/dist/agent-tools/assets.js +18 -0
  154. package/dist/agent-tools/clear-scene.d.ts +10 -0
  155. package/dist/agent-tools/clear-scene.d.ts.map +1 -0
  156. package/dist/agent-tools/clear-scene.js +9 -0
  157. package/dist/agent-tools/collections.d.ts +35 -0
  158. package/dist/agent-tools/collections.d.ts.map +1 -0
  159. package/dist/agent-tools/collections.js +31 -0
  160. package/dist/agent-tools/columns.d.ts +44 -0
  161. package/dist/agent-tools/columns.d.ts.map +1 -0
  162. package/dist/agent-tools/columns.js +59 -0
  163. package/dist/agent-tools/contract.d.ts +68 -0
  164. package/dist/agent-tools/contract.d.ts.map +1 -0
  165. package/dist/agent-tools/contract.js +1 -0
  166. package/dist/agent-tools/create-room.d.ts +63 -0
  167. package/dist/agent-tools/create-room.d.ts.map +1 -0
  168. package/dist/agent-tools/create-room.js +90 -0
  169. package/dist/agent-tools/find-by-type.d.ts +11 -0
  170. package/dist/agent-tools/find-by-type.d.ts.map +1 -0
  171. package/dist/agent-tools/find-by-type.js +14 -0
  172. package/dist/agent-tools/furnish-room.d.ts +26 -0
  173. package/dist/agent-tools/furnish-room.d.ts.map +1 -0
  174. package/dist/agent-tools/furnish-room.js +35 -0
  175. package/dist/agent-tools/hosted-services.d.ts +402 -0
  176. package/dist/agent-tools/hosted-services.d.ts.map +1 -0
  177. package/dist/agent-tools/hosted-services.js +148 -0
  178. package/dist/agent-tools/index.d.ts +864 -0
  179. package/dist/agent-tools/index.d.ts.map +1 -0
  180. package/dist/agent-tools/index.js +82 -0
  181. package/dist/agent-tools/levels.d.ts +72 -0
  182. package/dist/agent-tools/levels.d.ts.map +1 -0
  183. package/dist/agent-tools/levels.js +76 -0
  184. package/dist/agent-tools/measurement.d.ts +37 -0
  185. package/dist/agent-tools/measurement.d.ts.map +1 -0
  186. package/dist/agent-tools/measurement.js +94 -0
  187. package/dist/agent-tools/node-id.d.ts +3 -0
  188. package/dist/agent-tools/node-id.d.ts.map +1 -0
  189. package/dist/agent-tools/node-id.js +2 -0
  190. package/dist/agent-tools/nodes.d.ts +17 -0
  191. package/dist/agent-tools/nodes.d.ts.map +1 -0
  192. package/dist/agent-tools/nodes.js +13 -0
  193. package/dist/agent-tools/paint.d.ts +46 -0
  194. package/dist/agent-tools/paint.d.ts.map +1 -0
  195. package/dist/agent-tools/paint.js +29 -0
  196. package/dist/agent-tools/place-items.d.ts +19 -0
  197. package/dist/agent-tools/place-items.d.ts.map +1 -0
  198. package/dist/agent-tools/place-items.js +29 -0
  199. package/dist/agent-tools/refusal.d.ts +20 -0
  200. package/dist/agent-tools/refusal.d.ts.map +1 -0
  201. package/dist/agent-tools/refusal.js +29 -0
  202. package/dist/agent-tools/room-structure.d.ts +438 -0
  203. package/dist/agent-tools/room-structure.d.ts.map +1 -0
  204. package/dist/agent-tools/room-structure.js +207 -0
  205. package/dist/agent-tools/search-materials.d.ts +20 -0
  206. package/dist/agent-tools/search-materials.d.ts.map +1 -0
  207. package/dist/agent-tools/search-materials.js +32 -0
  208. package/dist/agent-tools/stairs.d.ts +86 -0
  209. package/dist/agent-tools/stairs.d.ts.map +1 -0
  210. package/dist/agent-tools/stairs.js +103 -0
  211. package/dist/agent-tools/verify-scene.d.ts +13 -0
  212. package/dist/agent-tools/verify-scene.d.ts.map +1 -0
  213. package/dist/agent-tools/verify-scene.js +21 -0
  214. package/dist/agent-tools/view-scene.d.ts +43 -0
  215. package/dist/agent-tools/view-scene.d.ts.map +1 -0
  216. package/dist/agent-tools/view-scene.js +80 -0
  217. package/dist/agent-tools/wall-openings.d.ts +163 -0
  218. package/dist/agent-tools/wall-openings.d.ts.map +1 -0
  219. package/dist/agent-tools/wall-openings.js +144 -0
  220. package/dist/agent-tools/walls.d.ts +21 -0
  221. package/dist/agent-tools/walls.d.ts.map +1 -0
  222. package/dist/agent-tools/walls.js +30 -0
  223. package/dist/agent-tools/write-target.d.ts +12 -0
  224. package/dist/agent-tools/write-target.d.ts.map +1 -0
  225. package/dist/agent-tools/write-target.js +10 -0
  226. package/dist/building/__fixtures__/wall-opening-cases.d.ts +736 -0
  227. package/dist/building/__fixtures__/wall-opening-cases.d.ts.map +1 -0
  228. package/dist/building/__fixtures__/wall-opening-cases.js +307 -0
  229. package/dist/building/door-types.d.ts +22 -0
  230. package/dist/building/door-types.d.ts.map +1 -0
  231. package/dist/building/door-types.js +167 -0
  232. package/dist/building/floor-item-fit.d.ts +38 -0
  233. package/dist/building/floor-item-fit.d.ts.map +1 -0
  234. package/dist/building/floor-item-fit.js +47 -0
  235. package/dist/building/index.d.ts +7 -0
  236. package/dist/building/index.d.ts.map +1 -0
  237. package/dist/building/index.js +6 -0
  238. package/dist/building/level-duplication.d.ts +8983 -0
  239. package/dist/building/level-duplication.d.ts.map +1 -0
  240. package/dist/building/level-duplication.js +314 -0
  241. package/dist/building/opening-style-presets.d.ts +46 -0
  242. package/dist/building/opening-style-presets.d.ts.map +1 -0
  243. package/dist/building/opening-style-presets.js +195 -0
  244. package/dist/building/wall-openings.d.ts +445 -0
  245. package/dist/building/wall-openings.d.ts.map +1 -0
  246. package/dist/building/wall-openings.js +231 -0
  247. package/dist/building/window-types.d.ts +17 -0
  248. package/dist/building/window-types.d.ts.map +1 -0
  249. package/dist/building/window-types.js +31 -0
  250. package/dist/commands/structure/apply-zone-transform.d.ts +23 -0
  251. package/dist/commands/structure/apply-zone-transform.d.ts.map +1 -0
  252. package/dist/commands/structure/apply-zone-transform.js +55 -0
  253. package/dist/commands/structure/create-mezzanine.d.ts +12 -0
  254. package/dist/commands/structure/create-mezzanine.d.ts.map +1 -0
  255. package/dist/commands/structure/create-mezzanine.js +46 -0
  256. package/dist/commands/structure/create-zone.d.ts +32 -0
  257. package/dist/commands/structure/create-zone.d.ts.map +1 -0
  258. package/dist/commands/structure/create-zone.js +126 -0
  259. package/dist/commands/structure/delete-zone.d.ts +51 -0
  260. package/dist/commands/structure/delete-zone.d.ts.map +1 -0
  261. package/dist/commands/structure/delete-zone.js +354 -0
  262. package/dist/commands/structure/divide-zone.d.ts +38 -0
  263. package/dist/commands/structure/divide-zone.d.ts.map +1 -0
  264. package/dist/commands/structure/divide-zone.js +186 -0
  265. package/dist/commands/structure/duplicate-zone.d.ts +7 -0
  266. package/dist/commands/structure/duplicate-zone.d.ts.map +1 -0
  267. package/dist/commands/structure/duplicate-zone.js +21 -0
  268. package/dist/commands/structure/floor-opening.d.ts +36 -0
  269. package/dist/commands/structure/floor-opening.d.ts.map +1 -0
  270. package/dist/commands/structure/floor-opening.js +124 -0
  271. package/dist/commands/structure/index.d.ts +22 -0
  272. package/dist/commands/structure/index.d.ts.map +1 -0
  273. package/dist/commands/structure/index.js +20 -0
  274. package/dist/commands/structure/lock-outside-faces.d.ts +12 -0
  275. package/dist/commands/structure/lock-outside-faces.d.ts.map +1 -0
  276. package/dist/commands/structure/lock-outside-faces.js +32 -0
  277. package/dist/commands/structure/merge-zones.d.ts +5 -0
  278. package/dist/commands/structure/merge-zones.d.ts.map +1 -0
  279. package/dist/commands/structure/merge-zones.js +22 -0
  280. package/dist/commands/structure/mezzanine-content.d.ts +16 -0
  281. package/dist/commands/structure/mezzanine-content.d.ts.map +1 -0
  282. package/dist/commands/structure/mezzanine-content.js +109 -0
  283. package/dist/commands/structure/plan-mezzanine-stair.d.ts +7 -0
  284. package/dist/commands/structure/plan-mezzanine-stair.d.ts.map +1 -0
  285. package/dist/commands/structure/plan-mezzanine-stair.js +127 -0
  286. package/dist/commands/structure/plan-wall-deletion.d.ts +9 -0
  287. package/dist/commands/structure/plan-wall-deletion.d.ts.map +1 -0
  288. package/dist/commands/structure/plan-wall-deletion.js +151 -0
  289. package/dist/commands/structure/rebase-floor-reference.d.ts +7 -0
  290. package/dist/commands/structure/rebase-floor-reference.d.ts.map +1 -0
  291. package/dist/commands/structure/rebase-floor-reference.js +90 -0
  292. package/dist/commands/structure/resize-mezzanine.d.ts +8 -0
  293. package/dist/commands/structure/resize-mezzanine.d.ts.map +1 -0
  294. package/dist/commands/structure/resize-mezzanine.js +43 -0
  295. package/dist/commands/structure/rotate-zone.d.ts +8 -0
  296. package/dist/commands/structure/rotate-zone.d.ts.map +1 -0
  297. package/dist/commands/structure/rotate-zone.js +28 -0
  298. package/dist/commands/structure/set-floor-foundation.d.ts +62 -0
  299. package/dist/commands/structure/set-floor-foundation.d.ts.map +1 -0
  300. package/dist/commands/structure/set-floor-foundation.js +162 -0
  301. package/dist/commands/structure/set-room-floor-construction.d.ts +8 -0
  302. package/dist/commands/structure/set-room-floor-construction.d.ts.map +1 -0
  303. package/dist/commands/structure/set-room-floor-construction.js +72 -0
  304. package/dist/commands/structure/set-wall-geometry.d.ts +10 -0
  305. package/dist/commands/structure/set-wall-geometry.d.ts.map +1 -0
  306. package/dist/commands/structure/set-wall-geometry.js +52 -0
  307. package/dist/commands/structure/set-zone-edges.d.ts +14 -0
  308. package/dist/commands/structure/set-zone-edges.d.ts.map +1 -0
  309. package/dist/commands/structure/set-zone-edges.js +143 -0
  310. package/dist/commands/structure/set-zone-intent.d.ts +39 -0
  311. package/dist/commands/structure/set-zone-intent.d.ts.map +1 -0
  312. package/dist/commands/structure/set-zone-intent.js +125 -0
  313. package/dist/commands/structure/shared.d.ts +4512 -0
  314. package/dist/commands/structure/shared.d.ts.map +1 -0
  315. package/dist/commands/structure/shared.js +102 -0
  316. package/dist/commands/structure/transform-zone.d.ts +23 -0
  317. package/dist/commands/structure/transform-zone.d.ts.map +1 -0
  318. package/dist/commands/structure/transform-zone.js +472 -0
  319. package/dist/commands/structure/validate-mezzanine.d.ts +5 -0
  320. package/dist/commands/structure/validate-mezzanine.d.ts.map +1 -0
  321. package/dist/commands/structure/validate-mezzanine.js +46 -0
  322. package/dist/commands/structure/zone-crossings.d.ts +8 -0
  323. package/dist/commands/structure/zone-crossings.d.ts.map +1 -0
  324. package/dist/commands/structure/zone-crossings.js +162 -0
  325. package/dist/commands/structure/zone-drop.d.ts +4 -0
  326. package/dist/commands/structure/zone-drop.d.ts.map +1 -0
  327. package/dist/commands/structure/zone-drop.js +68 -0
  328. package/dist/commands/structure/zone-insertion.d.ts +4 -0
  329. package/dist/commands/structure/zone-insertion.d.ts.map +1 -0
  330. package/dist/commands/structure/zone-insertion.js +200 -0
  331. package/dist/commands/structure/zone-transform-content.d.ts +6 -0
  332. package/dist/commands/structure/zone-transform-content.d.ts.map +1 -0
  333. package/dist/commands/structure/zone-transform-content.js +117 -0
  334. package/dist/commands/structure/zone-wall-merge.d.ts +4977 -0
  335. package/dist/commands/structure/zone-wall-merge.d.ts.map +1 -0
  336. package/dist/commands/structure/zone-wall-merge.js +135 -0
  337. package/dist/contracts/reference-discovery.d.ts +18 -0
  338. package/dist/contracts/reference-discovery.d.ts.map +1 -0
  339. package/dist/contracts/reference-discovery.js +100 -0
  340. package/dist/contracts/reference-inventory.d.ts +44 -0
  341. package/dist/contracts/reference-inventory.d.ts.map +1 -0
  342. package/dist/contracts/reference-inventory.js +872 -0
  343. package/dist/events/bus.d.ts +70 -9
  344. package/dist/events/bus.d.ts.map +1 -1
  345. package/dist/hooks/scene-registry/item-clip-registry.d.ts +6 -3
  346. package/dist/hooks/scene-registry/item-clip-registry.d.ts.map +1 -1
  347. package/dist/hooks/scene-registry/item-clip-registry.js +2 -1
  348. package/dist/hooks/spatial-grid/floor-placed-elevation.d.ts.map +1 -1
  349. package/dist/hooks/spatial-grid/floor-placed-elevation.js +15 -1
  350. package/dist/hooks/spatial-grid/spatial-grid-manager.d.ts +3 -2
  351. package/dist/hooks/spatial-grid/spatial-grid-manager.d.ts.map +1 -1
  352. package/dist/hooks/spatial-grid/spatial-grid-manager.js +53 -66
  353. package/dist/hooks/spatial-grid/spatial-grid-sync.d.ts +1612 -127
  354. package/dist/hooks/spatial-grid/spatial-grid-sync.d.ts.map +1 -1
  355. package/dist/hooks/spatial-grid/spatial-grid-sync.js +86 -83
  356. package/dist/hooks/spatial-grid/support-host-patch.d.ts +1 -0
  357. package/dist/hooks/spatial-grid/support-host-patch.d.ts.map +1 -1
  358. package/dist/hooks/spatial-grid/support-host-patch.js +12 -5
  359. package/dist/index.d.ts +80 -13
  360. package/dist/index.d.ts.map +1 -1
  361. package/dist/index.js +75 -11
  362. package/dist/lib/__bench__/near-linear-walls.d.ts +2 -0
  363. package/dist/lib/__bench__/near-linear-walls.d.ts.map +1 -0
  364. package/dist/lib/__bench__/near-linear-walls.js +24 -0
  365. package/dist/lib/__bench__/structure-preview.bench.d.ts +2 -0
  366. package/dist/lib/__bench__/structure-preview.bench.d.ts.map +1 -0
  367. package/dist/lib/__bench__/structure-preview.bench.js +72 -0
  368. package/dist/lib/__fixtures__/mezzanine.d.ts +13968 -0
  369. package/dist/lib/__fixtures__/mezzanine.d.ts.map +1 -0
  370. package/dist/lib/__fixtures__/mezzanine.js +43 -0
  371. package/dist/lib/absorb-wall-separators.d.ts +4483 -0
  372. package/dist/lib/absorb-wall-separators.d.ts.map +1 -0
  373. package/dist/lib/absorb-wall-separators.js +65 -0
  374. package/dist/lib/angle-accumulator.d.ts +3 -0
  375. package/dist/lib/angle-accumulator.d.ts.map +1 -0
  376. package/dist/lib/angle-accumulator.js +13 -0
  377. package/dist/lib/artifact-store.d.ts +31 -0
  378. package/dist/lib/artifact-store.d.ts.map +1 -0
  379. package/dist/lib/artifact-store.js +42 -0
  380. package/dist/lib/assembly-stack.d.ts +54 -0
  381. package/dist/lib/assembly-stack.d.ts.map +1 -0
  382. package/dist/lib/assembly-stack.js +52 -0
  383. package/dist/lib/asset-storage.d.ts.map +1 -1
  384. package/dist/lib/asset-storage.js +3 -0
  385. package/dist/lib/canonical-opening-ring.d.ts +3 -0
  386. package/dist/lib/canonical-opening-ring.d.ts.map +1 -0
  387. package/dist/lib/canonical-opening-ring.js +14 -0
  388. package/dist/lib/ceiling-children.d.ts +8 -0
  389. package/dist/lib/ceiling-children.d.ts.map +1 -0
  390. package/dist/lib/ceiling-children.js +36 -0
  391. package/dist/lib/ceiling-surface.d.ts +40 -0
  392. package/dist/lib/ceiling-surface.d.ts.map +1 -0
  393. package/dist/lib/ceiling-surface.js +65 -0
  394. package/dist/lib/cutter-host.d.ts +5 -0
  395. package/dist/lib/cutter-host.d.ts.map +1 -0
  396. package/dist/lib/cutter-host.js +30 -0
  397. package/dist/lib/floor-construction-lift.d.ts +4 -0
  398. package/dist/lib/floor-construction-lift.d.ts.map +1 -0
  399. package/dist/lib/floor-construction-lift.js +54 -0
  400. package/dist/lib/floor-footprint-key.d.ts +3 -0
  401. package/dist/lib/floor-footprint-key.d.ts.map +1 -0
  402. package/dist/lib/floor-footprint-key.js +9 -0
  403. package/dist/lib/floor-footprint-name.d.ts +11 -0
  404. package/dist/lib/floor-footprint-name.d.ts.map +1 -0
  405. package/dist/lib/floor-footprint-name.js +52 -0
  406. package/dist/lib/floor-foundation-datum.d.ts +31 -0
  407. package/dist/lib/floor-foundation-datum.d.ts.map +1 -0
  408. package/dist/lib/floor-foundation-datum.js +226 -0
  409. package/dist/lib/floor-foundation-stack.d.ts +16 -0
  410. package/dist/lib/floor-foundation-stack.d.ts.map +1 -0
  411. package/dist/lib/floor-foundation-stack.js +214 -0
  412. package/dist/lib/floor-intent-changes.d.ts +10 -0
  413. package/dist/lib/floor-intent-changes.d.ts.map +1 -0
  414. package/dist/lib/floor-intent-changes.js +461 -0
  415. package/dist/lib/floor-opening-footprints.d.ts +24 -0
  416. package/dist/lib/floor-opening-footprints.d.ts.map +1 -0
  417. package/dist/lib/floor-opening-footprints.js +127 -0
  418. package/dist/lib/floor-opening-intent.d.ts +16 -0
  419. package/dist/lib/floor-opening-intent.d.ts.map +1 -0
  420. package/dist/lib/floor-opening-intent.js +82 -0
  421. package/dist/lib/floor-plate-id.d.ts +5 -0
  422. package/dist/lib/floor-plate-id.d.ts.map +1 -0
  423. package/dist/lib/floor-plate-id.js +20 -0
  424. package/dist/lib/floor-plate-paint.d.ts +8 -0
  425. package/dist/lib/floor-plate-paint.d.ts.map +1 -0
  426. package/dist/lib/floor-plate-paint.js +11 -0
  427. package/dist/lib/floor-plates.d.ts +211 -0
  428. package/dist/lib/floor-plates.d.ts.map +1 -0
  429. package/dist/lib/floor-plates.js +729 -0
  430. package/dist/lib/floor-room-faces.d.ts +5 -0
  431. package/dist/lib/floor-room-faces.d.ts.map +1 -0
  432. package/dist/lib/floor-room-faces.js +29 -0
  433. package/dist/lib/floor-step-finish.d.ts +49 -0
  434. package/dist/lib/floor-step-finish.d.ts.map +1 -0
  435. package/dist/lib/floor-step-finish.js +128 -0
  436. package/dist/lib/geometry-script-node.d.ts +82 -0
  437. package/dist/lib/geometry-script-node.d.ts.map +1 -0
  438. package/dist/lib/geometry-script-node.js +147 -0
  439. package/dist/lib/geometry-surfaces.d.ts +61 -0
  440. package/dist/lib/geometry-surfaces.d.ts.map +1 -0
  441. package/dist/lib/geometry-surfaces.js +156 -0
  442. package/dist/lib/item-slab-support.d.ts +14 -0
  443. package/dist/lib/item-slab-support.d.ts.map +1 -0
  444. package/dist/lib/item-slab-support.js +40 -0
  445. package/dist/lib/level-footprints.d.ts +23 -0
  446. package/dist/lib/level-footprints.d.ts.map +1 -0
  447. package/dist/lib/level-footprints.js +398 -0
  448. package/dist/lib/level-name.d.ts +7 -0
  449. package/dist/lib/level-name.d.ts.map +1 -1
  450. package/dist/lib/level-name.js +11 -3
  451. package/dist/lib/new-zone.d.ts +10 -0
  452. package/dist/lib/new-zone.d.ts.map +1 -0
  453. package/dist/lib/new-zone.js +10 -0
  454. package/dist/lib/node-ancestry.d.ts +30 -0
  455. package/dist/lib/node-ancestry.d.ts.map +1 -0
  456. package/dist/lib/node-ancestry.js +76 -0
  457. package/dist/lib/object-cuts.d.ts +11 -0
  458. package/dist/lib/object-cuts.d.ts.map +1 -0
  459. package/dist/lib/object-cuts.js +63 -0
  460. package/dist/lib/opening-floor-datum.d.ts +24 -0
  461. package/dist/lib/opening-floor-datum.d.ts.map +1 -0
  462. package/dist/lib/opening-floor-datum.js +145 -0
  463. package/dist/lib/own-floor-intent.d.ts +15 -0
  464. package/dist/lib/own-floor-intent.d.ts.map +1 -0
  465. package/dist/lib/own-floor-intent.js +201 -0
  466. package/dist/lib/plate-reference.d.ts +3 -0
  467. package/dist/lib/plate-reference.d.ts.map +1 -0
  468. package/dist/lib/plate-reference.js +91 -0
  469. package/dist/lib/plate-surface.d.ts +120 -0
  470. package/dist/lib/plate-surface.d.ts.map +1 -0
  471. package/dist/lib/plate-surface.js +725 -0
  472. package/dist/lib/polygon-boolean.d.ts +17 -0
  473. package/dist/lib/polygon-boolean.d.ts.map +1 -0
  474. package/dist/lib/polygon-boolean.js +195 -0
  475. package/dist/lib/polygon-label.d.ts +7 -0
  476. package/dist/lib/polygon-label.d.ts.map +1 -0
  477. package/dist/lib/polygon-label.js +94 -0
  478. package/dist/lib/room-drawn-floor.d.ts +29 -0
  479. package/dist/lib/room-drawn-floor.d.ts.map +1 -0
  480. package/dist/lib/room-drawn-floor.js +88 -0
  481. package/dist/lib/room-floor-choices.d.ts +11 -0
  482. package/dist/lib/room-floor-choices.d.ts.map +1 -0
  483. package/dist/lib/room-floor-choices.js +60 -0
  484. package/dist/lib/room-floor-feasibility.d.ts +25 -0
  485. package/dist/lib/room-floor-feasibility.d.ts.map +1 -0
  486. package/dist/lib/room-floor-feasibility.js +293 -0
  487. package/dist/lib/room-floor-plate.d.ts +3 -0
  488. package/dist/lib/room-floor-plate.d.ts.map +1 -0
  489. package/dist/lib/room-floor-plate.js +4 -0
  490. package/dist/lib/room-graph.d.ts +79 -0
  491. package/dist/lib/room-graph.d.ts.map +1 -0
  492. package/dist/lib/room-graph.js +1265 -0
  493. package/dist/lib/room-name.d.ts +10 -0
  494. package/dist/lib/room-name.d.ts.map +1 -0
  495. package/dist/lib/room-name.js +22 -0
  496. package/dist/lib/room-topology-index.d.ts +53 -5
  497. package/dist/lib/room-topology-index.d.ts.map +1 -1
  498. package/dist/lib/room-topology-index.js +176 -30
  499. package/dist/lib/room-vertical-placement.d.ts +12 -0
  500. package/dist/lib/room-vertical-placement.d.ts.map +1 -0
  501. package/dist/lib/room-vertical-placement.js +28 -0
  502. package/dist/lib/room-zone-adoption.d.ts +74 -0
  503. package/dist/lib/room-zone-adoption.d.ts.map +1 -0
  504. package/dist/lib/room-zone-adoption.js +150 -0
  505. package/dist/lib/setback-envelope.d.ts +73 -0
  506. package/dist/lib/setback-envelope.d.ts.map +1 -0
  507. package/dist/lib/setback-envelope.js +506 -0
  508. package/dist/lib/slab-polygon.d.ts.map +1 -1
  509. package/dist/lib/slab-polygon.js +33 -12
  510. package/dist/lib/slots.d.ts +20 -0
  511. package/dist/lib/slots.d.ts.map +1 -1
  512. package/dist/lib/slots.js +44 -0
  513. package/dist/lib/space-detection.d.ts +14 -94
  514. package/dist/lib/space-detection.d.ts.map +1 -1
  515. package/dist/lib/space-detection.js +244 -1616
  516. package/dist/lib/structure-commit.d.ts +38 -0
  517. package/dist/lib/structure-commit.d.ts.map +1 -0
  518. package/dist/lib/structure-commit.js +52 -0
  519. package/dist/lib/structure-kernel.d.ts +66 -0
  520. package/dist/lib/structure-kernel.d.ts.map +1 -0
  521. package/dist/lib/structure-kernel.js +735 -0
  522. package/dist/lib/structure-reconcile.d.ts +15 -0
  523. package/dist/lib/structure-reconcile.d.ts.map +1 -0
  524. package/dist/lib/structure-reconcile.js +218 -0
  525. package/dist/lib/terrain-contours.d.ts +29 -0
  526. package/dist/lib/terrain-contours.d.ts.map +1 -0
  527. package/dist/lib/terrain-contours.js +199 -0
  528. package/dist/lib/terrain-source-persisted.d.ts +42 -0
  529. package/dist/lib/terrain-source-persisted.d.ts.map +1 -0
  530. package/dist/lib/terrain-source-persisted.js +68 -0
  531. package/dist/lib/terrain-source.d.ts +2 -40
  532. package/dist/lib/terrain-source.d.ts.map +1 -1
  533. package/dist/lib/terrain-source.js +2 -68
  534. package/dist/lib/terrain-support-query.d.ts +83 -0
  535. package/dist/lib/terrain-support-query.d.ts.map +1 -0
  536. package/dist/lib/terrain-support-query.js +187 -0
  537. package/dist/lib/terrain-support.d.ts +1 -77
  538. package/dist/lib/terrain-support.d.ts.map +1 -1
  539. package/dist/lib/terrain-support.js +3 -181
  540. package/dist/lib/unit-containment.js +2 -2
  541. package/dist/lib/unit-report.d.ts.map +1 -1
  542. package/dist/lib/unit-report.js +5 -4
  543. package/dist/lib/zone-colors.d.ts +11 -0
  544. package/dist/lib/zone-colors.d.ts.map +1 -0
  545. package/dist/lib/zone-colors.js +32 -0
  546. package/dist/lib/zone-quantities.d.ts.map +1 -1
  547. package/dist/lib/zone-quantities.js +113 -223
  548. package/dist/material-library.d.ts +9 -1
  549. package/dist/material-library.d.ts.map +1 -1
  550. package/dist/material-library.js +550 -1
  551. package/dist/node-slots/block.d.ts +7 -0
  552. package/dist/node-slots/block.d.ts.map +1 -0
  553. package/dist/node-slots/block.js +27 -0
  554. package/dist/node-slots/cabinet.d.ts +4 -0
  555. package/dist/node-slots/cabinet.d.ts.map +1 -0
  556. package/dist/node-slots/cabinet.js +24 -0
  557. package/dist/node-slots/ceiling.d.ts +6 -0
  558. package/dist/node-slots/ceiling.d.ts.map +1 -0
  559. package/dist/node-slots/ceiling.js +7 -0
  560. package/dist/node-slots/column.d.ts +9 -0
  561. package/dist/node-slots/column.d.ts.map +1 -0
  562. package/dist/node-slots/column.js +24 -0
  563. package/dist/node-slots/door.d.ts +9 -0
  564. package/dist/node-slots/door.d.ts.map +1 -0
  565. package/dist/node-slots/door.js +20 -0
  566. package/dist/node-slots/duct.d.ts +5 -0
  567. package/dist/node-slots/duct.d.ts.map +1 -0
  568. package/dist/node-slots/duct.js +5 -0
  569. package/dist/node-slots/elevator.d.ts +9 -0
  570. package/dist/node-slots/elevator.d.ts.map +1 -0
  571. package/dist/node-slots/elevator.js +17 -0
  572. package/dist/node-slots/fence.d.ts +10 -0
  573. package/dist/node-slots/fence.d.ts.map +1 -0
  574. package/dist/node-slots/fence.js +23 -0
  575. package/dist/node-slots/index.d.ts +25 -0
  576. package/dist/node-slots/index.d.ts.map +1 -0
  577. package/dist/node-slots/index.js +92 -0
  578. package/dist/node-slots/lean-to-extension.d.ts +5 -0
  579. package/dist/node-slots/lean-to-extension.d.ts.map +1 -0
  580. package/dist/node-slots/lean-to-extension.js +15 -0
  581. package/dist/node-slots/procedural-item.d.ts +4 -0
  582. package/dist/node-slots/procedural-item.d.ts.map +1 -0
  583. package/dist/node-slots/procedural-item.js +3 -0
  584. package/dist/node-slots/roof-accessories.d.ts +9 -0
  585. package/dist/node-slots/roof-accessories.d.ts.map +1 -0
  586. package/dist/node-slots/roof-accessories.js +34 -0
  587. package/dist/node-slots/shelf.d.ts +9 -0
  588. package/dist/node-slots/shelf.d.ts.map +1 -0
  589. package/dist/node-slots/shelf.js +30 -0
  590. package/dist/node-slots/slab.d.ts +7 -0
  591. package/dist/node-slots/slab.d.ts.map +1 -0
  592. package/dist/node-slots/slab.js +21 -0
  593. package/dist/node-slots/stair.d.ts +8 -0
  594. package/dist/node-slots/stair.d.ts.map +1 -0
  595. package/dist/node-slots/stair.js +17 -0
  596. package/dist/node-slots/wall.d.ts +12 -0
  597. package/dist/node-slots/wall.d.ts.map +1 -0
  598. package/dist/node-slots/wall.js +55 -0
  599. package/dist/node-slots/window.d.ts +5 -0
  600. package/dist/node-slots/window.d.ts.map +1 -0
  601. package/dist/node-slots/window.js +11 -0
  602. package/dist/procedural-items/design-placement.d.ts +49 -0
  603. package/dist/procedural-items/design-placement.d.ts.map +1 -0
  604. package/dist/procedural-items/design-placement.js +129 -0
  605. package/dist/procedural-items/design.d.ts +261 -0
  606. package/dist/procedural-items/design.d.ts.map +1 -0
  607. package/dist/procedural-items/design.js +707 -0
  608. package/dist/procedural-items/fixtures.d.ts +464 -24
  609. package/dist/procedural-items/fixtures.d.ts.map +1 -1
  610. package/dist/procedural-items/index.d.ts +5 -0
  611. package/dist/procedural-items/index.d.ts.map +1 -1
  612. package/dist/procedural-items/index.js +5 -0
  613. package/dist/procedural-items/integration.d.ts +127 -6
  614. package/dist/procedural-items/integration.d.ts.map +1 -1
  615. package/dist/procedural-items/joints.d.ts +56 -0
  616. package/dist/procedural-items/joints.d.ts.map +1 -0
  617. package/dist/procedural-items/joints.js +251 -0
  618. package/dist/procedural-items/library-colors.d.ts +12 -0
  619. package/dist/procedural-items/library-colors.d.ts.map +1 -1
  620. package/dist/procedural-items/library-colors.js +37 -3
  621. package/dist/procedural-items/motion-controller.d.ts +29 -0
  622. package/dist/procedural-items/motion-controller.d.ts.map +1 -0
  623. package/dist/procedural-items/motion-controller.js +130 -0
  624. package/dist/procedural-items/node.d.ts +490 -24
  625. package/dist/procedural-items/node.d.ts.map +1 -1
  626. package/dist/procedural-items/query.d.ts +18 -1
  627. package/dist/procedural-items/query.d.ts.map +1 -1
  628. package/dist/procedural-items/query.js +78 -39
  629. package/dist/procedural-items/recipe.d.ts +258 -14
  630. package/dist/procedural-items/recipe.d.ts.map +1 -1
  631. package/dist/procedural-items/recipe.js +933 -61
  632. package/dist/procedural-items/section.d.ts +27 -0
  633. package/dist/procedural-items/section.d.ts.map +1 -0
  634. package/dist/procedural-items/section.js +237 -0
  635. package/dist/procedural-items/spatial.d.ts +21 -0
  636. package/dist/procedural-items/spatial.d.ts.map +1 -1
  637. package/dist/procedural-items/spatial.js +90 -0
  638. package/dist/registry/handles.d.ts +2 -0
  639. package/dist/registry/handles.d.ts.map +1 -1
  640. package/dist/registry/index.d.ts +6 -4
  641. package/dist/registry/index.d.ts.map +1 -1
  642. package/dist/registry/index.js +4 -2
  643. package/dist/registry/mechanism.d.ts +9 -0
  644. package/dist/registry/mechanism.d.ts.map +1 -0
  645. package/dist/registry/mechanism.js +21 -0
  646. package/dist/registry/registry.d.ts +6 -3
  647. package/dist/registry/registry.d.ts.map +1 -1
  648. package/dist/registry/registry.js +59 -22
  649. package/dist/registry/scene-api.d.ts +20 -0
  650. package/dist/registry/scene-api.d.ts.map +1 -1
  651. package/dist/registry/scene-api.js +26 -13
  652. package/dist/registry/subtree.d.ts +8 -0
  653. package/dist/registry/subtree.d.ts.map +1 -1
  654. package/dist/registry/subtree.js +53 -0
  655. package/dist/registry/types.d.ts +340 -11
  656. package/dist/registry/types.d.ts.map +1 -1
  657. package/dist/schema/__fixtures__/node-fixtures.d.ts.map +1 -1
  658. package/dist/schema/__fixtures__/node-fixtures.js +2 -0
  659. package/dist/schema/assembly.d.ts +153 -0
  660. package/dist/schema/assembly.d.ts.map +1 -0
  661. package/dist/schema/assembly.js +155 -0
  662. package/dist/schema/asset-url.d.ts +2 -1
  663. package/dist/schema/asset-url.d.ts.map +1 -1
  664. package/dist/schema/asset-url.js +5 -2
  665. package/dist/schema/base.d.ts +26 -0
  666. package/dist/schema/base.d.ts.map +1 -1
  667. package/dist/schema/base.js +2 -0
  668. package/dist/schema/collection-templates.d.ts +46 -0
  669. package/dist/schema/collection-templates.d.ts.map +1 -0
  670. package/dist/schema/collection-templates.js +14 -0
  671. package/dist/schema/collections.d.ts +7 -0
  672. package/dist/schema/collections.d.ts.map +1 -1
  673. package/dist/schema/cut.d.ts +29 -0
  674. package/dist/schema/cut.d.ts.map +1 -0
  675. package/dist/schema/cut.js +50 -0
  676. package/dist/schema/geometry-metadata.d.ts +51 -0
  677. package/dist/schema/geometry-metadata.d.ts.map +1 -0
  678. package/dist/schema/geometry-metadata.js +57 -0
  679. package/dist/schema/geometry-source.d.ts +250 -0
  680. package/dist/schema/geometry-source.d.ts.map +1 -0
  681. package/dist/schema/geometry-source.js +130 -0
  682. package/dist/schema/index.d.ts +19 -7
  683. package/dist/schema/index.d.ts.map +1 -1
  684. package/dist/schema/index.js +21 -5
  685. package/dist/schema/nodes/block.d.ts +26 -0
  686. package/dist/schema/nodes/block.d.ts.map +1 -1
  687. package/dist/schema/nodes/block.js +1 -1
  688. package/dist/schema/nodes/box-vent.d.ts +26 -0
  689. package/dist/schema/nodes/box-vent.d.ts.map +1 -1
  690. package/dist/schema/nodes/building.d.ts +26 -0
  691. package/dist/schema/nodes/building.d.ts.map +1 -1
  692. package/dist/schema/nodes/cabinet.d.ts +61 -9
  693. package/dist/schema/nodes/cabinet.d.ts.map +1 -1
  694. package/dist/schema/nodes/ceiling.d.ts +37 -0
  695. package/dist/schema/nodes/ceiling.d.ts.map +1 -1
  696. package/dist/schema/nodes/ceiling.js +8 -0
  697. package/dist/schema/nodes/chimney.d.ts +26 -0
  698. package/dist/schema/nodes/chimney.d.ts.map +1 -1
  699. package/dist/schema/nodes/column.d.ts +126 -0
  700. package/dist/schema/nodes/column.d.ts.map +1 -1
  701. package/dist/schema/nodes/column.js +2 -0
  702. package/dist/schema/nodes/construction-dimension.d.ts +26 -0
  703. package/dist/schema/nodes/construction-dimension.d.ts.map +1 -1
  704. package/dist/schema/nodes/cupola.d.ts +26 -0
  705. package/dist/schema/nodes/cupola.d.ts.map +1 -1
  706. package/dist/schema/nodes/curtain-wall.d.ts +5 -5
  707. package/dist/schema/nodes/door.d.ts +139 -20
  708. package/dist/schema/nodes/door.d.ts.map +1 -1
  709. package/dist/schema/nodes/door.js +18 -33
  710. package/dist/schema/nodes/dormer.d.ts +28 -2
  711. package/dist/schema/nodes/dormer.d.ts.map +1 -1
  712. package/dist/schema/nodes/downspout.d.ts +27 -1
  713. package/dist/schema/nodes/downspout.d.ts.map +1 -1
  714. package/dist/schema/nodes/duct-fitting.d.ts +27 -1
  715. package/dist/schema/nodes/duct-fitting.d.ts.map +1 -1
  716. package/dist/schema/nodes/duct-segment.d.ts +27 -1
  717. package/dist/schema/nodes/duct-segment.d.ts.map +1 -1
  718. package/dist/schema/nodes/duct-terminal.d.ts +26 -0
  719. package/dist/schema/nodes/duct-terminal.d.ts.map +1 -1
  720. package/dist/schema/nodes/elevator.d.ts +26 -0
  721. package/dist/schema/nodes/elevator.d.ts.map +1 -1
  722. package/dist/schema/nodes/eyebrow-vent.d.ts +26 -0
  723. package/dist/schema/nodes/eyebrow-vent.d.ts.map +1 -1
  724. package/dist/schema/nodes/fence-feature.d.ts +141 -0
  725. package/dist/schema/nodes/fence-feature.d.ts.map +1 -0
  726. package/dist/schema/nodes/fence-feature.js +21 -0
  727. package/dist/schema/nodes/fence.d.ts +186 -0
  728. package/dist/schema/nodes/fence.d.ts.map +1 -1
  729. package/dist/schema/nodes/fence.js +92 -7
  730. package/dist/schema/nodes/floor-opening.d.ts +61 -0
  731. package/dist/schema/nodes/floor-opening.d.ts.map +1 -0
  732. package/dist/schema/nodes/floor-opening.js +17 -0
  733. package/dist/schema/nodes/guide.d.ts +26 -0
  734. package/dist/schema/nodes/guide.d.ts.map +1 -1
  735. package/dist/schema/nodes/gutter.d.ts +26 -0
  736. package/dist/schema/nodes/gutter.d.ts.map +1 -1
  737. package/dist/schema/nodes/hvac-equipment.d.ts +26 -0
  738. package/dist/schema/nodes/hvac-equipment.d.ts.map +1 -1
  739. package/dist/schema/nodes/imported-mesh.d.ts +26 -0
  740. package/dist/schema/nodes/imported-mesh.d.ts.map +1 -1
  741. package/dist/schema/nodes/item.d.ts +153 -2
  742. package/dist/schema/nodes/item.d.ts.map +1 -1
  743. package/dist/schema/nodes/item.js +13 -0
  744. package/dist/schema/nodes/lean-to-extension.d.ts +26 -0
  745. package/dist/schema/nodes/lean-to-extension.d.ts.map +1 -1
  746. package/dist/schema/nodes/level.d.ts +27 -1
  747. package/dist/schema/nodes/level.d.ts.map +1 -1
  748. package/dist/schema/nodes/lineset.d.ts +26 -0
  749. package/dist/schema/nodes/lineset.d.ts.map +1 -1
  750. package/dist/schema/nodes/liquid-line.d.ts +26 -0
  751. package/dist/schema/nodes/liquid-line.d.ts.map +1 -1
  752. package/dist/schema/nodes/measurement.d.ts +26 -0
  753. package/dist/schema/nodes/measurement.d.ts.map +1 -1
  754. package/dist/schema/nodes/opening-types.d.ts +41 -0
  755. package/dist/schema/nodes/opening-types.d.ts.map +1 -0
  756. package/dist/schema/nodes/opening-types.js +48 -0
  757. package/dist/schema/nodes/pipe-fitting.d.ts +26 -0
  758. package/dist/schema/nodes/pipe-fitting.d.ts.map +1 -1
  759. package/dist/schema/nodes/pipe-segment.d.ts +26 -0
  760. package/dist/schema/nodes/pipe-segment.d.ts.map +1 -1
  761. package/dist/schema/nodes/pipe-trap.d.ts +26 -0
  762. package/dist/schema/nodes/pipe-trap.d.ts.map +1 -1
  763. package/dist/schema/nodes/ridge-vent.d.ts +26 -0
  764. package/dist/schema/nodes/ridge-vent.d.ts.map +1 -1
  765. package/dist/schema/nodes/roof-segment-walls.d.ts.map +1 -1
  766. package/dist/schema/nodes/roof-segment-walls.js +2 -1
  767. package/dist/schema/nodes/roof-segment.d.ts +30 -2
  768. package/dist/schema/nodes/roof-segment.d.ts.map +1 -1
  769. package/dist/schema/nodes/roof-segment.js +9 -0
  770. package/dist/schema/nodes/roof.d.ts +101 -0
  771. package/dist/schema/nodes/roof.d.ts.map +1 -1
  772. package/dist/schema/nodes/roof.js +6 -0
  773. package/dist/schema/nodes/scan.d.ts +26 -0
  774. package/dist/schema/nodes/scan.d.ts.map +1 -1
  775. package/dist/schema/nodes/separator.d.ts +50 -0
  776. package/dist/schema/nodes/separator.d.ts.map +1 -0
  777. package/dist/schema/nodes/separator.js +8 -0
  778. package/dist/schema/nodes/shelf.d.ts +26 -0
  779. package/dist/schema/nodes/shelf.d.ts.map +1 -1
  780. package/dist/schema/nodes/site.d.ts +192 -0
  781. package/dist/schema/nodes/site.d.ts.map +1 -1
  782. package/dist/schema/nodes/site.js +178 -1
  783. package/dist/schema/nodes/skylight.d.ts +30 -4
  784. package/dist/schema/nodes/skylight.d.ts.map +1 -1
  785. package/dist/schema/nodes/slab.d.ts +84 -0
  786. package/dist/schema/nodes/slab.d.ts.map +1 -1
  787. package/dist/schema/nodes/slab.js +37 -2
  788. package/dist/schema/nodes/solar-panel.d.ts +26 -0
  789. package/dist/schema/nodes/solar-panel.d.ts.map +1 -1
  790. package/dist/schema/nodes/spawn.d.ts +26 -0
  791. package/dist/schema/nodes/spawn.d.ts.map +1 -1
  792. package/dist/schema/nodes/stair-construction.d.ts +21 -0
  793. package/dist/schema/nodes/stair-construction.d.ts.map +1 -0
  794. package/dist/schema/nodes/stair-construction.js +13 -0
  795. package/dist/schema/nodes/stair-design-targets.d.ts +9 -0
  796. package/dist/schema/nodes/stair-design-targets.d.ts.map +1 -0
  797. package/dist/schema/nodes/stair-design-targets.js +7 -0
  798. package/dist/schema/nodes/stair-segment.d.ts +72 -4
  799. package/dist/schema/nodes/stair-segment.d.ts.map +1 -1
  800. package/dist/schema/nodes/stair-segment.js +13 -0
  801. package/dist/schema/nodes/stair.d.ts +119 -2
  802. package/dist/schema/nodes/stair.d.ts.map +1 -1
  803. package/dist/schema/nodes/stair.js +59 -2
  804. package/dist/schema/nodes/structural-grid.d.ts +26 -0
  805. package/dist/schema/nodes/structural-grid.d.ts.map +1 -1
  806. package/dist/schema/nodes/surface-hole-metadata.d.ts +3 -0
  807. package/dist/schema/nodes/surface-hole-metadata.d.ts.map +1 -1
  808. package/dist/schema/nodes/surface-hole-metadata.js +2 -1
  809. package/dist/schema/nodes/surface-paint-region.d.ts +14 -0
  810. package/dist/schema/nodes/surface-paint-region.d.ts.map +1 -0
  811. package/dist/schema/nodes/surface-paint-region.js +12 -0
  812. package/dist/schema/nodes/turbine-vent.d.ts +26 -0
  813. package/dist/schema/nodes/turbine-vent.d.ts.map +1 -1
  814. package/dist/schema/nodes/unit.d.ts +26 -0
  815. package/dist/schema/nodes/unit.d.ts.map +1 -1
  816. package/dist/schema/nodes/wall.d.ts +352 -61
  817. package/dist/schema/nodes/wall.d.ts.map +1 -1
  818. package/dist/schema/nodes/wall.js +185 -186
  819. package/dist/schema/nodes/window.d.ts +139 -20
  820. package/dist/schema/nodes/window.d.ts.map +1 -1
  821. package/dist/schema/nodes/window.js +12 -14
  822. package/dist/schema/nodes/zone.d.ts +69 -1
  823. package/dist/schema/nodes/zone.d.ts.map +1 -1
  824. package/dist/schema/nodes/zone.js +46 -0
  825. package/dist/schema/provenance.d.ts +118 -0
  826. package/dist/schema/provenance.d.ts.map +1 -0
  827. package/dist/schema/provenance.js +76 -0
  828. package/dist/schema/source-ref.d.ts +23 -0
  829. package/dist/schema/source-ref.d.ts.map +1 -0
  830. package/dist/schema/source-ref.js +29 -0
  831. package/dist/schema/types.d.ts +3317 -68
  832. package/dist/schema/types.d.ts.map +1 -1
  833. package/dist/schema/types.js +7 -0
  834. package/dist/services/alignment-anchors.d.ts +2 -1
  835. package/dist/services/alignment-anchors.d.ts.map +1 -1
  836. package/dist/services/alignment-anchors.js +9 -6
  837. package/dist/services/index.d.ts +1 -1
  838. package/dist/services/index.d.ts.map +1 -1
  839. package/dist/services/index.js +1 -1
  840. package/dist/services/level-height.d.ts.map +1 -1
  841. package/dist/services/level-height.js +6 -4
  842. package/dist/services/storey.d.ts +21 -1
  843. package/dist/services/storey.d.ts.map +1 -1
  844. package/dist/services/storey.js +94 -8
  845. package/dist/services/surface-hosting.d.ts.map +1 -1
  846. package/dist/services/surface-hosting.js +4 -1
  847. package/dist/store/actions/node-actions.d.ts +4563 -8
  848. package/dist/store/actions/node-actions.d.ts.map +1 -1
  849. package/dist/store/actions/node-actions.js +495 -174
  850. package/dist/store/derived-node-guard.d.ts +84 -0
  851. package/dist/store/derived-node-guard.d.ts.map +1 -0
  852. package/dist/store/derived-node-guard.js +586 -0
  853. package/dist/store/history-control.d.ts +34 -0
  854. package/dist/store/history-control.d.ts.map +1 -1
  855. package/dist/store/history-control.js +99 -1
  856. package/dist/store/history-drafts.d.ts +48 -0
  857. package/dist/store/history-drafts.d.ts.map +1 -0
  858. package/dist/store/history-drafts.js +403 -0
  859. package/dist/store/history-invalidation.d.ts.map +1 -1
  860. package/dist/store/history-invalidation.js +1 -0
  861. package/dist/store/item-interaction.d.ts +28 -0
  862. package/dist/store/item-interaction.d.ts.map +1 -0
  863. package/dist/store/item-interaction.js +34 -0
  864. package/dist/store/registered-node-defaults.d.ts +11 -0
  865. package/dist/store/registered-node-defaults.d.ts.map +1 -0
  866. package/dist/store/registered-node-defaults.js +25 -0
  867. package/dist/store/scene-annotations.d.ts +8969 -0
  868. package/dist/store/scene-annotations.d.ts.map +1 -0
  869. package/dist/store/scene-annotations.js +107 -0
  870. package/dist/store/use-interactive.d.ts +23 -1
  871. package/dist/store/use-interactive.d.ts.map +1 -1
  872. package/dist/store/use-interactive.js +128 -5
  873. package/dist/store/use-scene.d.ts +68 -12
  874. package/dist/store/use-scene.d.ts.map +1 -1
  875. package/dist/store/use-scene.js +416 -305
  876. package/dist/systems/elevator/elevator-opening-sync.d.ts.map +1 -1
  877. package/dist/systems/elevator/elevator-opening-sync.js +4 -6
  878. package/dist/systems/elevator/elevator-opening-system.d.ts.map +1 -1
  879. package/dist/systems/elevator/elevator-opening-system.js +12 -6
  880. package/dist/systems/elevator/elevator-service.d.ts.map +1 -1
  881. package/dist/systems/elevator/elevator-service.js +8 -3
  882. package/dist/systems/fence/fence-centerline.d.ts.map +1 -1
  883. package/dist/systems/fence/fence-centerline.js +6 -5
  884. package/dist/systems/fence/fence-features.d.ts +36 -0
  885. package/dist/systems/fence/fence-features.d.ts.map +1 -0
  886. package/dist/systems/fence/fence-features.js +105 -0
  887. package/dist/systems/fence/fence-spline.d.ts +8 -5
  888. package/dist/systems/fence/fence-spline.d.ts.map +1 -1
  889. package/dist/systems/fence/fence-spline.js +51 -16
  890. package/dist/systems/owned-floor-openings.d.ts +9 -0
  891. package/dist/systems/owned-floor-openings.d.ts.map +1 -0
  892. package/dist/systems/owned-floor-openings.js +326 -0
  893. package/dist/systems/reconcile-owned-floor-openings.d.ts +3 -0
  894. package/dist/systems/reconcile-owned-floor-openings.d.ts.map +1 -0
  895. package/dist/systems/reconcile-owned-floor-openings.js +25 -0
  896. package/dist/systems/slab/__fixtures__/doorway-steps.d.ts +8 -0
  897. package/dist/systems/slab/__fixtures__/doorway-steps.d.ts.map +1 -0
  898. package/dist/systems/slab/__fixtures__/doorway-steps.js +62 -0
  899. package/dist/systems/slab/__fixtures__/floor-step.d.ts +5636 -0
  900. package/dist/systems/slab/__fixtures__/floor-step.d.ts.map +1 -0
  901. package/dist/systems/slab/__fixtures__/floor-step.js +66 -0
  902. package/dist/systems/slab/__fixtures__/raised-room.d.ts +5775 -0
  903. package/dist/systems/slab/__fixtures__/raised-room.d.ts.map +1 -0
  904. package/dist/systems/slab/__fixtures__/raised-room.js +54 -0
  905. package/dist/systems/slab/ensure-slab-openings.d.ts +9 -0
  906. package/dist/systems/slab/ensure-slab-openings.d.ts.map +1 -0
  907. package/dist/systems/slab/ensure-slab-openings.js +41 -0
  908. package/dist/systems/slab/slab-support.d.ts +25 -6
  909. package/dist/systems/slab/slab-support.d.ts.map +1 -1
  910. package/dist/systems/slab/slab-support.js +471 -54
  911. package/dist/systems/stair/stair-base-elevation.d.ts +3 -0
  912. package/dist/systems/stair/stair-base-elevation.d.ts.map +1 -0
  913. package/dist/systems/stair/stair-base-elevation.js +49 -0
  914. package/dist/systems/stair/stair-clearance.d.ts +39 -0
  915. package/dist/systems/stair/stair-clearance.d.ts.map +1 -0
  916. package/dist/systems/stair/stair-clearance.js +508 -0
  917. package/dist/systems/stair/stair-construction.d.ts +37 -0
  918. package/dist/systems/stair/stair-construction.d.ts.map +1 -0
  919. package/dist/systems/stair/stair-construction.js +314 -0
  920. package/dist/systems/stair/stair-detail-budget.d.ts +13 -0
  921. package/dist/systems/stair/stair-detail-budget.d.ts.map +1 -0
  922. package/dist/systems/stair/stair-detail-budget.js +64 -0
  923. package/dist/systems/stair/stair-flight.d.ts +2 -2
  924. package/dist/systems/stair/stair-flight.d.ts.map +1 -1
  925. package/dist/systems/stair/stair-flight.js +4 -3
  926. package/dist/systems/stair/stair-floor-footprints.d.ts +7 -0
  927. package/dist/systems/stair/stair-floor-footprints.d.ts.map +1 -0
  928. package/dist/systems/stair/stair-floor-footprints.js +113 -0
  929. package/dist/systems/stair/stair-footprint.d.ts +3 -1
  930. package/dist/systems/stair/stair-footprint.d.ts.map +1 -1
  931. package/dist/systems/stair/stair-footprint.js +97 -44
  932. package/dist/systems/stair/stair-layout.d.ts +39 -0
  933. package/dist/systems/stair/stair-layout.d.ts.map +1 -0
  934. package/dist/systems/stair/stair-layout.js +58 -0
  935. package/dist/systems/stair/stair-opening-preview.d.ts +1612 -80
  936. package/dist/systems/stair/stair-opening-preview.d.ts.map +1 -1
  937. package/dist/systems/stair/stair-opening-sync.d.ts +8 -2
  938. package/dist/systems/stair/stair-opening-sync.d.ts.map +1 -1
  939. package/dist/systems/stair/stair-opening-sync.js +136 -315
  940. package/dist/systems/stair/stair-opening-system.d.ts.map +1 -1
  941. package/dist/systems/stair/stair-opening-system.js +40 -8
  942. package/dist/systems/stair/stair-presets.d.ts +276 -0
  943. package/dist/systems/stair/stair-presets.d.ts.map +1 -0
  944. package/dist/systems/stair/stair-presets.js +151 -0
  945. package/dist/systems/stair/stair-rail-budget.d.ts +6 -0
  946. package/dist/systems/stair/stair-rail-budget.d.ts.map +1 -0
  947. package/dist/systems/stair/stair-rail-budget.js +36 -0
  948. package/dist/systems/stair/stair-rail-path.d.ts +22 -0
  949. package/dist/systems/stair/stair-rail-path.d.ts.map +1 -0
  950. package/dist/systems/stair/stair-rail-path.js +497 -0
  951. package/dist/systems/stair/stair-rise-edit.d.ts +9 -0
  952. package/dist/systems/stair/stair-rise-edit.d.ts.map +1 -0
  953. package/dist/systems/stair/stair-rise-edit.js +46 -0
  954. package/dist/systems/stair/stair-rise-query.d.ts +24 -0
  955. package/dist/systems/stair/stair-rise-query.d.ts.map +1 -0
  956. package/dist/systems/stair/stair-rise-query.js +125 -0
  957. package/dist/systems/stair/stair-rise.d.ts +4 -19
  958. package/dist/systems/stair/stair-rise.d.ts.map +1 -1
  959. package/dist/systems/stair/stair-rise.js +8 -71
  960. package/dist/systems/stair/stair-sizing.d.ts +414 -0
  961. package/dist/systems/stair/stair-sizing.d.ts.map +1 -0
  962. package/dist/systems/stair/stair-sizing.js +255 -0
  963. package/dist/systems/stair/stair-sweep-edit.d.ts +7 -0
  964. package/dist/systems/stair/stair-sweep-edit.d.ts.map +1 -0
  965. package/dist/systems/stair/stair-sweep-edit.js +8 -0
  966. package/dist/systems/stair/stair-walking-line.d.ts +5 -0
  967. package/dist/systems/stair/stair-walking-line.d.ts.map +1 -0
  968. package/dist/systems/stair/stair-walking-line.js +91 -0
  969. package/dist/systems/stair/stair-winder.d.ts +36 -0
  970. package/dist/systems/stair/stair-winder.d.ts.map +1 -0
  971. package/dist/systems/stair/stair-winder.js +173 -0
  972. package/dist/systems/wall/wall-assembly.d.ts +234 -0
  973. package/dist/systems/wall/wall-assembly.d.ts.map +1 -0
  974. package/dist/systems/wall/wall-assembly.js +854 -0
  975. package/dist/systems/wall/wall-curve.d.ts +2 -1
  976. package/dist/systems/wall/wall-curve.d.ts.map +1 -1
  977. package/dist/systems/wall/wall-curve.js +21 -5
  978. package/dist/systems/wall/wall-finish.d.ts +102 -0
  979. package/dist/systems/wall/wall-finish.d.ts.map +1 -0
  980. package/dist/systems/wall/wall-finish.js +264 -0
  981. package/dist/systems/wall/wall-footprint.d.ts +3 -0
  982. package/dist/systems/wall/wall-footprint.d.ts.map +1 -1
  983. package/dist/systems/wall/wall-footprint.js +15 -13
  984. package/dist/systems/wall/wall-frame.d.ts +45 -0
  985. package/dist/systems/wall/wall-frame.d.ts.map +1 -0
  986. package/dist/systems/wall/wall-frame.js +162 -0
  987. package/dist/systems/wall/wall-layer-bands.d.ts +38 -0
  988. package/dist/systems/wall/wall-layer-bands.d.ts.map +1 -0
  989. package/dist/systems/wall/wall-layer-bands.js +109 -0
  990. package/dist/systems/wall/wall-merge.d.ts +20 -1
  991. package/dist/systems/wall/wall-merge.d.ts.map +1 -1
  992. package/dist/systems/wall/wall-merge.js +189 -18
  993. package/dist/systems/wall/wall-mitering.d.ts +6 -5
  994. package/dist/systems/wall/wall-mitering.d.ts.map +1 -1
  995. package/dist/systems/wall/wall-mitering.js +70 -20
  996. package/dist/systems/wall/wall-operations.d.ts +1 -1
  997. package/dist/systems/wall/wall-operations.d.ts.map +1 -1
  998. package/dist/systems/wall/wall-operations.js +2 -1
  999. package/dist/systems/wall/wall-paint-plan.d.ts +30 -0
  1000. package/dist/systems/wall/wall-paint-plan.d.ts.map +1 -0
  1001. package/dist/systems/wall/wall-paint-plan.js +167 -0
  1002. package/dist/systems/wall/wall-room-sides.d.ts +6 -0
  1003. package/dist/systems/wall/wall-room-sides.d.ts.map +1 -0
  1004. package/dist/systems/wall/wall-room-sides.js +14 -0
  1005. package/dist/systems/wall/wall-step-openings.d.ts +17 -0
  1006. package/dist/systems/wall/wall-step-openings.d.ts.map +1 -0
  1007. package/dist/systems/wall/wall-step-openings.js +32 -0
  1008. package/dist/systems/wall/wall-top.d.ts +2 -6
  1009. package/dist/systems/wall/wall-top.d.ts.map +1 -1
  1010. package/dist/systems/wall/wall-top.js +3 -9
  1011. package/dist/systems/wall/wall-topology.d.ts +21 -0
  1012. package/dist/systems/wall/wall-topology.d.ts.map +1 -1
  1013. package/dist/systems/wall/wall-topology.js +405 -4
  1014. package/dist/utils/clone-scene-graph.d.ts +6 -0
  1015. package/dist/utils/clone-scene-graph.d.ts.map +1 -1
  1016. package/dist/utils/clone-scene-graph.js +123 -15
  1017. package/dist/utils/ensure-scene-openings.d.ts +8965 -0
  1018. package/dist/utils/ensure-scene-openings.d.ts.map +1 -0
  1019. package/dist/utils/ensure-scene-openings.js +29 -0
  1020. package/dist/utils/exterior-threshold-migration.d.ts +4 -0
  1021. package/dist/utils/exterior-threshold-migration.d.ts.map +1 -0
  1022. package/dist/utils/exterior-threshold-migration.js +114 -0
  1023. package/dist/utils/floor-follow-migration.d.ts +3 -0
  1024. package/dist/utils/floor-follow-migration.d.ts.map +1 -0
  1025. package/dist/utils/floor-follow-migration.js +29 -0
  1026. package/dist/utils/floor-opening-migration.d.ts +13 -0
  1027. package/dist/utils/floor-opening-migration.d.ts.map +1 -0
  1028. package/dist/utils/floor-opening-migration.js +148 -0
  1029. package/dist/utils/floor-piece-adoption.d.ts +50 -0
  1030. package/dist/utils/floor-piece-adoption.d.ts.map +1 -0
  1031. package/dist/utils/floor-piece-adoption.js +182 -0
  1032. package/dist/utils/floor-plate-migration.d.ts +4507 -0
  1033. package/dist/utils/floor-plate-migration.d.ts.map +1 -0
  1034. package/dist/utils/floor-plate-migration.js +1360 -0
  1035. package/dist/utils/heal-plan-coordinates.d.ts +2 -0
  1036. package/dist/utils/heal-plan-coordinates.d.ts.map +1 -0
  1037. package/dist/utils/heal-plan-coordinates.js +69 -0
  1038. package/dist/utils/heal-scene-graph.d.ts +20 -6
  1039. package/dist/utils/heal-scene-graph.d.ts.map +1 -1
  1040. package/dist/utils/heal-scene-graph.js +61 -16
  1041. package/dist/utils/legacy-material-slots.d.ts +23 -0
  1042. package/dist/utils/legacy-material-slots.d.ts.map +1 -0
  1043. package/dist/utils/legacy-material-slots.js +120 -0
  1044. package/dist/utils/legacy-opening-datums.d.ts +11 -0
  1045. package/dist/utils/legacy-opening-datums.d.ts.map +1 -0
  1046. package/dist/utils/legacy-opening-datums.js +92 -0
  1047. package/dist/utils/legacy-wall-datums.d.ts +6 -0
  1048. package/dist/utils/legacy-wall-datums.d.ts.map +1 -0
  1049. package/dist/utils/legacy-wall-datums.js +199 -0
  1050. package/dist/utils/load-migration.d.ts +28 -0
  1051. package/dist/utils/load-migration.d.ts.map +1 -0
  1052. package/dist/utils/load-migration.js +89 -0
  1053. package/dist/utils/node-defaults.d.ts +37 -0
  1054. package/dist/utils/node-defaults.d.ts.map +1 -0
  1055. package/dist/utils/node-defaults.js +96 -0
  1056. package/dist/utils/normalize-legacy-structure.d.ts +2 -0
  1057. package/dist/utils/normalize-legacy-structure.d.ts.map +1 -0
  1058. package/dist/utils/normalize-legacy-structure.js +61 -0
  1059. package/dist/utils/omit-undefined.d.ts +2 -0
  1060. package/dist/utils/omit-undefined.d.ts.map +1 -0
  1061. package/dist/utils/omit-undefined.js +17 -0
  1062. package/dist/utils/owned-floor-opening-migration.d.ts +4489 -0
  1063. package/dist/utils/owned-floor-opening-migration.d.ts.map +1 -0
  1064. package/dist/utils/owned-floor-opening-migration.js +365 -0
  1065. package/dist/utils/reconcile-structure-on-load.d.ts +8965 -0
  1066. package/dist/utils/reconcile-structure-on-load.d.ts.map +1 -0
  1067. package/dist/utils/reconcile-structure-on-load.js +307 -0
  1068. package/dist/utils/room-zone-migration.d.ts +18 -0
  1069. package/dist/utils/room-zone-migration.d.ts.map +1 -0
  1070. package/dist/utils/room-zone-migration.js +258 -0
  1071. package/dist/utils/scene-migrations.d.ts +16 -1
  1072. package/dist/utils/scene-migrations.d.ts.map +1 -1
  1073. package/dist/utils/scene-migrations.js +15 -1
  1074. package/dist/utils/structure-id.d.ts +4 -0
  1075. package/dist/utils/structure-id.d.ts.map +1 -0
  1076. package/dist/utils/structure-id.js +115 -0
  1077. package/dist/utils/vertical-scene-migration.d.ts +8 -8
  1078. package/dist/utils/vertical-scene-migration.d.ts.map +1 -1
  1079. package/dist/utils/vertical-scene-migration.js +18 -8
  1080. package/dist/utils/wall-assembly-migration.d.ts +14 -0
  1081. package/dist/utils/wall-assembly-migration.d.ts.map +1 -0
  1082. package/dist/utils/wall-assembly-migration.js +23 -0
  1083. package/dist/utils/wall-face-migration.d.ts +23 -0
  1084. package/dist/utils/wall-face-migration.d.ts.map +1 -0
  1085. package/dist/utils/wall-face-migration.js +246 -0
  1086. package/dist/validation/opening-bounds.d.ts +36 -0
  1087. package/dist/validation/opening-bounds.d.ts.map +1 -0
  1088. package/dist/validation/opening-bounds.js +34 -0
  1089. package/dist/validation/validate-build-json.d.ts +2 -0
  1090. package/dist/validation/validate-build-json.d.ts.map +1 -1
  1091. package/dist/validation/validate-build-json.js +36 -1
  1092. package/package.json +36 -3
  1093. package/dist/services/surface-hosting-procedural-parity.fixtures.d.ts +0 -13
  1094. package/dist/services/surface-hosting-procedural-parity.fixtures.d.ts.map +0 -1
  1095. package/dist/services/surface-hosting-procedural-parity.fixtures.js +0 -4691
  1096. package/dist/services/surface-hosting-shelf-parity.fixtures.d.ts +0 -1060
  1097. package/dist/services/surface-hosting-shelf-parity.fixtures.d.ts.map +0 -1
  1098. package/dist/services/surface-hosting-shelf-parity.fixtures.js +0 -3127
@@ -1,5 +1,7 @@
1
1
  import { z } from 'zod';
2
- import { rotateVector } from './spatial.js';
2
+ import { jointReach, partMoves, placeParts, usesPartTree, validatePartTree } from './joints.js';
3
+ import { extrusionTriangles, sectionRings, sectionThickness } from './section.js';
4
+ import { boundsOf, boxCorners, composePoses, eulerPose, frame, hingePose, IDENTITY_POSE, matrixEuler, posePoint, rotateVector, transformPoint, } from './spatial.js';
3
5
  const id = z.string().regex(/^[a-z][a-z0-9_]{0,47}$/);
4
6
  const finite = z.number().finite().min(-1000).max(1000);
5
7
  const expression = z.lazy(() => z.union([
@@ -10,17 +12,168 @@ const expression = z.lazy(() => z.union([
10
12
  args: z.array(expression).min(2).max(8),
11
13
  }),
12
14
  z.strictObject({
13
- op: z.enum(['floor', 'ceil', 'round', 'abs']),
15
+ op: z.enum(['floor', 'ceil', 'round', 'abs', 'sin', 'cos']),
14
16
  args: z.tuple([expression]),
15
17
  }),
16
18
  z.strictObject({
17
19
  op: z.literal('mod'),
18
20
  args: z.tuple([expression, expression]),
19
21
  }),
22
+ z.strictObject({
23
+ op: z.literal('select'),
24
+ args: z.array(expression).min(2).max(65),
25
+ }),
20
26
  ]));
27
+ export const ExpressionSchema = expression;
21
28
  const vector = z.tuple([expression, expression, expression]);
22
- export const RecipeSchema = z.strictObject({
23
- version: z.literal(1),
29
+ const sectionRing = z
30
+ .array(z.tuple([expression, expression]))
31
+ .min(3)
32
+ .max(64);
33
+ // An F1 section whose numbers may be expressions; it evaluates to a ResolvedSectionProfile.
34
+ const section = z.discriminatedUnion('kind', [
35
+ z.strictObject({
36
+ kind: z.literal('rectangle'),
37
+ width: expression,
38
+ depth: expression,
39
+ corner: expression.optional(),
40
+ }),
41
+ z.strictObject({ kind: z.literal('round'), radius: expression, wall: expression.optional() }),
42
+ z.strictObject({ kind: z.literal('oval'), width: expression, depth: expression }),
43
+ z.strictObject({
44
+ kind: z.literal('section'),
45
+ family: z.enum(['I', 'C', 'L', 'T', 'Z', 'rect-tube']),
46
+ width: expression,
47
+ depth: expression,
48
+ web: expression,
49
+ flange: expression,
50
+ }),
51
+ z.strictObject({
52
+ kind: z.literal('polygon'),
53
+ outer: sectionRing,
54
+ holes: z.array(sectionRing).max(16).optional(),
55
+ }),
56
+ ]);
57
+ const timing = {
58
+ delay: expression.optional(),
59
+ duration: expression.optional(),
60
+ easing: z.enum(['linear', 'smooth', 'soft']).optional(),
61
+ };
62
+ const cutCenter = z.tuple([expression, expression]).optional();
63
+ const cut = z.discriminatedUnion('shape', [
64
+ z.strictObject({
65
+ shape: z.literal('rect'),
66
+ size: z.tuple([expression, expression]),
67
+ center: cutCenter,
68
+ }),
69
+ z.strictObject({ shape: z.literal('circle'), diameter: expression, center: cutCenter }),
70
+ ]);
71
+ const motion = z.discriminatedUnion('kind', [
72
+ z.strictObject({
73
+ kind: z.literal('hinge'),
74
+ pivot: vector,
75
+ axis: z.enum(['x', 'y', 'z']),
76
+ angle: expression,
77
+ ...timing,
78
+ }),
79
+ z.strictObject({
80
+ kind: z.literal('slide'),
81
+ axis: z.enum(['x', 'y', 'z']),
82
+ distance: expression,
83
+ ...timing,
84
+ }),
85
+ z.strictObject({
86
+ kind: z.literal('spin'),
87
+ pivot: vector,
88
+ axis: z.enum(['x', 'y', 'z']),
89
+ radiansPerSecond: expression,
90
+ }),
91
+ ]);
92
+ // Version 2 lifts the part caps; triangles (counted as three.js builds them), bytes, repeat
93
+ // counts, expressions and the structural budget bound the rest.
94
+ // Inline v2 designs stay under R7's 24 KiB until pinned definitions (P-05) store larger ones.
95
+ export const RECIPE_V2_LIMITS = {
96
+ parts: 64,
97
+ partShapes: 512,
98
+ shapes: 512,
99
+ bytes: 24 * 1024,
100
+ };
101
+ export const RECIPE_LIMITS = {
102
+ bytes: 131072,
103
+ depth: 24,
104
+ expressions: 50000,
105
+ shapes: 256,
106
+ triangles: 100000,
107
+ dimension: 30,
108
+ motionParts: 8,
109
+ motionGroups: 32,
110
+ lights: 12,
111
+ };
112
+ // Shape keys keep v1's order (id, primitive, slot, size, position, …), so parsed v1 recipes
113
+ // serialize byte for byte as before.
114
+ const shapeTail = {
115
+ support: z.boolean().optional(),
116
+ // v2: the shape is built only where this evaluates to nonzero.
117
+ when: expression.optional(),
118
+ };
119
+ // Sized primitives keep a required size (R1: v1 consumers narrow on primitive and read it).
120
+ const solidShape = z.strictObject({
121
+ id,
122
+ primitive: z.enum(['box', 'roundedBox', 'cylinder', 'ellipsoid']),
123
+ slot: id,
124
+ size: vector,
125
+ position: vector,
126
+ rotation: vector.optional(),
127
+ radius: expression.optional(),
128
+ topScale: expression.optional(),
129
+ // v2 cylinders: side count (absent = 24), no end caps, hollow wall (inner radius as a
130
+ // fraction of the outer), and a partial sweep in radians from local +Z toward +X, closed
131
+ // by flat wedge sides unless open.
132
+ segments: z.number().int().min(3).max(64).optional(),
133
+ open: z.boolean().optional(),
134
+ inner: expression.optional(),
135
+ arc: expression.optional(),
136
+ ...shapeTail,
137
+ });
138
+ // v2 extrude: a section in local x/y, extruded along local z by length, centred.
139
+ const extrudeShape = z.strictObject({
140
+ id,
141
+ primitive: z.literal('extrude'),
142
+ slot: id,
143
+ section,
144
+ length: expression,
145
+ bevel: expression.optional(),
146
+ position: vector,
147
+ rotation: vector.optional(),
148
+ ...shapeTail,
149
+ });
150
+ // v2 revolve: [radius, height] points turned about local Y (segments and arc as on
151
+ // cylinders); the shape is closed where the profile meets the axis at both ends.
152
+ const revolveShape = z.strictObject({
153
+ id,
154
+ primitive: z.literal('revolve'),
155
+ slot: id,
156
+ profile: z
157
+ .array(z.tuple([expression, expression]))
158
+ .min(2)
159
+ .max(64),
160
+ segments: z.number().int().min(3).max(64).optional(),
161
+ arc: expression.optional(),
162
+ position: vector,
163
+ rotation: vector.optional(),
164
+ ...shapeTail,
165
+ });
166
+ /** The sized-primitive fields of a shape (none for an extrude). */
167
+ function solidFields(shape) {
168
+ if (shape.primitive === 'extrude')
169
+ return {};
170
+ if (shape.primitive === 'revolve')
171
+ return { segments: shape.segments, arc: shape.arc };
172
+ return shape;
173
+ }
174
+ const RecipeObject = z.strictObject({
175
+ // Version 2 marks content that older readers cannot evaluate; v2-only fields require it.
176
+ version: z.union([z.literal(1), z.literal(2)]),
24
177
  name: z.string().min(1).max(100),
25
178
  description: z.string().max(600),
26
179
  classification: z
@@ -33,6 +186,11 @@ export const RecipeSchema = z.strictObject({
33
186
  mounting: z
34
187
  .strictObject({ attachTo: z.enum(['wall-side', 'ceiling']), reference: id })
35
188
  .optional(),
189
+ // v2, floor designs: the design-space height that rests on the host floor.
190
+ base: expression.optional(),
191
+ // v2, ceiling designs: an opening in the host ceiling, drawn in the mounting reference's x/z
192
+ // plane around it. The design may rise above the reference only inside its cut.
193
+ cuts: z.array(cut).min(1).max(1).optional(),
36
194
  surfaces: z
37
195
  .array(z.strictObject({
38
196
  id,
@@ -52,7 +210,9 @@ export const RecipeSchema = z.strictObject({
52
210
  min: finite,
53
211
  max: finite,
54
212
  step: z.number().positive().max(100),
55
- unit: z.enum(['m', 'count', 'rad']),
213
+ // v2: 'bool' is 0 | 1; 'choice' is an index into `options`.
214
+ unit: z.enum(['m', 'count', 'rad', 's', 'bool', 'choice']),
215
+ options: z.array(z.string().min(1).max(60)).min(2).max(16).optional(),
56
216
  part: id.optional(),
57
217
  axis: z.enum(['x', 'y', 'z']).optional(),
58
218
  }))
@@ -72,22 +232,45 @@ export const RecipeSchema = z.strictObject({
72
232
  id,
73
233
  label: z.string().min(1).max(60),
74
234
  count: expression,
75
- shapes: z
76
- .array(z.strictObject({
77
- id,
78
- primitive: z.enum(['box', 'roundedBox', 'cylinder']),
79
- slot: id,
80
- size: vector,
235
+ // v2 part tree: the part moves with `parent` (repeating once, or exactly as often,
236
+ // bound by index) and its shapes, light and joint are authored in `frame`.
237
+ parent: id.optional(),
238
+ frame: z.strictObject({ position: vector, rotation: vector.optional() }).optional(),
239
+ // v2: a repeat is built only where this evaluates to nonzero.
240
+ when: expression.optional(),
241
+ motion: motion.optional(),
242
+ light: z
243
+ .strictObject({
81
244
  position: vector,
82
- rotation: vector.optional(),
83
- radius: expression.optional(),
84
- support: z.boolean().optional(),
85
- }))
245
+ color: z.string().regex(/^#[0-9a-fA-F]{6}$/),
246
+ intensity: z.number().finite().gt(0).max(10).optional(),
247
+ distance: z.number().finite().min(0.1).max(10).optional(),
248
+ emissiveSlot: id.optional(),
249
+ })
250
+ .optional(),
251
+ shapes: z
252
+ .array(z.discriminatedUnion('primitive', [solidShape, extrudeShape, revolveShape]))
86
253
  .min(1)
87
- .max(24),
254
+ .max(RECIPE_V2_LIMITS.partShapes),
88
255
  }))
89
256
  .min(1)
90
- .max(16),
257
+ .max(RECIPE_V2_LIMITS.parts),
258
+ // v2: at most one joint per part, keyed by the child part; origin and axis are in the part's
259
+ // frame. Values are radians (revolute, continuous speed per second) or metres (prismatic).
260
+ joints: z
261
+ .array(z.strictObject({
262
+ child: id,
263
+ kind: z.enum(['fixed', 'revolute', 'continuous', 'prismatic']),
264
+ origin: vector,
265
+ axis: vector,
266
+ open: expression.optional(),
267
+ rest: expression.optional(),
268
+ range: z.tuple([expression, expression]).optional(),
269
+ speed: expression.optional(),
270
+ ...timing,
271
+ }))
272
+ .max(64)
273
+ .optional(),
91
274
  constraints: z
92
275
  .array(z.strictObject({
93
276
  left: expression,
@@ -97,14 +280,11 @@ export const RecipeSchema = z.strictObject({
97
280
  }))
98
281
  .max(24),
99
282
  });
100
- export const RECIPE_LIMITS = {
101
- bytes: 131072,
102
- depth: 24,
103
- expressions: 50000,
104
- shapes: 256,
105
- triangles: 100000,
106
- dimension: 30,
107
- };
283
+ export const RecipeSchema = RecipeObject.superRefine((recipe, ctx) => {
284
+ const issue = versionIssue(recipe);
285
+ if (issue)
286
+ ctx.addIssue({ code: 'custom', message: issue });
287
+ });
108
288
  function guardTree(value, depth = 0, budget = { count: 0 }) {
109
289
  if (++budget.count > 12000 || depth > RECIPE_LIMITS.depth)
110
290
  throw new Error('Recipe exceeds structural budget');
@@ -116,11 +296,75 @@ function guardTree(value, depth = 0, budget = { count: 0 }) {
116
296
  }
117
297
  }
118
298
  }
299
+ function movingParts(recipe) {
300
+ return (recipe.parts.filter((part) => part.motion).length +
301
+ (recipe.joints ?? []).filter((joint) => joint.kind !== 'fixed').length);
302
+ }
303
+ function findV2Feature(recipe) {
304
+ for (const primitive of ['extrude', 'revolve'])
305
+ if (recipe.parts.some((part) => part.shapes.some((shape) => shape.primitive === primitive)))
306
+ return primitive;
307
+ if (recipe.parts.some((part) => part.shapes.some((shape) => [
308
+ solidFields(shape).segments,
309
+ solidFields(shape).open,
310
+ solidFields(shape).inner,
311
+ solidFields(shape).arc,
312
+ ].some((v) => v !== undefined))))
313
+ return 'Cylinder segments, open, inner and arc';
314
+ if (usesPartTree(recipe))
315
+ return 'Part trees and joints';
316
+ if (recipe.parameters.some((p) => p.unit === 'bool' || p.unit === 'choice' || p.options))
317
+ return 'Bool and choice parameters';
318
+ if (recipe.parts.some((part) => part.when !== undefined || part.shapes.some((s) => s.when !== undefined)))
319
+ return 'when';
320
+ const selects = (value) => Array.isArray(value)
321
+ ? value.some(selects)
322
+ : Boolean(value && typeof value === 'object') &&
323
+ (value.op === 'select' ||
324
+ Object.values(value).some(selects));
325
+ return selects(recipe) ? 'select' : null;
326
+ }
327
+ /**
328
+ * Version rules the exported schema, parseRecipe and evaluateRecipe all enforce: content
329
+ * only a v2 reader understands must say `version: 2`.
330
+ */
331
+ function versionIssue(recipe) {
332
+ if (recipe.base !== undefined) {
333
+ if (recipe.version !== 2)
334
+ return 'A declared base requires recipe version 2';
335
+ if (recipe.mounting)
336
+ return 'A declared base applies to floor designs; mounted designs use their reference';
337
+ }
338
+ if (recipe.version === 1) {
339
+ const feature = findV2Feature(recipe);
340
+ if (feature)
341
+ return `${feature} requires recipe version 2`;
342
+ }
343
+ if (recipe.version === 1 && recipe.parts.length > 16)
344
+ return 'More than 16 parts requires recipe version 2';
345
+ if (recipe.version === 1 && recipe.parts.some((part) => part.shapes.length > 24))
346
+ return 'More than 24 shapes in a part requires recipe version 2';
347
+ if (recipe.version === 2 && recipeBytes(recipe) > RECIPE_V2_LIMITS.bytes)
348
+ return 'A version 2 recipe above 24 KiB needs a pinned definition (P-05); keep it inline under 24 KiB';
349
+ if (recipe.cuts !== undefined) {
350
+ if (recipe.version !== 2)
351
+ return 'Cuts require recipe version 2';
352
+ if (recipe.mounting?.attachTo !== 'ceiling')
353
+ return 'Cuts need a ceiling-mounted design';
354
+ }
355
+ return null;
356
+ }
357
+ /** UTF-8 bytes of a recipe's compact JSON: what every inline size cap measures. */
358
+ export function recipeBytes(recipe) {
359
+ return new TextEncoder().encode(JSON.stringify(recipe)).length;
360
+ }
119
361
  export function parseRecipe(input) {
120
362
  guardTree(input);
121
363
  if (JSON.stringify(input).length > RECIPE_LIMITS.bytes)
122
364
  throw new Error('Recipe is too large');
123
365
  const recipe = RecipeSchema.parse(input);
366
+ if (usesPartTree(recipe))
367
+ validatePartTree(recipe);
124
368
  for (const list of [recipe.parameters, recipe.slots, recipe.parts]) {
125
369
  if (new Set(list.map((x) => x.id)).size !== list.length)
126
370
  throw new Error('IDs must be unique within each section');
@@ -130,22 +374,53 @@ export function parseRecipe(input) {
130
374
  throw new Error(`Invalid parameter ${p.id}`);
131
375
  if (p.unit === 'count' && ![p.min, p.max, p.default, p.step].every(Number.isInteger))
132
376
  throw new Error(`Count ${p.id} must be integral`);
377
+ if ((p.unit === 'bool' || p.unit === 'choice') &&
378
+ (p.min !== 0 ||
379
+ p.step !== 1 ||
380
+ p.axis ||
381
+ !Number.isInteger(p.default) ||
382
+ p.max !== (p.unit === 'bool' ? 1 : (p.options?.length ?? 0) - 1)))
383
+ throw new Error(`${p.unit === 'bool' ? 'Bool' : 'Choice'} ${p.id} must run 0..${p.unit === 'bool' ? 1 : 'options - 1'} in steps of 1 with no handle`);
384
+ if (p.options && p.unit !== 'choice')
385
+ throw new Error(`Only choice parameters have options (${p.id})`);
133
386
  if (p.part && !recipe.parts.some((part) => part.id === p.part))
134
387
  throw new Error(`Unknown part ${p.part}`);
135
388
  }
136
389
  for (const part of recipe.parts) {
137
390
  if (new Set(part.shapes.map((s) => s.id)).size !== part.shapes.length)
138
391
  throw new Error(`Duplicate shape in ${part.id}`);
139
- for (const shape of part.shapes)
392
+ for (const shape of part.shapes) {
140
393
  if (!recipe.slots.some((s) => s.id === shape.slot))
141
394
  throw new Error(`Unknown slot ${shape.slot}`);
395
+ const f = solidFields(shape);
396
+ if (f.topScale !== undefined && shape.primitive !== 'cylinder')
397
+ throw new Error(`topScale is only allowed on cylinders (${part.id}/${shape.id})`);
398
+ if ((shape.primitive === 'extrude' || shape.primitive === 'revolve') && shape.support)
399
+ throw new Error(`${shape.primitive} ${part.id}/${shape.id} cannot be a support surface`);
400
+ const cylinderOptions = [f.segments, f.open, f.inner, f.arc];
401
+ if (cylinderOptions.some((option) => option !== undefined)) {
402
+ if (shape.primitive !== 'cylinder' && shape.primitive !== 'revolve')
403
+ throw new Error(`segments, open, inner and arc apply to cylinders (${part.id}/${shape.id})`);
404
+ if (shape.support && (f.inner !== undefined || f.arc !== undefined || f.open))
405
+ throw new Error(`Support shape ${part.id}/${shape.id} cannot be hollow, open or partial`);
406
+ }
407
+ if (shape.support && partMoves(recipe, part.id))
408
+ throw new Error(`Moving part ${part.id} cannot contain support shapes`);
409
+ if (shape.primitive === 'ellipsoid' && shape.support)
410
+ throw new Error(`Ellipsoid ${part.id}/${shape.id} cannot be a support surface`);
411
+ }
142
412
  }
413
+ if (movingParts(recipe) > RECIPE_LIMITS.motionParts)
414
+ throw new Error(`Recipe exceeds ${RECIPE_LIMITS.motionParts} moving parts`);
143
415
  const surfaceIds = (recipe.surfaces ?? []).map((s) => s.id);
144
416
  if (new Set(surfaceIds).size !== surfaceIds.length)
145
417
  throw new Error('Duplicate surface ID');
146
- for (const surface of recipe.surfaces ?? [])
418
+ for (const surface of recipe.surfaces ?? []) {
147
419
  if (surface.part && !recipe.parts.some((p) => p.id === surface.part))
148
420
  throw new Error('Unknown surface part');
421
+ if (surface.part && partMoves(recipe, surface.part))
422
+ throw new Error(`Named surface ${surface.id} cannot belong to moving part ${surface.part}`);
423
+ }
149
424
  if (recipe.mounting &&
150
425
  !(recipe.surfaces ?? []).some((s) => s.id === recipe.mounting.reference && !s.part))
151
426
  throw new Error('Mounting requires one named, non-repeated reference surface');
@@ -155,7 +430,197 @@ export function parseRecipe(input) {
155
430
  evaluateRecipe(recipe);
156
431
  return recipe;
157
432
  }
433
+ function shapeCorners(size, position, rotation) {
434
+ const localMin = size.map((v) => -v / 2);
435
+ const localMax = size.map((v) => v / 2);
436
+ const shapeFrame = frame(position, rotation);
437
+ return boxCorners(localMin, localMax).map((point) => transformPoint(shapeFrame, point));
438
+ }
439
+ /** Axis-aligned bounds of one evaluated shape in the design frame. */
440
+ export function shapeBounds(shape) {
441
+ if (shape.primitive !== 'ellipsoid')
442
+ return boundsOf(shapeCorners(shape.size, shape.position, shape.rotation));
443
+ const axes = [0, 1, 2].map((axis) => rotateVector([0, 1, 2].map((j) => (j === axis ? 1 : 0)), shape.rotation));
444
+ const extent = [0, 1, 2].map((k) => Math.hypot(...axes.map((axis, j) => (axis[k] * shape.size[j]) / 2)));
445
+ return boundsOf([
446
+ shape.position.map((v, k) => v - extent[k]),
447
+ shape.position.map((v, k) => v + extent[k]),
448
+ ]);
449
+ }
450
+ // Points whose hull contains the shape: a cylinder's rim vertices (as rendered), otherwise the
451
+ // corners of its oriented box (exact for boxes, conservative for the rest).
452
+ function shapeFootprint(shape) {
453
+ if (shape.primitive === 'revolve') {
454
+ // Each profile point's ring as rendered, along the arc.
455
+ const f = frame(shape.position, shape.rotation);
456
+ const n = shape.segments ?? 24, arc = shape.arc ?? 2 * Math.PI;
457
+ const steps = arc < 2 * Math.PI - 1e-9 ? n + 1 : n;
458
+ return shape.profile.flatMap(([r, y]) => Array.from({ length: steps }, (_, k) => {
459
+ const theta = (arc * k) / n;
460
+ return transformPoint(f, [r * Math.sin(theta), y, r * Math.cos(theta)]);
461
+ }));
462
+ }
463
+ if (shape.primitive !== 'cylinder')
464
+ return shapeCorners(shape.size, shape.position, shape.rotation);
465
+ const f = frame(shape.position, shape.rotation);
466
+ const n = shape.segments ?? 24, arc = shape.arc ?? 2 * Math.PI;
467
+ const partial = arc < 2 * Math.PI - 1e-9;
468
+ // Rim vertices as rendered, along the arc; a hollow arc adds its inner rim; a closed
469
+ // partial solid (wedge sides through the axis) adds the axis.
470
+ const rims = shape.inner === undefined ? [1] : [1, shape.inner];
471
+ return [-0.5, 0.5].flatMap((y) => {
472
+ const r = y > 0 ? 0.5 * shape.topScale : 0.5;
473
+ const points = rims.flatMap((scale) => Array.from({ length: partial ? n + 1 : n }, (_, k) => {
474
+ const theta = (arc * k) / n;
475
+ return transformPoint(f, [
476
+ scale * r * Math.sin(theta) * shape.size[0],
477
+ y * shape.size[1],
478
+ scale * r * Math.cos(theta) * shape.size[2],
479
+ ]);
480
+ }));
481
+ return partial && shape.inner === undefined && !shape.open
482
+ ? [...points, transformPoint(f, [0, y * shape.size[1], 0])]
483
+ : points;
484
+ });
485
+ }
486
+ /** Where a flat motion has carried its group at `fraction` of its travel. */
487
+ function motionPose(motion, fraction) {
488
+ const axis = [0, 1, 2].map((k) => (['x', 'y', 'z'][k] === motion.axis ? 1 : 0));
489
+ if (motion.kind === 'slide')
490
+ return { r: IDENTITY_POSE.r, t: axis.map((v) => v * motion.amount * fraction) };
491
+ const angle = motion.kind === 'spin' ? 2 * Math.PI * fraction : motion.amount * fraction;
492
+ return hingePose(motion.pivot, axis, angle);
493
+ }
494
+ const LEGACY_TRIANGLE_CHARGE = { box: 12, roundedBox: 588, cylinder: 96, ellipsoid: 720 };
495
+ /** A revolve that meets the axis at both ends over a full turn encloses a solid. */
496
+ export function revolveIsClosed(shape) {
497
+ const profile = shape.profile;
498
+ return (profile[0][0] <= 1e-9 &&
499
+ profile.at(-1)[0] <= 1e-9 &&
500
+ (shape.arc === undefined || shape.arc >= 2 * Math.PI - 1e-9));
501
+ }
502
+ /** Triangles of the geometry the renderer builds for an evaluated shape (non-indexed). */
503
+ export function shapeTriangles(shape) {
504
+ switch (shape.primitive) {
505
+ case 'box':
506
+ return 12;
507
+ case 'roundedBox':
508
+ return 300; // RoundedBoxGeometry(…, 2): a 5 × 5 grid on each face
509
+ case 'cylinder': {
510
+ // Per side: one torso triangle per nonzero radius, one cap triangle per nonzero radius
511
+ // (two for a tube's ring), plus two triangles per wedge side of a closed partial sweep.
512
+ const n = shape.segments ?? 24, ends = shape.topScale > 0 ? 2 : 1;
513
+ const wedges = shape.arc !== undefined && shape.arc < 2 * Math.PI - 1e-9 && !shape.open;
514
+ // A hollow wall draws its inner face; an open solid draws its back face instead, since
515
+ // materials are front-sided.
516
+ const walls = shape.inner !== undefined || shape.open ? 2 : 1;
517
+ const caps = shape.open ? 0 : (shape.inner === undefined ? 1 : 2) * n * ends;
518
+ return walls * n * ends + caps + (wedges ? 4 : 0);
519
+ }
520
+ case 'ellipsoid':
521
+ return 720; // SphereGeometry(…, 24, 16) without the degenerate pole triangles
522
+ case 'extrude':
523
+ return extrusionTriangles(sectionRings(shape.section), shape.bevel ? 2 : 0);
524
+ case 'revolve': {
525
+ // LatheGeometry: two per segment per profile edge; an open surface also draws its back.
526
+ const n = shape.segments ?? 24, profile = shape.profile;
527
+ return 2 * n * (profile.length - 1) * (revolveIsClosed(shape) ? 1 : 2);
528
+ }
529
+ }
530
+ }
531
+ /**
532
+ * Triangles a shape charges against the recipe budget: v1 keeps its original, conservative
533
+ * charges so its acceptance never changes; v2 charges what the renderer builds.
534
+ */
535
+ export function triangleCharge(recipe, shape, built = shapeTriangles(shape)) {
536
+ return recipe.version === 1
537
+ ? LEGACY_TRIANGLE_CHARGE[shape.primitive]
538
+ : built;
539
+ }
540
+ function resolveSection(section, value) {
541
+ const length = (e, what) => {
542
+ const v = value(e);
543
+ if (!(v >= 0.001 && v <= RECIPE_LIMITS.dimension))
544
+ throw new Error(`Invalid section ${what}`);
545
+ return v;
546
+ };
547
+ switch (section.kind) {
548
+ case 'rectangle': {
549
+ const width = length(section.width, 'width'), depth = length(section.depth, 'depth');
550
+ const corner = section.corner === undefined ? 0 : value(section.corner);
551
+ if (!(corner >= 0 && corner <= Math.min(width, depth) / 2))
552
+ throw new Error('A section corner must be within 0..half its smaller side');
553
+ return corner
554
+ ? { kind: 'rectangle', width, depth, corner }
555
+ : { kind: 'rectangle', width, depth };
556
+ }
557
+ case 'round': {
558
+ const radius = length(section.radius, 'radius');
559
+ const wall = section.wall === undefined ? undefined : value(section.wall);
560
+ if (wall !== undefined && !(wall > 0 && wall < radius))
561
+ throw new Error('A round section wall must be within (0, radius)');
562
+ return wall === undefined ? { kind: 'round', radius } : { kind: 'round', radius, wall };
563
+ }
564
+ case 'oval':
565
+ return {
566
+ kind: 'oval',
567
+ width: length(section.width, 'width'),
568
+ depth: length(section.depth, 'depth'),
569
+ };
570
+ case 'section':
571
+ return {
572
+ kind: 'section',
573
+ family: section.family,
574
+ width: length(section.width, 'width'),
575
+ depth: length(section.depth, 'depth'),
576
+ web: length(section.web, 'web'),
577
+ flange: length(section.flange, 'flange'),
578
+ };
579
+ case 'polygon': {
580
+ const point = ([x, y]) => {
581
+ const p = [value(x), value(y)];
582
+ if (p.some((v) => Math.abs(v) > RECIPE_LIMITS.dimension))
583
+ throw new Error('Invalid section point');
584
+ return p;
585
+ };
586
+ return {
587
+ kind: 'polygon',
588
+ outer: section.outer.map(point),
589
+ ...(section.holes && { holes: section.holes.map((hole) => hole.map(point)) }),
590
+ };
591
+ }
592
+ }
593
+ }
158
594
  export function evaluateRecipe(recipe, values = {}) {
595
+ const issue = versionIssue(recipe);
596
+ if (issue)
597
+ throw new Error(issue);
598
+ const slotColors = new Map();
599
+ for (const part of recipe.parts) {
600
+ const light = part.light;
601
+ if (!light)
602
+ continue;
603
+ if (!/^#[0-9a-fA-F]{6}$/.test(light.color) ||
604
+ (light.intensity !== undefined &&
605
+ (!Number.isFinite(light.intensity) || light.intensity <= 0 || light.intensity > 10)) ||
606
+ (light.distance !== undefined &&
607
+ (!Number.isFinite(light.distance) || light.distance < 0.1 || light.distance > 10)))
608
+ throw new Error(`Invalid light for ${part.id}`);
609
+ if (!light.emissiveSlot)
610
+ continue;
611
+ if (!recipe.slots.some((slot) => slot.id === light.emissiveSlot))
612
+ throw new Error(`Unknown emissive slot ${light.emissiveSlot}`);
613
+ const previous = slotColors.get(light.emissiveSlot);
614
+ // v2 checks the lights it actually builds (below), so exclusive variants may differ.
615
+ if (recipe.version === 1 && previous && previous !== light.color.toLowerCase())
616
+ throw new Error(`Conflicting light colors on ${light.emissiveSlot}`);
617
+ slotColors.set(light.emissiveSlot, light.color.toLowerCase());
618
+ }
619
+ if (movingParts(recipe) > RECIPE_LIMITS.motionParts)
620
+ throw new Error(`Recipe exceeds ${RECIPE_LIMITS.motionParts} moving parts`);
621
+ for (const surface of recipe.surfaces ?? [])
622
+ if (surface.part && partMoves(recipe, surface.part))
623
+ throw new Error(`Named surface ${surface.id} cannot belong to moving part ${surface.part}`);
159
624
  const parameters = Object.create(null);
160
625
  for (const key of Object.keys(values))
161
626
  if (!recipe.parameters.some((p) => p.id === key))
@@ -165,7 +630,7 @@ export function evaluateRecipe(recipe, values = {}) {
165
630
  if (!Number.isFinite(v) ||
166
631
  v < p.min ||
167
632
  v > p.max ||
168
- (p.unit === 'count' && !Number.isInteger(v)))
633
+ ((p.unit === 'count' || p.unit === 'bool' || p.unit === 'choice') && !Number.isInteger(v)))
169
634
  throw new Error(`${p.label} must be between ${p.min} and ${p.max}`);
170
635
  parameters[p.id] = v;
171
636
  }
@@ -182,6 +647,12 @@ export function evaluateRecipe(recipe, values = {}) {
182
647
  throw new Error(`Unknown expression reference ${e}`);
183
648
  return parameters[e];
184
649
  }
650
+ if (e.op === 'select') {
651
+ const i = expr(e.args[0], index, depth + 1);
652
+ if (!Number.isInteger(i) || i < 0 || i >= e.args.length - 1)
653
+ throw new Error(`select index ${i} is outside 0..${e.args.length - 2}`);
654
+ return expr(e.args[i + 1], index, depth + 1);
655
+ }
185
656
  const a = e.args.map((x) => expr(x, index, depth + 1));
186
657
  let result;
187
658
  switch (e.op) {
@@ -209,6 +680,12 @@ export function evaluateRecipe(recipe, values = {}) {
209
680
  case 'abs':
210
681
  result = Math.abs(a[0]);
211
682
  break;
683
+ case 'sin':
684
+ result = Math.sin(a[0]);
685
+ break;
686
+ case 'cos':
687
+ result = Math.cos(a[0]);
688
+ break;
212
689
  case 'mod': {
213
690
  const divisor = a[1];
214
691
  if (divisor <= 0)
@@ -235,24 +712,200 @@ export function evaluateRecipe(recipe, values = {}) {
235
712
  if (c.relation === 'lte' ? a > b + 1e-8 : a < b - 1e-8)
236
713
  throw new Error(c.message);
237
714
  }
238
- const shapes = [], surfaces = [];
715
+ // The datum that rests on the host: design y = 0, or a v2 floor design's declared base.
716
+ // v2 ceiling designs hang from their top reference; their host bounds them against the floor.
717
+ const base = recipe.version === 2 && recipe.base !== undefined ? expr(recipe.base) : 0;
718
+ const hangsFromCeiling = recipe.version === 2 && recipe.mounting?.attachTo === 'ceiling';
719
+ const shapes = [], motions = [], lights = [], surfaces = [];
720
+ const motionGroupByInstance = Object.create(null);
721
+ const motionSignatures = new Map();
239
722
  const min = [Infinity, Infinity, Infinity], max = [-Infinity, -Infinity, -Infinity];
240
- let triangles = 0;
723
+ let triangles = 0, charged = 0;
724
+ const shapeLimit = recipe.version === 2 ? RECIPE_V2_LIMITS.shapes : RECIPE_LIMITS.shapes;
725
+ // Counts are settled before anything is expanded, so a huge count costs one expression.
726
+ const counts = new Map();
241
727
  for (const part of recipe.parts) {
242
728
  const count = expr(part.count);
243
729
  if (!Number.isInteger(count) || count < 0 || count > 64)
244
730
  throw new Error(`Invalid repeat count for ${part.label}`);
245
- for (let i = 0; i < count; i++)
246
- for (const s of part.shapes) {
247
- if (shapes.length >= RECIPE_LIMITS.shapes)
731
+ counts.set(part.id, count);
732
+ }
733
+ const placements = recipe.version === 2 && usesPartTree(recipe) ? placeParts(recipe, expr, counts) : null;
734
+ const jointGroups = new Set();
735
+ // Part repeats that built geometry; only these carry the part's named surfaces.
736
+ const builtRepeats = new Set();
737
+ for (const part of recipe.parts) {
738
+ const count = counts.get(part.id);
739
+ for (let i = 0; i < count; i++) {
740
+ if (part.when !== undefined && expr(part.when, i) === 0)
741
+ continue;
742
+ const placement = placements?.get(`${part.id}:${i}`);
743
+ if (placements && !placement)
744
+ continue;
745
+ // A joint is kept even where `when` skips all its part's shapes, since its children
746
+ // still ride it; joints that end up carrying nothing are dropped after the loop.
747
+ if (placement?.motion) {
748
+ if (motions.length >= RECIPE_LIMITS.motionGroups)
749
+ throw new Error(`Recipe exceeds ${RECIPE_LIMITS.motionGroups} evaluated motion groups`);
750
+ motions.push(placement.motion);
751
+ jointGroups.add(placement.motion.id);
752
+ motionGroupByInstance[`${part.id}:${i}`] = placement.motion.id;
753
+ }
754
+ const kept = part.shapes.filter((s) => s.when === undefined || expr(s.when, i) !== 0);
755
+ if (!kept.length)
756
+ continue;
757
+ builtRepeats.add(`${part.id}:${i}`);
758
+ // A part-tree pose re-expresses the part's frame in design space.
759
+ const pose = placement?.pose ?? IDENTITY_POSE;
760
+ const place = (position, rotation) => {
761
+ if (pose === IDENTITY_POSE)
762
+ return { position, rotation };
763
+ const placed = composePoses(pose, eulerPose(position, rotation));
764
+ return { position: placed.t, rotation: matrixEuler(placed.r) };
765
+ };
766
+ const vec = (v) => v.map((x) => expr(x, i));
767
+ const instanceMin = [Infinity, Infinity, Infinity];
768
+ const instanceMax = [-Infinity, -Infinity, -Infinity];
769
+ let motionGroup = placement?.group;
770
+ if (part.motion) {
771
+ const motion = part.motion;
772
+ const pivot = motion.kind === 'slide' ? [0, 0, 0] : vec(motion.pivot);
773
+ const amount = expr(motion.kind === 'hinge'
774
+ ? motion.angle
775
+ : motion.kind === 'slide'
776
+ ? motion.distance
777
+ : motion.radiansPerSecond, i);
778
+ const limit = motion.kind === 'hinge' ? Math.PI : motion.kind === 'slide' ? 5 : 20;
779
+ if (Math.abs(amount) <= 0 || Math.abs(amount) > limit)
780
+ throw new Error(`Invalid ${motion.kind} amount for ${part.id}: expected 0 < absolute value <= ${limit}`);
781
+ const rounded = (n) => Math.round(n * 1e6) / 1e6;
782
+ const delay = motion.kind === 'spin' ? 0 : expr(motion.delay ?? 0, i);
783
+ const duration = motion.kind === 'spin' ? 0 : expr(motion.duration ?? 0.45, i);
784
+ const easing = motion.kind === 'spin' ? 'linear' : (motion.easing ?? 'smooth');
785
+ if (!Number.isFinite(delay) ||
786
+ !Number.isFinite(duration) ||
787
+ delay < 0 ||
788
+ delay > 1 ||
789
+ !['linear', 'smooth', 'soft'].includes(easing) ||
790
+ (motion.kind !== 'spin' && (duration < 0.1 || duration > 2)))
791
+ throw new Error(`Invalid timing for ${part.id}`);
792
+ const signature = JSON.stringify([
793
+ part.id,
794
+ motion.kind,
795
+ motion.axis,
796
+ ...pivot.map(rounded),
797
+ rounded(amount),
798
+ delay,
799
+ duration,
800
+ easing,
801
+ ]);
802
+ // A part gated by `when` names groups by repeat index, so skipped repeats never
803
+ // renumber the survivors.
804
+ const gated = part.when !== undefined || part.shapes.some((shape) => shape.when !== undefined);
805
+ motionGroup = gated ? undefined : motionSignatures.get(signature);
806
+ if (!motionGroup) {
807
+ if (motions.length >= RECIPE_LIMITS.motionGroups)
808
+ throw new Error(`Recipe exceeds ${RECIPE_LIMITS.motionGroups} evaluated motion groups`);
809
+ const ordinal = gated ? i : motions.filter((m) => m.partId === part.id).length;
810
+ motionGroup = ordinal ? `${part.id}~${ordinal}` : part.id;
811
+ motionSignatures.set(signature, motionGroup);
812
+ motions.push({
813
+ id: motionGroup,
814
+ partId: part.id,
815
+ kind: motion.kind,
816
+ axis: motion.axis,
817
+ pivot,
818
+ amount,
819
+ delay,
820
+ duration,
821
+ easing,
822
+ });
823
+ }
824
+ motionGroupByInstance[`${part.id}:${i}`] = motionGroup;
825
+ }
826
+ for (const s of kept) {
827
+ if (shapes.length >= shapeLimit)
248
828
  throw new Error('Expanded shape budget exceeded');
249
- const vec = (v) => v.map((x) => expr(x, i));
250
- const size = vec(s.size), position = vec(s.position), rotation = vec(s.rotation ?? [0, 0, 0]);
829
+ let position = vec(s.position);
830
+ let rotation = vec(s.rotation ?? [0, 0, 0]);
831
+ let size;
832
+ let extrusion = {};
833
+ if (s.primitive === 'revolve') {
834
+ // Points that coincide with the previous one (a feature collapsed to zero) are dropped.
835
+ const points = [];
836
+ for (const [re, ye] of s.profile) {
837
+ const [r, y] = [expr(re, i), expr(ye, i)];
838
+ if (!(r >= 0 &&
839
+ r <= RECIPE_LIMITS.dimension / 2 &&
840
+ Math.abs(y) <= RECIPE_LIMITS.dimension))
841
+ throw new Error(`Invalid revolve profile for ${part.id}/${s.id}`);
842
+ const last = points.at(-1);
843
+ if (!last || Math.hypot(r - last[0], y - last[1]) > 1e-6)
844
+ points.push([r, y]);
845
+ }
846
+ if (points.length < 2)
847
+ throw new Error(`Invalid revolve profile for ${part.id}/${s.id}`);
848
+ const radius = Math.max(...points.map(([r]) => r));
849
+ const low = Math.min(...points.map(([, y]) => y)), high = Math.max(...points.map(([, y]) => y));
850
+ size = [2 * radius, high - low, 2 * radius];
851
+ const middle = (low + high) / 2;
852
+ position = position.map((v, k) => v + rotateVector([0, middle, 0], rotation)[k]);
853
+ extrusion = { profile: points.map(([r, y]) => [r, y - middle]) };
854
+ if (!(size[0] >= 0.001))
855
+ throw new Error(`Revolve profile for ${part.id}/${s.id} needs a radius`);
856
+ }
857
+ else if (s.primitive === 'extrude') {
858
+ const resolved = resolveSection(s.section, (e) => expr(e, i));
859
+ const rings = sectionRings(resolved);
860
+ const b = boundsOf(rings.outer.map(([x, y]) => [x, y, 0]));
861
+ const center = b.min.map((v, k) => (v + b.max[k]) / 2);
862
+ const length = expr(s.length, i);
863
+ const bevel = s.bevel === undefined ? 0 : expr(s.bevel, i);
864
+ // The bevel insets every contour, so it must stay under the section's thinnest wall.
865
+ if (!(bevel >= 0 &&
866
+ bevel <= Math.min(length / 4, 0.05) &&
867
+ (bevel === 0 || bevel <= sectionThickness(rings) / 2.5 + 1e-9)))
868
+ throw new Error(`bevel for ${part.id}/${s.id} must be within 0..min(length / 4, 5 cm, thinnest wall / 2.5)`);
869
+ size = [b.dimensions[0], b.dimensions[1], length];
870
+ // Evaluated shapes are centred in their box, so bounds and handles read them as boxes.
871
+ position = position.map((v, k) => v + rotateVector(center, rotation)[k]);
872
+ extrusion = {
873
+ section: resolved.kind === 'polygon'
874
+ ? {
875
+ kind: 'polygon',
876
+ outer: resolved.outer.map(([x, y]) => [x - center[0], y - center[1]]),
877
+ ...(resolved.holes && {
878
+ holes: resolved.holes.map((hole) => hole.map(([x, y]) => [x - center[0], y - center[1]])),
879
+ }),
880
+ }
881
+ : resolved,
882
+ ...(bevel > 0 && { bevel }),
883
+ };
884
+ }
885
+ else
886
+ size = vec(s.size);
887
+ const f = solidFields(s);
251
888
  if (size.some((x) => x < 0.001 || x > RECIPE_LIMITS.dimension))
252
889
  throw new Error(`Invalid dimensions for ${part.id}/${s.id}`);
253
- const radius = s.primitive === 'roundedBox' ? expr(s.radius ?? 0.02, i) : 0;
890
+ const radius = s.primitive === 'roundedBox' ? expr(f.radius ?? 0.02, i) : 0;
254
891
  if (radius < 0 || radius > Math.min(...size) / 2)
255
892
  throw new Error(`Invalid rounding for ${s.id}`);
893
+ if (f.topScale !== undefined && s.primitive !== 'cylinder')
894
+ throw new Error(`topScale is only allowed on cylinders (${part.id}/${s.id})`);
895
+ const topScale = f.topScale === undefined ? 1 : expr(f.topScale, i);
896
+ if (topScale < 0 || topScale > 1)
897
+ throw new Error(`topScale for ${part.id}/${s.id} must be within [0, 1]`);
898
+ if (s.support && (s.primitive === 'ellipsoid' || topScale < 1))
899
+ throw new Error(`Support surface ${part.id}/${s.id} cannot be ellipsoid or tapered cylinder`);
900
+ if (s.support && motionGroup)
901
+ throw new Error(`Moving part ${part.id} cannot contain support shapes`);
902
+ const inner = f.inner === undefined ? undefined : expr(f.inner, i);
903
+ if (inner !== undefined && !(inner > 0 && inner < 1))
904
+ throw new Error(`inner for ${part.id}/${s.id} must be within (0, 1)`);
905
+ const arc = f.arc === undefined ? undefined : expr(f.arc, i);
906
+ if (arc !== undefined && !(arc > 0 && arc <= 2 * Math.PI + 1e-9))
907
+ throw new Error(`arc for ${part.id}/${s.id} must be within (0, 2π]`);
908
+ ({ position, rotation } = place(position, rotation));
256
909
  const shapeId = `${part.id}:${i}:${s.id}`;
257
910
  shapes.push({
258
911
  id: shapeId,
@@ -263,28 +916,29 @@ export function evaluateRecipe(recipe, values = {}) {
263
916
  position,
264
917
  rotation,
265
918
  radius,
919
+ topScale,
920
+ ...(f.segments === undefined ? {} : { segments: f.segments }),
921
+ ...(f.open ? { open: true } : {}),
922
+ ...(inner === undefined ? {} : { inner }),
923
+ ...(arc === undefined ? {} : { arc }),
924
+ ...extrusion,
925
+ motionGroup,
266
926
  });
267
- triangles += s.primitive === 'roundedBox' ? 588 : s.primitive === 'cylinder' ? 96 : 12;
268
- if (triangles > RECIPE_LIMITS.triangles)
927
+ const built = shapeTriangles(shapes.at(-1));
928
+ triangles += built;
929
+ charged += triangleCharge(recipe, shapes.at(-1), built);
930
+ if (charged > RECIPE_LIMITS.triangles)
269
931
  throw new Error('Triangle budget exceeded');
270
- // XYZ Euler rotations match Three.js; bounding corners remain pure domain math.
271
- for (const x of [-size[0] / 2, size[0] / 2])
272
- for (const y of [-size[1] / 2, size[1] / 2])
273
- for (const z of [-size[2] / 2, size[2] / 2]) {
274
- const [rx, ry, rz] = rotation;
275
- const x1 = x * Math.cos(rz) - y * Math.sin(rz), y1 = x * Math.sin(rz) + y * Math.cos(rz);
276
- const x2 = x1 * Math.cos(ry) + z * Math.sin(ry), z2 = -x1 * Math.sin(ry) + z * Math.cos(ry);
277
- const point = [
278
- x2 + position[0],
279
- y1 * Math.cos(rx) - z2 * Math.sin(rx) + position[1],
280
- y1 * Math.sin(rx) + z2 * Math.cos(rx) + position[2],
281
- ];
282
- for (let k = 0; k < 3; k++) {
283
- min[k] = Math.min(min[k], point[k]);
284
- max[k] = Math.max(max[k], point[k]);
285
- }
286
- }
932
+ const bounds = shapeBounds({ primitive: s.primitive, size, position, rotation });
933
+ for (let k = 0; k < 3; k++) {
934
+ min[k] = Math.min(min[k], bounds.min[k]);
935
+ max[k] = Math.max(max[k], bounds.max[k]);
936
+ instanceMin[k] = Math.min(instanceMin[k], bounds.min[k]);
937
+ instanceMax[k] = Math.max(instanceMax[k], bounds.max[k]);
938
+ }
287
939
  if (s.support) {
940
+ if (surfaces.length >= 256)
941
+ throw new Error('Surface budget exceeded');
288
942
  if (rotation.some((v) => v !== 0))
289
943
  throw new Error('Support surfaces must be horizontal and unrotated in v1');
290
944
  surfaces.push({
@@ -297,17 +951,63 @@ export function evaluateRecipe(recipe, values = {}) {
297
951
  });
298
952
  }
299
953
  }
954
+ // A repeat whose shapes `when` all skipped builds no light either.
955
+ if (part.light && instanceMin[0] !== Infinity) {
956
+ if (lights.length >= RECIPE_LIMITS.lights)
957
+ throw new Error('Evaluated light budget exceeded');
958
+ const position = pose === IDENTITY_POSE
959
+ ? vec(part.light.position)
960
+ : posePoint(pose, vec(part.light.position));
961
+ if (position.some((value) => !Number.isFinite(value)))
962
+ throw new Error(`Invalid light position for ${part.id}`);
963
+ if (position.some((value, axis) => value < instanceMin[axis] - 0.02 || value > instanceMax[axis] + 0.02))
964
+ throw new Error(`Light for ${part.id}:${i} is outside its resting bounds`);
965
+ lights.push({
966
+ id: `${part.id}:${i}`,
967
+ partId: part.id,
968
+ index: i,
969
+ motionGroup,
970
+ position,
971
+ color: part.light.color,
972
+ intensity: part.light.intensity ?? 2,
973
+ distance: part.light.distance ?? 5,
974
+ emissiveSlot: part.light.emissiveSlot,
975
+ });
976
+ }
977
+ }
978
+ }
979
+ if (jointGroups.size) {
980
+ const carrying = new Set();
981
+ for (let group of shapes.map((shape) => shape.motionGroup))
982
+ while (group && !carrying.has(group)) {
983
+ carrying.add(group);
984
+ group = motions.find((motion) => motion.id === group)?.parent;
985
+ }
986
+ for (let k = motions.length - 1; k >= 0; k--) {
987
+ const id = motions[k].id;
988
+ if (carrying.has(id))
989
+ continue;
990
+ motions.splice(k, 1);
991
+ jointGroups.delete(id);
992
+ for (const [instance, group] of Object.entries(motionGroupByInstance))
993
+ if (group === id)
994
+ delete motionGroupByInstance[instance];
995
+ }
300
996
  }
301
997
  for (const surface of recipe.surfaces ?? []) {
302
998
  const part = recipe.parts.find((p) => p.id === surface.part);
303
- const count = part ? expr(part.count) : 1;
999
+ const count = part ? counts.get(part.id) : 1;
304
1000
  for (let i = 0; i < count; i++) {
1001
+ if (part && !builtRepeats.has(`${part.id}:${i}`))
1002
+ continue;
305
1003
  if (surfaces.length >= 256)
306
1004
  throw new Error('Surface budget exceeded');
307
1005
  const rotation = (surface.rotation ?? [0, 0, 0]).map((e) => expr(e, i));
308
1006
  const size = surface.size.map((e) => expr(e, i));
309
1007
  const position = surface.position.map((e) => expr(e, i));
310
- if (size.some((v) => v < 0.001 || v > 30) || position.some((v) => Math.abs(v) > 30))
1008
+ // Bounded where consumers read it: design space with the resting datum at y = 0.
1009
+ if (size.some((v) => v < 0.001 || v > 30) ||
1010
+ position.some((v, k) => Math.abs(k === 1 ? v - base : v) > 30))
311
1011
  throw new Error('Invalid surface region');
312
1012
  surfaces.push({
313
1013
  id: part ? `${surface.id}:${i}` : surface.id,
@@ -319,6 +1019,9 @@ export function evaluateRecipe(recipe, values = {}) {
319
1019
  });
320
1020
  }
321
1021
  }
1022
+ const cuts = [];
1023
+ // Recessed designs: whether a design-space [x, z] lies inside one of their cuts.
1024
+ let insideCut = null;
322
1025
  if (recipe.mounting) {
323
1026
  const reference = surfaces.find((s) => s.id === recipe.mounting.reference);
324
1027
  if (!reference || reference.id.includes(':'))
@@ -326,20 +1029,189 @@ export function evaluateRecipe(recipe, values = {}) {
326
1029
  if (recipe.mounting.attachTo === 'ceiling') {
327
1030
  if (Math.abs(reference.normal[1] - 1) > 1e-6)
328
1031
  throw new Error('Ceiling mounting reference must face local +Y');
329
- if (Math.abs(reference.position[1] - max[1]) > 1e-6)
1032
+ const recessed = recipe.version === 2 && recipe.cuts !== undefined;
1033
+ if (recessed
1034
+ ? reference.position[1] > max[1] + 1e-6
1035
+ : Math.abs(reference.position[1] - max[1]) > 1e-6)
330
1036
  throw new Error('Ceiling mounting reference must lie at the top of the design');
1037
+ if (recessed) {
1038
+ const u = rotateVector([1, 0, 0], reference.rotation), v = rotateVector([0, 0, 1], reference.rotation);
1039
+ const inside = [];
1040
+ for (const c of recipe.cuts) {
1041
+ const [cu, cv] = (c.center ?? [0, 0]).map((e) => expr(e));
1042
+ const cx = reference.position[0] + u[0] * cu + v[0] * cv, cz = reference.position[2] + u[2] * cu + v[2] * cv;
1043
+ const half = c.shape === 'rect'
1044
+ ? c.size.map((e) => expr(e) / 2)
1045
+ : [expr(c.diameter) / 2, expr(c.diameter) / 2];
1046
+ if (half.some((h) => !(h >= 0.005 && h <= 15)))
1047
+ throw new Error('Invalid cut size');
1048
+ const local = c.shape === 'rect'
1049
+ ? [
1050
+ [-half[0], -half[1]],
1051
+ [half[0], -half[1]],
1052
+ [half[0], half[1]],
1053
+ [-half[0], half[1]],
1054
+ ]
1055
+ : Array.from({ length: 32 }, (_, k) => [
1056
+ half[0] * Math.cos((k * Math.PI) / 16),
1057
+ half[0] * Math.sin((k * Math.PI) / 16),
1058
+ ]);
1059
+ cuts.push({
1060
+ host: 'ceiling',
1061
+ ring: local.map(([a, b]) => [cx + u[0] * a + v[0] * b, cz + u[2] * a + v[2] * b]),
1062
+ });
1063
+ inside.push((x, z) => {
1064
+ const a = (x - cx) * u[0] + (z - cz) * u[2], b = (x - cx) * v[0] + (z - cz) * v[2];
1065
+ return c.shape === 'rect'
1066
+ ? Math.abs(a) <= half[0] + 1e-6 && Math.abs(b) <= half[1] + 1e-6
1067
+ : Math.hypot(a, b) <= half[0] + 1e-6;
1068
+ });
1069
+ }
1070
+ for (const shape of shapes) {
1071
+ if (shapeBounds(shape).max[1] <= reference.position[1] + 1e-6)
1072
+ continue;
1073
+ const footprint = shapeFootprint(shape);
1074
+ if (!inside.some((test) => footprint.every(([x, , z]) => test(x, z))))
1075
+ throw new Error(`${shape.partId} rises above the ceiling reference outside its cut`);
1076
+ }
1077
+ insideCut = (x, z) => inside.some((test) => test(x, z));
1078
+ }
331
1079
  }
332
1080
  else if (Math.abs(reference.normal[2] + 1) > 1e-6)
333
1081
  throw new Error('Wall-side mounting reference must face local -Z');
334
1082
  }
1083
+ const reference = recipe.mounting && surfaces.find((s) => s.id === recipe.mounting.reference);
1084
+ const reach = insideCut ? { min: [...min], max: [...max] } : undefined;
1085
+ for (const { motion, bounds } of jointReach(motions.filter((m) => jointGroups.has(m.id)), shapes, shapeBounds)) {
1086
+ if (reach)
1087
+ for (let k = 0; k < 3; k++) {
1088
+ reach.min[k] = Math.min(reach.min[k], bounds.min[k]);
1089
+ reach.max[k] = Math.max(reach.max[k], bounds.max[k]);
1090
+ }
1091
+ if (!recipe.mounting && bounds.min[1] < base - 0.001)
1092
+ throw new Error(`Motion envelope for ${motion.partId} extends below the floor`);
1093
+ if (recipe.mounting?.attachTo === 'wall-side' &&
1094
+ reference &&
1095
+ bounds.min[2] < reference.position[2] - 0.001)
1096
+ throw new Error(`Motion envelope for ${motion.partId} crosses behind the wall reference`);
1097
+ if (recipe.mounting?.attachTo === 'ceiling' &&
1098
+ reference &&
1099
+ bounds.max[1] > reference.position[1] + 0.001 &&
1100
+ !boxCorners(bounds.min, bounds.max).every(([x, , z]) => insideCut?.(x, z)))
1101
+ throw new Error(`Motion envelope for ${motion.partId} rises above the ceiling reference`);
1102
+ }
1103
+ for (const motion of motions) {
1104
+ if (jointGroups.has(motion.id))
1105
+ continue;
1106
+ const steps = motion.kind === 'slide' ? 1 : motion.kind === 'hinge' ? 8 : 16;
1107
+ const poses = Array.from({ length: steps + 1 }, (_, step) => motionPose(motion, step / steps));
1108
+ for (const shape of shapes) {
1109
+ if (shape.motionGroup !== motion.id)
1110
+ continue;
1111
+ // Inside a cut, sample the rendered footprint so round parts may turn in round cuts.
1112
+ const points = insideCut
1113
+ ? shapeFootprint(shape)
1114
+ : shapeCorners(shape.size, shape.position, shape.rotation);
1115
+ for (const corner of points)
1116
+ for (const { r, t } of poses) {
1117
+ const [x, y, z] = corner;
1118
+ const point = [
1119
+ r[0] * x + r[1] * y + r[2] * z + t[0],
1120
+ r[3] * x + r[4] * y + r[5] * z + t[1],
1121
+ r[6] * x + r[7] * y + r[8] * z + t[2],
1122
+ ];
1123
+ if (reach)
1124
+ for (let k = 0; k < 3; k++) {
1125
+ reach.min[k] = Math.min(reach.min[k], point[k]);
1126
+ reach.max[k] = Math.max(reach.max[k], point[k]);
1127
+ }
1128
+ if (!recipe.mounting && point[1] < base - 0.001)
1129
+ throw new Error(`Motion envelope for ${shape.partId} extends below the floor`);
1130
+ if (recipe.mounting?.attachTo === 'wall-side' &&
1131
+ reference &&
1132
+ point[2] < reference.position[2] - 0.001)
1133
+ throw new Error(`Motion envelope for ${shape.partId} crosses behind the wall reference`);
1134
+ if (recipe.mounting?.attachTo === 'ceiling' &&
1135
+ reference &&
1136
+ point[1] > reference.position[1] + 0.001 &&
1137
+ !insideCut?.(point[0], point[2]))
1138
+ throw new Error(`Motion envelope for ${shape.partId} rises above the ceiling reference`);
1139
+ }
1140
+ }
1141
+ }
335
1142
  if (!shapes.length)
336
1143
  throw new Error('The item must contain geometry');
1144
+ const emitted = new Map();
1145
+ for (const light of lights) {
1146
+ if (!light.emissiveSlot)
1147
+ continue;
1148
+ const previous = emitted.get(light.emissiveSlot);
1149
+ if (previous && previous !== light.color.toLowerCase())
1150
+ throw new Error(`Conflicting light colors on ${light.emissiveSlot}`);
1151
+ emitted.set(light.emissiveSlot, light.color.toLowerCase());
1152
+ }
1153
+ if (base !== 0) {
1154
+ // Consumers keep reading design space with the resting datum at y = 0.
1155
+ const lower = (point) => [point[0], point[1] - base, point[2]];
1156
+ for (const shape of shapes)
1157
+ shape.position = lower(shape.position);
1158
+ for (const light of lights)
1159
+ light.position = lower(light.position);
1160
+ for (const surface of surfaces)
1161
+ surface.position = lower(surface.position);
1162
+ // A slide's pivot is the origin of its group, not a point of the design.
1163
+ for (const motion of motions)
1164
+ if (motion.kind !== 'slide')
1165
+ motion.pivot = lower(motion.pivot);
1166
+ min[1] -= base;
1167
+ max[1] -= base;
1168
+ }
337
1169
  const dimensions = max.map((x, i) => x - min[i]);
338
1170
  if (dimensions.some((x) => x > 30) || [...min, ...max].some((x) => Math.abs(x) > 30))
339
1171
  throw new Error('Item exceeds 30 m bounds');
340
- if (min[1] < -0.001)
341
- throw new Error('Geometry extends below the ground; base must be at y=0');
342
- return { shapes, surfaces, min, max, dimensions, parameters, triangles };
1172
+ if (!hangsFromCeiling && min[1] < -0.001)
1173
+ throw new Error(recipe.base === undefined
1174
+ ? 'Geometry extends below the ground; base must be at y=0'
1175
+ : 'Geometry extends below the declared base');
1176
+ return {
1177
+ shapes,
1178
+ motions,
1179
+ lights,
1180
+ motionGroupByInstance,
1181
+ surfaces,
1182
+ cuts,
1183
+ min,
1184
+ max,
1185
+ dimensions,
1186
+ parameters,
1187
+ triangles,
1188
+ ...(reach && motions.length > 0 && { reach }),
1189
+ };
1190
+ }
1191
+ export const EASINGS = {
1192
+ linear: (u) => u,
1193
+ smooth: (u) => 3 * u * u - 2 * u * u * u,
1194
+ soft: (u) => 6 * u ** 5 - 15 * u ** 4 + 10 * u ** 3,
1195
+ };
1196
+ export function finitePoseFraction(motion, time) {
1197
+ const u = Math.max(0, Math.min(1, (time - motion.delay) / motion.duration));
1198
+ return EASINGS[motion.easing](u);
1199
+ }
1200
+ export function motionTimeline(evaluation) {
1201
+ const perPart = Object.create(null);
1202
+ let T = 0;
1203
+ for (const motion of evaluation.motions) {
1204
+ if (motion.kind === 'spin')
1205
+ continue;
1206
+ const end = motion.delay + motion.duration;
1207
+ T = Math.max(T, end);
1208
+ const part = perPart[motion.partId];
1209
+ perPart[motion.partId] = {
1210
+ A: Math.min(part?.A ?? Infinity, motion.delay),
1211
+ B: Math.max(part?.B ?? 0, end),
1212
+ };
1213
+ }
1214
+ return { T, perPart };
343
1215
  }
344
1216
  export function sweepRecipe(recipe) {
345
1217
  const cases = [{}];