@pascal-app/nodes 0.1.1 → 1.0.0-beta.2

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 (408) hide show
  1. package/README.md +34 -0
  2. package/dist/building/definition.js +1 -1
  3. package/dist/cabinet/definition.d.ts.map +1 -1
  4. package/dist/cabinet/definition.js +809 -72
  5. package/dist/cabinet/geometry.d.ts.map +1 -1
  6. package/dist/cabinet/geometry.js +4 -0
  7. package/dist/cabinet/move-frame.js +3 -3
  8. package/dist/cabinet/panel.d.ts.map +1 -1
  9. package/dist/cabinet/panel.js +1 -0
  10. package/dist/cabinet/placement-snap.d.ts +8 -0
  11. package/dist/cabinet/placement-snap.d.ts.map +1 -0
  12. package/dist/cabinet/placement-snap.js +19 -0
  13. package/dist/cabinet/presets.js +8 -8
  14. package/dist/cabinet/quick-actions.d.ts.map +1 -1
  15. package/dist/cabinet/quick-actions.js +9 -3
  16. package/dist/cabinet/resize-limits.d.ts +11 -0
  17. package/dist/cabinet/resize-limits.d.ts.map +1 -0
  18. package/dist/cabinet/resize-limits.js +22 -0
  19. package/dist/cabinet/run-layout.d.ts +8 -2
  20. package/dist/cabinet/run-layout.d.ts.map +1 -1
  21. package/dist/cabinet/run-layout.js +59 -7
  22. package/dist/cabinet/run-ops.d.ts +44 -3
  23. package/dist/cabinet/run-ops.d.ts.map +1 -1
  24. package/dist/cabinet/run-ops.js +646 -110
  25. package/dist/cabinet/run-panel.d.ts +2 -1
  26. package/dist/cabinet/run-panel.d.ts.map +1 -1
  27. package/dist/cabinet/run-panel.js +38 -4
  28. package/dist/cabinet/stack-transitions.js +4 -4
  29. package/dist/cabinet/tool.d.ts.map +1 -1
  30. package/dist/cabinet/tool.js +95 -17
  31. package/dist/cabinet/wall-snap.d.ts.map +1 -1
  32. package/dist/cabinet/wall-snap.js +2 -6
  33. package/dist/ceiling/boundary-editor.d.ts.map +1 -1
  34. package/dist/ceiling/boundary-editor.js +2 -2
  35. package/dist/ceiling/definition.d.ts +1 -1
  36. package/dist/ceiling/definition.d.ts.map +1 -1
  37. package/dist/ceiling/definition.js +36 -5
  38. package/dist/ceiling/floorplan-affordances.d.ts +4 -4
  39. package/dist/ceiling/floorplan-move.d.ts +4 -4
  40. package/dist/ceiling/floorplan-move.d.ts.map +1 -1
  41. package/dist/ceiling/floorplan-move.js +5 -4
  42. package/dist/ceiling/hole-editor.d.ts.map +1 -1
  43. package/dist/ceiling/hole-editor.js +2 -2
  44. package/dist/ceiling/move-tool.d.ts.map +1 -1
  45. package/dist/ceiling/move-tool.js +4 -3
  46. package/dist/ceiling/panel.d.ts.map +1 -1
  47. package/dist/ceiling/panel.js +65 -3
  48. package/dist/ceiling/renderer.d.ts.map +1 -1
  49. package/dist/ceiling/renderer.js +6 -2
  50. package/dist/ceiling/tool.d.ts.map +1 -1
  51. package/dist/ceiling/tool.js +12 -1
  52. package/dist/chimney/definition.d.ts.map +1 -1
  53. package/dist/chimney/definition.js +1 -0
  54. package/dist/chimney/tool.d.ts.map +1 -1
  55. package/dist/chimney/tool.js +16 -1
  56. package/dist/column/definition.d.ts.map +1 -1
  57. package/dist/column/definition.js +14 -2
  58. package/dist/column/floorplan-affordances.d.ts.map +1 -1
  59. package/dist/column/floorplan-affordances.js +19 -14
  60. package/dist/column/floorplan-move.d.ts.map +1 -1
  61. package/dist/column/floorplan-move.js +7 -2
  62. package/dist/column/floorplan.d.ts +9 -1
  63. package/dist/column/floorplan.d.ts.map +1 -1
  64. package/dist/column/floorplan.js +59 -4
  65. package/dist/column/tool.d.ts.map +1 -1
  66. package/dist/column/tool.js +33 -7
  67. package/dist/construction-dimension/definition.d.ts +4 -0
  68. package/dist/construction-dimension/definition.d.ts.map +1 -0
  69. package/dist/construction-dimension/definition.js +83 -0
  70. package/dist/construction-dimension/drawing-coordination.d.ts +7 -0
  71. package/dist/construction-dimension/drawing-coordination.d.ts.map +1 -0
  72. package/dist/construction-dimension/drawing-coordination.js +54 -0
  73. package/dist/construction-dimension/floorplan-affordances.d.ts +4 -0
  74. package/dist/construction-dimension/floorplan-affordances.d.ts.map +1 -0
  75. package/dist/construction-dimension/floorplan-affordances.js +114 -0
  76. package/dist/construction-dimension/floorplan-tool.d.ts +21 -0
  77. package/dist/construction-dimension/floorplan-tool.d.ts.map +1 -0
  78. package/dist/construction-dimension/floorplan-tool.js +557 -0
  79. package/dist/construction-dimension/floorplan.d.ts +3 -0
  80. package/dist/construction-dimension/floorplan.d.ts.map +1 -0
  81. package/dist/construction-dimension/floorplan.js +457 -0
  82. package/dist/construction-dimension/geometry.d.ts +31 -0
  83. package/dist/construction-dimension/geometry.d.ts.map +1 -0
  84. package/dist/construction-dimension/geometry.js +144 -0
  85. package/dist/construction-dimension/index.d.ts +4 -0
  86. package/dist/construction-dimension/index.d.ts.map +1 -0
  87. package/dist/construction-dimension/index.js +3 -0
  88. package/dist/construction-dimension/panel.d.ts +2 -0
  89. package/dist/construction-dimension/panel.d.ts.map +1 -0
  90. package/dist/construction-dimension/panel.js +128 -0
  91. package/dist/construction-dimension/parametrics.d.ts +3 -0
  92. package/dist/construction-dimension/parametrics.d.ts.map +1 -0
  93. package/dist/construction-dimension/parametrics.js +4 -0
  94. package/dist/construction-dimension/schema.d.ts +2 -0
  95. package/dist/construction-dimension/schema.d.ts.map +1 -0
  96. package/dist/construction-dimension/schema.js +1 -0
  97. package/dist/door/contextual-dimensions.d.ts +3 -0
  98. package/dist/door/contextual-dimensions.d.ts.map +1 -0
  99. package/dist/door/contextual-dimensions.js +7 -0
  100. package/dist/door/definition.d.ts.map +1 -1
  101. package/dist/door/definition.js +13 -8
  102. package/dist/door/floorplan-affordances.d.ts +2 -5
  103. package/dist/door/floorplan-affordances.d.ts.map +1 -1
  104. package/dist/door/floorplan-affordances.js +9 -18
  105. package/dist/door/floorplan.d.ts +3 -4
  106. package/dist/door/floorplan.d.ts.map +1 -1
  107. package/dist/door/floorplan.js +88 -6
  108. package/dist/door/move-tool.d.ts.map +1 -1
  109. package/dist/door/move-tool.js +2 -2
  110. package/dist/door/panel.d.ts.map +1 -1
  111. package/dist/door/panel.js +3 -1
  112. package/dist/door/schema.d.ts +1 -1
  113. package/dist/door/schema.d.ts.map +1 -1
  114. package/dist/door/schema.js +1 -1
  115. package/dist/door/tool.d.ts.map +1 -1
  116. package/dist/door/tool.js +63 -6
  117. package/dist/dormer/definition.d.ts.map +1 -1
  118. package/dist/dormer/definition.js +1 -0
  119. package/dist/dormer/tool.d.ts.map +1 -1
  120. package/dist/dormer/tool.js +23 -1
  121. package/dist/duct-segment/tool.d.ts.map +1 -1
  122. package/dist/duct-segment/tool.js +20 -9
  123. package/dist/duct-terminal/tool.d.ts.map +1 -1
  124. package/dist/duct-terminal/tool.js +9 -6
  125. package/dist/elevator/floorplan-affordances.d.ts +2 -6
  126. package/dist/elevator/floorplan-affordances.d.ts.map +1 -1
  127. package/dist/elevator/floorplan-affordances.js +13 -12
  128. package/dist/fence/actions/move-endpoint.d.ts.map +1 -1
  129. package/dist/fence/actions/move-endpoint.js +29 -1
  130. package/dist/fence/definition.d.ts.map +1 -1
  131. package/dist/fence/definition.js +74 -14
  132. package/dist/fence/floorplan-affordances.d.ts.map +1 -1
  133. package/dist/fence/floorplan-affordances.js +48 -11
  134. package/dist/fence/floorplan-move.d.ts.map +1 -1
  135. package/dist/fence/floorplan-move.js +38 -3
  136. package/dist/fence/geometry.d.ts.map +1 -1
  137. package/dist/fence/geometry.js +15 -1
  138. package/dist/fence/lift.d.ts +38 -0
  139. package/dist/fence/lift.d.ts.map +1 -0
  140. package/dist/fence/lift.js +51 -0
  141. package/dist/fence/move-tool.d.ts.map +1 -1
  142. package/dist/fence/move-tool.js +25 -5
  143. package/dist/fence/system.d.ts +3 -0
  144. package/dist/fence/system.d.ts.map +1 -0
  145. package/dist/fence/system.js +46 -0
  146. package/dist/fence/tool.d.ts.map +1 -1
  147. package/dist/fence/tool.js +103 -32
  148. package/dist/hvac-equipment/tool.d.ts.map +1 -1
  149. package/dist/hvac-equipment/tool.js +8 -3
  150. package/dist/index.d.ts +2 -0
  151. package/dist/index.d.ts.map +1 -1
  152. package/dist/index.js +6 -0
  153. package/dist/item/definition.d.ts.map +1 -1
  154. package/dist/item/definition.js +7 -1
  155. package/dist/item/floorplan-move.d.ts.map +1 -1
  156. package/dist/item/floorplan-move.js +50 -43
  157. package/dist/item/floorplan.d.ts +1 -0
  158. package/dist/item/floorplan.d.ts.map +1 -1
  159. package/dist/item/floorplan.js +49 -0
  160. package/dist/item/renderer.d.ts +3 -0
  161. package/dist/item/renderer.d.ts.map +1 -1
  162. package/dist/item/renderer.js +96 -8
  163. package/dist/level/definition.d.ts.map +1 -1
  164. package/dist/level/definition.js +7 -3
  165. package/dist/lineset/tool.d.ts.map +1 -1
  166. package/dist/lineset/tool.js +5 -1
  167. package/dist/liquid-line/tool.d.ts.map +1 -1
  168. package/dist/liquid-line/tool.js +7 -1
  169. package/dist/measurement/definition.d.ts.map +1 -1
  170. package/dist/measurement/definition.js +5 -0
  171. package/dist/measurement/floorplan.d.ts.map +1 -1
  172. package/dist/measurement/floorplan.js +11 -10
  173. package/dist/measurement/index.d.ts +1 -1
  174. package/dist/measurement/index.d.ts.map +1 -1
  175. package/dist/measurement/index.js +1 -1
  176. package/dist/measurement/resolve.d.ts +5 -0
  177. package/dist/measurement/resolve.d.ts.map +1 -1
  178. package/dist/measurement/resolve.js +2 -2
  179. package/dist/measurement/surface-query.js +5 -5
  180. package/dist/measurement/tool.d.ts +6 -1
  181. package/dist/measurement/tool.d.ts.map +1 -1
  182. package/dist/measurement/tool.js +7 -11
  183. package/dist/pipe-segment/tool.d.ts.map +1 -1
  184. package/dist/pipe-segment/tool.js +22 -19
  185. package/dist/roof-segment/floorplan-affordances.d.ts.map +1 -1
  186. package/dist/roof-segment/floorplan-affordances.js +14 -8
  187. package/dist/shared/construction-dimension-standards.d.ts +34 -0
  188. package/dist/shared/construction-dimension-standards.d.ts.map +1 -0
  189. package/dist/shared/construction-dimension-standards.js +18 -0
  190. package/dist/shared/construction-length.d.ts +10 -0
  191. package/dist/shared/construction-length.d.ts.map +1 -0
  192. package/dist/shared/construction-length.js +57 -0
  193. package/dist/shared/dimension-string.d.ts +20 -0
  194. package/dist/shared/dimension-string.d.ts.map +1 -0
  195. package/dist/shared/dimension-string.js +19 -0
  196. package/dist/shared/draft-axis-guides.d.ts +36 -0
  197. package/dist/shared/draft-axis-guides.d.ts.map +1 -0
  198. package/dist/shared/draft-axis-guides.js +107 -0
  199. package/dist/shared/move-roof-tool.d.ts.map +1 -1
  200. package/dist/shared/move-roof-tool.js +17 -3
  201. package/dist/shared/opening-documentation-fields.d.ts +16 -0
  202. package/dist/shared/opening-documentation-fields.d.ts.map +1 -0
  203. package/dist/shared/opening-documentation-fields.js +54 -0
  204. package/dist/shared/opening-documentation.d.ts +47 -0
  205. package/dist/shared/opening-documentation.d.ts.map +1 -0
  206. package/dist/shared/opening-documentation.js +300 -0
  207. package/dist/shared/opening-guides-runtime.d.ts.map +1 -1
  208. package/dist/shared/opening-guides-runtime.js +3 -2
  209. package/dist/shared/opening-placement-dimensions.d.ts.map +1 -1
  210. package/dist/shared/opening-placement-dimensions.js +14 -5
  211. package/dist/shared/wall-opening-ceiling.d.ts +30 -0
  212. package/dist/shared/wall-opening-ceiling.d.ts.map +1 -0
  213. package/dist/shared/wall-opening-ceiling.js +29 -0
  214. package/dist/shelf/floorplan-affordances.d.ts.map +1 -1
  215. package/dist/shelf/floorplan-affordances.js +10 -5
  216. package/dist/shelf/floorplan-move.d.ts +2 -16
  217. package/dist/shelf/floorplan-move.d.ts.map +1 -1
  218. package/dist/shelf/floorplan-move.js +19 -40
  219. package/dist/shelf/tool.d.ts.map +1 -1
  220. package/dist/shelf/tool.js +8 -3
  221. package/dist/site/recessed-slab-ground-holes.d.ts.map +1 -1
  222. package/dist/site/recessed-slab-ground-holes.js +1 -4
  223. package/dist/site/renderer.d.ts.map +1 -1
  224. package/dist/site/renderer.js +118 -28
  225. package/dist/site/terrain-drape.d.ts +91 -0
  226. package/dist/site/terrain-drape.d.ts.map +1 -0
  227. package/dist/site/terrain-drape.js +205 -0
  228. package/dist/site/terrain-geometry.d.ts +131 -0
  229. package/dist/site/terrain-geometry.d.ts.map +1 -0
  230. package/dist/site/terrain-geometry.js +259 -0
  231. package/dist/site/terrain-mesh.d.ts +49 -0
  232. package/dist/site/terrain-mesh.d.ts.map +1 -0
  233. package/dist/site/terrain-mesh.js +122 -0
  234. package/dist/site/terrain-renderer.d.ts +28 -0
  235. package/dist/site/terrain-renderer.d.ts.map +1 -0
  236. package/dist/site/terrain-renderer.js +69 -0
  237. package/dist/skylight/definition.d.ts.map +1 -1
  238. package/dist/skylight/definition.js +1 -0
  239. package/dist/skylight/tool.d.ts.map +1 -1
  240. package/dist/skylight/tool.js +16 -1
  241. package/dist/slab/definition.d.ts.map +1 -1
  242. package/dist/slab/definition.js +87 -10
  243. package/dist/slab/elevation-limit.d.ts +43 -0
  244. package/dist/slab/elevation-limit.d.ts.map +1 -0
  245. package/dist/slab/elevation-limit.js +124 -0
  246. package/dist/slab/floorplan-affordances.d.ts +16 -0
  247. package/dist/slab/floorplan-affordances.d.ts.map +1 -1
  248. package/dist/slab/geometry.d.ts.map +1 -1
  249. package/dist/slab/geometry.js +98 -5
  250. package/dist/slab/panel.d.ts.map +1 -1
  251. package/dist/slab/panel.js +82 -4
  252. package/dist/slab/parametrics.d.ts +1 -1
  253. package/dist/slab/parametrics.d.ts.map +1 -1
  254. package/dist/slab/parametrics.js +13 -1
  255. package/dist/slab/placement-ownership.d.ts +3 -0
  256. package/dist/slab/placement-ownership.d.ts.map +1 -0
  257. package/dist/slab/placement-ownership.js +3 -0
  258. package/dist/slab/quick-measurement.d.ts.map +1 -1
  259. package/dist/slab/quick-measurement.js +3 -2
  260. package/dist/slab/system.d.ts.map +1 -1
  261. package/dist/slab/system.js +14 -4
  262. package/dist/slab/tool.d.ts.map +1 -1
  263. package/dist/slab/tool.js +81 -23
  264. package/dist/solar-panel/definition.d.ts.map +1 -1
  265. package/dist/solar-panel/definition.js +1 -0
  266. package/dist/solar-panel/tool.d.ts.map +1 -1
  267. package/dist/solar-panel/tool.js +17 -1
  268. package/dist/spawn/definition.d.ts.map +1 -1
  269. package/dist/spawn/definition.js +1 -0
  270. package/dist/spawn/floorplan-affordances.d.ts.map +1 -1
  271. package/dist/spawn/floorplan-affordances.js +7 -4
  272. package/dist/spawn/floorplan-move.d.ts.map +1 -1
  273. package/dist/spawn/floorplan-move.js +8 -6
  274. package/dist/spawn/renderer.d.ts +4 -0
  275. package/dist/spawn/renderer.d.ts.map +1 -1
  276. package/dist/spawn/renderer.js +32 -18
  277. package/dist/spawn/tool.d.ts +2 -2
  278. package/dist/spawn/tool.d.ts.map +1 -1
  279. package/dist/spawn/tool.js +78 -11
  280. package/dist/stair/definition.d.ts.map +1 -1
  281. package/dist/stair/definition.js +15 -7
  282. package/dist/stair/destination.d.ts +16 -0
  283. package/dist/stair/destination.d.ts.map +1 -0
  284. package/dist/stair/destination.js +24 -0
  285. package/dist/stair/documentation.d.ts +8 -0
  286. package/dist/stair/documentation.d.ts.map +1 -0
  287. package/dist/stair/documentation.js +245 -0
  288. package/dist/stair/floor-stack.d.ts.map +1 -1
  289. package/dist/stair/floor-stack.js +38 -0
  290. package/dist/stair/floorplan-affordances.d.ts.map +1 -1
  291. package/dist/stair/floorplan-affordances.js +28 -9
  292. package/dist/stair/floorplan-move.d.ts +3 -5
  293. package/dist/stair/floorplan-move.d.ts.map +1 -1
  294. package/dist/stair/floorplan-move.js +14 -16
  295. package/dist/stair/floorplan.d.ts.map +1 -1
  296. package/dist/stair/floorplan.js +27 -14
  297. package/dist/stair/panel.d.ts.map +1 -1
  298. package/dist/stair/panel.js +35 -2
  299. package/dist/stair/renderer.d.ts.map +1 -1
  300. package/dist/stair/renderer.js +4 -3
  301. package/dist/structural-grid/coordination.d.ts +16 -0
  302. package/dist/structural-grid/coordination.d.ts.map +1 -0
  303. package/dist/structural-grid/coordination.js +105 -0
  304. package/dist/structural-grid/definition.d.ts +4 -0
  305. package/dist/structural-grid/definition.d.ts.map +1 -0
  306. package/dist/structural-grid/definition.js +51 -0
  307. package/dist/structural-grid/floorplan-tool.d.ts +16 -0
  308. package/dist/structural-grid/floorplan-tool.d.ts.map +1 -0
  309. package/dist/structural-grid/floorplan-tool.js +183 -0
  310. package/dist/structural-grid/floorplan.d.ts +3 -0
  311. package/dist/structural-grid/floorplan.d.ts.map +1 -0
  312. package/dist/structural-grid/floorplan.js +61 -0
  313. package/dist/structural-grid/index.d.ts +2 -0
  314. package/dist/structural-grid/index.d.ts.map +1 -0
  315. package/dist/structural-grid/index.js +1 -0
  316. package/dist/structural-grid/schema.d.ts +2 -0
  317. package/dist/structural-grid/schema.d.ts.map +1 -0
  318. package/dist/structural-grid/schema.js +1 -0
  319. package/dist/wall/construction-dimensions.d.ts +32 -0
  320. package/dist/wall/construction-dimensions.d.ts.map +1 -0
  321. package/dist/wall/construction-dimensions.js +1031 -0
  322. package/dist/wall/contextual-dimensions.d.ts +13 -0
  323. package/dist/wall/contextual-dimensions.d.ts.map +1 -0
  324. package/dist/wall/contextual-dimensions.js +221 -0
  325. package/dist/wall/definition.d.ts.map +1 -1
  326. package/dist/wall/definition.js +20 -1
  327. package/dist/wall/floorplan-affordances.d.ts.map +1 -1
  328. package/dist/wall/floorplan-affordances.js +23 -8
  329. package/dist/wall/floorplan-overrides.d.ts +9 -6
  330. package/dist/wall/floorplan-overrides.d.ts.map +1 -1
  331. package/dist/wall/floorplan-overrides.js +20 -11
  332. package/dist/wall/floorplan.d.ts +12 -3
  333. package/dist/wall/floorplan.d.ts.map +1 -1
  334. package/dist/wall/floorplan.js +121 -79
  335. package/dist/wall/measurement.d.ts.map +1 -1
  336. package/dist/wall/measurement.js +17 -4
  337. package/dist/wall/move-endpoint-tool.d.ts.map +1 -1
  338. package/dist/wall/move-endpoint-tool.js +74 -27
  339. package/dist/wall/move-shared.d.ts.map +1 -1
  340. package/dist/wall/move-shared.js +3 -2
  341. package/dist/wall/move-tool.d.ts.map +1 -1
  342. package/dist/wall/move-tool.js +15 -3
  343. package/dist/wall/paint.d.ts.map +1 -1
  344. package/dist/wall/paint.js +10 -6
  345. package/dist/wall/panel.d.ts.map +1 -1
  346. package/dist/wall/panel.js +32 -5
  347. package/dist/wall/parametrics.d.ts.map +1 -1
  348. package/dist/wall/parametrics.js +2 -0
  349. package/dist/wall/preview.d.ts +8 -0
  350. package/dist/wall/preview.d.ts.map +1 -0
  351. package/dist/wall/preview.js +39 -0
  352. package/dist/wall/quick-measurement.d.ts.map +1 -1
  353. package/dist/wall/quick-measurement.js +3 -2
  354. package/dist/wall/renderer.d.ts.map +1 -1
  355. package/dist/wall/renderer.js +7 -5
  356. package/dist/wall/system.d.ts +1 -1
  357. package/dist/wall/system.d.ts.map +1 -1
  358. package/dist/wall/system.js +37 -2
  359. package/dist/wall/tool.d.ts.map +1 -1
  360. package/dist/wall/tool.js +148 -96
  361. package/dist/wall/treatment-level-data.d.ts +14 -0
  362. package/dist/wall/treatment-level-data.d.ts.map +1 -0
  363. package/dist/wall/treatment-level-data.js +31 -0
  364. package/dist/wall/treatments.d.ts +8 -2
  365. package/dist/wall/treatments.d.ts.map +1 -1
  366. package/dist/wall/treatments.js +58 -15
  367. package/dist/window/contextual-dimensions.d.ts +3 -0
  368. package/dist/window/contextual-dimensions.d.ts.map +1 -0
  369. package/dist/window/contextual-dimensions.js +7 -0
  370. package/dist/window/definition.d.ts.map +1 -1
  371. package/dist/window/definition.js +15 -10
  372. package/dist/window/floorplan-affordances.d.ts +2 -5
  373. package/dist/window/floorplan-affordances.d.ts.map +1 -1
  374. package/dist/window/floorplan-affordances.js +9 -15
  375. package/dist/window/floorplan-move.d.ts.map +1 -1
  376. package/dist/window/floorplan-move.js +1 -1
  377. package/dist/window/floorplan.d.ts.map +1 -1
  378. package/dist/window/floorplan.js +7 -1
  379. package/dist/window/move-tool.d.ts.map +1 -1
  380. package/dist/window/move-tool.js +3 -3
  381. package/dist/window/panel.d.ts.map +1 -1
  382. package/dist/window/panel.js +4 -1
  383. package/dist/window/schema.d.ts +1 -1
  384. package/dist/window/schema.d.ts.map +1 -1
  385. package/dist/window/schema.js +1 -1
  386. package/dist/window/tool.d.ts.map +1 -1
  387. package/dist/window/tool.js +64 -7
  388. package/dist/window/window-math.d.ts +7 -3
  389. package/dist/window/window-math.d.ts.map +1 -1
  390. package/dist/window/window-math.js +8 -3
  391. package/dist/zone/contextual-dimensions.d.ts +3 -0
  392. package/dist/zone/contextual-dimensions.d.ts.map +1 -0
  393. package/dist/zone/contextual-dimensions.js +43 -0
  394. package/dist/zone/definition.d.ts.map +1 -1
  395. package/dist/zone/definition.js +9 -1
  396. package/dist/zone/floorplan-affordances.d.ts +36 -0
  397. package/dist/zone/floorplan-affordances.d.ts.map +1 -1
  398. package/dist/zone/floorplan.d.ts.map +1 -1
  399. package/dist/zone/floorplan.js +59 -3
  400. package/dist/zone/quantities-panel.d.ts.map +1 -1
  401. package/dist/zone/quantities-panel.js +48 -4
  402. package/dist/zone/room-clear-dimensions.d.ts +3 -0
  403. package/dist/zone/room-clear-dimensions.d.ts.map +1 -0
  404. package/dist/zone/room-clear-dimensions.js +406 -0
  405. package/dist/zone/room-documentation.d.ts +11 -0
  406. package/dist/zone/room-documentation.d.ts.map +1 -0
  407. package/dist/zone/room-documentation.js +97 -0
  408. package/package.json +7 -7
@@ -1,8 +1,10 @@
1
1
  import { getFenceControlHandle, isSplineFence, } from '@pascal-app/core';
2
+ import { clearStructuralElevationGuide, publishStructuralElevationGuide, resolveStructuralElevationSnap, } from '@pascal-app/editor';
2
3
  import { buildFenceFloorplan } from './floorplan';
3
4
  import { fenceControlPointAffordance, fenceCurveAffordance, fenceMoveEndpointAffordance, fenceTangentAffordance, } from './floorplan-affordances';
4
5
  import { fenceFloorplanMoveTarget } from './floorplan-move';
5
6
  import { buildFenceGeometry } from './geometry';
7
+ import { resolveFenceLiftElevation, resolveFenceLiftElevationForNodes } from './lift';
6
8
  import { fencePaint } from './paint';
7
9
  import { fenceParametrics } from './parametrics';
8
10
  import { FenceNode } from './schema';
@@ -13,6 +15,12 @@ const SIDE_HANDLE_TOP_INSET = 0.08;
13
15
  const SIDE_HANDLE_MIN_HEIGHT = 0.4;
14
16
  const HEIGHT_HANDLE_OFFSET = 0.45;
15
17
  const MIN_FENCE_HEIGHT = 0.3;
18
+ function fenceBaseElevation(n, sceneApi) {
19
+ const nodes = sceneApi?.nodes();
20
+ return nodes
21
+ ? resolveFenceLiftElevationForNodes(n, nodes)
22
+ : resolveFenceLiftElevation(n, () => undefined);
23
+ }
16
24
  function fenceMidpointFrame(n) {
17
25
  const dx = n.end[0] - n.start[0];
18
26
  const dz = n.end[1] - n.start[1];
@@ -24,6 +32,14 @@ function fenceMidpointFrame(n) {
24
32
  normalZ: dx / len,
25
33
  };
26
34
  }
35
+ function fenceElevationGuideSource(n) {
36
+ const { midX, midZ } = fenceMidpointFrame(n);
37
+ return {
38
+ nodeId: n.id,
39
+ levelId: n.parentId,
40
+ anchor: [midX, midZ],
41
+ };
42
+ }
27
43
  // Side-move arrows: click to hand the fence to its move tool. Same shape
28
44
  // as wall — front + back faces, positioned past the fence thickness near
29
45
  // the top so they don't compete with endpoint pickers in the floating
@@ -34,11 +50,12 @@ function fenceSideMoveHandle(side) {
34
50
  kind: 'tap-action',
35
51
  onActivate: (node, _scene, editor) => editor.engageMove(node),
36
52
  placement: {
37
- position: (n) => {
53
+ position: (n, sceneApi) => {
38
54
  const { midX, midZ, normalX, normalZ } = fenceMidpointFrame(n);
39
55
  const offset = Math.max((n.thickness ?? 0.1) / 2 + SIDE_HANDLE_OFFSET, SIDE_HANDLE_MIN_OFFSET);
40
56
  const h = n.height ?? 1.8;
41
- const handleY = Math.max(h - SIDE_HANDLE_TOP_INSET, SIDE_HANDLE_MIN_HEIGHT);
57
+ const handleY = fenceBaseElevation(n, sceneApi) +
58
+ Math.max(h - SIDE_HANDLE_TOP_INSET, SIDE_HANDLE_MIN_HEIGHT);
42
59
  return [midX + sign * normalX * offset, handleY, midZ + sign * normalZ * offset];
43
60
  },
44
61
  rotationY: (n) => {
@@ -69,9 +86,13 @@ function fenceHeightHandle() {
69
86
  currentValue: (n) => n.height ?? 1.8,
70
87
  apply: (_n, newHeight) => ({ height: newHeight }),
71
88
  placement: {
72
- position: (n) => {
89
+ position: (n, sceneApi) => {
73
90
  const { midX, midZ } = fenceMidpointFrame(n);
74
- return [midX, (n.height ?? 1.8) + HEIGHT_HANDLE_OFFSET, midZ];
91
+ return [
92
+ midX,
93
+ fenceBaseElevation(n, sceneApi) + (n.height ?? 1.8) + HEIGHT_HANDLE_OFFSET,
94
+ midZ,
95
+ ];
75
96
  },
76
97
  rotationY: (n) => {
77
98
  const { normalX, normalZ } = fenceMidpointFrame(n);
@@ -80,6 +101,36 @@ function fenceHeightHandle() {
80
101
  },
81
102
  };
82
103
  }
104
+ function fenceElevationHandle(currentBase) {
105
+ return {
106
+ kind: 'linear-resize',
107
+ axis: 'y',
108
+ anchor: 'min',
109
+ shape: 'tracker',
110
+ gridSnap: true,
111
+ currentValue: () => currentBase,
112
+ magneticSnap: (n, newValue, sceneApi) => resolveStructuralElevationSnap(fenceElevationGuideSource(n), newValue, sceneApi.nodes()),
113
+ onDrag: (n, sceneApi) => publishStructuralElevationGuide(fenceElevationGuideSource(n), fenceBaseElevation(n, sceneApi), sceneApi.nodes()),
114
+ onDragEnd: (n) => clearStructuralElevationGuide(n.id),
115
+ apply: (initial, newBase, sceneApi) => {
116
+ // The offset is measured from the support WITHOUT the current offset —
117
+ // including the ground, so dragging a fence's base to an absolute height
118
+ // on a hillside stores the delta from that hillside and the fence keeps
119
+ // following it.
120
+ const supportBase = resolveFenceLiftElevationForNodes({ ...initial, supportOffset: undefined }, sceneApi.nodes());
121
+ const nextOffset = newBase - supportBase;
122
+ return {
123
+ supportOffset: Math.abs(nextOffset) < 1e-6 ? undefined : nextOffset,
124
+ };
125
+ },
126
+ placement: {
127
+ position: (n, sceneApi) => {
128
+ const { midX, midZ } = fenceMidpointFrame(n);
129
+ return [midX, fenceBaseElevation(n, sceneApi), midZ];
130
+ },
131
+ },
132
+ };
133
+ }
83
134
  // Corner picker — dashed vertical leader + billboarded hex disc at the
84
135
  // endpoint. Tap engages the endpoint-move flow (sister to the wall
85
136
  // pickers). nodeHeight controls the leader's vertical reach so the
@@ -92,9 +143,9 @@ function fenceCornerPicker(endpoint) {
92
143
  nodeHeight: (n) => n.height ?? 1.8,
93
144
  onActivate: (node, _scene, editor) => editor.engageEndpointMove(node, endpoint),
94
145
  placement: {
95
- position: (n) => {
146
+ position: (n, sceneApi) => {
96
147
  const corner = endpoint === 'start' ? n.start : n.end;
97
- return [corner[0], 0, corner[1]];
148
+ return [corner[0], fenceBaseElevation(n, sceneApi), corner[1]];
98
149
  },
99
150
  },
100
151
  };
@@ -108,9 +159,9 @@ function fenceControlPointPicker(index) {
108
159
  nodeHeight: (n) => n.height ?? 1.8,
109
160
  onActivate: (node, _scene, editor) => editor.engageControlPointMove(node, index),
110
161
  placement: {
111
- position: (n) => {
162
+ position: (n, sceneApi) => {
112
163
  const point = n.path?.[index] ?? n.start;
113
- return [point[0], 0, point[1]];
164
+ return [point[0], fenceBaseElevation(n, sceneApi), point[1]];
114
165
  },
115
166
  },
116
167
  };
@@ -125,23 +176,26 @@ function fenceTangentPicker(index, side) {
125
176
  nodeHeight: (n) => (n.height ?? 1.8) * 0.6,
126
177
  onActivate: (node, _scene, editor) => editor.engageTangentMove(node, index, side),
127
178
  placement: {
128
- position: (n) => {
179
+ position: (n, sceneApi) => {
129
180
  const point = n.path?.[index] ?? n.start;
181
+ const baseElevation = fenceBaseElevation(n, sceneApi);
130
182
  if (!n.path)
131
- return [point[0], 0, point[1]];
183
+ return [point[0], baseElevation, point[1]];
132
184
  const handle = getFenceControlHandle(n.path, n.tangents, index);
133
185
  return [
134
186
  point[0] + sign * handle.x * TANGENT_HANDLE_ARM_SCALE,
135
- 0,
187
+ baseElevation,
136
188
  point[1] + sign * handle.y * TANGENT_HANDLE_ARM_SCALE,
137
189
  ];
138
190
  },
139
191
  },
140
192
  };
141
193
  }
142
- const fenceHandles = (node) => {
194
+ const fenceHandles = (node, sceneApi) => {
195
+ const elevationHandle = fenceElevationHandle(fenceBaseElevation(node, sceneApi));
143
196
  if (isSplineFence(node) && node.path) {
144
197
  return [
198
+ elevationHandle,
145
199
  fenceHeightHandle(),
146
200
  ...node.path.flatMap((_, index) => [
147
201
  fenceControlPointPicker(index),
@@ -153,6 +207,7 @@ const fenceHandles = (node) => {
153
207
  return [
154
208
  fenceSideMoveHandle('front'),
155
209
  fenceSideMoveHandle('back'),
210
+ elevationHandle,
156
211
  fenceHeightHandle(),
157
212
  fenceCornerPicker('start'),
158
213
  fenceCornerPicker('end'),
@@ -174,7 +229,7 @@ const fenceHandles = (node) => {
174
229
  export const fenceDefinition = {
175
230
  kind: 'fence',
176
231
  snapProfile: 'structural',
177
- schemaVersion: 1,
232
+ schemaVersion: 2,
178
233
  schema: FenceNode,
179
234
  category: 'structure',
180
235
  surfaceRole: 'wall',
@@ -226,8 +281,13 @@ export const fenceDefinition = {
226
281
  tool: () => import('./tool'),
227
282
  // Stage B: pure geometry function. Generic <GeometrySystem> rebuilds
228
283
  // on dirtyNodes; <ParametricNodeRenderer> mounts the empty group.
229
- // `renderer` + `system` fields dropped along with their files.
230
284
  geometry: buildFenceGeometry,
285
+ // Dependency tracker only — a hosted railing (`supportSlabId`) renders at
286
+ // its slab's elevation, so host elevation edits must re-dirty the fence.
287
+ system: {
288
+ module: () => import('./system'),
289
+ priority: 4,
290
+ },
231
291
  // Stage C: floor-plan rendering. FloorplanRegistryLayer iterates kinds
232
292
  // with `floorplan` set and renders via FloorplanGeometryRenderer.
233
293
  // Legacy `floorplanFenceEntries` short-circuits to [] when fence is
@@ -1 +1 @@
1
- {"version":3,"file":"floorplan-affordances.d.ts","sourceRoot":"","sources":["../../src/fence/floorplan-affordances.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,SAAS,EACd,KAAK,mBAAmB,EAQzB,MAAM,kBAAkB,CAAA;AAoFzB;;;;;;;;;GASG;AACH,eAAO,MAAM,oBAAoB,EAAE,mBAAmB,CAAC,SAAS,CAsC/D,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,2BAA2B,EAAE,mBAAmB,CAAC,SAAS,CAqCtE,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB,EAAE,mBAAmB,CAAC,SAAS,CAoDjE,CAAA;AAED,eAAO,MAAM,2BAA2B,EAAE,mBAAmB,CAAC,SAAS,CAkFtE,CAAA"}
1
+ {"version":3,"file":"floorplan-affordances.d.ts","sourceRoot":"","sources":["../../src/fence/floorplan-affordances.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,SAAS,EACd,KAAK,mBAAmB,EASzB,MAAM,kBAAkB,CAAA;AAoFzB;;;;;;;;;GASG;AACH,eAAO,MAAM,oBAAoB,EAAE,mBAAmB,CAAC,SAAS,CAsC/D,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,2BAA2B,EAAE,mBAAmB,CAAC,SAAS,CAqCtE,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB,EAAE,mBAAmB,CAAC,SAAS,CAoDjE,CAAA;AAED,eAAO,MAAM,2BAA2B,EAAE,mBAAmB,CAAC,SAAS,CA4HtE,CAAA"}
@@ -1,4 +1,4 @@
1
- import { getMaxWallCurveOffset, getWallChordFrame, normalizeWallCurveOffset, useLiveNodeOverrides, useScene, } from '@pascal-app/core';
1
+ import { getMaxWallCurveOffset, getWallChordFrame, normalizeWallCurveOffset, resolveFenceSupportSlabPatch, useLiveNodeOverrides, useScene, } from '@pascal-app/core';
2
2
  import { alignFloorplanDraftPoint, getSegmentGridStep, isAlignmentGuideActive, isAngleSnapActive, isGridSnapActive, isMagneticSnapActive, isSegmentLongEnough, snapBuildingLocalToWorldGrid, snapFenceDraftPoint, snapScalarToGrid, useAlignmentGuides, } from '@pascal-app/editor';
3
3
  /**
4
4
  * Floor-plan 2D drag affordances for fence — sister to the 3D
@@ -204,6 +204,9 @@ export const fenceMoveEndpointAffordance = {
204
204
  const { walls, fences } = collectLevel(nodes, parentId);
205
205
  const linkedOriginals = collectLinkedFences(fences, node.id, originalMovingPoint);
206
206
  const affectedIds = [node.id, ...linkedOriginals.map((l) => l.id)];
207
+ let lastPatches = new Map();
208
+ let lastStart = originalStart;
209
+ let lastEnd = originalEnd;
207
210
  return {
208
211
  affectedIds,
209
212
  apply({ planPoint, modifiers }) {
@@ -249,22 +252,56 @@ export const fenceMoveEndpointAffordance = {
249
252
  start: pointsNearlyEqual(l.start, originalMovingPoint) ? aligned : l.start,
250
253
  end: pointsNearlyEqual(l.end, originalMovingPoint) ? aligned : l.end,
251
254
  }));
252
- useScene.getState().updateNodes([
253
- { id: node.id, data: { start: nextStart, end: nextEnd } },
254
- ...linkedUpdates.map((u) => ({
255
- id: u.id,
256
- data: { start: u.start, end: u.end },
257
- })),
255
+ lastStart = nextStart;
256
+ lastEnd = nextEnd;
257
+ const nextPatches = new Map([
258
+ [node.id, { start: nextStart, end: nextEnd }],
259
+ ...linkedUpdates.map((update) => [update.id, { start: update.start, end: update.end }]),
258
260
  ]);
261
+ // Re-elect the slab lift host as the endpoint drags (uncapped max
262
+ // election — 2D has no camera ray). Fences run no per-frame
263
+ // election: `supportSlabId` IS the lift.
264
+ const patchedNodes = { ...sceneNodes };
265
+ for (const [id, patch] of nextPatches) {
266
+ patchedNodes[id] = { ...patchedNodes[id], ...patch };
267
+ }
268
+ for (const id of nextPatches.keys()) {
269
+ const fence = patchedNodes[id];
270
+ if (fence?.type !== 'fence')
271
+ continue;
272
+ const patch = resolveFenceSupportSlabPatch(fence, patchedNodes);
273
+ if (patch.supportSlabId !== fence.supportSlabId) {
274
+ nextPatches.set(id, { ...nextPatches.get(id), ...patch });
275
+ }
276
+ }
277
+ const overrides = useLiveNodeOverrides.getState();
278
+ const scene = useScene.getState();
279
+ for (const linked of linkedOriginals) {
280
+ if (!nextPatches.has(linked.id)) {
281
+ overrides.clear(linked.id);
282
+ scene.markDirty(linked.id);
283
+ }
284
+ }
285
+ for (const [id, patch] of nextPatches) {
286
+ overrides.set(id, patch);
287
+ scene.markDirty(id);
288
+ }
289
+ lastPatches = nextPatches;
259
290
  },
260
291
  canCommit() {
261
292
  // Pointer-up always runs canCommit — drop the alignment guide here
262
293
  // so it doesn't linger after a commit / reject.
263
294
  useAlignmentGuides.getState().clear();
264
- const finalFence = useScene.getState().nodes[node.id];
265
- return (!!finalFence &&
266
- finalFence.type === 'fence' &&
267
- isSegmentLongEnough(finalFence.start, finalFence.end));
295
+ return isSegmentLongEnough(lastStart, lastEnd);
296
+ },
297
+ commit() {
298
+ useScene.getState().updateNodes(Array.from(lastPatches, ([id, data]) => ({
299
+ id,
300
+ data,
301
+ })));
302
+ const overrides = useLiveNodeOverrides.getState();
303
+ for (const id of affectedIds)
304
+ overrides.clear(id);
268
305
  },
269
306
  };
270
307
  },
@@ -1 +1 @@
1
- {"version":3,"file":"floorplan-move.d.ts","sourceRoot":"","sources":["../../src/fence/floorplan-move.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,SAAS,EACd,KAAK,mBAAmB,EAIzB,MAAM,kBAAkB,CAAA;AAuDzB;;;;;;GAMG;AACH,eAAO,MAAM,wBAAwB,EAAE,mBAAmB,CAAC,SAAS,CAiJnE,CAAA"}
1
+ {"version":3,"file":"floorplan-move.d.ts","sourceRoot":"","sources":["../../src/fence/floorplan-move.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,SAAS,EACd,KAAK,mBAAmB,EAKzB,MAAM,kBAAkB,CAAA;AAuDzB;;;;;;GAMG;AACH,eAAO,MAAM,wBAAwB,EAAE,mBAAmB,CAAC,SAAS,CA4LnE,CAAA"}
@@ -1,4 +1,4 @@
1
- import { useLiveNodeOverrides, useScene, } from '@pascal-app/core';
1
+ import { resolveFenceSupportSlabPatch, useLiveNodeOverrides, useScene, } from '@pascal-app/core';
2
2
  import { getSegmentGridStep, isGridSnapActive, isSegmentLongEnough, snapPointToGrid, } from '@pascal-app/editor';
3
3
  import { useViewer } from '@pascal-app/viewer';
4
4
  function pointsEqual(a, b) {
@@ -125,6 +125,27 @@ export const fenceFloorplanMoveTarget = ({ node }) => {
125
125
  // tracked change. Drop the override AFTER the scene write so
126
126
  // mid-commit reads still see the new position (override wins until
127
127
  // cleared; scene wins after).
128
+ // The re-elected slab lift host rides in the same write (uncapped max
129
+ // election — 2D has no camera ray): a fence moved onto / off an
130
+ // elevated deck must land on the right surface, since fences run no
131
+ // per-frame election (`supportSlabId` IS the lift). One updateNodes
132
+ // keeps the whole move a single tracked change. Election runs on the
133
+ // committed endpoints against the pre-write store (the patch only
134
+ // reads the parent level + the slab grid).
135
+ const baselineNodes = useScene.getState().nodes;
136
+ const supportFor = (start, end, path, id) => {
137
+ const fence = baselineNodes[id];
138
+ return fence?.type === 'fence'
139
+ ? resolveFenceSupportSlabPatch({
140
+ start,
141
+ end,
142
+ path,
143
+ curveOffset: fence.curveOffset,
144
+ thickness: fence.thickness,
145
+ parentId: fence.parentId,
146
+ }, baselineNodes)
147
+ : {};
148
+ };
128
149
  const fenceUpdate = isNew
129
150
  ? {
130
151
  id: fenceId,
@@ -133,9 +154,18 @@ export const fenceFloorplanMoveTarget = ({ node }) => {
133
154
  end: lastNextEnd,
134
155
  path: lastNextPath,
135
156
  metadata: { ...originalMetadata, isNew: false },
157
+ ...supportFor(lastNextStart, lastNextEnd, lastNextPath, fenceId),
136
158
  },
137
159
  }
138
- : { id: fenceId, data: { start: lastNextStart, end: lastNextEnd, path: lastNextPath } };
160
+ : {
161
+ id: fenceId,
162
+ data: {
163
+ start: lastNextStart,
164
+ end: lastNextEnd,
165
+ path: lastNextPath,
166
+ ...supportFor(lastNextStart, lastNextEnd, lastNextPath, fenceId),
167
+ },
168
+ };
139
169
  const linkedUpdates = linkedOriginals.map((l) => ({
140
170
  id: l.id,
141
171
  ...projectLinked(l, lastNextStart, lastNextEnd, lastDelta[0], lastDelta[1]),
@@ -144,7 +174,12 @@ export const fenceFloorplanMoveTarget = ({ node }) => {
144
174
  fenceUpdate,
145
175
  ...linkedUpdates.map((u) => ({
146
176
  id: u.id,
147
- data: { start: u.start, end: u.end, path: u.path },
177
+ data: {
178
+ start: u.start,
179
+ end: u.end,
180
+ path: u.path,
181
+ ...supportFor(u.start, u.end, u.path, u.id),
182
+ },
148
183
  })),
149
184
  ]);
150
185
  const overrides = useLiveNodeOverrides.getState();
@@ -1 +1 @@
1
- {"version":3,"file":"geometry.d.ts","sourceRoot":"","sources":["../../src/fence/geometry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,eAAe,EAA0B,MAAM,kBAAkB,CAAA;AAC/E,OAAO,EAEL,KAAK,WAAW,EAKhB,KAAK,aAAa,EAGnB,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EAAa,KAAK,EAAqC,MAAM,OAAO,CAAA;AAC3E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAwFzC,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,SAAS,EACf,GAAG,CAAC,EAAE,eAAe,EACrB,OAAO,GAAE,aAA0B,EACnC,QAAQ,UAAO,EACf,WAAW,GAAE,WAAoB,EACjC,UAAU,CAAC,EAAE,MAAM,GAClB,KAAK,CAwBP"}
1
+ {"version":3,"file":"geometry.d.ts","sourceRoot":"","sources":["../../src/fence/geometry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,eAAe,EAA0B,MAAM,kBAAkB,CAAA;AAC/F,OAAO,EAEL,KAAK,WAAW,EAKhB,KAAK,aAAa,EAGnB,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EAAa,KAAK,EAAqC,MAAM,OAAO,CAAA;AAE3E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAwFzC,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,SAAS,EACf,GAAG,CAAC,EAAE,eAAe,EACrB,OAAO,GAAE,aAA0B,EACnC,QAAQ,UAAO,EACf,WAAW,GAAE,WAAoB,EACjC,UAAU,CAAC,EAAE,MAAM,GAClB,KAAK,CA0CP"}
@@ -1,6 +1,7 @@
1
1
  import { getMaterialPresetByRef } from '@pascal-app/core';
2
2
  import { applyMaterialPresetToMaterials, createDefaultMaterial, createMaterial, createSurfaceRoleMaterial, generateFenceSlotGeometries, resolveMaterialRef, resolveSlotDefaultMaterial, } from '@pascal-app/viewer';
3
3
  import { FrontSide, Group, Mesh } from 'three';
4
+ import { resolveFenceLiftElevation } from './lift';
4
5
  import { FENCE_SLOT_DEFAULTS } from './slots';
5
6
  const FENCE_SLOT_ORDER = ['posts', 'infill', 'base', 'rail'];
6
7
  const fenceMaterialCache = new Map();
@@ -50,6 +51,19 @@ function getLegacyFenceMaterial(node, shading) {
50
51
  export function buildFenceGeometry(node, ctx, shading = 'rendered', textures = true, colorPreset = 'clay', sceneTheme) {
51
52
  const group = new Group();
52
53
  const geometries = generateFenceSlotGeometries(node);
54
+ // A hosted railing (`supportSlabId`) stands on its slab's walking surface;
55
+ // an unhosted one stands on the ground, which `ctx.levelBaseAt` resolves at
56
+ // the fence's own start point — the anchor its plan geometry is measured
57
+ // from, so the resolver and the mesh cannot disagree about where the ground
58
+ // is under this fence. The builder emits local-space children, so the lift
59
+ // lives on an inner group rather than the registered (React-transformed)
60
+ // root.
61
+ const lift = ctx
62
+ ? resolveFenceLiftElevation(node, (id) => ctx.resolve(id), ctx.levelBaseAt?.(node.start[0], node.start[1]) ?? 0)
63
+ : 0;
64
+ const meshParent = new Group();
65
+ meshParent.position.y = lift;
66
+ group.add(meshParent);
53
67
  for (const slotId of FENCE_SLOT_ORDER) {
54
68
  const geometry = geometries[slotId];
55
69
  if (geometry.getAttribute('position') === undefined)
@@ -59,7 +73,7 @@ export function buildFenceGeometry(node, ctx, shading = 'rendered', textures = t
59
73
  mesh.castShadow = true;
60
74
  mesh.receiveShadow = true;
61
75
  mesh.userData.slotId = slotId;
62
- group.add(mesh);
76
+ meshParent.add(mesh);
63
77
  }
64
78
  return group;
65
79
  }
@@ -0,0 +1,38 @@
1
+ import { type AnyNode } from '@pascal-app/core';
2
+ import type { FenceNode } from './schema';
3
+ /**
4
+ * Elevation (meters above the level plane) a hosted fence stands at.
5
+ *
6
+ * A fence carrying `supportSlabId` is a railing on that slab's walking
7
+ * surface (drawn onto a deck, or placed by a deck preset). The
8
+ * host pins the lift only while it still exists as a slab on the fence's
9
+ * own level — a stale host (deleted slab, reparented fence) silently
10
+ * falls back to the level floor, mirroring the read-path rules of the
11
+ * other `supportSlabId` carriers. Pure so it is unit-testable and
12
+ * callable from the geometry builder with `ctx.resolve`.
13
+ *
14
+ * `levelBase` is what "the level floor" means here — the sculpted ground
15
+ * under the fence (`levelBaseElevationAt`, reached through `ctx.levelBaseAt`
16
+ * in the builder and {@link resolveFenceLiftElevationForNodes} everywhere
17
+ * else), or 0 for a level with no terrain under it. A caller-resolved scalar
18
+ * rather than a terrain lookup inside, so this stays pure and the sample stays
19
+ * at the caller's chosen point; it substitutes for the literal `0` this used to
20
+ * return in every unhosted branch, and nowhere else — a host slab that still
21
+ * exists wins outright, so a railing on a deck pad keeps the pad's elevation
22
+ * instead of following the hillside around it.
23
+ */
24
+ export declare function resolveFenceLiftElevation(node: Pick<FenceNode, 'supportSlabId' | 'supportOffset' | 'parentId'>, resolve: (id: string) => AnyNode | undefined, levelBase?: number): number;
25
+ /**
26
+ * {@link resolveFenceLiftElevation} against a nodes record, with the level base
27
+ * resolved from the terrain under the fence's start point — the same anchor the
28
+ * geometry builder samples, so a handle, a snap guide and the rendered rail all
29
+ * agree about where the ground is.
30
+ *
31
+ * Exists so the callers that already hold the whole scene (handles via
32
+ * `sceneApi.nodes()`, the dependency tracker, the editor's elevation guides)
33
+ * don't each re-derive the level walk and the sample point. The builder keeps
34
+ * using the pure form, since `GeometryContext` deliberately exposes the ground
35
+ * as a closure rather than the store.
36
+ */
37
+ export declare function resolveFenceLiftElevationForNodes(node: Pick<FenceNode, 'id' | 'start' | 'supportSlabId' | 'supportOffset' | 'parentId'>, nodes: Record<string, AnyNode>): number;
38
+ //# sourceMappingURL=lift.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lift.d.ts","sourceRoot":"","sources":["../../src/fence/lift.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,OAAO,EAKb,MAAM,kBAAkB,CAAA;AACzB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAEzC;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,eAAe,GAAG,eAAe,GAAG,UAAU,CAAC,EACrE,OAAO,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,GAAG,SAAS,EAC5C,SAAS,SAAI,GACZ,MAAM,CAQR;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iCAAiC,CAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,GAAG,OAAO,GAAG,eAAe,GAAG,eAAe,GAAG,UAAU,CAAC,EACtF,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,MAAM,CAIR"}
@@ -0,0 +1,51 @@
1
+ import { findLevelAncestorId, levelBaseElevationAt, } from '@pascal-app/core';
2
+ /**
3
+ * Elevation (meters above the level plane) a hosted fence stands at.
4
+ *
5
+ * A fence carrying `supportSlabId` is a railing on that slab's walking
6
+ * surface (drawn onto a deck, or placed by a deck preset). The
7
+ * host pins the lift only while it still exists as a slab on the fence's
8
+ * own level — a stale host (deleted slab, reparented fence) silently
9
+ * falls back to the level floor, mirroring the read-path rules of the
10
+ * other `supportSlabId` carriers. Pure so it is unit-testable and
11
+ * callable from the geometry builder with `ctx.resolve`.
12
+ *
13
+ * `levelBase` is what "the level floor" means here — the sculpted ground
14
+ * under the fence (`levelBaseElevationAt`, reached through `ctx.levelBaseAt`
15
+ * in the builder and {@link resolveFenceLiftElevationForNodes} everywhere
16
+ * else), or 0 for a level with no terrain under it. A caller-resolved scalar
17
+ * rather than a terrain lookup inside, so this stays pure and the sample stays
18
+ * at the caller's chosen point; it substitutes for the literal `0` this used to
19
+ * return in every unhosted branch, and nowhere else — a host slab that still
20
+ * exists wins outright, so a railing on a deck pad keeps the pad's elevation
21
+ * instead of following the hillside around it.
22
+ */
23
+ export function resolveFenceLiftElevation(node, resolve, levelBase = 0) {
24
+ const offset = node.supportOffset ?? 0;
25
+ if (!node.supportSlabId)
26
+ return levelBase + offset;
27
+ const host = resolve(node.supportSlabId);
28
+ if (host?.type !== 'slab')
29
+ return levelBase + offset;
30
+ if ((host.parentId ?? null) !== (node.parentId ?? null))
31
+ return levelBase + offset;
32
+ const elevation = host.elevation;
33
+ return (Number.isFinite(elevation) ? elevation : 0) + offset;
34
+ }
35
+ /**
36
+ * {@link resolveFenceLiftElevation} against a nodes record, with the level base
37
+ * resolved from the terrain under the fence's start point — the same anchor the
38
+ * geometry builder samples, so a handle, a snap guide and the rendered rail all
39
+ * agree about where the ground is.
40
+ *
41
+ * Exists so the callers that already hold the whole scene (handles via
42
+ * `sceneApi.nodes()`, the dependency tracker, the editor's elevation guides)
43
+ * don't each re-derive the level walk and the sample point. The builder keeps
44
+ * using the pure form, since `GeometryContext` deliberately exposes the ground
45
+ * as a closure rather than the store.
46
+ */
47
+ export function resolveFenceLiftElevationForNodes(node, nodes) {
48
+ const levelId = findLevelAncestorId(node.id, nodes);
49
+ const levelBase = levelId ? levelBaseElevationAt(nodes, levelId, node.start[0], node.start[1]) : 0;
50
+ return resolveFenceLiftElevation(node, (id) => nodes[id], levelBase);
51
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"move-tool.d.ts","sourceRoot":"","sources":["../../src/fence/move-tool.tsx"],"names":[],"mappings":"AAEA,OAAO,EAIL,KAAK,SAAS,EAUf,MAAM,kBAAkB,CAAA;AAsHzB,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,CAwQvD,CAAA;AAED,eAAe,aAAa,CAAA"}
1
+ {"version":3,"file":"move-tool.d.ts","sourceRoot":"","sources":["../../src/fence/move-tool.tsx"],"names":[],"mappings":"AAEA,OAAO,EAIL,KAAK,SAAS,EAWf,MAAM,kBAAkB,CAAA;AAsHzB,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,CAgSvD,CAAA;AAED,eAAe,aAAa,CAAA"}
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
- import { constrainWallMoveDeltaToAxis, emitter, getPerpendicularWallMoveAxis, isCurvedWall, isSplineFence, useLiveNodeOverrides, useScene, } from '@pascal-app/core';
3
+ import { constrainWallMoveDeltaToAxis, emitter, getPerpendicularWallMoveAxis, isCurvedWall, isSplineFence, resolveFenceSupportSlabPatch, useLiveNodeOverrides, useScene, } from '@pascal-app/core';
4
4
  import { CursorSphere, consumePlacementDragRelease, getSegmentGridStep, isGridSnapActive, isMagneticSnapActive, markToolCancelConsumed, snapFenceDraftPoint, triggerSFX, useEditor, } from '@pascal-app/editor';
5
5
  import { useViewer } from '@pascal-app/viewer';
6
6
  import { useCallback, useEffect, useRef, useState } from 'react';
@@ -132,10 +132,30 @@ export const MoveFenceTool = ({ node }) => {
132
132
  }
133
133
  };
134
134
  const applyCommittedUpdates = (updates) => {
135
- useScene.getState().updateNodes(updates.map((entry) => ({
136
- id: entry.id,
137
- data: { start: entry.start, end: entry.end, path: entry.path },
138
- })));
135
+ // Fold the re-elected slab lift host into the same write — a fence
136
+ // moved onto / off an elevated deck must land on the right surface
137
+ // (fences run no per-frame election; `supportSlabId` IS the lift),
138
+ // and one updateNodes keeps the whole move a single undo step.
139
+ // Election runs on the committed endpoints against the pre-write
140
+ // store (the patch only reads the parent level + the slab grid).
141
+ const baselineNodes = useScene.getState().nodes;
142
+ useScene.getState().updateNodes(updates.map((entry) => {
143
+ const fence = baselineNodes[entry.id];
144
+ const support = fence?.type === 'fence'
145
+ ? resolveFenceSupportSlabPatch({
146
+ start: entry.start,
147
+ end: entry.end,
148
+ path: entry.path,
149
+ curveOffset: fence.curveOffset,
150
+ thickness: fence.thickness,
151
+ parentId: fence.parentId,
152
+ }, baselineNodes)
153
+ : {};
154
+ return {
155
+ id: entry.id,
156
+ data: { start: entry.start, end: entry.end, path: entry.path, ...support },
157
+ };
158
+ }));
139
159
  for (const entry of updates) {
140
160
  useScene.getState().markDirty(entry.id);
141
161
  }
@@ -0,0 +1,3 @@
1
+ declare const FenceSystems: () => null;
2
+ export default FenceSystems;
3
+ //# sourceMappingURL=system.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"system.d.ts","sourceRoot":"","sources":["../../src/fence/system.tsx"],"names":[],"mappings":"AAiCA,QAAA,MAAM,YAAY,YAgBjB,CAAA;AAED,eAAe,YAAY,CAAA"}
@@ -0,0 +1,46 @@
1
+ 'use client';
2
+ import { useScene } from '@pascal-app/core';
3
+ import { useEffect } from 'react';
4
+ import { resolveFenceLiftElevationForNodes } from './lift';
5
+ /**
6
+ * Hosted-railing dependency tracker. A fence with `supportSlabId` renders at
7
+ * its host slab's elevation, but a store update only dirties the node that
8
+ * changed — editing the slab's elevation (or restoring a deleted host) would
9
+ * leave the railing floating at the stale height. Watch each hosted fence's
10
+ * resolved lift and dirty the fence when it moves; `GeometrySystem` rebuilds
11
+ * through `def.geometry` as usual. (Deleting the host needs no help here:
12
+ * `deleteNodesAction` strips `supportSlabId` and dirties the fence itself.)
13
+ */
14
+ function fenceLiftSignatures(nodes) {
15
+ const signatures = new Map();
16
+ for (const node of Object.values(nodes)) {
17
+ if (node.type !== 'fence')
18
+ continue;
19
+ const fence = node;
20
+ // Unhosted fences are covered too, and by a different mechanism: their lift
21
+ // is the ground, which only a sculpt moves, and `markTerrainSupportDependents`
22
+ // dirties them from the terrain change itself. Tracking them here would
23
+ // resolve every fence in the scene on every store update to catch an event
24
+ // this subscription never sees.
25
+ if (!fence.supportSlabId)
26
+ continue;
27
+ signatures.set(fence.id, resolveFenceLiftElevationForNodes(fence, nodes));
28
+ }
29
+ return signatures;
30
+ }
31
+ const FenceSystems = () => {
32
+ useEffect(() => {
33
+ let previous = fenceLiftSignatures(useScene.getState().nodes);
34
+ return useScene.subscribe((state) => {
35
+ const current = fenceLiftSignatures(state.nodes);
36
+ for (const [fenceId, lift] of current.entries()) {
37
+ if (previous.get(fenceId) !== lift) {
38
+ state.markDirty(fenceId);
39
+ }
40
+ }
41
+ previous = current;
42
+ });
43
+ }, []);
44
+ return null;
45
+ };
46
+ export default FenceSystems;
@@ -1 +1 @@
1
- {"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../src/fence/tool.tsx"],"names":[],"mappings":"AAqbA,eAAO,MAAM,SAAS,EAAE,KAAK,CAAC,EAM7B,CAAA;AA+cD,eAAe,SAAS,CAAA"}
1
+ {"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../src/fence/tool.tsx"],"names":[],"mappings":"AAycA,eAAO,MAAM,SAAS,EAAE,KAAK,CAAC,EAM7B,CAAA;AAweD,eAAe,SAAS,CAAA"}