@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,13 +1,27 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { calculateLevelMiters, collectAlignmentAnchors, emitter, getTwoPointFenceCurveTangents, getWallMiterBoundaryPoints, resolveAlignment, sampleFenceSpline, useScene, } from '@pascal-app/core';
4
- import { CursorSphere, createFenceOnCurrentLevel, createSplineFenceOnCurrentLevel, EDITOR_LAYER, formatAngleRadians, formatLinearMeasurement, getAngleArcToSegmentReference, getAngleToSegmentReference, getSegmentAngleReferenceAtPoint, getSegmentGridStep, isAlignmentGuideActive, isAngleSnapActive, isGridSnapActive, isMagneticSnapActive, markToolCancelConsumed, snapFenceDraftPoint, snapScalarToGrid, triggerSFX, useAlignmentGuides, useEditor, useFenceCurveDraft, useSegmentDraftChain, } from '@pascal-app/editor';
4
+ import { CursorSphere, clearPlacementSurface, createFenceOnCurrentLevel, createSplineFenceOnCurrentLevel, EDITOR_LAYER, formatAngleRadians, formatLinearMeasurement, getAngleArcToSegmentReference, getAngleToSegmentReference, getSegmentAngleReferenceAtPoint, getSegmentGridStep, isAlignmentGuideActive, isAngleSnapActive, isGridSnapActive, isMagneticSnapActive, markToolCancelConsumed, publishPlacementSurface, resolvePointerSupportSurface, snapFenceDraftPoint, snapScalarToGrid, triggerSFX, useAlignmentGuides, useEditor, useFenceCurveDraft, useFloorplanDraftPreview, useSegmentDraftChain, } from '@pascal-app/editor';
5
5
  import { getSceneTheme, useViewer } from '@pascal-app/viewer';
6
- import { Html } from '@react-three/drei';
6
+ import { useThree } from '@react-three/fiber';
7
7
  import { useEffect, useMemo, useRef, useState } from 'react';
8
- import { BoxGeometry, BufferGeometry, DoubleSide, Vector3 } from 'three';
8
+ import { BoxGeometry, BufferGeometry, DoubleSide, Vector3, } from 'three';
9
+ import { DraftAngleArc, DraftAxisGuides, DraftMeasurementLabel, getNearestAxisAngleLabel, } from '../shared/draft-axis-guides';
9
10
  const FENCE_PREVIEW_HEIGHT = 1.8;
10
11
  const FENCE_PREVIEW_THICKNESS = 0.08;
12
+ // Grid-plane surface publish (pointer-decided): scratch + constant normal so
13
+ // per-move publishes don't allocate.
14
+ const SURFACE_UP = new Vector3(0, 1, 0);
15
+ const surfacePointScratch = new Vector3();
16
+ // The walking surface the pointer actually aims at (deck top when over the
17
+ // deck, floor/ground underneath it) — only for genuine 3D pointer events.
18
+ // The 2D floor plan emits synthetic grid events with no camera ray behind
19
+ // them; those keep the uncapped max election and leave the grid plane alone.
20
+ function pointedSurfaceFor(camera, event) {
21
+ return event.nativeEvent?.target instanceof HTMLCanvasElement
22
+ ? resolvePointerSupportSurface(camera, event.position)
23
+ : null;
24
+ }
11
25
  /** Figma-style alignment-snap threshold (meters), matching the move tools. */
12
26
  const ALIGNMENT_THRESHOLD_M = 0.08;
13
27
  // HUD label heights are measured from the top of the preview bar, so they
@@ -17,7 +31,6 @@ const DRAFT_ANGLE_LABEL_Y_OFFSET = 0.08;
17
31
  const DRAFT_ANGLE_ARC_Y_OFFSET = 0.012;
18
32
  const DRAFT_ANGLE_ARC_MIN_RADIUS = 0.32;
19
33
  const DRAFT_ANGLE_ARC_MAX_RADIUS = 0.72;
20
- const DRAFT_ANGLE_ARC_SEGMENTS = 24;
21
34
  function clamp(value, min, max) {
22
35
  return Math.min(max, Math.max(min, value));
23
36
  }
@@ -290,12 +303,18 @@ const StraightFenceTool = () => {
290
303
  previewHeightRef.current = previewHeight;
291
304
  const previewThicknessRef = useRef(previewThickness);
292
305
  previewThicknessRef.current = previewThickness;
306
+ // Camera for the pointer-support resolution (deck top vs floor) — read
307
+ // through a ref so the live event handlers see the current camera.
308
+ const camera = useThree((state) => state.camera);
309
+ const cameraRef = useRef(camera);
310
+ cameraRef.current = camera;
293
311
  const cursorRef = useRef(null);
294
312
  const previewRef = useRef(null);
295
313
  const startingPoint = useRef(new Vector3(0, 0, 0));
296
314
  const endingPoint = useRef(new Vector3(0, 0, 0));
297
315
  const buildingState = useRef(0);
298
316
  const [draftMeasurement, setDraftMeasurement] = useState(null);
317
+ const [axisGuide, setAxisGuide] = useState(null);
299
318
  const measurementColor = isDark ? '#ffffff' : '#111111';
300
319
  const measurementShadowColor = isDark ? '#111111' : '#ffffff';
301
320
  // Scope seeded defaults to this tool session: clear on deactivation so a
@@ -334,12 +353,25 @@ const StraightFenceTool = () => {
334
353
  buildingState.current = 0;
335
354
  previewRef.current.visible = false;
336
355
  setDraftMeasurement(null);
356
+ setAxisGuide(null);
357
+ const draftPreview = useFloorplanDraftPreview.getState();
358
+ draftPreview.setFenceDraftStart(null);
359
+ draftPreview.setFenceDraftEnd(null);
337
360
  useSegmentDraftChain.getState().clear('fence');
338
361
  useAlignmentGuides.getState().clear();
339
362
  };
340
363
  const onGridMove = (event) => {
341
364
  if (!(cursorRef.current && previewRef.current))
342
365
  return;
366
+ // Ride the grid event plane on the pointed surface: aiming at an
367
+ // elevated deck lifts the plane to the deck top, so the draft's XZ
368
+ // lands where the cursor points and the preview/cursor Y
369
+ // (`event.localPosition[1]`) sits at the lift the committed fence
370
+ // will get. Aiming past the deck edge drops it back to the floor.
371
+ const pointed = pointedSurfaceFor(cameraRef.current, event);
372
+ if (pointed) {
373
+ publishPlacementSurface(surfacePointScratch.set(event.position[0], pointed.worldY, event.position[2]), SURFACE_UP);
374
+ }
343
375
  const { walls, fences } = getCurrentLevelElements();
344
376
  const localPoint = [event.localPosition[0], event.localPosition[2]];
345
377
  // While drafting, the segment locks to 15° rays from its start.
@@ -357,7 +389,16 @@ const StraightFenceTool = () => {
357
389
  magnetic: isMagneticSnapActive(),
358
390
  }), { applySnap: !angleLocked });
359
391
  endingPoint.current.set(snappedLocal[0], event.localPosition[1], snappedLocal[1]);
392
+ const draftPreview = useFloorplanDraftPreview.getState();
393
+ draftPreview.setFenceDraftStart([startingPoint.current.x, startingPoint.current.z]);
394
+ draftPreview.setFenceDraftEnd(snappedLocal);
360
395
  cursorRef.current.position.copy(endingPoint.current);
396
+ setAxisGuide({
397
+ origin: [startingPoint.current.x, startingPoint.current.z],
398
+ endOrigin: snappedLocal,
399
+ y: startingPoint.current.y,
400
+ angleLabel: getNearestAxisAngleLabel([startingPoint.current.x, startingPoint.current.z], snappedLocal, startingPoint.current.y),
401
+ });
361
402
  const currentFenceEnd = [snappedLocal[0], snappedLocal[1]];
362
403
  if (previousFenceEnd &&
363
404
  (currentFenceEnd[0] !== previousFenceEnd[0] || currentFenceEnd[1] !== previousFenceEnd[1])) {
@@ -376,6 +417,7 @@ const StraightFenceTool = () => {
376
417
  }));
377
418
  cursorRef.current.position.set(snappedPoint[0], event.localPosition[1], snappedPoint[1]);
378
419
  setDraftMeasurement(null);
420
+ setAxisGuide(null);
379
421
  }
380
422
  };
381
423
  const onGridClick = (event) => {
@@ -397,9 +439,18 @@ const StraightFenceTool = () => {
397
439
  startingPoint.current.set(snappedStart[0], event.localPosition[1], snappedStart[1]);
398
440
  endingPoint.current.copy(startingPoint.current);
399
441
  buildingState.current = 1;
442
+ const draftPreview = useFloorplanDraftPreview.getState();
443
+ draftPreview.setFenceDraftStart(snappedStart);
444
+ draftPreview.setFenceDraftEnd(snappedStart);
400
445
  triggerSFX('sfx:structure-build-start');
401
446
  previewRef.current.visible = true;
402
447
  setDraftMeasurement(null);
448
+ setAxisGuide({
449
+ origin: snappedStart,
450
+ endOrigin: null,
451
+ y: event.localPosition[1],
452
+ angleLabel: null,
453
+ });
403
454
  }
404
455
  else {
405
456
  const angleLocked = isAngleSnapActive();
@@ -415,7 +466,8 @@ const StraightFenceTool = () => {
415
466
  const dz = snappedEnd[1] - startingPoint.current.z;
416
467
  if (dx * dx + dz * dz < 0.01 * 0.01)
417
468
  return;
418
- const createdFence = createFenceOnCurrentLevel([startingPoint.current.x, startingPoint.current.z], snappedEnd);
469
+ const pointed = pointedSurfaceFor(cameraRef.current, event);
470
+ const createdFence = createFenceOnCurrentLevel([startingPoint.current.x, startingPoint.current.z], snappedEnd, { supportCap: pointed ? pointed.elevation : null });
419
471
  if (!createdFence)
420
472
  return;
421
473
  // The new segment is now a real node — make it an alignment target
@@ -435,10 +487,20 @@ const StraightFenceTool = () => {
435
487
  useSegmentDraftChain.getState().setChainStart('fence', [nextStart[0], nextStart[1]]);
436
488
  startingPoint.current.set(nextStart[0], event.localPosition[1], nextStart[1]);
437
489
  endingPoint.current.copy(startingPoint.current);
490
+ const draftPreview = useFloorplanDraftPreview.getState();
491
+ draftPreview.setFenceDraftEnd(null);
492
+ draftPreview.setFenceDraftStart(nextStart);
493
+ draftPreview.setFenceDraftEnd(nextStart);
438
494
  cursorRef.current?.position.copy(startingPoint.current);
439
495
  previewRef.current.visible = false;
440
496
  buildingState.current = 1;
441
497
  setDraftMeasurement(null);
498
+ setAxisGuide({
499
+ origin: nextStart,
500
+ endOrigin: null,
501
+ y: event.localPosition[1],
502
+ angleLabel: null,
503
+ });
442
504
  }
443
505
  };
444
506
  const onCancel = () => {
@@ -454,11 +516,15 @@ const StraightFenceTool = () => {
454
516
  emitter.off('grid:move', onGridMove);
455
517
  emitter.off('grid:click', onGridClick);
456
518
  emitter.off('tool:cancel', onCancel);
519
+ clearPlacementSurface();
457
520
  useSegmentDraftChain.getState().clear('fence');
458
521
  useAlignmentGuides.getState().clear();
522
+ const draftPreview = useFloorplanDraftPreview.getState();
523
+ draftPreview.setFenceDraftStart(null);
524
+ draftPreview.setFenceDraftEnd(null);
459
525
  };
460
526
  }, [unit]);
461
- return (_jsxs("group", { children: [_jsx(CursorSphere, { height: previewHeight, ref: cursorRef }), _jsxs("mesh", { layers: EDITOR_LAYER, ref: previewRef, renderOrder: 1, visible: false, children: [_jsx("shapeGeometry", {}), _jsx("meshBasicMaterial", { color: "#ffffff", depthTest: false, depthWrite: false, opacity: 0.45, side: DoubleSide, transparent: true })] }), draftMeasurement && (_jsxs(_Fragment, { children: [_jsx(DraftMeasurementLabel, { color: measurementColor, label: draftMeasurement.lengthLabel, position: draftMeasurement.lengthPosition, shadowColor: measurementShadowColor }), draftMeasurement.angleLabels.map((angleLabel) => (_jsxs("group", { children: [_jsx(DraftAngleArc, { arc: angleLabel.arc, color: measurementColor }), _jsx(DraftMeasurementLabel, { color: measurementColor, label: angleLabel.label, position: angleLabel.position, shadowColor: measurementShadowColor })] }, angleLabel.id)))] }))] }));
527
+ return (_jsxs("group", { children: [_jsx(DraftAxisGuides, { guide: axisGuide, labelColor: measurementColor, labelShadowColor: measurementShadowColor }), _jsx(CursorSphere, { height: previewHeight, ref: cursorRef }), _jsxs("mesh", { layers: EDITOR_LAYER, ref: previewRef, renderOrder: 1, visible: false, children: [_jsx("shapeGeometry", {}), _jsx("meshBasicMaterial", { color: "#ffffff", depthTest: false, depthWrite: false, opacity: 0.45, side: DoubleSide, transparent: true })] }), draftMeasurement && (_jsxs(_Fragment, { children: [_jsx(DraftMeasurementLabel, { color: measurementColor, label: draftMeasurement.lengthLabel, position: draftMeasurement.lengthPosition, shadowColor: measurementShadowColor }), draftMeasurement.angleLabels.map((angleLabel) => (_jsxs("group", { children: [_jsx(DraftAngleArc, { arc: angleLabel.arc, color: measurementColor }), _jsx(DraftMeasurementLabel, { color: measurementColor, label: angleLabel.label, position: angleLabel.position, shadowColor: measurementShadowColor })] }, angleLabel.id)))] }))] }));
462
528
  };
463
529
  const SPLINE_PREVIEW_COLOR = '#8381ed';
464
530
  const SPLINE_PREVIEW_SEGMENTS = 40;
@@ -468,13 +534,23 @@ const SplineFenceDraft = () => {
468
534
  : FENCE_PREVIEW_HEIGHT;
469
535
  const [draftPoints, setDraftPoints] = useState([]);
470
536
  const [cursor, setCursor] = useState(null);
537
+ // Building-local Y of the grid plane (rides the pointed surface — see
538
+ // `pointedSurfaceFor`), so the spline preview draws on the deck top when
539
+ // the curve is being laid out on one.
540
+ const [liftY, setLiftY] = useState(0);
541
+ const camera = useThree((state) => state.camera);
542
+ const cameraRef = useRef(camera);
543
+ cameraRef.current = camera;
544
+ // Pointer cap for the commit (Enter / double-click carry no useful grid
545
+ // event of their own) — last resolved on move/click.
546
+ const supportCapRef = useRef(null);
471
547
  const draftRef = useRef(draftPoints);
472
548
  draftRef.current = draftPoints;
473
- // Mirror the draft length into the HUD store so the "finish curve" hint only
474
- // shows once drafting has started; always clear it when the tool unmounts.
549
+ // Mirror the full transient curve so additional preview surfaces observe
550
+ // the same snapped control points as the local preview.
475
551
  useEffect(() => {
476
- useFenceCurveDraft.getState().setPointCount(draftPoints.length);
477
- }, [draftPoints]);
552
+ useFenceCurveDraft.getState().setDraft(draftPoints, cursor);
553
+ }, [cursor, draftPoints]);
478
554
  useEffect(() => () => useFenceCurveDraft.getState().reset(), []);
479
555
  useEffect(() => () => useEditor.getState().setToolDefaults('fence', null), []);
480
556
  useEffect(() => {
@@ -487,7 +563,9 @@ const SplineFenceDraft = () => {
487
563
  const commit = () => {
488
564
  const points = draftRef.current;
489
565
  if (points.length >= 2) {
490
- const created = createSplineFenceOnCurrentLevel(points);
566
+ const created = createSplineFenceOnCurrentLevel(points, undefined, {
567
+ supportCap: supportCapRef.current,
568
+ });
491
569
  if (created) {
492
570
  triggerSFX('sfx:item-place');
493
571
  // Once the new curve fence is selected for direct editing, leave
@@ -500,10 +578,20 @@ const SplineFenceDraft = () => {
500
578
  setDraftPoints([]);
501
579
  setCursor(null);
502
580
  };
581
+ const trackPointedSurface = (event) => {
582
+ const pointed = pointedSurfaceFor(cameraRef.current, event);
583
+ if (!pointed)
584
+ return;
585
+ supportCapRef.current = pointed.elevation;
586
+ publishPlacementSurface(surfacePointScratch.set(event.position[0], pointed.worldY, event.position[2]), SURFACE_UP);
587
+ setLiftY(event.localPosition[1]);
588
+ };
503
589
  const onMove = (event) => {
590
+ trackPointedSurface(event);
504
591
  setCursor(snapPoint([event.localPosition[0], event.localPosition[2]]));
505
592
  };
506
593
  const onClick = (event) => {
594
+ trackPointedSurface(event);
507
595
  if (event.nativeEvent.detail >= 2) {
508
596
  commit();
509
597
  return;
@@ -530,6 +618,7 @@ const SplineFenceDraft = () => {
530
618
  emitter.off('grid:move', onMove);
531
619
  emitter.off('grid:click', onClick);
532
620
  emitter.off('tool:cancel', onCancel);
621
+ clearPlacementSurface();
533
622
  window.removeEventListener('keydown', onKeyDown);
534
623
  };
535
624
  }, []);
@@ -538,26 +627,8 @@ const SplineFenceDraft = () => {
538
627
  if (previewPoints.length < 2)
539
628
  return null;
540
629
  const sampled = sampleFenceSpline(previewPoints, getTwoPointFenceCurveTangents(previewPoints), SPLINE_PREVIEW_SEGMENTS);
541
- return new BufferGeometry().setFromPoints(sampled.map((point) => new Vector3(point.x, previewHeight, point.y)));
542
- }, [previewHeight, previewPoints]);
543
- return (_jsxs("group", { children: [cursor && _jsx(CursorSphere, { height: previewHeight, position: [cursor[0], 0, cursor[1]] }), draftPoints.map((point, index) => (_jsxs("mesh", { layers: EDITOR_LAYER, position: [point[0], previewHeight, point[1]], children: [_jsx("sphereGeometry", { args: [0.07, 16, 12] }), _jsx("meshBasicMaterial", { color: SPLINE_PREVIEW_COLOR, depthTest: false })] }, `fence-spline-pt-${index}`))), curveGeometry && (_jsx("line", { frustumCulled: false, geometry: curveGeometry, layers: EDITOR_LAYER, renderOrder: 2, children: _jsx("lineBasicNodeMaterial", { color: SPLINE_PREVIEW_COLOR, depthTest: false, depthWrite: false, linewidth: 2, opacity: 0.95, transparent: true }) }))] }));
630
+ return new BufferGeometry().setFromPoints(sampled.map((point) => new Vector3(point.x, liftY + previewHeight, point.y)));
631
+ }, [liftY, previewHeight, previewPoints]);
632
+ return (_jsxs("group", { children: [cursor && _jsx(CursorSphere, { height: previewHeight, position: [cursor[0], liftY, cursor[1]] }), draftPoints.map((point, index) => (_jsxs("mesh", { layers: EDITOR_LAYER, position: [point[0], liftY + previewHeight, point[1]], children: [_jsx("sphereGeometry", { args: [0.07, 16, 12] }), _jsx("meshBasicMaterial", { color: SPLINE_PREVIEW_COLOR, depthTest: false })] }, `fence-spline-pt-${index}`))), curveGeometry && (_jsx("line", { frustumCulled: false, geometry: curveGeometry, layers: EDITOR_LAYER, renderOrder: 2, children: _jsx("lineBasicNodeMaterial", { color: SPLINE_PREVIEW_COLOR, depthTest: false, depthWrite: false, linewidth: 2, opacity: 0.95, transparent: true }) }))] }));
544
633
  };
545
- function DraftAngleArc({ arc, color }) {
546
- const geometry = useMemo(() => {
547
- const segmentCount = Math.max(8, Math.ceil((Math.abs(arc.endAngle - arc.startAngle) / Math.PI) * DRAFT_ANGLE_ARC_SEGMENTS));
548
- const points = Array.from({ length: segmentCount + 1 }, (_, index) => {
549
- const t = index / segmentCount;
550
- const angle = arc.startAngle + (arc.endAngle - arc.startAngle) * t;
551
- return new Vector3(arc.center[0] + Math.cos(angle) * arc.radius, arc.y, arc.center[1] + Math.sin(angle) * arc.radius);
552
- });
553
- return new BufferGeometry().setFromPoints(points);
554
- }, [arc]);
555
- return (_jsx("line", { frustumCulled: false, geometry: geometry, layers: EDITOR_LAYER, renderOrder: 2, children: _jsx("lineBasicNodeMaterial", { color: color, depthTest: false, depthWrite: false, linewidth: 2, opacity: 0.95, transparent: true }) }));
556
- }
557
- function DraftMeasurementLabel({ color, label, position, shadowColor, }) {
558
- return (_jsx(Html, { center: true, position: position, style: { pointerEvents: 'none', userSelect: 'none' }, zIndexRange: [100, 0], children: _jsx("div", { className: "whitespace-nowrap font-bold font-mono text-[15px]", style: {
559
- color,
560
- textShadow: `-1.5px -1.5px 0 ${shadowColor}, 1.5px -1.5px 0 ${shadowColor}, -1.5px 1.5px 0 ${shadowColor}, 1.5px 1.5px 0 ${shadowColor}, 0 0 4px ${shadowColor}, 0 0 4px ${shadowColor}`,
561
- }, children: label }) }));
562
- }
563
634
  export default FenceTool;
@@ -1 +1 @@
1
- {"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../src/hvac-equipment/tool.tsx"],"names":[],"mappings":"AAqBA;;;;;;;GAOG;AACH,QAAA,MAAM,iBAAiB,0CAoGtB,CAAA;AAED,eAAe,iBAAiB,CAAA"}
1
+ {"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../src/hvac-equipment/tool.tsx"],"names":[],"mappings":"AA2BA;;;;;;;GAOG;AACH,QAAA,MAAM,iBAAiB,0CAyGtB,CAAA;AAED,eAAe,iBAAiB,CAAA"}
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { emitter, HvacEquipmentNode, useScene } from '@pascal-app/core';
3
+ import { emitter, HvacEquipmentNode, resolveSupportSlabPatch, useScene, } from '@pascal-app/core';
4
4
  import { isGridSnapActive, isMagneticSnapActive, triggerSFX, useEditor } from '@pascal-app/editor';
5
5
  import { useViewer } from '@pascal-app/viewer';
6
6
  import { Html } from '@react-three/drei';
@@ -65,9 +65,14 @@ const HvacEquipmentTool = () => {
65
65
  name: 'Furnace',
66
66
  position,
67
67
  rotation: yawRef.current,
68
+ parentId: activeLevelId,
68
69
  });
69
- useScene.getState().createNode(unit, activeLevelId);
70
- useViewer.getState().setSelection({ selectedIds: [unit.id] });
70
+ const committedUnit = HvacEquipmentNode.parse({
71
+ ...unit,
72
+ ...resolveSupportSlabPatch(unit, useScene.getState().nodes),
73
+ });
74
+ useScene.getState().createNode(committedUnit, activeLevelId);
75
+ useViewer.getState().setSelection({ selectedIds: [committedUnit.id] });
71
76
  triggerSFX('sfx:item-place');
72
77
  };
73
78
  const onKeyDown = (e) => {
package/dist/index.d.ts CHANGED
@@ -22,6 +22,7 @@ export { bakeCabinetAnimationClip, type CabinetPlacementType, cabinetDefinition,
22
22
  export { ceilingDefinition } from './ceiling';
23
23
  export { chimneyDefinition } from './chimney';
24
24
  export { columnDefinition } from './column';
25
+ export { constructionDimensionDefinition } from './construction-dimension';
25
26
  export { cupolaDefinition } from './cupola';
26
27
  export { doorDefinition } from './door';
27
28
  export { dormerDefinition } from './dormer';
@@ -55,6 +56,7 @@ export { solarPanelDefinition } from './solar-panel';
55
56
  export { spawnDefinition } from './spawn';
56
57
  export { stairDefinition } from './stair';
57
58
  export { stairSegmentDefinition } from './stair-segment';
59
+ export { structuralGridDefinition } from './structural-grid';
58
60
  export { turbineVentDefinition } from './turbine-vent';
59
61
  export { wallDefinition } from './wall';
60
62
  export { windowDefinition } from './window';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -4,6 +4,7 @@ import { cabinetDefinition, cabinetModuleDefinition } from './cabinet';
4
4
  import { ceilingDefinition } from './ceiling';
5
5
  import { chimneyDefinition } from './chimney';
6
6
  import { columnDefinition } from './column';
7
+ import { constructionDimensionDefinition } from './construction-dimension';
7
8
  import { cupolaDefinition } from './cupola';
8
9
  import { doorDefinition } from './door';
9
10
  import { dormerDefinition } from './dormer';
@@ -37,6 +38,7 @@ import { solarPanelDefinition } from './solar-panel';
37
38
  import { spawnDefinition } from './spawn';
38
39
  import { stairDefinition } from './stair';
39
40
  import { stairSegmentDefinition } from './stair-segment';
41
+ import { structuralGridDefinition } from './structural-grid';
40
42
  import { turbineVentDefinition } from './turbine-vent';
41
43
  import { wallDefinition } from './wall';
42
44
  import { windowDefinition } from './window';
@@ -88,6 +90,8 @@ export const builtinPlugin = {
88
90
  guideDefinition,
89
91
  scanDefinition,
90
92
  measurementDefinition,
93
+ constructionDimensionDefinition,
94
+ structuralGridDefinition,
91
95
  // Roof-mounted accessories (custom renderer + bespoke roof-event tool).
92
96
  boxVentDefinition,
93
97
  ridgeVentDefinition,
@@ -119,6 +123,7 @@ export { bakeCabinetAnimationClip, cabinetDefinition, cabinetModuleDefinition, p
119
123
  export { ceilingDefinition } from './ceiling';
120
124
  export { chimneyDefinition } from './chimney';
121
125
  export { columnDefinition } from './column';
126
+ export { constructionDimensionDefinition } from './construction-dimension';
122
127
  export { cupolaDefinition } from './cupola';
123
128
  export { doorDefinition } from './door';
124
129
  export { dormerDefinition } from './dormer';
@@ -152,6 +157,7 @@ export { solarPanelDefinition } from './solar-panel';
152
157
  export { spawnDefinition } from './spawn';
153
158
  export { stairDefinition } from './stair';
154
159
  export { stairSegmentDefinition } from './stair-segment';
160
+ export { structuralGridDefinition } from './structural-grid';
155
161
  export { turbineVentDefinition } from './turbine-vent';
156
162
  export { wallDefinition } from './wall';
157
163
  export { windowDefinition } from './window';
@@ -1 +1 @@
1
- {"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../src/item/definition.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,cAAc,EACpB,MAAM,kBAAkB,CAAA;AAKzB,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AA+HnC;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,eAAO,MAAM,cAAc,EAAE,cAAc,CAAC,OAAO,QAAQ,CA0K1D,CAAA"}
1
+ {"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../src/item/definition.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,cAAc,EACpB,MAAM,kBAAkB,CAAA;AAMzB,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AA+HnC;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,eAAO,MAAM,cAAc,EAAE,cAAc,CAAC,OAAO,QAAQ,CAgL1D,CAAA"}
@@ -1,5 +1,5 @@
1
1
  import { getScaledDimensions, } from '@pascal-app/core';
2
- import { buildItemFloorplan } from './floorplan';
2
+ import { buildItemContextualDimensions, buildItemFloorplan } from './floorplan';
3
3
  import { itemFloorplanMoveTarget } from './floorplan-move';
4
4
  import { itemPaint } from './paint';
5
5
  import { itemParametrics } from './parametrics';
@@ -158,6 +158,11 @@ export const itemDefinition = {
158
158
  schema: ItemNode,
159
159
  category: 'furnish',
160
160
  surfaceRole: 'furnishing',
161
+ extensions: {
162
+ 'pascal:editor/floorplan': {
163
+ contextualDimensions: buildItemContextualDimensions,
164
+ },
165
+ },
161
166
  // Defaults shape is cast: the schema requires a fully-typed `asset`
162
167
  // field, but in practice items are always created from the catalog
163
168
  // (the asset is supplied at placement time). `createNode` re-parses
@@ -261,6 +266,7 @@ export const itemDefinition = {
261
266
  kind: 'parametric',
262
267
  module: () => import('./renderer'),
263
268
  },
269
+ preview: () => import('./renderer').then(({ ItemPreview }) => ({ default: ItemPreview })),
264
270
  system: {
265
271
  module: () => import('./system'),
266
272
  // Same priority as the legacy ItemSystem.
@@ -1 +1 @@
1
- {"version":3,"file":"floorplan-move.d.ts","sourceRoot":"","sources":["../../src/item/floorplan-move.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,mBAAmB,EAIxB,KAAK,QAAQ,EAKd,MAAM,kBAAkB,CAAA;AAkJzB,eAAO,MAAM,uBAAuB,EAAE,mBAAmB,CAAC,QAAQ,CA+BjE,CAAA"}
1
+ {"version":3,"file":"floorplan-move.d.ts","sourceRoot":"","sources":["../../src/item/floorplan-move.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,mBAAmB,EAIxB,KAAK,QAAQ,EAMd,MAAM,kBAAkB,CAAA;AAkJzB,eAAO,MAAM,uBAAuB,EAAE,mBAAmB,CAAC,QAAQ,CA+BjE,CAAA"}
@@ -1,4 +1,4 @@
1
- import { collectAlignmentAnchors, getRoofWallFaceFrame, getScaledDimensions, movingFootprintAnchors, roofFacePointToSegment, useScene, } from '@pascal-app/core';
1
+ import { collectAlignmentAnchors, getRoofWallFaceFrame, getScaledDimensions, movingFootprintAnchors, roofFacePointToSegment, useLiveNodeOverrides, useScene, } from '@pascal-app/core';
2
2
  import { applyFloorplanAlignment, isGridSnapActive, isMagneticSnapActive, useEditor, } from '@pascal-app/editor';
3
3
  import { createFloorplanCursorResolver } from '../shared/floorplan-cursor';
4
4
  import { findClosestWallInPlan, snapLocalXToNeighbors } from '../shared/wall-attach-target';
@@ -125,6 +125,7 @@ function buildWallItemSession(node, startLevelId) {
125
125
  original: resolveItemPlanPoint(node, useScene.getState().nodes),
126
126
  metadata: node.metadata,
127
127
  });
128
+ let lastPatch = null;
128
129
  return {
129
130
  affectedIds: [node.id],
130
131
  apply({ planPoint }) {
@@ -151,25 +152,25 @@ function buildWallItemSession(node, startLevelId) {
151
152
  const snappedLocalX = neighborX ?? (step <= 0 ? hit.localX : Math.round(hit.localX / step) * step);
152
153
  const halfW = width / 2;
153
154
  const clampedX = Math.max(halfW, Math.min(hit.wallLength - halfW, snappedLocalX));
154
- useScene.getState().updateNodes([
155
- {
156
- id: node.id,
157
- data: {
158
- position: [clampedX, startLocalY, 0],
159
- rotation: [0, hit.itemRotation, 0],
160
- side: hit.side,
161
- parentId: hit.wall.id,
162
- // Re-anchoring to a wall ends any roof-segment hosting; the
163
- // overlay's snapshot restores it if the move is reverted.
164
- roofSegmentId: undefined,
165
- roofFace: undefined,
166
- },
167
- },
168
- ]);
155
+ lastPatch = {
156
+ position: [clampedX, startLocalY, 0],
157
+ rotation: [0, hit.itemRotation, 0],
158
+ side: hit.side,
159
+ parentId: hit.wall.id,
160
+ roofSegmentId: undefined,
161
+ roofFace: undefined,
162
+ };
163
+ useLiveNodeOverrides.getState().set(node.id, lastPatch);
164
+ useScene.getState().markDirty(node.id);
169
165
  },
170
166
  canCommit() {
171
- const live = useScene.getState().nodes[node.id];
172
- return !!live && live.type === 'item' && !!live.parentId;
167
+ return !!lastPatch?.parentId;
168
+ },
169
+ commit() {
170
+ if (!lastPatch)
171
+ return;
172
+ useLiveNodeOverrides.getState().clear(node.id);
173
+ useScene.getState().updateNodes([{ id: node.id, data: lastPatch }]);
173
174
  },
174
175
  };
175
176
  }
@@ -190,6 +191,7 @@ function buildFloorItemSession(node, startLevelId, nodes) {
190
191
  const resolvePlanPoint = createPlanarMovePointResolver(resolveItemPlanPoint(node, nodes), node);
191
192
  // Alignment candidates gathered once — scene is stable during the drag.
192
193
  const candidates = collectAlignmentAnchors(nodes, node.id);
194
+ let lastPatch = null;
193
195
  return {
194
196
  affectedIds: [node.id],
195
197
  apply({ planPoint }) {
@@ -200,22 +202,24 @@ function buildFloorItemSession(node, startLevelId, nodes) {
200
202
  const { point: snapped } = applyFloorplanAlignment(gridSnapped, movingFootprintAnchors(node, gridSnapped[0], gridSnapped[1], rotationY), candidates, { applySnap: isMagneticSnapActive() });
201
203
  const sourceY = node.position[1];
202
204
  const nextPosition = [snapped[0], sourceY, snapped[1]];
203
- useScene.getState().updateNodes([
204
- {
205
- id: node.id,
206
- data: {
207
- position: nextPosition,
208
- // Keep parent as the level we resolved at session-start. If
209
- // somehow it's null (e.g. orphaned item), fall back to the
210
- // existing parent so we don't write `null` and detach.
211
- parentId: startLevelId ?? node.parentId,
212
- },
213
- },
214
- ]);
205
+ lastPatch = {
206
+ position: nextPosition,
207
+ // Keep parent as the level we resolved at session-start. If
208
+ // somehow it's null (e.g. orphaned item), fall back to the
209
+ // existing parent so we don't write `null` and detach.
210
+ parentId: startLevelId ?? node.parentId,
211
+ };
212
+ useLiveNodeOverrides.getState().set(node.id, lastPatch);
213
+ useScene.getState().markDirty(node.id);
215
214
  },
216
215
  canCommit() {
217
- const live = useScene.getState().nodes[node.id];
218
- return !!live && live.type === 'item';
216
+ return lastPatch !== null;
217
+ },
218
+ commit() {
219
+ if (!lastPatch)
220
+ return;
221
+ useLiveNodeOverrides.getState().clear(node.id);
222
+ useScene.getState().updateNodes([{ id: node.id, data: lastPatch }]);
219
223
  },
220
224
  };
221
225
  }
@@ -229,6 +233,7 @@ function buildFloorItemSession(node, startLevelId, nodes) {
229
233
  */
230
234
  function buildSurfaceItemSession(node, startLevelId, targetKind) {
231
235
  const resolvePlanPoint = createPlanarMovePointResolver(resolveItemPlanPoint(node, useScene.getState().nodes), node);
236
+ let lastPatch = null;
232
237
  return {
233
238
  affectedIds: [node.id],
234
239
  apply({ planPoint }) {
@@ -237,19 +242,21 @@ function buildSurfaceItemSession(node, startLevelId, targetKind) {
237
242
  const surface = findContainingSurface(snapped, nodes, startLevelId, targetKind);
238
243
  const sourceY = node.position[1];
239
244
  const nextPosition = [snapped[0], sourceY, snapped[1]];
240
- useScene.getState().updateNodes([
241
- {
242
- id: node.id,
243
- data: {
244
- position: nextPosition,
245
- parentId: surface ? surface.id : node.parentId,
246
- },
247
- },
248
- ]);
245
+ lastPatch = {
246
+ position: nextPosition,
247
+ parentId: surface ? surface.id : node.parentId,
248
+ };
249
+ useLiveNodeOverrides.getState().set(node.id, lastPatch);
250
+ useScene.getState().markDirty(node.id);
249
251
  },
250
252
  canCommit() {
251
- const live = useScene.getState().nodes[node.id];
252
- return !!live && live.type === 'item';
253
+ return lastPatch !== null;
254
+ },
255
+ commit() {
256
+ if (!lastPatch)
257
+ return;
258
+ useLiveNodeOverrides.getState().clear(node.id);
259
+ useScene.getState().updateNodes([{ id: node.id, data: lastPatch }]);
253
260
  },
254
261
  };
255
262
  }
@@ -1,3 +1,4 @@
1
1
  import { type FloorplanGeometry, type GeometryContext, type ItemNode } from '@pascal-app/core';
2
+ export declare function buildItemContextualDimensions(node: ItemNode, ctx: GeometryContext): FloorplanGeometry | null;
2
3
  export declare function buildItemFloorplan(node: ItemNode, ctx: GeometryContext): FloorplanGeometry | null;
3
4
  //# sourceMappingURL=floorplan.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"floorplan.d.ts","sourceRoot":"","sources":["../../src/item/floorplan.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,iBAAiB,EAEtB,KAAK,eAAe,EAGpB,KAAK,QAAQ,EAId,MAAM,kBAAkB,CAAA;AA+IzB,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,eAAe,GAAG,iBAAiB,GAAG,IAAI,CAmGjG"}
1
+ {"version":3,"file":"floorplan.d.ts","sourceRoot":"","sources":["../../src/item/floorplan.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,iBAAiB,EAEtB,KAAK,eAAe,EAGpB,KAAK,QAAQ,EAId,MAAM,kBAAkB,CAAA;AAgJzB,wBAAgB,6BAA6B,CAC3C,IAAI,EAAE,QAAQ,EACd,GAAG,EAAE,eAAe,GACnB,iBAAiB,GAAG,IAAI,CA+C1B;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,eAAe,GAAG,iBAAiB,GAAG,IAAI,CAmGjG"}
@@ -1,4 +1,5 @@
1
1
  import { getRoofWallFaceFrame, getScaledDimensions, roofFacePointToSegment, useLiveTransforms, } from '@pascal-app/core';
2
+ import { formatLinearMeasurement, readFloorplanMetricNotationOverride } from '@pascal-app/editor';
2
3
  // Plan-space rotation convention used by the legacy `rotatePlanVector`
3
4
  // in `editor/src/lib/floorplan/geometry.ts`. This is a CLOCKWISE rotation
4
5
  // — the registry-side equivalent of the canonical floor-plan transform
@@ -104,6 +105,54 @@ function resolveItemTransform(item, ctx, cache = new Map()) {
104
105
  cache.set(item.id, result);
105
106
  return result;
106
107
  }
108
+ export function buildItemContextualDimensions(node, ctx) {
109
+ const transform = resolveItemTransform(node, ctx);
110
+ if (!transform)
111
+ return null;
112
+ const [width, , depth] = getScaledDimensions(node);
113
+ if (width <= 1e-6 || depth <= 1e-6)
114
+ return null;
115
+ const centerLocalZ = node.asset.attachTo === 'wall-side' ? depth / 2 : 0;
116
+ const [centerOffsetX, centerOffsetY] = rotateVec(0, centerLocalZ, transform.rotation);
117
+ const cx = transform.x + centerOffsetX;
118
+ const cy = transform.y + centerOffsetY;
119
+ const halfWidth = width / 2;
120
+ const halfDepth = depth / 2;
121
+ const point = (x, y) => {
122
+ const [rx, ry] = rotateVec(x, y, transform.rotation);
123
+ return [cx + rx, cy + ry];
124
+ };
125
+ const widthNormal = rotateVec(0, -1, transform.rotation);
126
+ const depthNormal = rotateVec(1, 0, transform.rotation);
127
+ const unit = ctx.viewState?.unit ?? 'metric';
128
+ const metricNotation = readFloorplanMetricNotationOverride(ctx) ?? 'meters';
129
+ const stroke = ctx.viewState?.palette?.selectedStroke ?? '#2563eb';
130
+ return {
131
+ kind: 'group',
132
+ children: [
133
+ {
134
+ kind: 'dimension',
135
+ start: point(-halfWidth, -halfDepth),
136
+ end: point(halfWidth, -halfDepth),
137
+ offsetNormal: widthNormal,
138
+ offsetDistance: 0.28,
139
+ extensionOvershoot: 0.08,
140
+ text: formatLinearMeasurement(width, unit, metricNotation),
141
+ stroke,
142
+ },
143
+ {
144
+ kind: 'dimension',
145
+ start: point(halfWidth, -halfDepth),
146
+ end: point(halfWidth, halfDepth),
147
+ offsetNormal: depthNormal,
148
+ offsetDistance: 0.28,
149
+ extensionOvershoot: 0.08,
150
+ text: formatLinearMeasurement(depth, unit, metricNotation),
151
+ stroke,
152
+ },
153
+ ],
154
+ };
155
+ }
107
156
  export function buildItemFloorplan(node, ctx) {
108
157
  const transform = resolveItemTransform(node, ctx);
109
158
  if (!transform)
@@ -2,5 +2,8 @@ import { type ItemNode } from '@pascal-app/core';
2
2
  export declare const ItemRenderer: ({ node: storeNode }: {
3
3
  node: ItemNode;
4
4
  }) => import("react").JSX.Element;
5
+ export declare const ItemPreview: ({ node }: {
6
+ node: ItemNode;
7
+ }) => import("react").JSX.Element;
5
8
  export default ItemRenderer;
6
9
  //# sourceMappingURL=renderer.d.ts.map