@pascal-app/nodes 1.0.0 → 1.0.3

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 (439) hide show
  1. package/dist/block/definition.d.ts.map +1 -1
  2. package/dist/block/definition.js +4 -1
  3. package/dist/block/face-host.d.ts.map +1 -1
  4. package/dist/block/face-host.js +19 -2
  5. package/dist/block/hosted-edit.d.ts +13 -0
  6. package/dist/block/hosted-edit.d.ts.map +1 -0
  7. package/dist/block/hosted-edit.js +205 -0
  8. package/dist/block/last-operation.d.ts +1 -1
  9. package/dist/block/last-operation.d.ts.map +1 -1
  10. package/dist/block/last-operation.js +6 -4
  11. package/dist/block/modal-session.d.ts +2 -1
  12. package/dist/block/modal-session.d.ts.map +1 -1
  13. package/dist/block/modal-session.js +2 -2
  14. package/dist/block/selection.d.ts.map +1 -1
  15. package/dist/block/selection.js +82 -24
  16. package/dist/block/surface.d.ts +4 -0
  17. package/dist/block/surface.d.ts.map +1 -0
  18. package/dist/block/surface.js +54 -0
  19. package/dist/block/use-block-face-operation.d.ts +2 -2
  20. package/dist/block/use-block-face-operation.d.ts.map +1 -1
  21. package/dist/block/use-block-face-operation.js +25 -11
  22. package/dist/box-vent/definition.d.ts.map +1 -1
  23. package/dist/box-vent/definition.js +1 -0
  24. package/dist/box-vent/panel.js +4 -4
  25. package/dist/building/renderer.d.ts.map +1 -1
  26. package/dist/building/renderer.js +1 -1
  27. package/dist/cabinet/appliance-layout.d.ts +26 -0
  28. package/dist/cabinet/appliance-layout.d.ts.map +1 -0
  29. package/dist/cabinet/appliance-layout.js +52 -0
  30. package/dist/cabinet/countertop-layout.d.ts +173 -0
  31. package/dist/cabinet/countertop-layout.d.ts.map +1 -0
  32. package/dist/cabinet/countertop-layout.js +80 -0
  33. package/dist/cabinet/definition.d.ts.map +1 -1
  34. package/dist/cabinet/definition.js +17 -8
  35. package/dist/cabinet/geometry/cooktop.d.ts.map +1 -1
  36. package/dist/cabinet/geometry/cooktop.js +2 -2
  37. package/dist/cabinet/geometry/run.d.ts.map +1 -1
  38. package/dist/cabinet/geometry/run.js +10 -71
  39. package/dist/cabinet/geometry/sink.d.ts +2 -12
  40. package/dist/cabinet/geometry/sink.d.ts.map +1 -1
  41. package/dist/cabinet/geometry/sink.js +8 -39
  42. package/dist/cabinet/hosted-resize.d.ts +5 -0
  43. package/dist/cabinet/hosted-resize.d.ts.map +1 -0
  44. package/dist/cabinet/hosted-resize.js +14 -0
  45. package/dist/cabinet/placement-snap.d.ts.map +1 -1
  46. package/dist/cabinet/placement-snap.js +4 -2
  47. package/dist/cabinet/run-layout.d.ts +8 -1
  48. package/dist/cabinet/run-layout.d.ts.map +1 -1
  49. package/dist/cabinet/run-layout.js +22 -14
  50. package/dist/cabinet/run-ops.d.ts +3 -3
  51. package/dist/cabinet/run-ops.js +3 -3
  52. package/dist/cabinet/run-panel.d.ts +1 -1
  53. package/dist/cabinet/run-panel.d.ts.map +1 -1
  54. package/dist/cabinet/run-panel.js +16 -7
  55. package/dist/cabinet/surfaces.d.ts +5 -0
  56. package/dist/cabinet/surfaces.d.ts.map +1 -0
  57. package/dist/cabinet/surfaces.js +113 -0
  58. package/dist/cabinet/tool.d.ts.map +1 -1
  59. package/dist/cabinet/tool.js +8 -4
  60. package/dist/cabinet/tree-structure.d.ts.map +1 -1
  61. package/dist/cabinet/tree-structure.js +10 -9
  62. package/dist/ceiling/definition.d.ts.map +1 -1
  63. package/dist/ceiling/definition.js +6 -1
  64. package/dist/ceiling/floorplan-affordances.d.ts +4 -4
  65. package/dist/ceiling/panel.js +1 -1
  66. package/dist/ceiling/renderer.d.ts.map +1 -1
  67. package/dist/ceiling/renderer.js +3 -2
  68. package/dist/chimney/definition.d.ts.map +1 -1
  69. package/dist/chimney/definition.js +1 -0
  70. package/dist/chimney/panel.js +9 -9
  71. package/dist/column/definition.d.ts.map +1 -1
  72. package/dist/column/definition.js +10 -3
  73. package/dist/column/floorplan-affordances.d.ts.map +1 -1
  74. package/dist/column/floorplan-affordances.js +6 -1
  75. package/dist/column/floorplan.d.ts.map +1 -1
  76. package/dist/column/floorplan.js +23 -11
  77. package/dist/column/hosted-resize.d.ts +116 -0
  78. package/dist/column/hosted-resize.d.ts.map +1 -0
  79. package/dist/column/hosted-resize.js +9 -0
  80. package/dist/column/panel.d.ts.map +1 -1
  81. package/dist/column/panel.js +6 -3
  82. package/dist/column/renderer.d.ts.map +1 -1
  83. package/dist/column/renderer.js +25 -103
  84. package/dist/column/shape.d.ts +22 -0
  85. package/dist/column/shape.d.ts.map +1 -0
  86. package/dist/column/shape.js +120 -0
  87. package/dist/column/surface.d.ts +4 -0
  88. package/dist/column/surface.d.ts.map +1 -0
  89. package/dist/column/surface.js +66 -0
  90. package/dist/cupola/definition.d.ts.map +1 -1
  91. package/dist/cupola/definition.js +1 -0
  92. package/dist/cupola/panel.js +1 -1
  93. package/dist/door/definition.d.ts.map +1 -1
  94. package/dist/door/definition.js +40 -1
  95. package/dist/door/door-math.d.ts +1 -1
  96. package/dist/door/door-math.d.ts.map +1 -1
  97. package/dist/door/door-math.js +7 -10
  98. package/dist/door/floorplan-affordances.d.ts.map +1 -1
  99. package/dist/door/floorplan-affordances.js +8 -12
  100. package/dist/door/move-tool.d.ts.map +1 -1
  101. package/dist/door/move-tool.js +3 -4
  102. package/dist/door/panel.d.ts.map +1 -1
  103. package/dist/door/panel.js +28 -57
  104. package/dist/door/tool.d.ts.map +1 -1
  105. package/dist/door/tool.js +20 -2
  106. package/dist/dormer/definition.d.ts.map +1 -1
  107. package/dist/dormer/definition.js +1 -0
  108. package/dist/dormer/panel-position-section.js +2 -2
  109. package/dist/dormer/panel.js +1 -1
  110. package/dist/downspout/definition.d.ts.map +1 -1
  111. package/dist/downspout/definition.js +1 -0
  112. package/dist/duct-segment/parametrics.d.ts.map +1 -1
  113. package/dist/duct-segment/parametrics.js +5 -1
  114. package/dist/duct-segment/tool.d.ts +1 -0
  115. package/dist/duct-segment/tool.d.ts.map +1 -1
  116. package/dist/duct-segment/tool.js +21 -8
  117. package/dist/duct-terminal/tool.d.ts.map +1 -1
  118. package/dist/duct-terminal/tool.js +77 -8
  119. package/dist/elevator/definition.d.ts.map +1 -1
  120. package/dist/elevator/definition.js +2 -0
  121. package/dist/elevator/parametrics.d.ts.map +1 -1
  122. package/dist/elevator/parametrics.js +98 -1
  123. package/dist/eyebrow-vent/definition.d.ts.map +1 -1
  124. package/dist/eyebrow-vent/definition.js +1 -0
  125. package/dist/eyebrow-vent/panel.js +1 -1
  126. package/dist/fence/definition.d.ts.map +1 -1
  127. package/dist/fence/definition.js +1 -0
  128. package/dist/fence/inspector-editors.js +1 -1
  129. package/dist/fence/tool.js +2 -2
  130. package/dist/guide/definition.d.ts.map +1 -1
  131. package/dist/guide/definition.js +1 -0
  132. package/dist/gutter/definition.d.ts.map +1 -1
  133. package/dist/gutter/definition.js +1 -0
  134. package/dist/hvac-equipment/tool.d.ts.map +1 -1
  135. package/dist/hvac-equipment/tool.js +8 -2
  136. package/dist/imported-mesh/definition.d.ts +5 -0
  137. package/dist/imported-mesh/definition.d.ts.map +1 -0
  138. package/dist/imported-mesh/definition.js +38 -0
  139. package/dist/imported-mesh/floorplan.d.ts +4 -0
  140. package/dist/imported-mesh/floorplan.d.ts.map +1 -0
  141. package/dist/imported-mesh/floorplan.js +34 -0
  142. package/dist/imported-mesh/geometry.d.ts +5 -0
  143. package/dist/imported-mesh/geometry.d.ts.map +1 -0
  144. package/dist/imported-mesh/geometry.js +34 -0
  145. package/dist/imported-mesh/index.d.ts +4 -0
  146. package/dist/imported-mesh/index.d.ts.map +1 -0
  147. package/dist/imported-mesh/index.js +3 -0
  148. package/dist/imported-mesh/schema.d.ts +2 -0
  149. package/dist/imported-mesh/schema.d.ts.map +1 -0
  150. package/dist/imported-mesh/schema.js +1 -0
  151. package/dist/index.d.ts +2 -0
  152. package/dist/index.d.ts.map +1 -1
  153. package/dist/index.js +8 -0
  154. package/dist/item/__fixtures__/main-floorplan.d.ts +26 -0
  155. package/dist/item/__fixtures__/main-floorplan.d.ts.map +1 -0
  156. package/dist/item/__fixtures__/main-floorplan.js +297 -0
  157. package/dist/item/definition.d.ts.map +1 -1
  158. package/dist/item/definition.js +3 -1
  159. package/dist/item/floorplan-move.d.ts +9 -1
  160. package/dist/item/floorplan-move.d.ts.map +1 -1
  161. package/dist/item/floorplan-move.js +231 -99
  162. package/dist/item/floorplan.d.ts +22 -0
  163. package/dist/item/floorplan.d.ts.map +1 -1
  164. package/dist/item/floorplan.js +72 -2
  165. package/dist/item/move-tool.d.ts +1 -1
  166. package/dist/item/move-tool.d.ts.map +1 -1
  167. package/dist/item/move-tool.js +15 -7
  168. package/dist/item/panel.js +1 -1
  169. package/dist/item/renderer.d.ts.map +1 -1
  170. package/dist/item/renderer.js +8 -2
  171. package/dist/level/renderer.js +1 -1
  172. package/dist/lineset/tool.d.ts.map +1 -1
  173. package/dist/lineset/tool.js +1 -0
  174. package/dist/liquid-line/tool.d.ts.map +1 -1
  175. package/dist/liquid-line/tool.js +5 -1
  176. package/dist/measurement/definition.d.ts.map +1 -1
  177. package/dist/measurement/definition.js +1 -0
  178. package/dist/pipe-segment/parametrics.d.ts.map +1 -1
  179. package/dist/pipe-segment/parametrics.js +5 -1
  180. package/dist/pipe-segment/tool.d.ts.map +1 -1
  181. package/dist/pipe-segment/tool.js +14 -3
  182. package/dist/pipe-trap/tool.d.ts.map +1 -1
  183. package/dist/pipe-trap/tool.js +7 -8
  184. package/dist/procedural-item/definition.d.ts +4 -0
  185. package/dist/procedural-item/definition.d.ts.map +1 -0
  186. package/dist/procedural-item/definition.js +257 -0
  187. package/dist/procedural-item/geometry.d.ts +31 -0
  188. package/dist/procedural-item/geometry.d.ts.map +1 -0
  189. package/dist/procedural-item/geometry.js +88 -0
  190. package/dist/procedural-item/index.d.ts +3 -0
  191. package/dist/procedural-item/index.d.ts.map +1 -0
  192. package/dist/procedural-item/index.js +2 -0
  193. package/dist/procedural-item/move-session.d.ts +15 -0
  194. package/dist/procedural-item/move-session.d.ts.map +1 -0
  195. package/dist/procedural-item/move-session.js +197 -0
  196. package/dist/procedural-item/move-tool.d.ts +5 -0
  197. package/dist/procedural-item/move-tool.d.ts.map +1 -0
  198. package/dist/procedural-item/move-tool.js +193 -0
  199. package/dist/procedural-item/renderer.d.ts +5 -0
  200. package/dist/procedural-item/renderer.d.ts.map +1 -0
  201. package/dist/procedural-item/renderer.js +66 -0
  202. package/dist/ridge-vent/definition.d.ts.map +1 -1
  203. package/dist/ridge-vent/definition.js +1 -0
  204. package/dist/ridge-vent/panel.js +4 -4
  205. package/dist/roof/definition.d.ts.map +1 -1
  206. package/dist/roof/definition.js +4 -1
  207. package/dist/roof/panel-model.d.ts +4 -0
  208. package/dist/roof/panel-model.d.ts.map +1 -0
  209. package/dist/roof/panel-model.js +151 -0
  210. package/dist/roof/panel.d.ts.map +1 -1
  211. package/dist/roof/panel.js +9 -8
  212. package/dist/roof/parametrics.d.ts.map +1 -1
  213. package/dist/roof/parametrics.js +16 -1
  214. package/dist/roof-segment/definition.d.ts.map +1 -1
  215. package/dist/roof-segment/definition.js +1 -0
  216. package/dist/roof-segment/panel.d.ts.map +1 -1
  217. package/dist/roof-segment/panel.js +5 -5
  218. package/dist/roof-segment/parametrics.d.ts.map +1 -1
  219. package/dist/roof-segment/parametrics.js +176 -1
  220. package/dist/scan/definition.d.ts.map +1 -1
  221. package/dist/scan/definition.js +1 -0
  222. package/dist/shared/automatic-run-end-cap.d.ts +1 -0
  223. package/dist/shared/automatic-run-end-cap.d.ts.map +1 -1
  224. package/dist/shared/automatic-run-end-cap.js +10 -0
  225. package/dist/shared/commit-opening-move.d.ts +4 -0
  226. package/dist/shared/commit-opening-move.d.ts.map +1 -0
  227. package/dist/shared/commit-opening-move.js +9 -0
  228. package/dist/shared/curtain-opening-limits.d.ts +14 -0
  229. package/dist/shared/curtain-opening-limits.d.ts.map +1 -0
  230. package/dist/shared/curtain-opening-limits.js +53 -0
  231. package/dist/shared/distribution-run-tool.d.ts +10 -0
  232. package/dist/shared/distribution-run-tool.d.ts.map +1 -1
  233. package/dist/shared/distribution-run-tool.js +56 -11
  234. package/dist/shared/draft-axis-guides.d.ts +0 -6
  235. package/dist/shared/draft-axis-guides.d.ts.map +1 -1
  236. package/dist/shared/draft-axis-guides.js +1 -8
  237. package/dist/shared/hosted-resize.d.ts +12 -0
  238. package/dist/shared/hosted-resize.d.ts.map +1 -0
  239. package/dist/shared/hosted-resize.js +166 -0
  240. package/dist/shared/opening-grid-follow.d.ts +8 -0
  241. package/dist/shared/opening-grid-follow.d.ts.map +1 -0
  242. package/dist/shared/opening-grid-follow.js +12 -0
  243. package/dist/shared/opening-property-preview-host.d.ts +3 -0
  244. package/dist/shared/opening-property-preview-host.d.ts.map +1 -0
  245. package/dist/shared/opening-property-preview-host.js +21 -0
  246. package/dist/shared/opening-property-preview.d.ts +19 -0
  247. package/dist/shared/opening-property-preview.d.ts.map +1 -0
  248. package/dist/shared/opening-property-preview.js +99 -0
  249. package/dist/shared/panel-fields.d.ts +15 -0
  250. package/dist/shared/panel-fields.d.ts.map +1 -0
  251. package/dist/shared/panel-fields.js +31 -0
  252. package/dist/shared/resting-surface-plan.d.ts +4 -0
  253. package/dist/shared/resting-surface-plan.d.ts.map +1 -0
  254. package/dist/shared/resting-surface-plan.js +53 -0
  255. package/dist/shared/surface-counterparts.d.ts +12 -0
  256. package/dist/shared/surface-counterparts.d.ts.map +1 -0
  257. package/dist/shared/surface-counterparts.js +27 -0
  258. package/dist/shared/wall-attach-target.d.ts +1 -0
  259. package/dist/shared/wall-attach-target.d.ts.map +1 -1
  260. package/dist/shared/wall-attach-target.js +4 -1
  261. package/dist/shared/wall-event-from-grid.d.ts +5 -0
  262. package/dist/shared/wall-event-from-grid.d.ts.map +1 -0
  263. package/dist/shared/wall-event-from-grid.js +36 -0
  264. package/dist/shelf/definition.d.ts.map +1 -1
  265. package/dist/shelf/definition.js +5 -2
  266. package/dist/shelf/floorplan-affordances.d.ts.map +1 -1
  267. package/dist/shelf/floorplan-affordances.js +5 -3
  268. package/dist/shelf/floorplan-move.d.ts.map +1 -1
  269. package/dist/shelf/floorplan-move.js +3 -2
  270. package/dist/shelf/floorplan.d.ts.map +1 -1
  271. package/dist/shelf/floorplan.js +9 -2
  272. package/dist/shelf/geometry.d.ts.map +1 -1
  273. package/dist/shelf/geometry.js +2 -10
  274. package/dist/site/renderer.d.ts.map +1 -1
  275. package/dist/site/renderer.js +9 -2
  276. package/dist/skylight/definition.d.ts.map +1 -1
  277. package/dist/skylight/definition.js +1 -0
  278. package/dist/skylight/panel.js +6 -6
  279. package/dist/slab/definition.d.ts.map +1 -1
  280. package/dist/slab/definition.js +4 -0
  281. package/dist/slab/panel.js +1 -1
  282. package/dist/solar-panel/definition.d.ts.map +1 -1
  283. package/dist/solar-panel/definition.js +1 -0
  284. package/dist/solar-panel/panel.js +2 -2
  285. package/dist/spawn/definition.d.ts.map +1 -1
  286. package/dist/spawn/definition.js +1 -0
  287. package/dist/spawn/panel.js +1 -1
  288. package/dist/stair/definition.d.ts.map +1 -1
  289. package/dist/stair/definition.js +2 -0
  290. package/dist/stair/panel.d.ts.map +1 -1
  291. package/dist/stair/panel.js +9 -7
  292. package/dist/stair/parametrics.d.ts.map +1 -1
  293. package/dist/stair/parametrics.js +164 -1
  294. package/dist/stair-segment/definition.d.ts.map +1 -1
  295. package/dist/stair-segment/definition.js +1 -0
  296. package/dist/stair-segment/panel.js +4 -4
  297. package/dist/stair-segment/parametrics.d.ts.map +1 -1
  298. package/dist/stair-segment/parametrics.js +81 -1
  299. package/dist/turbine-vent/definition.d.ts.map +1 -1
  300. package/dist/turbine-vent/definition.js +1 -0
  301. package/dist/turbine-vent/panel.js +1 -1
  302. package/dist/unit/definition.d.ts +10 -0
  303. package/dist/unit/definition.d.ts.map +1 -0
  304. package/dist/unit/definition.js +38 -0
  305. package/dist/unit/index.d.ts +2 -0
  306. package/dist/unit/index.d.ts.map +1 -0
  307. package/dist/unit/index.js +1 -0
  308. package/dist/unit/parametrics.d.ts +3 -0
  309. package/dist/unit/parametrics.d.ts.map +1 -0
  310. package/dist/unit/parametrics.js +4 -0
  311. package/dist/unit/schema.d.ts +2 -0
  312. package/dist/unit/schema.d.ts.map +1 -0
  313. package/dist/unit/schema.js +1 -0
  314. package/dist/unit/unit-panel.d.ts +5 -0
  315. package/dist/unit/unit-panel.d.ts.map +1 -0
  316. package/dist/unit/unit-panel.js +61 -0
  317. package/dist/wall/actions.d.ts +3 -0
  318. package/dist/wall/actions.d.ts.map +1 -0
  319. package/dist/wall/actions.js +56 -0
  320. package/dist/wall/curtain-opening-frame.d.ts +14 -0
  321. package/dist/wall/curtain-opening-frame.d.ts.map +1 -0
  322. package/dist/wall/curtain-opening-frame.js +111 -0
  323. package/dist/wall/curtain-panel-highlight.d.ts +3 -0
  324. package/dist/wall/curtain-panel-highlight.d.ts.map +1 -0
  325. package/dist/wall/curtain-panel-highlight.js +113 -0
  326. package/dist/wall/curtain-wall-adapter.d.ts +3 -0
  327. package/dist/wall/curtain-wall-adapter.d.ts.map +1 -0
  328. package/dist/wall/curtain-wall-adapter.js +55 -0
  329. package/dist/wall/curtain-wall-floorplan.d.ts +3 -0
  330. package/dist/wall/curtain-wall-floorplan.d.ts.map +1 -0
  331. package/dist/wall/curtain-wall-floorplan.js +91 -0
  332. package/dist/wall/curtain-wall-geometry.d.ts +4 -0
  333. package/dist/wall/curtain-wall-geometry.d.ts.map +1 -0
  334. package/dist/wall/curtain-wall-geometry.js +226 -0
  335. package/dist/wall/curtain-wall-layout.d.ts +16 -0
  336. package/dist/wall/curtain-wall-layout.d.ts.map +1 -0
  337. package/dist/wall/curtain-wall-layout.js +176 -0
  338. package/dist/wall/curtain-wall-materials.d.ts +5 -0
  339. package/dist/wall/curtain-wall-materials.d.ts.map +1 -0
  340. package/dist/wall/curtain-wall-materials.js +55 -0
  341. package/dist/wall/curtain-wall-panel.d.ts +14 -0
  342. package/dist/wall/curtain-wall-panel.d.ts.map +1 -0
  343. package/dist/wall/curtain-wall-panel.js +167 -0
  344. package/dist/wall/curtain-wall-piece-geometry.d.ts +5 -0
  345. package/dist/wall/curtain-wall-piece-geometry.d.ts.map +1 -0
  346. package/dist/wall/curtain-wall-piece-geometry.js +220 -0
  347. package/dist/wall/curtain-wall-shadow.d.ts +4 -0
  348. package/dist/wall/curtain-wall-shadow.d.ts.map +1 -0
  349. package/dist/wall/curtain-wall-shadow.js +15 -0
  350. package/dist/wall/definition.d.ts +0 -15
  351. package/dist/wall/definition.d.ts.map +1 -1
  352. package/dist/wall/definition.js +65 -4
  353. package/dist/wall/drawing-mode.d.ts +12 -0
  354. package/dist/wall/drawing-mode.d.ts.map +1 -0
  355. package/dist/wall/drawing-mode.js +38 -0
  356. package/dist/wall/floorplan-tool.d.ts +4 -0
  357. package/dist/wall/floorplan-tool.d.ts.map +1 -0
  358. package/dist/wall/floorplan-tool.js +107 -0
  359. package/dist/wall/floorplan.d.ts.map +1 -1
  360. package/dist/wall/floorplan.js +6 -2
  361. package/dist/wall/length-patch.d.ts +3 -0
  362. package/dist/wall/length-patch.d.ts.map +1 -0
  363. package/dist/wall/length-patch.js +14 -0
  364. package/dist/wall/move-tool.d.ts.map +1 -1
  365. package/dist/wall/move-tool.js +23 -1
  366. package/dist/wall/paint.d.ts.map +1 -1
  367. package/dist/wall/paint.js +39 -4
  368. package/dist/wall/panel-model.d.ts +4 -0
  369. package/dist/wall/panel-model.d.ts.map +1 -0
  370. package/dist/wall/panel-model.js +117 -0
  371. package/dist/wall/panel.d.ts.map +1 -1
  372. package/dist/wall/panel.js +20 -24
  373. package/dist/wall/property-preview.d.ts +7 -0
  374. package/dist/wall/property-preview.d.ts.map +1 -0
  375. package/dist/wall/property-preview.js +31 -0
  376. package/dist/wall/rectangle-command.d.ts +149 -0
  377. package/dist/wall/rectangle-command.d.ts.map +1 -0
  378. package/dist/wall/rectangle-command.js +22 -0
  379. package/dist/wall/rectangle-tool.d.ts +2 -0
  380. package/dist/wall/rectangle-tool.d.ts.map +1 -0
  381. package/dist/wall/rectangle-tool.js +147 -0
  382. package/dist/wall/renderer.d.ts.map +1 -1
  383. package/dist/wall/renderer.js +7 -4
  384. package/dist/wall/slots.d.ts +2 -2
  385. package/dist/wall/slots.d.ts.map +1 -1
  386. package/dist/wall/slots.js +10 -2
  387. package/dist/wall/split-floorplan-layer.d.ts +4 -0
  388. package/dist/wall/split-floorplan-layer.d.ts.map +1 -0
  389. package/dist/wall/split-floorplan-layer.js +71 -0
  390. package/dist/wall/split-pointer.d.ts +3 -0
  391. package/dist/wall/split-pointer.d.ts.map +1 -0
  392. package/dist/wall/split-pointer.js +95 -0
  393. package/dist/wall/split-preview.d.ts +55 -0
  394. package/dist/wall/split-preview.d.ts.map +1 -0
  395. package/dist/wall/split-preview.js +106 -0
  396. package/dist/wall/split-session.d.ts +16 -0
  397. package/dist/wall/split-session.d.ts.map +1 -0
  398. package/dist/wall/split-session.js +138 -0
  399. package/dist/wall/split-store.d.ts +16 -0
  400. package/dist/wall/split-store.d.ts.map +1 -0
  401. package/dist/wall/split-store.js +6 -0
  402. package/dist/wall/split-tool.d.ts +10 -0
  403. package/dist/wall/split-tool.d.ts.map +1 -0
  404. package/dist/wall/split-tool.js +95 -0
  405. package/dist/wall/system.d.ts.map +1 -1
  406. package/dist/wall/system.js +3 -1
  407. package/dist/wall/tool.d.ts.map +1 -1
  408. package/dist/wall/tool.js +14 -6
  409. package/dist/wall/wall-batch-system.d.ts.map +1 -1
  410. package/dist/wall/wall-batch-system.js +3 -0
  411. package/dist/window/definition.d.ts.map +1 -1
  412. package/dist/window/definition.js +48 -1
  413. package/dist/window/floorplan-affordances.d.ts.map +1 -1
  414. package/dist/window/floorplan-affordances.js +8 -10
  415. package/dist/window/move-tool.d.ts.map +1 -1
  416. package/dist/window/move-tool.js +4 -6
  417. package/dist/window/panel.d.ts.map +1 -1
  418. package/dist/window/panel.js +22 -60
  419. package/dist/window/tool.d.ts.map +1 -1
  420. package/dist/window/tool.js +34 -2
  421. package/dist/window/window-math.d.ts +1 -1
  422. package/dist/window/window-math.d.ts.map +1 -1
  423. package/dist/window/window-math.js +8 -11
  424. package/dist/zone/definition.d.ts.map +1 -1
  425. package/dist/zone/definition.js +8 -1
  426. package/dist/zone/floorplan.d.ts +1 -3
  427. package/dist/zone/floorplan.d.ts.map +1 -1
  428. package/dist/zone/floorplan.js +43 -28
  429. package/dist/zone/quantities-panel.d.ts.map +1 -1
  430. package/dist/zone/quantities-panel.js +32 -44
  431. package/dist/zone/renderer.d.ts.map +1 -1
  432. package/dist/zone/renderer.js +21 -7
  433. package/dist/zone/unit-membership.d.ts +12 -0
  434. package/dist/zone/unit-membership.d.ts.map +1 -0
  435. package/dist/zone/unit-membership.js +22 -0
  436. package/package.json +15 -9
  437. package/dist/shared/opening-documentation-fields.d.ts +0 -16
  438. package/dist/shared/opening-documentation-fields.d.ts.map +0 -1
  439. package/dist/shared/opening-documentation-fields.js +0 -54
@@ -1,92 +1,19 @@
1
- import { collectAlignmentAnchors, getBlockFaceFrame, getRoofWallFaceFrame, getScaledDimensions, movingFootprintAnchors, roofFacePointToSegment, useLiveNodeOverrides, useScene, } from '@pascal-app/core';
2
- import { applyFloorplanAlignment, isGridSnapActive, isMagneticSnapActive, useEditor, } from '@pascal-app/editor';
1
+ import { cascadeDirty, clearFaceHostItemFields, collectAlignmentAnchors, collectDescendants, createSceneApi, getBlockFaceFrame, getScaledDimensions, getSurfaceProvider, movingFootprintAnchors, nodeRegistry, resolveSupportSlabPatch, resolveSurfacePlacement, surfaceRegionContainsPoint, useLiveNodeOverrides, useScene, } from '@pascal-app/core';
2
+ import { boundsOf, boxCorners, composeFrames, frame, transformPoint, } from '@pascal-app/core/procedural-items';
3
+ import { applyFloorplanAlignment, isGridSnapActive, isMagneticSnapActive, surfaceAttachmentId, surfaceFramePose, updateSurfaceNode, useEditor, useInteractionScope, } from '@pascal-app/editor';
3
4
  import { createFloorplanCursorResolver } from '../shared/floorplan-cursor';
5
+ import { restingNodePlanFrame } from '../shared/resting-surface-plan';
4
6
  import { findClosestWallInPlan, snapLocalXToNeighbors } from '../shared/wall-attach-target';
5
- function rotateVec(x, z, rotationY) {
6
- const c = Math.cos(rotationY);
7
- const s = Math.sin(rotationY);
8
- return [x * c + z * s, -x * s + z * c];
9
- }
10
- function resolveItemPlanTransform(item, nodes, cache = new Map()) {
11
- const cached = cache.get(item.id);
12
- if (cached)
13
- return cached;
14
- const localRotation = item.rotation[1] ?? 0;
15
- let result = {
16
- point: [item.position[0], item.position[2]],
17
- rotation: localRotation,
7
+ import { resolveItemTransform } from './floorplan';
8
+ function resolveItemPlanTransform(item, nodes) {
9
+ const pose = resolveItemTransform(item, { resolve: (id) => nodes[id] });
10
+ return {
11
+ point: pose ? [pose.x, pose.y] : [item.position[0], item.position[2]],
12
+ rotation: pose?.rotation ?? item.rotation[1],
18
13
  };
19
- const parent = item.parentId ? nodes[item.parentId] : null;
20
- if (parent?.type === 'wall') {
21
- const wallRotation = -Math.atan2(parent.end[1] - parent.start[1], parent.end[0] - parent.start[0]);
22
- const wallLocalZ = item.asset.attachTo === 'wall-side'
23
- ? ((parent.thickness ?? 0.1) / 2) * (item.side === 'front' ? 1 : -1)
24
- : item.position[2];
25
- const [offsetX, offsetZ] = rotateVec(item.position[0], wallLocalZ, wallRotation);
26
- result = {
27
- point: [parent.start[0] + offsetX, parent.start[1] + offsetZ],
28
- rotation: wallRotation + localRotation,
29
- };
30
- }
31
- else if (parent?.type === 'shelf') {
32
- const shelf = parent;
33
- const [offsetX, offsetZ] = rotateVec(item.position[0], item.position[2], shelf.rotation[1] ?? 0);
34
- result = {
35
- point: [shelf.position[0] + offsetX, shelf.position[2] + offsetZ],
36
- rotation: (shelf.rotation[1] ?? 0) + localRotation,
37
- };
38
- }
39
- else if (parent?.type === 'item') {
40
- const parentTransform = resolveItemPlanTransform(parent, nodes, cache);
41
- const [offsetX, offsetZ] = rotateVec(item.position[0], item.position[2], parentTransform.rotation);
42
- result = {
43
- point: [parentTransform.point[0] + offsetX, parentTransform.point[1] + offsetZ],
44
- rotation: parentTransform.rotation + localRotation,
45
- };
46
- }
47
- else if (parent?.type === 'roof-segment') {
48
- // Roof-hosted wall item: FACE-LOCAL position mapped through the face
49
- // frame, then composed through the segment's and roof's yaw +
50
- // position into level-local plan coords — without this the drag seed
51
- // jumps off the roof at move start.
52
- const segment = parent;
53
- const roof = segment.parentId
54
- ? nodes[segment.parentId]
55
- : undefined;
56
- if (roof?.type === 'roof' && item.roofFace) {
57
- const frame = getRoofWallFaceFrame(segment, item.roofFace);
58
- const segLocal = roofFacePointToSegment(segment, item.roofFace, item.position);
59
- const [sx, sz] = rotateVec(segLocal[0], segLocal[2], segment.rotation ?? 0);
60
- const [rx, rz] = rotateVec(sx + segment.position[0], sz + segment.position[2], roof.rotation ?? 0);
61
- result = {
62
- point: [rx + roof.position[0], rz + roof.position[2]],
63
- rotation: (roof.rotation ?? 0) + (segment.rotation ?? 0) + frame.yaw + localRotation,
64
- };
65
- }
66
- }
67
- else if (parent?.type === 'block' && item.blockFaceId) {
68
- const frame = getBlockFaceFrame(parent.topology, item.blockFaceId);
69
- if (frame) {
70
- const localX = frame.origin[0] +
71
- frame.xAxis[0] * item.position[0] +
72
- frame.yAxis[0] * item.position[1] +
73
- frame.normal[0] * item.position[2];
74
- const localZ = frame.origin[2] +
75
- frame.xAxis[2] * item.position[0] +
76
- frame.yAxis[2] * item.position[1] +
77
- frame.normal[2] * item.position[2];
78
- const [offsetX, offsetZ] = rotateVec(localX, localZ, parent.rotation ?? 0);
79
- result = {
80
- point: [parent.position[0] + offsetX, parent.position[2] + offsetZ],
81
- rotation: (parent.rotation ?? 0) - Math.atan2(frame.xAxis[2], frame.xAxis[0]) + localRotation,
82
- };
83
- }
84
- }
85
- cache.set(item.id, result);
86
- return result;
87
14
  }
88
- function resolveItemPlanPoint(item, nodes, cache = new Map()) {
89
- return resolveItemPlanTransform(item, nodes, cache).point;
15
+ function resolveItemPlanPoint(item, nodes) {
16
+ return resolveItemPlanTransform(item, nodes).point;
90
17
  }
91
18
  function createPlanarMovePointResolver(originalPlanPoint, node) {
92
19
  const resolveCursor = createFloorplanCursorResolver({
@@ -200,47 +127,252 @@ function buildWallItemSession(node, startLevelId) {
200
127
  * bookkeeping and the item drops out of the level→children DFS the
201
128
  * floor-plan layer walks → the polygon stops rendering mid-drag.
202
129
  *
203
- * For the 2D move we just translate `position` in level-local coords and
204
- * leave the parent as the level (matching the 3D `detachItemSurfaceToFloor`
205
- * in `use-placement-coordinator.tsx`). Snap to the 0.5m grid unless the
206
- * user holds Shift.
130
+ * A host exit converts the pose to the level frame, matching the 3D
131
+ * `detachItemSurfaceToFloor`; inherited support lift stays out of stored Y.
207
132
  */
208
133
  function buildFloorItemSession(node, startLevelId, nodes) {
209
- const rotationY = node.rotation[1] ?? 0;
210
- const resolvePlanPoint = createPlanarMovePointResolver(resolveItemPlanPoint(node, nodes), node);
134
+ const host = node.parentId ? nodes[node.parentId] : undefined;
135
+ const hosted = host && host.type !== 'level';
136
+ const surfaceId = surfaceAttachmentId(node);
137
+ const hostPose = surfaceFramePose(node.parentId, surfaceId, node, false);
138
+ const planTransform = resolveItemPlanTransform(node, nodes);
139
+ const levelFrame = hosted ? restingNodePlanFrame(node, (id) => nodes[id]) : null;
140
+ const rotationY = levelFrame
141
+ ? Math.atan2(levelFrame.axes[2][0], levelFrame.axes[2][2])
142
+ : planTransform.rotation;
143
+ const levelRotation = [...node.rotation];
144
+ if (hosted) {
145
+ if (node.type === 'procedural-item') {
146
+ // Generated footprints use the query frame; catalog footprints keep their legacy plan mapping.
147
+ planTransform.point = [levelFrame.position[0], levelFrame.position[2]];
148
+ const hostFrame = restingNodePlanFrame(host, (id) => nodes[id]);
149
+ const headingPose = surfaceFramePose(node.parentId, surfaceId, { position: node.position, rotation: [0, node.rotation[1], 0] }, false);
150
+ levelRotation[1] =
151
+ headingPose.rotation[1] + Math.atan2(hostFrame.axes[2][0], hostFrame.axes[2][2]);
152
+ }
153
+ else {
154
+ levelRotation.splice(0, 3, hostPose.rotation[0], rotationY, hostPose.rotation[2]);
155
+ }
156
+ }
157
+ if (host?.type === 'block' && node.blockFaceId)
158
+ levelRotation.splice(0, 3, 0, rotationY, 0);
159
+ const resolvePlanPoint = createPlanarMovePointResolver(planTransform.point, node);
211
160
  // Alignment candidates gathered once — scene is stable during the drag.
212
161
  const candidates = collectAlignmentAnchors(nodes, node.id);
162
+ const scene = createSceneApi(useScene);
163
+ const bounds = nodeRegistry.get(node.type)?.capabilities.dragBounds?.(node, nodes);
164
+ const dimensions = bounds?.size ?? getScaledDimensions(node);
165
+ const localBounds = bounds?.center
166
+ ? {
167
+ min: bounds.center.map((v, i) => v - dimensions[i] / 2),
168
+ max: bounds.center.map((v, i) => v + dimensions[i] / 2),
169
+ }
170
+ : {
171
+ min: [-dimensions[0] / 2, 0, -dimensions[2] / 2],
172
+ max: [dimensions[0] / 2, dimensions[1], dimensions[2] / 2],
173
+ };
174
+ const originalBounds = boundsOf(boxCorners(localBounds.min, localBounds.max).map((p) => transformPoint(frame(hostPose.position, hostPose.rotation), p)));
175
+ const originalPlacement = hosted
176
+ ? resolveSurfacePlacement({
177
+ host,
178
+ childKind: node.type,
179
+ childId: node.id,
180
+ childFootprint: {
181
+ size: dimensions,
182
+ rotationY: hostPose.rotation[1],
183
+ rotation: hostPose.rotation,
184
+ localBounds,
185
+ },
186
+ hit: {
187
+ point: [
188
+ (originalBounds.min[0] + originalBounds.max[0]) / 2,
189
+ originalBounds.min[1],
190
+ (originalBounds.min[2] + originalBounds.max[2]) / 2,
191
+ ],
192
+ normalWorldY: 1,
193
+ },
194
+ origin: hostPose.position,
195
+ scene,
196
+ })
197
+ : null;
198
+ const retainedSurfaceId = hosted && originalPlacement
199
+ ? getSurfaceProvider(host)
200
+ .surfaces?.(host, { scene })
201
+ .find((s) => s.id === (surfaceId ?? originalPlacement.surfaceId))?.id
202
+ : undefined;
203
+ const markMoved = () => {
204
+ for (const id of new Set([
205
+ ...cascadeDirty(node.id, { scene }),
206
+ ...collectDescendants(node.id, { scene }),
207
+ ]))
208
+ useScene.getState().markDirty(id);
209
+ };
213
210
  let lastPatch = null;
214
- return {
211
+ let lastInput = null;
212
+ let commitBlocked = false;
213
+ let lastHostedPatch = {
214
+ parentId: node.parentId,
215
+ position: [...node.position],
216
+ rotation: [...node.rotation],
217
+ supportSlabId: undefined,
218
+ };
219
+ const session = {
215
220
  affectedIds: [node.id],
216
- apply({ planPoint }) {
221
+ apply(input) {
222
+ lastInput = input;
223
+ commitBlocked = false;
224
+ const { planPoint } = input;
217
225
  const gridSnapped = resolvePlanPoint(planPoint);
218
226
  // Figma-style alignment layered on the grid snap, mode-driven (matching 3D):
219
227
  // guides are DISPLAYED in every snapping mode; the magnetic pull onto them
220
228
  // is applied only in "lines" mode (`applySnap`).
221
229
  const { point: snapped } = applyFloorplanAlignment(gridSnapped, movingFootprintAnchors(node, gridSnapped[0], gridSnapped[1], rotationY), candidates, { applySnap: isMagneticSnapActive() });
222
- const sourceY = node.position[1];
223
- const nextPosition = [snapped[0], sourceY, snapped[1]];
230
+ const liveHost = host && useScene.getState().nodes[host.id];
231
+ if (liveHost?.type === 'block' && node.blockFaceId) {
232
+ const face = getBlockFaceFrame(liveHost.topology, node.blockFaceId);
233
+ if (face && face.normal[1] > 0.99) {
234
+ const hostFrame = restingNodePlanFrame(liveHost, (id) => useScene.getState().nodes[id]);
235
+ const surface = composeFrames(hostFrame, {
236
+ position: face.origin,
237
+ axes: [face.xAxis, face.yAxis, face.normal],
238
+ });
239
+ const delta = [snapped[0] - surface.position[0], 0, snapped[1] - surface.position[2]];
240
+ const uv = surface.axes
241
+ .slice(0, 2)
242
+ .map((axis) => axis.reduce((sum, v, i) => sum + v * delta[i], 0));
243
+ const vertices = new Map(liveHost.topology.vertices.map((v) => [v.id, v.position]));
244
+ const polygon = liveHost.topology.faces
245
+ .find((f) => f.id === node.blockFaceId)
246
+ .vertexIds.map((id) => {
247
+ const v = vertices.get(id);
248
+ const delta = v.map((value, i) => value - face.origin[i]);
249
+ return [face.xAxis, face.yAxis].map((axis) => axis.reduce((sum, value, i) => sum + value * delta[i], 0));
250
+ });
251
+ if (surfaceRegionContainsPoint({ kind: 'polygon', points: polygon }, uv)) {
252
+ lastPatch = {
253
+ parentId: liveHost.id,
254
+ position: [uv[0], uv[1], node.position[2]],
255
+ rotation: [...node.rotation],
256
+ supportSlabId: undefined,
257
+ };
258
+ useLiveNodeOverrides.getState().set(node.id, lastPatch);
259
+ markMoved();
260
+ return;
261
+ }
262
+ }
263
+ }
264
+ if (hosted && liveHost && (liveHost.type !== 'block' || !node.blockFaceId)) {
265
+ const host = liveHost;
266
+ const retainedSurface = getSurfaceProvider(host)
267
+ .surfaces?.(host, { scene })
268
+ .find((s) => s.id === retainedSurfaceId);
269
+ const hostFrame = restingNodePlanFrame(host, (id) => useScene.getState().nodes[id]);
270
+ if (host.type === 'item') {
271
+ const plan = resolveItemTransform(host, {
272
+ resolve: (id) => useScene.getState().nodes[id],
273
+ });
274
+ if (plan) {
275
+ hostFrame.position[0] = plan.x;
276
+ hostFrame.position[2] = plan.y;
277
+ }
278
+ }
279
+ const surfaceFrame = composeFrames(hostFrame, frame(retainedSurface ? [...retainedSurface.position] : [0, hostPose.position[1], 0], retainedSurface ? [...(retainedSurface.rotation ?? [0, 0, 0])] : [0, 0, 0]));
280
+ const normal = surfaceFrame.axes[1];
281
+ const localRotation = originalPlacement?.surfaceLocal?.rotation ?? hostPose.rotation;
282
+ const bottomOffset = retainedSurface
283
+ ? -Math.min(...boxCorners(localBounds.min, localBounds.max).map((p) => transformPoint(frame([0, 0, 0], [...localRotation]), p)[1]))
284
+ : 0;
285
+ const y = surfaceFrame.position[1] +
286
+ (bottomOffset -
287
+ normal[0] * (snapped[0] - surfaceFrame.position[0]) -
288
+ normal[2] * (snapped[1] - surfaceFrame.position[2])) /
289
+ normal[1];
290
+ const delta = [
291
+ snapped[0] - hostFrame.position[0],
292
+ y - hostFrame.position[1],
293
+ snapped[1] - hostFrame.position[2],
294
+ ];
295
+ const local = hostFrame.axes.map((axis) => axis.reduce((sum, v, i) => sum + v * delta[i], 0));
296
+ const projected = boundsOf(boxCorners(localBounds?.min ?? [-dimensions[0] / 2, 0, -dimensions[2] / 2], localBounds?.max ?? [dimensions[0] / 2, dimensions[1], dimensions[2] / 2]).map((p) => transformPoint(frame(local, hostPose.rotation), p)));
297
+ let occupied = false;
298
+ const pose = resolveSurfacePlacement({
299
+ host,
300
+ surface: retainedSurface,
301
+ childKind: node.type,
302
+ childId: node.id,
303
+ childFootprint: {
304
+ size: dimensions,
305
+ rotationY: hostPose.rotation[1],
306
+ rotation: hostPose.rotation,
307
+ localBounds,
308
+ },
309
+ hit: {
310
+ point: [
311
+ (projected.min[0] + projected.max[0]) / 2,
312
+ projected.min[1],
313
+ (projected.min[2] + projected.max[2]) / 2,
314
+ ],
315
+ normalWorldY: 1,
316
+ },
317
+ origin: local,
318
+ scene: createSceneApi(useScene),
319
+ onReject: (reason) => {
320
+ occupied = reason === 'surface-occupied';
321
+ },
322
+ });
323
+ if (occupied) {
324
+ commitBlocked = useInteractionScope.getState().ownedSubtree?.creation.rootId === node.id;
325
+ lastPatch = lastHostedPatch;
326
+ useLiveNodeOverrides.getState().set(node.id, lastPatch);
327
+ markMoved();
328
+ return;
329
+ }
330
+ if (pose &&
331
+ (pose.childFrame === 'surface-local' ? pose.surfaceId === surfaceId : surfaceId === null)) {
332
+ const stored = pose.childFrame === 'surface-local' ? pose.surfaceLocal : pose;
333
+ lastPatch = {
334
+ parentId: host.id,
335
+ position: [...stored.position],
336
+ rotation: [...node.rotation],
337
+ supportSlabId: undefined,
338
+ };
339
+ lastHostedPatch = lastPatch;
340
+ useLiveNodeOverrides.getState().set(node.id, lastPatch);
341
+ markMoved();
342
+ return;
343
+ }
344
+ }
345
+ const nextPosition = [
346
+ snapped[0],
347
+ hosted ? 0 : node.position[1],
348
+ snapped[1],
349
+ ];
224
350
  lastPatch = {
351
+ ...(node.blockFaceId ? clearFaceHostItemFields(host) : {}),
225
352
  position: nextPosition,
353
+ rotation: levelRotation,
226
354
  // Keep parent as the level we resolved at session-start. If
227
355
  // somehow it's null (e.g. orphaned item), fall back to the
228
356
  // existing parent so we don't write `null` and detach.
229
357
  parentId: startLevelId ?? node.parentId,
230
358
  };
359
+ Object.assign(lastPatch, resolveSupportSlabPatch({ ...node, ...lastPatch }, nodes));
231
360
  useLiveNodeOverrides.getState().set(node.id, lastPatch);
232
- useScene.getState().markDirty(node.id);
361
+ markMoved();
233
362
  },
234
363
  canCommit() {
235
- return lastPatch !== null;
364
+ return lastPatch !== null && !commitBlocked;
236
365
  },
237
366
  commit() {
367
+ if (lastInput)
368
+ session.apply(lastInput);
238
369
  if (!lastPatch)
239
370
  return;
371
+ updateSurfaceNode(node.id, lastPatch);
240
372
  useLiveNodeOverrides.getState().clear(node.id);
241
- useScene.getState().updateNodes([{ id: node.id, data: lastPatch }]);
242
373
  },
243
374
  };
375
+ return session;
244
376
  }
245
377
  /**
246
378
  * Ceiling items reparent to whichever ceiling polygon contains the
@@ -286,7 +418,7 @@ function buildSurfaceItemSession(node, startLevelId, targetKind) {
286
418
  * valid target: floor items are parented to the level, not the slab,
287
419
  * because slabs don't carry a `children` field on their schema.
288
420
  */
289
- function findContainingSurface(point, nodes, parentLevelId, targetKind) {
421
+ export function findContainingSurface(point, nodes, parentLevelId, targetKind) {
290
422
  if (!parentLevelId)
291
423
  return null;
292
424
  const level = nodes[parentLevelId];
@@ -1,4 +1,26 @@
1
1
  import { type FloorplanGeometry, type GeometryContext, type ItemNode } from '@pascal-app/core';
2
+ /**
3
+ * Stage C floor-plan builder for item.
4
+ *
5
+ * Items can be parented to a wall, ceiling, slab, or another item.
6
+ * Position is in the parent's local frame, so we walk the parent chain
7
+ * via `ctx.resolve` to compute the world-space (level-local) transform.
8
+ *
9
+ * Mirrors `getItemFloorplanTransform` from editor/lib/floorplan/items.ts
10
+ * but uses the registry's resolve callback instead of a node map. Logic
11
+ * is identical so visual output matches the legacy.
12
+ *
13
+ * Returns a rotated rectangle of width × depth at the resolved position.
14
+ * Phase 5 follow-up may render `asset.floorPlanUrl` as a custom image
15
+ * overlay when present.
16
+ */
17
+ type Transform = {
18
+ x: number;
19
+ y: number;
20
+ rotation: number;
21
+ };
22
+ export declare function resolveItemTransform(item: ItemNode, ctx: GeometryContext, cache?: Map<`roof_${string}` | `rseg_${string}` | `site_${string}` | `building_${string}` | `level_${string}` | `elevator_${string}` | `unit_${string}` | `zone_${string}` | `block_${string}` | `ceiling_${string}` | `item_${string}` | `procedural-item_${string}` | `column_${string}` | `construction-dimension_${string}` | `wall_${string}` | `slab_${string}` | `fence_${string}` | `structural-grid_${string}` | `imesh_${string}` | `stair_${string}` | `scan_${string}` | `guide_${string}` | `measurement_${string}` | `spawn_${string}` | `shelf_${string}` | `duct-segment_${string}` | `duct-fitting_${string}` | `duct-terminal_${string}` | `hvac-equipment_${string}` | `lineset_${string}` | `liquid-line_${string}` | `pipe-segment_${string}` | `pipe-fitting_${string}` | `pipe-trap_${string}` | `leanto_${string}` | `door_${string}` | `window_${string}` | `cabinet_${string}` | `cabinet-module_${string}` | `sseg_${string}` | `bvent_${string}` | `rvent_${string}` | `tvent_${string}` | `cupola_${string}` | `eyebrow-vent_${string}` | `gutter_${string}` | `chimney_${string}` | `solarpanel_${string}` | `skylight_${string}` | `dormer_${string}` | `downspout_${string}`, Transform | null>): Transform | null;
2
23
  export declare function buildItemContextualDimensions(node: ItemNode, ctx: GeometryContext): FloorplanGeometry | null;
3
24
  export declare function buildItemFloorplan(node: ItemNode, ctx: GeometryContext): FloorplanGeometry | null;
25
+ export {};
4
26
  //# sourceMappingURL=floorplan.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"floorplan.d.ts","sourceRoot":"","sources":["../../src/item/floorplan.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,iBAAiB,EAEtB,KAAK,eAAe,EAIpB,KAAK,QAAQ,EAId,MAAM,kBAAkB,CAAA;AAsKzB,wBAAgB,6BAA6B,CAC3C,IAAI,EAAE,QAAQ,EACd,GAAG,EAAE,eAAe,GACnB,iBAAiB,GAAG,IAAI,CA+C1B;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,eAAe,GAAG,iBAAiB,GAAG,IAAI,CAmGjG"}
1
+ {"version":3,"file":"floorplan.d.ts","sourceRoot":"","sources":["../../src/item/floorplan.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,iBAAiB,EAEtB,KAAK,eAAe,EAKpB,KAAK,QAAQ,EAId,MAAM,kBAAkB,CAAA;AAIzB;;;;;;;;;;;;;;GAcG;AACH,KAAK,SAAS,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAA;AA2D3D,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,QAAQ,EACd,GAAG,EAAE,eAAe,EACpB,KAAK,0pCAAyC,GAC7C,SAAS,GAAG,IAAI,CAwKlB;AAED,wBAAgB,6BAA6B,CAC3C,IAAI,EAAE,QAAQ,EACd,GAAG,EAAE,eAAe,GACnB,iBAAiB,GAAG,IAAI,CA+C1B;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,eAAe,GAAG,iBAAiB,GAAG,IAAI,CAmGjG"}
@@ -1,5 +1,6 @@
1
- import { getBlockFaceFrame, getRoofWallFaceFrame, getScaledDimensions, roofFacePointToSegment, useLiveTransforms, } from '@pascal-app/core';
1
+ import { getBlockFaceFrame, getEffectiveNode, getRoofWallFaceFrame, getScaledDimensions, roofFacePointToSegment, useLiveTransforms, } from '@pascal-app/core';
2
2
  import { formatLinearMeasurement, readFloorplanMetricNotationOverride } from '@pascal-app/editor';
3
+ import { restingNodePlanFrame } from '../shared/resting-surface-plan';
3
4
  // Plan-space rotation convention used by the legacy `rotatePlanVector`
4
5
  // in `editor/src/lib/floorplan/geometry.ts`. This is a CLOCKWISE rotation
5
6
  // — the registry-side equivalent of the canonical floor-plan transform
@@ -12,10 +13,57 @@ function rotateVec(x, y, angle) {
12
13
  const s = Math.sin(angle);
13
14
  return [x * c + y * s, -x * s + y * c];
14
15
  }
15
- function resolveItemTransform(item, ctx, cache = new Map()) {
16
+ function needsFullAncestorFrame(item, ctx) {
17
+ let id = item.parentId;
18
+ const visited = new Set([item.id]);
19
+ while (id && !visited.has(id)) {
20
+ visited.add(id);
21
+ const parent = ctx.resolve(id);
22
+ if (!parent || parent.type === 'level')
23
+ break;
24
+ if (![
25
+ 'wall',
26
+ 'ceiling',
27
+ 'roof',
28
+ 'roof-segment',
29
+ 'item',
30
+ 'shelf',
31
+ 'cabinet',
32
+ 'cabinet-module',
33
+ 'procedural-item',
34
+ 'block',
35
+ 'slab',
36
+ ].includes(parent.type)) {
37
+ const effective = getEffectiveNode(parent);
38
+ const live = useLiveTransforms.getState().get(parent.id);
39
+ const position = live?.position ?? effective.position;
40
+ const rotation = effective.rotation;
41
+ // Main's level-local fallback already handles identity plugins directly on a level.
42
+ if (parent.type === 'column' ||
43
+ (parent.parentId && ctx.resolve(parent.parentId)?.type !== 'level') ||
44
+ position?.some((v) => v !== 0) ||
45
+ live?.rotation ||
46
+ (Array.isArray(rotation) ? rotation.some((v) => v !== 0) : rotation))
47
+ return true;
48
+ }
49
+ id = parent.parentId;
50
+ }
51
+ return false;
52
+ }
53
+ export function resolveItemTransform(item, ctx, cache = new Map()) {
16
54
  const cached = cache.get(item.id);
17
55
  if (cached !== undefined)
18
56
  return cached;
57
+ if (needsFullAncestorFrame(item, ctx)) {
58
+ const f = restingNodePlanFrame(item, ctx.resolve);
59
+ const result = {
60
+ x: f.position[0],
61
+ y: f.position[2],
62
+ rotation: Math.atan2(f.axes[2][0], f.axes[2][2]),
63
+ };
64
+ cache.set(item.id, result);
65
+ return result;
66
+ }
19
67
  const localRotation = item.rotation[1] ?? 0;
20
68
  let result = null;
21
69
  const parentNode = item.parentId
@@ -47,6 +95,16 @@ function resolveItemTransform(item, ctx, cache = new Map()) {
47
95
  };
48
96
  }
49
97
  }
98
+ else if (parentNode?.type === 'cabinet' ||
99
+ parentNode?.type === 'cabinet-module' ||
100
+ parentNode?.type === 'procedural-item') {
101
+ const f = restingNodePlanFrame(item, ctx.resolve);
102
+ result = {
103
+ x: f.position[0],
104
+ y: f.position[2],
105
+ rotation: Math.atan2(f.axes[2][0], f.axes[2][2]),
106
+ };
107
+ }
50
108
  else if (parentNode?.type === 'shelf') {
51
109
  // Shelf-hosted item: `item.position` is in shelf-local coords. The
52
110
  // shelf has its own `position` + `rotation[1]` in its parent (level)
@@ -64,6 +122,18 @@ function resolveItemTransform(item, ctx, cache = new Map()) {
64
122
  // shelf's own entry follows via the layer's effectiveNode override.
65
123
  const shelf = parentNode;
66
124
  const live = useLiveTransforms.getState().get(shelf.id);
125
+ if (shelf.parentId &&
126
+ ['item', 'shelf', 'cabinet', 'cabinet-module', 'procedural-item'].includes(ctx.resolve(shelf.parentId)?.type ?? '')) {
127
+ const parentT = resolveItemTransform({
128
+ ...shelf,
129
+ position: live?.position ?? shelf.position,
130
+ rotation: [0, live?.rotation ?? shelf.rotation[1], 0],
131
+ }, ctx, cache);
132
+ if (!parentT)
133
+ return null;
134
+ const [x, y] = rotateVec(item.position[0], item.position[2], parentT.rotation);
135
+ return { x: parentT.x + x, y: parentT.y + y, rotation: parentT.rotation + localRotation };
136
+ }
67
137
  const shelfX = live?.position[0] ?? shelf.position[0];
68
138
  const shelfZ = live?.position[2] ?? shelf.position[2];
69
139
  const shelfRotationY = live?.rotation ?? shelf.rotation[1] ?? 0;
@@ -26,7 +26,7 @@ import { type PlacementState } from '@pascal-app/editor';
26
26
  * and dropped from editor.
27
27
  */
28
28
  export declare function getInitialState(node: ItemNode, parent?: AnyNode | undefined): PlacementState;
29
- export declare function MoveItemTool({ node }: {
29
+ export declare function MoveItemTool({ node: source }: {
30
30
  node: ItemNode;
31
31
  }): import("react").JSX.Element;
32
32
  export default MoveItemTool;
@@ -1 +1 @@
1
- {"version":3,"file":"move-tool.d.ts","sourceRoot":"","sources":["../../src/item/move-tool.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,OAAO,EAAkB,KAAK,QAAQ,EAAY,MAAM,kBAAkB,CAAA;AACxF,OAAO,EACL,KAAK,cAAc,EAKpB,MAAM,oBAAoB,CAAA;AAG3B;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,QAAQ,EACd,MAAM,GAAE,OAAO,GAAG,SAEL,GACZ,cAAc,CA4EhB;AAED,wBAAgB,YAAY,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,+BAsDxD;AAED,eAAe,YAAY,CAAA"}
1
+ {"version":3,"file":"move-tool.d.ts","sourceRoot":"","sources":["../../src/item/move-tool.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,OAAO,EAGZ,KAAK,QAAQ,EAEd,MAAM,kBAAkB,CAAA;AACzB,OAAO,EACL,KAAK,cAAc,EAKpB,MAAM,oBAAoB,CAAA;AAI3B;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,QAAQ,EACd,MAAM,GAAE,OAAO,GAAG,SAEL,GACZ,cAAc,CAiFhB;AAED,wBAAgB,YAAY,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,+BAkEhE;AAED,eAAe,YAAY,CAAA"}
@@ -1,7 +1,8 @@
1
1
  'use client';
2
2
  import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
3
- import { useScene } from '@pascal-app/core';
3
+ import { canHostSurfaceChild, useScene, } from '@pascal-app/core';
4
4
  import { triggerSFX, useDraftNode, useEditor, usePlacementCoordinator, } from '@pascal-app/editor';
5
+ import { useMemo } from 'react';
5
6
  import { Vector3 } from 'three';
6
7
  /**
7
8
  * Phase 5 Stage D — item's registry-driven 3D move affordance.
@@ -78,7 +79,10 @@ export function getInitialState(node, parent = node.parentId
78
79
  // handler — which preserves the grab offset — instead of a fresh `enter()`
79
80
  // that snaps the item's origin under the cursor. Without this the item
80
81
  // teleports the instant it's grabbed.
81
- if (parent?.type === 'item') {
82
+ if (parent?.type === 'item' ||
83
+ parent?.type === 'cabinet' ||
84
+ parent?.type === 'procedural-item' ||
85
+ (parent && parent.type !== 'shelf' && canHostSurfaceChild(parent, node.type, node.id))) {
82
86
  return {
83
87
  surface: 'item-surface',
84
88
  wallId: null,
@@ -107,12 +111,16 @@ export function getInitialState(node, parent = node.parentId
107
111
  shelfId: null,
108
112
  };
109
113
  }
110
- export function MoveItemTool({ node }) {
114
+ export function MoveItemTool({ node: source }) {
115
+ const node = useMemo(() => source.metadata?.isNew
116
+ ? (useScene.getState().nodes[source.id] ?? source)
117
+ : source, [source]);
111
118
  const draftNode = useDraftNode();
112
119
  const meta = typeof node.metadata === 'object' && node.metadata !== null
113
120
  ? node.metadata
114
121
  : {};
115
122
  const isNew = !!meta.isNew;
123
+ const isSceneDraft = useMemo(() => isNew && !!useScene.getState().nodes[node.id], [isNew, node.id]);
116
124
  const cursor = usePlacementCoordinator({
117
125
  asset: node.asset,
118
126
  draftNode,
@@ -120,7 +128,7 @@ export function MoveItemTool({ node }) {
120
128
  // items create their draft lazily inside the coordinator).
121
129
  slots: node.slots,
122
130
  // Duplicates start fresh in floor mode; wall/ceiling draft is created lazily by ensureDraft.
123
- initialState: isNew
131
+ initialState: isNew && !isSceneDraft
124
132
  ? {
125
133
  surface: 'floor',
126
134
  wallId: null,
@@ -132,9 +140,9 @@ export function MoveItemTool({ node }) {
132
140
  : getInitialState(node),
133
141
  // Preserve the original item's scale so Y-position calculations use the correct height.
134
142
  defaultScale: isNew ? node.scale : undefined,
135
- preserveDragOffset: true,
143
+ preserveDragOffset: !isSceneDraft,
136
144
  initDraft: (gridPosition) => {
137
- if (isNew) {
145
+ if (isNew && !isSceneDraft) {
138
146
  // Duplicate: floor items get a draft immediately; wall/ceiling
139
147
  // items are created lazily on surface entry.
140
148
  gridPosition.copy(new Vector3(...node.position));
@@ -144,7 +152,7 @@ export function MoveItemTool({ node }) {
144
152
  }
145
153
  else {
146
154
  draftNode.adopt(node);
147
- gridPosition.copy(new Vector3(...node.position));
155
+ gridPosition.copy(new Vector3(...draftNode.current.position));
148
156
  }
149
157
  },
150
158
  onCommitted: () => {
@@ -78,7 +78,7 @@ export default function ItemPanel() {
78
78
  }, [selectedId, deleteNode, setSelection]);
79
79
  if (!(node && node.type === 'item' && selectedId))
80
80
  return null;
81
- return (_jsxs(PanelWrapper, { icon: node.asset.thumbnail || '/icons/item.webp', onClose: handleClose, title: node.name || node.asset.name, width: 300, children: [_jsxs(PanelSection, { title: "Position", children: [_jsx(SliderControl, { label: _jsxs(_Fragment, { children: ["X", _jsx("sub", { className: "ml-[1px] text-[11px] opacity-70", children: "pos" })] }), max: node.position[0] + 2, min: node.position[0] - 2, onChange: (value) => handleUpdate({ position: [value, node.position[1], node.position[2]] }), precision: 2, step: 0.01, unit: "m", value: Math.round(node.position[0] * 100) / 100 }), _jsx(SliderControl, { label: _jsxs(_Fragment, { children: ["Y", _jsx("sub", { className: "ml-[1px] text-[11px] opacity-70", children: "pos" })] }), max: node.position[1] + 2, min: node.position[1] - 2, onChange: (value) => handleUpdate({ position: [node.position[0], value, node.position[2]] }), precision: 2, step: 0.01, unit: "m", value: Math.round(node.position[1] * 100) / 100 }), _jsx(SliderControl, { label: _jsxs(_Fragment, { children: ["Z", _jsx("sub", { className: "ml-[1px] text-[11px] opacity-70", children: "pos" })] }), max: node.position[2] + 2, min: node.position[2] - 2, onChange: (value) => handleUpdate({ position: [node.position[0], node.position[1], value] }), precision: 2, step: 0.01, unit: "m", value: Math.round(node.position[2] * 100) / 100 })] }), _jsxs(PanelSection, { title: "Rotation", children: [_jsx(SliderControl, { label: _jsxs(_Fragment, { children: ["Y", _jsx("sub", { className: "ml-[1px] text-[11px] opacity-70", children: "rot" })] }), max: Math.round((node.rotation[1] * 180) / Math.PI) + 45, min: Math.round((node.rotation[1] * 180) / Math.PI) - 45, onChange: (degrees) => {
81
+ return (_jsxs(PanelWrapper, { icon: node.asset.thumbnail || '/icons/item.webp', onClose: handleClose, title: node.name || node.asset.name, width: 300, children: [_jsxs(PanelSection, { title: "Position", children: [_jsx(SliderControl, { label: _jsxs(_Fragment, { children: ["X", _jsx("sub", { className: "ml-[1px] text-[11px] opacity-70", children: "pos" })] }), max: node.position[0] + 2, min: node.position[0] - 2, onChange: (value) => handleUpdate({ position: [value, node.position[1], node.position[2]] }), precision: 2, step: 0.01, unit: "m", value: node.position[0] }), _jsx(SliderControl, { label: _jsxs(_Fragment, { children: ["Y", _jsx("sub", { className: "ml-[1px] text-[11px] opacity-70", children: "pos" })] }), max: node.position[1] + 2, min: node.position[1] - 2, onChange: (value) => handleUpdate({ position: [node.position[0], value, node.position[2]] }), precision: 2, step: 0.01, unit: "m", value: node.position[1] }), _jsx(SliderControl, { label: _jsxs(_Fragment, { children: ["Z", _jsx("sub", { className: "ml-[1px] text-[11px] opacity-70", children: "pos" })] }), max: node.position[2] + 2, min: node.position[2] - 2, onChange: (value) => handleUpdate({ position: [node.position[0], node.position[1], value] }), precision: 2, step: 0.01, unit: "m", value: node.position[2] })] }), _jsxs(PanelSection, { title: "Rotation", children: [_jsx(SliderControl, { label: _jsxs(_Fragment, { children: ["Y", _jsx("sub", { className: "ml-[1px] text-[11px] opacity-70", children: "rot" })] }), max: Math.round((node.rotation[1] * 180) / Math.PI) + 45, min: Math.round((node.rotation[1] * 180) / Math.PI) - 45, onChange: (degrees) => {
82
82
  const radians = (degrees * Math.PI) / 180;
83
83
  handleUpdate({ rotation: [node.rotation[0], radians, node.rotation[2]] });
84
84
  }, precision: 0, step: 1, unit: "\u00B0", value: Math.round((node.rotation[1] * 180) / Math.PI) }), _jsxs("div", { className: "flex gap-1.5 px-1 pt-2 pb-1", children: [_jsx(ActionButton, { label: "-45\u00B0", onClick: () => {
@@ -1 +1 @@
1
- {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/item/renderer.tsx"],"names":[],"mappings":"AAEA,OAAO,EAML,KAAK,QAAQ,EAYd,MAAM,kBAAkB,CAAA;AA6ZzB,eAAO,MAAM,YAAY,GAAI,qBAAqB;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,gCA4DnE,CAAA;AA+CD,eAAO,MAAM,WAAW,GAAI,UAAU;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,gCAUvD,CAAA;AA4RD,eAAe,YAAY,CAAA"}
1
+ {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/item/renderer.tsx"],"names":[],"mappings":"AAEA,OAAO,EAML,KAAK,QAAQ,EAYd,MAAM,kBAAkB,CAAA;AA6ZzB,eAAO,MAAM,YAAY,GAAI,qBAAqB;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,gCAmEnE,CAAA;AA+CD,eAAO,MAAM,WAAW,GAAI,UAAU;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,gCAUvD,CAAA;AA4RD,eAAe,YAAY,CAAA"}
@@ -292,8 +292,14 @@ export const ItemRenderer = ({ node: storeNode }) => {
292
292
  setSettled(true);
293
293
  }, [roomClearPreview, setSettled]);
294
294
  const content = (_jsx("group", { position: node.position, ref: ref, rotation: node.rotation, visible: node.visible, children: roomClearPreview ? (_jsx(ClearPreviewModel, { node: node })) : (_jsxs(_Fragment, { children: [_jsx(ModelWithRetry, { node: node, setSettled: setSettled }, node.asset.src ?? 'no-src'), node.children?.map((childId) => (_jsx(NodeRenderer, { nodeId: childId }, childId)))] })) }));
295
- if (node.blockFaceId && node.parentId) {
296
- return (_jsx(BlockFaceHostFrame, { blockId: node.parentId, faceId: node.blockFaceId, children: content }));
295
+ // A floor-exit override is still mounted beneath the stored block until commit.
296
+ const faceNode = liveOverrides?.parentId &&
297
+ useScene.getState().nodes[liveOverrides.parentId]?.type === 'level' &&
298
+ useScene.getState().nodes[storeNode.parentId]?.type === 'block'
299
+ ? storeNode
300
+ : node;
301
+ if (faceNode.blockFaceId && faceNode.parentId) {
302
+ return (_jsx(BlockFaceHostFrame, { blockId: faceNode.parentId, faceId: faceNode.blockFaceId, children: content }));
297
303
  }
298
304
  if (!node.roofSegmentId)
299
305
  return content;
@@ -7,6 +7,6 @@ export const LevelRenderer = ({ node }) => {
7
7
  const ref = useRef(null);
8
8
  useRegistry(node.id, node.type, ref);
9
9
  const handlers = useNodeEvents(node, 'level');
10
- return (_jsx("group", { ref: ref, ...handlers, children: node.children.map((childId) => (_jsx(NodeRenderer, { nodeId: childId }, childId))) }));
10
+ return (_jsx("group", { ref: ref, visible: node.visible !== false, ...handlers, children: node.children.map((childId) => (_jsx(NodeRenderer, { nodeId: childId }, childId))) }));
11
11
  };
12
12
  export default LevelRenderer;