@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,10 +1,11 @@
1
1
  'use client';
2
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
- import { useScene } from '@pascal-app/core';
4
- import { ActionButton, ActionGroup, holeEditScope, PanelSection, PanelWrapper, SliderControl, triggerSFX, useEditingHole, useEditor, useInteractionScope, } from '@pascal-app/editor';
2
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { MIN_SLAB_THICKNESS, useScene } from '@pascal-app/core';
4
+ import { ActionButton, ActionGroup, holeEditScope, PanelSection, PanelWrapper, SegmentedControl, SliderControl, triggerSFX, useEditingHole, useEditor, useInteractionScope, } from '@pascal-app/editor';
5
5
  import { useViewer } from '@pascal-app/viewer';
6
6
  import { Edit, Move, Plus, Trash2 } from 'lucide-react';
7
7
  import { useCallback, useEffect, useRef } from 'react';
8
+ import { applySlabAnchorElevationChange, applySlabElevationPreset, applySlabRecessDepthChange, applySlabThicknessChange, applySlabTopChange, clampSlabElevation, getSlabAnchorElevation, getSlabBaseElevation, getSlabRecessDepth, } from './elevation-limit';
8
9
  /**
9
10
  * Phase 5 Stage E — slab inspector (kind-owned).
10
11
  *
@@ -18,6 +19,7 @@ import { useCallback, useEffect, useRef } from 'react';
18
19
  */
19
20
  export function SlabPanel() {
20
21
  const selectedId = useViewer((s) => s.selection.selectedIds[0]);
22
+ const unit = useViewer((s) => s.unit);
21
23
  const setSelection = useViewer((s) => s.setSelection);
22
24
  const editingHole = useEditingHole();
23
25
  const setMovingNode = useEditor((s) => s.setMovingNode);
@@ -32,6 +34,64 @@ export function SlabPanel() {
32
34
  return;
33
35
  useScene.getState().updateNode(selectedId, updates);
34
36
  }, [selectedId]);
37
+ const handleElevationChange = useCallback((proposed) => {
38
+ const current = nodeRef.current;
39
+ if (!current)
40
+ return;
41
+ const { elevation } = clampSlabElevation(useScene.getState().nodes, current, proposed);
42
+ handleUpdate(applySlabTopChange(current, elevation));
43
+ }, [handleUpdate]);
44
+ const handleThicknessChange = useCallback((proposed) => {
45
+ const current = nodeRef.current;
46
+ if (!current)
47
+ return;
48
+ const base = getSlabBaseElevation(current);
49
+ const requested = applySlabThicknessChange(current, proposed);
50
+ const clamped = clampSlabElevation(useScene.getState().nodes, current, requested.elevation);
51
+ handleUpdate(applySlabThicknessChange(current, Math.max(MIN_SLAB_THICKNESS, clamped.elevation - base)));
52
+ }, [handleUpdate]);
53
+ const handleAnchorChange = useCallback((proposed) => {
54
+ const current = nodeRef.current;
55
+ if (!current)
56
+ return;
57
+ const patch = applySlabAnchorElevationChange(current, proposed);
58
+ const requestedTop = patch.elevation ?? current.elevation;
59
+ const { elevation } = clampSlabElevation(useScene.getState().nodes, current, requestedTop);
60
+ if (current.recessed) {
61
+ const delta = elevation - requestedTop;
62
+ handleUpdate({
63
+ ...patch,
64
+ elevation,
65
+ recessedRimElevation: (patch.recessedRimElevation ?? proposed) + delta,
66
+ });
67
+ return;
68
+ }
69
+ handleUpdate(applySlabAnchorElevationChange(current, elevation - current.thickness));
70
+ }, [handleUpdate]);
71
+ const handleRecessDepthChange = useCallback((proposed) => {
72
+ const current = nodeRef.current;
73
+ if (!current?.recessed)
74
+ return;
75
+ handleUpdate(applySlabRecessDepthChange(current, proposed));
76
+ }, [handleUpdate]);
77
+ const handleElevationPreset = useCallback((signedDepth) => {
78
+ const current = nodeRef.current;
79
+ if (!current)
80
+ return;
81
+ const anchor = getSlabAnchorElevation(current);
82
+ const requested = applySlabElevationPreset(current, signedDepth);
83
+ if (requested.recessed) {
84
+ handleUpdate(requested);
85
+ return;
86
+ }
87
+ const requestedTop = requested.elevation ?? current.elevation;
88
+ const { elevation } = clampSlabElevation(useScene.getState().nodes, current, requestedTop);
89
+ const thickness = Math.max(MIN_SLAB_THICKNESS, elevation - anchor);
90
+ handleUpdate({ ...requested, elevation: anchor + thickness, thickness });
91
+ }, [handleUpdate]);
92
+ const handleTerrainModeChange = useCallback((mode) => {
93
+ handleUpdate({ fillToTerrain: mode === 'terrain' ? true : undefined });
94
+ }, [handleUpdate]);
35
95
  const handleClose = useCallback(() => {
36
96
  setSelection({ selectedIds: [] });
37
97
  useInteractionScope
@@ -128,7 +188,25 @@ export function SlabPanel() {
128
188
  return Math.abs(area) / 2;
129
189
  };
130
190
  const area = calculateArea(node.polygon);
131
- return (_jsxs(PanelWrapper, { icon: "/icons/floor.webp", onClose: handleClose, title: node.name || 'Slab', width: 320, children: [_jsxs(PanelSection, { title: "Elevation", children: [_jsx(SliderControl, { label: "Height", max: 1, min: -1, onChange: (v) => handleUpdate({ elevation: v }), precision: 3, step: 0.01, unit: "m", value: Math.round(node.elevation * 1000) / 1000 }), _jsxs("div", { className: "mt-2 grid grid-cols-2 gap-1.5 px-1 pb-1", children: [_jsx(ActionButton, { label: "Sunken (-15cm)", onClick: () => handleUpdate({ elevation: -0.15 }) }), _jsx(ActionButton, { label: "Ground (0m)", onClick: () => handleUpdate({ elevation: 0 }) }), _jsx(ActionButton, { label: "Raised (+5cm)", onClick: () => handleUpdate({ elevation: 0.05 }) }), _jsx(ActionButton, { label: "Step (+15cm)", onClick: () => handleUpdate({ elevation: 0.15 }) })] })] }), _jsx(PanelSection, { title: "Info", children: _jsxs("div", { className: "flex items-center justify-between px-2 py-1 text-muted-foreground text-sm", children: [_jsx("span", { children: "Area" }), _jsxs("span", { className: "font-mono text-white", children: [area.toFixed(2), " m\u00B2"] })] }) }), _jsxs(PanelSection, { title: "Holes", children: [node.holes && node.holes.length > 0 ? (_jsx("div", { className: "flex flex-col gap-1 pb-2", children: node.holes.map((hole, index) => {
191
+ // Clean preset values per display system; imperial stores exact meters
192
+ // for whole-inch offsets.
193
+ const elevationPresets = unit === 'imperial'
194
+ ? [
195
+ { label: 'Sunken (6")', elevation: -0.1524 },
196
+ { label: 'Thin (1")', elevation: 0.0254 },
197
+ { label: 'Standard (2")', elevation: 0.0508 },
198
+ { label: 'Thick (6")', elevation: 0.1524 },
199
+ ]
200
+ : [
201
+ { label: 'Sunken (15cm)', elevation: -0.15 },
202
+ { label: 'Thin (2cm)', elevation: 0.02 },
203
+ { label: 'Standard (5cm)', elevation: 0.05 },
204
+ { label: 'Thick (15cm)', elevation: 0.15 },
205
+ ];
206
+ return (_jsxs(PanelWrapper, { icon: "/icons/floor.webp", onClose: handleClose, title: node.name || 'Slab', width: 320, children: [_jsxs(PanelSection, { title: "Elevation", children: [_jsx(SliderControl, { label: node.recessed ? 'Floor' : 'Surface', max: 6, min: -3, onChange: handleElevationChange, precision: 3, step: 0.01, unit: "m", value: Math.round(node.elevation * 1000) / 1000 }), _jsx(SliderControl, { label: node.recessed ? 'Rim' : 'Base', max: 6, min: -3, onChange: handleAnchorChange, precision: 3, step: 0.01, unit: "m", value: Math.round(getSlabAnchorElevation(node) * 1000) / 1000 }), node.recessed ? (_jsx(SliderControl, { label: "Depth", max: 2, min: MIN_SLAB_THICKNESS, onChange: handleRecessDepthChange, precision: 2, step: 0.01, unit: "m", value: Math.round(getSlabRecessDepth(node) * 100) / 100 })) : (_jsx(SliderControl, { label: "Thickness", max: 0.5, min: MIN_SLAB_THICKNESS, onChange: handleThicknessChange, precision: 2, step: 0.01, unit: "m", value: Math.round((node.thickness ?? 0.05) * 100) / 100 })), !node.recessed && (_jsxs(_Fragment, { children: [_jsx("div", { className: "px-1 font-medium text-[10px] text-muted-foreground/80 uppercase tracking-wider", children: "Foundation" }), _jsx(SegmentedControl, { onChange: handleTerrainModeChange, options: [
207
+ { label: 'Fixed', value: 'fixed' },
208
+ { label: 'Follows terrain', value: 'terrain' },
209
+ ], value: node.fillToTerrain ? 'terrain' : 'fixed' }), node.fillToTerrain && (_jsx("div", { className: "px-1 text-[11px] text-muted-foreground", children: "Extends the perimeter down to terrain. The flat surface, base, and thickness stay unchanged." }))] })), _jsx("div", { className: "mt-2 grid grid-cols-2 gap-1.5 px-1 pb-1", children: elevationPresets.map((preset) => (_jsx(ActionButton, { label: preset.label, onClick: () => handleElevationPreset(preset.elevation) }, preset.label))) })] }), _jsx(PanelSection, { title: "Info", children: _jsxs("div", { className: "flex items-center justify-between px-2 py-1 text-muted-foreground text-sm", children: [_jsx("span", { children: "Area" }), _jsxs("span", { className: "font-mono text-white", children: [area.toFixed(2), " m\u00B2"] })] }) }), _jsxs(PanelSection, { title: "Holes", children: [node.holes && node.holes.length > 0 ? (_jsx("div", { className: "flex flex-col gap-1 pb-2", children: node.holes.map((hole, index) => {
132
210
  const holeArea = calculateArea(hole);
133
211
  const isEditing = editingHole?.nodeId === selectedId && editingHole?.holeIndex === index;
134
212
  const source = node.holeMetadata?.[index]?.source ?? 'manual';
@@ -1,4 +1,4 @@
1
- import type { ParametricDescriptor } from '@pascal-app/core';
1
+ import { type ParametricDescriptor } from '@pascal-app/core';
2
2
  import type { SlabNode } from './schema';
3
3
  /**
4
4
  * Inspector descriptor for slab.
@@ -1 +1 @@
1
- {"version":3,"file":"parametrics.d.ts","sourceRoot":"","sources":["../../src/slab/parametrics.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAA;AAC5D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAExC;;;;;;;;;GASG;AACH,eAAO,MAAM,eAAe,EAAE,oBAAoB,CAAC,QAAQ,CAQ1D,CAAA"}
1
+ {"version":3,"file":"parametrics.d.ts","sourceRoot":"","sources":["../../src/slab/parametrics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,oBAAoB,EAAE,MAAM,kBAAkB,CAAA;AAChF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAExC;;;;;;;;;GASG;AACH,eAAO,MAAM,eAAe,EAAE,oBAAoB,CAAC,QAAQ,CAmB1D,CAAA"}
@@ -1,3 +1,4 @@
1
+ import { MIN_SLAB_THICKNESS } from '@pascal-app/core';
1
2
  /**
2
3
  * Inspector descriptor for slab.
3
4
  *
@@ -12,7 +13,18 @@ export const slabParametrics = {
12
13
  groups: [
13
14
  {
14
15
  label: 'Elevation',
15
- fields: [{ key: 'elevation', kind: 'number', unit: 'm', min: -1, max: 1, step: 0.01 }],
16
+ fields: [
17
+ { key: 'elevation', kind: 'number', unit: 'm', min: -1, max: 1, step: 0.01 },
18
+ {
19
+ key: 'thickness',
20
+ kind: 'number',
21
+ unit: 'm',
22
+ min: MIN_SLAB_THICKNESS,
23
+ max: 0.5,
24
+ step: 0.01,
25
+ visibleIf: (n) => !n.recessed,
26
+ },
27
+ ],
16
28
  },
17
29
  ],
18
30
  customPanel: () => import('./panel'),
@@ -0,0 +1,3 @@
1
+ export type SlabCompletionTrigger = 'grid' | 'keyboard';
2
+ export declare function shouldRegistryCommitSlab(viewMode: '2d' | '3d' | 'split', trigger: SlabCompletionTrigger): boolean;
3
+ //# sourceMappingURL=placement-ownership.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"placement-ownership.d.ts","sourceRoot":"","sources":["../../src/slab/placement-ownership.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,qBAAqB,GAAG,MAAM,GAAG,UAAU,CAAA;AAEvD,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,IAAI,GAAG,IAAI,GAAG,OAAO,EAC/B,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAET"}
@@ -0,0 +1,3 @@
1
+ export function shouldRegistryCommitSlab(viewMode, trigger) {
2
+ return trigger === 'keyboard' || viewMode !== '2d';
3
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"quick-measurement.d.ts","sourceRoot":"","sources":["../../src/slab/quick-measurement.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAOxE,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,QAAQ,GAAG,sBAAsB,GAAG,IAAI,CAiClF"}
1
+ {"version":3,"file":"quick-measurement.d.ts","sourceRoot":"","sources":["../../src/slab/quick-measurement.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAOxE,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,QAAQ,GAAG,sBAAsB,GAAG,IAAI,CAkClF"}
@@ -2,11 +2,12 @@ import { polygonBoundaryLength, polygonReportAnchor, polygonSurfaceArea, } from
2
2
  export function slabQuickMeasurement(node) {
3
3
  if (node.polygon.length < 3)
4
4
  return null;
5
- const thickness = node.elevation ?? 0.05;
5
+ const elevation = node.elevation ?? 0.05;
6
+ const thickness = node.thickness ?? 0.05;
6
7
  return {
7
8
  title: node.name ?? 'Floor slab',
8
9
  kindLabel: 'Floor slab',
9
- anchor: polygonReportAnchor(node.polygon, thickness + 0.04),
10
+ anchor: polygonReportAnchor(node.polygon, elevation + 0.04),
10
11
  metrics: [
11
12
  {
12
13
  key: 'area',
@@ -1 +1 @@
1
- {"version":3,"file":"system.d.ts","sourceRoot":"","sources":["../../src/slab/system.tsx"],"names":[],"mappings":"AA0DA,QAAA,MAAM,WAAW,YAmBhB,CAAA;AAED,eAAe,WAAW,CAAA"}
1
+ {"version":3,"file":"system.d.ts","sourceRoot":"","sources":["../../src/slab/system.tsx"],"names":[],"mappings":"AAmEA,QAAA,MAAM,WAAW,YAmBhB,CAAA;AAED,eAAe,WAAW,CAAA"}
@@ -6,10 +6,10 @@ import { useEffect } from 'react';
6
6
  * context — wall centerlines/thickness (exterior flush offsets) and sibling
7
7
  * slab polygons (interior centerline seams) — none of which lives on the slab
8
8
  * node itself. Store updates only dirty the node that changed, so a wall
9
- * thickness edit or a neighbour slab add/remove/reshape would leave stale
10
- * slab meshes. Watch a per-level signature of those inputs and dirty every
11
- * slab on a level whose signature moved; `GeometrySystem` then rebuilds
12
- * them through `def.geometry` as usual.
9
+ * thickness edit, a neighbour slab add/remove/reshape, or a building transform
10
+ * would leave stale slab meshes. Watch a per-level signature of those inputs
11
+ * and dirty every slab on a level whose signature moved; `GeometrySystem` then
12
+ * rebuilds them through `def.geometry` as usual.
13
13
  */
14
14
  function levelSlabContextSignatures(nodes) {
15
15
  const partsByLevel = new Map();
@@ -35,6 +35,16 @@ function levelSlabContextSignatures(nodes) {
35
35
  push(levelId, `s|${slab.id}|${slab.elevation ?? ''}|${slab.polygon.map(([x, z]) => `${x},${z}`).join(';')}`);
36
36
  }
37
37
  }
38
+ for (const node of Object.values(nodes)) {
39
+ if (node.type !== 'building')
40
+ continue;
41
+ const transform = `${node.position.join(',')}|${node.rotation.join(',')}`;
42
+ for (const childId of node.children) {
43
+ const child = nodes[childId];
44
+ if (child?.type === 'level')
45
+ push(child.id, `b|${node.id}|${transform}`);
46
+ }
47
+ }
38
48
  const signatures = new Map();
39
49
  for (const [levelId, parts] of partsByLevel.entries()) {
40
50
  signatures.set(levelId, parts.sort().join('||'));
@@ -1 +1 @@
1
- {"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../src/slab/tool.tsx"],"names":[],"mappings":"AAsDA,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EA4O5B,CAAA;AAED,eAAe,QAAQ,CAAA"}
1
+ {"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../src/slab/tool.tsx"],"names":[],"mappings":"AA4EA,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EA2T5B,CAAA;AAED,eAAe,QAAQ,CAAA"}
package/dist/slab/tool.js CHANGED
@@ -1,10 +1,12 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { DEFAULT_ANGLE_STEP, emitter, snapPointAlongAngleRay, snapPointToGrid, useScene, } from '@pascal-app/core';
4
- import { CursorSphere, clearSlabSnapFeedback, EDITOR_LAYER, isAngleSnapActive, isGridSnapActive, markToolCancelConsumed, resolveSlabPlanPointSnap, triggerSFX, useEditor, } from '@pascal-app/editor';
3
+ import { DEFAULT_ANGLE_STEP, emitter, resolveSlabPlacementElevation, snapPointAlongAngleRay, snapPointToGrid, useScene, } from '@pascal-app/core';
4
+ import { CursorSphere, clearPlacementSurface, clearSlabSnapFeedback, EDITOR_LAYER, isAngleSnapActive, isGridSnapActive, markToolCancelConsumed, publishHorizontalConstructionPlane, publishPlacementSurface, resampleTerrainConstructionPlane, resolveEventConstructionPlane, resolveLevelConstructionPlane, resolvePointerSupportSurface, resolveSlabPlanPointSnap, triggerSFX, useEditor, useFloorplanDraftPreview, } from '@pascal-app/editor';
5
5
  import { useViewer } from '@pascal-app/viewer';
6
+ import { useThree } from '@react-three/fiber';
6
7
  import { useEffect, useMemo, useRef, useState } from 'react';
7
8
  import { BufferGeometry, DoubleSide, Shape, Vector3 } from 'three';
9
+ import { shouldRegistryCommitSlab } from './placement-ownership';
8
10
  import { SlabNode } from './schema';
9
11
  /**
10
12
  * Phase 5 Stage D — slab placement tool (kind-owned via `def.tool`).
@@ -18,14 +20,20 @@ import { SlabNode } from './schema';
18
20
  * single pointer-down → drag-up.
19
21
  */
20
22
  const Y_OFFSET = 0.02;
21
- function commitSlabDrawing(levelId, points) {
23
+ const SURFACE_UP = new Vector3(0, 1, 0);
24
+ const surfacePointScratch = new Vector3();
25
+ function commitSlabDrawing(levelId, points, baseElevation) {
22
26
  const { createNode, nodes } = useScene.getState();
23
27
  const slabCount = Object.values(nodes).filter((n) => n.type === 'slab').length;
24
28
  const name = `Slab ${slabCount + 1}`;
25
29
  // A placed slab preset seeds `toolDefaults.slab` (thickness, material, …)
26
30
  // before the tool activates; the drawn polygon always wins.
27
31
  const defaults = useEditor.getState().toolDefaults.slab ?? {};
28
- const slab = SlabNode.parse({ ...defaults, name, polygon: points });
32
+ const authored = SlabNode.parse({ ...defaults, name, polygon: points });
33
+ const slab = {
34
+ ...authored,
35
+ elevation: resolveSlabPlacementElevation(authored, baseElevation),
36
+ };
29
37
  createNode(slab, levelId);
30
38
  triggerSFX('sfx:structure-build');
31
39
  return slab.id;
@@ -36,33 +44,70 @@ export const SlabTool = () => {
36
44
  const closingLineRef = useRef(null);
37
45
  const currentLevelId = useViewer((s) => s.selection.levelId);
38
46
  const setSelection = useViewer((s) => s.setSelection);
47
+ const slabDefaults = useEditor((s) => s.toolDefaults.slab);
48
+ const isRecessed = slabDefaults?.recessed === true;
49
+ const camera = useThree((state) => state.camera);
50
+ const cameraRef = useRef(camera);
51
+ cameraRef.current = camera;
39
52
  const [points, setPoints] = useState([]);
40
53
  const [cursorPosition, setCursorPosition] = useState([0, 0]);
41
54
  const [snappedCursorPosition, setSnappedCursorPosition] = useState([0, 0]);
42
55
  const [levelY, setLevelY] = useState(0);
43
56
  const previousSnappedPointRef = useRef(null);
57
+ const constructionPlaneRef = useRef(null);
44
58
  // Clear preset-seeded defaults on deactivation so a later manual slab draw
45
59
  // isn't built with a stale preset's parameters. Unmount-only.
46
60
  useEffect(() => () => useEditor.getState().setToolDefaults('slab', null), []);
47
- useEffect(() => () => clearSlabSnapFeedback(), []);
61
+ useEffect(() => () => {
62
+ clearSlabSnapFeedback();
63
+ clearPlacementSurface();
64
+ }, []);
48
65
  // Publish the live vertex count so the HUD shows "Finish" only at ≥ 3 points.
49
66
  useEffect(() => {
50
67
  useEditor.getState().setDraftVertexCount(points.length);
51
68
  }, [points.length]);
52
69
  useEffect(() => () => useEditor.getState().setDraftVertexCount(0), []);
70
+ useEffect(() => {
71
+ useFloorplanDraftPreview.getState().setPolygonDraft('slab', points);
72
+ }, [points]);
73
+ useEffect(() => () => {
74
+ const draftPreview = useFloorplanDraftPreview.getState();
75
+ if (draftPreview.polygonDraftType === 'slab') {
76
+ draftPreview.setPolygonDraft(null, []);
77
+ }
78
+ draftPreview.setCursorPoint(null);
79
+ }, []);
53
80
  useEffect(() => {
54
81
  if (!currentLevelId)
55
82
  return;
83
+ const pointedSurfaceFor = (event) => event.nativeEvent?.target instanceof HTMLCanvasElement
84
+ ? resolvePointerSupportSurface(cameraRef.current, event.position)
85
+ : null;
86
+ const resetDraft = () => {
87
+ setPoints([]);
88
+ constructionPlaneRef.current = null;
89
+ previousSnappedPointRef.current = null;
90
+ clearSlabSnapFeedback();
91
+ clearPlacementSurface();
92
+ };
56
93
  const onGridMove = (event) => {
57
94
  if (!cursorRef.current)
58
95
  return;
59
- const rawPoint = [event.localPosition[0], event.localPosition[2]];
96
+ const pointed = points.length === 0 && !isRecessed ? pointedSurfaceFor(event) : null;
97
+ const plane = constructionPlaneRef.current ?? (isRecessed ? resolveLevelConstructionPlane() : null);
98
+ if (plane) {
99
+ publishHorizontalConstructionPlane(event, plane);
100
+ }
101
+ else if (pointed) {
102
+ publishPlacementSurface(surfacePointScratch.set(event.position[0], pointed.worldY, event.position[2]), SURFACE_UP);
103
+ }
104
+ const localPosition = pointed?.localPoint ?? event.localPosition;
105
+ const rawPoint = [localPosition[0], localPosition[2]];
60
106
  // Slab drafting is the 'polygon' snap context (grid / lines / off — no
61
107
  // angle, no Shift bypass; Shift cycles the mode, Off is the bypass).
62
108
  const gridStep = isGridSnapActive() ? useEditor.getState().gridSnapStep : 0;
63
109
  const gridPosition = [...snapPointToGrid(rawPoint, gridStep)];
64
110
  setCursorPosition(gridPosition);
65
- setLevelY(event.localPosition[1]);
66
111
  const lastPoint = points[points.length - 1];
67
112
  // Angle lock only when the mode asks for it (polygon never does today, but
68
113
  // honour the flag so the behaviour follows the HUD).
@@ -74,6 +119,10 @@ export const SlabTool = () => {
74
119
  fallbackPoint: orthoPoint,
75
120
  levelId: currentLevelId,
76
121
  }).point;
122
+ const hoverPlane = plane ??
123
+ resampleTerrainConstructionPlane(resolveEventConstructionPlane(event, pointed), displayPoint);
124
+ setLevelY(hoverPlane.localY);
125
+ useFloorplanDraftPreview.getState().setCursorPoint(displayPoint);
77
126
  setSnappedCursorPosition(displayPoint);
78
127
  if (points.length > 0 &&
79
128
  previousSnappedPointRef.current &&
@@ -82,9 +131,9 @@ export const SlabTool = () => {
82
131
  triggerSFX('sfx:grid-snap');
83
132
  }
84
133
  previousSnappedPointRef.current = displayPoint;
85
- cursorRef.current.position.set(displayPoint[0], event.localPosition[1], displayPoint[1]);
134
+ cursorRef.current.position.set(displayPoint[0], hoverPlane.localY, displayPoint[1]);
86
135
  };
87
- const onGridClick = (_event) => {
136
+ const onGridClick = (event) => {
88
137
  if (!currentLevelId)
89
138
  return;
90
139
  const clickPoint = previousSnappedPointRef.current ?? cursorPosition;
@@ -93,12 +142,21 @@ export const SlabTool = () => {
93
142
  firstPoint &&
94
143
  Math.abs(clickPoint[0] - firstPoint[0]) < 0.25 &&
95
144
  Math.abs(clickPoint[1] - firstPoint[1]) < 0.25) {
96
- const slabId = commitSlabDrawing(currentLevelId, points);
97
- setSelection({ selectedIds: [slabId] });
98
- setPoints([]);
99
- clearSlabSnapFeedback();
145
+ if (shouldRegistryCommitSlab(useEditor.getState().viewMode, 'grid')) {
146
+ const slabId = commitSlabDrawing(currentLevelId, points, constructionPlaneRef.current?.elevation ?? null);
147
+ setSelection({ selectedIds: [slabId] });
148
+ }
149
+ resetDraft();
100
150
  }
101
151
  else {
152
+ if (points.length === 0) {
153
+ const plane = isRecessed
154
+ ? (resolveLevelConstructionPlane() ?? resolveEventConstructionPlane(event, null))
155
+ : resampleTerrainConstructionPlane(resolveEventConstructionPlane(event, pointedSurfaceFor(event)), clickPoint);
156
+ constructionPlaneRef.current = plane;
157
+ setLevelY(plane.localY);
158
+ publishHorizontalConstructionPlane(event, plane);
159
+ }
102
160
  // Every non-closing vertex is a "start" tick; the closing click above
103
161
  // fires the structure-build (end) cue.
104
162
  triggerSFX('sfx:structure-build-start');
@@ -107,27 +165,27 @@ export const SlabTool = () => {
107
165
  };
108
166
  // Finish the polygon (Enter or double-click): commit once there are enough
109
167
  // vertices. Closing near the first vertex (in onGridClick) is the third way.
110
- const finishDrawing = () => {
168
+ const finishDrawing = (trigger) => {
111
169
  if (points.length < 3)
112
170
  return;
113
- const slabId = commitSlabDrawing(currentLevelId, points);
114
- setSelection({ selectedIds: [slabId] });
115
- setPoints([]);
116
- clearSlabSnapFeedback();
171
+ if (shouldRegistryCommitSlab(useEditor.getState().viewMode, trigger)) {
172
+ const slabId = commitSlabDrawing(currentLevelId, points, constructionPlaneRef.current?.elevation ?? null);
173
+ setSelection({ selectedIds: [slabId] });
174
+ }
175
+ resetDraft();
117
176
  };
118
177
  const onGridDoubleClick = (_event) => {
119
- finishDrawing();
178
+ finishDrawing('grid');
120
179
  };
121
180
  const onCancel = () => {
122
181
  if (points.length > 0)
123
182
  markToolCancelConsumed();
124
- setPoints([]);
125
- clearSlabSnapFeedback();
183
+ resetDraft();
126
184
  };
127
185
  const onKeyDown = (e) => {
128
186
  if (e.key === 'Enter') {
129
187
  e.preventDefault();
130
- finishDrawing();
188
+ finishDrawing('keyboard');
131
189
  }
132
190
  };
133
191
  document.addEventListener('keydown', onKeyDown);
@@ -142,7 +200,7 @@ export const SlabTool = () => {
142
200
  emitter.off('grid:double-click', onGridDoubleClick);
143
201
  emitter.off('tool:cancel', onCancel);
144
202
  };
145
- }, [currentLevelId, points, cursorPosition, setSelection]);
203
+ }, [currentLevelId, points, cursorPosition, isRecessed, setSelection]);
146
204
  useEffect(() => {
147
205
  if (!(mainLineRef.current && closingLineRef.current))
148
206
  return;
@@ -1 +1 @@
1
- {"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../src/solar-panel/definition.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,cAAc,EAGpB,MAAM,kBAAkB,CAAA;AAGzB,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAgNzC;;;;;;;;;;GAUG;AACH,eAAO,MAAM,oBAAoB,EAAE,cAAc,CAAC,OAAO,cAAc,CAwDtE,CAAA"}
1
+ {"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../src/solar-panel/definition.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,cAAc,EAGpB,MAAM,kBAAkB,CAAA;AAGzB,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAgNzC;;;;;;;;;;GAUG;AACH,eAAO,MAAM,oBAAoB,EAAE,cAAc,CAAC,OAAO,cAAc,CAyDtE,CAAA"}
@@ -239,6 +239,7 @@ export const solarPanelDefinition = {
239
239
  kind: 'parametric',
240
240
  module: () => import('./renderer'),
241
241
  },
242
+ preview: () => import('./preview'),
242
243
  tool: () => import('./tool'),
243
244
  affordanceTools: {
244
245
  move: () => import('./move-tool'),
@@ -1 +1 @@
1
- {"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../src/solar-panel/tool.tsx"],"names":[],"mappings":"AA4BA;;;;;;;GAOG;AACH,QAAA,MAAM,cAAc,mCAoInB,CAAA;AAED,eAAe,cAAc,CAAA"}
1
+ {"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../src/solar-panel/tool.tsx"],"names":[],"mappings":"AA4BA;;;;;;;GAOG;AACH,QAAA,MAAM,cAAc,mCAoJnB,CAAA;AAED,eAAe,cAAc,CAAA"}
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { emitter, SolarPanelNode, sceneRegistry, useScene, } from '@pascal-app/core';
4
- import { triggerSFX } from '@pascal-app/editor';
4
+ import { triggerSFX, usePlacementPreview } from '@pascal-app/editor';
5
5
  import { useViewer } from '@pascal-app/viewer';
6
6
  import { useEffect, useMemo, useRef, useState } from 'react';
7
7
  import * as THREE from 'three';
@@ -67,6 +67,13 @@ const SolarPanelTool = () => {
67
67
  setPreviewSurfaceQuat(surfaceQuatFromNormal(normal, new THREE.Quaternion()));
68
68
  setPreviewYaw((event.node.rotation ?? 0) + (hit.segment.rotation ?? 0));
69
69
  setPreviewPos(worldToBuildingLocal(wx, wy, wz));
70
+ usePlacementPreview.getState().set(SolarPanelNode.parse({
71
+ ...previewNode,
72
+ parentId: hit.segment.id,
73
+ position: [hit.localX, hit.localY, hit.localZ],
74
+ roofSegmentId: hit.segment.id,
75
+ surfaceNormal: [normal.x, normal.y, normal.z],
76
+ }), hit.segment);
70
77
  publishRoofSurfacePlacementGuides({
71
78
  roof: event.node,
72
79
  segment: hit.segment,
@@ -98,6 +105,9 @@ const SolarPanelTool = () => {
98
105
  state.dirtyNodes.add(hit.segment.id);
99
106
  setSelection({ selectedIds: [panel.id] });
100
107
  triggerSFX('sfx:item-place');
108
+ const placementPreview = usePlacementPreview.getState();
109
+ if (placementPreview.node?.id === previewNode.id)
110
+ placementPreview.clear();
101
111
  clearRoofSurfacePlacementGuides();
102
112
  event.stopPropagation();
103
113
  };
@@ -108,12 +118,18 @@ const SolarPanelTool = () => {
108
118
  emitter.off('roof:move', updatePreview);
109
119
  emitter.off('roof:enter', updatePreview);
110
120
  emitter.off('roof:click', onClick);
121
+ const placementPreview = usePlacementPreview.getState();
122
+ if (placementPreview.node?.id === previewNode.id)
123
+ placementPreview.clear();
111
124
  clearRoofSurfacePlacementGuides();
112
125
  };
113
126
  }, [activeBuildingId, setSelection, previewNode]);
114
127
  return (_jsxs(_Fragment, { children: [_jsx(RoofAttachmentFallbackPreview, { activeBuildingId: activeBuildingId, ghost: _jsx(SolarPanelPreview, { node: previewNode, invalid: true }), onInvalidTarget: () => {
115
128
  setPreviewPos(null);
116
129
  setPreviewSurfaceQuat(null);
130
+ const placementPreview = usePlacementPreview.getState();
131
+ if (placementPreview.node?.id === previewNode.id)
132
+ placementPreview.clear();
117
133
  clearRoofSurfacePlacementGuides();
118
134
  } }), activeBuildingId && previewPos && previewSurfaceQuat && (_jsx("group", { position: previewPos, children: _jsx("group", { "rotation-y": previewYaw, children: _jsx("group", { quaternion: previewSurfaceQuat, children: _jsx(SolarPanelPreview, { node: previewNode }) }) }) }))] }));
119
135
  };
@@ -1 +1 @@
1
- {"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../src/spawn/definition.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAoB,cAAc,EAA8B,MAAM,kBAAkB,CAAA;AAKpG,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AA0CpC,eAAO,MAAM,eAAe,EAAE,cAAc,CAAC,OAAO,SAAS,CAsE5D,CAAA"}
1
+ {"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../src/spawn/definition.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAoB,cAAc,EAA8B,MAAM,kBAAkB,CAAA;AAKpG,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AA0CpC,eAAO,MAAM,eAAe,EAAE,cAAc,CAAC,OAAO,SAAS,CAuE5D,CAAA"}
@@ -92,6 +92,7 @@ export const spawnDefinition = {
92
92
  tool: () => import('./tool'),
93
93
  toolHints: [
94
94
  { key: 'Left click', label: 'Place spawn point' },
95
+ { key: 'R / T', label: 'Rotate spawn point' },
95
96
  { key: 'Esc', label: 'Cancel' },
96
97
  ],
97
98
  presentation: {
@@ -1 +1 @@
1
- {"version":3,"file":"floorplan-affordances.d.ts","sourceRoot":"","sources":["../../src/spawn/floorplan-affordances.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,mBAAmB,EACxB,KAAK,SAAS,EAEf,MAAM,kBAAkB,CAAA;AAGzB,eAAO,MAAM,qBAAqB,EAAE,mBAAmB,CAAC,SAAS,CA6BhE,CAAA"}
1
+ {"version":3,"file":"floorplan-affordances.d.ts","sourceRoot":"","sources":["../../src/spawn/floorplan-affordances.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,mBAAmB,EACxB,KAAK,SAAS,EAGf,MAAM,kBAAkB,CAAA;AAIzB,eAAO,MAAM,qBAAqB,EAAE,mBAAmB,CAAC,SAAS,CA+BhE,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
  export const spawnRotateAffordance = {
4
5
  start({ node, initialPlanPoint }) {
@@ -10,20 +11,22 @@ export const spawnRotateAffordance = {
10
11
  let lastRotation = initialRotation;
11
12
  return {
12
13
  affectedIds: [spawnId],
13
- apply({ planPoint, modifiers }) {
14
+ apply({ planPoint }) {
14
15
  const delta = rotateAffordanceDelta({
15
16
  center: [cx, cz],
16
17
  initialAngle,
17
18
  planPoint,
18
- free: modifiers.shiftKey,
19
+ free: !isAngleSnapActive(),
19
20
  });
20
21
  lastRotation = initialRotation - delta;
21
- useScene.getState().updateNode(spawnId, { rotation: lastRotation });
22
+ useLiveNodeOverrides.getState().set(spawnId, { rotation: lastRotation });
23
+ useScene.getState().markDirty(spawnId);
22
24
  },
23
25
  canCommit() {
24
26
  return true;
25
27
  },
26
28
  commit() {
29
+ useLiveNodeOverrides.getState().clear(spawnId);
27
30
  useScene.getState().updateNode(spawnId, { rotation: lastRotation });
28
31
  },
29
32
  };
@@ -1 +1 @@
1
- {"version":3,"file":"floorplan-move.d.ts","sourceRoot":"","sources":["../../src/spawn/floorplan-move.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,mBAAmB,EAExB,KAAK,SAAS,EAGf,MAAM,kBAAkB,CAAA;AAGzB,eAAO,MAAM,wBAAwB,EAAE,mBAAmB,CAAC,SAAS,CA4BnE,CAAA"}
1
+ {"version":3,"file":"floorplan-move.d.ts","sourceRoot":"","sources":["../../src/spawn/floorplan-move.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,mBAAmB,EAExB,KAAK,SAAS,EAIf,MAAM,kBAAkB,CAAA;AAGzB,eAAO,MAAM,wBAAwB,EAAE,mBAAmB,CAAC,SAAS,CA8BnE,CAAA"}
@@ -1,5 +1,5 @@
1
- import { snapScalar, useScene, } from '@pascal-app/core';
2
- import { getSegmentGridStep } from '@pascal-app/editor';
1
+ import { snapScalar, useLiveNodeOverrides, useScene, } from '@pascal-app/core';
2
+ import { getSegmentGridStep, isGridSnapActive } from '@pascal-app/editor';
3
3
  export const spawnFloorplanMoveTarget = ({ node }) => {
4
4
  const spawnId = node.id;
5
5
  const startY = node.position[1];
@@ -7,14 +7,15 @@ export const spawnFloorplanMoveTarget = ({ node }) => {
7
7
  let lastPosition = null;
8
8
  const session = {
9
9
  affectedIds: [spawnId],
10
- apply({ planPoint, modifiers }) {
11
- const step = getSegmentGridStep();
12
- const snap = (value) => (modifiers.shiftKey ? value : snapScalar(value, step));
10
+ apply({ planPoint }) {
11
+ const step = isGridSnapActive() ? getSegmentGridStep() : 0;
12
+ const snap = (value) => (step > 0 ? snapScalar(value, step) : value);
13
13
  const next = [snap(planPoint[0]), startY, snap(planPoint[1])];
14
14
  if (lastPosition && lastPosition[0] === next[0] && lastPosition[2] === next[2])
15
15
  return;
16
16
  lastPosition = next;
17
- useScene.getState().updateNodes([{ id: spawnId, data: { position: next } }]);
17
+ useLiveNodeOverrides.getState().set(spawnId, { position: next });
18
+ useScene.getState().markDirty(spawnId);
18
19
  },
19
20
  canCommit() {
20
21
  if (!lastPosition)
@@ -24,6 +25,7 @@ export const spawnFloorplanMoveTarget = ({ node }) => {
24
25
  commit() {
25
26
  if (!lastPosition)
26
27
  return;
28
+ useLiveNodeOverrides.getState().clear(spawnId);
27
29
  useScene.getState().updateNodes([{ id: spawnId, data: { position: lastPosition } }]);
28
30
  },
29
31
  };
@@ -1,4 +1,8 @@
1
1
  import { type SpawnNode } from '@pascal-app/core';
2
+ export declare const SpawnPreview: ({ layers, node }: {
3
+ layers?: number;
4
+ node: SpawnNode;
5
+ }) => import("react").JSX.Element;
2
6
  /**
3
7
  * Registry-driven spawn renderer. Behaviorally identical to the legacy
4
8
  * `@pascal-app/viewer/components/renderers/spawn/spawn-renderer.tsx` — same
@@ -1 +1 @@
1
- {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/spawn/renderer.tsx"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,SAAS,EAIf,MAAM,kBAAkB,CAAA;AAOzB;;;;;;;;;GASG;AACH,QAAA,MAAM,aAAa,GAAI,UAAU;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,gCAkEnD,CAAA;AAED,eAAe,aAAa,CAAA"}
1
+ {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/spawn/renderer.tsx"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,SAAS,EAIf,MAAM,kBAAkB,CAAA;AAoGzB,eAAO,MAAM,YAAY,GAAI,kBAAkB;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,SAAS,CAAA;CAAE,gCAElF,CAAA;AAED;;;;;;;;;GASG;AACH,QAAA,MAAM,aAAa,GAAI,UAAU;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,gCAsBnD,CAAA;AAED,eAAe,aAAa,CAAA"}