@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
@@ -0,0 +1,167 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { getCurtainWallConfig, getEffectiveNode, getWallCurveLength, getWallThickness, } from '@pascal-app/core';
4
+ import { getLinearUnitLabel, linearControlValueToMeters, metersToLinearUnit, PanelSection, SegmentedControl, SliderControl, ToggleControl, } from '@pascal-app/editor';
5
+ import { useState } from 'react';
6
+ import { useCurtainPanelHighlight } from './curtain-panel-highlight';
7
+ import { curtainGridPositions, curtainPanelType } from './curtain-wall-layout';
8
+ function Choice({ label, value, options, onChange, }) {
9
+ return (_jsxs("label", { className: "flex items-center justify-between gap-2 text-xs text-muted-foreground", children: [label, _jsx("select", { "aria-label": label, className: "max-w-[160px] rounded-md border border-border bg-background px-2 py-1.5 text-foreground", onChange: (event) => {
10
+ const option = options.find((entry) => entry.value === event.target.value);
11
+ if (option)
12
+ onChange(option.value);
13
+ }, value: value, children: options.map((option) => (_jsx("option", { value: option.value, children: option.label }, option.value))) })] }));
14
+ }
15
+ function LengthControl({ label, value, min, max, unit, onChange, onCommit, onCancel, profile = false, }) {
16
+ const millimeters = profile && unit === 'metric';
17
+ const display = (meters) => millimeters ? meters * 1000 : metersToLinearUnit(meters, unit);
18
+ return (_jsx(SliderControl, { onCommit: onCommit, onCancel: onCancel, restoreOnCommit: false, previewWhileTyping: true, label: label, max: display(max), min: display(min), onChange: (next) => onChange(millimeters
19
+ ? Math.max(min, Math.min(max, next / 1000))
20
+ : linearControlValueToMeters(next, unit, { minMeters: min, maxMeters: max })), precision: millimeters ? 1 : 3, step: millimeters ? 1 : 0.005, unit: millimeters ? 'mm' : getLinearUnitLabel(unit), value: display(value) }));
21
+ }
22
+ function GridSection({ length, vertical = false, onPreview, title, value, unit, onChange, onCommit, onCancel, }) {
23
+ return (_jsxs(PanelSection, { title: title, children: [_jsx(Choice, { label: "Layout", onChange: (layout) => onChange({ ...value, layout }), options: [
24
+ { label: 'Panel count', value: 'count' },
25
+ { label: 'Maximum spacing', value: 'maximum-spacing' },
26
+ { label: 'Fixed spacing', value: 'fixed-spacing' },
27
+ ], value: value.layout }), value.layout === 'count' ? (_jsx(SliderControl, { onCommit: onCommit, onCancel: onCancel, restoreOnCommit: false, previewWhileTyping: true, label: "Panels", max: 32, min: 1, onChange: (count) => onPreview({ ...value, count: Math.round(count) }), precision: 0, step: 1, value: value.count })) : (_jsx(LengthControl, { onCommit: onCommit, onCancel: onCancel, label: "Spacing", max: 100, min: 0.2, onChange: (spacing) => onPreview({ ...value, spacing }), unit: unit, value: value.spacing })), value.layout === 'fixed-spacing' && (_jsx(SegmentedControl, { onChange: (alignment) => onChange({ ...value, alignment }), options: [
28
+ { label: vertical ? 'Bottom' : 'Start', value: 'start' },
29
+ { label: 'Center', value: 'center' },
30
+ { label: vertical ? 'Top' : 'End', value: 'end' },
31
+ ], value: value.alignment })), _jsx("p", { className: "text-[11px] text-muted-foreground", children: (() => {
32
+ const positions = curtainGridPositions(length, value);
33
+ const spans = positions.slice(1).map((position, i) => position - positions[i]);
34
+ if (!spans.length)
35
+ return 'No panels';
36
+ const min = metersToLinearUnit(Math.min(...spans), unit);
37
+ const max = metersToLinearUnit(Math.max(...spans), unit);
38
+ return `${spans.length} ${vertical ? 'rows' : 'columns'} · ${min.toFixed(2)}${max - min > 0.005 ? `–${max.toFixed(2)}` : ''} ${getLinearUnitLabel(unit)} grid spacing`;
39
+ })() })] }));
40
+ }
41
+ const PANEL_OPTIONS = [
42
+ { label: 'Glass', value: 'glass' },
43
+ { label: 'Solid', value: 'solid' },
44
+ { label: 'Empty', value: 'empty' },
45
+ ];
46
+ export function getCurtainWallUpdate(node, patch) {
47
+ return {
48
+ curtainWall: { ...getCurtainWallConfig(getEffectiveNode(node)), ...patch },
49
+ };
50
+ }
51
+ export function CurtainWallPanel({ node, height, unit, onUpdate, onPreview, onCommit, onCancel, }) {
52
+ const config = getCurtainWallConfig(node);
53
+ const update = (patch, preview = false) => {
54
+ ;
55
+ (preview ? onPreview : onUpdate)(getCurtainWallUpdate(node, patch));
56
+ };
57
+ const [tintEditing, setTintEditing] = useState(false);
58
+ const [panelEditing, setPanelEditing] = useState(false);
59
+ const [selectedColumn, setColumn] = useState(0);
60
+ const [selectedRow, setRow] = useState(0);
61
+ const columnCount = curtainGridPositions(getWallCurveLength(node), config.columns).length - 1;
62
+ const rowCount = curtainGridPositions(height, config.rows).length - 1;
63
+ const column = Math.max(0, Math.min(selectedColumn, columnCount - 1));
64
+ const row = Math.max(0, Math.min(selectedRow, rowCount - 1));
65
+ const selectedType = curtainPanelType(config, column, row, rowCount);
66
+ const changePanel = (type) => update({
67
+ panels: [
68
+ ...config.panels.filter((panel) => panel.column !== column || panel.row !== row),
69
+ ...(type ? [{ column, row, type }] : []),
70
+ ],
71
+ });
72
+ const hiddenOverrides = config.panels.filter((panel) => panel.column >= columnCount || panel.row >= rowCount);
73
+ const diagramWidth = Math.max(240, columnCount * 32);
74
+ const diagramHeight = Math.max(150, rowCount * 32);
75
+ const overridden = config.panels.some((panel) => panel.column === column && panel.row === row);
76
+ const xs = curtainGridPositions(getWallCurveLength(node), config.columns);
77
+ const ys = curtainGridPositions(height, config.rows);
78
+ useCurtainPanelHighlight(node, xs[column] ?? 0, xs[column + 1] ?? 0, ys[row] ?? 0, ys[row + 1] ?? 0, panelEditing);
79
+ const hasGlass = xs
80
+ .slice(1)
81
+ .some((_, c) => ys.slice(1).some((_, r) => curtainPanelType(config, c, r, rowCount) === 'glass'));
82
+ const paintedGlass = Boolean(node.slots?.['curtain-glass']);
83
+ const effectiveThickness = Math.min(config.glassThickness, getWallThickness(node) * 0.45);
84
+ return (_jsxs(_Fragment, { children: [_jsxs(PanelSection, { title: "Wall system", children: [_jsx(Choice, { label: "Construction", onChange: (construction) => update({ construction }), options: [
85
+ { label: 'Stick-built', value: 'stick' },
86
+ { label: 'Unitized', value: 'unitized' },
87
+ ], value: config.construction }), _jsx(Choice, { label: "Framing", onChange: (framing) => update({ framing }), options: [
88
+ { label: 'Fully capped', value: 'capped' },
89
+ { label: 'Vertical caps', value: 'vertical-caps' },
90
+ { label: 'Horizontal caps', value: 'horizontal-caps' },
91
+ { label: 'Structural glazing', value: 'structural-glazing' },
92
+ ], value: config.framing }), _jsx("p", { className: "text-[11px] text-muted-foreground", children: config.construction === 'unitized'
93
+ ? 'Separate framed modules with joints between units.'
94
+ : 'Continuous mullions and transoms assembled along the wall.' }), config.framing !== 'capped' && (_jsx("p", { className: "text-[11px] text-muted-foreground", children: "Uncapped members sit behind the glazing." }))] }), _jsx(GridSection, { onChange: (columns) => update({ columns }), onPreview: (columns) => update({ columns }, true), onCommit: onCommit, onCancel: onCancel, title: "Column layout", length: getWallCurveLength(node), unit: unit, value: config.columns }), _jsx(GridSection, { onChange: (rows) => update({ rows }), onPreview: (rows) => update({ rows }, true), onCommit: onCommit, onCancel: onCancel, title: "Row layout", length: height, vertical: true, unit: unit, value: config.rows }), ((getWallCurveLength(node) / config.columns.spacing > 32 &&
95
+ config.columns.layout !== 'count') ||
96
+ (height / config.rows.spacing > 32 && config.rows.layout !== 'count')) && (_jsx("p", { className: "px-3 text-[11px] text-muted-foreground", children: "Grid limited to 32 panels per axis. Spacing expands to fit this wall." })), _jsxs(PanelSection, { title: "Frame dimensions", children: [_jsx(LengthControl, { profile: true, onCommit: onCommit, onCancel: onCancel, label: "Vertical frame width", max: 0.3, min: 0.01, onChange: (mullionWidth) => update({ mullionWidth }, true), unit: unit, value: config.mullionWidth }), _jsx(LengthControl, { profile: true, onCommit: onCommit, onCancel: onCancel, label: "Horizontal frame width", max: 0.3, min: 0.01, onChange: (transomWidth) => update({ transomWidth }, true), unit: unit, value: config.transomWidth }), _jsx(LengthControl, { profile: true, onCommit: onCommit, onCancel: onCancel, label: "Border / opening frame", max: 0.3, min: 0.01, onChange: (perimeterWidth) => update({ perimeterWidth }, true), unit: unit, value: config.perimeterWidth }), (config.construction === 'unitized' || config.framing !== 'capped') && (_jsx(LengthControl, { profile: true, onCommit: onCommit, onCancel: onCancel, label: config.construction === 'unitized' ? 'Module joint width' : 'Glazing gap', max: 0.05, min: 0.002, onChange: (jointWidth) => update({ jointWidth }, true), unit: unit, value: config.jointWidth }))] }), _jsxs(PanelSection, { title: "Panel infill", children: [_jsx(Choice, { label: "Default panel", onChange: (panelType) => update({ panelType }), options: PANEL_OPTIONS, value: config.panelType }), _jsx(Choice, { label: "Opaque band", onChange: (spandrel) => update({ spandrel }), options: [
97
+ { label: 'None', value: 'none' },
98
+ { label: 'Bottom row', value: 'bottom' },
99
+ { label: 'Top row', value: 'top' },
100
+ ], value: config.spandrel }), _jsx("p", { className: "text-[11px] text-muted-foreground", children: "Opaque bands replace a full row with solid panels. Apply their finish with the paint tool." }), _jsx(LengthControl, { profile: true, onCommit: onCommit, onCancel: onCancel, label: "Panel thickness", max: 0.08, min: 0.004, onChange: (glassThickness) => update({ glassThickness }, true), unit: unit, value: config.glassThickness }), effectiveThickness < config.glassThickness - 1e-6 && (_jsxs("p", { className: "text-[11px] text-muted-foreground", children: ["Effective thickness:", ' ', unit === 'metric'
101
+ ? `${(effectiveThickness * 1000).toFixed(1)} mm`
102
+ : `${metersToLinearUnit(effectiveThickness, unit).toFixed(3)} ${getLinearUnitLabel(unit)}`, ", limited by frame depth."] }))] }), _jsxs(PanelSection, { title: "Edit individual panels", children: [_jsx(ToggleControl, { checked: panelEditing, label: "Enable panel editing", onChange: setPanelEditing }), panelEditing && (_jsxs(_Fragment, { children: [_jsx("p", { className: "text-[11px] text-muted-foreground", children: "Choose a cell or enter its column and row. Use arrow keys to move between cells. Columns run from the wall start; rows count upward." }), _jsx("div", { className: "max-h-64 overflow-auto rounded border border-border", children: _jsx("svg", { viewBox: `0 0 ${diagramWidth} ${diagramHeight}`, style: { width: diagramWidth, height: diagramHeight }, className: "block", role: "group", "aria-label": "Curtain wall panel selection", children: xs.slice(1).flatMap((_, c) => ys.slice(1).map((_, r) => {
103
+ const type = curtainPanelType(config, c, r, rowCount);
104
+ const selected = c === column && r === row;
105
+ return (_jsx("rect", { role: "button", tabIndex: selected ? 0 : -1, "aria-label": `Column ${c + 1}, row ${r + 1}: ${type}`, "aria-pressed": selected, "data-cell": `${c}-${r}`, x: (c / columnCount) * diagramWidth, y: diagramHeight - ((r + 1) / rowCount) * diagramHeight, width: diagramWidth / columnCount, height: diagramHeight / rowCount, fill: type === 'glass'
106
+ ? '#53788a'
107
+ : type === 'solid'
108
+ ? '#64748b'
109
+ : 'transparent', stroke: selected ? '#fb923c' : '#94a3b8', strokeWidth: selected ? 3 : 1, className: "cursor-pointer focus:stroke-orange-400 focus:stroke-[3]", onClick: () => {
110
+ setColumn(c);
111
+ setRow(r);
112
+ }, onKeyDown: (event) => {
113
+ const arrows = {
114
+ ArrowLeft: [-1, 0],
115
+ ArrowRight: [1, 0],
116
+ ArrowUp: [0, 1],
117
+ ArrowDown: [0, -1],
118
+ };
119
+ const delta = arrows[event.key];
120
+ if (delta) {
121
+ event.preventDefault();
122
+ const nextColumn = Math.max(0, Math.min(columnCount - 1, c + delta[0]));
123
+ const nextRow = Math.max(0, Math.min(rowCount - 1, r + delta[1]));
124
+ setColumn(nextColumn);
125
+ setRow(nextRow);
126
+ const target = event.currentTarget.parentElement?.querySelector(`[data-cell="${nextColumn}-${nextRow}"]`);
127
+ target?.focus();
128
+ target?.scrollIntoView({ block: 'nearest', inline: 'nearest' });
129
+ }
130
+ if (event.key === 'Enter' || event.key === ' ') {
131
+ event.preventDefault();
132
+ setColumn(c);
133
+ setRow(r);
134
+ }
135
+ } }, `${c}-${r}`));
136
+ })) }) }), hiddenOverrides.length > 0 && (_jsxs("div", { className: "space-y-2 text-[11px] text-muted-foreground", children: [_jsxs("p", { children: [hiddenOverrides.length, " custom panels are outside this grid. They return if the grid expands."] }), _jsx("button", { type: "button", className: "rounded border border-border px-2 py-1 text-xs", onClick: () => update({
137
+ panels: config.panels.filter((panel) => panel.column < columnCount && panel.row < rowCount),
138
+ }), children: "Clear hidden overrides" })] })), _jsxs("p", { className: "text-[11px] text-muted-foreground", children: ["Column ", column + 1, ", row ", row + 1, " \u00B7", ' ', overridden ? 'Custom infill' : 'Following wall defaults'] }), _jsx(SliderControl, { label: "Column", max: Math.max(1, columnCount), min: 1, onChange: (value) => setColumn(Math.round(value) - 1), precision: 0, step: 1, value: column + 1 }), _jsx(SliderControl, { label: "Row", max: Math.max(1, rowCount), min: 1, onChange: (value) => setRow(Math.round(value) - 1), precision: 0, step: 1, value: row + 1 }), _jsx(Choice, { label: "Panel infill", onChange: changePanel, options: PANEL_OPTIONS, value: selectedType }), _jsx("button", { className: "rounded border border-border px-2 py-1 text-xs disabled:cursor-default disabled:opacity-40", disabled: !overridden, onClick: () => changePanel(), type: "button", children: "Reset this panel" }), _jsx("p", { className: "text-[11px] text-muted-foreground", children: "Use the Door or Window tool to add an opening through the wall." })] }))] }), hasGlass && (_jsxs(PanelSection, { title: "Glass appearance", children: [paintedGlass && (_jsxs("div", { className: "space-y-2 text-xs text-muted-foreground", children: [_jsx("p", { children: "Glass appearance is controlled by the paint tool." }), _jsx("button", { type: "button", className: "rounded border border-border px-2 py-1", onClick: () => {
139
+ onCommit();
140
+ const slots = { ...node.slots };
141
+ delete slots['curtain-glass'];
142
+ onUpdate({ slots });
143
+ }, children: "Use glass settings instead" })] })), !paintedGlass && (_jsxs("div", { className: "space-y-2", children: [_jsx(SliderControl, { onCommit: onCommit, onCancel: onCancel, restoreOnCommit: false, previewWhileTyping: true, label: "Opacity", max: 100, min: 5, onChange: (value) => update({ glassOpacity: value / 100 }, true), precision: 0, step: 5, unit: "%", value: Math.round(config.glassOpacity * 100) }), _jsx(SliderControl, { onCommit: onCommit, onCancel: onCancel, restoreOnCommit: false, previewWhileTyping: true, label: "Surface roughness", max: 1, min: 0, onChange: (glassRoughness) => update({ glassRoughness }, true), precision: 2, step: 0.05, value: config.glassRoughness }), _jsxs("label", { className: "flex items-center justify-between text-xs text-muted-foreground", children: ["Glass tint", _jsx("input", { "aria-label": "Glass tint", className: "h-7 w-10 cursor-pointer rounded border border-border bg-transparent", onKeyDown: (event) => {
144
+ if (event.key === 'Escape') {
145
+ event.preventDefault();
146
+ onCancel();
147
+ setTintEditing(false);
148
+ }
149
+ }, onChange: (event) => {
150
+ setTintEditing(true);
151
+ update({ glassColor: event.target.value }, true);
152
+ }, onBlur: () => {
153
+ if (!tintEditing)
154
+ return;
155
+ onCommit();
156
+ setTintEditing(false);
157
+ }, onInput: (event) => {
158
+ setTintEditing(true);
159
+ update({ glassColor: event.currentTarget.value }, true);
160
+ }, type: "color", value: config.glassColor })] }), tintEditing && (_jsxs("div", { className: "flex gap-2", children: [_jsx("button", { type: "button", className: "rounded border border-border px-2 py-1 text-xs", onClick: () => {
161
+ onCommit();
162
+ setTintEditing(false);
163
+ }, children: "Apply tint" }), _jsx("button", { type: "button", className: "rounded border border-border px-2 py-1 text-xs", onClick: () => {
164
+ onCancel();
165
+ setTintEditing(false);
166
+ }, children: "Cancel tint" })] })), _jsx("p", { className: "text-[11px] text-muted-foreground", children: "Low roughness is smooth; high roughness gives a matte surface in rendered shading." })] }))] }))] }));
167
+ }
@@ -0,0 +1,5 @@
1
+ import { BufferGeometry, Vector2 } from 'three';
2
+ import type { CurtainWallPiece } from './curtain-wall-layout';
3
+ export declare function buildStraightCurtainPiecesWithCutouts(pieces: readonly CurtainWallPiece[], base: number, cutouts: readonly (readonly Vector2[])[]): BufferGeometry<import("three").NormalBufferAttributes, import("three").BufferGeometryEventMap>;
4
+ export declare function buildStraightCurtainPieces(pieces: readonly CurtainWallPiece[], base: number, cullSharedFaces?: boolean): BufferGeometry<import("three").NormalBufferAttributes, import("three").BufferGeometryEventMap>;
5
+ //# sourceMappingURL=curtain-wall-piece-geometry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"curtain-wall-piece-geometry.d.ts","sourceRoot":"","sources":["../../src/wall/curtain-wall-piece-geometry.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAsC,OAAO,EAAE,MAAM,OAAO,CAAA;AACnF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAI7D,wBAAgB,qCAAqC,CACnD,MAAM,EAAE,SAAS,gBAAgB,EAAE,EACnC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,SAAS,CAAC,SAAS,OAAO,EAAE,CAAC,EAAE,kGA+GzC;AAGD,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,SAAS,gBAAgB,EAAE,EACnC,IAAI,EAAE,MAAM,EACZ,eAAe,UAAO,kGA0HvB"}
@@ -0,0 +1,220 @@
1
+ import { subtractPolygonsFromPolygon } from '@pascal-app/core';
2
+ import { ensureRenderableGeometryAttributes } from '@pascal-app/viewer';
3
+ import { BufferGeometry, Float32BufferAttribute, ShapeUtils, Vector2 } from 'three';
4
+ export function buildStraightCurtainPiecesWithCutouts(pieces, base, cutouts) {
5
+ const positions = [];
6
+ const normals = [];
7
+ const preparedCutouts = cutouts.map((cutout) => {
8
+ const points = cutout.map((point) => [point.x, point.y]);
9
+ const xs = points.map(([x]) => x);
10
+ const ys = points.map(([, y]) => y);
11
+ return {
12
+ points,
13
+ minX: Math.min(...xs),
14
+ maxX: Math.max(...xs),
15
+ minY: Math.min(...ys),
16
+ maxY: Math.max(...ys),
17
+ };
18
+ });
19
+ const vertex = (point, normal) => {
20
+ positions.push(point[0], point[1], point[2]);
21
+ normals.push(normal[0], normal[1], normal[2]);
22
+ };
23
+ const contains = (ring, point) => {
24
+ let inside = false;
25
+ for (let index = 0, previous = ring.length - 1; index < ring.length; previous = index++) {
26
+ const a = ring[index];
27
+ const b = ring[previous];
28
+ if (a[1] > point[1] !== b[1] > point[1] &&
29
+ point[0] < ((b[0] - a[0]) * (point[1] - a[1])) / (b[1] - a[1]) + a[0]) {
30
+ inside = !inside;
31
+ }
32
+ }
33
+ return inside;
34
+ };
35
+ const area = (ring) => Math.abs(ring.reduce((sum, point, index) => {
36
+ const next = ring[(index + 1) % ring.length];
37
+ return sum + point[0] * next[1] - next[0] * point[1];
38
+ }, 0) / 2);
39
+ for (const piece of pieces) {
40
+ const bottom = piece.bottom + base;
41
+ const top = piece.top + base;
42
+ const overlapping = preparedCutouts.filter((cutout) => cutout.maxX > piece.left &&
43
+ cutout.minX < piece.right &&
44
+ cutout.maxY > bottom &&
45
+ cutout.minY < top);
46
+ const subject = [
47
+ [piece.left, bottom],
48
+ [piece.right, bottom],
49
+ [piece.right, top],
50
+ [piece.left, top],
51
+ ];
52
+ const rings = subtractPolygonsFromPolygon(subject, overlapping.map(({ points }) => points)).sort((a, b) => area(b) - area(a));
53
+ const groups = [];
54
+ for (const ring of rings) {
55
+ const parent = groups.find(({ contour }) => contains(contour, ring[0]));
56
+ if (parent)
57
+ parent.holes.push([...ring].reverse());
58
+ else
59
+ groups.push({ contour: ring, holes: [] });
60
+ }
61
+ for (const { contour, holes } of groups) {
62
+ const flattened = [contour, ...holes].flat();
63
+ const triangles = ShapeUtils.triangulateShape(contour.map(([x, y]) => new Vector2(x, y)), holes.map((hole) => hole.map(([x, y]) => new Vector2(x, y))));
64
+ for (const triangle of triangles) {
65
+ const aIndex = triangle[0];
66
+ const bIndex = triangle[1];
67
+ const cIndex = triangle[2];
68
+ const a = flattened[aIndex];
69
+ const b = flattened[bIndex];
70
+ const c = flattened[cIndex];
71
+ vertex([a[0], a[1], piece.front], [0, 0, 1]);
72
+ vertex([b[0], b[1], piece.front], [0, 0, 1]);
73
+ vertex([c[0], c[1], piece.front], [0, 0, 1]);
74
+ vertex([c[0], c[1], piece.back], [0, 0, -1]);
75
+ vertex([b[0], b[1], piece.back], [0, 0, -1]);
76
+ vertex([a[0], a[1], piece.back], [0, 0, -1]);
77
+ }
78
+ for (const ring of [contour, ...holes]) {
79
+ for (let index = 0; index < ring.length; index++) {
80
+ const a = ring[index];
81
+ const b = ring[(index + 1) % ring.length];
82
+ const dx = b[0] - a[0];
83
+ const dy = b[1] - a[1];
84
+ const length = Math.hypot(dx, dy);
85
+ if (length <= 1e-6)
86
+ continue;
87
+ const normal = [dy / length, -dx / length, 0];
88
+ vertex([a[0], a[1], piece.back], normal);
89
+ vertex([b[0], b[1], piece.back], normal);
90
+ vertex([b[0], b[1], piece.front], normal);
91
+ vertex([a[0], a[1], piece.back], normal);
92
+ vertex([b[0], b[1], piece.front], normal);
93
+ vertex([a[0], a[1], piece.front], normal);
94
+ }
95
+ }
96
+ }
97
+ }
98
+ const geometry = new BufferGeometry();
99
+ geometry.setAttribute('position', new Float32BufferAttribute(positions, 3));
100
+ geometry.setAttribute('normal', new Float32BufferAttribute(normals, 3));
101
+ ensureRenderableGeometryAttributes(geometry);
102
+ return geometry;
103
+ }
104
+ // Adjacent fragments of one pane share a boundary, not a second glass surface.
105
+ export function buildStraightCurtainPieces(pieces, base, cullSharedFaces = true) {
106
+ if (!cullSharedFaces) {
107
+ const valuesPerPiece = 6 * 6 * 3;
108
+ const positions = new Float32Array(pieces.length * valuesPerPiece);
109
+ const normals = new Float32Array(pieces.length * valuesPerPiece);
110
+ let offset = 0;
111
+ const vertex = (point, normal) => {
112
+ positions[offset] = point[0];
113
+ normals[offset++] = normal[0];
114
+ positions[offset] = point[1];
115
+ normals[offset++] = normal[1];
116
+ positions[offset] = point[2];
117
+ normals[offset++] = normal[2];
118
+ };
119
+ const quad = (a, b, c, d, normal) => {
120
+ vertex(a, normal);
121
+ vertex(b, normal);
122
+ vertex(c, normal);
123
+ vertex(a, normal);
124
+ vertex(c, normal);
125
+ vertex(d, normal);
126
+ };
127
+ for (const piece of pieces) {
128
+ const { left: l, right: r, bottom, top, front: f, back: k } = piece;
129
+ const b = bottom + base;
130
+ const t = top + base;
131
+ quad([l, b, f], [r, b, f], [r, t, f], [l, t, f], [0, 0, 1]);
132
+ quad([r, b, k], [l, b, k], [l, t, k], [r, t, k], [0, 0, -1]);
133
+ quad([l, b, k], [l, b, f], [l, t, f], [l, t, k], [-1, 0, 0]);
134
+ quad([r, b, f], [r, b, k], [r, t, k], [r, t, f], [1, 0, 0]);
135
+ quad([l, b, k], [r, b, k], [r, b, f], [l, b, f], [0, -1, 0]);
136
+ quad([l, t, f], [r, t, f], [r, t, k], [l, t, k], [0, 1, 0]);
137
+ }
138
+ const geometry = new BufferGeometry();
139
+ geometry.setAttribute('position', new Float32BufferAttribute(positions, 3));
140
+ geometry.setAttribute('normal', new Float32BufferAttribute(normals, 3));
141
+ ensureRenderableGeometryAttributes(geometry);
142
+ return geometry;
143
+ }
144
+ const positions = new Float32Array(pieces.length * 6 * 6 * 3);
145
+ const normals = new Float32Array(positions.length);
146
+ let offset = 0;
147
+ const vertex = (point, normal) => {
148
+ positions[offset] = point[0];
149
+ normals[offset++] = normal[0];
150
+ positions[offset] = point[1];
151
+ normals[offset++] = normal[1];
152
+ positions[offset] = point[2];
153
+ normals[offset++] = normal[2];
154
+ };
155
+ const quad = (a, b, c, d, normal) => {
156
+ vertex(a, normal);
157
+ vertex(b, normal);
158
+ vertex(c, normal);
159
+ vertex(a, normal);
160
+ vertex(c, normal);
161
+ vertex(d, normal);
162
+ };
163
+ const sides = ['left', 'right', 'bottom', 'top'];
164
+ const key = (piece, side, coordinate = piece[side]) => `${side}:${coordinate.toFixed(7)}:${piece.front.toFixed(7)}:${piece.back.toFixed(7)}`;
165
+ const edges = new Map();
166
+ if (cullSharedFaces) {
167
+ for (const piece of pieces) {
168
+ for (const side of sides) {
169
+ const id = key(piece, side);
170
+ const neighbors = edges.get(id) ?? [];
171
+ neighbors.push(piece);
172
+ edges.set(id, neighbors);
173
+ }
174
+ }
175
+ }
176
+ for (const piece of pieces) {
177
+ const { left: l, right: r, bottom, top, front: f, back: k } = piece;
178
+ const b = bottom + base;
179
+ const t = top + base;
180
+ quad([l, b, f], [r, b, f], [r, t, f], [l, t, f], [0, 0, 1]);
181
+ quad([r, b, k], [l, b, k], [l, t, k], [r, t, k], [0, 0, -1]);
182
+ for (const side of sides) {
183
+ const vertical = side === 'left' || side === 'right';
184
+ let runs = vertical ? [[bottom, top]] : [[l, r]];
185
+ const opposite = side === 'left' ? 'right' : side === 'right' ? 'left' : side === 'bottom' ? 'top' : 'bottom';
186
+ if (cullSharedFaces) {
187
+ for (const other of edges.get(key(piece, opposite, piece[side])) ?? []) {
188
+ if (other === piece)
189
+ continue;
190
+ const low = vertical ? other.bottom : other.left;
191
+ const high = vertical ? other.top : other.right;
192
+ runs = runs.flatMap(([start, end]) => high <= start || low >= end
193
+ ? [[start, end]]
194
+ : [
195
+ ...(low > start ? [[start, low]] : []),
196
+ ...(high < end ? [[high, end]] : []),
197
+ ]);
198
+ }
199
+ }
200
+ for (const [start, end] of runs) {
201
+ if (vertical) {
202
+ const y0 = start + base, y1 = end + base;
203
+ if (side === 'left')
204
+ quad([l, y0, k], [l, y0, f], [l, y1, f], [l, y1, k], [-1, 0, 0]);
205
+ else
206
+ quad([r, y0, f], [r, y0, k], [r, y1, k], [r, y1, f], [1, 0, 0]);
207
+ }
208
+ else if (side === 'bottom')
209
+ quad([start, b, k], [end, b, k], [end, b, f], [start, b, f], [0, -1, 0]);
210
+ else
211
+ quad([start, t, f], [end, t, f], [end, t, k], [start, t, k], [0, 1, 0]);
212
+ }
213
+ }
214
+ }
215
+ const geometry = new BufferGeometry();
216
+ geometry.setAttribute('position', new Float32BufferAttribute(positions.subarray(0, offset), 3));
217
+ geometry.setAttribute('normal', new Float32BufferAttribute(normals.subarray(0, offset), 3));
218
+ ensureRenderableGeometryAttributes(geometry);
219
+ return geometry;
220
+ }
@@ -0,0 +1,4 @@
1
+ import type { BufferGeometry } from 'three';
2
+ export declare const CURTAIN_WALL_SHADOW_NAME = "curtain-wall-shadow";
3
+ export declare function buildCurtainWallShadowGeometry(source: BufferGeometry, opaqueGlass: boolean): BufferGeometry;
4
+ //# sourceMappingURL=curtain-wall-shadow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"curtain-wall-shadow.d.ts","sourceRoot":"","sources":["../../src/wall/curtain-wall-shadow.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAA;AAE3C,eAAO,MAAM,wBAAwB,wBAAwB,CAAA;AAE7D,wBAAgB,8BAA8B,CAC5C,MAAM,EAAE,cAAc,EACtB,WAAW,EAAE,OAAO,GACnB,cAAc,CAYhB"}
@@ -0,0 +1,15 @@
1
+ export const CURTAIN_WALL_SHADOW_NAME = 'curtain-wall-shadow';
2
+ export function buildCurtainWallShadowGeometry(source, opaqueGlass) {
3
+ const geometry = source.clone();
4
+ const indices = [];
5
+ for (const group of source.groups) {
6
+ if (group.materialIndex === 1 && !opaqueGlass)
7
+ continue;
8
+ for (let i = group.start; i < group.start + group.count; i++)
9
+ indices.push(source.index ? source.index.getX(i) : i);
10
+ }
11
+ geometry.clearGroups();
12
+ geometry.setIndex(indices);
13
+ geometry.setDrawRange(0, indices.length);
14
+ return geometry;
15
+ }
@@ -1,19 +1,4 @@
1
1
  import { type NodeDefinition } from '@pascal-app/core';
2
2
  import { WallNode } from './schema';
3
- /**
4
- * Wall — the Phase 3 stress test of the registry-driven node model.
5
- *
6
- * Stage A: registered (capabilities, relations, parametrics, presentation).
7
- * Stage B: deferred — wall geometry depends on level-batch miter data that
8
- * doesn't fit the generic `(node, ctx) => Group` shape without `ctx.
9
- * levelData?.miters`. See plan's "GeometryContext" extension note.
10
- * `renderer` + `system` keep wrap-exporting legacy WallRenderer +
11
- * WallSystem + WallCutout.
12
- * Stage C: `def.floorplan` builder produces the mitered plan footprint
13
- * polygon from shared floor-plan level data, with `ctx.siblings` as the
14
- * direct-caller fallback.
15
- * floorplan-panel.tsx's `wallPolygons` short-circuits to [] when
16
- * wall is registered.
17
- */
18
3
  export declare const wallDefinition: NodeDefinition<typeof WallNode>;
19
4
  //# sourceMappingURL=definition.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../src/wall/definition.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,cAAc,EAEpB,MAAM,kBAAkB,CAAA;AAwBzB,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAGnC;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,cAAc,EAAE,cAAc,CAAC,OAAO,QAAQ,CA4J1D,CAAA"}
1
+ {"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../src/wall/definition.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,cAAc,EAEpB,MAAM,kBAAkB,CAAA;AA4BzB,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAyBnC,eAAO,MAAM,cAAc,EAAE,cAAc,CAAC,OAAO,QAAQ,CAsN1D,CAAA"}
@@ -1,17 +1,22 @@
1
1
  import { getWallBaseElevationForNodes, getWallEffectiveHeightForNodes, } from '@pascal-app/core';
2
- import { DRAFTING_SURFACE_EXTENSION_KEY, } from '@pascal-app/editor';
2
+ import { DRAFTING_SURFACE_EXTENSION_KEY, PANEL_MODEL_EXTENSION, } from '@pascal-app/editor';
3
3
  import { buildWallContextualDimensions } from './contextual-dimensions';
4
4
  import { hasWallCurveBlockingChildren } from './curve-eligibility';
5
+ import { useWallDrawingMode } from './drawing-mode';
5
6
  import { buildWallFloorplan, computeWallFloorplanLevelData } from './floorplan';
6
7
  import { wallCurveAffordance, wallMoveEndpointAffordance, wallThicknessAffordance, } from './floorplan-affordances';
7
8
  import { wallFloorplanMoveTarget } from './floorplan-move';
8
9
  import { wallFloorplanSiblingOverrides } from './floorplan-overrides';
9
10
  import { matchWallMeasurementFeature, resolveWallMeasurementFeature, wallMeasurementFeatures, } from './measurement';
10
11
  import { wallPaint } from './paint';
12
+ import { wallSettings } from './panel-model';
11
13
  import { wallParametrics } from './parametrics';
12
14
  import { wallQuickMeasurement } from './quick-measurement';
13
15
  import { WallNode } from './schema';
14
16
  import { wallSlots } from './slots';
17
+ import { WALL_SPLIT_MAX_CUTS } from './split-preview';
18
+ import { setWallSplitCuts } from './split-session';
19
+ import { useWallSplit } from './split-store';
15
20
  /**
16
21
  * Wall — the Phase 3 stress test of the registry-driven node model.
17
22
  *
@@ -27,14 +32,18 @@ import { wallSlots } from './slots';
27
32
  * floorplan-panel.tsx's `wallPolygons` short-circuits to [] when
28
33
  * wall is registered.
29
34
  */
35
+ const SPLIT_CUT_COUNTS = Array.from({ length: WALL_SPLIT_MAX_CUTS }, (_, index) => String(index + 1));
30
36
  export const wallDefinition = {
31
37
  kind: 'wall',
32
38
  snapProfile: 'structural',
33
- schemaVersion: 8,
39
+ schemaVersion: 9,
34
40
  schema: WallNode,
35
41
  category: 'structure',
36
42
  surfaceRole: 'wall',
37
43
  extensions: {
44
+ [PANEL_MODEL_EXTENSION]: {
45
+ rows: ({ node, nodes, update }) => wallSettings(node, nodes, update),
46
+ },
38
47
  [DRAFTING_SURFACE_EXTENSION_KEY]: {
39
48
  kind: 'wall',
40
49
  classifyFace: (node, localNormal) => {
@@ -55,8 +64,11 @@ export const wallDefinition = {
55
64
  },
56
65
  },
57
66
  'pascal:editor/floorplan': {
67
+ tool: () => import('./floorplan-tool'),
68
+ reshapeLayers: { split: () => import('./split-floorplan-layer') },
58
69
  contextualDimensions: buildWallContextualDimensions,
59
70
  actionMenu: {
71
+ actions: () => import('./actions'),
60
72
  canCurve: ({ node, nodes }) => !hasWallCurveBlockingChildren(node.children.flatMap((childId) => {
61
73
  const child = nodes[childId];
62
74
  return child ? [child] : [];
@@ -82,6 +94,7 @@ export const wallDefinition = {
82
94
  selectable: { hitVolume: 'bbox' },
83
95
  // Front + back faces host items (paintings, shelves, switches).
84
96
  surfaces: {
97
+ hosting: false,
85
98
  top: {
86
99
  height: (node, { nodes }) => {
87
100
  const wall = node;
@@ -101,7 +114,7 @@ export const wallDefinition = {
101
114
  // `{ slotId, label, default }` contract every other paintable kind exposes.
102
115
  // Paint still writes the legacy inline fields for base faces via
103
116
  // `wallPaint`; migrating those fully into `node.slots` is a later step.
104
- slots: () => wallSlots(),
117
+ slots: (node) => wallSlots(node),
105
118
  },
106
119
  relations: {
107
120
  hosts: ['door', 'window', 'item', 'lean-to-extension'],
@@ -125,6 +138,7 @@ export const wallDefinition = {
125
138
  curve: () => import('./curve-tool'),
126
139
  'move-endpoint': () => import('./move-endpoint-tool'),
127
140
  move: () => import('./move-tool'),
141
+ split: () => import('./split-tool'),
128
142
  },
129
143
  renderer: {
130
144
  kind: 'parametric',
@@ -159,8 +173,55 @@ export const wallDefinition = {
159
173
  floorplanSiblingOverrides: wallFloorplanSiblingOverrides,
160
174
  toolHints: [
161
175
  { key: 'Left click', label: 'Set wall start / end' },
176
+ {
177
+ key: 'R',
178
+ label: 'Shape',
179
+ chip: {
180
+ subscribe: (onChange) => useWallDrawingMode.subscribe(onChange),
181
+ value: () => useWallDrawingMode.getState().mode,
182
+ cycle: () => useWallDrawingMode.getState().toggle(),
183
+ labels: { line: 'Shape: Line', rectangle: 'Shape: Rectangle' },
184
+ icons: { line: 'lucide:minus', rectangle: 'lucide:square' },
185
+ tooltip: 'Wall shape — click or press R to toggle',
186
+ },
187
+ },
162
188
  { key: 'Esc', label: 'Cancel' },
163
189
  ],
190
+ // The split session (`split-session.ts`) is the wall's own reshape; the HUD
191
+ // shows these while it runs. The snapping chip comes from the scope.
192
+ affordanceHints: {
193
+ split: [
194
+ { key: 'Left click', label: 'Split at the marks' },
195
+ {
196
+ key: 'Scroll',
197
+ label: 'Cuts',
198
+ chip: {
199
+ subscribe: (onChange) => useWallSplit.subscribe(onChange),
200
+ value: () => String(useWallSplit.getState().draft?.cuts ?? 1),
201
+ cycle: () => {
202
+ const cuts = useWallSplit.getState().draft?.cuts ?? 1;
203
+ setWallSplitCuts(cuts >= WALL_SPLIT_MAX_CUTS ? 1 : cuts + 1);
204
+ },
205
+ labels: Object.fromEntries(SPLIT_CUT_COUNTS.map((count) => [
206
+ count,
207
+ count === '1' ? 'Cuts: 1' : `Cuts: ${count}, even`,
208
+ ])),
209
+ icons: Object.fromEntries(SPLIT_CUT_COUNTS.map((count) => [count, 'lucide:scissors'])),
210
+ tooltip: 'Number of cuts — scroll or click to change',
211
+ },
212
+ },
213
+ {
214
+ key: 'Alt',
215
+ label: 'Free placement',
216
+ // Several cuts are evenly spaced, so there is nothing to place freely.
217
+ visible: {
218
+ subscribe: (onChange) => useWallSplit.subscribe(onChange),
219
+ value: () => (useWallSplit.getState().draft?.cuts ?? 1) === 1,
220
+ },
221
+ },
222
+ { key: 'Esc', label: 'Cancel' },
223
+ ],
224
+ },
164
225
  presentation: {
165
226
  label: 'Wall',
166
227
  description: 'A straight or curved wall segment. Hosts doors, windows, lean-to extensions, and wall-mounted items.',
@@ -169,6 +230,6 @@ export const wallDefinition = {
169
230
  paletteOrder: 10,
170
231
  },
171
232
  mcp: {
172
- description: 'A wall segment defined by start + end points, with optional curve sagitta.',
233
+ description: 'A wall defined by endpoints and optional curve sagitta. wallType selects standard or curtain. curtainWall configures construction, framing, grids, glazing, spandrels, and zero-based panel overrides. Thickness is frame depth for curtain walls.',
173
234
  },
174
235
  };
@@ -0,0 +1,12 @@
1
+ export declare const useWallDrawingMode: import("zustand").UseBoundStore<import("zustand").StoreApi<{
2
+ mode: "line" | "rectangle";
3
+ toggle: () => void;
4
+ }>>;
5
+ /**
6
+ * R toggles line / rectangle drawing (the HUD's Shape chip cycles the same
7
+ * store). Both wall tools mount this: the 3D tool only exists once the canvas
8
+ * does, and split view mounts both, so one listener serves whichever is up.
9
+ * The mode outlives the tool: re-arming walls resumes the last shape used.
10
+ */
11
+ export declare function useWallDrawingModeKeys(): void;
12
+ //# sourceMappingURL=drawing-mode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"drawing-mode.d.ts","sourceRoot":"","sources":["../../src/wall/drawing-mode.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,kBAAkB;UACvB,MAAM,GAAG,WAAW;YAClB,MAAM,IAAI;GAOjB,CAAA;AAWH;;;;;GAKG;AACH,wBAAgB,sBAAsB,SAOrC"}