@pascal-app/nodes 1.0.3 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (708) hide show
  1. package/dist/block/definition.d.ts.map +1 -1
  2. package/dist/block/definition.js +18 -3
  3. package/dist/block/floorplan.d.ts +11 -1
  4. package/dist/block/floorplan.d.ts.map +1 -1
  5. package/dist/block/floorplan.js +81 -13
  6. package/dist/block/geometry.d.ts +2 -2
  7. package/dist/block/geometry.d.ts.map +1 -1
  8. package/dist/block/geometry.js +39 -24
  9. package/dist/block/hosted-edit.d.ts.map +1 -1
  10. package/dist/block/hosted-edit.js +25 -0
  11. package/dist/block/material-slots.d.ts +1 -3
  12. package/dist/block/material-slots.d.ts.map +1 -1
  13. package/dist/block/material-slots.js +1 -11
  14. package/dist/block/paint.d.ts.map +1 -1
  15. package/dist/block/paint.js +4 -10
  16. package/dist/block/panel.d.ts.map +1 -1
  17. package/dist/block/panel.js +8 -3
  18. package/dist/block/selection.d.ts.map +1 -1
  19. package/dist/block/selection.js +2 -2
  20. package/dist/box-vent/definition.d.ts.map +1 -1
  21. package/dist/box-vent/definition.js +2 -5
  22. package/dist/box-vent/panel.d.ts.map +1 -1
  23. package/dist/box-vent/panel.js +5 -28
  24. package/dist/cabinet/countertop-layout.d.ts +13 -2
  25. package/dist/cabinet/countertop-layout.d.ts.map +1 -1
  26. package/dist/cabinet/definition.d.ts.map +1 -1
  27. package/dist/cabinet/definition.js +1 -2
  28. package/dist/cabinet/floorplan.d.ts.map +1 -1
  29. package/dist/cabinet/floorplan.js +125 -28
  30. package/dist/cabinet/geometry/shared.d.ts +1 -2
  31. package/dist/cabinet/geometry/shared.d.ts.map +1 -1
  32. package/dist/cabinet/geometry/shared.js +1 -2
  33. package/dist/cabinet/run-layout.d.ts.map +1 -1
  34. package/dist/cabinet/run-layout.js +8 -5
  35. package/dist/cabinet/run-ops.d.ts +13 -2
  36. package/dist/cabinet/run-ops.d.ts.map +1 -1
  37. package/dist/cabinet/tool.d.ts.map +1 -1
  38. package/dist/cabinet/tool.js +22 -24
  39. package/dist/cabinet/wall-snap.d.ts.map +1 -1
  40. package/dist/cabinet/wall-snap.js +8 -8
  41. package/dist/ceiling/boundary-editor.d.ts.map +1 -1
  42. package/dist/ceiling/boundary-editor.js +5 -3
  43. package/dist/ceiling/definition.d.ts +4 -4
  44. package/dist/ceiling/definition.d.ts.map +1 -1
  45. package/dist/ceiling/definition.js +15 -15
  46. package/dist/ceiling/floorplan-affordances.d.ts +84 -4
  47. package/dist/ceiling/floorplan-affordances.d.ts.map +1 -1
  48. package/dist/ceiling/floorplan-affordances.js +0 -1
  49. package/dist/ceiling/floorplan-move.d.ts.map +1 -1
  50. package/dist/ceiling/floorplan-move.js +0 -1
  51. package/dist/ceiling/floorplan.d.ts +1 -1
  52. package/dist/ceiling/floorplan.d.ts.map +1 -1
  53. package/dist/ceiling/floorplan.js +2 -1
  54. package/dist/ceiling/height-bounds.d.ts +19 -0
  55. package/dist/ceiling/height-bounds.d.ts.map +1 -0
  56. package/dist/ceiling/height-bounds.js +24 -0
  57. package/dist/ceiling/hole-editor.d.ts.map +1 -1
  58. package/dist/ceiling/hole-editor.js +3 -4
  59. package/dist/ceiling/materials.d.ts +1 -1
  60. package/dist/ceiling/materials.d.ts.map +1 -1
  61. package/dist/ceiling/materials.js +10 -3
  62. package/dist/ceiling/paint.d.ts +2 -8
  63. package/dist/ceiling/paint.d.ts.map +1 -1
  64. package/dist/ceiling/paint.js +121 -24
  65. package/dist/ceiling/panel.d.ts.map +1 -1
  66. package/dist/ceiling/panel.js +40 -23
  67. package/dist/ceiling/renderer.d.ts.map +1 -1
  68. package/dist/ceiling/renderer.js +41 -5
  69. package/dist/chimney/move-tool.d.ts.map +1 -1
  70. package/dist/chimney/move-tool.js +8 -2
  71. package/dist/chimney/paint.d.ts.map +1 -1
  72. package/dist/chimney/paint.js +3 -10
  73. package/dist/column/definition.d.ts.map +1 -1
  74. package/dist/column/definition.js +24 -2
  75. package/dist/column/floorplan-affordances.d.ts.map +1 -1
  76. package/dist/column/floorplan-affordances.js +5 -0
  77. package/dist/column/floorplan.d.ts +1 -1
  78. package/dist/column/floorplan.d.ts.map +1 -1
  79. package/dist/column/floorplan.js +47 -2
  80. package/dist/column/hosted-resize.d.ts +101 -2
  81. package/dist/column/hosted-resize.d.ts.map +1 -1
  82. package/dist/column/panel.d.ts.map +1 -1
  83. package/dist/column/panel.js +147 -146
  84. package/dist/column/renderer.d.ts.map +1 -1
  85. package/dist/column/renderer.js +6 -4
  86. package/dist/column/surface.d.ts.map +1 -1
  87. package/dist/column/surface.js +7 -0
  88. package/dist/construction-dimension/floorplan.js +7 -3
  89. package/dist/cupola/definition.d.ts.map +1 -1
  90. package/dist/cupola/definition.js +2 -8
  91. package/dist/cupola/panel.d.ts.map +1 -1
  92. package/dist/cupola/panel.js +5 -23
  93. package/dist/door/definition.d.ts.map +1 -1
  94. package/dist/door/definition.js +12 -3
  95. package/dist/door/door-math.d.ts +5 -10
  96. package/dist/door/door-math.d.ts.map +1 -1
  97. package/dist/door/door-math.js +14 -15
  98. package/dist/door/floorplan-move.d.ts.map +1 -1
  99. package/dist/door/floorplan-move.js +3 -1
  100. package/dist/door/floorplan.d.ts.map +1 -1
  101. package/dist/door/floorplan.js +55 -21
  102. package/dist/door/mechanism.d.ts +4 -0
  103. package/dist/door/mechanism.d.ts.map +1 -0
  104. package/dist/door/mechanism.js +24 -0
  105. package/dist/door/move-tool.d.ts.map +1 -1
  106. package/dist/door/move-tool.js +72 -48
  107. package/dist/door/paint.d.ts.map +1 -1
  108. package/dist/door/paint.js +3 -0
  109. package/dist/door/panel.d.ts.map +1 -1
  110. package/dist/door/panel.js +34 -259
  111. package/dist/door/placement.d.ts +45 -0
  112. package/dist/door/placement.d.ts.map +1 -0
  113. package/dist/door/placement.js +51 -0
  114. package/dist/door/preview.d.ts.map +1 -1
  115. package/dist/door/preview.js +2 -0
  116. package/dist/door/renderer.d.ts.map +1 -1
  117. package/dist/door/renderer.js +3 -2
  118. package/dist/door/tool.d.ts.map +1 -1
  119. package/dist/door/tool.js +92 -21
  120. package/dist/dormer/csg-geometry.d.ts.map +1 -1
  121. package/dist/dormer/csg-geometry.js +2 -0
  122. package/dist/dormer/paint.d.ts.map +1 -1
  123. package/dist/dormer/paint.js +2 -5
  124. package/dist/dormer/panel.d.ts.map +1 -1
  125. package/dist/dormer/panel.js +4 -14
  126. package/dist/downspout/definition.d.ts.map +1 -1
  127. package/dist/downspout/definition.js +2 -2
  128. package/dist/duct-fitting/definition.d.ts.map +1 -1
  129. package/dist/duct-fitting/definition.js +2 -1
  130. package/dist/duct-fitting/geometry.d.ts.map +1 -1
  131. package/dist/duct-fitting/geometry.js +1 -1
  132. package/dist/duct-fitting/move-tool.d.ts.map +1 -1
  133. package/dist/duct-fitting/move-tool.js +8 -2
  134. package/dist/duct-segment/definition.d.ts.map +1 -1
  135. package/dist/duct-segment/definition.js +2 -2
  136. package/dist/duct-segment/geometry.d.ts.map +1 -1
  137. package/dist/duct-segment/geometry.js +1 -1
  138. package/dist/duct-segment/move-tool.d.ts.map +1 -1
  139. package/dist/duct-segment/move-tool.js +8 -2
  140. package/dist/elevator/definition.d.ts.map +1 -1
  141. package/dist/elevator/definition.js +1 -2
  142. package/dist/elevator/panel.d.ts.map +1 -1
  143. package/dist/elevator/panel.js +5 -27
  144. package/dist/elevator/parametrics.js +1 -1
  145. package/dist/elevator/renderer.d.ts.map +1 -1
  146. package/dist/elevator/renderer.js +3 -4
  147. package/dist/eyebrow-vent/definition.d.ts.map +1 -1
  148. package/dist/eyebrow-vent/definition.js +2 -5
  149. package/dist/eyebrow-vent/paint.d.ts.map +1 -1
  150. package/dist/eyebrow-vent/paint.js +3 -6
  151. package/dist/eyebrow-vent/panel.d.ts.map +1 -1
  152. package/dist/eyebrow-vent/panel.js +5 -23
  153. package/dist/fence/actions/move-endpoint.d.ts +1 -1
  154. package/dist/fence/actions/move-endpoint.d.ts.map +1 -1
  155. package/dist/fence/actions/move-endpoint.js +2 -1
  156. package/dist/fence/definition.d.ts +2 -1
  157. package/dist/fence/definition.d.ts.map +1 -1
  158. package/dist/fence/definition.js +83 -28
  159. package/dist/fence/drafting.d.ts +36 -0
  160. package/dist/fence/drafting.d.ts.map +1 -0
  161. package/dist/fence/drafting.js +210 -0
  162. package/dist/fence/feature-tool.d.ts +4 -0
  163. package/dist/fence/feature-tool.d.ts.map +1 -0
  164. package/dist/fence/feature-tool.js +140 -0
  165. package/dist/fence/features.d.ts +2 -0
  166. package/dist/fence/features.d.ts.map +1 -0
  167. package/dist/fence/features.js +12 -0
  168. package/dist/fence/floorplan-affordances.d.ts.map +1 -1
  169. package/dist/fence/floorplan-affordances.js +2 -1
  170. package/dist/fence/floorplan.d.ts +2 -3
  171. package/dist/fence/floorplan.d.ts.map +1 -1
  172. package/dist/fence/floorplan.js +131 -71
  173. package/dist/fence/geometry-parts.d.ts +50 -0
  174. package/dist/fence/geometry-parts.d.ts.map +1 -0
  175. package/dist/fence/geometry-parts.js +1144 -0
  176. package/dist/fence/geometry.d.ts +2 -3
  177. package/dist/fence/geometry.d.ts.map +1 -1
  178. package/dist/fence/geometry.js +84 -7
  179. package/dist/fence/index.d.ts +1 -0
  180. package/dist/fence/index.d.ts.map +1 -1
  181. package/dist/fence/index.js +1 -0
  182. package/dist/fence/inspector-editors.d.ts +15 -0
  183. package/dist/fence/inspector-editors.d.ts.map +1 -1
  184. package/dist/fence/inspector-editors.js +128 -3
  185. package/dist/fence/lift.d.ts.map +1 -1
  186. package/dist/fence/lift.js +5 -2
  187. package/dist/fence/move-tool.js +2 -1
  188. package/dist/fence/panel-model.d.ts +4 -0
  189. package/dist/fence/panel-model.d.ts.map +1 -0
  190. package/dist/fence/panel-model.js +12 -0
  191. package/dist/fence/parametrics.d.ts +0 -12
  192. package/dist/fence/parametrics.d.ts.map +1 -1
  193. package/dist/fence/parametrics.js +185 -18
  194. package/dist/fence/system.d.ts.map +1 -1
  195. package/dist/fence/system.js +141 -31
  196. package/dist/fence/tool.d.ts.map +1 -1
  197. package/dist/fence/tool.js +256 -47
  198. package/dist/fence-feature/actions.d.ts +7 -0
  199. package/dist/fence-feature/actions.d.ts.map +1 -0
  200. package/dist/fence-feature/actions.js +26 -0
  201. package/dist/fence-feature/definition.d.ts +4 -0
  202. package/dist/fence-feature/definition.d.ts.map +1 -0
  203. package/dist/fence-feature/definition.js +112 -0
  204. package/dist/fence-feature/floorplan-affordances.d.ts +3 -0
  205. package/dist/fence-feature/floorplan-affordances.d.ts.map +1 -0
  206. package/dist/fence-feature/floorplan-affordances.js +37 -0
  207. package/dist/fence-feature/floorplan.d.ts +4 -0
  208. package/dist/fence-feature/floorplan.d.ts.map +1 -0
  209. package/dist/fence-feature/floorplan.js +120 -0
  210. package/dist/fence-feature/geometry.d.ts +5 -0
  211. package/dist/fence-feature/geometry.d.ts.map +1 -0
  212. package/dist/fence-feature/geometry.js +43 -0
  213. package/dist/fence-feature/handles.d.ts +5 -0
  214. package/dist/fence-feature/handles.d.ts.map +1 -0
  215. package/dist/fence-feature/handles.js +84 -0
  216. package/dist/fence-feature/inspector.d.ts +6 -0
  217. package/dist/fence-feature/inspector.d.ts.map +1 -0
  218. package/dist/fence-feature/inspector.js +214 -0
  219. package/dist/fence-feature/interaction.d.ts +3 -0
  220. package/dist/fence-feature/interaction.d.ts.map +1 -0
  221. package/dist/fence-feature/interaction.js +41 -0
  222. package/dist/fence-feature/move-session.d.ts +9 -0
  223. package/dist/fence-feature/move-session.d.ts.map +1 -0
  224. package/dist/fence-feature/move-session.js +48 -0
  225. package/dist/fence-feature/move-tool.d.ts +5 -0
  226. package/dist/fence-feature/move-tool.d.ts.map +1 -0
  227. package/dist/fence-feature/move-tool.js +58 -0
  228. package/dist/fence-feature/pick-target.d.ts +7 -0
  229. package/dist/fence-feature/pick-target.d.ts.map +1 -0
  230. package/dist/fence-feature/pick-target.js +52 -0
  231. package/dist/floor-opening/definition.d.ts +3 -0
  232. package/dist/floor-opening/definition.d.ts.map +1 -0
  233. package/dist/floor-opening/definition.js +41 -0
  234. package/dist/floor-opening/floorplan.d.ts +156 -0
  235. package/dist/floor-opening/floorplan.d.ts.map +1 -0
  236. package/dist/floor-opening/floorplan.js +63 -0
  237. package/dist/gutter/definition.d.ts.map +1 -1
  238. package/dist/gutter/definition.js +2 -2
  239. package/dist/imported-mesh/definition.d.ts.map +1 -1
  240. package/dist/imported-mesh/definition.js +2 -0
  241. package/dist/imported-mesh/geometry.d.ts +1 -1
  242. package/dist/imported-mesh/geometry.d.ts.map +1 -1
  243. package/dist/imported-mesh/geometry.js +40 -12
  244. package/dist/index.d.ts +13 -2
  245. package/dist/index.d.ts.map +1 -1
  246. package/dist/index.js +20 -2
  247. package/dist/item/authored-face-host.d.ts +10 -0
  248. package/dist/item/authored-face-host.d.ts.map +1 -0
  249. package/dist/item/authored-face-host.js +87 -0
  250. package/dist/item/authored-params.d.ts +15 -0
  251. package/dist/item/authored-params.d.ts.map +1 -0
  252. package/dist/item/authored-params.js +72 -0
  253. package/dist/item/definition.d.ts +2 -2
  254. package/dist/item/definition.d.ts.map +1 -1
  255. package/dist/item/definition.js +33 -4
  256. package/dist/item/floorplan.d.ts +1 -1
  257. package/dist/item/floorplan.d.ts.map +1 -1
  258. package/dist/item/floorplan.js +35 -5
  259. package/dist/item/index.d.ts +1 -0
  260. package/dist/item/index.d.ts.map +1 -1
  261. package/dist/item/index.js +1 -0
  262. package/dist/item/model-loader.d.ts +2 -0
  263. package/dist/item/model-loader.d.ts.map +1 -1
  264. package/dist/item/model-loader.js +55 -23
  265. package/dist/item/move-tool.js +4 -4
  266. package/dist/item/paint.d.ts.map +1 -1
  267. package/dist/item/paint.js +5 -24
  268. package/dist/item/panel.d.ts +1 -3
  269. package/dist/item/panel.d.ts.map +1 -1
  270. package/dist/item/panel.js +20 -24
  271. package/dist/item/placement-notice.d.ts +14 -0
  272. package/dist/item/placement-notice.d.ts.map +1 -0
  273. package/dist/item/placement-notice.js +38 -0
  274. package/dist/item/plan-symbols.d.ts +67 -0
  275. package/dist/item/plan-symbols.d.ts.map +1 -0
  276. package/dist/item/plan-symbols.js +407 -0
  277. package/dist/item/renderer.d.ts +10 -0
  278. package/dist/item/renderer.d.ts.map +1 -1
  279. package/dist/item/renderer.js +64 -38
  280. package/dist/item/script-param-defaults.d.ts +12 -0
  281. package/dist/item/script-param-defaults.d.ts.map +1 -0
  282. package/dist/item/script-param-defaults.js +34 -0
  283. package/dist/lean-to-extension/definition.d.ts.map +1 -1
  284. package/dist/lean-to-extension/definition.js +1 -2
  285. package/dist/lean-to-extension/geometry.d.ts.map +1 -1
  286. package/dist/lean-to-extension/geometry.js +1 -1
  287. package/dist/lean-to-extension/layout.d.ts.map +1 -1
  288. package/dist/lean-to-extension/layout.js +2 -3
  289. package/dist/lean-to-extension/placement-validation.d.ts.map +1 -1
  290. package/dist/lean-to-extension/placement-validation.js +5 -5
  291. package/dist/lean-to-extension/tool.d.ts.map +1 -1
  292. package/dist/lean-to-extension/tool.js +5 -5
  293. package/dist/lineset/move-tool.d.ts.map +1 -1
  294. package/dist/lineset/move-tool.js +8 -2
  295. package/dist/liquid-line/move-tool.d.ts.map +1 -1
  296. package/dist/liquid-line/move-tool.js +8 -2
  297. package/dist/measurement/definition.js +1 -1
  298. package/dist/pipe-fitting/move-tool.d.ts.map +1 -1
  299. package/dist/pipe-fitting/move-tool.js +8 -2
  300. package/dist/pipe-segment/move-tool.d.ts.map +1 -1
  301. package/dist/pipe-segment/move-tool.js +8 -2
  302. package/dist/procedural-item/animation.d.ts +8 -0
  303. package/dist/procedural-item/animation.d.ts.map +1 -0
  304. package/dist/procedural-item/animation.js +116 -0
  305. package/dist/procedural-item/definition.d.ts.map +1 -1
  306. package/dist/procedural-item/definition.js +74 -8
  307. package/dist/procedural-item/geometry.d.ts +5 -1
  308. package/dist/procedural-item/geometry.d.ts.map +1 -1
  309. package/dist/procedural-item/geometry.js +239 -15
  310. package/dist/procedural-item/renderer.d.ts.map +1 -1
  311. package/dist/procedural-item/renderer.js +272 -23
  312. package/dist/ridge-vent/panel.d.ts.map +1 -1
  313. package/dist/ridge-vent/panel.js +5 -23
  314. package/dist/ridge-vent/renderer.d.ts.map +1 -1
  315. package/dist/ridge-vent/renderer.js +9 -8
  316. package/dist/roof/definition.d.ts.map +1 -1
  317. package/dist/roof/definition.js +4 -1
  318. package/dist/roof/floorplan.d.ts +8 -0
  319. package/dist/roof/floorplan.d.ts.map +1 -1
  320. package/dist/roof/floorplan.js +194 -18
  321. package/dist/roof/panel-model.d.ts.map +1 -1
  322. package/dist/roof/panel-model.js +10 -6
  323. package/dist/roof/panel.d.ts.map +1 -1
  324. package/dist/roof/panel.js +3 -10
  325. package/dist/roof/renderer.d.ts.map +1 -1
  326. package/dist/roof/renderer.js +5 -2
  327. package/dist/roof-segment/panel.d.ts.map +1 -1
  328. package/dist/roof-segment/panel.js +5 -24
  329. package/dist/roof-segment/renderer.d.ts.map +1 -1
  330. package/dist/roof-segment/renderer.js +17 -8
  331. package/dist/separator/definition.d.ts +3 -0
  332. package/dist/separator/definition.d.ts.map +1 -0
  333. package/dist/separator/definition.js +39 -0
  334. package/dist/separator/renderer.d.ts +5 -0
  335. package/dist/separator/renderer.d.ts.map +1 -0
  336. package/dist/separator/renderer.js +36 -0
  337. package/dist/shared/duct-body-paint.d.ts +0 -4
  338. package/dist/shared/duct-body-paint.d.ts.map +1 -1
  339. package/dist/shared/duct-body-paint.js +1 -5
  340. package/dist/shared/item-interaction-actions.d.ts +6 -0
  341. package/dist/shared/item-interaction-actions.d.ts.map +1 -0
  342. package/dist/shared/item-interaction-actions.js +27 -0
  343. package/dist/shared/item-interactions.d.ts +9 -0
  344. package/dist/shared/item-interactions.d.ts.map +1 -0
  345. package/dist/shared/item-interactions.js +74 -0
  346. package/dist/shared/item-light-placement.d.ts +2 -0
  347. package/dist/shared/item-light-placement.d.ts.map +1 -0
  348. package/dist/shared/item-light-placement.js +3 -0
  349. package/dist/shared/move-roof-tool.js +2 -1
  350. package/dist/shared/node-batch/batchable.d.ts +12 -0
  351. package/dist/shared/node-batch/batchable.d.ts.map +1 -0
  352. package/dist/shared/node-batch/batchable.js +41 -0
  353. package/dist/shared/node-batch/candidates.d.ts +7 -5
  354. package/dist/shared/node-batch/candidates.d.ts.map +1 -1
  355. package/dist/shared/node-batch/candidates.js +43 -59
  356. package/dist/shared/node-batch/release.d.ts +8 -0
  357. package/dist/shared/node-batch/release.d.ts.map +1 -0
  358. package/dist/shared/node-batch/release.js +16 -0
  359. package/dist/shared/node-batch/system.d.ts.map +1 -1
  360. package/dist/shared/node-batch/system.js +17 -12
  361. package/dist/shared/node-batch/types.d.ts +4 -1
  362. package/dist/shared/node-batch/types.d.ts.map +1 -1
  363. package/dist/shared/opening-documentation.d.ts +13 -1
  364. package/dist/shared/opening-documentation.d.ts.map +1 -1
  365. package/dist/shared/opening-documentation.js +245 -59
  366. package/dist/shared/opening-guides-runtime.d.ts.map +1 -1
  367. package/dist/shared/opening-guides-runtime.js +17 -14
  368. package/dist/shared/opening-placement-dimensions.d.ts.map +1 -1
  369. package/dist/shared/opening-placement-dimensions.js +3 -3
  370. package/dist/shared/opening-plane-offset.d.ts +23 -0
  371. package/dist/shared/opening-plane-offset.d.ts.map +1 -0
  372. package/dist/shared/opening-plane-offset.js +24 -0
  373. package/dist/shared/polygon-centroid-move.d.ts.map +1 -1
  374. package/dist/shared/polygon-centroid-move.js +4 -1
  375. package/dist/shared/polygon-vertex-affordance.d.ts.map +1 -1
  376. package/dist/shared/polygon-vertex-affordance.js +19 -15
  377. package/dist/shared/run-hangers.d.ts.map +1 -1
  378. package/dist/shared/run-hangers.js +5 -4
  379. package/dist/shared/scripted-opening-handles.d.ts +18 -0
  380. package/dist/shared/scripted-opening-handles.d.ts.map +1 -0
  381. package/dist/shared/scripted-opening-handles.js +53 -0
  382. package/dist/shared/scripted-opening.d.ts +25 -0
  383. package/dist/shared/scripted-opening.d.ts.map +1 -0
  384. package/dist/shared/scripted-opening.js +72 -0
  385. package/dist/shared/slot-paint.d.ts +14 -2
  386. package/dist/shared/slot-paint.d.ts.map +1 -1
  387. package/dist/shared/slot-paint.js +29 -29
  388. package/dist/shared/surface-paint.d.ts.map +1 -1
  389. package/dist/shared/surface-paint.js +2 -5
  390. package/dist/shared/swap-preview-material.d.ts +11 -0
  391. package/dist/shared/swap-preview-material.d.ts.map +1 -0
  392. package/dist/shared/swap-preview-material.js +16 -0
  393. package/dist/shared/system-checks.d.ts.map +1 -1
  394. package/dist/shared/system-checks.js +5 -3
  395. package/dist/shared/wall-attach-target.d.ts +3 -10
  396. package/dist/shared/wall-attach-target.d.ts.map +1 -1
  397. package/dist/shared/wall-attach-target.js +3 -63
  398. package/dist/shared/wall-opening-ceiling.d.ts +5 -15
  399. package/dist/shared/wall-opening-ceiling.d.ts.map +1 -1
  400. package/dist/shared/wall-opening-ceiling.js +10 -18
  401. package/dist/shelf/definition.d.ts.map +1 -1
  402. package/dist/shelf/definition.js +1 -1
  403. package/dist/shelf/geometry.d.ts.map +1 -1
  404. package/dist/shelf/geometry.js +1 -2
  405. package/dist/shelf/paint.d.ts.map +1 -1
  406. package/dist/shelf/paint.js +4 -10
  407. package/dist/site/line-ribbon.d.ts +31 -0
  408. package/dist/site/line-ribbon.d.ts.map +1 -0
  409. package/dist/site/line-ribbon.js +117 -0
  410. package/dist/site/lot-mask.d.ts +18 -0
  411. package/dist/site/lot-mask.d.ts.map +1 -0
  412. package/dist/site/lot-mask.js +35 -0
  413. package/dist/site/panel.d.ts +10 -0
  414. package/dist/site/panel.d.ts.map +1 -0
  415. package/dist/site/panel.js +155 -0
  416. package/dist/site/parametrics.d.ts +7 -0
  417. package/dist/site/parametrics.d.ts.map +1 -1
  418. package/dist/site/parametrics.js +8 -0
  419. package/dist/site/recessed-slab-ground-holes.d.ts.map +1 -1
  420. package/dist/site/recessed-slab-ground-holes.js +5 -2
  421. package/dist/site/renderer.d.ts.map +1 -1
  422. package/dist/site/renderer.js +150 -19
  423. package/dist/site/setbacks.d.ts +33 -0
  424. package/dist/site/setbacks.d.ts.map +1 -0
  425. package/dist/site/setbacks.js +204 -0
  426. package/dist/site/terrain-geometry.d.ts +28 -1
  427. package/dist/site/terrain-geometry.d.ts.map +1 -1
  428. package/dist/site/terrain-geometry.js +78 -4
  429. package/dist/site/terrain-holes.d.ts +15 -0
  430. package/dist/site/terrain-holes.d.ts.map +1 -0
  431. package/dist/site/terrain-holes.js +74 -0
  432. package/dist/site/terrain-mesh.d.ts +9 -2
  433. package/dist/site/terrain-mesh.d.ts.map +1 -1
  434. package/dist/site/terrain-mesh.js +36 -9
  435. package/dist/site/terrain-renderer.d.ts +9 -2
  436. package/dist/site/terrain-renderer.d.ts.map +1 -1
  437. package/dist/site/terrain-renderer.js +14 -4
  438. package/dist/slab/boundary-editor.d.ts +1 -1
  439. package/dist/slab/boundary-editor.d.ts.map +1 -1
  440. package/dist/slab/boundary-editor.js +13 -13
  441. package/dist/slab/definition.d.ts.map +1 -1
  442. package/dist/slab/definition.js +19 -3
  443. package/dist/slab/dependency-tracker.d.ts.map +1 -1
  444. package/dist/slab/dependency-tracker.js +67 -7
  445. package/dist/slab/elevation-limit.d.ts.map +1 -1
  446. package/dist/slab/elevation-limit.js +2 -2
  447. package/dist/slab/floorplan-affordances.d.ts +176 -4
  448. package/dist/slab/floorplan-affordances.d.ts.map +1 -1
  449. package/dist/slab/floorplan-affordances.js +0 -1
  450. package/dist/slab/floorplan-move.d.ts.map +1 -1
  451. package/dist/slab/floorplan-move.js +3 -4
  452. package/dist/slab/floorplan.d.ts +7 -0
  453. package/dist/slab/floorplan.d.ts.map +1 -1
  454. package/dist/slab/floorplan.js +22 -5
  455. package/dist/slab/geometry.d.ts.map +1 -1
  456. package/dist/slab/geometry.js +186 -76
  457. package/dist/slab/move-tool.js +7 -6
  458. package/dist/slab/paint.d.ts +18 -5
  459. package/dist/slab/paint.d.ts.map +1 -1
  460. package/dist/slab/paint.js +458 -9
  461. package/dist/slab/panel.d.ts.map +1 -1
  462. package/dist/slab/panel.js +28 -9
  463. package/dist/slab/placement-ownership.d.ts +2 -1
  464. package/dist/slab/placement-ownership.d.ts.map +1 -1
  465. package/dist/slab/placement-ownership.js +2 -2
  466. package/dist/slab/surface-split.d.ts +24 -0
  467. package/dist/slab/surface-split.d.ts.map +1 -0
  468. package/dist/slab/surface-split.js +389 -0
  469. package/dist/slab/tool.d.ts.map +1 -1
  470. package/dist/slab/tool.js +3 -3
  471. package/dist/stair/baluster-geometry.d.ts +21 -0
  472. package/dist/stair/baluster-geometry.d.ts.map +1 -0
  473. package/dist/stair/baluster-geometry.js +74 -0
  474. package/dist/stair/baluster-guard.d.ts +50 -0
  475. package/dist/stair/baluster-guard.d.ts.map +1 -0
  476. package/dist/stair/baluster-guard.js +71 -0
  477. package/dist/stair/boards-guard.d.ts +37 -0
  478. package/dist/stair/boards-guard.d.ts.map +1 -0
  479. package/dist/stair/boards-guard.js +61 -0
  480. package/dist/stair/cable-guard.d.ts +39 -0
  481. package/dist/stair/cable-guard.d.ts.map +1 -0
  482. package/dist/stair/cable-guard.js +105 -0
  483. package/dist/stair/construction-controls.d.ts +15 -0
  484. package/dist/stair/construction-controls.d.ts.map +1 -0
  485. package/dist/stair/construction-controls.js +29 -0
  486. package/dist/stair/continuous-railings.d.ts +10 -0
  487. package/dist/stair/continuous-railings.d.ts.map +1 -0
  488. package/dist/stair/continuous-railings.js +159 -0
  489. package/dist/stair/definition.d.ts.map +1 -1
  490. package/dist/stair/definition.js +16 -37
  491. package/dist/stair/documentation.d.ts +1 -1
  492. package/dist/stair/documentation.d.ts.map +1 -1
  493. package/dist/stair/documentation.js +10 -17
  494. package/dist/stair/floorplan-affordances.d.ts.map +1 -1
  495. package/dist/stair/floorplan-affordances.js +9 -25
  496. package/dist/stair/floorplan.d.ts +1 -23
  497. package/dist/stair/floorplan.d.ts.map +1 -1
  498. package/dist/stair/floorplan.js +102 -86
  499. package/dist/stair/glass-guard.d.ts +72 -0
  500. package/dist/stair/glass-guard.d.ts.map +1 -0
  501. package/dist/stair/glass-guard.js +167 -0
  502. package/dist/stair/guard-path.d.ts +119 -0
  503. package/dist/stair/guard-path.d.ts.map +1 -0
  504. package/dist/stair/guard-path.js +208 -0
  505. package/dist/stair/materials.d.ts +11 -0
  506. package/dist/stair/materials.d.ts.map +1 -0
  507. package/dist/stair/materials.js +51 -0
  508. package/dist/stair/metal-guard.d.ts +38 -0
  509. package/dist/stair/metal-guard.d.ts.map +1 -0
  510. package/dist/stair/metal-guard.js +79 -0
  511. package/dist/stair/paint.d.ts +32 -0
  512. package/dist/stair/paint.d.ts.map +1 -1
  513. package/dist/stair/paint.js +75 -36
  514. package/dist/stair/panel.d.ts.map +1 -1
  515. package/dist/stair/panel.js +154 -17
  516. package/dist/stair/parametrics.d.ts +1 -1
  517. package/dist/stair/parametrics.d.ts.map +1 -1
  518. package/dist/stair/parametrics.js +32 -15
  519. package/dist/stair/plan-entry.d.ts +31 -0
  520. package/dist/stair/plan-entry.d.ts.map +1 -0
  521. package/dist/stair/plan-entry.js +325 -0
  522. package/dist/stair/post-and-rail-guard.d.ts +31 -0
  523. package/dist/stair/post-and-rail-guard.d.ts.map +1 -0
  524. package/dist/stair/post-and-rail-guard.js +63 -0
  525. package/dist/stair/railing-controls.d.ts +9 -0
  526. package/dist/stair/railing-controls.d.ts.map +1 -0
  527. package/dist/stair/railing-controls.js +49 -0
  528. package/dist/stair/renderer.d.ts.map +1 -1
  529. package/dist/stair/renderer.js +259 -259
  530. package/dist/stair/use-stair-render-data.d.ts +317 -0
  531. package/dist/stair/use-stair-render-data.d.ts.map +1 -0
  532. package/dist/stair/use-stair-render-data.js +73 -0
  533. package/dist/stair-segment/definition.d.ts.map +1 -1
  534. package/dist/stair-segment/definition.js +51 -10
  535. package/dist/stair-segment/panel.d.ts.map +1 -1
  536. package/dist/stair-segment/panel.js +36 -42
  537. package/dist/stair-segment/parametrics.d.ts +1 -1
  538. package/dist/stair-segment/parametrics.d.ts.map +1 -1
  539. package/dist/stair-segment/parametrics.js +21 -8
  540. package/dist/stair-segment/renderer.d.ts.map +1 -1
  541. package/dist/stair-segment/renderer.js +16 -28
  542. package/dist/turbine-vent/definition.d.ts.map +1 -1
  543. package/dist/turbine-vent/definition.js +2 -5
  544. package/dist/turbine-vent/paint.d.ts.map +1 -1
  545. package/dist/turbine-vent/paint.js +2 -5
  546. package/dist/turbine-vent/panel.d.ts.map +1 -1
  547. package/dist/turbine-vent/panel.js +5 -23
  548. package/dist/unit/unit-panel.d.ts.map +1 -1
  549. package/dist/unit/unit-panel.js +6 -1
  550. package/dist/wall/actions.d.ts.map +1 -1
  551. package/dist/wall/actions.js +7 -2
  552. package/dist/wall/construction-dimensions.js +8 -5
  553. package/dist/wall/contextual-dimensions.js +4 -4
  554. package/dist/wall/curtain-wall-materials.d.ts +1 -1
  555. package/dist/wall/curtain-wall-materials.d.ts.map +1 -1
  556. package/dist/wall/curtain-wall-materials.js +2 -2
  557. package/dist/wall/curve-tool.d.ts.map +1 -1
  558. package/dist/wall/curve-tool.js +4 -0
  559. package/dist/wall/definition.d.ts.map +1 -1
  560. package/dist/wall/definition.js +41 -17
  561. package/dist/wall/floorplan-move.d.ts +1 -1
  562. package/dist/wall/floorplan-move.d.ts.map +1 -1
  563. package/dist/wall/floorplan-move.js +20 -83
  564. package/dist/wall/floorplan-tool.d.ts.map +1 -1
  565. package/dist/wall/floorplan-tool.js +10 -11
  566. package/dist/wall/floorplan.d.ts +3 -1
  567. package/dist/wall/floorplan.d.ts.map +1 -1
  568. package/dist/wall/floorplan.js +184 -21
  569. package/dist/wall/measurement.d.ts.map +1 -1
  570. package/dist/wall/measurement.js +5 -5
  571. package/dist/wall/move-endpoint-tool.d.ts.map +1 -1
  572. package/dist/wall/move-endpoint-tool.js +20 -7
  573. package/dist/wall/move-shared.d.ts.map +1 -1
  574. package/dist/wall/move-shared.js +11 -7
  575. package/dist/wall/move-tool.d.ts.map +1 -1
  576. package/dist/wall/move-tool.js +118 -148
  577. package/dist/wall/paint.d.ts +26 -15
  578. package/dist/wall/paint.d.ts.map +1 -1
  579. package/dist/wall/paint.js +306 -117
  580. package/dist/wall/panel-model.d.ts +18 -0
  581. package/dist/wall/panel-model.d.ts.map +1 -1
  582. package/dist/wall/panel-model.js +77 -19
  583. package/dist/wall/panel.d.ts.map +1 -1
  584. package/dist/wall/panel.js +217 -41
  585. package/dist/wall/parametrics.d.ts.map +1 -1
  586. package/dist/wall/parametrics.js +3 -0
  587. package/dist/wall/rectangle-command.d.ts +111 -12
  588. package/dist/wall/rectangle-command.d.ts.map +1 -1
  589. package/dist/wall/rectangle-tool.d.ts.map +1 -1
  590. package/dist/wall/rectangle-tool.js +26 -8
  591. package/dist/wall/renderer.d.ts.map +1 -1
  592. package/dist/wall/renderer.js +4 -2
  593. package/dist/wall/split-floorplan-layer.d.ts.map +1 -1
  594. package/dist/wall/split-floorplan-layer.js +7 -7
  595. package/dist/wall/split-session.d.ts.map +1 -1
  596. package/dist/wall/split-session.js +7 -1
  597. package/dist/wall/system.d.ts.map +1 -1
  598. package/dist/wall/system.js +36 -4
  599. package/dist/wall/tool.d.ts.map +1 -1
  600. package/dist/wall/tool.js +105 -49
  601. package/dist/wall/treatment-level-data.d.ts +3 -2
  602. package/dist/wall/treatment-level-data.d.ts.map +1 -1
  603. package/dist/wall/treatment-level-data.js +17 -13
  604. package/dist/wall/treatments.d.ts +10 -10
  605. package/dist/wall/treatments.d.ts.map +1 -1
  606. package/dist/wall/treatments.js +67 -54
  607. package/dist/wall/wall-batch-system.d.ts +7 -0
  608. package/dist/wall/wall-batch-system.d.ts.map +1 -1
  609. package/dist/wall/wall-batch-system.js +35 -3
  610. package/dist/wall/wall-batch.d.ts +6 -0
  611. package/dist/wall/wall-batch.d.ts.map +1 -1
  612. package/dist/wall/wall-batch.js +7 -1
  613. package/dist/window/definition.d.ts.map +1 -1
  614. package/dist/window/definition.js +12 -4
  615. package/dist/window/floorplan-move.d.ts.map +1 -1
  616. package/dist/window/floorplan-move.js +3 -1
  617. package/dist/window/floorplan.d.ts.map +1 -1
  618. package/dist/window/floorplan.js +145 -60
  619. package/dist/window/mechanism.d.ts +4 -0
  620. package/dist/window/mechanism.d.ts.map +1 -0
  621. package/dist/window/mechanism.js +20 -0
  622. package/dist/window/move-tool.d.ts.map +1 -1
  623. package/dist/window/move-tool.js +79 -48
  624. package/dist/window/paint.d.ts.map +1 -1
  625. package/dist/window/paint.js +3 -0
  626. package/dist/window/panel.d.ts.map +1 -1
  627. package/dist/window/panel.js +32 -88
  628. package/dist/window/placement.d.ts +23 -0
  629. package/dist/window/placement.d.ts.map +1 -0
  630. package/dist/window/placement.js +66 -0
  631. package/dist/window/preview.d.ts.map +1 -1
  632. package/dist/window/preview.js +2 -0
  633. package/dist/window/renderer.d.ts.map +1 -1
  634. package/dist/window/renderer.js +3 -2
  635. package/dist/window/tool.d.ts.map +1 -1
  636. package/dist/window/tool.js +96 -24
  637. package/dist/window/window-math.d.ts +6 -14
  638. package/dist/window/window-math.d.ts.map +1 -1
  639. package/dist/window/window-math.js +14 -20
  640. package/dist/zone/contextual-dimensions.d.ts.map +1 -1
  641. package/dist/zone/contextual-dimensions.js +6 -28
  642. package/dist/zone/definition.d.ts.map +1 -1
  643. package/dist/zone/definition.js +3 -3
  644. package/dist/zone/floorplan-affordances.d.ts +200 -0
  645. package/dist/zone/floorplan-affordances.d.ts.map +1 -1
  646. package/dist/zone/floorplan.d.ts +1 -1
  647. package/dist/zone/floorplan.d.ts.map +1 -1
  648. package/dist/zone/floorplan.js +93 -53
  649. package/dist/zone/quantities-panel.d.ts.map +1 -1
  650. package/dist/zone/quantities-panel.js +3 -14
  651. package/dist/zone/quick-measurement.d.ts +2 -2
  652. package/dist/zone/quick-measurement.d.ts.map +1 -1
  653. package/dist/zone/quick-measurement.js +6 -5
  654. package/dist/zone/renderer.d.ts +1 -1
  655. package/dist/zone/renderer.d.ts.map +1 -1
  656. package/dist/zone/renderer.js +58 -146
  657. package/dist/zone/room-clear-dimensions.js +3 -3
  658. package/dist/zone/room-documentation.d.ts.map +1 -1
  659. package/dist/zone/room-documentation.js +2 -6
  660. package/package.json +11 -11
  661. package/dist/block/slots.d.ts +0 -4
  662. package/dist/block/slots.d.ts.map +0 -1
  663. package/dist/block/slots.js +0 -17
  664. package/dist/cabinet/slots.d.ts +0 -4
  665. package/dist/cabinet/slots.d.ts.map +0 -1
  666. package/dist/cabinet/slots.js +0 -24
  667. package/dist/ceiling/slots.d.ts +0 -6
  668. package/dist/ceiling/slots.d.ts.map +0 -1
  669. package/dist/ceiling/slots.js +0 -7
  670. package/dist/column/slots.d.ts +0 -9
  671. package/dist/column/slots.d.ts.map +0 -1
  672. package/dist/column/slots.js +0 -19
  673. package/dist/door/slots.d.ts +0 -9
  674. package/dist/door/slots.d.ts.map +0 -1
  675. package/dist/door/slots.js +0 -20
  676. package/dist/elevator/slots.d.ts +0 -8
  677. package/dist/elevator/slots.d.ts.map +0 -1
  678. package/dist/elevator/slots.js +0 -17
  679. package/dist/fence/slots.d.ts +0 -10
  680. package/dist/fence/slots.d.ts.map +0 -1
  681. package/dist/fence/slots.js +0 -23
  682. package/dist/item/__fixtures__/main-floorplan.d.ts +0 -26
  683. package/dist/item/__fixtures__/main-floorplan.d.ts.map +0 -1
  684. package/dist/item/__fixtures__/main-floorplan.js +0 -297
  685. package/dist/lean-to-extension/slots.d.ts +0 -5
  686. package/dist/lean-to-extension/slots.d.ts.map +0 -1
  687. package/dist/lean-to-extension/slots.js +0 -15
  688. package/dist/shelf/slots.d.ts +0 -9
  689. package/dist/shelf/slots.d.ts.map +0 -1
  690. package/dist/shelf/slots.js +0 -30
  691. package/dist/slab/slots.d.ts +0 -10
  692. package/dist/slab/slots.d.ts.map +0 -1
  693. package/dist/slab/slots.js +0 -20
  694. package/dist/stair/floor-stack.d.ts +0 -10
  695. package/dist/stair/floor-stack.d.ts.map +0 -1
  696. package/dist/stair/floor-stack.js +0 -115
  697. package/dist/stair/slots.d.ts +0 -7
  698. package/dist/stair/slots.d.ts.map +0 -1
  699. package/dist/stair/slots.js +0 -13
  700. package/dist/wall/drawing-mode.d.ts +0 -12
  701. package/dist/wall/drawing-mode.d.ts.map +0 -1
  702. package/dist/wall/drawing-mode.js +0 -38
  703. package/dist/wall/slots.d.ts +0 -10
  704. package/dist/wall/slots.d.ts.map +0 -1
  705. package/dist/wall/slots.js +0 -92
  706. package/dist/window/slots.d.ts +0 -5
  707. package/dist/window/slots.d.ts.map +0 -1
  708. package/dist/window/slots.js +0 -11
@@ -1,5 +1,66 @@
1
- import { roofPlanOverlapEntryOwns, subtractPolygonsFromPolygon, unionPolygons, } from '@pascal-app/core';
1
+ import { getRoofSegmentVisibleTopBounds, roofPlanOverlapEntryOwns, subtractPolygonsFromPolygon, unionPolygons, } from '@pascal-app/core';
2
+ import { floorplanGeometryMetadata, readFloorplanContext } from '@pascal-app/editor';
2
3
  import { getConicalRoofPlanFootprint, getRoofSegmentPlanLinework } from '../roof-segment/floorplan';
4
+ /**
5
+ * `roof-segment.pitch` is stored in DEGREES; a roof plan is annotated as the
6
+ * rise over a 12 run. 30.256° → tan 0.5833 × 12 → 7.00 → '7:12'. Rounded to
7
+ * the nearest half, so a modelled pitch a hair off a standard slope still
8
+ * reads as the slope the framer will cut. Returns '' for a flat roof, which
9
+ * has no slope to annotate.
10
+ */
11
+ export function roofPitchLabel(pitchDeg) {
12
+ if (!Number.isFinite(pitchDeg) || pitchDeg <= 0)
13
+ return '';
14
+ const rise = Math.tan((pitchDeg * Math.PI) / 180) * 12;
15
+ if (!Number.isFinite(rise) || rise <= 0)
16
+ return '';
17
+ const rounded = Math.round(rise * 2) / 2;
18
+ return `${Number.isInteger(rounded) ? rounded : rounded.toFixed(1)}:12`;
19
+ }
20
+ /**
21
+ * One down-slope arrow per roof PLANE, in segment-local coordinates
22
+ * (lx = width axis, lz = depth axis) — the same local space
23
+ * `getRoofSegmentPlanLinework` returns ridges and hips in:
24
+ *
25
+ * gable / gambrel two planes falling away from the centre ridge (±lz)
26
+ * shed one plane, high eave at −lz falling to +lz
27
+ * hip / mansard / four planes, one off each eave
28
+ * dutch
29
+ * flat none
30
+ *
31
+ * Arrows run from just off the ridge to just short of the eave so the head
32
+ * lands inside the roof outline rather than on it.
33
+ */
34
+ function slopeArrows(node) {
35
+ const hw = Math.max(node.width, 0.01) / 2;
36
+ const hd = Math.max(node.depth, 0.01) / 2;
37
+ const along = (run) => ({ near: run * 0.14, far: run * 0.86 });
38
+ switch (node.roofType) {
39
+ case 'flat':
40
+ return [];
41
+ case 'shed':
42
+ // Unchanged from the linework builder: the 3D shed falls −lz → +lz.
43
+ return [{ tail: [0, -hd * 0.55], head: [0, hd * 0.55] }];
44
+ case 'gable':
45
+ case 'gambrel': {
46
+ const z = along(hd);
47
+ return [
48
+ { tail: [-hw * 0.35, z.near], head: [-hw * 0.35, z.far] },
49
+ { tail: [hw * 0.35, -z.near], head: [hw * 0.35, -z.far] },
50
+ ];
51
+ }
52
+ default: {
53
+ const z = along(hd);
54
+ const x = along(hw);
55
+ return [
56
+ { tail: [0, z.near], head: [0, z.far] },
57
+ { tail: [0, -z.near], head: [0, -z.far] },
58
+ { tail: [x.near, 0], head: [x.far, 0] },
59
+ { tail: [-x.near, 0], head: [-x.far, 0] },
60
+ ];
61
+ }
62
+ }
63
+ }
3
64
  function overlapEntry(entry, ctx) {
4
65
  const supportSegment = entry.roof.support?.kind === 'roof'
5
66
  ? ctx.resolve(entry.roof.support.roofSegmentId)
@@ -17,7 +78,7 @@ function overlapEntry(entry, ctx) {
17
78
  };
18
79
  }
19
80
  /** A segment's footprint + ridge/hip/break/slope linework, in world plan coords. */
20
- function buildSegPlan(roof, seg) {
81
+ function buildSegPlan(roof, seg, drafting) {
21
82
  const cosRoof = Math.cos(-roof.rotation);
22
83
  const sinRoof = Math.sin(-roof.rotation);
23
84
  const segCx = roof.position[0] + seg.position[0] * cosRoof - seg.position[2] * sinRoof;
@@ -39,17 +100,42 @@ function buildSegPlan(roof, seg) {
39
100
  const footprint = seg.roofType === 'conical'
40
101
  ? getConicalRoofPlanFootprint(seg).map(([x, z]) => tp(x, z))
41
102
  : [tp(-hw, -hd), tp(hw, -hd), tp(hw, hd), tp(-hw, hd)];
103
+ const ridges = lw.ridges.map(mapSeg);
104
+ const hips = lw.hips.map(mapSeg);
105
+ const breaks = lw.breaks.map(mapSeg);
106
+ if (!drafting) {
107
+ const slopes = lw.slope
108
+ ? [
109
+ {
110
+ tail: tp(lw.slope.tail[0], lw.slope.tail[1]),
111
+ head: tp(lw.slope.head[0], lw.slope.head[1]),
112
+ pitch: '',
113
+ },
114
+ ]
115
+ : [];
116
+ return { footprint, eave: footprint, ridges, hips, breaks, slopes };
117
+ }
118
+ // The drip edge: core's own visible-top bounds, which add the horizontal
119
+ // component of `overhang` (plus half the wall thickness and, on the sloped
120
+ // faces, the shingle projection) to the footprint on each side.
121
+ const edge = getRoofSegmentVisibleTopBounds(seg);
122
+ const pitch = roofPitchLabel(seg.pitch);
42
123
  return {
43
124
  footprint,
44
- ridges: lw.ridges.map(mapSeg),
45
- hips: lw.hips.map(mapSeg),
46
- breaks: lw.breaks.map(mapSeg),
47
- slope: lw.slope
48
- ? {
49
- tail: tp(lw.slope.tail[0], lw.slope.tail[1]),
50
- head: tp(lw.slope.head[0], lw.slope.head[1]),
51
- }
52
- : null,
125
+ eave: [
126
+ tp(edge.minX, edge.minZ),
127
+ tp(edge.maxX, edge.minZ),
128
+ tp(edge.maxX, edge.maxZ),
129
+ tp(edge.minX, edge.maxZ),
130
+ ],
131
+ ridges,
132
+ hips,
133
+ breaks,
134
+ slopes: slopeArrows(seg).map((arrow) => ({
135
+ tail: tp(arrow.tail[0], arrow.tail[1]),
136
+ head: tp(arrow.head[0], arrow.head[1]),
137
+ pitch,
138
+ })),
53
139
  };
54
140
  }
55
141
  function pointInPolygon(point, polygon) {
@@ -126,10 +212,13 @@ export function buildRoofFloorplan(node, ctx) {
126
212
  const segments = ctx.children.filter((c) => c.type === 'roof-segment');
127
213
  if (segments.length === 0)
128
214
  return null;
215
+ // Eave outlines, an arrow per plane, pitch tags and the 'roof-plan' role are
216
+ // sheet drafting; the editor plan keeps its outline, linework and one arrow.
217
+ const drafting = readFloorplanContext(ctx).drafting;
129
218
  const entries = segments.map((segment) => ({
130
219
  roof: node,
131
220
  segment,
132
- plan: buildSegPlan(node, segment),
221
+ plan: buildSegPlan(node, segment, drafting),
133
222
  }));
134
223
  for (const sibling of ctx.siblings) {
135
224
  if (sibling.type !== 'roof')
@@ -138,7 +227,7 @@ export function buildRoofFloorplan(node, ctx) {
138
227
  const segment = ctx.resolve(childId);
139
228
  if (segment?.type !== 'roof-segment')
140
229
  continue;
141
- entries.push({ roof: sibling, segment, plan: buildSegPlan(sibling, segment) });
230
+ entries.push({ roof: sibling, segment, plan: buildSegPlan(sibling, segment, drafting) });
142
231
  }
143
232
  }
144
233
  const currentEntries = entries.filter((entry) => entry.roof.id === node.id);
@@ -156,11 +245,15 @@ export function buildRoofFloorplan(node, ctx) {
156
245
  plan: entry.plan,
157
246
  cutters,
158
247
  footprints: subtractPolygonsFromPolygon(entry.plan.footprint, cutters),
248
+ eaves: subtractPolygonsFromPolygon(entry.plan.eave, cutters),
249
+ /** True when the drip edge is far enough outside the wall line to draw. */
250
+ hasOverhang: drafting && polygonSpread(entry.plan.eave) - polygonSpread(entry.plan.footprint) > 0.04,
159
251
  };
160
252
  });
161
253
  const rings = unionPolygons(visiblePlans.flatMap(({ footprints }) => footprints));
162
254
  if (rings.length === 0)
163
255
  return null;
256
+ const eaveRings = unionPolygons(visiblePlans.flatMap(({ eaves, hasOverhang }) => (hasOverhang ? eaves : [])));
164
257
  const view = ctx.viewState;
165
258
  const palette = view?.palette;
166
259
  const showSelectedChrome = (view?.selected ?? false) || (view?.highlighted ?? false);
@@ -168,6 +261,13 @@ export function buildRoofFloorplan(node, ctx) {
168
261
  const eaveWidth = showSelectedChrome ? 0.04 : 0.03;
169
262
  const ridgeWidth = showSelectedChrome ? 0.05 : 0.038;
170
263
  const hipWidth = showSelectedChrome ? 0.04 : 0.026;
264
+ const overhangWidth = showSelectedChrome ? 0.03 : 0.022;
265
+ // Drafted, two strata: the REFERENCE a floor plan always carries (the dashed
266
+ // overhang line — the roof flying past the walls) and the ROOF PLAN
267
+ // proper (outline, ridges, hips, arrows, pitches), which is the
268
+ // 'roof-plan' annotation — off over a floor plan until the Roof plan
269
+ // layer is on, the roof is selected, or the sheet IS the roof plan.
270
+ const reference = [];
171
271
  const children = [];
172
272
  const pushLine = (a, b, width) => {
173
273
  children.push({
@@ -182,7 +282,25 @@ export function buildRoofFloorplan(node, ctx) {
182
282
  pointerEvents: 'none',
183
283
  });
184
284
  };
185
- // Merged outline (eaves).
285
+ // The drip edge — the roof's actual outer boundary, overhang included —
286
+ // drawn DASHED under the wall line so the two never read as one edge. This
287
+ // is the convention every roof plan uses: solid where the roof meets the
288
+ // structure, dashed where it flies past it.
289
+ for (const ring of eaveRings) {
290
+ if (ring.length < 3)
291
+ continue;
292
+ reference.push({
293
+ kind: 'polygon',
294
+ points: ring.map(([x, z]) => [x, z]),
295
+ fill: 'none',
296
+ stroke: ink,
297
+ strokeWidth: overhangWidth,
298
+ strokeDasharray: '0.28 0.16',
299
+ strokeLinejoin: 'miter',
300
+ pointerEvents: 'none',
301
+ });
302
+ }
303
+ // Merged outline (wall line under the roof).
186
304
  for (const ring of rings) {
187
305
  if (ring.length < 3)
188
306
  continue;
@@ -212,9 +330,11 @@ export function buildRoofFloorplan(node, ctx) {
212
330
  pushLine(visible[0], visible[1], ridgeWidth);
213
331
  }
214
332
  }
215
- if (plan.slope) {
216
- const { tail, head } = plan.slope;
217
- const visibleSlope = clipLineByCutters([tail, head], cutters).at(-1);
333
+ // One down-slope arrow per roof plane, each tagged with the pitch in
334
+ // 12ths — the annotation a roof plan is read for. The arrow points the
335
+ // way water runs; the tag is the number the framer cuts to.
336
+ for (const slope of plan.slopes) {
337
+ const visibleSlope = clipLineByCutters([slope.tail, slope.head], cutters).at(-1);
218
338
  if (!visibleSlope)
219
339
  continue;
220
340
  const [visibleTail, visibleHead] = visibleSlope;
@@ -239,7 +359,63 @@ export function buildRoofFloorplan(node, ctx) {
239
359
  strokeLinejoin: 'round',
240
360
  pointerEvents: 'none',
241
361
  });
362
+ if (!slope.pitch || len < PITCH_LABEL_MIN_RUN)
363
+ continue;
364
+ // Set beside the shaft, clear of it, at the arrow's midpoint. The
365
+ // perpendicular is chosen so the tag always sits ABOVE its arrow (and
366
+ // to its right where the arrow runs vertically), so opposing slopes of
367
+ // the same roof do not put their tags on opposite sides.
368
+ let px = uz;
369
+ let pz = -ux;
370
+ if (pz > 1e-6 || (Math.abs(pz) <= 1e-6 && px < 0)) {
371
+ px = -px;
372
+ pz = -pz;
373
+ }
374
+ const mx = (visibleTail[0] + visibleHead[0]) / 2 + px * PITCH_LABEL_OFFSET;
375
+ const mz = (visibleTail[1] + visibleHead[1]) / 2 + pz * PITCH_LABEL_OFFSET;
376
+ children.push({
377
+ kind: 'text',
378
+ x: mx,
379
+ y: mz,
380
+ text: slope.pitch,
381
+ fontSize: PITCH_LABEL_FONT_SIZE,
382
+ fill: ink,
383
+ stroke: '#ffffff',
384
+ strokeWidth: PITCH_LABEL_FONT_SIZE * 0.3,
385
+ paintOrder: 'stroke',
386
+ fontFamily: 'system-ui, -apple-system, sans-serif',
387
+ fontWeight: 600,
388
+ textAnchor: 'middle',
389
+ dominantBaseline: 'central',
390
+ upright: true,
391
+ metadata: floorplanGeometryMetadata({ annotationRole: 'roof-pitch' }),
392
+ });
242
393
  }
243
394
  }
244
- return children.length > 0 ? { kind: 'group', children } : null;
395
+ if (!drafting)
396
+ return children.length > 0 ? { kind: 'group', children } : null;
397
+ if (reference.length === 0 && children.length === 0)
398
+ return null;
399
+ // A selected / highlighted roof shows its plan whatever the layer says —
400
+ // the user is looking at the roof.
401
+ const plan = showSelectedChrome
402
+ ? { kind: 'group', children }
403
+ : {
404
+ kind: 'group',
405
+ children,
406
+ metadata: floorplanGeometryMetadata({ annotationRole: 'roof-plan' }),
407
+ };
408
+ return { kind: 'group', children: children.length > 0 ? [...reference, plan] : reference };
409
+ }
410
+ /** Longest edge of a polygon's bounding box — how the overhang test compares. */
411
+ function polygonSpread(polygon) {
412
+ if (polygon.length === 0)
413
+ return 0;
414
+ const xs = polygon.map(([x]) => x);
415
+ const zs = polygon.map(([, z]) => z);
416
+ return Math.max(...xs) - Math.min(...xs) + (Math.max(...zs) - Math.min(...zs));
245
417
  }
418
+ const PITCH_LABEL_FONT_SIZE = 0.22;
419
+ const PITCH_LABEL_OFFSET = 0.24;
420
+ /** Below this arrow length the tag would sit on top of its own arrowhead. */
421
+ const PITCH_LABEL_MIN_RUN = 0.6;
@@ -1 +1 @@
1
- {"version":3,"file":"panel-model.d.ts","sourceRoot":"","sources":["../../src/roof/panel-model.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,QAAQ,EAEd,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAEL,KAAK,cAAc,EAIpB,MAAM,oBAAoB,CAAA;AAG3B,eAAO,MAAM,cAAc,EAAE,cAAc,CAAC,QAAQ,CAqJnD,CAAA"}
1
+ {"version":3,"file":"panel-model.d.ts","sourceRoot":"","sources":["../../src/roof/panel-model.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,QAAQ,EAEd,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAEL,KAAK,cAAc,EAIpB,MAAM,oBAAoB,CAAA;AAG3B,eAAO,MAAM,cAAc,EAAE,cAAc,CAAC,QAAQ,CAyJnD,CAAA"}
@@ -1,5 +1,5 @@
1
1
  import { nodeRegistry, useScene, } from '@pascal-app/core';
2
- import { duplicateRoofSubtree, triggerSFX, useEditor, } from '@pascal-app/editor';
2
+ import { duplicateNodeAndPickUp, triggerSFX, useEditor, } from '@pascal-app/editor';
3
3
  import { useViewer } from '@pascal-app/viewer';
4
4
  export const roofPanelModel = {
5
5
  rows({ node, nodes, update }) {
@@ -28,7 +28,12 @@ export const roofPanelModel = {
28
28
  kind: 'action',
29
29
  section: 'Segments',
30
30
  label: 'Draw Segment',
31
- onSelect: () => activate('roof'),
31
+ // Arming a tool ends the selection; the roof tool draws into the roof
32
+ // selected while it is armed, so hand it this one explicitly.
33
+ onSelect: () => {
34
+ activate('roof');
35
+ select(node.id);
36
+ },
32
37
  });
33
38
  for (const axis of [0, 1, 2])
34
39
  rows.push({
@@ -124,10 +129,9 @@ export const roofPanelModel = {
124
129
  id: 'duplicate',
125
130
  label: 'Duplicate',
126
131
  onSelect: () => {
127
- if (!useScene.getState().nodes[node.id])
128
- return;
129
- triggerSFX('sfx:item-pick');
130
- duplicateRoofSubtree(node.id, { mode: 'move' });
132
+ const live = useScene.getState().nodes[node.id];
133
+ if (live)
134
+ duplicateNodeAndPickUp(live);
131
135
  },
132
136
  },
133
137
  {
@@ -1 +1 @@
1
- {"version":3,"file":"panel.d.ts","sourceRoot":"","sources":["../../src/roof/panel.tsx"],"names":[],"mappings":"AAmCA,MAAM,CAAC,OAAO,UAAU,SAAS,uCA2gBhC"}
1
+ {"version":3,"file":"panel.d.ts","sourceRoot":"","sources":["../../src/roof/panel.tsx"],"names":[],"mappings":"AAmCA,MAAM,CAAC,OAAO,UAAU,SAAS,uCAogBhC"}
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useScene, } from '@pascal-app/core';
4
- import { ActionButton, ActionGroup, commitParametricNodeFields, duplicateRoofSubtree, formatLinearMeasurement, PanelSection, PanelWrapper, SegmentedControl, SliderControl, triggerSFX, useEditor, } from '@pascal-app/editor';
4
+ import { ActionButton, ActionGroup, commitParametricNodeFields, duplicateNodeAndPickUp, formatLinearMeasurement, PanelSection, PanelWrapper, SegmentedControl, SliderControl, triggerSFX, useEditor, } from '@pascal-app/editor';
5
5
  import { useViewer } from '@pascal-app/viewer';
6
6
  import { Copy, Move, Plus, Trash2 } from 'lucide-react';
7
7
  import { useCallback, useState } from 'react';
@@ -124,15 +124,8 @@ export default function RoofPanel() {
124
124
  setSelection({ selectedIds: [segmentId] });
125
125
  }, [setSelection]);
126
126
  const handleDuplicate = useCallback(() => {
127
- if (!node)
128
- return;
129
- triggerSFX('sfx:item-pick');
130
- try {
131
- duplicateRoofSubtree(node.id, { mode: 'move' });
132
- }
133
- catch (e) {
134
- console.error('Failed to duplicate roof', e);
135
- }
127
+ if (node)
128
+ duplicateNodeAndPickUp(node);
136
129
  }, [node]);
137
130
  const handleMove = useCallback(() => {
138
131
  if (node) {
@@ -1 +1 @@
1
- {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/roof/renderer.tsx"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,QAAQ,EAKd,MAAM,kBAAkB,CAAA;AAQzB,eAAO,MAAM,YAAY,GAAI,mBAAmB;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,gCAkHjE,CAAA;AAED,eAAe,YAAY,CAAA"}
1
+ {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/roof/renderer.tsx"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,QAAQ,EAKd,MAAM,kBAAkB,CAAA;AAczB,eAAO,MAAM,YAAY,GAAI,mBAAmB;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,gCA8HjE,CAAA;AAED,eAAe,YAAY,CAAA"}
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { hasSegmentMaterialOverride, useLiveNodeOverrides, useRegistry, useScene, } from '@pascal-app/core';
4
- import { getRoofMaterialArray, NodeRenderer, useNodeEvents, useViewer } from '@pascal-app/viewer';
4
+ import { getRoofMaterialArray, levelWallCladdingRef, NodeRenderer, useNodeEvents, useViewer, } from '@pascal-app/viewer';
5
5
  import { useEffect, useLayoutEffect, useMemo, useRef } from 'react';
6
6
  import { useShallow } from 'zustand/react/shallow';
7
7
  import { createPlaceholderGeometry } from '../shared/placeholder-geometry';
@@ -65,7 +65,10 @@ export const RoofRenderer = ({ node: rawNode }) => {
65
65
  }));
66
66
  // 4 groups map 1:1 to the roof's 4-material array (see getRoofMaterialArray).
67
67
  const placeholderGeometry = useMemo(() => createPlaceholderGeometry(4), []);
68
- const customMaterial = useMemo(() => getRoofMaterialArray(node, shading, textures, colorPreset, sceneTheme), [node, shading, textures, colorPreset, sceneTheme]);
68
+ // The gable band is clad like the walls below it (their assemblies).
69
+ const wallCladdingRef = useScene((state) => levelWallCladdingRef(state.nodes, node));
70
+ const sceneMaterials = useScene((state) => state.materials);
71
+ const customMaterial = useMemo(() => getRoofMaterialArray(node, shading, textures, colorPreset, sceneTheme, wallCladdingRef, sceneMaterials), [node, shading, textures, colorPreset, sceneTheme, wallCladdingRef, sceneMaterials]);
69
72
  const material = debugColors
70
73
  ? getRoofDebugMaterials(shading)
71
74
  : customMaterial || getRoofMaterials(shading, textures, colorPreset);
@@ -1 +1 @@
1
- {"version":3,"file":"panel.d.ts","sourceRoot":"","sources":["../../src/roof-segment/panel.tsx"],"names":[],"mappings":"AAkGA,MAAM,CAAC,OAAO,UAAU,gBAAgB,uCAsoBvC"}
1
+ {"version":3,"file":"panel.d.ts","sourceRoot":"","sources":["../../src/roof-segment/panel.tsx"],"names":[],"mappings":"AAkGA,MAAM,CAAC,OAAO,UAAU,gBAAgB,uCAknBvC"}
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
- import { createDefaultRidgeVentsForSegment, getConicalRoofCoverage, isAutoGutterEnabled, isAutoRidgeVentEnabled, isDefaultRidgeVentNode, normalizeRoofSegmentTrim, ROOF_SHAPE_DEFAULTS, RoofSegmentNode as RoofSegmentNodeSchema, useScene, } from '@pascal-app/core';
4
- import { ActionButton, ActionGroup, PanelSection, PanelWrapper, SegmentedControl, SliderControl, ToggleControl, triggerSFX, useEditor, } from '@pascal-app/editor';
3
+ import { createDefaultRidgeVentsForSegment, getConicalRoofCoverage, isAutoGutterEnabled, isAutoRidgeVentEnabled, isDefaultRidgeVentNode, normalizeRoofSegmentTrim, ROOF_SHAPE_DEFAULTS, useScene, } from '@pascal-app/core';
4
+ import { ActionButton, ActionGroup, duplicateNodeAndPickUp, PanelSection, PanelWrapper, SegmentedControl, SliderControl, ToggleControl, triggerSFX, useEditor, } from '@pascal-app/editor';
5
5
  import { useViewer } from '@pascal-app/viewer';
6
6
  import { Check, Copy, Move, Pencil, RotateCcw, Trash2 } from 'lucide-react';
7
7
  import { useCallback } from 'react';
@@ -146,28 +146,9 @@ export default function RoofSegmentPanel() {
146
146
  }
147
147
  }, [node, setRoofHostDragArmedId, setSelection, updateNode]);
148
148
  const handleDuplicate = useCallback(() => {
149
- if (!node?.parentId)
150
- return;
151
- triggerSFX('sfx:item-pick');
152
- let duplicateInfo = structuredClone(node);
153
- delete duplicateInfo.id;
154
- duplicateInfo.metadata = { ...duplicateInfo.metadata, isNew: true };
155
- // Offset slightly so it's visible
156
- duplicateInfo.position = [
157
- duplicateInfo.position[0] + 1,
158
- duplicateInfo.position[1],
159
- duplicateInfo.position[2] + 1,
160
- ];
161
- try {
162
- const duplicate = RoofSegmentNodeSchema.parse(duplicateInfo);
163
- useScene.getState().createNode(duplicate, duplicate.parentId);
164
- setSelection({ selectedIds: [] });
165
- setMovingNode(duplicate);
166
- }
167
- catch (e) {
168
- console.error('Failed to duplicate roof segment', e);
169
- }
170
- }, [node, setSelection, setMovingNode]);
149
+ if (node)
150
+ duplicateNodeAndPickUp(node);
151
+ }, [node]);
171
152
  const handleMove = useCallback(() => {
172
153
  if (node) {
173
154
  triggerSFX('sfx:item-pick');
@@ -1 +1 @@
1
- {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/roof-segment/renderer.tsx"],"names":[],"mappings":"AAEA,OAAO,EAKL,KAAK,eAAe,EAIrB,MAAM,kBAAkB,CAAA;AAazB,eAAO,MAAM,mBAAmB,GAAI,UAAU;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,gCAsGtE,CAAA;AAED,eAAe,mBAAmB,CAAA"}
1
+ {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/roof-segment/renderer.tsx"],"names":[],"mappings":"AAEA,OAAO,EAKL,KAAK,eAAe,EAIrB,MAAM,kBAAkB,CAAA;AAczB,eAAO,MAAM,mBAAmB,GAAI,UAAU;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,gCAyHtE,CAAA;AAED,eAAe,mBAAmB,CAAA"}
@@ -1,15 +1,22 @@
1
1
  'use client';
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
3
  import { getEffectiveRoofSurfaceMaterial, getEffectiveSegmentSurfaceMaterial, useRegistry, useScene, } from '@pascal-app/core';
4
- import { createMaterial, createMaterialFromPresetRef, getRoofMaterialArray, useNodeEvents, useViewer, } from '@pascal-app/viewer';
5
- import { useEffect, useMemo, useRef } from 'react';
4
+ import { createMaterial, getRoofMaterialArray, levelWallCladdingRef, resolveMaterialRef, useNodeEvents, useViewer, } from '@pascal-app/viewer';
5
+ import { useEffect, useLayoutEffect, useMemo, useRef } from 'react';
6
6
  import * as THREE from 'three';
7
7
  import { getRoofDebugMaterials, getRoofMaterials } from '../roof/roof-materials';
8
8
  import { createPlaceholderGeometry } from '../shared/placeholder-geometry';
9
9
  export const RoofSegmentRenderer = ({ node }) => {
10
10
  const ref = useRef(null);
11
11
  const nodes = useScene((state) => state.nodes);
12
+ const sceneMaterials = useScene((state) => state.materials);
12
13
  useRegistry(node.id, 'roof-segment', ref);
14
+ // The renderer loads lazily, so the scene-load dirty mark can be consumed
15
+ // before this mesh registers. A painted segment is built only from its own
16
+ // mesh (the merged shell skips it), so it would keep its empty placeholder.
17
+ useLayoutEffect(() => {
18
+ useScene.getState().markDirty(node.id);
19
+ }, [node.id]);
13
20
  const handlers = useNodeEvents(node, 'roof-segment');
14
21
  const debugColors = useViewer((s) => s.debugColors);
15
22
  const shading = useViewer((s) => s.shading);
@@ -33,16 +40,16 @@ export const RoofSegmentRenderer = ({ node }) => {
33
40
  // slot 1 → 'wall' (deck top & shingle eave bands)
34
41
  // slot 2 → 'wall' (interior)
35
42
  // slot 3 → 'top' (shingle / roof surface)
43
+ // The gable band is clad like the walls below it (their assemblies).
44
+ const wallCladdingRef = useScene((state) => parentNode ? levelWallCladdingRef(state.nodes, parentNode) : null);
36
45
  // biome-ignore lint/correctness/useExhaustiveDependencies: deps deliberately list the build inputs; depending on the whole object would rebuild on unrelated field changes.
37
46
  const customMaterial = useMemo(() => {
38
47
  const resolveSlot = (role) => {
39
48
  const parentSpec = parentNode ? getEffectiveRoofSurfaceMaterial(parentNode, role) : undefined;
40
49
  const spec = getEffectiveSegmentSurfaceMaterial(node, role, parentSpec);
41
- if (typeof spec.materialPreset === 'string') {
42
- const resolved = createMaterialFromPresetRef(spec.materialPreset, shading);
43
- if (resolved)
44
- return resolved;
45
- }
50
+ const resolved = resolveMaterialRef(spec.materialPreset, sceneMaterials, shading);
51
+ if (resolved)
52
+ return resolved;
46
53
  if (spec.material !== undefined) {
47
54
  return createMaterial(spec.material, shading);
48
55
  }
@@ -51,7 +58,7 @@ export const RoofSegmentRenderer = ({ node }) => {
51
58
  // Themed parent-roof array (per-role scene-theme colours) — used both as the
52
59
  // full fallback and to fill any individual untextured slot below.
53
60
  const themedArray = parentNode
54
- ? getRoofMaterialArray(parentNode, shading, textures, colorPreset, sceneTheme)
61
+ ? getRoofMaterialArray(parentNode, shading, textures, colorPreset, sceneTheme, wallCladdingRef, sceneMaterials)
55
62
  : null;
56
63
  const edge = resolveSlot('edge');
57
64
  const wall = resolveSlot('wall');
@@ -71,10 +78,12 @@ export const RoofSegmentRenderer = ({ node }) => {
71
78
  node.topMaterial,
72
79
  node.topMaterialPreset,
73
80
  node.edgeMaterial,
81
+ wallCladdingRef,
74
82
  node.edgeMaterialPreset,
75
83
  node.wallMaterial,
76
84
  node.wallMaterialPreset,
77
85
  parentNode,
86
+ sceneMaterials,
78
87
  shading,
79
88
  textures,
80
89
  colorPreset,
@@ -0,0 +1,3 @@
1
+ import { type NodeDefinition, SeparatorNode } from '@pascal-app/core';
2
+ export declare const separatorDefinition: NodeDefinition<typeof SeparatorNode>;
3
+ //# sourceMappingURL=definition.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../src/separator/definition.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAErE,eAAO,MAAM,mBAAmB,EAAE,cAAc,CAAC,OAAO,aAAa,CAqCpE,CAAA"}
@@ -0,0 +1,39 @@
1
+ import { SeparatorNode } from '@pascal-app/core';
2
+ export const separatorDefinition = {
3
+ kind: 'separator',
4
+ bake: 'strip',
5
+ schemaVersion: 1,
6
+ schema: SeparatorNode,
7
+ category: 'structure',
8
+ defaults: () => {
9
+ const { id: _id, type: _type, ...rest } = SeparatorNode.parse({ start: [0, 0], end: [1, 0] });
10
+ return rest;
11
+ },
12
+ capabilities: {
13
+ selectable: { hitVolume: 'bbox' },
14
+ duplicable: false,
15
+ deletable: true,
16
+ presettable: false,
17
+ },
18
+ dirtyTracking: false,
19
+ rendersChildren: false,
20
+ renderer: { kind: 'parametric', module: () => import('./renderer') },
21
+ floorplan: (node) => ({
22
+ kind: 'line',
23
+ x1: node.start[0],
24
+ y1: node.start[1],
25
+ x2: node.end[0],
26
+ y2: node.end[1],
27
+ stroke: '#818cf8',
28
+ strokeWidth: 2,
29
+ strokeDasharray: '6 4',
30
+ vectorEffect: 'non-scaling-stroke',
31
+ pointerEvents: 'stroke',
32
+ }),
33
+ presentation: {
34
+ icon: { kind: 'iconify', name: 'lucide:split' },
35
+ label: 'Separator',
36
+ hidden: true,
37
+ actionMenu: false,
38
+ },
39
+ };
@@ -0,0 +1,5 @@
1
+ import { type SeparatorNode } from '@pascal-app/core';
2
+ export default function SeparatorRenderer({ node }: {
3
+ node: SeparatorNode;
4
+ }): import("react").JSX.Element;
5
+ //# sourceMappingURL=renderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/separator/renderer.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,aAAa,EAAyB,MAAM,kBAAkB,CAAA;AAU5E,MAAM,CAAC,OAAO,UAAU,iBAAiB,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,+BAgD1E"}
@@ -0,0 +1,36 @@
1
+ 'use client';
2
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useRegistry, useScene } from '@pascal-app/core';
4
+ import { useEditor } from '@pascal-app/editor';
5
+ import { useNodeEvents, useViewer } from '@pascal-app/viewer';
6
+ import { useEffect, useMemo, useRef } from 'react';
7
+ import { BufferGeometry, Float32BufferAttribute } from 'three';
8
+ import { LineBasicNodeMaterial, MeshBasicNodeMaterial } from 'three/webgpu';
9
+ const separatorMaterial = new LineBasicNodeMaterial({ color: '#818cf8', depthWrite: false });
10
+ const hitMaterial = new MeshBasicNodeMaterial({ transparent: true, opacity: 0, depthWrite: false });
11
+ export default function SeparatorRenderer({ node }) {
12
+ const ref = useRef(null);
13
+ useRegistry(node.id, 'separator', ref);
14
+ const roomId = useEditor((s) => s.room?.zoneId);
15
+ const viewerRoomId = useViewer((s) => s.selection.zoneId);
16
+ const zone = useScene((s) => {
17
+ const id = roomId ?? viewerRoomId;
18
+ return id ? s.nodes[id] : undefined;
19
+ });
20
+ const visible = zone?.type === 'zone' && zone.boundarySeparatorIds.includes(node.id);
21
+ const events = useNodeEvents(node, 'separator');
22
+ const y = zone?.type === 'zone' ? (zone.floor?.elevation ?? 0.05) + 0.02 : 0.07;
23
+ const dx = node.end[0] - node.start[0], dz = node.end[1] - node.start[1];
24
+ const length = Math.hypot(dx, dz);
25
+ const geometry = useMemo(() => {
26
+ const positions = [];
27
+ if (Number.isFinite(length)) {
28
+ for (let distance = 0; distance < length; distance += 0.25) {
29
+ positions.push(distance, 0, 0, Math.min(distance + 0.15, length), 0, 0);
30
+ }
31
+ }
32
+ return new BufferGeometry().setAttribute('position', new Float32BufferAttribute(positions, 3));
33
+ }, [length]);
34
+ useEffect(() => () => geometry.dispose(), [geometry]);
35
+ return (_jsx("group", { ref: ref, visible: visible, children: visible && (_jsxs(_Fragment, { children: [_jsx("lineSegments", { geometry: geometry, material: separatorMaterial, position: [node.start[0], y, node.start[1]], rotation: [0, -Math.atan2(dz, dx), 0], raycast: () => { } }), _jsx("mesh", { ...events, material: hitMaterial, position: [(node.start[0] + node.end[0]) / 2, y, (node.start[1] + node.end[1]) / 2], rotation: [0, -Math.atan2(dz, dx), 0], children: _jsx("boxGeometry", { args: [length, 0.03, 0.1] }) })] })) }));
36
+ }
@@ -1,6 +1,2 @@
1
- import type { SlotDeclaration } from '@pascal-app/core';
2
- export declare const DUCT_BODY_SLOT_ID = "body";
3
- export declare const DUCT_BODY_SLOT_DEFAULT = "#ffffff";
4
- export declare function ductBodySlots(): SlotDeclaration[];
5
1
  export declare const ductBodyPaint: import("@pascal-app/core").PaintCapability;
6
2
  //# sourceMappingURL=duct-body-paint.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"duct-body-paint.d.ts","sourceRoot":"","sources":["../../src/shared/duct-body-paint.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAGvD,eAAO,MAAM,iBAAiB,SAAS,CAAA;AACvC,eAAO,MAAM,sBAAsB,YAAY,CAAA;AAE/C,wBAAgB,aAAa,IAAI,eAAe,EAAE,CAEjD;AAED,eAAO,MAAM,aAAa,4CAMxB,CAAA"}
1
+ {"version":3,"file":"duct-body-paint.d.ts","sourceRoot":"","sources":["../../src/shared/duct-body-paint.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,aAAa,4CAMxB,CAAA"}
@@ -1,9 +1,5 @@
1
+ import { DUCT_BODY_SLOT_ID } from '@pascal-app/core';
1
2
  import { createSlotPaintCapability, previewGeometrySlot } from './slot-paint';
2
- export const DUCT_BODY_SLOT_ID = 'body';
3
- export const DUCT_BODY_SLOT_DEFAULT = '#ffffff';
4
- export function ductBodySlots() {
5
- return [{ slotId: DUCT_BODY_SLOT_ID, label: 'Body', default: DUCT_BODY_SLOT_DEFAULT }];
6
- }
7
3
  export const ductBodyPaint = createSlotPaintCapability({
8
4
  resolveRole: ({ hitObject }) => {
9
5
  const slotId = hitObject?.userData?.slotId;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * The light switch for a single selected item or procedural item. Play/Stop
3
+ * comes from the action menu's `capabilities.mechanism` button.
4
+ */
5
+ export default function ItemInteractionActions(): import("react").JSX.Element | null;
6
+ //# sourceMappingURL=item-interaction-actions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"item-interaction-actions.d.ts","sourceRoot":"","sources":["../../src/shared/item-interaction-actions.tsx"],"names":[],"mappings":"AAOA;;;GAGG;AACH,MAAM,CAAC,OAAO,UAAU,sBAAsB,uCAsB7C"}