@pascal-app/nodes 1.0.0-beta.5 → 1.0.0

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 (831) hide show
  1. package/LICENSE +21 -0
  2. package/dist/block/commands.d.ts +68 -0
  3. package/dist/block/commands.d.ts.map +1 -0
  4. package/dist/block/commands.js +1144 -0
  5. package/dist/block/contextual-help.d.ts +3 -0
  6. package/dist/block/contextual-help.d.ts.map +1 -0
  7. package/dist/block/contextual-help.js +38 -0
  8. package/dist/block/definition.d.ts +8 -0
  9. package/dist/block/definition.d.ts.map +1 -0
  10. package/dist/block/definition.js +126 -0
  11. package/dist/block/edit-session.d.ts +16 -0
  12. package/dist/block/edit-session.d.ts.map +1 -0
  13. package/dist/block/edit-session.js +32 -0
  14. package/dist/block/face-host.d.ts +3 -0
  15. package/dist/block/face-host.d.ts.map +1 -0
  16. package/dist/block/face-host.js +178 -0
  17. package/dist/block/floorplan.d.ts +3 -0
  18. package/dist/block/floorplan.d.ts.map +1 -0
  19. package/dist/block/floorplan.js +43 -0
  20. package/dist/block/geometry-snap.d.ts +18 -0
  21. package/dist/block/geometry-snap.d.ts.map +1 -0
  22. package/dist/block/geometry-snap.js +137 -0
  23. package/dist/block/geometry.d.ts +11 -0
  24. package/dist/block/geometry.d.ts.map +1 -0
  25. package/dist/block/geometry.js +146 -0
  26. package/dist/block/gesture-wheel.d.ts +8 -0
  27. package/dist/block/gesture-wheel.d.ts.map +1 -0
  28. package/dist/block/gesture-wheel.js +7 -0
  29. package/dist/block/interaction-sfx.d.ts +3 -0
  30. package/dist/block/interaction-sfx.d.ts.map +1 -0
  31. package/dist/block/interaction-sfx.js +16 -0
  32. package/dist/block/last-operation.d.ts +48 -0
  33. package/dist/block/last-operation.d.ts.map +1 -0
  34. package/dist/block/last-operation.js +120 -0
  35. package/dist/block/loop-cut-interaction.d.ts +5 -0
  36. package/dist/block/loop-cut-interaction.d.ts.map +1 -0
  37. package/dist/block/loop-cut-interaction.js +13 -0
  38. package/dist/block/material-slots.d.ts +61 -0
  39. package/dist/block/material-slots.d.ts.map +1 -0
  40. package/dist/block/material-slots.js +131 -0
  41. package/dist/block/modal-face-operation.d.ts +13 -0
  42. package/dist/block/modal-face-operation.d.ts.map +1 -0
  43. package/dist/block/modal-face-operation.js +40 -0
  44. package/dist/block/modal-session.d.ts +15 -0
  45. package/dist/block/modal-session.d.ts.map +1 -0
  46. package/dist/block/modal-session.js +40 -0
  47. package/dist/block/modal-transform.d.ts +30 -0
  48. package/dist/block/modal-transform.d.ts.map +1 -0
  49. package/dist/block/modal-transform.js +144 -0
  50. package/dist/block/paint.d.ts +3 -0
  51. package/dist/block/paint.d.ts.map +1 -0
  52. package/dist/block/paint.js +136 -0
  53. package/dist/block/panel.d.ts +2 -0
  54. package/dist/block/panel.d.ts.map +1 -0
  55. package/dist/block/panel.js +234 -0
  56. package/dist/block/parametrics.d.ts +4 -0
  57. package/dist/block/parametrics.d.ts.map +1 -0
  58. package/dist/block/parametrics.js +9 -0
  59. package/dist/block/preview.d.ts +6 -0
  60. package/dist/block/preview.d.ts.map +1 -0
  61. package/dist/block/preview.js +46 -0
  62. package/dist/block/rotation-drag.d.ts +5 -0
  63. package/dist/block/rotation-drag.d.ts.map +1 -0
  64. package/dist/block/rotation-drag.js +18 -0
  65. package/dist/block/schema.d.ts +2 -0
  66. package/dist/block/schema.d.ts.map +1 -0
  67. package/dist/block/schema.js +1 -0
  68. package/dist/block/selection-geometry.d.ts +9 -0
  69. package/dist/block/selection-geometry.d.ts.map +1 -0
  70. package/dist/block/selection-geometry.js +31 -0
  71. package/dist/block/selection-model.d.ts +17 -0
  72. package/dist/block/selection-model.d.ts.map +1 -0
  73. package/dist/block/selection-model.js +84 -0
  74. package/dist/block/selection.d.ts +4 -0
  75. package/dist/block/selection.d.ts.map +1 -0
  76. package/dist/block/selection.js +2570 -0
  77. package/dist/block/slots.d.ts +4 -0
  78. package/dist/block/slots.d.ts.map +1 -0
  79. package/dist/block/slots.js +17 -0
  80. package/dist/block/tool.d.ts +3 -0
  81. package/dist/block/tool.d.ts.map +1 -0
  82. package/dist/block/tool.js +174 -0
  83. package/dist/block/toolbar-state.d.ts +46 -0
  84. package/dist/block/toolbar-state.d.ts.map +1 -0
  85. package/dist/block/toolbar-state.js +67 -0
  86. package/dist/block/use-block-face-operation.d.ts +39 -0
  87. package/dist/block/use-block-face-operation.d.ts.map +1 -0
  88. package/dist/block/use-block-face-operation.js +218 -0
  89. package/dist/box-vent/definition.d.ts.map +1 -1
  90. package/dist/box-vent/definition.js +8 -5
  91. package/dist/box-vent/geometry.d.ts +4 -0
  92. package/dist/box-vent/geometry.d.ts.map +1 -1
  93. package/dist/box-vent/geometry.js +76 -44
  94. package/dist/box-vent/paint.d.ts +4 -0
  95. package/dist/box-vent/paint.d.ts.map +1 -0
  96. package/dist/box-vent/paint.js +40 -0
  97. package/dist/box-vent/panel.js +1 -1
  98. package/dist/box-vent/parametrics.js +3 -3
  99. package/dist/box-vent/renderer.d.ts.map +1 -1
  100. package/dist/box-vent/renderer.js +29 -10
  101. package/dist/cabinet/compartment-card.d.ts.map +1 -1
  102. package/dist/cabinet/compartment-card.js +11 -3
  103. package/dist/cabinet/continuous-placement.d.ts +3 -0
  104. package/dist/cabinet/continuous-placement.d.ts.map +1 -1
  105. package/dist/cabinet/continuous-placement.js +6 -0
  106. package/dist/cabinet/definition.d.ts.map +1 -1
  107. package/dist/cabinet/definition.js +400 -54
  108. package/dist/cabinet/floorplan-move.d.ts.map +1 -1
  109. package/dist/cabinet/floorplan-move.js +91 -22
  110. package/dist/cabinet/geometry/fridge.d.ts.map +1 -1
  111. package/dist/cabinet/geometry/fridge.js +25 -1
  112. package/dist/cabinet/geometry/fronts.d.ts +4 -0
  113. package/dist/cabinet/geometry/fronts.d.ts.map +1 -1
  114. package/dist/cabinet/geometry/fronts.js +1 -1
  115. package/dist/cabinet/geometry/run.d.ts.map +1 -1
  116. package/dist/cabinet/geometry/run.js +19 -1
  117. package/dist/cabinet/geometry.d.ts.map +1 -1
  118. package/dist/cabinet/geometry.js +63 -1
  119. package/dist/cabinet/index.d.ts +1 -0
  120. package/dist/cabinet/index.d.ts.map +1 -1
  121. package/dist/cabinet/index.js +1 -0
  122. package/dist/cabinet/insertion.d.ts +19 -0
  123. package/dist/cabinet/insertion.d.ts.map +1 -0
  124. package/dist/cabinet/insertion.js +49 -0
  125. package/dist/cabinet/move-frame.d.ts.map +1 -1
  126. package/dist/cabinet/move-frame.js +68 -2
  127. package/dist/cabinet/panel-context.d.ts +7 -0
  128. package/dist/cabinet/panel-context.d.ts.map +1 -0
  129. package/dist/cabinet/panel-context.js +16 -0
  130. package/dist/cabinet/panel-visibility.d.ts +9 -0
  131. package/dist/cabinet/panel-visibility.d.ts.map +1 -0
  132. package/dist/cabinet/panel-visibility.js +26 -0
  133. package/dist/cabinet/panel.d.ts.map +1 -1
  134. package/dist/cabinet/panel.js +221 -37
  135. package/dist/cabinet/placement-dimensions.d.ts +42 -0
  136. package/dist/cabinet/placement-dimensions.d.ts.map +1 -0
  137. package/dist/cabinet/placement-dimensions.js +227 -0
  138. package/dist/cabinet/placement-snap.d.ts +21 -1
  139. package/dist/cabinet/placement-snap.d.ts.map +1 -1
  140. package/dist/cabinet/placement-snap.js +48 -6
  141. package/dist/cabinet/preset-width-debt.d.ts +7 -0
  142. package/dist/cabinet/preset-width-debt.d.ts.map +1 -0
  143. package/dist/cabinet/preset-width-debt.js +45 -0
  144. package/dist/cabinet/presets.d.ts.map +1 -1
  145. package/dist/cabinet/presets.js +14 -13
  146. package/dist/cabinet/profiles.d.ts +14 -0
  147. package/dist/cabinet/profiles.d.ts.map +1 -0
  148. package/dist/cabinet/profiles.js +30 -0
  149. package/dist/cabinet/quick-actions.d.ts.map +1 -1
  150. package/dist/cabinet/quick-actions.js +8 -24
  151. package/dist/cabinet/reveals.d.ts +37 -0
  152. package/dist/cabinet/reveals.d.ts.map +1 -0
  153. package/dist/cabinet/reveals.js +13 -0
  154. package/dist/cabinet/run-layout.d.ts +90 -4
  155. package/dist/cabinet/run-layout.d.ts.map +1 -1
  156. package/dist/cabinet/run-layout.js +408 -23
  157. package/dist/cabinet/run-ops.d.ts +202 -10
  158. package/dist/cabinet/run-ops.d.ts.map +1 -1
  159. package/dist/cabinet/run-ops.js +520 -33
  160. package/dist/cabinet/run-panel.d.ts +6 -2
  161. package/dist/cabinet/run-panel.d.ts.map +1 -1
  162. package/dist/cabinet/run-panel.js +285 -108
  163. package/dist/cabinet/stack-transitions.d.ts.map +1 -1
  164. package/dist/cabinet/stack-transitions.js +35 -24
  165. package/dist/cabinet/stack.d.ts +169 -1
  166. package/dist/cabinet/stack.d.ts.map +1 -1
  167. package/dist/cabinet/stack.js +57 -18
  168. package/dist/cabinet/tool.d.ts.map +1 -1
  169. package/dist/cabinet/tool.js +615 -91
  170. package/dist/cabinet/validation.d.ts +27 -0
  171. package/dist/cabinet/validation.d.ts.map +1 -0
  172. package/dist/cabinet/validation.js +56 -0
  173. package/dist/cabinet/wall-height-presets.d.ts +12 -0
  174. package/dist/cabinet/wall-height-presets.d.ts.map +1 -0
  175. package/dist/cabinet/wall-height-presets.js +15 -0
  176. package/dist/cabinet/wall-snap.d.ts +27 -3
  177. package/dist/cabinet/wall-snap.d.ts.map +1 -1
  178. package/dist/cabinet/wall-snap.js +278 -62
  179. package/dist/cabinet/widths.d.ts +10 -0
  180. package/dist/cabinet/widths.d.ts.map +1 -0
  181. package/dist/cabinet/widths.js +13 -0
  182. package/dist/ceiling/definition.d.ts.map +1 -1
  183. package/dist/ceiling/definition.js +7 -1
  184. package/dist/ceiling/floorplan-affordances.d.ts +8 -8
  185. package/dist/ceiling/materials.d.ts.map +1 -1
  186. package/dist/ceiling/materials.js +0 -1
  187. package/dist/ceiling/panel.js +1 -1
  188. package/dist/ceiling/parametrics.js +1 -1
  189. package/dist/chimney/definition.js +1 -1
  190. package/dist/chimney/panel.js +1 -1
  191. package/dist/chimney/parametrics.js +3 -3
  192. package/dist/column/definition.d.ts.map +1 -1
  193. package/dist/column/definition.js +22 -4
  194. package/dist/column/panel.d.ts.map +1 -1
  195. package/dist/column/panel.js +37 -7
  196. package/dist/column/parametrics.d.ts.map +1 -1
  197. package/dist/column/parametrics.js +5 -3
  198. package/dist/column/tool.d.ts.map +1 -1
  199. package/dist/column/tool.js +50 -14
  200. package/dist/cupola/definition.d.ts.map +1 -1
  201. package/dist/cupola/definition.js +15 -6
  202. package/dist/cupola/geometry.d.ts +6 -0
  203. package/dist/cupola/geometry.d.ts.map +1 -1
  204. package/dist/cupola/geometry.js +60 -13
  205. package/dist/cupola/paint.d.ts +4 -0
  206. package/dist/cupola/paint.d.ts.map +1 -0
  207. package/dist/cupola/paint.js +39 -0
  208. package/dist/cupola/panel.js +1 -1
  209. package/dist/cupola/parametrics.js +3 -3
  210. package/dist/cupola/renderer.d.ts.map +1 -1
  211. package/dist/cupola/renderer.js +27 -8
  212. package/dist/door/floorplan-move.d.ts.map +1 -1
  213. package/dist/door/floorplan-move.js +1 -1
  214. package/dist/door/move-tool.d.ts.map +1 -1
  215. package/dist/door/move-tool.js +86 -32
  216. package/dist/door/panel.d.ts.map +1 -1
  217. package/dist/door/panel.js +1 -1
  218. package/dist/door/parametrics.js +2 -2
  219. package/dist/door/tool.d.ts.map +1 -1
  220. package/dist/door/tool.js +16 -4
  221. package/dist/dormer/csg-geometry.d.ts +6 -42
  222. package/dist/dormer/csg-geometry.d.ts.map +1 -1
  223. package/dist/dormer/csg-geometry.js +38 -209
  224. package/dist/dormer/definition.d.ts +4 -12
  225. package/dist/dormer/definition.d.ts.map +1 -1
  226. package/dist/dormer/definition.js +18 -193
  227. package/dist/dormer/floorplan.d.ts +3 -3
  228. package/dist/dormer/floorplan.d.ts.map +1 -1
  229. package/dist/dormer/floorplan.js +6 -17
  230. package/dist/dormer/geometry.d.ts +5 -24
  231. package/dist/dormer/geometry.d.ts.map +1 -1
  232. package/dist/dormer/geometry.js +64 -41
  233. package/dist/dormer/index.d.ts +1 -1
  234. package/dist/dormer/index.d.ts.map +1 -1
  235. package/dist/dormer/index.js +1 -1
  236. package/dist/dormer/move-tool.d.ts.map +1 -1
  237. package/dist/dormer/move-tool.js +31 -3
  238. package/dist/dormer/panel-windows-section.d.ts +9 -0
  239. package/dist/dormer/panel-windows-section.d.ts.map +1 -0
  240. package/dist/dormer/panel-windows-section.js +7 -0
  241. package/dist/dormer/panel.d.ts.map +1 -1
  242. package/dist/dormer/panel.js +100 -18
  243. package/dist/dormer/parametrics.d.ts.map +1 -1
  244. package/dist/dormer/parametrics.js +8 -77
  245. package/dist/dormer/preview.d.ts.map +1 -1
  246. package/dist/dormer/preview.js +9 -1
  247. package/dist/dormer/renderer.d.ts.map +1 -1
  248. package/dist/dormer/renderer.js +24 -26
  249. package/dist/dormer/tool.d.ts.map +1 -1
  250. package/dist/dormer/tool.js +3 -1
  251. package/dist/dormer/window-layout.d.ts +15 -0
  252. package/dist/dormer/window-layout.d.ts.map +1 -0
  253. package/dist/dormer/window-layout.js +59 -0
  254. package/dist/downspout/definition.d.ts.map +1 -1
  255. package/dist/downspout/definition.js +17 -4
  256. package/dist/downspout/geometry.d.ts.map +1 -1
  257. package/dist/downspout/geometry.js +10 -0
  258. package/dist/downspout/inspector-editors.d.ts.map +1 -1
  259. package/dist/downspout/inspector-editors.js +9 -1
  260. package/dist/downspout/parametrics.d.ts.map +1 -1
  261. package/dist/downspout/parametrics.js +2 -1
  262. package/dist/downspout/renderer.d.ts.map +1 -1
  263. package/dist/downspout/renderer.js +19 -3
  264. package/dist/downspout/system.d.ts +7 -0
  265. package/dist/downspout/system.d.ts.map +1 -0
  266. package/dist/downspout/system.js +114 -0
  267. package/dist/duct-fitting/accessory-geometry.d.ts +4 -0
  268. package/dist/duct-fitting/accessory-geometry.d.ts.map +1 -0
  269. package/dist/duct-fitting/accessory-geometry.js +47 -0
  270. package/dist/duct-fitting/definition.d.ts.map +1 -1
  271. package/dist/duct-fitting/definition.js +11 -1
  272. package/dist/duct-fitting/floorplan.d.ts.map +1 -1
  273. package/dist/duct-fitting/floorplan.js +8 -0
  274. package/dist/duct-fitting/geometry.d.ts.map +1 -1
  275. package/dist/duct-fitting/geometry.js +52 -38
  276. package/dist/duct-fitting/parametrics.d.ts.map +1 -1
  277. package/dist/duct-fitting/parametrics.js +78 -15
  278. package/dist/duct-fitting/ports.d.ts +1 -0
  279. package/dist/duct-fitting/ports.d.ts.map +1 -1
  280. package/dist/duct-fitting/ports.js +46 -0
  281. package/dist/duct-fitting/tool.d.ts +19 -0
  282. package/dist/duct-fitting/tool.d.ts.map +1 -1
  283. package/dist/duct-fitting/tool.js +126 -34
  284. package/dist/duct-segment/continuation.d.ts +21 -0
  285. package/dist/duct-segment/continuation.d.ts.map +1 -0
  286. package/dist/duct-segment/continuation.js +167 -0
  287. package/dist/duct-segment/definition.d.ts.map +1 -1
  288. package/dist/duct-segment/definition.js +19 -18
  289. package/dist/duct-segment/floorplan.d.ts.map +1 -1
  290. package/dist/duct-segment/floorplan.js +43 -0
  291. package/dist/duct-segment/geometry.d.ts.map +1 -1
  292. package/dist/duct-segment/geometry.js +3 -0
  293. package/dist/duct-segment/move-tool.d.ts.map +1 -1
  294. package/dist/duct-segment/move-tool.js +33 -6
  295. package/dist/duct-segment/parametrics.d.ts.map +1 -1
  296. package/dist/duct-segment/parametrics.js +45 -1
  297. package/dist/duct-segment/selection.d.ts +3 -4
  298. package/dist/duct-segment/selection.d.ts.map +1 -1
  299. package/dist/duct-segment/selection.js +186 -158
  300. package/dist/duct-segment/tool.d.ts +37 -0
  301. package/dist/duct-segment/tool.d.ts.map +1 -1
  302. package/dist/duct-segment/tool.js +305 -678
  303. package/dist/duct-terminal/parametrics.js +2 -2
  304. package/dist/duct-terminal/tool.d.ts.map +1 -1
  305. package/dist/duct-terminal/tool.js +37 -7
  306. package/dist/elevator/panel.d.ts.map +1 -1
  307. package/dist/elevator/panel.js +7 -7
  308. package/dist/elevator/system.d.ts.map +1 -1
  309. package/dist/elevator/system.js +10 -1
  310. package/dist/eyebrow-vent/definition.d.ts.map +1 -1
  311. package/dist/eyebrow-vent/definition.js +8 -5
  312. package/dist/eyebrow-vent/geometry.d.ts +4 -0
  313. package/dist/eyebrow-vent/geometry.d.ts.map +1 -1
  314. package/dist/eyebrow-vent/geometry.js +60 -15
  315. package/dist/eyebrow-vent/paint.d.ts +4 -0
  316. package/dist/eyebrow-vent/paint.d.ts.map +1 -0
  317. package/dist/eyebrow-vent/paint.js +33 -0
  318. package/dist/eyebrow-vent/panel.js +1 -1
  319. package/dist/eyebrow-vent/parametrics.js +3 -3
  320. package/dist/eyebrow-vent/renderer.d.ts.map +1 -1
  321. package/dist/eyebrow-vent/renderer.js +27 -8
  322. package/dist/fence/definition.d.ts.map +1 -1
  323. package/dist/fence/definition.js +2 -1
  324. package/dist/fence/floorplan-affordances.d.ts +1 -0
  325. package/dist/fence/floorplan-affordances.d.ts.map +1 -1
  326. package/dist/fence/floorplan-affordances.js +30 -1
  327. package/dist/fence/floorplan.d.ts.map +1 -1
  328. package/dist/fence/floorplan.js +14 -0
  329. package/dist/fence/parametrics.js +3 -3
  330. package/dist/fence/tool.d.ts.map +1 -1
  331. package/dist/fence/tool.js +47 -20
  332. package/dist/gutter/corner-mitre.d.ts.map +1 -1
  333. package/dist/gutter/corner-mitre.js +47 -7
  334. package/dist/gutter/definition.d.ts.map +1 -1
  335. package/dist/gutter/definition.js +23 -13
  336. package/dist/gutter/eave-align.d.ts.map +1 -1
  337. package/dist/gutter/eave-align.js +10 -0
  338. package/dist/gutter/eave-snap.d.ts +1 -1
  339. package/dist/gutter/eave-snap.d.ts.map +1 -1
  340. package/dist/gutter/eave-snap.js +10 -23
  341. package/dist/gutter/geometry.d.ts.map +1 -1
  342. package/dist/gutter/geometry.js +126 -8
  343. package/dist/gutter/outlet-lookup.d.ts.map +1 -1
  344. package/dist/gutter/outlet-lookup.js +22 -1
  345. package/dist/gutter/paint.d.ts +3 -0
  346. package/dist/gutter/paint.d.ts.map +1 -0
  347. package/dist/gutter/paint.js +6 -0
  348. package/dist/gutter/parametrics.d.ts.map +1 -1
  349. package/dist/gutter/parametrics.js +4 -1
  350. package/dist/gutter/renderer.d.ts.map +1 -1
  351. package/dist/gutter/renderer.js +63 -7
  352. package/dist/gutter/trim-clip.d.ts +3 -0
  353. package/dist/gutter/trim-clip.d.ts.map +1 -0
  354. package/dist/gutter/trim-clip.js +5 -0
  355. package/dist/hvac-equipment/parametrics.js +3 -3
  356. package/dist/hvac-equipment/tool.d.ts.map +1 -1
  357. package/dist/hvac-equipment/tool.js +12 -2
  358. package/dist/index.d.ts +5 -2
  359. package/dist/index.d.ts.map +1 -1
  360. package/dist/index.js +9 -2
  361. package/dist/item/definition.d.ts.map +1 -1
  362. package/dist/item/definition.js +10 -2
  363. package/dist/item/floorplan-move.d.ts.map +1 -1
  364. package/dist/item/floorplan-move.js +20 -1
  365. package/dist/item/floorplan.d.ts.map +1 -1
  366. package/dist/item/floorplan.js +22 -1
  367. package/dist/item/move-tool.d.ts +28 -1
  368. package/dist/item/move-tool.d.ts.map +1 -1
  369. package/dist/item/move-tool.js +14 -2
  370. package/dist/item/renderer.d.ts.map +1 -1
  371. package/dist/item/renderer.js +16 -6
  372. package/dist/item/system.d.ts +5 -0
  373. package/dist/item/system.d.ts.map +1 -1
  374. package/dist/item/system.js +7 -1
  375. package/dist/lean-to-extension/arc.d.ts +14 -0
  376. package/dist/lean-to-extension/arc.d.ts.map +1 -0
  377. package/dist/lean-to-extension/arc.js +56 -0
  378. package/dist/lean-to-extension/assembly.d.ts +61 -0
  379. package/dist/lean-to-extension/assembly.d.ts.map +1 -0
  380. package/dist/lean-to-extension/assembly.js +761 -0
  381. package/dist/lean-to-extension/canopy-joint.d.ts +35 -0
  382. package/dist/lean-to-extension/canopy-joint.d.ts.map +1 -0
  383. package/dist/lean-to-extension/canopy-joint.js +234 -0
  384. package/dist/lean-to-extension/conical-host.d.ts +15 -0
  385. package/dist/lean-to-extension/conical-host.d.ts.map +1 -0
  386. package/dist/lean-to-extension/conical-host.js +113 -0
  387. package/dist/lean-to-extension/corner-joint.d.ts +29 -0
  388. package/dist/lean-to-extension/corner-joint.d.ts.map +1 -0
  389. package/dist/lean-to-extension/corner-joint.js +1202 -0
  390. package/dist/lean-to-extension/definition.d.ts +4 -0
  391. package/dist/lean-to-extension/definition.d.ts.map +1 -0
  392. package/dist/lean-to-extension/definition.js +433 -0
  393. package/dist/lean-to-extension/floorplan-affordances.d.ts +4 -0
  394. package/dist/lean-to-extension/floorplan-affordances.d.ts.map +1 -0
  395. package/dist/lean-to-extension/floorplan-affordances.js +144 -0
  396. package/dist/lean-to-extension/floorplan-move.d.ts +3 -0
  397. package/dist/lean-to-extension/floorplan-move.d.ts.map +1 -0
  398. package/dist/lean-to-extension/floorplan-move.js +157 -0
  399. package/dist/lean-to-extension/floorplan-tool.d.ts +4 -0
  400. package/dist/lean-to-extension/floorplan-tool.d.ts.map +1 -0
  401. package/dist/lean-to-extension/floorplan-tool.js +385 -0
  402. package/dist/lean-to-extension/floorplan.d.ts +3 -0
  403. package/dist/lean-to-extension/floorplan.d.ts.map +1 -0
  404. package/dist/lean-to-extension/floorplan.js +373 -0
  405. package/dist/lean-to-extension/geometry.d.ts +7 -0
  406. package/dist/lean-to-extension/geometry.d.ts.map +1 -0
  407. package/dist/lean-to-extension/geometry.js +662 -0
  408. package/dist/lean-to-extension/index.d.ts +8 -0
  409. package/dist/lean-to-extension/index.d.ts.map +1 -0
  410. package/dist/lean-to-extension/index.js +7 -0
  411. package/dist/lean-to-extension/layout.d.ts +108 -0
  412. package/dist/lean-to-extension/layout.d.ts.map +1 -0
  413. package/dist/lean-to-extension/layout.js +477 -0
  414. package/dist/lean-to-extension/managed-preview.d.ts +3 -0
  415. package/dist/lean-to-extension/managed-preview.d.ts.map +1 -0
  416. package/dist/lean-to-extension/managed-preview.js +93 -0
  417. package/dist/lean-to-extension/move-tool.d.ts +8 -0
  418. package/dist/lean-to-extension/move-tool.d.ts.map +1 -0
  419. package/dist/lean-to-extension/move-tool.js +202 -0
  420. package/dist/lean-to-extension/paint.d.ts +2 -0
  421. package/dist/lean-to-extension/paint.d.ts.map +1 -0
  422. package/dist/lean-to-extension/paint.js +16 -0
  423. package/dist/lean-to-extension/parametrics.d.ts +4 -0
  424. package/dist/lean-to-extension/parametrics.d.ts.map +1 -0
  425. package/dist/lean-to-extension/parametrics.js +570 -0
  426. package/dist/lean-to-extension/placement-scope.d.ts +3 -0
  427. package/dist/lean-to-extension/placement-scope.d.ts.map +1 -0
  428. package/dist/lean-to-extension/placement-scope.js +4 -0
  429. package/dist/lean-to-extension/placement-validation.d.ts +4 -0
  430. package/dist/lean-to-extension/placement-validation.d.ts.map +1 -0
  431. package/dist/lean-to-extension/placement-validation.js +324 -0
  432. package/dist/lean-to-extension/placement.d.ts +59 -0
  433. package/dist/lean-to-extension/placement.d.ts.map +1 -0
  434. package/dist/lean-to-extension/placement.js +331 -0
  435. package/dist/lean-to-extension/plan-footprint.d.ts +10 -0
  436. package/dist/lean-to-extension/plan-footprint.d.ts.map +1 -0
  437. package/dist/lean-to-extension/plan-footprint.js +27 -0
  438. package/dist/lean-to-extension/preview-geometry.d.ts +7 -0
  439. package/dist/lean-to-extension/preview-geometry.d.ts.map +1 -0
  440. package/dist/lean-to-extension/preview-geometry.js +40 -0
  441. package/dist/lean-to-extension/preview.d.ts +7 -0
  442. package/dist/lean-to-extension/preview.d.ts.map +1 -0
  443. package/dist/lean-to-extension/preview.js +20 -0
  444. package/dist/lean-to-extension/renderer.d.ts +6 -0
  445. package/dist/lean-to-extension/renderer.d.ts.map +1 -0
  446. package/dist/lean-to-extension/renderer.js +34 -0
  447. package/dist/lean-to-extension/roof-attachment.d.ts +28 -0
  448. package/dist/lean-to-extension/roof-attachment.d.ts.map +1 -0
  449. package/dist/lean-to-extension/roof-attachment.js +376 -0
  450. package/dist/lean-to-extension/schema.d.ts +2 -0
  451. package/dist/lean-to-extension/schema.d.ts.map +1 -0
  452. package/dist/lean-to-extension/schema.js +1 -0
  453. package/dist/lean-to-extension/slots.d.ts +5 -0
  454. package/dist/lean-to-extension/slots.d.ts.map +1 -0
  455. package/dist/lean-to-extension/slots.js +15 -0
  456. package/dist/lean-to-extension/system.d.ts +7 -0
  457. package/dist/lean-to-extension/system.d.ts.map +1 -0
  458. package/dist/lean-to-extension/system.js +726 -0
  459. package/dist/lean-to-extension/tool.d.ts +3 -0
  460. package/dist/lean-to-extension/tool.d.ts.map +1 -0
  461. package/dist/lean-to-extension/tool.js +580 -0
  462. package/dist/lean-to-extension/wall-target.d.ts +10 -0
  463. package/dist/lean-to-extension/wall-target.d.ts.map +1 -0
  464. package/dist/lean-to-extension/wall-target.js +29 -0
  465. package/dist/lineset/definition.d.ts.map +1 -1
  466. package/dist/lineset/definition.js +1 -0
  467. package/dist/liquid-line/definition.d.ts.map +1 -1
  468. package/dist/liquid-line/definition.js +1 -0
  469. package/dist/pipe-fitting/definition.d.ts.map +1 -1
  470. package/dist/pipe-fitting/definition.js +16 -2
  471. package/dist/pipe-fitting/floorplan.d.ts.map +1 -1
  472. package/dist/pipe-fitting/floorplan.js +4 -0
  473. package/dist/pipe-fitting/geometry.d.ts +3 -5
  474. package/dist/pipe-fitting/geometry.d.ts.map +1 -1
  475. package/dist/pipe-fitting/geometry.js +154 -21
  476. package/dist/pipe-fitting/inline-insertion.d.ts +13 -0
  477. package/dist/pipe-fitting/inline-insertion.d.ts.map +1 -0
  478. package/dist/pipe-fitting/inline-insertion.js +96 -0
  479. package/dist/pipe-fitting/parametrics.d.ts.map +1 -1
  480. package/dist/pipe-fitting/parametrics.js +17 -3
  481. package/dist/pipe-fitting/ports.d.ts.map +1 -1
  482. package/dist/pipe-fitting/ports.js +8 -1
  483. package/dist/pipe-fitting/tool.d.ts +26 -0
  484. package/dist/pipe-fitting/tool.d.ts.map +1 -1
  485. package/dist/pipe-fitting/tool.js +182 -37
  486. package/dist/pipe-segment/continuation.d.ts +22 -0
  487. package/dist/pipe-segment/continuation.d.ts.map +1 -0
  488. package/dist/pipe-segment/continuation.js +146 -0
  489. package/dist/pipe-segment/definition.d.ts.map +1 -1
  490. package/dist/pipe-segment/definition.js +23 -7
  491. package/dist/pipe-segment/floorplan.d.ts.map +1 -1
  492. package/dist/pipe-segment/floorplan.js +42 -0
  493. package/dist/pipe-segment/geometry.d.ts +2 -1
  494. package/dist/pipe-segment/geometry.d.ts.map +1 -1
  495. package/dist/pipe-segment/geometry.js +4 -1
  496. package/dist/pipe-segment/move-tool.d.ts.map +1 -1
  497. package/dist/pipe-segment/move-tool.js +25 -5
  498. package/dist/pipe-segment/parametrics.d.ts.map +1 -1
  499. package/dist/pipe-segment/parametrics.js +45 -0
  500. package/dist/pipe-segment/selection.d.ts +3 -4
  501. package/dist/pipe-segment/selection.d.ts.map +1 -1
  502. package/dist/pipe-segment/selection.js +169 -105
  503. package/dist/pipe-segment/slope.d.ts +5 -0
  504. package/dist/pipe-segment/slope.d.ts.map +1 -0
  505. package/dist/pipe-segment/slope.js +10 -0
  506. package/dist/pipe-segment/tool.d.ts.map +1 -1
  507. package/dist/pipe-segment/tool.js +325 -545
  508. package/dist/pipe-trap/tool.d.ts.map +1 -1
  509. package/dist/pipe-trap/tool.js +15 -2
  510. package/dist/ridge-vent/definition.js +1 -1
  511. package/dist/ridge-vent/panel.d.ts.map +1 -1
  512. package/dist/ridge-vent/panel.js +2 -2
  513. package/dist/ridge-vent/parametrics.js +1 -1
  514. package/dist/roof/conical-roof-placement.d.ts +36 -0
  515. package/dist/roof/conical-roof-placement.d.ts.map +1 -0
  516. package/dist/roof/conical-roof-placement.js +134 -0
  517. package/dist/roof/conical-roof.d.ts +3 -0
  518. package/dist/roof/conical-roof.d.ts.map +1 -0
  519. package/dist/roof/conical-roof.js +53 -0
  520. package/dist/roof/definition.d.ts +3 -10
  521. package/dist/roof/definition.d.ts.map +1 -1
  522. package/dist/roof/definition.js +83 -13
  523. package/dist/roof/floorplan.d.ts +3 -10
  524. package/dist/roof/floorplan.d.ts.map +1 -1
  525. package/dist/roof/floorplan.js +139 -165
  526. package/dist/roof/index.d.ts +1 -0
  527. package/dist/roof/index.d.ts.map +1 -1
  528. package/dist/roof/index.js +1 -0
  529. package/dist/roof/panel.d.ts.map +1 -1
  530. package/dist/roof/panel.js +22 -23
  531. package/dist/roof/renderer.d.ts.map +1 -1
  532. package/dist/roof/roof-footprint-source.d.ts +16 -0
  533. package/dist/roof/roof-footprint-source.d.ts.map +1 -0
  534. package/dist/roof/roof-footprint-source.js +14 -0
  535. package/dist/roof/roof-footprint.d.ts +25 -0
  536. package/dist/roof/roof-footprint.d.ts.map +1 -0
  537. package/dist/roof/roof-footprint.js +94 -0
  538. package/dist/roof/roof-placement-mode.d.ts +18 -0
  539. package/dist/roof/roof-placement-mode.d.ts.map +1 -0
  540. package/dist/roof/roof-placement-mode.js +24 -0
  541. package/dist/roof/tool.d.ts +10 -0
  542. package/dist/roof/tool.d.ts.map +1 -0
  543. package/dist/roof/tool.js +922 -0
  544. package/dist/roof-segment/definition.d.ts.map +1 -1
  545. package/dist/roof-segment/definition.js +52 -8
  546. package/dist/roof-segment/floorplan-affordances.d.ts +5 -6
  547. package/dist/roof-segment/floorplan-affordances.d.ts.map +1 -1
  548. package/dist/roof-segment/floorplan-affordances.js +64 -18
  549. package/dist/roof-segment/floorplan.d.ts +3 -2
  550. package/dist/roof-segment/floorplan.d.ts.map +1 -1
  551. package/dist/roof-segment/floorplan.js +95 -46
  552. package/dist/roof-segment/panel.d.ts.map +1 -1
  553. package/dist/roof-segment/panel.js +122 -27
  554. package/dist/scan/definition.d.ts +2 -3
  555. package/dist/scan/definition.d.ts.map +1 -1
  556. package/dist/scan/definition.js +9 -7
  557. package/dist/scan/parametrics.d.ts.map +1 -1
  558. package/dist/scan/parametrics.js +13 -1
  559. package/dist/scan/renderer.d.ts.map +1 -1
  560. package/dist/scan/renderer.js +8 -2
  561. package/dist/shared/accessory-cursor.d.ts +7 -0
  562. package/dist/shared/accessory-cursor.d.ts.map +1 -0
  563. package/dist/shared/accessory-cursor.js +83 -0
  564. package/dist/shared/accessory-floorplan.d.ts +4 -0
  565. package/dist/shared/accessory-floorplan.d.ts.map +1 -0
  566. package/dist/shared/accessory-floorplan.js +51 -0
  567. package/dist/shared/accessory-geometry.d.ts +7 -0
  568. package/dist/shared/accessory-geometry.d.ts.map +1 -0
  569. package/dist/shared/accessory-geometry.js +79 -0
  570. package/dist/shared/accessory-placement.d.ts +10 -0
  571. package/dist/shared/accessory-placement.d.ts.map +1 -0
  572. package/dist/shared/accessory-placement.js +126 -0
  573. package/dist/shared/accessory-snapping.d.ts +5 -0
  574. package/dist/shared/accessory-snapping.d.ts.map +1 -0
  575. package/dist/shared/accessory-snapping.js +40 -0
  576. package/dist/shared/automatic-run-end-cap.d.ts +11 -0
  577. package/dist/shared/automatic-run-end-cap.d.ts.map +1 -0
  578. package/dist/shared/automatic-run-end-cap.js +159 -0
  579. package/dist/shared/block-face-host.d.ts +15 -0
  580. package/dist/shared/block-face-host.d.ts.map +1 -0
  581. package/dist/shared/block-face-host.js +36 -0
  582. package/dist/shared/connection-compatibility.d.ts +8 -0
  583. package/dist/shared/connection-compatibility.d.ts.map +1 -0
  584. package/dist/shared/connection-compatibility.js +28 -0
  585. package/dist/shared/connection-feedback.d.ts +10 -0
  586. package/dist/shared/connection-feedback.d.ts.map +1 -0
  587. package/dist/shared/connection-feedback.js +17 -0
  588. package/dist/shared/distribution-run-contract.d.ts +49 -0
  589. package/dist/shared/distribution-run-contract.d.ts.map +1 -0
  590. package/dist/shared/distribution-run-contract.js +30 -0
  591. package/dist/shared/distribution-run-tool.d.ts +107 -0
  592. package/dist/shared/distribution-run-tool.d.ts.map +1 -0
  593. package/dist/shared/distribution-run-tool.js +941 -0
  594. package/dist/shared/dormer-wall-opening-placement.d.ts +21 -0
  595. package/dist/shared/dormer-wall-opening-placement.d.ts.map +1 -0
  596. package/dist/shared/dormer-wall-opening-placement.js +101 -0
  597. package/dist/shared/duct-adapter.d.ts +10 -0
  598. package/dist/shared/duct-adapter.d.ts.map +1 -0
  599. package/dist/shared/duct-adapter.js +43 -0
  600. package/dist/shared/elbow-branch-continuation.d.ts +20 -0
  601. package/dist/shared/elbow-branch-continuation.d.ts.map +1 -0
  602. package/dist/shared/elbow-branch-continuation.js +200 -0
  603. package/dist/shared/fitting-clearance.d.ts +5 -0
  604. package/dist/shared/fitting-clearance.d.ts.map +1 -0
  605. package/dist/shared/fitting-clearance.js +11 -0
  606. package/dist/shared/fitting-deletion-cleanup.d.ts +14 -0
  607. package/dist/shared/fitting-deletion-cleanup.d.ts.map +1 -0
  608. package/dist/shared/fitting-deletion-cleanup.js +297 -0
  609. package/dist/shared/fitting-surface-support.d.ts +5 -0
  610. package/dist/shared/fitting-surface-support.d.ts.map +1 -0
  611. package/dist/shared/fitting-surface-support.js +42 -0
  612. package/dist/shared/fitting-tool-options.d.ts +4 -0
  613. package/dist/shared/fitting-tool-options.d.ts.map +1 -0
  614. package/dist/shared/fitting-tool-options.js +175 -0
  615. package/dist/shared/floor-placement.d.ts +1 -1
  616. package/dist/shared/floor-placement.d.ts.map +1 -1
  617. package/dist/shared/floor-placement.js +13 -33
  618. package/dist/shared/ghost-materials.d.ts.map +1 -1
  619. package/dist/shared/ghost-materials.js +2 -1
  620. package/dist/shared/lean-to-post-omissions.d.ts +8 -0
  621. package/dist/shared/lean-to-post-omissions.d.ts.map +1 -0
  622. package/dist/shared/lean-to-post-omissions.js +51 -0
  623. package/dist/shared/mep-fitting-actions.d.ts +5 -0
  624. package/dist/shared/mep-fitting-actions.d.ts.map +1 -0
  625. package/dist/shared/mep-fitting-actions.js +16 -0
  626. package/dist/shared/mep-presets.d.ts +11 -0
  627. package/dist/shared/mep-presets.d.ts.map +1 -0
  628. package/dist/shared/mep-presets.js +34 -0
  629. package/dist/shared/node-batch/candidates.d.ts +29 -0
  630. package/dist/shared/node-batch/candidates.d.ts.map +1 -0
  631. package/dist/shared/node-batch/candidates.js +260 -0
  632. package/dist/shared/node-batch/store.d.ts +26 -0
  633. package/dist/shared/node-batch/store.d.ts.map +1 -0
  634. package/dist/shared/node-batch/store.js +319 -0
  635. package/dist/shared/node-batch/system.d.ts +8 -0
  636. package/dist/shared/node-batch/system.d.ts.map +1 -0
  637. package/dist/shared/node-batch/system.js +569 -0
  638. package/dist/shared/node-batch/types.d.ts +99 -0
  639. package/dist/shared/node-batch/types.d.ts.map +1 -0
  640. package/dist/shared/node-batch/types.js +4 -0
  641. package/dist/shared/opening-move-history.d.ts +47 -0
  642. package/dist/shared/opening-move-history.d.ts.map +1 -0
  643. package/dist/shared/opening-move-history.js +18 -0
  644. package/dist/shared/opening-move-wall-gate.d.ts +55 -0
  645. package/dist/shared/opening-move-wall-gate.d.ts.map +1 -0
  646. package/dist/shared/opening-move-wall-gate.js +44 -0
  647. package/dist/shared/path-point-affordance.d.ts +2 -2
  648. package/dist/shared/path-point-affordance.d.ts.map +1 -1
  649. package/dist/shared/path-point-affordance.js +30 -6
  650. package/dist/shared/placeholder-geometry.d.ts.map +1 -1
  651. package/dist/shared/placeholder-geometry.js +4 -0
  652. package/dist/shared/ports.d.ts +20 -3
  653. package/dist/shared/ports.d.ts.map +1 -1
  654. package/dist/shared/ports.js +148 -7
  655. package/dist/shared/primitive-uv.d.ts +17 -0
  656. package/dist/shared/primitive-uv.d.ts.map +1 -0
  657. package/dist/shared/primitive-uv.js +107 -0
  658. package/dist/shared/reducer-size.d.ts +2 -0
  659. package/dist/shared/reducer-size.d.ts.map +1 -0
  660. package/dist/shared/reducer-size.js +12 -0
  661. package/dist/shared/ridge-snap.js +1 -1
  662. package/dist/shared/roof-surface.d.ts.map +1 -1
  663. package/dist/shared/roof-surface.js +17 -2
  664. package/dist/shared/run-cursor.d.ts +22 -0
  665. package/dist/shared/run-cursor.d.ts.map +1 -0
  666. package/dist/shared/run-cursor.js +19 -0
  667. package/dist/shared/run-direction-feedback.d.ts +20 -0
  668. package/dist/shared/run-direction-feedback.d.ts.map +1 -0
  669. package/dist/shared/run-direction-feedback.js +139 -0
  670. package/dist/shared/run-hanger-controls.d.ts +7 -0
  671. package/dist/shared/run-hanger-controls.d.ts.map +1 -0
  672. package/dist/shared/run-hanger-controls.js +44 -0
  673. package/dist/shared/run-hanger-inspector.d.ts +5 -0
  674. package/dist/shared/run-hanger-inspector.d.ts.map +1 -0
  675. package/dist/shared/run-hanger-inspector.js +43 -0
  676. package/dist/shared/run-hanger-mode.d.ts +11 -0
  677. package/dist/shared/run-hanger-mode.d.ts.map +1 -0
  678. package/dist/shared/run-hanger-mode.js +32 -0
  679. package/dist/shared/run-hanger-system.d.ts +3 -0
  680. package/dist/shared/run-hanger-system.d.ts.map +1 -0
  681. package/dist/shared/run-hanger-system.js +39 -0
  682. package/dist/shared/run-hangers.d.ts +25 -0
  683. package/dist/shared/run-hangers.d.ts.map +1 -0
  684. package/dist/shared/run-hangers.js +261 -0
  685. package/dist/shared/run-port-snap.d.ts +11 -0
  686. package/dist/shared/run-port-snap.d.ts.map +1 -0
  687. package/dist/shared/run-port-snap.js +19 -0
  688. package/dist/shared/run-screen-direction.d.ts +5 -0
  689. package/dist/shared/run-screen-direction.d.ts.map +1 -0
  690. package/dist/shared/run-screen-direction.js +24 -0
  691. package/dist/shared/selection-handles.d.ts +4 -0
  692. package/dist/shared/selection-handles.d.ts.map +1 -1
  693. package/dist/shared/selection-handles.js +10 -0
  694. package/dist/shared/slot-paint.d.ts +8 -1
  695. package/dist/shared/slot-paint.d.ts.map +1 -1
  696. package/dist/shared/slot-paint.js +120 -27
  697. package/dist/shared/surface-paint.d.ts +1 -2
  698. package/dist/shared/surface-paint.d.ts.map +1 -1
  699. package/dist/shared/surface-paint.js +9 -20
  700. package/dist/shared/system-check-panel.d.ts +6 -0
  701. package/dist/shared/system-check-panel.d.ts.map +1 -0
  702. package/dist/shared/system-check-panel.js +62 -0
  703. package/dist/shared/system-checks.d.ts +9 -0
  704. package/dist/shared/system-checks.d.ts.map +1 -0
  705. package/dist/shared/system-checks.js +131 -0
  706. package/dist/shared/wall-attach-target.d.ts +14 -2
  707. package/dist/shared/wall-attach-target.d.ts.map +1 -1
  708. package/dist/shared/wall-attach-target.js +108 -4
  709. package/dist/shared/wall-opening-clearance.d.ts +19 -0
  710. package/dist/shared/wall-opening-clearance.d.ts.map +1 -0
  711. package/dist/shared/wall-opening-clearance.js +28 -0
  712. package/dist/shared/wall-run-move.d.ts +17 -0
  713. package/dist/shared/wall-run-move.d.ts.map +1 -0
  714. package/dist/shared/wall-run-move.js +56 -0
  715. package/dist/shelf/parametrics.js +4 -4
  716. package/dist/site/renderer.d.ts.map +1 -1
  717. package/dist/site/renderer.js +40 -28
  718. package/dist/site/terrain-geometry.d.ts +1 -1
  719. package/dist/site/terrain-geometry.d.ts.map +1 -1
  720. package/dist/site/terrain-geometry.js +35 -9
  721. package/dist/site/terrain-mesh.d.ts +5 -0
  722. package/dist/site/terrain-mesh.d.ts.map +1 -1
  723. package/dist/site/terrain-mesh.js +63 -34
  724. package/dist/skylight/definition.js +1 -1
  725. package/dist/skylight/panel.js +1 -1
  726. package/dist/skylight/parametrics.js +2 -2
  727. package/dist/slab/definition.d.ts.map +1 -1
  728. package/dist/slab/definition.js +6 -1
  729. package/dist/slab/dependency-tracker.d.ts +3 -0
  730. package/dist/slab/dependency-tracker.d.ts.map +1 -0
  731. package/dist/slab/dependency-tracker.js +104 -0
  732. package/dist/slab/floorplan-affordances.d.ts +8 -8
  733. package/dist/slab/geometry.d.ts.map +1 -1
  734. package/dist/slab/geometry.js +16 -2
  735. package/dist/slab/panel.js +1 -1
  736. package/dist/slab/parametrics.js +1 -1
  737. package/dist/slab/system.d.ts.map +1 -1
  738. package/dist/slab/system.js +8 -64
  739. package/dist/solar-panel/definition.js +1 -1
  740. package/dist/solar-panel/panel.js +1 -1
  741. package/dist/solar-panel/parametrics.js +2 -2
  742. package/dist/stair/panel.d.ts.map +1 -1
  743. package/dist/stair/panel.js +18 -13
  744. package/dist/stair/stair-type.d.ts +18 -0
  745. package/dist/stair/stair-type.d.ts.map +1 -0
  746. package/dist/stair/stair-type.js +25 -0
  747. package/dist/stair-segment/panel.d.ts.map +1 -1
  748. package/dist/stair-segment/panel.js +44 -5
  749. package/dist/turbine-vent/definition.d.ts.map +1 -1
  750. package/dist/turbine-vent/definition.js +8 -5
  751. package/dist/turbine-vent/geometry.d.ts.map +1 -1
  752. package/dist/turbine-vent/geometry.js +48 -18
  753. package/dist/turbine-vent/paint.d.ts +4 -0
  754. package/dist/turbine-vent/paint.d.ts.map +1 -0
  755. package/dist/turbine-vent/paint.js +35 -0
  756. package/dist/turbine-vent/panel.js +1 -1
  757. package/dist/turbine-vent/parametrics.js +2 -2
  758. package/dist/turbine-vent/renderer.d.ts.map +1 -1
  759. package/dist/turbine-vent/renderer.js +31 -9
  760. package/dist/wall/curve-eligibility.d.ts +3 -0
  761. package/dist/wall/curve-eligibility.d.ts.map +1 -0
  762. package/dist/wall/curve-eligibility.js +10 -0
  763. package/dist/wall/curve-tool.d.ts.map +1 -1
  764. package/dist/wall/curve-tool.js +8 -11
  765. package/dist/wall/definition.d.ts +1 -1
  766. package/dist/wall/definition.d.ts.map +1 -1
  767. package/dist/wall/definition.js +36 -13
  768. package/dist/wall/floorplan-affordances.d.ts +1 -0
  769. package/dist/wall/floorplan-affordances.d.ts.map +1 -1
  770. package/dist/wall/floorplan-affordances.js +46 -7
  771. package/dist/wall/floorplan-move.d.ts +3 -4
  772. package/dist/wall/floorplan-move.d.ts.map +1 -1
  773. package/dist/wall/floorplan-move.js +122 -9
  774. package/dist/wall/floorplan.d.ts.map +1 -1
  775. package/dist/wall/floorplan.js +19 -23
  776. package/dist/wall/move-shared.d.ts.map +1 -1
  777. package/dist/wall/move-shared.js +10 -7
  778. package/dist/wall/paint.d.ts.map +1 -1
  779. package/dist/wall/paint.js +2 -0
  780. package/dist/wall/panel.d.ts.map +1 -1
  781. package/dist/wall/panel.js +10 -17
  782. package/dist/wall/parametrics.js +2 -2
  783. package/dist/wall/pointer-transparency.d.ts +128 -0
  784. package/dist/wall/pointer-transparency.d.ts.map +1 -0
  785. package/dist/wall/pointer-transparency.js +147 -0
  786. package/dist/wall/renderer.d.ts.map +1 -1
  787. package/dist/wall/renderer.js +65 -8
  788. package/dist/wall/selection-hit-owner.d.ts +53 -0
  789. package/dist/wall/selection-hit-owner.d.ts.map +1 -0
  790. package/dist/wall/selection-hit-owner.js +79 -0
  791. package/dist/wall/system.d.ts +2 -0
  792. package/dist/wall/system.d.ts.map +1 -1
  793. package/dist/wall/system.js +66 -25
  794. package/dist/wall/tool.d.ts.map +1 -1
  795. package/dist/wall/tool.js +5 -0
  796. package/dist/wall/treatment-level-data.d.ts +6 -1
  797. package/dist/wall/treatment-level-data.d.ts.map +1 -1
  798. package/dist/wall/treatment-level-data.js +82 -5
  799. package/dist/wall/treatments.d.ts +1 -0
  800. package/dist/wall/treatments.d.ts.map +1 -1
  801. package/dist/wall/treatments.js +5 -0
  802. package/dist/wall/wall-batch-system.d.ts +38 -6
  803. package/dist/wall/wall-batch-system.d.ts.map +1 -1
  804. package/dist/wall/wall-batch-system.js +122 -25
  805. package/dist/wall/wall-batch.js +2 -2
  806. package/dist/window/definition.d.ts +2 -1
  807. package/dist/window/definition.d.ts.map +1 -1
  808. package/dist/window/definition.js +51 -24
  809. package/dist/window/floorplan-move.d.ts.map +1 -1
  810. package/dist/window/floorplan-move.js +1 -1
  811. package/dist/window/move-tool.d.ts +7 -5
  812. package/dist/window/move-tool.d.ts.map +1 -1
  813. package/dist/window/move-tool.js +344 -58
  814. package/dist/window/panel.d.ts.map +1 -1
  815. package/dist/window/panel.js +2 -0
  816. package/dist/window/parametrics.js +2 -2
  817. package/dist/window/renderer.d.ts.map +1 -1
  818. package/dist/window/renderer.js +5 -7
  819. package/dist/window/tool.d.ts.map +1 -1
  820. package/dist/window/tool.js +227 -13
  821. package/dist/zone/floorplan-affordances.d.ts +12 -12
  822. package/package.json +11 -9
  823. package/dist/dormer/panel-window-section.d.ts +0 -14
  824. package/dist/dormer/panel-window-section.d.ts.map +0 -1
  825. package/dist/dormer/panel-window-section.js +0 -59
  826. package/dist/dormer/window-assembly.d.ts +0 -22
  827. package/dist/dormer/window-assembly.d.ts.map +0 -1
  828. package/dist/dormer/window-assembly.js +0 -111
  829. package/dist/dormer/window-frame.d.ts +0 -24
  830. package/dist/dormer/window-frame.d.ts.map +0 -1
  831. package/dist/dormer/window-frame.js +0 -100
@@ -1,598 +1,378 @@
1
1
  'use client';
2
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
- import { emitter, PipeSegmentNode, useScene } from '@pascal-app/core';
4
- import { CursorSphere, DimensionPill, EDITOR_LAYER, isAngleSnapActive, isGridSnapActive, isMagneticSnapActive, markToolCancelConsumed, triggerSFX, useEditor, usePathDraftPreview, } from '@pascal-app/editor';
5
- import { useViewer } from '@pascal-app/viewer';
6
- import { Html } from '@react-three/drei';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { PipeSegmentNode } from '@pascal-app/core';
4
+ import { EDITOR_LAYER, triggerSFX, useEditor, usePathDraftPreview, useRegistryToolContext, } from '@pascal-app/editor';
7
5
  import { useEffect, useRef, useState } from 'react';
8
6
  import { Vector3 } from 'three';
9
7
  import { planPipeBranchTap, planPipeCrossAtRunBody, planPipeElbowAtPort, } from '../shared/auto-fitting';
10
- import { alignDrawPoint, clearDrawAlignment } from '../shared/draw-alignment';
8
+ import { createPipeRunEndCap, findMatedRunEndCapIds, isRunEndCapPort, } from '../shared/automatic-run-end-cap';
9
+ import { ConnectionFeedback } from '../shared/connection-feedback';
10
+ import { createRunWallAttachment } from '../shared/distribution-run-contract';
11
+ import { DistributionRunCursor, RUN_PREVIEW_OPACITY, runDistanceSquared, runSectionHalfSizeM, stepNominalRunSize, useDistributionRunTool, } from '../shared/distribution-run-tool';
12
+ import { FITTING_CLEARANCE_MESSAGE, hasFittingClearance } from '../shared/fitting-clearance';
11
13
  import { LevelOffsetGroup } from '../shared/level-offset-group';
12
- import { collectScenePorts, DWV_PORT_SYSTEMS, findNearestPortXZ, findNearestRunBodyXZ, findRunBodyCrossingXZ, } from '../shared/ports';
14
+ import { PipeFittingGhost } from '../shared/mep-ghost';
15
+ import { collectScenePorts, DWV_PORT_SYSTEMS, findNearestRunBody3D, findRunBodyCrossingSurface, } from '../shared/ports';
16
+ import { RunHangerPreview } from '../shared/run-hanger-controls';
17
+ import { useRunHangerMode } from '../shared/run-hanger-mode';
18
+ import { currentPipeContinuationSeed, pipeEndpointPort } from './continuation';
13
19
  import { pipeSegmentDefinition } from './definition';
14
- /**
15
- * Slope-aware two-click placement tool for DWV pipe runs — the plumbing
16
- * sibling of the duct tool.
17
- *
18
- * - **First click** anchors the run start (port snap joins onto an
19
- * existing pipe end — DWV ports only, duct/refrigerant collars are
20
- * invisible to it). The start inherits the snapped port's height.
21
- * - **Second click** commits a two-point pipe and re-arms.
22
- * - **Slope**: runs draw LEVEL by default. **S** toggles slope mode,
23
- * where waste runs fall at ¼" per foot (1:48) of horizontal
24
- * distance, the IPC default for residential drains. When sloped, a
25
- * freely placed start is RAISED so the run falls onto the grid plane
26
- * (nothing clips below); a port/body-snapped start keeps its fixed
27
- * height and the end drops instead. Vent runs always stay level.
28
- * The pill shows the live drop in the Y part.
29
- * - **Q** toggles waste ↔ vent. **[ / ]** steps the pipe size through
30
- * nominal DWV diameters.
31
- * - Hold **Alt** → vertical mode (stacks): XZ locks to the start,
32
- * mouse vertical motion drives Y, click commits the riser.
33
- * - The in-flight end follows the active snapping mode: `angles` locks it
34
- * to 45° in XZ from the start; `grid`/`lines`/`off` leave it free. Shift
35
- * cycles the snapping mode.
36
- * - Esc clears an anchored start point.
37
- */
38
- const PREVIEW_OPACITY = 0.55;
39
- /** green-500 — the project's snap accent. The cursor ring + vertical line
40
- * recolour to this while the point is snapped onto an existing run / port,
41
- * so the coincidence reads with the familiar snap green (matches the duct
42
- * tool). */
43
- const SNAP_CURSOR_COLOR = '#22c55e';
44
- /** Nominal residential DWV sizes (inches). */
20
+ import { applyPipeGrade } from './slope';
45
21
  const PIPE_DIAMETERS_IN = [1.25, 1.5, 2, 3, 4, 6];
46
- /** IPC default drain slope — ¼" per foot (1:48). */
47
- const DRAIN_SLOPE = 1 / 48;
48
- /** Snap radius (meters, XZ) for joining onto an existing pipe end. */
49
- const PORT_SNAP_RADIUS_M = 0.5;
50
- /** Snap radius (meters, XZ) for tapping the side of an existing run. */
51
22
  const BODY_SNAP_RADIUS_M = 0.3;
52
- const ANGLE_STEP_RAD = Math.PI / 4;
53
- const ALT_PIXELS_PER_METER = 100;
54
- const ALT_Y_MIN_M = -3;
55
- const ALT_Y_MAX_M = 10;
56
- function snap(value, step) {
57
- if (step <= 0)
58
- return value;
59
- return Math.round(value / step) * step;
60
- }
61
- function dist2(a, b) {
62
- const dx = a[0] - b[0];
63
- const dy = a[1] - b[1];
64
- const dz = a[2] - b[2];
65
- return dx * dx + dy * dy + dz * dz;
66
- }
67
- function findNearbyPort(point) {
68
- return findNearestPortXZ(point, collectScenePorts({ systems: DWV_PORT_SYSTEMS }), PORT_SNAP_RADIUS_M);
69
- }
70
- function pipeEndPort(pipe, id) {
71
- if (pipe.path.length < 2)
72
- return null;
73
- const index = id === 'start' ? 0 : pipe.path.length - 1;
74
- const neighborIndex = id === 'start' ? 1 : pipe.path.length - 2;
75
- const position = pipe.path[index];
76
- const neighbor = pipe.path[neighborIndex];
77
- const dx = position[0] - neighbor[0];
78
- const dy = position[1] - neighbor[1];
79
- const dz = position[2] - neighbor[2];
80
- const len = Math.hypot(dx, dy, dz);
81
- const direction = len < 1e-9 ? [1, 0, 0] : [dx / len, dy / len, dz / len];
82
- return {
83
- id,
84
- nodeId: pipe.id,
85
- position,
86
- direction,
87
- diameter: pipe.diameter,
88
- system: pipe.system,
89
- };
90
- }
91
- function projectToAngleLock(from, raw) {
92
- const dx = raw[0] - from[0];
93
- const dz = raw[2] - from[2];
94
- const len = Math.hypot(dx, dz);
95
- if (len < 1e-4)
96
- return [from[0], from[1], from[2]];
97
- const theta = Math.atan2(dz, dx);
98
- const snapped = Math.round(theta / ANGLE_STEP_RAD) * ANGLE_STEP_RAD;
99
- const proj = dx * Math.cos(snapped) + dz * Math.sin(snapped);
100
- const d = Math.max(0, proj);
101
- return [from[0] + Math.cos(snapped) * d, from[1], from[2] + Math.sin(snapped) * d];
23
+ function getConnectionPorts(levelId, nodes) {
24
+ return collectScenePorts({
25
+ systems: DWV_PORT_SYSTEMS,
26
+ levelId: levelId ?? undefined,
27
+ }).filter((port) => !isRunEndCapPort(port, nodes));
102
28
  }
103
29
  const PipeSegmentTool = () => {
104
- const activeLevelId = useViewer((s) => s.selection.levelId);
105
- const unit = useViewer((s) => s.unit);
106
- const [system, setSystem] = useState('waste');
30
+ const { activeLevelId, sceneApi, unit } = useRegistryToolContext();
31
+ const continuationSeedRef = useRef(currentPipeContinuationSeed());
32
+ const continuationSeed = continuationSeedRef.current;
33
+ const hangerDefaults = useEditor((state) => state.toolDefaults['pipe-segment']);
34
+ const initialAutoHangersRef = useRef(Boolean(hangerDefaults?.autoHangers ?? continuationSeed?.pipe.autoHangers ?? false));
35
+ const autoHangers = useRunHangerMode((state) => state.enabled['pipe-segment']);
36
+ const hangerStyle = (hangerDefaults?.hangerStyle ?? continuationSeed?.pipe.hangerStyle) === 'double'
37
+ ? 'double'
38
+ : 'single';
39
+ const hangerStyleRef = useRef(hangerStyle);
40
+ hangerStyleRef.current = hangerStyle;
41
+ const autoHangersRef = useRef(autoHangers);
42
+ autoHangersRef.current = autoHangers;
43
+ const pendingPromotionRef = useRef(continuationSeed?.promotedFitting ?? null);
44
+ const defaults = pipeSegmentDefinition.defaults();
45
+ const [system, setSystem] = useState(continuationSeed?.pipe.system ?? defaults.system);
107
46
  const [sloped, setSloped] = useState(false);
108
- const [diameter, setDiameter] = useState(pipeSegmentDefinition.defaults().diameter);
109
- const [draftStart, setDraftStart] = useState(null);
110
- const [cursorPos, setCursorPos] = useState(null);
111
- const [snapTarget, setSnapTarget] = useState(null);
112
- const [altActive, setAltActive] = useState(false);
113
- const startRef = useRef(draftStart);
114
- startRef.current = draftStart;
47
+ const slopePercent = 100 / 48;
48
+ const slopeDirection = 1;
49
+ const gradeRef = useRef(slopePercent / 100);
50
+ gradeRef.current = (slopeDirection * slopePercent) / 100;
51
+ const [diameter, setDiameter] = useState(continuationSeed?.pipe.diameter ?? defaults.diameter);
52
+ const [pipeMaterial, setPipeMaterial] = useState(continuationSeed?.pipe.pipeMaterial ?? defaults.pipeMaterial);
115
53
  const systemRef = useRef(system);
116
54
  systemRef.current = system;
117
55
  const slopedRef = useRef(sloped);
118
56
  slopedRef.current = sloped;
119
57
  const diameterRef = useRef(diameter);
120
58
  diameterRef.current = diameter;
121
- // Port / run-body the anchored start snapped onto — read at commit so
122
- // joints mint bends (corner) or wyes / sanitary tees (body tap).
123
- const startPortRef = useRef(null);
124
- const startBodyRef = useRef(null);
125
- const altAnchorRef = useRef(null);
126
- const lastClientYRef = useRef(null);
127
- const displayStart = draftStart &&
128
- cursorPos &&
129
- sloped &&
130
- system === 'waste' &&
131
- !startPortRef.current &&
132
- !startBodyRef.current &&
133
- !snapTarget &&
134
- !altActive
135
- ? [
136
- draftStart[0],
137
- draftStart[1] +
138
- Math.hypot(cursorPos[0] - draftStart[0], cursorPos[2] - draftStart[2]) * DRAIN_SLOPE,
139
- draftStart[2],
140
- ]
141
- : draftStart;
142
- useEffect(() => {
143
- usePathDraftPreview
144
- .getState()
145
- .setDraft('pipe-segment', displayStart ? [displayStart] : [], cursorPos, { diameter, system });
146
- }, [cursorPos, diameter, displayStart, system]);
147
- useEffect(() => () => usePathDraftPreview.getState().clear('pipe-segment'), []);
59
+ const pipeMaterialRef = useRef(pipeMaterial);
60
+ pipeMaterialRef.current = pipeMaterial;
148
61
  useEffect(() => {
62
+ const mode = useRunHangerMode.getState();
63
+ mode.setEnabled('pipe-segment', initialAutoHangersRef.current);
64
+ return () => mode.setEnabled('pipe-segment', false);
65
+ }, []);
66
+ const commitSegment = ({ start: rawStart, end, startConnection, endConnection, surfaceTarget, previewOnly = false, }) => {
149
67
  if (!activeLevelId)
150
- return;
151
- /** Corner-bend gate: joints onto another PIPE run's open end. */
152
- const bendPlanFor = (port, awayDir) => {
68
+ return null;
69
+ const promotedFitting = pendingPromotionRef.current;
70
+ const bendPlanFor = (port, awayDirection) => {
153
71
  if (!port)
154
72
  return null;
155
- const owner = useScene.getState().nodes[port.nodeId];
73
+ const owner = sceneApi.get(port.nodeId);
156
74
  if (owner?.type !== 'pipe-segment')
157
75
  return null;
158
- const plan = planPipeElbowAtPort(port, awayDir, diameterRef.current, owner.pipeMaterial);
76
+ const plan = planPipeElbowAtPort(port, awayDirection, diameterRef.current, pipeMaterialRef.current);
159
77
  if (!plan)
160
78
  return null;
161
- // Trim the run's snapped endpoint back to the bend's inlet collar.
162
- const path = owner.path.map((p) => [...p]);
79
+ const path = owner.path.map((point) => [...point]);
163
80
  const index = port.id === 'start' ? 0 : path.length - 1;
164
81
  const neighbor = path[index === 0 ? 1 : index - 1];
165
- const remaining = Math.hypot(plan.trimmedPortPoint[0] - neighbor[0], plan.trimmedPortPoint[1] - neighbor[1], plan.trimmedPortPoint[2] - neighbor[2]);
166
82
  const original = path[index];
167
- const originalLen = Math.hypot(original[0] - neighbor[0], original[1] - neighbor[1], original[2] - neighbor[2]);
168
- if (remaining < 0.05 || remaining >= originalLen)
169
- return null;
83
+ const direction = [
84
+ original[0] - neighbor[0],
85
+ original[1] - neighbor[1],
86
+ original[2] - neighbor[2],
87
+ ];
88
+ const hasClearance = hasFittingClearance(neighbor, plan.trimmedPortPoint, direction, 0.05);
170
89
  path[index] = plan.trimmedPortPoint;
171
- return { ...plan, trim: { id: port.nodeId, data: { path } } };
90
+ return {
91
+ ...plan,
92
+ hasClearance,
93
+ trim: { id: port.nodeId, data: { path } },
94
+ };
172
95
  };
173
- const commitSegment = (rawStart, end, endPort = null, endBody = null) => {
174
- // Free waste start: lift it by the drain fall so the run lands ON
175
- // the grid plane instead of sinking below it. Snapped starts are
176
- // height-fixed (fixture drain, run end), so their end drops instead.
177
- let start = rawStart;
178
- if (slopedRef.current &&
179
- systemRef.current === 'waste' &&
180
- !startPortRef.current &&
181
- !startBodyRef.current &&
182
- !endPort) {
183
- const run = Math.hypot(end[0] - rawStart[0], end[2] - rawStart[2]);
184
- start = [rawStart[0], rawStart[1] + run * DRAIN_SLOPE, rawStart[2]];
96
+ const start = rawStart;
97
+ const length = Math.hypot(end[0] - start[0], end[1] - start[1], end[2] - start[2]);
98
+ if (length < 1e-4)
99
+ return null;
100
+ const direction = [
101
+ (end[0] - start[0]) / length,
102
+ (end[1] - start[1]) / length,
103
+ (end[2] - start[2]) / length,
104
+ ];
105
+ const startBend = bendPlanFor(promotedFitting ? null : startConnection.port, direction);
106
+ const endBend = bendPlanFor(endConnection.port, [-direction[0], -direction[1], -direction[2]]);
107
+ const invalidPlan = () => previewOnly
108
+ ? {
109
+ validationMessage: FITTING_CLEARANCE_MESSAGE,
110
+ nextStart: rawStart,
111
+ nextConnection: startConnection,
112
+ previewPipes: [],
113
+ previewFittings: [],
185
114
  }
186
- const length = Math.hypot(end[0] - start[0], end[1] - start[1], end[2] - start[2]);
187
- if (length < 1e-4)
188
- return;
189
- const dir = [
190
- (end[0] - start[0]) / length,
191
- (end[1] - start[1]) / length,
192
- (end[2] - start[2]) / length,
193
- ];
194
- const startPlan = bendPlanFor(startPortRef.current, dir);
195
- const endPlan = bendPlanFor(endPort, [-dir[0], -dir[1], -dir[2]]);
196
- // Body tap (wye / sanitary tee) when the start landed on a run's side.
197
- const body = startPlan ? null : startBodyRef.current;
198
- const bodyOwner = body ? useScene.getState().nodes[body.nodeId] : null;
199
- const tapPlan = body && bodyOwner?.type === 'pipe-segment'
200
- ? planPipeBranchTap(bodyOwner, body, dir, diameterRef.current)
201
- : null;
202
- // End body tap: the END landed on a run's side — split that trunk and
203
- // the new run ends at the branch collar, the branch leaving back
204
- // toward the drawn run (along -dir, since dir points start→end).
205
- const endTapBody = endPlan ? null : endBody;
206
- const endTapOwner = endTapBody ? useScene.getState().nodes[endTapBody.nodeId] : null;
207
- const endTapPlan = endTapBody && endTapOwner?.type === 'pipe-segment'
208
- ? planPipeBranchTap(endTapOwner, endTapBody, [-dir[0], -dir[1], -dir[2]], diameterRef.current)
209
- : null;
210
- // Both ends tapping the SAME run would split one polyline twice in a
211
- // single change — drop the end tap and let the end butt-join instead.
212
- const endTap = endTapPlan && endTapBody?.nodeId === body?.nodeId ? null : endTapPlan;
213
- let pipeStart = startPlan?.collarPoint ?? tapPlan?.branchCollar ?? start;
214
- let pipeEnd = endPlan?.collarPoint ?? endTap?.branchCollar ?? end;
215
- const remaining = Math.hypot(pipeEnd[0] - pipeStart[0], pipeEnd[1] - pipeStart[1], pipeEnd[2] - pipeStart[2]);
216
- let bends = [startPlan, endPlan].filter((p) => p !== null);
217
- let tap = tapPlan;
218
- let endTapFinal = endTap;
219
- // Cross tap: the drawn run passes straight THROUGH a run's body
220
- // (interior crossing, not an end touch). Split that run and the drawn
221
- // pipe into two halves meeting the cross's opposed branch collars.
222
- // Skip a run already tapped by a start / end tee so one polyline isn't
223
- // split twice in a single change.
224
- const crossHit = findRunBodyCrossingXZ(start, end, BODY_SNAP_RADIUS_M, {
115
+ : null;
116
+ if (startBend?.hasClearance === false || endBend?.hasClearance === false)
117
+ return invalidPlan();
118
+ const startBody = startBend ? null : startConnection.body;
119
+ const startOwner = startBody ? sceneApi.get(startBody.nodeId) : null;
120
+ const startTap = startBody && startOwner?.type === 'pipe-segment'
121
+ ? planPipeBranchTap(startOwner, startBody, direction, diameterRef.current)
122
+ : null;
123
+ const endBody = endBend ? null : endConnection.body;
124
+ const endOwner = endBody ? sceneApi.get(endBody.nodeId) : null;
125
+ let endTap = endBody && endOwner?.type === 'pipe-segment'
126
+ ? planPipeBranchTap(endOwner, endBody, [-direction[0], -direction[1], -direction[2]], diameterRef.current)
127
+ : null;
128
+ if (endBody?.nodeId === startBody?.nodeId)
129
+ endTap = null;
130
+ const pipeStart = startBend?.collarPoint ?? startTap?.branchCollar ?? start;
131
+ const pipeEnd = endBend?.collarPoint ?? endTap?.branchCollar ?? end;
132
+ const bends = [startBend, endBend].filter((plan) => plan !== null);
133
+ const crossHit = surfaceTarget
134
+ ? findRunBodyCrossingSurface(start, end, BODY_SNAP_RADIUS_M, surfaceTarget, {
225
135
  kinds: ['pipe-segment'],
226
- });
227
- const crossOwner = crossHit ? useScene.getState().nodes[crossHit.nodeId] : null;
228
- const crossTappedElsewhere = crossHit?.nodeId === body?.nodeId || crossHit?.nodeId === endTapBody?.nodeId;
229
- let cross = crossHit && !crossTappedElsewhere && crossOwner?.type === 'pipe-segment'
230
- ? planPipeCrossAtRunBody(crossOwner, crossHit, dir, diameterRef.current)
231
- : null;
232
- if (remaining <= 0.05) {
233
- bends = [];
234
- tap = null;
235
- endTapFinal = null;
236
- cross = null;
237
- pipeStart = start;
238
- pipeEnd = end;
239
- }
240
- const makePipe = (from, to) => PipeSegmentNode.parse({
241
- ...pipeSegmentDefinition.defaults(),
242
- name: systemRef.current === 'vent' ? 'Vent' : 'Drain',
243
- path: [from, to],
244
- diameter: diameterRef.current,
245
- system: systemRef.current,
246
- });
247
- // A cross splits the drawn run into two halves that meet its opposed
248
- // branch collars; otherwise it's one pipe end-to-end. Degenerate
249
- // halves (the crossing too near an end) are dropped.
250
- const pipes = cross
251
- ? [
252
- dist2(pipeStart, cross.branchCollarNear) > 0.05 * 0.05
253
- ? makePipe(pipeStart, cross.branchCollarNear)
254
- : null,
255
- dist2(cross.branchCollarFar, pipeEnd) > 0.05 * 0.05
256
- ? makePipe(cross.branchCollarFar, pipeEnd)
257
- : null,
258
- ].filter((p) => p !== null)
259
- : [makePipe(pipeStart, pipeEnd)];
260
- useScene.getState().applyNodeChanges({
261
- create: [
262
- ...bends.map((plan) => ({ node: plan.fitting, parentId: activeLevelId })),
263
- ...(tap
264
- ? [
265
- { node: tap.fitting, parentId: activeLevelId },
266
- { node: tap.runTail, parentId: activeLevelId },
267
- ]
268
- : []),
269
- ...(endTapFinal
270
- ? [
271
- { node: endTapFinal.fitting, parentId: activeLevelId },
272
- { node: endTapFinal.runTail, parentId: activeLevelId },
273
- ]
274
- : []),
275
- ...(cross
276
- ? [
277
- { node: cross.fitting, parentId: activeLevelId },
278
- { node: cross.runTail, parentId: activeLevelId },
279
- ]
280
- : []),
281
- ...pipes.map((node) => ({ node, parentId: activeLevelId })),
282
- ],
283
- update: [
284
- ...bends.map((plan) => plan.trim),
285
- ...(tap ? [tap.runUpdate] : []),
286
- ...(endTapFinal
287
- ? [endTapFinal.runUpdate]
288
- : []),
289
- ...(cross ? [cross.runUpdate] : []),
290
- ],
291
- });
292
- const nextPipe = pipes.at(-1);
293
- const nextStart = nextPipe ? nextPipe.path[nextPipe.path.length - 1] : end;
294
- const nextPort = nextPipe ? pipeEndPort(nextPipe, 'end') : endPort;
295
- triggerSFX('sfx:item-place');
296
- setDraftStart(nextStart);
297
- setSnapTarget(null);
298
- startPortRef.current = nextPort;
299
- startBodyRef.current = nextPort ? null : endBody;
300
- altAnchorRef.current = null;
301
- setAltActive(false);
136
+ })
137
+ : null;
138
+ const crossOwner = crossHit ? sceneApi.get(crossHit.nodeId) : null;
139
+ const cross = crossHit &&
140
+ crossHit.nodeId !== startBody?.nodeId &&
141
+ crossHit.nodeId !== endBody?.nodeId &&
142
+ crossOwner?.type === 'pipe-segment'
143
+ ? planPipeCrossAtRunBody(crossOwner, crossHit, direction, diameterRef.current)
144
+ : null;
145
+ if (!hasFittingClearance(pipeStart, pipeEnd, direction, 0.05) ||
146
+ (startBody && !startTap) ||
147
+ (endBody && endBody.nodeId !== startBody?.nodeId && !endTap) ||
148
+ (crossHit &&
149
+ crossHit.nodeId !== startBody?.nodeId &&
150
+ crossHit.nodeId !== endBody?.nodeId &&
151
+ !cross))
152
+ return invalidPlan();
153
+ if (cross &&
154
+ (!hasFittingClearance(pipeStart, cross.branchCollarNear, direction, 0.05) ||
155
+ !hasFittingClearance(cross.branchCollarFar, pipeEnd, direction, 0.05)))
156
+ return invalidPlan();
157
+ const makePipe = (from, to) => PipeSegmentNode.parse({
158
+ ...pipeSegmentDefinition.defaults(),
159
+ ...useEditor.getState().toolDefaults['pipe-segment'],
160
+ autoHangers: autoHangersRef.current,
161
+ hangerStyle: hangerStyleRef.current,
162
+ name: systemRef.current === 'vent' ? 'Vent' : 'Drain',
163
+ path: [from, to],
164
+ diameter: diameterRef.current,
165
+ pipeMaterial: pipeMaterialRef.current,
166
+ system: systemRef.current,
167
+ });
168
+ const pipes = cross
169
+ ? [
170
+ runDistanceSquared(pipeStart, cross.branchCollarNear) > 0.05 * 0.05
171
+ ? makePipe(pipeStart, cross.branchCollarNear)
172
+ : null,
173
+ runDistanceSquared(cross.branchCollarFar, pipeEnd) > 0.05 * 0.05
174
+ ? makePipe(cross.branchCollarFar, pipeEnd)
175
+ : null,
176
+ ].filter((pipe) => pipe !== null)
177
+ : [makePipe(pipeStart, pipeEnd)];
178
+ const attachPipe = (pipe) => {
179
+ const wallAttachment = surfaceTarget?.kind === 'wall'
180
+ ? createRunWallAttachment(surfaceTarget.hostId, surfaceTarget.side, pipe.path[0], pipe.path.at(-1), surfaceTarget, (diameterRef.current * 0.0254) / 2)
181
+ : undefined;
182
+ return { ...pipe, wallAttachment };
302
183
  };
303
- /** Apply the drain fall to an XZ-resolved end point. Only snapped
304
- * starts (fixture drain, run end/body) drop the end — they're
305
- * height-fixed. A free start keeps the end on the grid plane and
306
- * gets LIFTED at commit instead, so the run never sinks below it. */
307
- const applySlope = (start, end) => {
308
- if (!slopedRef.current || systemRef.current !== 'waste')
309
- return end;
310
- if (!startPortRef.current && !startBodyRef.current)
311
- return end;
312
- const run = Math.hypot(end[0] - start[0], end[2] - start[2]);
313
- return [end[0], start[1] - run * DRAIN_SLOPE, end[2]];
184
+ const attachedPipes = pipes.map(attachPipe);
185
+ const sceneNodes = sceneApi.nodes();
186
+ const consumedEndCapIds = Array.from(new Set([
187
+ ...findMatedRunEndCapIds(startConnection.port, sceneNodes, 'pipe-fitting'),
188
+ ...findMatedRunEndCapIds(endConnection.port, sceneNodes, 'pipe-fitting'),
189
+ ]));
190
+ const firstPipe = attachedPipes[0];
191
+ const nextPipe = attachedPipes.at(-1);
192
+ const startEndCap = firstPipe && !startConnection.port && !startConnection.body
193
+ ? createPipeRunEndCap(firstPipe, 'start')
194
+ : null;
195
+ const nextEndCap = nextPipe && !endConnection.port && !endConnection.body ? createPipeRunEndCap(nextPipe) : null;
196
+ const changes = {
197
+ create: [
198
+ ...bends.map((plan) => ({
199
+ node: plan.fitting,
200
+ parentId: activeLevelId,
201
+ })),
202
+ ...(startTap
203
+ ? [
204
+ { node: startTap.fitting, parentId: activeLevelId },
205
+ { node: startTap.runTail, parentId: activeLevelId },
206
+ ]
207
+ : []),
208
+ ...(endTap
209
+ ? [
210
+ { node: endTap.fitting, parentId: activeLevelId },
211
+ { node: endTap.runTail, parentId: activeLevelId },
212
+ ]
213
+ : []),
214
+ ...(cross
215
+ ? [
216
+ { node: cross.fitting, parentId: activeLevelId },
217
+ { node: cross.runTail, parentId: activeLevelId },
218
+ ]
219
+ : []),
220
+ ...attachedPipes.map((node) => ({ node, parentId: activeLevelId })),
221
+ ...(startEndCap ? [{ node: startEndCap, parentId: activeLevelId }] : []),
222
+ ...(nextEndCap ? [{ node: nextEndCap, parentId: activeLevelId }] : []),
223
+ ],
224
+ update: [
225
+ ...(promotedFitting
226
+ ? [
227
+ {
228
+ id: promotedFitting.id,
229
+ data: {
230
+ name: promotedFitting.name,
231
+ fittingType: promotedFitting.fittingType,
232
+ rotation: promotedFitting.rotation,
233
+ diameter2: promotedFitting.diameter2,
234
+ },
235
+ },
236
+ ]
237
+ : []),
238
+ ...bends.map((plan) => plan.trim),
239
+ ...(startTap
240
+ ? [
241
+ startTap.runUpdate,
242
+ ]
243
+ : []),
244
+ ...(endTap ? [endTap.runUpdate] : []),
245
+ ...(cross ? [cross.runUpdate] : []),
246
+ ],
247
+ delete: consumedEndCapIds,
314
248
  };
315
- const resolveSnappedPoint = (event) => {
316
- // Port / body mating is the run's primary affordance; it stays on in
317
- // every snapping mode except `off` (the raw-cursor bypass).
318
- const snapEnabled = isGridSnapActive() || isMagneticSnapActive() || isAngleSnapActive();
319
- const start = startRef.current;
320
- if (!start) {
321
- const raw = [event.localPosition[0], 0, event.localPosition[2]];
322
- const step = isGridSnapActive() ? useEditor.getState().gridSnapStep : 0;
323
- if (event.nativeEvent?.altKey !== true && snapEnabled) {
324
- const port = findNearbyPort(raw);
325
- if (port) {
326
- const p = [
327
- port.position[0],
328
- port.position[1],
329
- port.position[2],
330
- ];
331
- return { point: p, snapped: p, port, body: null };
332
- }
333
- // No open end nearby — try the side of a run (wye / santee tap).
334
- // Probe with a grid-snapped cursor so the tap steps along the run
335
- // like every other placement; `off` mode (step 0) rides smoothly.
336
- const probe = [snap(raw[0], step), 0, snap(raw[2], step)];
337
- const body = findNearestRunBodyXZ(probe, BODY_SNAP_RADIUS_M, {
338
- kinds: ['pipe-segment'],
339
- });
340
- if (body)
341
- return { point: body.point, snapped: body.point, port: null, body };
342
- }
343
- return {
344
- point: [snap(raw[0], step), 0, snap(raw[2], step)],
345
- snapped: null,
346
- port: null,
347
- body: null,
348
- };
349
- }
350
- const rawXZ = [
351
- event.localPosition[0],
352
- start[1],
353
- event.localPosition[2],
354
- ];
355
- // The 45° lock is now the `angles` snapping mode (Shift cycles to it),
356
- // not a held key.
357
- const angleLocked = isAngleSnapActive();
358
- const angled = angleLocked ? projectToAngleLock(start, rawXZ) : rawXZ;
359
- const step = isGridSnapActive() ? useEditor.getState().gridSnapStep : 0;
360
- if (event.nativeEvent?.altKey !== true && snapEnabled) {
361
- const port = findNearbyPort(rawXZ);
362
- if (port) {
363
- const p = [port.position[0], port.position[1], port.position[2]];
364
- return { point: p, snapped: p, port, body: null };
365
- }
366
- // No open end nearby — landing on the side of a run taps a wye /
367
- // sanitary tee there (mirror of the first-point tap). Probe with a
368
- // grid-snapped cursor so the tap steps along the run; checked against
369
- // the cursor, not the 45° projection, so a slightly-off trunk captures.
370
- const probe = [
371
- snap(rawXZ[0], step),
372
- rawXZ[1],
373
- snap(rawXZ[2], step),
374
- ];
375
- const body = findNearestRunBodyXZ(probe, BODY_SNAP_RADIUS_M, { kinds: ['pipe-segment'] });
376
- if (body)
377
- return { point: body.point, snapped: body.point, port: null, body };
378
- }
379
- let end;
380
- if (!angleLocked) {
381
- end = [snap(angled[0], step), angled[1], snap(angled[2], step)];
382
- }
383
- else {
384
- // Snap the run LENGTH along the locked ray, not each axis — an
385
- // off-grid start (port / body snap) plus per-axis rounding pulls
386
- // the end off the 45° ray, bending the run as the cursor moves.
387
- const dx = angled[0] - start[0];
388
- const dz = angled[2] - start[2];
389
- const len = Math.hypot(dx, dz);
390
- if (len < 1e-6) {
391
- end = angled;
392
- }
393
- else {
394
- const s = snap(len, step) / len;
395
- end = [start[0] + dx * s, angled[1], start[2] + dz * s];
396
- }
397
- }
398
- return { point: applySlope(start, end), snapped: null, port: null, body: null };
249
+ if (!previewOnly) {
250
+ if (!sceneApi.applyChanges)
251
+ throw new Error('Registry SceneApi must support atomic changes');
252
+ sceneApi.applyChanges(changes);
253
+ pendingPromotionRef.current = null;
254
+ }
255
+ const nextStart = nextPipe ? nextPipe.path[nextPipe.path.length - 1] : end;
256
+ const nextPort = nextPipe ? pipeEndpointPort(nextPipe, 'end') : endConnection.port;
257
+ return {
258
+ validationMessage: null,
259
+ nextStart,
260
+ previewPipes: attachedPipes,
261
+ previewFittings: changes.create
262
+ .map(({ node }) => node)
263
+ .filter((node) => node.type === 'pipe-fitting'),
264
+ nextConnection: {
265
+ port: nextPort,
266
+ body: nextPort ? null : endConnection.body,
267
+ },
399
268
  };
400
- const resolveAltVerticalPoint = (clientY) => {
401
- const anchor = altAnchorRef.current;
402
- const start = startRef.current;
403
- if (!anchor || !start)
404
- return null;
405
- const step = isGridSnapActive() ? useEditor.getState().gridSnapStep : 0;
406
- const dy = (anchor.clientY - clientY) / ALT_PIXELS_PER_METER;
407
- const snappedDy = snap(dy, step);
408
- const y = Math.min(ALT_Y_MAX_M, Math.max(ALT_Y_MIN_M, anchor.baseY + snappedDy));
409
- return [start[0], y, start[2]];
410
- };
411
- // Resolve the cursor point (port / body / grid / angle snap) then layer
412
- // Figma-style alignment so a run lines up with other runs, fittings, and
413
- // items as it's drawn. A free point (first vertex, or no angle lock) snaps;
414
- // an angle-locked continuation shows the guide passively. Alignment follows
415
- // the `lines` mode; a port / body snap or Alt-vertical bypasses it.
416
- const resolveAlignedPoint = (event) => {
417
- const r = resolveSnappedPoint(event);
418
- const hasStart = !!startRef.current;
419
- const alt = event.nativeEvent?.altKey === true;
420
- const point = alignDrawPoint(r.point, {
421
- applySnap: isMagneticSnapActive() && (!hasStart || !isAngleSnapActive()),
422
- bypass: alt || r.snapped !== null,
423
- });
424
- return { ...r, point };
425
- };
426
- const onMove = (event) => {
427
- const clientY = event.nativeEvent?.clientY;
428
- if (typeof clientY === 'number')
429
- lastClientYRef.current = clientY;
430
- if (altAnchorRef.current && typeof clientY === 'number') {
431
- const point = resolveAltVerticalPoint(clientY);
432
- if (point) {
433
- clearDrawAlignment();
434
- setCursorPos(point);
435
- setSnapTarget(null);
436
- return;
437
- }
438
- }
439
- const { point, snapped } = resolveAlignedPoint(event);
440
- setCursorPos(point);
441
- setSnapTarget(snapped);
442
- };
443
- const onClick = (event) => {
444
- const start = startRef.current;
445
- if (altAnchorRef.current && start) {
446
- const clientY = event.nativeEvent?.clientY ?? lastClientYRef.current;
447
- if (typeof clientY === 'number') {
448
- const point = resolveAltVerticalPoint(clientY);
449
- if (point && Math.abs(point[1] - start[1]) >= 1e-4)
450
- commitSegment(start, point);
451
- }
269
+ };
270
+ const run = useDistributionRunTool({
271
+ active: !!activeLevelId,
272
+ levelId: activeLevelId,
273
+ toolName: 'pipe-segment',
274
+ initialStart: continuationSeed
275
+ ? [
276
+ ...(continuationSeed.port?.position ?? continuationSeed.body?.point ?? [0, 0, 0]),
277
+ ]
278
+ : null,
279
+ initialConnection: continuationSeed
280
+ ? { port: continuationSeed.port, body: continuationSeed.body }
281
+ : null,
282
+ getPorts: () => getConnectionPorts(activeLevelId, sceneApi.nodes()),
283
+ findBody: (point) => findNearestRunBody3D(point, BODY_SNAP_RADIUS_M, {
284
+ kinds: ['pipe-segment'],
285
+ levelId: activeLevelId ?? undefined,
286
+ }),
287
+ surfaceClearance: (surface) => (surface ? runSectionHalfSizeM(diameterRef.current) : 0),
288
+ minimumSegmentLength: 0.05,
289
+ resolveFreeEnd: (start, end, startConnection) => {
290
+ if (!slopedRef.current || systemRef.current !== 'waste')
291
+ return end;
292
+ return applyPipeGrade(start, end, gradeRef.current);
293
+ },
294
+ inheritFromConnection: ({ port, body }) => {
295
+ const ownerId = port?.nodeId ?? body?.nodeId;
296
+ const owner = ownerId ? sceneApi.get(ownerId) : null;
297
+ if (owner?.type !== 'pipe-segment')
452
298
  return;
453
- }
454
- const { point, port, body } = resolveAlignedPoint(event);
455
- if (!start) {
456
- // First click: anchor the start, remembering the port / run body
457
- // it snapped to so the commit can mint a bend / wye.
299
+ setDiameter(owner.diameter);
300
+ setPipeMaterial(owner.pipeMaterial);
301
+ setSystem(owner.system);
302
+ },
303
+ commit: commitSegment,
304
+ onShortcut: (event) => {
305
+ if (event.key === '[' || event.key === ']') {
306
+ event.preventDefault();
307
+ const next = stepNominalRunSize(PIPE_DIAMETERS_IN, diameterRef.current, event.key === ']' ? 1 : -1);
308
+ if (next !== diameterRef.current)
309
+ setDiameter(next);
458
310
  triggerSFX('sfx:grid-snap');
459
- startPortRef.current = port;
460
- startBodyRef.current = port ? null : body;
461
- // Continue an existing run at its true size: adopt the snapped
462
- // pipe's diameter so the new segment carries on at the same gauge
463
- // instead of whatever size the tool last drew.
464
- const ownerId = port?.nodeId ?? (port ? null : body?.nodeId);
465
- const owner = ownerId ? useScene.getState().nodes[ownerId] : null;
466
- if (owner?.type === 'pipe-segment' && owner.diameter !== diameterRef.current) {
467
- setDiameter(owner.diameter);
468
- }
469
- setDraftStart(point);
470
- return;
471
- }
472
- commitSegment(start, point, port, port ? null : body);
473
- };
474
- const enterAltMode = () => {
475
- const start = startRef.current;
476
- if (!start || lastClientYRef.current === null)
477
- return;
478
- if (altAnchorRef.current)
479
- return;
480
- altAnchorRef.current = { clientY: lastClientYRef.current, baseY: start[1] };
481
- setAltActive(true);
482
- };
483
- const exitAltMode = () => {
484
- if (!altAnchorRef.current)
485
- return;
486
- altAnchorRef.current = null;
487
- setAltActive(false);
488
- };
489
- const stepDiameter = (step) => {
490
- const sizes = PIPE_DIAMETERS_IN;
491
- const current = diameterRef.current;
492
- let nearest = 0;
493
- for (let i = 1; i < sizes.length; i++) {
494
- if (Math.abs(sizes[i] - current) < Math.abs(sizes[nearest] - current))
495
- nearest = i;
496
- }
497
- const next = sizes[Math.min(sizes.length - 1, Math.max(0, nearest + step))];
498
- if (next === current)
499
- return;
500
- setDiameter(next);
501
- triggerSFX('sfx:grid-snap');
502
- };
503
- const onKeyDown = (e) => {
504
- const tag = e.target?.tagName;
505
- if (tag === 'INPUT' || tag === 'TEXTAREA')
506
- return;
507
- if (e.key === 'Alt') {
508
- e.preventDefault();
509
- enterAltMode();
510
- }
511
- else if (e.key === '[') {
512
- e.preventDefault();
513
- stepDiameter(-1);
514
311
  }
515
- else if (e.key === ']') {
516
- e.preventDefault();
517
- stepDiameter(1);
518
- }
519
- else if (e.key === 'q' || e.key === 'Q') {
520
- e.preventDefault();
521
- setSystem((s) => (s === 'waste' ? 'vent' : 'waste'));
312
+ else if (event.key === 'q' || event.key === 'Q') {
313
+ event.preventDefault();
314
+ setSystem((value) => (value === 'waste' ? 'vent' : 'waste'));
522
315
  triggerSFX('sfx:grid-snap');
523
316
  }
524
- else if (e.key === 's' || e.key === 'S') {
525
- e.preventDefault();
526
- setSloped((s) => !s);
317
+ else if (event.key === 's' || event.key === 'S') {
318
+ event.preventDefault();
319
+ setSloped((value) => !value);
527
320
  triggerSFX('sfx:grid-snap');
528
321
  }
529
- };
530
- const onKeyUp = (e) => {
531
- if (e.key === 'Alt') {
532
- e.preventDefault();
533
- exitAltMode();
322
+ else if (event.key === 'h' || event.key === 'H') {
323
+ event.preventDefault();
324
+ useRunHangerMode.getState().toggle('pipe-segment');
325
+ triggerSFX('sfx:grid-snap');
534
326
  }
535
- };
536
- const onCancel = () => {
537
- clearDrawAlignment();
538
- if (!startRef.current)
539
- return;
540
- markToolCancelConsumed();
541
- setDraftStart(null);
542
- setCursorPos(null);
543
- setSnapTarget(null);
544
- startPortRef.current = null;
545
- startBodyRef.current = null;
546
- };
547
- emitter.on('grid:move', onMove);
548
- emitter.on('grid:click', onClick);
549
- emitter.on('tool:cancel', onCancel);
550
- window.addEventListener('keydown', onKeyDown);
551
- window.addEventListener('keyup', onKeyUp);
552
- return () => {
553
- emitter.off('grid:move', onMove);
554
- emitter.off('grid:click', onClick);
555
- emitter.off('tool:cancel', onCancel);
556
- window.removeEventListener('keydown', onKeyDown);
557
- window.removeEventListener('keyup', onKeyUp);
558
- altAnchorRef.current = null;
559
- clearDrawAlignment();
560
- };
561
- }, [activeLevelId]);
327
+ },
328
+ });
329
+ const refreshCursor = run.refreshCursor;
330
+ // Slope settings are read through refs by the cursor resolver; refresh after those refs update.
331
+ // biome-ignore lint/correctness/useExhaustiveDependencies: settings must refresh a stationary cursor
332
+ useEffect(() => {
333
+ if (!run.altActive)
334
+ refreshCursor();
335
+ }, [sloped, system, run.altActive, refreshCursor]);
336
+ const displayStart = run.start;
337
+ const previewPlan = run.start && run.cursor
338
+ ? commitSegment({
339
+ start: run.start,
340
+ end: run.cursor,
341
+ startConnection: run.startConnection,
342
+ endConnection: run.endConnection,
343
+ surfaceTarget: run.surfaceTarget,
344
+ previewOnly: true,
345
+ })
346
+ : null;
347
+ useEffect(() => {
348
+ usePathDraftPreview
349
+ .getState()
350
+ .setDraft('pipe-segment', displayStart ? [displayStart] : [], run.cursor, {
351
+ autoHangers,
352
+ hangerStyle,
353
+ diameter,
354
+ system,
355
+ });
356
+ }, [autoHangers, hangerStyle, diameter, displayStart, run.cursor, system]);
357
+ useEffect(() => () => usePathDraftPreview.getState().clear('pipe-segment'), []);
358
+ useEffect(() => () => useEditor.getState().setToolDefaults('pipe-segment', null), []);
562
359
  if (!activeLevelId)
563
360
  return null;
564
- const pillParts = cursorPos
565
- ? [
566
- ...['x', 'y', 'z'].map((axis, i) => ({
567
- key: axis,
568
- prefix: axis.toUpperCase(),
569
- value: displayStart ? cursorPos[i] - displayStart[i] : cursorPos[i],
570
- signed: !!displayStart,
571
- })),
572
- { key: 'diameter', prefix: 'Ø', value: diameter * 0.0254, signed: false },
573
- ]
574
- : null;
575
- const pillPrimary = draftStart && cursorPos ? (altActive ? 'y' : 'y') : undefined;
576
- return (_jsxs(LevelOffsetGroup, { children: [cursorPos && (_jsxs(_Fragment, { children: [_jsx(CursorSphere, { color: snapTarget ? SNAP_CURSOR_COLOR : undefined, position: cursorPos }), pillParts && (_jsx("group", { position: cursorPos, children: _jsx(Html, { center: true, position: [0, 1.45, 0], style: { pointerEvents: 'none', userSelect: 'none' }, zIndexRange: [100, 0], children: _jsxs("div", { className: "flex flex-col items-center gap-1", children: [_jsx(DimensionPill, { parts: pillParts, primary: pillPrimary, unit: unit }), _jsxs("div", { className: "whitespace-nowrap rounded-full border border-border/60 bg-background/90 px-3 py-0.5 text-[10px] text-muted-foreground shadow-sm backdrop-blur", children: [system === 'waste'
577
- ? sloped
578
- ? 'Waste · ¼″/ft fall'
579
- : 'Waste · level'
580
- : 'Vent · level', ' ', "\u00B7 Q system", system === 'waste' ? ' · S slope' : ''] })] }) }) }))] })), snapTarget && (_jsxs("mesh", { layers: EDITOR_LAYER, position: snapTarget, children: [_jsx("sphereGeometry", { args: [0.1, 24, 16] }), _jsx("meshBasicMaterial", { color: "#818cf8", depthTest: false, opacity: 0.35, transparent: true })] })), displayStart && (_jsxs("mesh", { layers: EDITOR_LAYER, position: displayStart, children: [_jsx("sphereGeometry", { args: [0.05, 16, 12] }), _jsx("meshBasicMaterial", { color: "#818cf8", depthTest: false })] })), displayStart && cursorPos && (_jsx(PreviewPipe, { a: displayStart, b: cursorPos, diameterIn: diameter }))] }));
361
+ return (_jsxs(LevelOffsetGroup, { children: [_jsx(ConnectionFeedback, { point: run.cursor, target: run.endConnection.port, levelId: activeLevelId, profile: { diameter, system } }), _jsx(DistributionRunCursor, { altActive: run.altActive, cursor: run.cursor, directionMode: run.directionMode, extraParts: [{ key: 'diameter', prefix: 'Ø', value: diameter * 0.0254 }], lengthInput: run.lengthInput, onLengthInputChange: run.onLengthInputChange, onDirectionSelect: run.onDirectionSelect, validationMessage: previewPlan?.validationMessage ?? run.validationMessage, snapTarget: run.snapTarget, snapScreen: run.snapScreen, start: displayStart, startDirection: run.startConnection.port?.direction ?? null, unit: unit }), run.snapTarget && (_jsxs("mesh", { layers: EDITOR_LAYER, position: run.snapTarget, children: [_jsx("sphereGeometry", { args: [0.1, 24, 16] }), _jsx("meshBasicMaterial", { color: "#818cf8", depthTest: false, opacity: 0.35, transparent: true })] })), displayStart && (_jsxs("mesh", { layers: EDITOR_LAYER, position: displayStart, children: [_jsx("sphereGeometry", { args: [0.05, 16, 12] }), _jsx("meshBasicMaterial", { color: "#818cf8", depthTest: false })] })), previewPlan?.previewPipes.map((pipe, index) => (_jsx(PreviewPipe, { a: pipe.path[0], b: pipe.path.at(-1), diameterIn: diameter }, index))), previewPlan?.previewPipes.map((pipe, index) => (_jsx(RunHangerPreview, { run: pipe, levelId: activeLevelId }, `hanger-${index}`))), previewPlan?.previewFittings.map((fitting, index) => (_jsx(PipeFittingGhost, { fitting: fitting }, index)))] }));
581
362
  };
582
- function PreviewPipe({ a, b, diameterIn, }) {
363
+ function PreviewPipe({ a, b, diameterIn }) {
583
364
  const start = new Vector3(...a);
584
365
  const end = new Vector3(...b);
585
- const dir = new Vector3().subVectors(end, start);
586
- const length = dir.length();
366
+ const direction = new Vector3().subVectors(end, start);
367
+ const length = direction.length();
587
368
  if (length < 1e-4)
588
369
  return null;
589
- dir.normalize();
590
- const mid = new Vector3().addVectors(start, end).multiplyScalar(0.5);
370
+ direction.normalize();
371
+ const midpoint = new Vector3().addVectors(start, end).multiplyScalar(0.5);
591
372
  const radius = (diameterIn * 0.0254) / 2;
592
- return (_jsxs("mesh", { layers: EDITOR_LAYER, position: mid.toArray(), ref: (m) => {
593
- if (!m)
594
- return;
595
- m.quaternion.setFromUnitVectors(new Vector3(0, 1, 0), dir);
596
- }, children: [_jsx("cylinderGeometry", { args: [radius, radius, length, 20, 1, false] }), _jsx("meshBasicMaterial", { color: "#818cf8", depthTest: false, opacity: PREVIEW_OPACITY, transparent: true })] }));
373
+ return (_jsxs("mesh", { layers: EDITOR_LAYER, position: midpoint.toArray(), ref: (mesh) => {
374
+ if (mesh)
375
+ mesh.quaternion.setFromUnitVectors(new Vector3(0, 1, 0), direction);
376
+ }, children: [_jsx("cylinderGeometry", { args: [radius, radius, length, 20, 1, false] }), _jsx("meshBasicMaterial", { color: "#818cf8", depthTest: false, opacity: RUN_PREVIEW_OPACITY, transparent: true })] }));
597
377
  }
598
378
  export default PipeSegmentTool;