@pascal-app/nodes 1.1.0 → 1.1.1

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 (272) hide show
  1. package/README.md +3 -2
  2. package/dist/beam/definition.edit.d.ts.map +1 -1
  3. package/dist/beam/definition.edit.js +0 -2
  4. package/dist/beam/definition.render.d.ts.map +1 -1
  5. package/dist/beam/definition.render.js +2 -0
  6. package/dist/beam/floorplan.d.ts.map +1 -1
  7. package/dist/beam/floorplan.js +1 -2
  8. package/dist/block/definition.edit.d.ts.map +1 -1
  9. package/dist/block/definition.edit.js +0 -2
  10. package/dist/block/definition.render.d.ts.map +1 -1
  11. package/dist/block/definition.render.js +2 -0
  12. package/dist/block/floorplan.d.ts.map +1 -1
  13. package/dist/block/floorplan.js +1 -2
  14. package/dist/box-vent/definition.edit.d.ts.map +1 -1
  15. package/dist/box-vent/definition.edit.js +0 -2
  16. package/dist/box-vent/definition.render.d.ts.map +1 -1
  17. package/dist/box-vent/definition.render.js +2 -0
  18. package/dist/builtin-definitions.d.ts +57 -57
  19. package/dist/builtin-edit-contributions.d.ts +1 -1
  20. package/dist/cabinet/definition.edit.d.ts.map +1 -1
  21. package/dist/cabinet/definition.edit.js +0 -3
  22. package/dist/cabinet/definition.render.d.ts.map +1 -1
  23. package/dist/cabinet/definition.render.js +3 -0
  24. package/dist/cabinet/floorplan.js +1 -1
  25. package/dist/ceiling/definition.edit.d.ts.map +1 -1
  26. package/dist/ceiling/definition.edit.js +0 -2
  27. package/dist/ceiling/definition.render.d.ts.map +1 -1
  28. package/dist/ceiling/definition.render.js +2 -0
  29. package/dist/chimney/definition.edit.d.ts.map +1 -1
  30. package/dist/chimney/definition.edit.js +0 -2
  31. package/dist/chimney/definition.render.d.ts.map +1 -1
  32. package/dist/chimney/definition.render.js +2 -0
  33. package/dist/chimney/panel.js +1 -1
  34. package/dist/column/definition.edit.d.ts.map +1 -1
  35. package/dist/column/definition.edit.js +0 -3
  36. package/dist/column/definition.render.d.ts.map +1 -1
  37. package/dist/column/definition.render.js +3 -0
  38. package/dist/column/floorplan.d.ts.map +1 -1
  39. package/dist/column/floorplan.js +1 -2
  40. package/dist/construction-dimension/definition.edit.d.ts.map +1 -1
  41. package/dist/construction-dimension/definition.edit.js +0 -2
  42. package/dist/construction-dimension/definition.render.d.ts.map +1 -1
  43. package/dist/construction-dimension/definition.render.js +2 -0
  44. package/dist/construction-dimension/floorplan-tool.d.ts.map +1 -1
  45. package/dist/construction-dimension/floorplan-tool.js +2 -2
  46. package/dist/construction-dimension/floorplan.d.ts.map +1 -1
  47. package/dist/construction-dimension/floorplan.js +1 -2
  48. package/dist/cupola/definition.edit.d.ts.map +1 -1
  49. package/dist/cupola/definition.edit.js +0 -2
  50. package/dist/cupola/definition.render.d.ts.map +1 -1
  51. package/dist/cupola/definition.render.js +2 -0
  52. package/dist/definition-contributions.d.ts +1 -1
  53. package/dist/definition-contributions.d.ts.map +1 -1
  54. package/dist/door/definition.edit.d.ts.map +1 -1
  55. package/dist/door/definition.edit.js +1 -6
  56. package/dist/door/definition.render.d.ts.map +1 -1
  57. package/dist/door/definition.render.js +6 -0
  58. package/dist/door/floorplan.d.ts.map +1 -1
  59. package/dist/door/floorplan.js +1 -2
  60. package/dist/dormer/definition.edit.d.ts.map +1 -1
  61. package/dist/dormer/definition.edit.js +0 -2
  62. package/dist/dormer/definition.render.d.ts.map +1 -1
  63. package/dist/dormer/definition.render.js +2 -0
  64. package/dist/dormer/panel-position-section.js +1 -1
  65. package/dist/duct-fitting/definition.edit.d.ts.map +1 -1
  66. package/dist/duct-fitting/definition.edit.js +0 -2
  67. package/dist/duct-fitting/definition.render.d.ts.map +1 -1
  68. package/dist/duct-fitting/definition.render.js +2 -0
  69. package/dist/duct-segment/continuation-handle.d.ts +8 -0
  70. package/dist/duct-segment/continuation-handle.d.ts.map +1 -0
  71. package/dist/duct-segment/continuation-handle.js +36 -0
  72. package/dist/duct-segment/continuation.d.ts +1 -5
  73. package/dist/duct-segment/continuation.d.ts.map +1 -1
  74. package/dist/duct-segment/continuation.js +2 -36
  75. package/dist/duct-segment/definition.edit.d.ts.map +1 -1
  76. package/dist/duct-segment/definition.edit.js +0 -2
  77. package/dist/duct-segment/definition.render.d.ts.map +1 -1
  78. package/dist/duct-segment/definition.render.js +2 -0
  79. package/dist/duct-segment/floorplan.js +1 -1
  80. package/dist/duct-segment/selection.d.ts.map +1 -1
  81. package/dist/duct-segment/selection.js +2 -1
  82. package/dist/duct-segment/tool.d.ts.map +1 -1
  83. package/dist/duct-segment/tool.js +2 -1
  84. package/dist/duct-terminal/definition.edit.d.ts.map +1 -1
  85. package/dist/duct-terminal/definition.edit.js +0 -2
  86. package/dist/duct-terminal/definition.render.d.ts.map +1 -1
  87. package/dist/duct-terminal/definition.render.js +2 -0
  88. package/dist/elevator/definition.edit.d.ts.map +1 -1
  89. package/dist/elevator/definition.edit.js +0 -10
  90. package/dist/elevator/definition.render.d.ts.map +1 -1
  91. package/dist/elevator/definition.render.js +10 -0
  92. package/dist/eyebrow-vent/definition.edit.d.ts.map +1 -1
  93. package/dist/eyebrow-vent/definition.edit.js +0 -2
  94. package/dist/eyebrow-vent/definition.render.d.ts.map +1 -1
  95. package/dist/eyebrow-vent/definition.render.js +2 -0
  96. package/dist/fence/definition.edit.d.ts.map +1 -1
  97. package/dist/fence/definition.edit.js +0 -6
  98. package/dist/fence/definition.render.d.ts.map +1 -1
  99. package/dist/fence/definition.render.js +2 -0
  100. package/dist/fence-feature/definition.edit.d.ts.map +1 -1
  101. package/dist/fence-feature/definition.edit.js +0 -3
  102. package/dist/fence-feature/definition.render.d.ts.map +1 -1
  103. package/dist/fence-feature/definition.render.js +3 -0
  104. package/dist/floor-opening/definition.edit.d.ts.map +1 -1
  105. package/dist/floor-opening/definition.edit.js +1 -3
  106. package/dist/floor-opening/definition.render.d.ts.map +1 -1
  107. package/dist/floor-opening/definition.render.js +3 -0
  108. package/dist/floor-opening/floorplan-affordances.d.ts +150 -0
  109. package/dist/floor-opening/floorplan-affordances.d.ts.map +1 -0
  110. package/dist/floor-opening/floorplan-affordances.js +67 -0
  111. package/dist/floor-opening/floorplan.d.ts +2 -151
  112. package/dist/floor-opening/floorplan.d.ts.map +1 -1
  113. package/dist/floor-opening/floorplan.js +0 -66
  114. package/dist/gutter/definition.edit.d.ts.map +1 -1
  115. package/dist/gutter/definition.edit.js +0 -2
  116. package/dist/gutter/definition.render.d.ts.map +1 -1
  117. package/dist/gutter/definition.render.js +2 -0
  118. package/dist/hvac-equipment/definition.edit.d.ts.map +1 -1
  119. package/dist/hvac-equipment/definition.edit.js +0 -2
  120. package/dist/hvac-equipment/definition.render.d.ts.map +1 -1
  121. package/dist/hvac-equipment/definition.render.js +2 -0
  122. package/dist/imported-mesh/definition.edit.d.ts.map +1 -1
  123. package/dist/imported-mesh/definition.edit.js +0 -2
  124. package/dist/imported-mesh/definition.render.d.ts.map +1 -1
  125. package/dist/imported-mesh/definition.render.js +2 -0
  126. package/dist/item/definition.edit.d.ts.map +1 -1
  127. package/dist/item/definition.edit.js +1 -4
  128. package/dist/item/definition.render.d.ts.map +1 -1
  129. package/dist/item/definition.render.js +4 -0
  130. package/dist/item/floorplan.d.ts.map +1 -1
  131. package/dist/item/floorplan.js +1 -2
  132. package/dist/item/plan-symbols.js +1 -1
  133. package/dist/lean-to-extension/definition.edit.d.ts.map +1 -1
  134. package/dist/lean-to-extension/definition.edit.js +0 -2
  135. package/dist/lean-to-extension/definition.render.d.ts.map +1 -1
  136. package/dist/lean-to-extension/definition.render.js +2 -0
  137. package/dist/lineset/definition.edit.d.ts.map +1 -1
  138. package/dist/lineset/definition.edit.js +0 -2
  139. package/dist/lineset/definition.render.d.ts.map +1 -1
  140. package/dist/lineset/definition.render.js +2 -0
  141. package/dist/liquid-line/definition.edit.d.ts.map +1 -1
  142. package/dist/liquid-line/definition.edit.js +0 -2
  143. package/dist/liquid-line/definition.render.d.ts.map +1 -1
  144. package/dist/liquid-line/definition.render.js +2 -0
  145. package/dist/measurement/definition.edit.d.ts.map +1 -1
  146. package/dist/measurement/definition.edit.js +0 -2
  147. package/dist/measurement/definition.render.d.ts.map +1 -1
  148. package/dist/measurement/definition.render.js +2 -0
  149. package/dist/measurement/floorplan.d.ts.map +1 -1
  150. package/dist/measurement/floorplan.js +2 -3
  151. package/dist/pipe-fitting/definition.edit.d.ts.map +1 -1
  152. package/dist/pipe-fitting/definition.edit.js +0 -2
  153. package/dist/pipe-fitting/definition.render.d.ts.map +1 -1
  154. package/dist/pipe-fitting/definition.render.js +2 -0
  155. package/dist/pipe-segment/continuation-handle.d.ts +9 -0
  156. package/dist/pipe-segment/continuation-handle.d.ts.map +1 -0
  157. package/dist/pipe-segment/continuation-handle.js +35 -0
  158. package/dist/pipe-segment/continuation.d.ts +1 -5
  159. package/dist/pipe-segment/continuation.d.ts.map +1 -1
  160. package/dist/pipe-segment/continuation.js +2 -35
  161. package/dist/pipe-segment/definition.edit.d.ts.map +1 -1
  162. package/dist/pipe-segment/definition.edit.js +0 -2
  163. package/dist/pipe-segment/definition.render.d.ts.map +1 -1
  164. package/dist/pipe-segment/definition.render.js +2 -0
  165. package/dist/pipe-segment/floorplan.js +1 -1
  166. package/dist/pipe-segment/selection.d.ts.map +1 -1
  167. package/dist/pipe-segment/selection.js +2 -1
  168. package/dist/pipe-segment/tool.d.ts.map +1 -1
  169. package/dist/pipe-segment/tool.js +2 -1
  170. package/dist/pipe-trap/definition.edit.d.ts.map +1 -1
  171. package/dist/pipe-trap/definition.edit.js +0 -2
  172. package/dist/pipe-trap/definition.render.d.ts.map +1 -1
  173. package/dist/pipe-trap/definition.render.js +2 -0
  174. package/dist/procedural-item/definition.edit.d.ts.map +1 -1
  175. package/dist/procedural-item/definition.edit.js +1 -54
  176. package/dist/procedural-item/definition.render.d.ts.map +1 -1
  177. package/dist/procedural-item/definition.render.js +55 -2
  178. package/dist/ridge-vent/definition.edit.d.ts.map +1 -1
  179. package/dist/ridge-vent/definition.edit.js +0 -2
  180. package/dist/ridge-vent/definition.render.d.ts.map +1 -1
  181. package/dist/ridge-vent/definition.render.js +2 -0
  182. package/dist/roof/definition.d.ts +1 -1
  183. package/dist/roof/definition.edit.d.ts.map +1 -1
  184. package/dist/roof/definition.edit.js +0 -2
  185. package/dist/roof/definition.render.d.ts.map +1 -1
  186. package/dist/roof/definition.render.js +16 -5
  187. package/dist/roof/floorplan.d.ts.map +1 -1
  188. package/dist/roof/floorplan.js +1 -2
  189. package/dist/roof/renderer.d.ts.map +1 -1
  190. package/dist/roof/renderer.js +10 -5
  191. package/dist/roof-segment/definition.edit.d.ts.map +1 -1
  192. package/dist/roof-segment/definition.edit.js +0 -2
  193. package/dist/roof-segment/definition.render.d.ts.map +1 -1
  194. package/dist/roof-segment/definition.render.js +2 -0
  195. package/dist/separator/definition.edit.d.ts.map +1 -1
  196. package/dist/separator/definition.edit.js +0 -2
  197. package/dist/separator/definition.render.d.ts.map +1 -1
  198. package/dist/separator/definition.render.js +2 -0
  199. package/dist/separator/floorplan.js +1 -1
  200. package/dist/shared/opening-documentation.d.ts +1 -1
  201. package/dist/shared/opening-documentation.d.ts.map +1 -1
  202. package/dist/shared/opening-documentation.js +1 -2
  203. package/dist/shared/opening-placement-dimensions.d.ts.map +1 -1
  204. package/dist/shared/opening-placement-dimensions.js +1 -2
  205. package/dist/shelf/definition.edit.d.ts.map +1 -1
  206. package/dist/shelf/definition.edit.js +0 -2
  207. package/dist/shelf/definition.render.d.ts.map +1 -1
  208. package/dist/shelf/definition.render.js +2 -0
  209. package/dist/skylight/definition.edit.d.ts.map +1 -1
  210. package/dist/skylight/definition.edit.js +0 -2
  211. package/dist/skylight/definition.render.d.ts.map +1 -1
  212. package/dist/skylight/definition.render.js +2 -0
  213. package/dist/skylight/panel.js +1 -1
  214. package/dist/slab/definition.edit.d.ts.map +1 -1
  215. package/dist/slab/definition.edit.js +0 -4
  216. package/dist/slab/definition.render.d.ts.map +1 -1
  217. package/dist/slab/definition.render.js +4 -0
  218. package/dist/slab/floorplan.d.ts.map +1 -1
  219. package/dist/slab/floorplan.js +1 -2
  220. package/dist/solar-panel/definition.edit.d.ts.map +1 -1
  221. package/dist/solar-panel/definition.edit.js +0 -2
  222. package/dist/solar-panel/definition.render.d.ts.map +1 -1
  223. package/dist/solar-panel/definition.render.js +2 -0
  224. package/dist/spawn/definition.edit.d.ts.map +1 -1
  225. package/dist/spawn/definition.edit.js +0 -9
  226. package/dist/spawn/definition.render.d.ts.map +1 -1
  227. package/dist/spawn/definition.render.js +2 -0
  228. package/dist/stair/definition.edit.d.ts.map +1 -1
  229. package/dist/stair/definition.edit.js +0 -13
  230. package/dist/stair/definition.render.d.ts.map +1 -1
  231. package/dist/stair/definition.render.js +10 -0
  232. package/dist/stair/documentation.d.ts.map +1 -1
  233. package/dist/stair/documentation.js +1 -2
  234. package/dist/stair/floorplan.d.ts.map +1 -1
  235. package/dist/stair/floorplan.js +1 -2
  236. package/dist/stair/plan-entry.d.ts.map +1 -1
  237. package/dist/stair/plan-entry.js +1 -2
  238. package/dist/structural-grid/definition.edit.d.ts.map +1 -1
  239. package/dist/structural-grid/definition.edit.js +0 -2
  240. package/dist/structural-grid/definition.render.d.ts.map +1 -1
  241. package/dist/structural-grid/definition.render.js +2 -0
  242. package/dist/structural-grid/floorplan.js +1 -1
  243. package/dist/turbine-vent/definition.edit.d.ts.map +1 -1
  244. package/dist/turbine-vent/definition.edit.js +0 -2
  245. package/dist/turbine-vent/definition.render.d.ts.map +1 -1
  246. package/dist/turbine-vent/definition.render.js +2 -0
  247. package/dist/wall/contextual-dimensions.d.ts.map +1 -1
  248. package/dist/wall/contextual-dimensions.js +1 -2
  249. package/dist/wall/definition.edit.d.ts.map +1 -1
  250. package/dist/wall/definition.edit.js +0 -5
  251. package/dist/wall/definition.render.d.ts.map +1 -1
  252. package/dist/wall/definition.render.js +5 -0
  253. package/dist/wall/floorplan.d.ts.map +1 -1
  254. package/dist/wall/floorplan.js +1 -2
  255. package/dist/window/definition.edit.d.ts.map +1 -1
  256. package/dist/window/definition.edit.js +1 -6
  257. package/dist/window/definition.render.d.ts.map +1 -1
  258. package/dist/window/definition.render.js +6 -0
  259. package/dist/window/floorplan.d.ts.map +1 -1
  260. package/dist/window/floorplan.js +1 -2
  261. package/dist/zone/definition.edit.d.ts.map +1 -1
  262. package/dist/zone/definition.edit.js +0 -2
  263. package/dist/zone/definition.render.d.ts.map +1 -1
  264. package/dist/zone/definition.render.js +2 -0
  265. package/dist/zone/floorplan.d.ts.map +1 -1
  266. package/dist/zone/floorplan.js +1 -2
  267. package/dist/zone/room-clear-dimensions.d.ts.map +1 -1
  268. package/dist/zone/room-clear-dimensions.js +1 -2
  269. package/dist/zone/room-documentation.d.ts +1 -2
  270. package/dist/zone/room-documentation.d.ts.map +1 -1
  271. package/dist/zone/room-documentation.js +1 -1
  272. package/package.json +8 -8
@@ -1 +1 @@
1
- {"version":3,"file":"definition.edit.d.ts","sourceRoot":"","sources":["../../src/lean-to-extension/definition.edit.ts"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAA;AAuZnD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AACvE,eAAO,MAAM,+BAA+B,EAAE,oBAAoB,CAAC,OAAO,mBAAmB,CA8B5F,CAAA"}
1
+ {"version":3,"file":"definition.edit.d.ts","sourceRoot":"","sources":["../../src/lean-to-extension/definition.edit.ts"],"names":[],"mappings":"AA2BA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAA;AAuZnD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AACvE,eAAO,MAAM,+BAA+B,EAAE,oBAAoB,CAAC,OAAO,mBAAmB,CA6B5F,CAAA"}
@@ -1,6 +1,5 @@
1
1
  import { findLevelAncestorId, } from '@pascal-app/core';
2
2
  import { clearStructuralElevationGuide, publishResolvedElevationGuide, } from '@pascal-app/editor';
3
- import { buildLeanToExtensionFloorplan } from './floorplan.js';
4
3
  import { leanToResizeAffordance, leanToRotateAffordance } from './floorplan-affordances.js';
5
4
  import { leanToFloorplanMoveTarget } from './floorplan-move.js';
6
5
  import { leanToWallLocalPose, resolveLeanToEdgeSnapTargets, resolveLeanToHighEdgeHeightSnap, resolveLeanToLayout, resolveLeanToSpanResizeProposal, } from './layout.js';
@@ -371,7 +370,6 @@ export const leanToExtensionEditContribution = {
371
370
  },
372
371
  parametrics: leanToExtensionParametrics,
373
372
  handles: leanToExtensionHandles,
374
- floorplan: buildLeanToExtensionFloorplan,
375
373
  floorplanMoveTarget: leanToFloorplanMoveTarget,
376
374
  floorplanAffordances: {
377
375
  'lean-to-resize': leanToResizeAffordance,
@@ -1 +1 @@
1
- {"version":3,"file":"definition.render.d.ts","sourceRoot":"","sources":["../../src/lean-to-extension/definition.render.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAEvE,OAAO,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAA;AAE9C,eAAO,MAAM,+BAA+B,EAAE,oBAAoB,CAAC,OAAO,mBAAmB,CAAC,GAAG;IAC/F,IAAI,EAAE,mBAAmB,CAAA;CA6C1B,CAAA"}
1
+ {"version":3,"file":"definition.render.d.ts","sourceRoot":"","sources":["../../src/lean-to-extension/definition.render.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAGvE,OAAO,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAA;AAE9C,eAAO,MAAM,+BAA+B,EAAE,oBAAoB,CAAC,OAAO,mBAAmB,CAAC,GAAG;IAC/F,IAAI,EAAE,mBAAmB,CAAA;CA8C1B,CAAA"}
@@ -1,4 +1,5 @@
1
1
  import { leanToSlots } from '@pascal-app/core';
2
+ import { buildLeanToExtensionFloorplan } from './floorplan.js';
2
3
  import { buildLeanToExtensionGeometry, leanToExtensionGeometryKey } from './geometry.js';
3
4
  import { LeanToExtensionNode } from './schema.js';
4
5
  export const leanToExtensionRenderDefinition = {
@@ -32,6 +33,7 @@ export const leanToExtensionRenderDefinition = {
32
33
  module: () => import('./system.js'),
33
34
  priority: 1,
34
35
  },
36
+ floorplan: buildLeanToExtensionFloorplan,
35
37
  presentation: {
36
38
  label: 'Canopy',
37
39
  description: 'An attached mono-pitch or freestanding mono, gable, or butterfly canopy with managed structure and drainage.',
@@ -1 +1 @@
1
- {"version":3,"file":"definition.edit.d.ts","sourceRoot":"","sources":["../../src/lineset/definition.edit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAIvE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAE3C,eAAO,MAAM,uBAAuB,EAAE,oBAAoB,CAAC,OAAO,WAAW,CAkC5E,CAAA"}
1
+ {"version":3,"file":"definition.edit.d.ts","sourceRoot":"","sources":["../../src/lineset/definition.edit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAGvE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAE3C,eAAO,MAAM,uBAAuB,EAAE,oBAAoB,CAAC,OAAO,WAAW,CAiC5E,CAAA"}
@@ -1,5 +1,4 @@
1
1
  import { createPathPointMoveAffordance } from '../shared/path-point-affordance.js';
2
- import { buildLinesetFloorplan } from './floorplan.js';
3
2
  import { linesetParametrics } from './parametrics.js';
4
3
  export const linesetEditContribution = {
5
4
  drafting: { cancelOnHistoryJump: true },
@@ -8,7 +7,6 @@ export const linesetEditContribution = {
8
7
  // lock available as a cyclable mode.
9
8
  snapProfile: 'structural',
10
9
  parametrics: linesetParametrics,
11
- floorplan: buildLinesetFloorplan,
12
10
  // 2D selection-time path-point handles — the floor-plan twin of the 3D
13
11
  // `affordanceTools.selection` handles. The builder emits an
14
12
  // `endpoint-handle` per path vertex; this drags the matching point.
@@ -1 +1 @@
1
- {"version":3,"file":"definition.render.d.ts","sourceRoot":"","sources":["../../src/lineset/definition.render.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAEvE,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAEtC,eAAO,MAAM,uBAAuB,EAAE,oBAAoB,CAAC,OAAO,WAAW,CAAC,GAAG;IAC/E,IAAI,EAAE,SAAS,CAAA;CA0EhB,CAAA"}
1
+ {"version":3,"file":"definition.render.d.ts","sourceRoot":"","sources":["../../src/lineset/definition.render.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAGvE,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAEtC,eAAO,MAAM,uBAAuB,EAAE,oBAAoB,CAAC,OAAO,WAAW,CAAC,GAAG;IAC/E,IAAI,EAAE,SAAS,CAAA;CA2EhB,CAAA"}
@@ -1,3 +1,4 @@
1
+ import { buildLinesetFloorplan } from './floorplan.js';
1
2
  import { buildLinesetGeometry } from './geometry.js';
2
3
  import { LinesetNode } from './schema.js';
3
4
  export const linesetRenderDefinition = {
@@ -59,6 +60,7 @@ export const linesetRenderDefinition = {
59
60
  },
60
61
  ];
61
62
  },
63
+ floorplan: buildLinesetFloorplan,
62
64
  presentation: {
63
65
  label: 'Lineset',
64
66
  description: 'Refrigerant lineset — copper suction + liquid pair joining a condenser to the indoor coil.',
@@ -1 +1 @@
1
- {"version":3,"file":"definition.edit.d.ts","sourceRoot":"","sources":["../../src/liquid-line/definition.edit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAIvE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAE9C,eAAO,MAAM,0BAA0B,EAAE,oBAAoB,CAAC,OAAO,cAAc,CA2BlF,CAAA"}
1
+ {"version":3,"file":"definition.edit.d.ts","sourceRoot":"","sources":["../../src/liquid-line/definition.edit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAGvE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAE9C,eAAO,MAAM,0BAA0B,EAAE,oBAAoB,CAAC,OAAO,cAAc,CA0BlF,CAAA"}
@@ -1,5 +1,4 @@
1
1
  import { createPathPointMoveAffordance } from '../shared/path-point-affordance.js';
2
- import { buildLiquidLineFloorplan } from './floorplan.js';
3
2
  import { liquidLineParametrics } from './parametrics.js';
4
3
  export const liquidLineEditContribution = {
5
4
  drafting: { cancelOnHistoryJump: true },
@@ -8,7 +7,6 @@ export const liquidLineEditContribution = {
8
7
  // lock available as a cyclable mode.
9
8
  snapProfile: 'structural',
10
9
  parametrics: liquidLineParametrics,
11
- floorplan: buildLiquidLineFloorplan,
12
10
  // 2D selection-time path-point handles — the floor-plan twin of the 3D
13
11
  // `affordanceTools.selection` handles.
14
12
  floorplanAffordances: {
@@ -1 +1 @@
1
- {"version":3,"file":"definition.render.d.ts","sourceRoot":"","sources":["../../src/liquid-line/definition.render.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAEvE,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAEzC,eAAO,MAAM,0BAA0B,EAAE,oBAAoB,CAAC,OAAO,cAAc,CAAC,GAAG;IACrF,IAAI,EAAE,aAAa,CAAA;CAwEpB,CAAA"}
1
+ {"version":3,"file":"definition.render.d.ts","sourceRoot":"","sources":["../../src/liquid-line/definition.render.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAGvE,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAEzC,eAAO,MAAM,0BAA0B,EAAE,oBAAoB,CAAC,OAAO,cAAc,CAAC,GAAG;IACrF,IAAI,EAAE,aAAa,CAAA;CAyEpB,CAAA"}
@@ -1,3 +1,4 @@
1
+ import { buildLiquidLineFloorplan } from './floorplan.js';
1
2
  import { buildLiquidLineGeometry } from './geometry.js';
2
3
  import { LiquidLineNode } from './schema.js';
3
4
  export const liquidLineRenderDefinition = {
@@ -57,6 +58,7 @@ export const liquidLineRenderDefinition = {
57
58
  },
58
59
  ];
59
60
  },
61
+ floorplan: buildLiquidLineFloorplan,
60
62
  presentation: {
61
63
  label: 'Liquid Line',
62
64
  description: 'Standalone refrigerant liquid line — a thin bare-copper run; Follow mode traces an existing lineset.',
@@ -1 +1 @@
1
- {"version":3,"file":"definition.edit.d.ts","sourceRoot":"","sources":["../../src/measurement/definition.edit.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAGvE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAE/C,eAAO,MAAM,2BAA2B,EAAE,oBAAoB,CAAC,OAAO,eAAe,CAsBpF,CAAA"}
1
+ {"version":3,"file":"definition.edit.d.ts","sourceRoot":"","sources":["../../src/measurement/definition.edit.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAEvE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAE/C,eAAO,MAAM,2BAA2B,EAAE,oBAAoB,CAAC,OAAO,eAAe,CAqBpF,CAAA"}
@@ -1,9 +1,7 @@
1
1
  import { measurementReferenceNodeIds } from '@pascal-app/core';
2
- import { buildMeasurementFloorplan } from './floorplan.js';
3
2
  import { measurementMoveVertexAffordance } from './floorplan-affordance.js';
4
3
  export const measurementEditContribution = {
5
4
  snapProfile: 'structural',
6
- floorplan: buildMeasurementFloorplan,
7
5
  floorplanDependencies: (node) => measurementReferenceNodeIds(node.measurement),
8
6
  extensions: {
9
7
  'pascal:editor/floorplan': {
@@ -1 +1 @@
1
- {"version":3,"file":"definition.render.d.ts","sourceRoot":"","sources":["../../src/measurement/definition.render.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AACvE,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAE1C,eAAO,MAAM,2BAA2B,EAAE,oBAAoB,CAAC,OAAO,eAAe,CAAC,GAAG;IACvF,IAAI,EAAE,aAAa,CAAA;CA2CpB,CAAA"}
1
+ {"version":3,"file":"definition.render.d.ts","sourceRoot":"","sources":["../../src/measurement/definition.render.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAEvE,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAE1C,eAAO,MAAM,2BAA2B,EAAE,oBAAoB,CAAC,OAAO,eAAe,CAAC,GAAG;IACvF,IAAI,EAAE,aAAa,CAAA;CA4CpB,CAAA"}
@@ -1,3 +1,4 @@
1
+ import { buildMeasurementFloorplan } from './floorplan.js';
1
2
  import { MeasurementNode } from './schema.js';
2
3
  export const measurementRenderDefinition = {
3
4
  kind: 'measurement',
@@ -30,6 +31,7 @@ export const measurementRenderDefinition = {
30
31
  kind: 'parametric',
31
32
  module: () => import('./renderer.js'),
32
33
  },
34
+ floorplan: buildMeasurementFloorplan,
33
35
  presentation: {
34
36
  label: 'Measurement',
35
37
  description: 'A persistent distance, angle, area, perimeter, or volume annotation.',
@@ -1 +1 @@
1
- {"version":3,"file":"floorplan.d.ts","sourceRoot":"","sources":["../../src/measurement/floorplan.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,iBAAiB,EAOtB,KAAK,eAAe,EACpB,KAAK,eAAe,EAOrB,MAAM,kBAAkB,CAAA;AA0BzB,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,eAAe,EACrB,GAAG,EAAE,eAAe,GACnB,iBAAiB,GAAG,IAAI,CA4M1B"}
1
+ {"version":3,"file":"floorplan.d.ts","sourceRoot":"","sources":["../../src/measurement/floorplan.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,iBAAiB,EAOtB,KAAK,eAAe,EACpB,KAAK,eAAe,EASrB,MAAM,kBAAkB,CAAA;AAwBzB,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,eAAe,EACrB,GAAG,EAAE,eAAe,GACnB,iBAAiB,GAAG,IAAI,CA4M1B"}
@@ -1,6 +1,5 @@
1
- import { buildMeasurementAngleArcPoints, formatAngleRadians, formatAreaLabel, formatLinearMeasurement, formatVolumeLabel, measurementAngle, measurementArea, measurementDistance, measurementPerimeter, measurementPrismVolume, } from '@pascal-app/core';
2
- import { measurementFloorplanPresentationColor, readFloorplanContext, withFloorplanGeometryMetadata, } from '@pascal-app/editor';
3
- import { measurementPolygonLabelAnchor } from '@pascal-app/viewer';
1
+ import { buildMeasurementAngleArcPoints, formatAngleRadians, formatAreaLabel, formatLinearMeasurement, formatVolumeLabel, measurementAngle, measurementArea, measurementDistance, measurementPerimeter, measurementPrismVolume, readFloorplanContext, withFloorplanGeometryMetadata, } from '@pascal-app/core';
2
+ import { measurementFloorplanPresentationColor, measurementPolygonLabelAnchor, } from '@pascal-app/viewer';
4
3
  import { measurementResolvedEditPoints } from './edit.js';
5
4
  import { resolveMeasurementNode } from './resolve.js';
6
5
  const projectPoint = (point) => [point[0], point[2]];
@@ -1 +1 @@
1
- {"version":3,"file":"definition.edit.d.ts","sourceRoot":"","sources":["../../src/pipe-fitting/definition.edit.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAMvE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAE/C,eAAO,MAAM,2BAA2B,EAAE,oBAAoB,CAAC,OAAO,eAAe,CA0CpF,CAAA"}
1
+ {"version":3,"file":"definition.edit.d.ts","sourceRoot":"","sources":["../../src/pipe-fitting/definition.edit.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAKvE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAE/C,eAAO,MAAM,2BAA2B,EAAE,oBAAoB,CAAC,OAAO,eAAe,CAyCpF,CAAA"}
@@ -2,12 +2,10 @@ import { useScene } from '@pascal-app/core';
2
2
  import { getRotationAxis, rotateEulerWorld } from '../shared/fitting-rotation.js';
3
3
  import { pipeFittingToolOptions } from '../shared/fitting-tool-options.js';
4
4
  import { pipeFittingQuickActions } from '../shared/mep-fitting-actions.js';
5
- import { buildPipeFittingFloorplan } from './floorplan.js';
6
5
  import { pipeFittingParametrics } from './parametrics.js';
7
6
  export const pipeFittingEditContribution = {
8
7
  snapProfile: 'item',
9
8
  parametrics: pipeFittingParametrics,
10
- floorplan: buildPipeFittingFloorplan,
11
9
  quickActions: pipeFittingQuickActions,
12
10
  quickActionNodeScope: 'level',
13
11
  // R/T rotate a selected fitting ±45° around the shared active axis —
@@ -1 +1 @@
1
- {"version":3,"file":"definition.render.d.ts","sourceRoot":"","sources":["../../src/pipe-fitting/definition.render.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAGvE,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAE1C,eAAO,MAAM,2BAA2B,EAAE,oBAAoB,CAAC,OAAO,eAAe,CAAC,GAAG;IACvF,IAAI,EAAE,cAAc,CAAA;CAqDrB,CAAA"}
1
+ {"version":3,"file":"definition.render.d.ts","sourceRoot":"","sources":["../../src/pipe-fitting/definition.render.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAIvE,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAE1C,eAAO,MAAM,2BAA2B,EAAE,oBAAoB,CAAC,OAAO,eAAe,CAAC,GAAG;IACvF,IAAI,EAAE,cAAc,CAAA;CAsDrB,CAAA"}
@@ -1,3 +1,4 @@
1
+ import { buildPipeFittingFloorplan } from './floorplan.js';
1
2
  import { buildPipeFittingGeometry } from './geometry.js';
2
3
  import { getPipeFittingPorts } from './ports.js';
3
4
  import { PipeFittingNode } from './schema.js';
@@ -39,6 +40,7 @@ export const pipeFittingRenderDefinition = {
39
40
  n.system,
40
41
  ]),
41
42
  ports: getPipeFittingPorts,
43
+ floorplan: buildPipeFittingFloorplan,
42
44
  presentation: {
43
45
  label: 'Pipe Fitting',
44
46
  description: 'DWV joint — elbow bend, 45° wye, or sanitary tee.',
@@ -0,0 +1,9 @@
1
+ import type { AnyNode } from '@pascal-app/core';
2
+ import type { ScenePort } from '@pascal-app/editor/distribution';
3
+ import { type RunContinuationHandlePlan } from '../shared/elbow-branch-continuation.js';
4
+ import type { PipeSegmentNode } from './schema.js';
5
+ export type PipeEndpoint = 'start' | 'end';
6
+ export declare function pipeEndpointPort(pipe: PipeSegmentNode, endpoint: PipeEndpoint): ScenePort | null;
7
+ export declare function pipeContinuationHandlePoint(pipe: PipeSegmentNode, endpoint: PipeEndpoint, gap?: number): [number, number, number] | null;
8
+ export declare function pipeContinuationHandlePlan(pipe: PipeSegmentNode, endpoint: PipeEndpoint, nodes: Readonly<Record<string, AnyNode>>, gap?: number): RunContinuationHandlePlan | null;
9
+ //# sourceMappingURL=continuation-handle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"continuation-handle.d.ts","sourceRoot":"","sources":["../../src/pipe-segment/continuation-handle.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AAC/C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAA;AAChE,OAAO,EACL,KAAK,yBAAyB,EAE/B,MAAM,qCAAqC,CAAA;AAC5C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAE/C,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,KAAK,CAAA;AAE1C,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,eAAe,EAAE,QAAQ,EAAE,YAAY,GAAG,SAAS,GAAG,IAAI,CAkBhG;AAED,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,eAAe,EACrB,QAAQ,EAAE,YAAY,EACtB,GAAG,SAAO,GACT,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAQjC;AAED,wBAAgB,0BAA0B,CACxC,IAAI,EAAE,eAAe,EACrB,QAAQ,EAAE,YAAY,EACtB,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACxC,GAAG,SAAO,GACT,yBAAyB,GAAG,IAAI,CAGlC"}
@@ -0,0 +1,35 @@
1
+ import { resolvePipeContinuationHandle, } from '../shared/elbow-branch-continuation.js';
2
+ export function pipeEndpointPort(pipe, endpoint) {
3
+ if (pipe.path.length < 2)
4
+ return null;
5
+ const index = endpoint === 'start' ? 0 : pipe.path.length - 1;
6
+ const neighborIndex = endpoint === 'start' ? 1 : pipe.path.length - 2;
7
+ const position = pipe.path[index];
8
+ const neighbor = pipe.path[neighborIndex];
9
+ const dx = position[0] - neighbor[0];
10
+ const dy = position[1] - neighbor[1];
11
+ const dz = position[2] - neighbor[2];
12
+ const length = Math.hypot(dx, dy, dz);
13
+ return {
14
+ id: endpoint,
15
+ nodeId: pipe.id,
16
+ position,
17
+ direction: length < 1e-9 ? [1, 0, 0] : [dx / length, dy / length, dz / length],
18
+ diameter: pipe.diameter,
19
+ system: pipe.system,
20
+ };
21
+ }
22
+ export function pipeContinuationHandlePoint(pipe, endpoint, gap = 0.28) {
23
+ const port = pipeEndpointPort(pipe, endpoint);
24
+ if (!port)
25
+ return null;
26
+ return [
27
+ port.position[0] + port.direction[0] * gap,
28
+ port.position[1] + port.direction[1] * gap,
29
+ port.position[2] + port.direction[2] * gap,
30
+ ];
31
+ }
32
+ export function pipeContinuationHandlePlan(pipe, endpoint, nodes, gap = 0.28) {
33
+ const port = pipeEndpointPort(pipe, endpoint);
34
+ return port ? resolvePipeContinuationHandle(port, nodes, gap) : null;
35
+ }
@@ -1,18 +1,14 @@
1
1
  import { type AnyNode, type AnyNodeId, type FloorplanAffordance, type NodePort } from '@pascal-app/core';
2
2
  import type { RunBodyHit, ScenePort } from '@pascal-app/editor/distribution';
3
3
  import type { PipeFittingNode } from '../pipe-fitting/schema.js';
4
- import { type RunContinuationHandlePlan } from '../shared/elbow-branch-continuation.js';
4
+ import { type PipeEndpoint } from './continuation-handle.js';
5
5
  import { PipeSegmentNode } from './schema.js';
6
- export type PipeEndpoint = 'start' | 'end';
7
6
  export type PipeContinuationSeed = {
8
7
  pipe: PipeSegmentNode;
9
8
  port: ScenePort | null;
10
9
  body: RunBodyHit | null;
11
10
  promotedFitting?: PipeFittingNode;
12
11
  };
13
- export declare function pipeEndpointPort(pipe: PipeSegmentNode, endpoint: PipeEndpoint): ScenePort | null;
14
- export declare function pipeContinuationHandlePoint(pipe: PipeSegmentNode, endpoint: PipeEndpoint, gap?: number): [number, number, number] | null;
15
- export declare function pipeContinuationHandlePlan(pipe: PipeSegmentNode, endpoint: PipeEndpoint, nodes: Readonly<Record<string, AnyNode>>, gap?: number): RunContinuationHandlePlan | null;
16
12
  export declare function resolvePipeContinuationSeed(defaults: unknown, nodes: Record<string, AnyNode>): PipeContinuationSeed | null;
17
13
  export declare function activatePipeBranch(pipe: PipeSegmentNode, segmentIndex: number, point: [number, number, number]): void;
18
14
  export declare function activatePipeContinuation(pipe: PipeSegmentNode, endpoint: PipeEndpoint, fittingId?: AnyNodeId): void;
@@ -1 +1 @@
1
- {"version":3,"file":"continuation.d.ts","sourceRoot":"","sources":["../../src/pipe-segment/continuation.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,OAAO,EACZ,KAAK,SAAS,EACd,KAAK,mBAAmB,EACxB,KAAK,QAAQ,EAEd,MAAM,kBAAkB,CAAA;AAEzB,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAA;AAE5E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AAC7D,OAAO,EAIL,KAAK,yBAAyB,EAE/B,MAAM,qCAAqC,CAAA;AAE5C,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAG1C,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,KAAK,CAAA;AAE1C,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,EAAE,eAAe,CAAA;IACrB,IAAI,EAAE,SAAS,GAAG,IAAI,CAAA;IACtB,IAAI,EAAE,UAAU,GAAG,IAAI,CAAA;IACvB,eAAe,CAAC,EAAE,eAAe,CAAA;CAClC,CAAA;AAaD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,eAAe,EAAE,QAAQ,EAAE,YAAY,GAAG,SAAS,GAAG,IAAI,CAkBhG;AAED,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,eAAe,EACrB,QAAQ,EAAE,YAAY,EACtB,GAAG,SAAO,GACT,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAQjC;AAED,wBAAgB,0BAA0B,CACxC,IAAI,EAAE,eAAe,EACrB,QAAQ,EAAE,YAAY,EACtB,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACxC,GAAG,SAAO,GACT,yBAAyB,GAAG,IAAI,CAGlC;AAED,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,OAAO,EACjB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,oBAAoB,GAAG,IAAI,CA8D7B;AAED,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,eAAe,EACrB,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,GAC9B,IAAI,CAWN;AAED,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,eAAe,EACrB,QAAQ,EAAE,YAAY,EACtB,SAAS,CAAC,EAAE,SAAS,GACpB,IAAI,CAuBN;AAED,wBAAgB,8BAA8B,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,GAAG,IAAI,CAwBlF;AAED,eAAO,MAAM,0BAA0B,EAAE,mBAAmB,CAAC,eAAe,CAiB3E,CAAA;AAED,eAAO,MAAM,oBAAoB,EAAE,mBAAmB,CAAC,eAAe,CAiBrE,CAAA;AAED,wBAAgB,2BAA2B,IAAI,oBAAoB,GAAG,IAAI,CAKzE"}
1
+ {"version":3,"file":"continuation.d.ts","sourceRoot":"","sources":["../../src/pipe-segment/continuation.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,OAAO,EACZ,KAAK,SAAS,EACd,KAAK,mBAAmB,EACxB,KAAK,QAAQ,EAEd,MAAM,kBAAkB,CAAA;AAEzB,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAA;AAE5E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AAO7D,OAAO,EAAE,KAAK,YAAY,EAAoB,MAAM,uBAAuB,CAAA;AAC3E,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAG1C,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,EAAE,eAAe,CAAA;IACrB,IAAI,EAAE,SAAS,GAAG,IAAI,CAAA;IACtB,IAAI,EAAE,UAAU,GAAG,IAAI,CAAA;IACvB,eAAe,CAAC,EAAE,eAAe,CAAA;CAClC,CAAA;AAaD,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,OAAO,EACjB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,oBAAoB,GAAG,IAAI,CA8D7B;AAED,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,eAAe,EACrB,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,GAC9B,IAAI,CAWN;AAED,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,eAAe,EACrB,QAAQ,EAAE,YAAY,EACtB,SAAS,CAAC,EAAE,SAAS,GACpB,IAAI,CAuBN;AAED,wBAAgB,8BAA8B,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,GAAG,IAAI,CAwBlF;AAED,eAAO,MAAM,0BAA0B,EAAE,mBAAmB,CAAC,eAAe,CAiB3E,CAAA;AAED,eAAO,MAAM,oBAAoB,EAAE,mBAAmB,CAAC,eAAe,CAiBrE,CAAA;AAED,wBAAgB,2BAA2B,IAAI,oBAAoB,GAAG,IAAI,CAKzE"}
@@ -1,44 +1,11 @@
1
1
  import { useScene, } from '@pascal-app/core';
2
2
  import { useEditor } from '@pascal-app/editor';
3
3
  import { useViewer } from '@pascal-app/viewer';
4
- import { findMatedScenePorts, planPipeElbowBranchPromotion, planPipeTeeCrossPromotion, resolvePipeContinuationHandle, } from '../shared/elbow-branch-continuation.js';
4
+ import { findMatedScenePorts, planPipeElbowBranchPromotion, planPipeTeeCrossPromotion, } from '../shared/elbow-branch-continuation.js';
5
5
  import { pipeCollar, pipeCollarOccupied } from './collar-connection.js';
6
+ import { pipeEndpointPort } from './continuation-handle.js';
6
7
  import { PipeSegmentNode } from './schema.js';
7
8
  import { pipeGrade } from './slope.js';
8
- export function pipeEndpointPort(pipe, endpoint) {
9
- if (pipe.path.length < 2)
10
- return null;
11
- const index = endpoint === 'start' ? 0 : pipe.path.length - 1;
12
- const neighborIndex = endpoint === 'start' ? 1 : pipe.path.length - 2;
13
- const position = pipe.path[index];
14
- const neighbor = pipe.path[neighborIndex];
15
- const dx = position[0] - neighbor[0];
16
- const dy = position[1] - neighbor[1];
17
- const dz = position[2] - neighbor[2];
18
- const length = Math.hypot(dx, dy, dz);
19
- return {
20
- id: endpoint,
21
- nodeId: pipe.id,
22
- position,
23
- direction: length < 1e-9 ? [1, 0, 0] : [dx / length, dy / length, dz / length],
24
- diameter: pipe.diameter,
25
- system: pipe.system,
26
- };
27
- }
28
- export function pipeContinuationHandlePoint(pipe, endpoint, gap = 0.28) {
29
- const port = pipeEndpointPort(pipe, endpoint);
30
- if (!port)
31
- return null;
32
- return [
33
- port.position[0] + port.direction[0] * gap,
34
- port.position[1] + port.direction[1] * gap,
35
- port.position[2] + port.direction[2] * gap,
36
- ];
37
- }
38
- export function pipeContinuationHandlePlan(pipe, endpoint, nodes, gap = 0.28) {
39
- const port = pipeEndpointPort(pipe, endpoint);
40
- return port ? resolvePipeContinuationHandle(port, nodes, gap) : null;
41
- }
42
9
  export function resolvePipeContinuationSeed(defaults, nodes) {
43
10
  const continuation = defaults?.continuation;
44
11
  if (typeof continuation?.nodeId === 'string' && typeof continuation.portId === 'string') {
@@ -1 +1 @@
1
- {"version":3,"file":"definition.edit.d.ts","sourceRoot":"","sources":["../../src/pipe-segment/definition.edit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAOvE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAE/C,eAAO,MAAM,2BAA2B,EAAE,oBAAoB,CAAC,OAAO,eAAe,CAyCpF,CAAA"}
1
+ {"version":3,"file":"definition.edit.d.ts","sourceRoot":"","sources":["../../src/pipe-segment/definition.edit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAMvE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAE/C,eAAO,MAAM,2BAA2B,EAAE,oBAAoB,CAAC,OAAO,eAAe,CAwCpF,CAAA"}
@@ -1,7 +1,6 @@
1
1
  import { createRunHangerToolHint } from '../shared/run-hanger-mode.js';
2
2
  import { pipeRunToolOptions } from '../shared/run-tool-options.js';
3
3
  import { pipeBranchAffordance, pipeContinuationAffordance } from './continuation.js';
4
- import { buildPipeSegmentFloorplan } from './floorplan.js';
5
4
  import { pipeGradePointAffordance } from './grade-affordance.js';
6
5
  import { pipeSegmentParametrics } from './parametrics.js';
7
6
  export const pipeSegmentEditContribution = {
@@ -12,7 +11,6 @@ export const pipeSegmentEditContribution = {
12
11
  snapProfile: 'structural',
13
12
  parametrics: pipeSegmentParametrics,
14
13
  floorplanDependsOnSiblings: true,
15
- floorplan: buildPipeSegmentFloorplan,
16
14
  // 2D selection-time path-point handles — the floor-plan twin of the 3D
17
15
  // `affordanceTools.selection` handles. The builder emits an
18
16
  // `endpoint-handle` per path vertex; this drags the matching point.
@@ -1 +1 @@
1
- {"version":3,"file":"definition.render.d.ts","sourceRoot":"","sources":["../../src/pipe-segment/definition.render.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAEvE,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAE1C,eAAO,MAAM,2BAA2B,EAAE,oBAAoB,CAAC,OAAO,eAAe,CAAC,GAAG;IACvF,IAAI,EAAE,cAAc,CAAA;CAgFrB,CAAA"}
1
+ {"version":3,"file":"definition.render.d.ts","sourceRoot":"","sources":["../../src/pipe-segment/definition.render.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAGvE,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAE1C,eAAO,MAAM,2BAA2B,EAAE,oBAAoB,CAAC,OAAO,eAAe,CAAC,GAAG;IACvF,IAAI,EAAE,cAAc,CAAA;CAiFrB,CAAA"}
@@ -1,3 +1,4 @@
1
+ import { buildPipeSegmentFloorplan } from './floorplan.js';
1
2
  import { buildPipeSegmentGeometry } from './geometry.js';
2
3
  import { PipeSegmentNode } from './schema.js';
3
4
  export const pipeSegmentRenderDefinition = {
@@ -65,6 +66,7 @@ export const pipeSegmentRenderDefinition = {
65
66
  },
66
67
  ];
67
68
  },
69
+ floorplan: buildPipeSegmentFloorplan,
68
70
  presentation: {
69
71
  label: 'DWV Pipe',
70
72
  description: 'Drain / waste / vent pipe run — draw level or choose grade and downhill direction.',
@@ -1,7 +1,7 @@
1
1
  import { defaultI18n, } from '@pascal-app/core';
2
2
  import { INCHES_TO_METERS } from '../duct-segment/profile.js';
3
3
  import { runHangerFloorplan } from '../shared/run-hangers.js';
4
- import { pipeContinuationHandlePlan, pipeEndpointPort } from './continuation.js';
4
+ import { pipeContinuationHandlePlan, pipeEndpointPort } from './continuation-handle.js';
5
5
  import { formatPipeGradePercent } from './grade-label.js';
6
6
  import { pipeGrade } from './slope.js';
7
7
  const WASTE_COLOR = '#57534e';
@@ -1 +1 @@
1
- {"version":3,"file":"selection.d.ts","sourceRoot":"","sources":["../../src/pipe-segment/selection.tsx"],"names":[],"mappings":"AAsFA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,QAAA,MAAM,8BAA8B,0CA+BnC,CAAA;eAu4Bc,8BAA8B"}
1
+ {"version":3,"file":"selection.d.ts","sourceRoot":"","sources":["../../src/pipe-segment/selection.tsx"],"names":[],"mappings":"AAmFA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,QAAA,MAAM,8BAA8B,0CA+BnC,CAAA;eAu4Bc,8BAA8B"}
@@ -15,7 +15,8 @@ import { PipeFittingGhost, PipeSegmentGhost } from '../shared/mep-ghost.js';
15
15
  import { DWV_PORT_SYSTEMS } from '../shared/port-systems.js';
16
16
  import { ContinuePlusHandle, HandleCube, MoveChevron } from '../shared/selection-handles.js';
17
17
  import { refreshWallRunAttachment } from '../shared/wall-run-move.js';
18
- import { activatePipeContinuation, pipeContinuationHandlePlan, } from './continuation.js';
18
+ import { activatePipeContinuation } from './continuation.js';
19
+ import { pipeContinuationHandlePlan } from './continuation-handle.js';
19
20
  import { pipeGradeBlockedNotice } from './grade-affordance.js';
20
21
  import { pipeUpdatesPreserveGrades } from './grade-operation.js';
21
22
  import { startPipeRunMove } from './run-move.js';
@@ -1 +1 @@
1
- {"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../src/pipe-segment/tool.tsx"],"names":[],"mappings":"AAsEA,QAAA,MAAM,eAAe,0CAukBpB,CAAA;eA8Bc,eAAe"}
1
+ {"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../src/pipe-segment/tool.tsx"],"names":[],"mappings":"AAuEA,QAAA,MAAM,eAAe,0CAukBpB,CAAA;eA8Bc,eAAe"}
@@ -16,7 +16,8 @@ import { RunHangerPreview } from '../shared/run-hanger-controls.js';
16
16
  import { useRunHangerMode } from '../shared/run-hanger-mode.js';
17
17
  import { clearRunContinuation, updateRunDefaults } from '../shared/run-tool-options.js';
18
18
  import { planPipeCollarConnection } from './collar-connection.js';
19
- import { currentPipeContinuationSeed, pipeEndpointPort } from './continuation.js';
19
+ import { currentPipeContinuationSeed } from './continuation.js';
20
+ import { pipeEndpointPort } from './continuation-handle.js';
20
21
  import { pipeSegmentDefinition } from './definition.js';
21
22
  import { pipeGradeLabel } from './grade-label.js';
22
23
  import { applyPipeGrade, pipeGrade } from './slope.js';
@@ -1 +1 @@
1
- {"version":3,"file":"definition.edit.d.ts","sourceRoot":"","sources":["../../src/pipe-trap/definition.edit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAGvE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAE5C,eAAO,MAAM,wBAAwB,EAAE,oBAAoB,CAAC,OAAO,YAAY,CAU9E,CAAA"}
1
+ {"version":3,"file":"definition.edit.d.ts","sourceRoot":"","sources":["../../src/pipe-trap/definition.edit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAEvE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAE5C,eAAO,MAAM,wBAAwB,EAAE,oBAAoB,CAAC,OAAO,YAAY,CAS9E,CAAA"}
@@ -1,9 +1,7 @@
1
- import { buildPipeTrapFloorplan } from './floorplan.js';
2
1
  import { pipeTrapParametrics } from './parametrics.js';
3
2
  export const pipeTrapEditContribution = {
4
3
  snapProfile: 'item',
5
4
  parametrics: pipeTrapParametrics,
6
- floorplan: buildPipeTrapFloorplan,
7
5
  tool: () => import('./tool.js'),
8
6
  toolHints: [
9
7
  { key: 'Click', label: 'Place trap' },
@@ -1 +1 @@
1
- {"version":3,"file":"definition.render.d.ts","sourceRoot":"","sources":["../../src/pipe-trap/definition.render.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAGvE,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAEvC,eAAO,MAAM,wBAAwB,EAAE,oBAAoB,CAAC,OAAO,YAAY,CAAC,GAAG;IACjF,IAAI,EAAE,WAAW,CAAA;CA0ClB,CAAA"}
1
+ {"version":3,"file":"definition.render.d.ts","sourceRoot":"","sources":["../../src/pipe-trap/definition.render.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAIvE,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAEvC,eAAO,MAAM,wBAAwB,EAAE,oBAAoB,CAAC,OAAO,YAAY,CAAC,GAAG;IACjF,IAAI,EAAE,WAAW,CAAA;CA2ClB,CAAA"}
@@ -1,3 +1,4 @@
1
+ import { buildPipeTrapFloorplan } from './floorplan.js';
1
2
  import { buildPipeTrapGeometry } from './geometry.js';
2
3
  import { getPipeTrapPorts } from './ports.js';
3
4
  import { PipeTrapNode } from './schema.js';
@@ -30,6 +31,7 @@ export const pipeTrapRenderDefinition = {
30
31
  geometry: buildPipeTrapGeometry,
31
32
  geometryKey: (n) => JSON.stringify([n.diameter, n.pipeMaterial, n.armLengthM]),
32
33
  ports: getPipeTrapPorts,
34
+ floorplan: buildPipeTrapFloorplan,
33
35
  presentation: {
34
36
  label: 'Trap',
35
37
  description: 'DWV P-trap — water seal on the waste line. The trap arm runs to the vent.',
@@ -1 +1 @@
1
- {"version":3,"file":"definition.edit.d.ts","sourceRoot":"","sources":["../../src/procedural-item/definition.edit.ts"],"names":[],"mappings":"AAUA,OAAO,EAML,KAAK,kBAAkB,EAUxB,MAAM,mCAAmC,CAAA;AAK1C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AA4EvE,eAAO,MAAM,8BAA8B,EAAE,oBAAoB,CAAC,OAAO,kBAAkB,CAuN1F,CAAA"}
1
+ {"version":3,"file":"definition.edit.d.ts","sourceRoot":"","sources":["../../src/procedural-item/definition.edit.ts"],"names":[],"mappings":"AAUA,OAAO,EAML,KAAK,kBAAkB,EAQxB,MAAM,mCAAmC,CAAA;AAK1C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AA4EvE,eAAO,MAAM,8BAA8B,EAAE,oBAAoB,CAAC,OAAO,kBAAkB,CA2J1F,CAAA"}
@@ -1,5 +1,5 @@
1
1
  import { getEffectiveNode, toggleMechanism, useInteractive, useScene, } from '@pascal-app/core';
2
- import { boundsOf, boxCorners, evaluateRecipe, frame, operableParts, parameterPatch, proceduralCeilingHole, proceduralSlotColor, queryProceduralItem, resolveProceduralWallPlacement, setProceduralMaterial, snapParameters, transformPoint, validateProceduralRelations, } from '@pascal-app/core/procedural-items';
2
+ import { boundsOf, boxCorners, evaluateRecipe, frame, operableParts, parameterPatch, proceduralCeilingHole, resolveProceduralWallPlacement, setProceduralMaterial, snapParameters, transformPoint, validateProceduralRelations, } from '@pascal-app/core/procedural-items';
3
3
  import { usePlacementPreview } from '@pascal-app/editor';
4
4
  import { decorateProceduralEmission } from '@pascal-app/viewer';
5
5
  import { itemPaint } from '../item/paint.js';
@@ -198,58 +198,5 @@ export const proceduralItemEditContribution = {
198
198
  });
199
199
  return result;
200
200
  },
201
- floorplan: (node, ctx) => {
202
- const chain = { [node.id]: node };
203
- let current = node.parentId, depth = 0;
204
- while (current && depth++ < 32) {
205
- const parent = ctx.resolve(current);
206
- if (!parent)
207
- break;
208
- chain[current] = parent;
209
- current = parent.parentId;
210
- }
211
- const q = queryProceduralItem(node, chain), b = q.levelBounds;
212
- const floorPlanUrl = node.metadata.floorPlanUrl;
213
- if (typeof floorPlanUrl === 'string' && floorPlanUrl.trim()) {
214
- const local = q.localBounds;
215
- const center = transformPoint(q.frame, local.min.map((v, i) => (v + local.max[i]) / 2));
216
- const points = [
217
- [local.min[0], local.min[2]],
218
- [local.max[0], local.min[2]],
219
- [local.max[0], local.max[2]],
220
- [local.min[0], local.max[2]],
221
- ].map(([x, z]) => {
222
- const point = transformPoint(q.frame, [x, 0, z]);
223
- return [point[0], point[2]];
224
- });
225
- const selected = ctx.viewState?.selected || ctx.viewState?.highlighted;
226
- const stroke = selected ? (ctx.viewState?.palette?.selectedStroke ?? '#3b82f6') : '#92400e';
227
- const strokeWidth = selected ? 0.035 : 0.012;
228
- const children = [
229
- { kind: 'polygon', points, fill: 'transparent', stroke, strokeWidth, opacity: 0.85 },
230
- {
231
- kind: 'image',
232
- url: floorPlanUrl,
233
- center: [center[0], center[2]],
234
- width: local.dimensions[0],
235
- height: local.dimensions[2],
236
- rotation: Math.atan2(q.frame.axes[0][2], q.frame.axes[0][0]),
237
- },
238
- ];
239
- if (selected)
240
- children.push({ kind: 'polygon', points, fill: 'none', stroke, strokeWidth });
241
- return { kind: 'group', children };
242
- }
243
- return {
244
- kind: 'rect',
245
- x: b.min[0],
246
- y: b.min[2],
247
- width: b.dimensions[0],
248
- height: b.dimensions[2],
249
- fill: proceduralSlotColor(node.slots[node.recipe.slots[0].id], node.recipe.slots[0].color, ctx.materials ?? {}),
250
- stroke: '#44403c',
251
- strokeWidth: 0.01,
252
- };
253
- },
254
201
  renderer: { kind: 'parametric', module: () => import('./renderer.edit.js') },
255
202
  };
@@ -1 +1 @@
1
- {"version":3,"file":"definition.render.d.ts","sourceRoot":"","sources":["../../src/procedural-item/definition.render.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,kBAAkB,EAInB,MAAM,mCAAmC,CAAA;AAC1C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAIvE,eAAO,MAAM,8BAA8B,EAAE,oBAAoB,CAAC,OAAO,kBAAkB,CAAC,GAAG;IAC7F,IAAI,EAAE,iBAAiB,CAAA;CAqFxB,CAAA"}
1
+ {"version":3,"file":"definition.render.d.ts","sourceRoot":"","sources":["../../src/procedural-item/definition.render.ts"],"names":[],"mappings":"AAOA,OAAO,EAEL,kBAAkB,EAOnB,MAAM,mCAAmC,CAAA;AAC1C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAIvE,eAAO,MAAM,8BAA8B,EAAE,oBAAoB,CAAC,OAAO,kBAAkB,CAAC,GAAG;IAC7F,IAAI,EAAE,iBAAiB,CAAA;CAiJxB,CAAA"}
@@ -1,5 +1,5 @@
1
- import { getEffectiveNode, proceduralItemSlots } from '@pascal-app/core';
2
- import { evaluateRecipe, ProceduralItemNode, proceduralCeilingHole, proceduralFootprint, shelfRecipe, } from '@pascal-app/core/procedural-items';
1
+ import { getEffectiveNode, proceduralItemSlots, } from '@pascal-app/core';
2
+ import { evaluateRecipe, ProceduralItemNode, proceduralCeilingHole, proceduralFootprint, proceduralSlotColor, queryProceduralItem, shelfRecipe, transformPoint, } from '@pascal-app/core/procedural-items';
3
3
  import { proceduralMechanism } from '../shared/item-interactions.js';
4
4
  import { bakeProceduralAnimationClips, isProceduralMotionPlaying } from './animation.js';
5
5
  export const proceduralItemRenderDefinition = {
@@ -75,6 +75,59 @@ export const proceduralItemRenderDefinition = {
75
75
  relations: { hosts: ['item', 'procedural-item'], cascadeDelete: 'descendants' },
76
76
  renderer: { kind: 'parametric', module: () => import('./renderer.js') },
77
77
  exportAnimation: ({ node, object }) => bakeProceduralAnimationClips(node, object),
78
+ floorplan: (node, ctx) => {
79
+ const chain = { [node.id]: node };
80
+ let current = node.parentId, depth = 0;
81
+ while (current && depth++ < 32) {
82
+ const parent = ctx.resolve(current);
83
+ if (!parent)
84
+ break;
85
+ chain[current] = parent;
86
+ current = parent.parentId;
87
+ }
88
+ const q = queryProceduralItem(node, chain), b = q.levelBounds;
89
+ const floorPlanUrl = node.metadata.floorPlanUrl;
90
+ if (typeof floorPlanUrl === 'string' && floorPlanUrl.trim()) {
91
+ const local = q.localBounds;
92
+ const center = transformPoint(q.frame, local.min.map((v, i) => (v + local.max[i]) / 2));
93
+ const points = [
94
+ [local.min[0], local.min[2]],
95
+ [local.max[0], local.min[2]],
96
+ [local.max[0], local.max[2]],
97
+ [local.min[0], local.max[2]],
98
+ ].map(([x, z]) => {
99
+ const point = transformPoint(q.frame, [x, 0, z]);
100
+ return [point[0], point[2]];
101
+ });
102
+ const selected = ctx.viewState?.selected || ctx.viewState?.highlighted;
103
+ const stroke = selected ? (ctx.viewState?.palette?.selectedStroke ?? '#3b82f6') : '#92400e';
104
+ const strokeWidth = selected ? 0.035 : 0.012;
105
+ const children = [
106
+ { kind: 'polygon', points, fill: 'transparent', stroke, strokeWidth, opacity: 0.85 },
107
+ {
108
+ kind: 'image',
109
+ url: floorPlanUrl,
110
+ center: [center[0], center[2]],
111
+ width: local.dimensions[0],
112
+ height: local.dimensions[2],
113
+ rotation: Math.atan2(q.frame.axes[0][2], q.frame.axes[0][0]),
114
+ },
115
+ ];
116
+ if (selected)
117
+ children.push({ kind: 'polygon', points, fill: 'none', stroke, strokeWidth });
118
+ return { kind: 'group', children };
119
+ }
120
+ return {
121
+ kind: 'rect',
122
+ x: b.min[0],
123
+ y: b.min[2],
124
+ width: b.dimensions[0],
125
+ height: b.dimensions[2],
126
+ fill: proceduralSlotColor(node.slots[node.recipe.slots[0].id], node.recipe.slots[0].color, ctx.materials ?? {}),
127
+ stroke: '#44403c',
128
+ strokeWidth: 0.01,
129
+ };
130
+ },
78
131
  presentation: {
79
132
  label: 'Procedural item',
80
133
  description: 'Experimental editable recipe',