@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,29 +1,18 @@
1
1
  'use client';
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { useLiveNodeOverrides, useLiveTransforms, useRegistry, } from '@pascal-app/core';
4
4
  import { createDefaultMaterial, useNodeEvents, useViewer } from '@pascal-app/viewer';
5
5
  import { useMemo, useRef } from 'react';
6
6
  import { Color, Shape } from 'three';
7
7
  const SPAWN_COLOR = new Color('#818cf8');
8
+ const disableRaycast = () => { };
8
9
  /**
9
- * Registry-driven spawn renderer. Behaviorally identical to the legacy
10
- * `@pascal-app/viewer/components/renderers/spawn/spawn-renderer.tsx` — same
11
- * geometry and event surface. When the spawn definition lands
12
- * in `builtinPlugin.nodes`, the Phase 0 dispatch shims switch the renderer
13
- * here and the legacy one is short-circuited.
14
- *
15
- * Lives in `@pascal-app/nodes` (not viewer) so the kind owns its own render
16
- * code. Phase 5's batch migration applies the same pattern to every node.
10
+ * Shared visible spawn model. Placement uses the same four meshes as the
11
+ * committed renderer so the orientation shown before click is authoritative.
17
12
  */
18
- const SpawnRenderer = ({ node }) => {
19
- const ref = useRef(null);
13
+ const SpawnVisual = ({ ghost = false, layers, node, }) => {
20
14
  const handlers = useNodeEvents(node, 'spawn');
21
- const liveOverride = useLiveNodeOverrides((state) => state.get(node.id));
22
- const effectiveNode = useMemo(() => (liveOverride ? { ...node, ...liveOverride } : node), [node, liveOverride]);
23
- const liveTransform = useLiveTransforms((state) => state.get(node.id));
24
- const walkthroughMode = useViewer((state) => state.walkthroughMode);
25
15
  const shading = useViewer((state) => state.shading);
26
- useRegistry(node.id, 'spawn', ref);
27
16
  const material = useMemo(() => {
28
17
  const next = createDefaultMaterial('#818cf8', 0.42, shading);
29
18
  next.emissive?.copy(SPAWN_COLOR);
@@ -31,9 +20,14 @@ const SpawnRenderer = ({ node }) => {
31
20
  next.emissiveIntensity = 0.08;
32
21
  if ('metalness' in next)
33
22
  next.metalness = 0.03;
23
+ if (ghost) {
24
+ next.transparent = true;
25
+ next.opacity = 0.5;
26
+ next.depthWrite = false;
27
+ }
34
28
  next.needsUpdate = true;
35
29
  return next;
36
- }, [shading]);
30
+ }, [ghost, shading]);
37
31
  const arrowShape = useMemo(() => {
38
32
  const shape = new Shape();
39
33
  shape.moveTo(0, 0.24);
@@ -42,6 +36,26 @@ const SpawnRenderer = ({ node }) => {
42
36
  shape.closePath();
43
37
  return shape;
44
38
  }, []);
45
- return (_jsxs("group", { position: liveTransform?.position ?? effectiveNode.position, ref: ref, rotation: [0, liveTransform?.rotation ?? effectiveNode.rotation, 0], visible: !walkthroughMode && effectiveNode.visible !== false, children: [_jsxs("mesh", { position: [0, 0.09, 0], rotation: [-Math.PI / 2, 0, 0], ...handlers, children: [_jsx("ringGeometry", { args: [0.34, 0.48, 48] }), _jsx("primitive", { attach: "material", object: material })] }), _jsxs("mesh", { position: [0, 0.1, -0.52], rotation: [-Math.PI / 2, 0, 0], ...handlers, children: [_jsx("shapeGeometry", { args: [arrowShape] }), _jsx("primitive", { attach: "material", object: material })] }), _jsxs("mesh", { position: [0, 0.41, 0], ...handlers, children: [_jsx("boxGeometry", { args: [0.3, 0.54, 0.16] }), _jsx("primitive", { attach: "material", object: material })] }), _jsxs("mesh", { position: [0, 0.83, 0], ...handlers, children: [_jsx("boxGeometry", { args: [0.18, 0.18, 0.18] }), _jsx("primitive", { attach: "material", object: material })] })] }));
39
+ return (_jsxs(_Fragment, { children: [_jsxs("mesh", { layers: layers, position: [0, 0.09, 0], raycast: ghost ? disableRaycast : undefined, rotation: [-Math.PI / 2, 0, 0], ...(ghost ? {} : handlers), children: [_jsx("ringGeometry", { args: [0.34, 0.48, 48] }), _jsx("primitive", { attach: "material", object: material })] }), _jsxs("mesh", { layers: layers, position: [0, 0.1, -0.52], raycast: ghost ? disableRaycast : undefined, rotation: [-Math.PI / 2, 0, 0], ...(ghost ? {} : handlers), children: [_jsx("shapeGeometry", { args: [arrowShape] }), _jsx("primitive", { attach: "material", object: material })] }), _jsxs("mesh", { layers: layers, position: [0, 0.41, 0], raycast: ghost ? disableRaycast : undefined, ...(ghost ? {} : handlers), children: [_jsx("boxGeometry", { args: [0.3, 0.54, 0.16] }), _jsx("primitive", { attach: "material", object: material })] }), _jsxs("mesh", { layers: layers, position: [0, 0.83, 0], raycast: ghost ? disableRaycast : undefined, ...(ghost ? {} : handlers), children: [_jsx("boxGeometry", { args: [0.18, 0.18, 0.18] }), _jsx("primitive", { attach: "material", object: material })] })] }));
40
+ };
41
+ export const SpawnPreview = ({ layers, node }) => (_jsx(SpawnVisual, { ghost: true, layers: layers, node: node }));
42
+ /**
43
+ * Registry-driven spawn renderer. Behaviorally identical to the legacy
44
+ * `@pascal-app/viewer/components/renderers/spawn/spawn-renderer.tsx` — same
45
+ * geometry and event surface. When the spawn definition lands
46
+ * in `builtinPlugin.nodes`, the Phase 0 dispatch shims switch the renderer
47
+ * here and the legacy one is short-circuited.
48
+ *
49
+ * Lives in `@pascal-app/nodes` (not viewer) so the kind owns its own render
50
+ * code. Phase 5's batch migration applies the same pattern to every node.
51
+ */
52
+ const SpawnRenderer = ({ node }) => {
53
+ const ref = useRef(null);
54
+ const liveOverride = useLiveNodeOverrides((state) => state.get(node.id));
55
+ const effectiveNode = useMemo(() => (liveOverride ? { ...node, ...liveOverride } : node), [node, liveOverride]);
56
+ const liveTransform = useLiveTransforms((state) => state.get(node.id));
57
+ const walkthroughMode = useViewer((state) => state.walkthroughMode);
58
+ useRegistry(node.id, 'spawn', ref);
59
+ return (_jsx("group", { position: liveTransform?.position ?? effectiveNode.position, ref: ref, rotation: [0, liveTransform?.rotation ?? effectiveNode.rotation, 0], visible: !walkthroughMode && effectiveNode.visible !== false, children: _jsx(SpawnVisual, { node: effectiveNode }) }));
46
60
  };
47
61
  export default SpawnRenderer;
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * Registry-driven spawn placement tool. Reads `activeLevelId` from useViewer
3
3
  * directly (no props), broadcasts placement via store updates + SFX, and
4
- * uses the shared CursorSphere from @pascal-app/editor for visual parity
5
- * with legacy placement tools. Snapping is mode-driven (grid + Figma-style
4
+ * shows the real spawn model as a translucent placement ghost, and supports
5
+ * R/T yaw before commit. Snapping is mode-driven (grid + Figma-style
6
6
  * alignment "lines"), matching the shelf / column build tools.
7
7
  */
8
8
  declare const SpawnTool: () => import("react").JSX.Element | null;
@@ -1 +1 @@
1
- {"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../src/spawn/tool.tsx"],"names":[],"mappings":"AAoCA;;;;;;GAMG;AACH,QAAA,MAAM,SAAS,0CAwGd,CAAA;AAED,eAAe,SAAS,CAAA"}
1
+ {"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../src/spawn/tool.tsx"],"names":[],"mappings":"AAyCA;;;;;;GAMG;AACH,QAAA,MAAM,SAAS,0CA8Kd,CAAA;AAED,eAAe,SAAS,CAAA"}
@@ -1,10 +1,12 @@
1
1
  'use client';
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
- import { collectAlignmentAnchors, emitter, SpawnNode, useScene, } from '@pascal-app/core';
4
- import { CursorSphere, getFloorStackPreviewPosition, isAlignmentGuideActive, isGridSnapActive, isMagneticSnapActive, movementSfxStepKey, triggerSFX, useAlignmentGuides, useEditor, } from '@pascal-app/editor';
3
+ import { collectAlignmentAnchors, emitter, resolveSupportSlabPatch, SpawnNode, useScene, } from '@pascal-app/core';
4
+ import { EDITOR_LAYER, getFloorStackPreviewPosition, isAlignmentGuideActive, isGridSnapActive, isMagneticSnapActive, movementSfxStepKey, triggerSFX, useAlignmentGuides, useEditor, usePlacementPreview, } from '@pascal-app/editor';
5
5
  import { useViewer } from '@pascal-app/viewer';
6
- import { useEffect, useMemo, useRef } from 'react';
6
+ import { useEffect, useMemo, useRef, useState } from 'react';
7
7
  import { getLevelLocalSnappedPosition, resolveAlignedFloorPlacement, } from '../shared/floor-placement';
8
+ import { SpawnPreview } from './renderer';
9
+ const ROTATION_STEP = Math.PI / 4;
8
10
  function getExistingSpawnIds() {
9
11
  const nodes = useScene.getState().nodes;
10
12
  return Object.values(nodes)
@@ -15,23 +17,34 @@ function getExistingSpawnIds() {
15
17
  /**
16
18
  * Registry-driven spawn placement tool. Reads `activeLevelId` from useViewer
17
19
  * directly (no props), broadcasts placement via store updates + SFX, and
18
- * uses the shared CursorSphere from @pascal-app/editor for visual parity
19
- * with legacy placement tools. Snapping is mode-driven (grid + Figma-style
20
+ * shows the real spawn model as a translucent placement ghost, and supports
21
+ * R/T yaw before commit. Snapping is mode-driven (grid + Figma-style
20
22
  * alignment "lines"), matching the shelf / column build tools.
21
23
  */
22
24
  const SpawnTool = () => {
23
25
  const activeLevelId = useViewer((state) => state.selection.levelId);
24
26
  const cursorRef = useRef(null);
25
27
  const previousSnapRef = useRef(null);
28
+ const rotationRef = useRef(0);
29
+ const cursorVisibleRef = useRef(false);
30
+ const [cursorVisible, setCursorVisible] = useState(false);
26
31
  // Default spawn for the footprint anchors the alignment solver reads.
27
32
  const previewNode = useMemo(() => SpawnNode.parse({ name: 'Spawn Point', position: [0, 0, 0], rotation: 0 }), []);
28
33
  useEffect(() => {
29
34
  if (!activeLevelId)
30
35
  return;
31
36
  previousSnapRef.current = null;
37
+ rotationRef.current = 0;
38
+ cursorRef.current?.rotation.set(0, 0, 0);
39
+ cursorVisibleRef.current = false;
40
+ setCursorVisible(false);
32
41
  const lastCursorRef = { current: null };
33
42
  let alignmentCandidates = collectAlignmentAnchors(useScene.getState().nodes, previewNode.id);
34
43
  const onGridMove = (event) => {
44
+ if (!cursorVisibleRef.current) {
45
+ cursorVisibleRef.current = true;
46
+ setCursorVisible(true);
47
+ }
35
48
  const { position, guides } = resolveAlignedFloorPlacement({
36
49
  node: previewNode,
37
50
  rawX: event.localPosition[0],
@@ -46,11 +59,16 @@ const SpawnTool = () => {
46
59
  const visualPosition = getFloorStackPreviewPosition({
47
60
  node: previewNode,
48
61
  position,
49
- rotation: 0,
62
+ rotation: rotationRef.current,
50
63
  levelId: activeLevelId,
51
64
  });
52
65
  cursorRef.current?.position.set(...visualPosition);
53
66
  lastCursorRef.current = position;
67
+ usePlacementPreview.getState().set({
68
+ ...previewNode,
69
+ position,
70
+ rotation: rotationRef.current,
71
+ });
54
72
  const nextSnapKey = movementSfxStepKey({
55
73
  coords: [position[0], position[2]],
56
74
  gridSnapActive: isGridSnapActive(),
@@ -68,10 +86,18 @@ const SpawnTool = () => {
68
86
  const [existingSpawnId, ...duplicates] = getExistingSpawnIds();
69
87
  let placedId;
70
88
  if (existingSpawnId) {
89
+ const live = useScene.getState().nodes[existingSpawnId];
90
+ const effectiveSpawn = SpawnNode.parse({
91
+ ...live,
92
+ parentId: activeLevelId,
93
+ position: next,
94
+ rotation: rotationRef.current,
95
+ });
71
96
  useScene.getState().updateNode(existingSpawnId, {
72
97
  parentId: activeLevelId,
73
98
  position: next,
74
- rotation: 0,
99
+ rotation: rotationRef.current,
100
+ ...resolveSupportSlabPatch(effectiveSpawn, useScene.getState().nodes),
75
101
  });
76
102
  if (duplicates.length > 0) {
77
103
  useScene.getState().deleteNodes(duplicates);
@@ -82,28 +108,69 @@ const SpawnTool = () => {
82
108
  const spawn = SpawnNode.parse({
83
109
  name: 'Spawn Point',
84
110
  position: next,
85
- rotation: 0,
111
+ rotation: rotationRef.current,
112
+ parentId: activeLevelId,
113
+ });
114
+ const committedSpawn = SpawnNode.parse({
115
+ ...spawn,
116
+ ...resolveSupportSlabPatch(spawn, useScene.getState().nodes),
86
117
  });
87
- useScene.getState().createNode(spawn, activeLevelId);
88
- placedId = spawn.id;
118
+ useScene.getState().createNode(committedSpawn, activeLevelId);
119
+ placedId = committedSpawn.id;
89
120
  }
90
121
  useViewer.getState().setSelection({ selectedIds: [placedId] });
91
122
  triggerSFX('sfx:structure-build');
92
123
  alignmentCandidates = collectAlignmentAnchors(useScene.getState().nodes, previewNode.id);
93
124
  useAlignmentGuides.getState().clear();
125
+ usePlacementPreview.getState().clear();
94
126
  useEditor.getState().setTool(null);
95
127
  useEditor.getState().setMode('select');
96
128
  };
129
+ const onKeyDown = (event) => {
130
+ const target = event.target;
131
+ if (event.repeat ||
132
+ event.metaKey ||
133
+ event.ctrlKey ||
134
+ event.altKey ||
135
+ target?.tagName === 'INPUT' ||
136
+ target?.tagName === 'TEXTAREA' ||
137
+ target?.isContentEditable) {
138
+ return;
139
+ }
140
+ let delta = 0;
141
+ if (event.key === 'r' || event.key === 'R')
142
+ delta = ROTATION_STEP;
143
+ else if (event.key === 't' || event.key === 'T')
144
+ delta = -ROTATION_STEP;
145
+ else
146
+ return;
147
+ event.preventDefault();
148
+ event.stopPropagation();
149
+ rotationRef.current += delta;
150
+ if (cursorRef.current)
151
+ cursorRef.current.rotation.y = rotationRef.current;
152
+ if (lastCursorRef.current) {
153
+ usePlacementPreview.getState().set({
154
+ ...previewNode,
155
+ position: lastCursorRef.current,
156
+ rotation: rotationRef.current,
157
+ });
158
+ }
159
+ triggerSFX('sfx:item-rotate');
160
+ };
97
161
  emitter.on('grid:move', onGridMove);
98
162
  emitter.on('grid:click', onGridClick);
163
+ window.addEventListener('keydown', onKeyDown, true);
99
164
  return () => {
100
165
  emitter.off('grid:move', onGridMove);
101
166
  emitter.off('grid:click', onGridClick);
167
+ window.removeEventListener('keydown', onKeyDown, true);
102
168
  useAlignmentGuides.getState().clear();
169
+ usePlacementPreview.getState().clear();
103
170
  };
104
171
  }, [activeLevelId, previewNode]);
105
172
  if (!activeLevelId)
106
173
  return null;
107
- return _jsx(CursorSphere, { color: "#818cf8", height: 2.2, ref: cursorRef });
174
+ return (_jsx("group", { ref: cursorRef, visible: cursorVisible, children: _jsx(SpawnPreview, { layers: EDITOR_LAYER, node: previewNode }) }));
108
175
  };
109
176
  export default SpawnTool;
@@ -1 +1 @@
1
- {"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../src/stair/definition.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,cAAc,EAMpB,MAAM,kBAAkB,CAAA;AAkZzB,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAGpC;;;;GAIG;AACH,eAAO,MAAM,eAAe,EAAE,cAAc,CAAC,OAAO,SAAS,CA0G5D,CAAA"}
1
+ {"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../src/stair/definition.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,cAAc,EAQpB,MAAM,kBAAkB,CAAA;AAuZzB,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAGpC;;;;GAIG;AACH,eAAO,MAAM,eAAe,EAAE,cAAc,CAAC,OAAO,SAAS,CAgH5D,CAAA"}
@@ -1,4 +1,4 @@
1
- import { StairNode as StairNodeSchema, stairFootprintAABB, } from '@pascal-app/core';
1
+ import { resolveStairTotalRise, StairNode as StairNodeSchema, stairFootprintAABB, useScene, } from '@pascal-app/core';
2
2
  const MIN_CURVED_RISE = 0.3;
3
3
  const MIN_CURVED_WIDTH = 0.4;
4
4
  const MIN_CURVED_INNER_RADIUS_SPIRAL = 0.05;
@@ -21,10 +21,13 @@ const CURVED_INNER_RING_MIN = 0.05;
21
21
  const STAIR_ROTATE_CORNER_OFFSET = 0.4;
22
22
  const STAIR_ROTATE_RING_OFFSET = 0.08;
23
23
  const STAIR_MOVE_FRONT_OFFSET = 0.35;
24
+ function readTotalRise(node) {
25
+ return Math.max(resolveStairTotalRise(node, useScene.getState().nodes), 0.1);
26
+ }
24
27
  function readCurvedStairGeometry(node) {
25
28
  const isSpiral = node.stairType === 'spiral';
26
29
  const stepCount = Math.max(2, Math.round(node.stepCount ?? 10));
27
- const totalRise = Math.max(node.totalRise ?? 2.5, 0.1);
30
+ const totalRise = readTotalRise(node);
28
31
  const width = Math.max(node.width ?? 1, MIN_CURVED_WIDTH);
29
32
  const minInnerRadius = isSpiral ? MIN_CURVED_INNER_RADIUS_SPIRAL : MIN_CURVED_INNER_RADIUS_CURVED;
30
33
  const innerRadius = Math.max(minInnerRadius, node.innerRadius ?? 0.9);
@@ -61,7 +64,7 @@ function fallbackStraightStairMoveBounds(node) {
61
64
  maxX: width / 2,
62
65
  minZ: 0,
63
66
  maxZ: depth,
64
- height: Math.max(node.totalRise ?? 2.5, 0.1),
67
+ height: readTotalRise(node),
65
68
  };
66
69
  }
67
70
  function readStraightStairMoveBounds(node, sceneApi) {
@@ -119,7 +122,7 @@ function curvedRiseHandle() {
119
122
  axis: 'y',
120
123
  anchor: 'min',
121
124
  min: MIN_CURVED_RISE,
122
- currentValue: (n) => Math.max(n.totalRise ?? 2.5, 0.1),
125
+ currentValue: readTotalRise,
123
126
  apply: (_n, newRise) => ({ totalRise: newRise }),
124
127
  placement: {
125
128
  position: (n) => {
@@ -255,7 +258,7 @@ function stairRotateGizmoPosition(n) {
255
258
  return [radius * Math.cos(angle), g.totalRise / 2, radius * Math.sin(angle)];
256
259
  }
257
260
  const width = Math.max(n.width ?? 1, MIN_CURVED_WIDTH);
258
- const yMid = Math.max(n.totalRise ?? 2.5, 0.1) / 2;
261
+ const yMid = readTotalRise(n) / 2;
259
262
  return [width / 2 + STAIR_ROTATE_CORNER_OFFSET, yMid, -STAIR_ROTATE_CORNER_OFFSET];
260
263
  }
261
264
  function stairRotateHandle() {
@@ -290,7 +293,7 @@ function stairRotateHandle() {
290
293
  return (Math.hypot(width / 2 + STAIR_ROTATE_CORNER_OFFSET, STAIR_ROTATE_CORNER_OFFSET) +
291
294
  STAIR_ROTATE_RING_OFFSET);
292
295
  },
293
- y: (n) => Math.max(n.totalRise ?? 2.5, 0.1) / 2,
296
+ y: (n) => readTotalRise(n) / 2,
294
297
  },
295
298
  };
296
299
  }
@@ -346,6 +349,11 @@ export const stairDefinition = {
346
349
  schemaVersion: 1,
347
350
  schema: StairNode,
348
351
  category: 'structure',
352
+ extensions: {
353
+ 'pascal:editor/floorplan': {
354
+ linkedLevelIds: (node) => node.toLevelId && node.toLevelId !== node.parentId ? [node.toLevelId] : [],
355
+ },
356
+ },
349
357
  snapProfile: 'structural',
350
358
  // A footprint with a clear front: you approach a stair from the low end,
351
359
  // which sits on the -Z side of the run (the run ascends along +Z). Show the
@@ -377,7 +385,7 @@ export const stairDefinition = {
377
385
  const aabb = stairFootprintAABB(node, nodes);
378
386
  return aabb ? { shape: 'aabb', ...aabb } : null;
379
387
  },
380
- duplicable: true,
388
+ duplicable: { subtree: true },
381
389
  deletable: true,
382
390
  floorPlaced: {
383
391
  footprints: (node, ctx) => ctx ? getStairFloorPlacedFootprints(node, ctx.nodes) : [],
@@ -0,0 +1,16 @@
1
+ import type { AnyNode, StairNode } from '@pascal-app/core';
2
+ /**
3
+ * Computes the stair patch for a destination ("To") switch.
4
+ *
5
+ * Attaching to a deck clears any explicit custom rise (the rise follows the
6
+ * deck's elevation from now on) and disables the auto cutout — a deck stair
7
+ * lands ON its destination slab, not through it. Switching a deck-attached
8
+ * stair back to a level clears both again so the rise re-derives from the
9
+ * storey height, and restores `slabOpeningMode: 'destination'` — the
10
+ * placement default (the schema default is 'none', but the stair tool places
11
+ * ordinary stairs with 'destination', so that is what a level-destination
12
+ * stair regains). Plain level-to-level switches leave rise and opening mode
13
+ * alone.
14
+ */
15
+ export declare function getStairDestinationUpdates(stair: StairNode, target: AnyNode | undefined, targetId: string): Partial<StairNode>;
16
+ //# sourceMappingURL=destination.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"destination.d.ts","sourceRoot":"","sources":["../../src/stair/destination.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAE1D;;;;;;;;;;;;GAYG;AACH,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,SAAS,EAChB,MAAM,EAAE,OAAO,GAAG,SAAS,EAC3B,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,SAAS,CAAC,CAUpB"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Computes the stair patch for a destination ("To") switch.
3
+ *
4
+ * Attaching to a deck clears any explicit custom rise (the rise follows the
5
+ * deck's elevation from now on) and disables the auto cutout — a deck stair
6
+ * lands ON its destination slab, not through it. Switching a deck-attached
7
+ * stair back to a level clears both again so the rise re-derives from the
8
+ * storey height, and restores `slabOpeningMode: 'destination'` — the
9
+ * placement default (the schema default is 'none', but the stair tool places
10
+ * ordinary stairs with 'destination', so that is what a level-destination
11
+ * stair regains). Plain level-to-level switches leave rise and opening mode
12
+ * alone.
13
+ */
14
+ export function getStairDestinationUpdates(stair, target, targetId) {
15
+ if (target?.type === 'slab') {
16
+ return { deckSlabId: targetId, totalRise: undefined, slabOpeningMode: 'none' };
17
+ }
18
+ const updates = { toLevelId: targetId, deckSlabId: undefined };
19
+ if (stair.deckSlabId) {
20
+ updates.totalRise = undefined;
21
+ updates.slabOpeningMode = 'destination';
22
+ }
23
+ return updates;
24
+ }
@@ -0,0 +1,8 @@
1
+ import { type FloorplanGeometry, type GeometryContext, type StairNode } from '@pascal-app/core';
2
+ import type { FloorplanStairArrowEntry, FloorplanStairEntry } from '@pascal-app/editor';
3
+ export type StairPlanDirection = 'up' | 'down';
4
+ export declare function resolveStairPlanDirection(stair: StairNode, activeLevelId: string | null | undefined): StairPlanDirection;
5
+ export declare function resolveStraightStairDirectionArrow(entry: FloorplanStairEntry, direction: StairPlanDirection): FloorplanStairArrowEntry | null;
6
+ export declare function stairPlanBreakStep(stepCount: number): number;
7
+ export declare function buildStairDocumentation(stair: StairNode, entry: FloorplanStairEntry, ctx: GeometryContext): FloorplanGeometry[];
8
+ //# sourceMappingURL=documentation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"documentation.d.ts","sourceRoot":"","sources":["../../src/stair/documentation.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,iBAAiB,EAEtB,KAAK,eAAe,EAGpB,KAAK,SAAS,EAEf,MAAM,kBAAkB,CAAA;AACzB,OAAO,KAAK,EACV,wBAAwB,EACxB,mBAAmB,EAEpB,MAAM,oBAAoB,CAAA;AAgB3B,MAAM,MAAM,kBAAkB,GAAG,IAAI,GAAG,MAAM,CAAA;AAE9C,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,SAAS,EAChB,aAAa,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACvC,kBAAkB,CAUpB;AAED,wBAAgB,kCAAkC,CAChD,KAAK,EAAE,mBAAmB,EAC1B,SAAS,EAAE,kBAAkB,GAC5B,wBAAwB,GAAG,IAAI,CA0BjC;AAED,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAE5D;AAED,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,SAAS,EAChB,KAAK,EAAE,mBAAmB,EAC1B,GAAG,EAAE,eAAe,GACnB,iBAAiB,EAAE,CAYrB"}
@@ -0,0 +1,245 @@
1
+ import { resolveStairTotalRise, useScene, } from '@pascal-app/core';
2
+ import { floorplanGeometryMetadata, readFloorplanContext } from '@pascal-app/editor';
3
+ import { formatConstructionLength, } from '../shared/construction-length';
4
+ const ANNOTATION_OFFSET = 0.28;
5
+ const ANNOTATION_FONT_SIZE = 0.125;
6
+ const DIRECTION_FONT_SIZE = 0.16;
7
+ const BREAK_POSITION = 0.68;
8
+ const BREAK_ZIGZAG = 0.07;
9
+ const MIN_ARROW_HEAD = 0.14;
10
+ const MAX_ARROW_HEAD = 0.24;
11
+ export function resolveStairPlanDirection(stair, activeLevelId) {
12
+ if (activeLevelId &&
13
+ stair.toLevelId &&
14
+ stair.toLevelId !== stair.fromLevelId &&
15
+ activeLevelId === stair.toLevelId) {
16
+ return 'down';
17
+ }
18
+ return 'up';
19
+ }
20
+ export function resolveStraightStairDirectionArrow(entry, direction) {
21
+ const arrow = entry.arrow;
22
+ if (!arrow || direction === 'up')
23
+ return arrow;
24
+ const polyline = [...arrow.polyline].reverse();
25
+ const tip = polyline[polyline.length - 1];
26
+ const tail = polyline[polyline.length - 2];
27
+ if (!(tip && tail))
28
+ return null;
29
+ const bodyLength = distance(tail, tip);
30
+ if (bodyLength <= Number.EPSILON)
31
+ return null;
32
+ const headLength = clamp(bodyLength * 0.72, MIN_ARROW_HEAD, MAX_ARROW_HEAD);
33
+ const directionX = (tip.x - tail.x) / bodyLength;
34
+ const directionY = (tip.y - tail.y) / bodyLength;
35
+ const base = {
36
+ x: tip.x - directionX * headLength,
37
+ y: tip.y - directionY * headLength,
38
+ };
39
+ const halfWidth = headLength * 0.34;
40
+ return {
41
+ polyline,
42
+ head: [
43
+ tip,
44
+ { x: base.x - directionY * halfWidth, y: base.y + directionX * halfWidth },
45
+ { x: base.x + directionY * halfWidth, y: base.y - directionX * halfWidth },
46
+ ],
47
+ };
48
+ }
49
+ export function stairPlanBreakStep(stepCount) {
50
+ return Math.max(1, Math.ceil(Math.max(1, Math.round(stepCount)) * BREAK_POSITION));
51
+ }
52
+ export function buildStairDocumentation(stair, entry, ctx) {
53
+ const activeLevelId = ctx.parent?.type === 'level' ? ctx.parent.id : stair.parentId;
54
+ const direction = resolveStairPlanDirection(stair, activeLevelId);
55
+ const unit = ctx.viewState?.unit ?? 'metric';
56
+ const floorplanContext = readFloorplanContext(ctx);
57
+ const profile = floorplanContext.purpose === 'document' ? 'document' : 'editor';
58
+ const metricNotation = floorplanContext.metricNotation;
59
+ const stroke = ctx.viewState?.palette.measurementStroke ?? '#334155';
60
+ return stair.stairType === 'straight'
61
+ ? buildStraightDocumentation(stair, entry, direction, unit, profile, metricNotation, stroke)
62
+ : buildCurvedDocumentation(stair, direction, unit, profile, metricNotation, stroke);
63
+ }
64
+ function buildStraightDocumentation(stair, entry, direction, unit, profile, metricNotation, stroke) {
65
+ const geometries = [];
66
+ const arrow = resolveStraightStairDirectionArrow(entry, direction);
67
+ const arrowStart = arrow?.polyline[0];
68
+ const arrowNext = arrow?.polyline[1];
69
+ if (arrowStart && arrowNext) {
70
+ const arrowDirection = normalizedDirection(arrowStart, arrowNext);
71
+ const labelPoint = arrowDirection
72
+ ? {
73
+ x: arrowStart.x - arrowDirection.y * 0.18,
74
+ y: arrowStart.y + arrowDirection.x * 0.18,
75
+ }
76
+ : arrowStart;
77
+ geometries.push(annotationText(labelPoint, direction === 'up' ? 'UP' : 'DN', DIRECTION_FONT_SIZE, stroke));
78
+ }
79
+ let railNotePlaced = false;
80
+ for (const segmentEntry of entry.segments) {
81
+ if (segmentEntry.segment.segmentType !== 'stair')
82
+ continue;
83
+ const frame = segmentFrame(segmentEntry);
84
+ if (!frame)
85
+ continue;
86
+ const segment = segmentEntry.segment;
87
+ const riserCount = Math.max(1, Math.round(segment.stepCount));
88
+ const riserHeight = segment.height / riserCount;
89
+ const treadDepth = segment.length / riserCount;
90
+ const rightAnchor = {
91
+ x: frame.rightMid.x + frame.widthDirection.x * ANNOTATION_OFFSET,
92
+ y: frame.rightMid.y + frame.widthDirection.y * ANNOTATION_OFFSET,
93
+ };
94
+ geometries.push(annotationText(rightAnchor, `${riserCount} R @ ${formatConstructionLength(riserHeight, unit, profile, { metricNotation })} · T ${formatConstructionLength(treadDepth, unit, profile, { metricNotation })} · CLR W ${formatConstructionLength(segment.width, unit, profile, { metricNotation })}`, ANNOTATION_FONT_SIZE, stroke), buildStraightBreakLine(segmentEntry, stroke));
95
+ if (!railNotePlaced && stair.railingMode !== 'none') {
96
+ const leftAnchor = {
97
+ x: frame.leftMid.x - frame.widthDirection.x * ANNOTATION_OFFSET,
98
+ y: frame.leftMid.y - frame.widthDirection.y * ANNOTATION_OFFSET,
99
+ };
100
+ geometries.push(annotationText(leftAnchor, `RAIL ${stair.railingMode.toLocaleUpperCase()} @ ${formatConstructionLength(stair.railingHeight, unit, profile, { metricNotation })}`, ANNOTATION_FONT_SIZE, stroke));
101
+ railNotePlaced = true;
102
+ }
103
+ }
104
+ return geometries;
105
+ }
106
+ function buildCurvedDocumentation(stair, direction, unit, profile, metricNotation, stroke) {
107
+ const stairType = stair.stairType === 'spiral' ? 'spiral' : 'curved';
108
+ const stepCount = Math.max(stairType === 'spiral' ? 6 : 4, Math.round(stair.stepCount));
109
+ const sweep = normalizedSweep(stair);
110
+ const startAngle = -stair.rotation - sweep / 2;
111
+ const endAngle = startAngle + sweep;
112
+ const innerRadius = Math.max(stairType === 'spiral' ? 0.05 : 0.2, stair.innerRadius);
113
+ const outerRadius = innerRadius + stair.width;
114
+ const walkingRadius = innerRadius + stair.width / 2;
115
+ const riserHeight = resolveStairTotalRise(stair, useScene.getState().nodes) / stepCount;
116
+ const treadDepth = (Math.abs(sweep) * walkingRadius) / stepCount;
117
+ const center = { x: stair.position[0], y: stair.position[2] };
118
+ const noteAngle = (startAngle + endAngle) / 2;
119
+ const notePoint = arcPoint(center, outerRadius + ANNOTATION_OFFSET, noteAngle);
120
+ const directionAngle = direction === 'up' ? startAngle + sweep * 0.18 : endAngle - sweep * 0.18;
121
+ const directionPoint = arcPoint(center, walkingRadius, directionAngle);
122
+ const breakAngle = startAngle + sweep * BREAK_POSITION;
123
+ const geometries = [
124
+ annotationText(notePoint, `${stepCount} R @ ${formatConstructionLength(riserHeight, unit, profile, { metricNotation })} · T(CL) ${formatConstructionLength(treadDepth, unit, profile, { metricNotation })} · CLR W ${formatConstructionLength(stair.width, unit, profile, { metricNotation })}`, ANNOTATION_FONT_SIZE, stroke),
125
+ annotationText(directionPoint, direction === 'up' ? 'UP' : 'DN', DIRECTION_FONT_SIZE, stroke),
126
+ buildCurvedBreakLine(center, innerRadius, outerRadius, breakAngle, stroke),
127
+ ];
128
+ if (stair.railingMode !== 'none') {
129
+ geometries.push(annotationText(arcPoint(center, outerRadius + ANNOTATION_OFFSET * 2, noteAngle), `RAIL ${stair.railingMode.toLocaleUpperCase()} @ ${formatConstructionLength(stair.railingHeight, unit, profile, { metricNotation })}`, ANNOTATION_FONT_SIZE, stroke));
130
+ }
131
+ return geometries;
132
+ }
133
+ function buildStraightBreakLine(segmentEntry, stroke) {
134
+ const [backLeft, backRight, frontRight, frontLeft] = segmentEntry.innerPolygon;
135
+ if (!(backLeft && backRight && frontRight && frontLeft)) {
136
+ return { kind: 'group', children: [] };
137
+ }
138
+ const left = interpolate(backLeft, frontLeft, BREAK_POSITION);
139
+ const right = interpolate(backRight, frontRight, BREAK_POSITION);
140
+ const travel = normalizedDirection(backLeft, frontLeft) ?? { x: 0, y: 1 };
141
+ return {
142
+ kind: 'polyline',
143
+ points: [
144
+ toTuple(left),
145
+ offset(interpolate(left, right, 0.42), travel, BREAK_ZIGZAG),
146
+ offset(interpolate(left, right, 0.5), travel, -BREAK_ZIGZAG),
147
+ offset(interpolate(left, right, 0.58), travel, BREAK_ZIGZAG),
148
+ toTuple(right),
149
+ ],
150
+ fill: 'none',
151
+ stroke,
152
+ strokeWidth: 1.5,
153
+ vectorEffect: 'non-scaling-stroke',
154
+ metadata: floorplanGeometryMetadata({ annotationRole: 'stair-annotation' }),
155
+ };
156
+ }
157
+ function buildCurvedBreakLine(center, innerRadius, outerRadius, angle, stroke) {
158
+ const radial = { x: Math.cos(angle), y: Math.sin(angle) };
159
+ const tangent = { x: -radial.y, y: radial.x };
160
+ const pointAt = (t, tangentOffset = 0) => {
161
+ const radius = innerRadius + (outerRadius - innerRadius) * t;
162
+ return [
163
+ center.x + radial.x * radius + tangent.x * tangentOffset,
164
+ center.y + radial.y * radius + tangent.y * tangentOffset,
165
+ ];
166
+ };
167
+ return {
168
+ kind: 'polyline',
169
+ points: [
170
+ pointAt(0),
171
+ pointAt(0.42, BREAK_ZIGZAG),
172
+ pointAt(0.5, -BREAK_ZIGZAG),
173
+ pointAt(0.58, BREAK_ZIGZAG),
174
+ pointAt(1),
175
+ ],
176
+ fill: 'none',
177
+ stroke,
178
+ strokeWidth: 1.5,
179
+ vectorEffect: 'non-scaling-stroke',
180
+ metadata: floorplanGeometryMetadata({ annotationRole: 'stair-annotation' }),
181
+ };
182
+ }
183
+ function annotationText(point, text, fontSize, fill) {
184
+ return {
185
+ kind: 'text',
186
+ x: point.x,
187
+ y: point.y,
188
+ text,
189
+ fontSize,
190
+ fill,
191
+ stroke: '#ffffff',
192
+ strokeWidth: fontSize * 0.22,
193
+ paintOrder: 'stroke',
194
+ fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace',
195
+ fontWeight: 650,
196
+ textAnchor: 'middle',
197
+ dominantBaseline: 'central',
198
+ upright: true,
199
+ metadata: floorplanGeometryMetadata({ annotationRole: 'stair-annotation' }),
200
+ };
201
+ }
202
+ function segmentFrame(segmentEntry) {
203
+ const [backLeft, backRight, frontRight, frontLeft] = segmentEntry.polygon;
204
+ if (!(backLeft && backRight && frontRight && frontLeft))
205
+ return null;
206
+ const widthDirection = normalizedDirection(backLeft, backRight);
207
+ if (!widthDirection)
208
+ return null;
209
+ return {
210
+ widthDirection,
211
+ leftMid: interpolate(backLeft, frontLeft, 0.5),
212
+ rightMid: interpolate(backRight, frontRight, 0.5),
213
+ };
214
+ }
215
+ function normalizedSweep(stair) {
216
+ const defaultSweep = stair.stairType === 'spiral' ? Math.PI * 2 : Math.PI / 2;
217
+ const sweep = stair.sweepAngle ?? defaultSweep;
218
+ if (Math.abs(sweep) < Math.PI * 2)
219
+ return sweep;
220
+ return Math.sign(sweep || 1) * (Math.PI * 2 - 0.001);
221
+ }
222
+ function arcPoint(center, radius, angle) {
223
+ return { x: center.x + Math.cos(angle) * radius, y: center.y + Math.sin(angle) * radius };
224
+ }
225
+ function normalizedDirection(start, end) {
226
+ const dx = end.x - start.x;
227
+ const dy = end.y - start.y;
228
+ const length = Math.hypot(dx, dy);
229
+ return length <= Number.EPSILON ? null : { x: dx / length, y: dy / length };
230
+ }
231
+ function interpolate(start, end, t) {
232
+ return { x: start.x + (end.x - start.x) * t, y: start.y + (end.y - start.y) * t };
233
+ }
234
+ function offset(point, direction, amount) {
235
+ return [point.x + direction.x * amount, point.y + direction.y * amount];
236
+ }
237
+ function toTuple(point) {
238
+ return [point.x, point.y];
239
+ }
240
+ function distance(first, second) {
241
+ return Math.hypot(second.x - first.x, second.y - first.y);
242
+ }
243
+ function clamp(value, min, max) {
244
+ return Math.min(max, Math.max(min, value));
245
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"floor-stack.d.ts","sourceRoot":"","sources":["../../src/stair/floor-stack.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EACP,SAAS,EACT,oBAAoB,EACpB,SAAS,EACT,gBAAgB,EACjB,MAAM,kBAAkB,CAAA;AAEzB,KAAK,gBAAgB,GAAG;IACtB,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IAClC,QAAQ,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE,SAAS,EAChB,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,GAC1C,oBAAoB,EAAE,CAMxB;AAED,wBAAgB,oCAAoC,CAClD,KAAK,EAAE,SAAS,EAChB,QAAQ,EAAE,SAAS,gBAAgB,EAAE,GACpC,oBAAoB,EAAE,CA4BxB;AAED,wBAAgB,uCAAuC,CACrD,QAAQ,EAAE,SAAS,gBAAgB,EAAE,GACpC,gBAAgB,EAAE,CAgDpB"}
1
+ {"version":3,"file":"floor-stack.d.ts","sourceRoot":"","sources":["../../src/stair/floor-stack.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EACP,SAAS,EACT,oBAAoB,EACpB,SAAS,EACT,gBAAgB,EACjB,MAAM,kBAAkB,CAAA;AAEzB,KAAK,gBAAgB,GAAG;IACtB,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IAClC,QAAQ,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE,SAAS,EAChB,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,GAC1C,oBAAoB,EAAE,CAUxB;AA+CD,wBAAgB,oCAAoC,CAClD,KAAK,EAAE,SAAS,EAChB,QAAQ,EAAE,SAAS,gBAAgB,EAAE,GACpC,oBAAoB,EAAE,CA4BxB;AAED,wBAAgB,uCAAuC,CACrD,QAAQ,EAAE,SAAS,gBAAgB,EAAE,GACpC,gBAAgB,EAAE,CAgDpB"}