@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
@@ -0,0 +1,300 @@
1
+ import { withFloorplanGeometryMetadata } from '@pascal-app/editor';
2
+ import { formatConstructionLength, } from './construction-length';
3
+ export function computeDoorFloorplanLevelData(args) {
4
+ return resolveOpeningMarks(args.siblings, args.nodes, 'door');
5
+ }
6
+ export function computeWindowFloorplanLevelData(args) {
7
+ return resolveOpeningMarks(args.siblings, args.nodes, 'window');
8
+ }
9
+ export function buildDoorFloorplanSchedule(args) {
10
+ if (args.siblings.length === 0)
11
+ return null;
12
+ const marks = resolveOpeningMarks(args.siblings, args.nodes, 'door', args.levelId);
13
+ return {
14
+ id: 'doors',
15
+ title: 'DOOR SCHEDULE',
16
+ columns: [
17
+ { key: 'mark', label: 'MARK', weight: 0.65 },
18
+ { key: 'type', label: 'TYPE', weight: 1.25 },
19
+ { key: 'size', label: 'NOMINAL SIZE', weight: 1.35 },
20
+ { key: 'roughOpening', label: 'ROUGH OPENING', weight: 1.35 },
21
+ { key: 'operation', label: 'OPERATION', weight: 1.35 },
22
+ { key: 'frame', label: 'FRAME T / D', weight: 1.25 },
23
+ { key: 'hardware', label: 'HARDWARE', weight: 1.35 },
24
+ ],
25
+ rows: args.siblings.map((door) => ({
26
+ id: door.id,
27
+ cells: {
28
+ mark: marks.markById.get(door.id) ?? '—',
29
+ type: door.openingKind === 'opening' ? 'Opening' : titleCase(door.doorType),
30
+ size: formatSize(door.width, door.height, args.unit, args.profile ?? 'document'),
31
+ roughOpening: formatRoughOpening(door, args.unit, args.profile ?? 'document'),
32
+ operation: doorOperation(door),
33
+ frame: `${formatConstructionLength(door.frameThickness, args.unit, args.profile ?? 'document')} / ${formatConstructionLength(door.frameDepth, args.unit, args.profile ?? 'document')}`,
34
+ hardware: doorHardware(door),
35
+ },
36
+ })),
37
+ issues: marks.issues,
38
+ };
39
+ }
40
+ export function buildWindowFloorplanSchedule(args) {
41
+ if (args.siblings.length === 0)
42
+ return null;
43
+ const marks = resolveOpeningMarks(args.siblings, args.nodes, 'window', args.levelId);
44
+ return {
45
+ id: 'windows',
46
+ title: 'WINDOW SCHEDULE',
47
+ columns: [
48
+ { key: 'mark', label: 'MARK', weight: 0.65 },
49
+ { key: 'type', label: 'TYPE', weight: 1.2 },
50
+ { key: 'size', label: 'NOMINAL SIZE', weight: 1.35 },
51
+ { key: 'roughOpening', label: 'ROUGH OPENING', weight: 1.35 },
52
+ { key: 'sill', label: 'SILL', weight: 0.9 },
53
+ { key: 'head', label: 'HEAD', weight: 0.9 },
54
+ { key: 'operation', label: 'OPERATION', weight: 1.35 },
55
+ ],
56
+ rows: args.siblings.map((window) => ({
57
+ id: window.id,
58
+ cells: {
59
+ mark: marks.markById.get(window.id) ?? '—',
60
+ type: window.openingKind === 'opening' ? 'Opening' : titleCase(window.windowType),
61
+ size: formatSize(window.width, window.height, args.unit, args.profile ?? 'document'),
62
+ roughOpening: formatRoughOpening(window, args.unit, args.profile ?? 'document'),
63
+ sill: formatConstructionLength(Math.max(0, window.position[1] - window.height / 2), args.unit, args.profile ?? 'document'),
64
+ head: formatConstructionLength(window.position[1] + window.height / 2, args.unit, args.profile ?? 'document'),
65
+ operation: windowOperation(window),
66
+ },
67
+ })),
68
+ issues: marks.issues,
69
+ };
70
+ }
71
+ export function buildOpeningMarkAnnotation(opening, wall, levelData, { preferredSide = -1, stroke = '#334155', } = {}) {
72
+ const dx = wall.end[0] - wall.start[0];
73
+ const dz = wall.end[1] - wall.start[1];
74
+ const wallLength = Math.hypot(dx, dz);
75
+ if (wallLength < 1e-6)
76
+ return null;
77
+ const dirX = dx / wallLength;
78
+ const dirZ = dz / wallLength;
79
+ const normalX = -dirZ;
80
+ const normalZ = dirX;
81
+ const side = interiorSide(wall, preferredSide);
82
+ const openingCenterX = wall.start[0] + dirX * opening.position[0];
83
+ const openingCenterZ = wall.start[1] + dirZ * opening.position[0];
84
+ const halfDepth = (wall.thickness ?? 0.1) / 2;
85
+ const bubbleOffset = halfDepth + 0.5;
86
+ const bubbleX = openingCenterX + normalX * bubbleOffset * side;
87
+ const bubbleZ = openingCenterZ + normalZ * bubbleOffset * side;
88
+ const explicitMark = opening.mark?.trim();
89
+ const mark = levelData?.markById.get(opening.id) ?? (explicitMark || fallbackMark(opening));
90
+ const bubbleWidth = Math.max(0.38, mark.length * 0.105 + 0.18);
91
+ const bubbleHeight = 0.32;
92
+ const leaderEndOffset = bubbleOffset - bubbleHeight / 2;
93
+ return withFloorplanGeometryMetadata({
94
+ kind: 'group',
95
+ children: [
96
+ {
97
+ kind: 'line',
98
+ x1: openingCenterX + normalX * halfDepth * side,
99
+ y1: openingCenterZ + normalZ * halfDepth * side,
100
+ x2: openingCenterX + normalX * leaderEndOffset * side,
101
+ y2: openingCenterZ + normalZ * leaderEndOffset * side,
102
+ stroke,
103
+ strokeWidth: 0.018,
104
+ },
105
+ {
106
+ kind: 'rect',
107
+ x: bubbleX - bubbleWidth / 2,
108
+ y: bubbleZ - bubbleHeight / 2,
109
+ width: bubbleWidth,
110
+ height: bubbleHeight,
111
+ rx: bubbleHeight / 2,
112
+ ry: bubbleHeight / 2,
113
+ fill: '#ffffff',
114
+ stroke,
115
+ strokeWidth: 0.02,
116
+ },
117
+ {
118
+ kind: 'text',
119
+ x: bubbleX,
120
+ y: bubbleZ,
121
+ text: mark,
122
+ fontSize: 0.15,
123
+ fill: stroke,
124
+ fontWeight: 700,
125
+ fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace',
126
+ textAnchor: 'middle',
127
+ dominantBaseline: 'middle',
128
+ upright: true,
129
+ },
130
+ ],
131
+ }, { annotationRole: 'opening-mark' });
132
+ }
133
+ export function resolveOpeningDimensionDocumentation(opening) {
134
+ const constructionType = opening.constructionType ?? 'framed';
135
+ const requestedReference = constructionType === 'masonry' &&
136
+ opening.dimensionReference === 'nominal' &&
137
+ opening.masonryOpeningWidth !== undefined
138
+ ? 'masonry-opening'
139
+ : (opening.dimensionReference ?? 'nominal');
140
+ const dimensions = openingDocumentationDimensions(opening, requestedReference);
141
+ return {
142
+ constructionType,
143
+ reference: requestedReference,
144
+ locationPolicy: constructionType === 'masonry' ? 'edge-to-edge' : 'centerline',
145
+ width: dimensions.width,
146
+ height: dimensions.height,
147
+ prefix: openingDimensionPrefix(requestedReference),
148
+ verified: requestedReference === 'nominal' || dimensions.width !== null,
149
+ };
150
+ }
151
+ function resolveOpeningMarks(openings, nodes, kind, explicitLevelId) {
152
+ const markById = new Map();
153
+ const explicitMarks = new Map();
154
+ const used = new Set();
155
+ for (const opening of openings) {
156
+ const mark = opening.mark?.trim();
157
+ if (!mark)
158
+ continue;
159
+ markById.set(opening.id, mark);
160
+ used.add(mark.toLocaleUpperCase());
161
+ const normalized = mark.toLocaleUpperCase();
162
+ const ids = explicitMarks.get(normalized);
163
+ if (ids)
164
+ ids.push(opening.id);
165
+ else
166
+ explicitMarks.set(normalized, [opening.id]);
167
+ }
168
+ const level = resolveLevel(openings[0], nodes, explicitLevelId);
169
+ let sequence = 1;
170
+ for (const opening of openings) {
171
+ if (markById.has(opening.id))
172
+ continue;
173
+ let candidate = automaticMark(kind, level?.level ?? 0, sequence);
174
+ while (used.has(candidate.toLocaleUpperCase())) {
175
+ sequence++;
176
+ candidate = automaticMark(kind, level?.level ?? 0, sequence);
177
+ }
178
+ markById.set(opening.id, candidate);
179
+ used.add(candidate.toLocaleUpperCase());
180
+ sequence++;
181
+ }
182
+ const issues = [...explicitMarks.entries()]
183
+ .filter(([, ids]) => ids.length > 1)
184
+ .map(([mark, ids]) => `Duplicate ${kind} mark ${mark} (${ids.length} instances)`);
185
+ return { markById, issues };
186
+ }
187
+ function resolveLevel(opening, nodes, explicitLevelId) {
188
+ const explicit = explicitLevelId ? nodes[explicitLevelId] : undefined;
189
+ if (explicit?.type === 'level')
190
+ return explicit;
191
+ let current = opening;
192
+ const visited = new Set();
193
+ while (current?.parentId && !visited.has(current.parentId)) {
194
+ visited.add(current.parentId);
195
+ current = nodes[current.parentId];
196
+ if (current?.type === 'level')
197
+ return current;
198
+ }
199
+ return undefined;
200
+ }
201
+ function automaticMark(kind, level, sequence) {
202
+ if (kind === 'door')
203
+ return String((Math.max(0, level) + 1) * 100 + sequence);
204
+ return `W${String(sequence).padStart(2, '0')}`;
205
+ }
206
+ function fallbackMark(opening) {
207
+ return opening.type === 'door' ? 'D?' : 'W?';
208
+ }
209
+ function interiorSide(wall, fallback) {
210
+ if (wall.frontSide === 'exterior' && wall.backSide !== 'exterior')
211
+ return -1;
212
+ if (wall.backSide === 'exterior' && wall.frontSide !== 'exterior')
213
+ return 1;
214
+ return fallback;
215
+ }
216
+ function formatSize(width, height, unit, profile) {
217
+ return `${formatConstructionLength(width, unit, profile)} x ${formatConstructionLength(height, unit, profile)}`;
218
+ }
219
+ function formatRoughOpening(opening, unit, profile) {
220
+ if (opening.roughOpeningWidth === undefined || opening.roughOpeningHeight === undefined) {
221
+ return 'VERIFY';
222
+ }
223
+ return formatSize(opening.roughOpeningWidth, opening.roughOpeningHeight, unit, profile);
224
+ }
225
+ function openingDocumentationDimensions(opening, reference) {
226
+ switch (reference) {
227
+ case 'nominal':
228
+ return { width: opening.width, height: opening.height };
229
+ case 'rough-opening':
230
+ return {
231
+ width: opening.roughOpeningWidth ?? null,
232
+ height: opening.roughOpeningHeight ?? null,
233
+ };
234
+ case 'masonry-opening':
235
+ return {
236
+ width: opening.masonryOpeningWidth ?? null,
237
+ height: opening.masonryOpeningHeight ?? null,
238
+ };
239
+ case 'finish-opening':
240
+ return {
241
+ width: opening.finishOpeningWidth ?? null,
242
+ height: opening.finishOpeningHeight ?? null,
243
+ };
244
+ }
245
+ }
246
+ function openingDimensionPrefix(reference) {
247
+ switch (reference) {
248
+ case 'nominal':
249
+ return '';
250
+ case 'rough-opening':
251
+ return 'RO';
252
+ case 'masonry-opening':
253
+ return 'MO';
254
+ case 'finish-opening':
255
+ return 'FO';
256
+ }
257
+ }
258
+ function doorOperation(door) {
259
+ if (door.openingKind === 'opening')
260
+ return 'None';
261
+ if (door.doorType === 'hinged')
262
+ return `${titleCase(door.hingesSide)} / ${titleCase(door.swingDirection)}`;
263
+ if (door.doorType === 'sliding' || door.doorType === 'pocket' || door.doorType === 'barn') {
264
+ return `Slide ${titleCase(door.slideDirection)}`;
265
+ }
266
+ return titleCase(door.doorType);
267
+ }
268
+ function doorHardware(door) {
269
+ if (door.openingKind === 'opening')
270
+ return 'None';
271
+ const hardware = [];
272
+ if (door.doorCloser)
273
+ hardware.push('Closer');
274
+ if (door.panicBar)
275
+ hardware.push('Panic bar');
276
+ if (door.threshold)
277
+ hardware.push('Threshold');
278
+ return hardware.length > 0 ? hardware.join(', ') : 'Standard';
279
+ }
280
+ function windowOperation(window) {
281
+ if (window.openingKind === 'opening')
282
+ return 'None';
283
+ if (window.windowType === 'fixed')
284
+ return 'Fixed';
285
+ if (window.windowType === 'casement') {
286
+ return window.casementStyle === 'french'
287
+ ? 'French casement'
288
+ : `${titleCase(window.hingesSide)} hinge`;
289
+ }
290
+ if (window.windowType === 'awning' || window.windowType === 'hopper') {
291
+ return titleCase(window.awningDirection);
292
+ }
293
+ return titleCase(window.windowType);
294
+ }
295
+ function titleCase(value) {
296
+ return value
297
+ .split('-')
298
+ .map((part) => part.charAt(0).toLocaleUpperCase() + part.slice(1))
299
+ .join(' ');
300
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"opening-guides-runtime.d.ts","sourceRoot":"","sources":["../../src/shared/opening-guides-runtime.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,KAAK,OAAO,EAIZ,KAAK,WAAW,EAIhB,KAAK,QAAQ,EACd,MAAM,kBAAkB,CAAA;AASzB;;qFAEqF;AACrF,KAAK,OAAO,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;AAEjE,sEAAsE;AACtE,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,QAAQ,EACd,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,WAAW,EAAE,CAgBf;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE;IACpC,IAAI,EAAE,QAAQ,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAC/B,GAAG,MAAM,GAAG,IAAI,CAchB;AAED,2EAA2E;AAC3E,wBAAgB,sBAAsB,CAAC,IAAI,EAAE;IAC3C,IAAI,EAAE,QAAQ,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,eAAe,EAAE,OAAO,CAAA;IACxB,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAC/B,GAAG,IAAI,CA2EP;AAED,wBAAgB,oBAAoB,IAAI,IAAI,CAE3C;AAiBD;yEACyE;AACzE,wBAAgB,WAAW,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CASnD;AAED;;;;;GAKG;AACH,wBAAgB,gCAAgC,CAAC,IAAI,EAAE;IACrD,IAAI,EAAE,QAAQ,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,eAAe,EAAE,OAAO,CAAA;IACxB,YAAY,EAAE,MAAM,CAAA;IACpB,aAAa,EAAE,MAAM,CAAA;CACtB,GAAG,IAAI,CAQP;AAED;;;;;GAKG;AACH,wBAAgB,0BAA0B,CACxC,IAAI,EAAE;IACJ,EAAE,EAAE,MAAM,CAAA;IACV,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,QAAQ,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IAC3C,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;CACf,EACD,eAAe,EAAE,OAAO,GACvB,IAAI,CAeN"}
1
+ {"version":3,"file":"opening-guides-runtime.d.ts","sourceRoot":"","sources":["../../src/shared/opening-guides-runtime.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,KAAK,OAAO,EAIZ,KAAK,WAAW,EAIhB,KAAK,QAAQ,EACd,MAAM,kBAAkB,CAAA;AAUzB;;qFAEqF;AACrF,KAAK,OAAO,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;AAEjE,sEAAsE;AACtE,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,QAAQ,EACd,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,WAAW,EAAE,CAgBf;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE;IACpC,IAAI,EAAE,QAAQ,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAC/B,GAAG,MAAM,GAAG,IAAI,CAchB;AAED,2EAA2E;AAC3E,wBAAgB,sBAAsB,CAAC,IAAI,EAAE;IAC3C,IAAI,EAAE,QAAQ,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,eAAe,EAAE,OAAO,CAAA;IACxB,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAC/B,GAAG,IAAI,CA2EP;AAED,wBAAgB,oBAAoB,IAAI,IAAI,CAE3C;AAiBD;yEACyE;AACzE,wBAAgB,WAAW,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAYnD;AAED;;;;;GAKG;AACH,wBAAgB,gCAAgC,CAAC,IAAI,EAAE;IACrD,IAAI,EAAE,QAAQ,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,eAAe,EAAE,OAAO,CAAA;IACxB,YAAY,EAAE,MAAM,CAAA;IACpB,aAAa,EAAE,MAAM,CAAA;CACtB,GAAG,IAAI,CAQP;AAED;;;;;GAKG;AACH,wBAAgB,0BAA0B,CACxC,IAAI,EAAE;IACJ,EAAE,EAAE,MAAM,CAAA;IACV,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,QAAQ,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IAC3C,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;CACf,EACD,eAAe,EAAE,OAAO,GACvB,IAAI,CAeN"}
@@ -4,6 +4,7 @@
4
4
  // tool's per-tick hook is a single call.
5
5
  import { computeOpeningGuides, detectVerticalAlignment, sceneRegistry, spatialGridManager, useScene, } from '@pascal-app/core';
6
6
  import { useOpeningGuides } from '@pascal-app/editor';
7
+ import { resolveWallOpeningCeiling } from './wall-opening-ceiling';
7
8
  // Parity with `snapLocalXToNeighbors`' along-wall threshold.
8
9
  const SILL_SNAP_THRESHOLD_M = 0.08;
9
10
  // Hide a dimension that has collapsed to nothing (sill flush to the floor, or
@@ -50,7 +51,7 @@ export function resolveSillSnap(args) {
50
51
  export function publishOpeningGuides3D(args) {
51
52
  const { wall, centerS, centerY, width, toWorld } = args;
52
53
  const wallLength = Math.hypot(wall.end[0] - wall.start[0], wall.end[1] - wall.start[1]);
53
- const wallHeight = wall.height ?? 2.5;
54
+ const wallHeight = resolveWallOpeningCeiling(wall, args.nodes);
54
55
  const siblings = collectOpeningSiblings(wall, args.movingId, args.nodes);
55
56
  const guides = computeOpeningGuides({
56
57
  moving: { id: args.movingId, centerS, width, centerY, height: args.height },
@@ -139,7 +140,7 @@ function makeWallToWorld(wall, levelYOffset, slabElevation) {
139
140
  export function wallToWorld(wall) {
140
141
  const levelId = wall.parentId;
141
142
  const levelYOffset = levelId ? (sceneRegistry.nodes.get(levelId)?.position.y ?? 0) : 0;
142
- const slabElevation = spatialGridManager.getSlabElevationForWall(wall.parentId ?? '', wall.start, wall.end);
143
+ const slabElevation = spatialGridManager.getSlabElevationForWall(wall.parentId ?? '', wall.start, wall.end, wall.curveOffset ?? 0, wall.thickness, wall.supportSlabId);
143
144
  return makeWallToWorld(wall, levelYOffset, slabElevation);
144
145
  }
145
146
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"opening-placement-dimensions.d.ts","sourceRoot":"","sources":["../../src/shared/opening-placement-dimensions.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,QAAQ,EACb,KAAK,iBAAiB,EAEtB,KAAK,eAAe,EAIpB,KAAK,UAAU,EAChB,MAAM,kBAAkB,CAAA;AAEzB;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,+BAA+B,CAC7C,OAAO,EAAE,QAAQ,GAAG,UAAU,EAC9B,GAAG,EAAE,eAAe,GACnB,iBAAiB,EAAE,CAsGrB"}
1
+ {"version":3,"file":"opening-placement-dimensions.d.ts","sourceRoot":"","sources":["../../src/shared/opening-placement-dimensions.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,QAAQ,EACb,KAAK,iBAAiB,EAEtB,KAAK,eAAe,EAKpB,KAAK,UAAU,EAChB,MAAM,kBAAkB,CAAA;AAKzB;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,+BAA+B,CAC7C,OAAO,EAAE,QAAQ,GAAG,UAAU,EAC9B,GAAG,EAAE,eAAe,GACnB,iBAAiB,EAAE,CA4GrB"}
@@ -1,4 +1,7 @@
1
- import { computeOpeningGuides, isCurvedWall, } from '@pascal-app/core';
1
+ import { computeOpeningGuides, isCurvedWall, useScene, } from '@pascal-app/core';
2
+ import { readFloorplanContext } from '@pascal-app/editor';
3
+ import { formatConstructionLength } from './construction-length';
4
+ import { resolveWallOpeningCeiling } from './wall-opening-ceiling';
2
5
  /**
3
6
  * Build placement-measurement dimension lines for a door / window
4
7
  * being moved on a wall. Mirrors the legacy
@@ -46,7 +49,8 @@ export function buildOpeningPlacementDimensions(opening, ctx) {
46
49
  z1 + dirZ * along + outwardNormal[1] * halfThickness,
47
50
  ];
48
51
  const centrePoint = (along) => [x1 + dirX * along, z1 + dirZ * along];
49
- const round = (value) => Number.parseFloat(value.toFixed(2));
52
+ const unit = ctx.viewState?.unit ?? 'metric';
53
+ const metricNotation = readFloorplanContext(ctx).metricNotation;
50
54
  // This wall's OTHER openings as wall-local spans. `ctx.siblings` only includes
51
55
  // same-kind nodes; doors and windows need each other, so resolve the wall's
52
56
  // children directly.
@@ -76,7 +80,10 @@ export function buildOpeningPlacementDimensions(opening, ctx) {
76
80
  height: opening.height,
77
81
  },
78
82
  siblings,
79
- wall: { length: wallLength, height: wall.height ?? 2.5 },
83
+ wall: {
84
+ length: wallLength,
85
+ height: resolveWallOpeningCeiling(wall, useScene.getState().nodes),
86
+ },
80
87
  // The 2D plan is top-down: sill/head height and vertical alignment aren't
81
88
  // representable here — those belong to the 3D viewport.
82
89
  includeVertical: false,
@@ -93,14 +100,16 @@ export function buildOpeningPlacementDimensions(opening, ctx) {
93
100
  offsetNormal: outwardNormal,
94
101
  offsetDistance: FLOORPLAN_WALL_OUTER_MEASUREMENT_OFFSET,
95
102
  extensionOvershoot: 0.12,
96
- text: `${round(gap.distance)}m`,
103
+ text: formatConstructionLength(gap.distance, unit, 'editor', { metricNotation }),
97
104
  stroke: '#f97316',
98
105
  });
99
106
  }
100
107
  // Equal-spacing rhythm — a "=" badge per equal gap, on the wall centreline.
101
108
  if (guides.equalSpacing) {
102
109
  const wallAngle = Math.atan2(dz, dx);
103
- const text = `${round(guides.equalSpacing.gap)}m`;
110
+ const text = formatConstructionLength(guides.equalSpacing.gap, unit, 'editor', {
111
+ metricNotation,
112
+ });
104
113
  for (const seg of guides.equalSpacing.segments) {
105
114
  out.push({
106
115
  kind: 'equal-spacing-badge',
@@ -0,0 +1,30 @@
1
+ import { type AnyNode, type AnyNodeId, type WallNode } from '@pascal-app/core';
2
+ /**
3
+ * Structural subset of `SceneApi` the opening-cap readers need — matches
4
+ * both handle-descriptor callbacks (which receive the full SceneApi) and
5
+ * tools holding a nodes snapshot.
6
+ */
7
+ export type WallCeilingSceneReader = {
8
+ get: (id: AnyNodeId) => unknown;
9
+ nodes: () => Readonly<Record<AnyNodeId, AnyNode>>;
10
+ };
11
+ /**
12
+ * Available wall-local Y span for an opening hosted on `wall`: the wall's
13
+ * resolved top (storey plane for plane-bound walls, stored height for
14
+ * explicit ones) minus the wall's elected slab base. Wall-local Y = 0 sits
15
+ * at the elected base (where the viewer positions the wall mesh), so this
16
+ * is the ceiling an opening's top edge must stay under.
17
+ *
18
+ * Uses the same slab election as the viewer's WallSystem
19
+ * (`spatialGridManager.getSlabSupportForWall`) so the cap agrees with the
20
+ * rendered wall; headless callers with an empty spatial grid elect base 0
21
+ * and fall back to the full storey height.
22
+ */
23
+ export declare function resolveWallOpeningCeiling(wall: WallNode, nodes: Readonly<Record<AnyNodeId, AnyNode>>): number;
24
+ /**
25
+ * Height cap for a wall-hosted opening's resize handles. Infinity only when
26
+ * the opening is unhosted (no wallId, or the wall is gone) — roof-hosted
27
+ * openings clamp elsewhere.
28
+ */
29
+ export declare function readHostWallCeiling(wallId: string | null | undefined, scene: WallCeilingSceneReader): number;
30
+ //# sourceMappingURL=wall-opening-ceiling.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wall-opening-ceiling.d.ts","sourceRoot":"","sources":["../../src/shared/wall-opening-ceiling.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,OAAO,EACZ,KAAK,SAAS,EAEd,KAAK,QAAQ,EACd,MAAM,kBAAkB,CAAA;AAEzB;;;;GAIG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACnC,GAAG,EAAE,CAAC,EAAE,EAAE,SAAS,KAAK,OAAO,CAAA;IAC/B,KAAK,EAAE,MAAM,QAAQ,CAAC,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAA;CAClD,CAAA;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,QAAQ,EACd,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,GAC1C,MAAM,CAER;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACjC,KAAK,EAAE,sBAAsB,GAC5B,MAAM,CAKR"}
@@ -0,0 +1,29 @@
1
+ import { getWallEffectiveHeightForNodes, } from '@pascal-app/core';
2
+ /**
3
+ * Available wall-local Y span for an opening hosted on `wall`: the wall's
4
+ * resolved top (storey plane for plane-bound walls, stored height for
5
+ * explicit ones) minus the wall's elected slab base. Wall-local Y = 0 sits
6
+ * at the elected base (where the viewer positions the wall mesh), so this
7
+ * is the ceiling an opening's top edge must stay under.
8
+ *
9
+ * Uses the same slab election as the viewer's WallSystem
10
+ * (`spatialGridManager.getSlabSupportForWall`) so the cap agrees with the
11
+ * rendered wall; headless callers with an empty spatial grid elect base 0
12
+ * and fall back to the full storey height.
13
+ */
14
+ export function resolveWallOpeningCeiling(wall, nodes) {
15
+ return getWallEffectiveHeightForNodes(wall, nodes);
16
+ }
17
+ /**
18
+ * Height cap for a wall-hosted opening's resize handles. Infinity only when
19
+ * the opening is unhosted (no wallId, or the wall is gone) — roof-hosted
20
+ * openings clamp elsewhere.
21
+ */
22
+ export function readHostWallCeiling(wallId, scene) {
23
+ if (!wallId)
24
+ return Number.POSITIVE_INFINITY;
25
+ const wall = scene.get(wallId);
26
+ if (!wall)
27
+ return Number.POSITIVE_INFINITY;
28
+ return resolveWallOpeningCeiling(wall, scene.nodes());
29
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"floorplan-affordances.d.ts","sourceRoot":"","sources":["../../src/shelf/floorplan-affordances.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,mBAAmB,EACxB,KAAK,SAAS,EAEf,MAAM,kBAAkB,CAAA;AAQzB,MAAM,MAAM,kBAAkB,GAAG;IAC/B,GAAG,EAAE,OAAO,GAAG,OAAO,CAAA;IAGtB,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAC3B,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,EAAE,mBAAmB,CAAC,SAAS,CAiChE,CAAA;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,qBAAqB,EAAE,mBAAmB,CAAC,SAAS,CA+BhE,CAAA"}
1
+ {"version":3,"file":"floorplan-affordances.d.ts","sourceRoot":"","sources":["../../src/shelf/floorplan-affordances.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,mBAAmB,EACxB,KAAK,SAAS,EAGf,MAAM,kBAAkB,CAAA;AASzB,MAAM,MAAM,kBAAkB,GAAG;IAC/B,GAAG,EAAE,OAAO,GAAG,OAAO,CAAA;IAGtB,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAC3B,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,EAAE,mBAAmB,CAAC,SAAS,CAmChE,CAAA;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,qBAAqB,EAAE,mBAAmB,CAAC,SAAS,CAiChE,CAAA"}
@@ -1,4 +1,5 @@
1
- import { useScene, } from '@pascal-app/core';
1
+ import { useLiveNodeOverrides, useScene, } from '@pascal-app/core';
2
+ import { isAngleSnapActive } from '@pascal-app/editor';
2
3
  import { rotateAffordanceDelta } from '../shared/rotate-affordance';
3
4
  // Mirror the 3D handles in `shelf/definition.ts` so a drag can't push a
4
5
  // value past what the renderer / geometry builder accepts.
@@ -30,13 +31,15 @@ export const shelfResizeAffordance = {
30
31
  else {
31
32
  lastPatch = { depth: Math.max(MIN_SHELF_DEPTH, initialDepth + 2 * projDelta) };
32
33
  }
33
- useScene.getState().updateNode(shelfId, lastPatch);
34
+ useLiveNodeOverrides.getState().set(shelfId, lastPatch);
35
+ useScene.getState().markDirty(shelfId);
34
36
  },
35
37
  canCommit() {
36
38
  return true;
37
39
  },
38
40
  commit() {
39
41
  if (Object.keys(lastPatch).length > 0) {
42
+ useLiveNodeOverrides.getState().clear(shelfId);
40
43
  useScene.getState().updateNode(shelfId, lastPatch);
41
44
  }
42
45
  },
@@ -66,21 +69,23 @@ export const shelfRotateAffordance = {
66
69
  let lastRotation = [r[0], initialRotationY, r[2]];
67
70
  return {
68
71
  affectedIds: [shelfId],
69
- apply({ planPoint, modifiers }) {
72
+ apply({ planPoint }) {
70
73
  const delta = rotateAffordanceDelta({
71
74
  center: [cx, cz],
72
75
  initialAngle,
73
76
  planPoint,
74
- free: modifiers.shiftKey,
77
+ free: !isAngleSnapActive(),
75
78
  });
76
79
  const newRotationY = initialRotationY - delta;
77
80
  lastRotation = [r[0], newRotationY, r[2]];
78
- useScene.getState().updateNode(shelfId, { rotation: lastRotation });
81
+ useLiveNodeOverrides.getState().set(shelfId, { rotation: lastRotation });
82
+ useScene.getState().markDirty(shelfId);
79
83
  },
80
84
  canCommit() {
81
85
  return true;
82
86
  },
83
87
  commit() {
88
+ useLiveNodeOverrides.getState().clear(shelfId);
84
89
  useScene.getState().updateNode(shelfId, { rotation: lastRotation });
85
90
  },
86
91
  };
@@ -4,22 +4,8 @@ import { type FloorplanMoveTarget, type ShelfNode } from '@pascal-app/core';
4
4
  * because shelf is a `position`-field kind (it carries its location in
5
5
  * `node.position`, not in polygon vertices):
6
6
  *
7
- * - Each pointermove writes the absolute world-plan position straight
8
- * to `useScene` (history is paused by the overlay). This is the single
9
- * source of truth: the 2D `FloorplanRegistryLayer` and the 3D
10
- * `ParametricNodeRenderer` group transform both follow it reactively,
11
- * so 2D and 3D can never diverge.
12
- * - On commit, the overlay's snapshot-diff reverts to baseline, resumes
13
- * history, and re-applies the final position as one undoable step.
14
- * `canCommit` only validates.
15
- *
16
- * Earlier this used the `useLiveTransforms` + imperative-mesh pattern that
17
- * `slab` / `ceiling` use. That works for polygon kinds because their commit
18
- * rebuilds geometry (the vertices change), which forces the 3D group to
19
- * reconcile. Shelf's `geometryKey` excludes `position`, so its commit
20
- * `markDirty` is a no-op and nothing reconciled the 3D group off the cleared
21
- * live transform — the 2D SVG moved but the 3D mesh stayed put. Writing the
22
- * scene directly removes that second source of truth entirely.
7
+ * - Each pointermove previews through `useLiveNodeOverrides`.
8
+ * - On commit, the final position is written once as one undoable step.
23
9
  */
24
10
  export declare const shelfFloorplanMoveTarget: FloorplanMoveTarget<ShelfNode>;
25
11
  //# sourceMappingURL=floorplan-move.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"floorplan-move.d.ts","sourceRoot":"","sources":["../../src/shelf/floorplan-move.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,mBAAmB,EAGxB,KAAK,SAAS,EAEf,MAAM,kBAAkB,CAAA;AAWzB;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,wBAAwB,EAAE,mBAAmB,CAAC,SAAS,CA2EnE,CAAA"}
1
+ {"version":3,"file":"floorplan-move.d.ts","sourceRoot":"","sources":["../../src/shelf/floorplan-move.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,mBAAmB,EAGxB,KAAK,SAAS,EAGf,MAAM,kBAAkB,CAAA;AAYzB;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB,EAAE,mBAAmB,CAAC,SAAS,CAqEnE,CAAA"}
@@ -1,27 +1,13 @@
1
- import { collectAlignmentAnchors, movingFootprintAnchors, useScene, } from '@pascal-app/core';
2
- import { applyFloorplanAlignment, getFloorStackPreviewPosition, isMagneticSnapActive, triggerSFX, useEditor, } from '@pascal-app/editor';
1
+ import { collectAlignmentAnchors, movingFootprintAnchors, useLiveNodeOverrides, useScene, } from '@pascal-app/core';
2
+ import { applyFloorplanAlignment, getFloorStackPreviewPosition, getSegmentGridStep, isGridSnapActive, isMagneticSnapActive, triggerSFX, } from '@pascal-app/editor';
3
3
  import { createFloorplanCursorResolver } from '../shared/floorplan-cursor';
4
4
  /**
5
5
  * 2D floor-plan move handler for shelf — mirrors `itemFloorplanMoveTarget`,
6
6
  * because shelf is a `position`-field kind (it carries its location in
7
7
  * `node.position`, not in polygon vertices):
8
8
  *
9
- * - Each pointermove writes the absolute world-plan position straight
10
- * to `useScene` (history is paused by the overlay). This is the single
11
- * source of truth: the 2D `FloorplanRegistryLayer` and the 3D
12
- * `ParametricNodeRenderer` group transform both follow it reactively,
13
- * so 2D and 3D can never diverge.
14
- * - On commit, the overlay's snapshot-diff reverts to baseline, resumes
15
- * history, and re-applies the final position as one undoable step.
16
- * `canCommit` only validates.
17
- *
18
- * Earlier this used the `useLiveTransforms` + imperative-mesh pattern that
19
- * `slab` / `ceiling` use. That works for polygon kinds because their commit
20
- * rebuilds geometry (the vertices change), which forces the 3D group to
21
- * reconcile. Shelf's `geometryKey` excludes `position`, so its commit
22
- * `markDirty` is a no-op and nothing reconciled the 3D group off the cleared
23
- * live transform — the 2D SVG moved but the 3D mesh stayed put. Writing the
24
- * scene directly removes that second source of truth entirely.
9
+ * - Each pointermove previews through `useLiveNodeOverrides`.
10
+ * - On commit, the final position is written once as one undoable step.
25
11
  */
26
12
  export const shelfFloorplanMoveTarget = ({ node, nodes }) => {
27
13
  const shelfId = node.id;
@@ -32,6 +18,7 @@ export const shelfFloorplanMoveTarget = ({ node, nodes }) => {
32
18
  metadata: node.metadata,
33
19
  });
34
20
  let lastPosition = originalPosition;
21
+ let lastVisualPosition = originalPosition;
35
22
  let lastSnapKey = null;
36
23
  // Alignment candidates — corner/edge/segment anchors of every OTHER node
37
24
  // (incl. wall faces). Gathered once: the scene is stable during the drag
@@ -39,25 +26,21 @@ export const shelfFloorplanMoveTarget = ({ node, nodes }) => {
39
26
  const candidates = collectAlignmentAnchors(nodes, shelfId);
40
27
  const session = {
41
28
  affectedIds: [shelfId],
42
- apply({ planPoint, modifiers }) {
43
- const snap = (value) => {
44
- if (modifiers.shiftKey)
45
- return value;
46
- const step = useEditor.getState().gridSnapStep;
47
- return Math.round(value / step) * step;
48
- };
29
+ apply({ planPoint }) {
30
+ const gridSnapActive = isGridSnapActive();
31
+ const step = gridSnapActive ? getSegmentGridStep() : 0;
32
+ const snap = (value) => (step > 0 ? Math.round(value / step) * step : value);
49
33
  const gridSnapped = resolveCursor(planPoint, { snap });
50
34
  // Figma-style alignment layered on the grid snap — the shelf footprint
51
- // edges snap to neighbours / wall faces and a guide is published. Alt
52
- // bypasses alignment; Shift bypasses all snap.
53
- const { point: snapped } = applyFloorplanAlignment(gridSnapped, movingFootprintAnchors(node, gridSnapped[0], gridSnapped[1], originalRotationY), candidates, { applySnap: isMagneticSnapActive(), bypass: modifiers.altKey || modifiers.shiftKey });
35
+ // edges snap to neighbours / wall faces and a guide is published.
36
+ const { point: snapped } = applyFloorplanAlignment(gridSnapped, movingFootprintAnchors(node, gridSnapped[0], gridSnapped[1], originalRotationY), candidates, { applySnap: isMagneticSnapActive() });
54
37
  const next = [snapped[0], originalPosition[1], snapped[1]];
55
38
  lastPosition = next;
56
39
  // Grid-snap SFX on cell crossings — matches the 3D `MoveSlabTool`
57
40
  // and the placement coordinators. Item / slab / wall flows fire
58
41
  // the same cue, so the shelf following along is the expected UX.
59
42
  const snapKey = `${snapped[0]},${snapped[1]}`;
60
- if (!modifiers.shiftKey && snapKey !== lastSnapKey) {
43
+ if (gridSnapActive && snapKey !== lastSnapKey) {
61
44
  triggerSFX('sfx:grid-snap');
62
45
  lastSnapKey = snapKey;
63
46
  }
@@ -67,17 +50,9 @@ export const shelfFloorplanMoveTarget = ({ node, nodes }) => {
67
50
  rotation: node.rotation,
68
51
  levelId: node.parentId ?? null,
69
52
  });
70
- // Single source of truth — write the absolute position straight to
71
- // the scene (history is paused by the overlay). Both the 2D SVG and
72
- // the 3D group transform read `node.position` reactively, so they
73
- // stay in lockstep. The overlay's snapshot-diff turns the whole drag
74
- // into one undoable step on commit.
75
- useScene.getState().updateNodes([
76
- {
77
- id: shelfId,
78
- data: { position: visualPosition },
79
- },
80
- ]);
53
+ lastVisualPosition = visualPosition;
54
+ useLiveNodeOverrides.getState().set(shelfId, { position: visualPosition });
55
+ useScene.getState().markDirty(shelfId);
81
56
  },
82
57
  canCommit() {
83
58
  const live = useScene.getState().nodes[shelfId];
@@ -85,6 +60,10 @@ export const shelfFloorplanMoveTarget = ({ node, nodes }) => {
85
60
  return false;
86
61
  return !(lastPosition[0] === originalPosition[0] && lastPosition[2] === originalPosition[2]);
87
62
  },
63
+ commit() {
64
+ useLiveNodeOverrides.getState().clear(shelfId);
65
+ useScene.getState().updateNodes([{ id: shelfId, data: { position: lastVisualPosition } }]);
66
+ },
88
67
  };
89
68
  return session;
90
69
  };
@@ -1 +1 @@
1
- {"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../src/shelf/tool.tsx"],"names":[],"mappings":"AAgCA,QAAA,MAAM,SAAS,0CA0Id,CAAA;AAED,eAAe,SAAS,CAAA"}
1
+ {"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../src/shelf/tool.tsx"],"names":[],"mappings":"AAiCA,QAAA,MAAM,SAAS,0CA+Id,CAAA;AAED,eAAe,SAAS,CAAA"}