@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
@@ -2,10 +2,11 @@ import type { CabinetModuleNode as CabinetModuleNodeType, CabinetNode as Cabinet
2
2
  import { useScene } from '@pascal-app/core';
3
3
  export type CabinetEditableNode = CabinetNodeType | CabinetModuleNodeType;
4
4
  export declare function bumpRunLayoutRevisionViaStore(scene: ReturnType<typeof useScene.getState>, run: CabinetNodeType): void;
5
- export declare function reflowRunModules({ modules, parentRun, patch, scene, selected, }: {
5
+ export declare function reflowRunModules({ modules, parentRun, patch, preserveExtent, scene, selected, }: {
6
6
  modules: CabinetModuleNodeType[];
7
7
  parentRun: CabinetNodeType;
8
8
  patch: Partial<CabinetModuleNodeType>;
9
+ preserveExtent?: boolean;
9
10
  scene: ReturnType<typeof useScene.getState>;
10
11
  selected: CabinetModuleNodeType;
11
12
  }): void;
@@ -1 +1 @@
1
- {"version":3,"file":"run-panel.d.ts","sourceRoot":"","sources":["../../src/cabinet/run-panel.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAEV,iBAAiB,IAAI,qBAAqB,EAC1C,WAAW,IAAI,eAAe,EAC/B,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAkB,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AA6B3D,MAAM,MAAM,mBAAmB,GAAG,eAAe,GAAG,qBAAqB,CAAA;AA2CzE,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE,UAAU,CAAC,OAAO,QAAQ,CAAC,QAAQ,CAAC,EAC3C,GAAG,EAAE,eAAe,QAIrB;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,OAAO,EACP,SAAS,EACT,KAAK,EACL,KAAK,EACL,QAAQ,GACT,EAAE;IACD,OAAO,EAAE,qBAAqB,EAAE,CAAA;IAChC,SAAS,EAAE,eAAe,CAAA;IAC1B,KAAK,EAAE,OAAO,CAAC,qBAAqB,CAAC,CAAA;IACrC,KAAK,EAAE,UAAU,CAAC,OAAO,QAAQ,CAAC,QAAQ,CAAC,CAAA;IAC3C,QAAQ,EAAE,qBAAqB,CAAA;CAChC,QAmDA;AAED,wBAAgB,eAAe,CAAC,EAC9B,IAAI,EACJ,OAAO,EACP,OAAO,GACR,EAAE;IACD,IAAI,EAAE,eAAe,CAAA;IACrB,OAAO,EAAE,qBAAqB,EAAE,CAAA;IAChC,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB,+BA0YA"}
1
+ {"version":3,"file":"run-panel.d.ts","sourceRoot":"","sources":["../../src/cabinet/run-panel.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAEV,iBAAiB,IAAI,qBAAqB,EAC1C,WAAW,IAAI,eAAe,EAC/B,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAkB,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AA8B3D,MAAM,MAAM,mBAAmB,GAAG,eAAe,GAAG,qBAAqB,CAAA;AA4CzE,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE,UAAU,CAAC,OAAO,QAAQ,CAAC,QAAQ,CAAC,EAC3C,GAAG,EAAE,eAAe,QAIrB;AAkCD,wBAAgB,gBAAgB,CAAC,EAC/B,OAAO,EACP,SAAS,EACT,KAAK,EACL,cAAsB,EACtB,KAAK,EACL,QAAQ,GACT,EAAE;IACD,OAAO,EAAE,qBAAqB,EAAE,CAAA;IAChC,SAAS,EAAE,eAAe,CAAA;IAC1B,KAAK,EAAE,OAAO,CAAC,qBAAqB,CAAC,CAAA;IACrC,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,KAAK,EAAE,UAAU,CAAC,OAAO,QAAQ,CAAC,QAAQ,CAAC,CAAA;IAC3C,QAAQ,EAAE,qBAAqB,CAAA;CAChC,QA8DA;AAED,wBAAgB,eAAe,CAAC,EAC9B,IAAI,EACJ,OAAO,EACP,OAAO,GACR,EAAE;IACD,IAAI,EAAE,eAAe,CAAA;IACrB,OAAO,EAAE,qBAAqB,EAAE,CAAA;IAChC,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB,+BA0YA"}
@@ -5,7 +5,7 @@ import { ActionButton, PanelSection, PanelWrapper, SegmentedControl, SliderContr
5
5
  import { useViewer } from '@pascal-app/viewer';
6
6
  import { Plus, Trash } from 'lucide-react';
7
7
  import { useCallback, useMemo } from 'react';
8
- import { addCabinetModuleSide, backAlignZ, bumpCabinetRunLayoutRevision, cornerLinkedSourceModuleForRun, runModuleBaseY, syncCornerRunsFromSourceModule, syncCornerStyleGroupFromRun, wallChildOf, } from './run-ops';
8
+ import { addCabinetModuleSide, backAlignZ, bumpCabinetRunLayoutRevision, cabinetMetadataRecord, cornerLinkedSourceModuleForRun, runModuleBaseY, syncCornerRunsFromSourceModule, syncCornerStyleGroupFromRun, wallChildOf, } from './run-ops';
9
9
  import { backAnchoredModuleZ, minCabinetCarcassHeightForStack, reflowCabinetRunModules, stackForCabinet, } from './stack';
10
10
  const RUN_POSITION_PATCH_KEYS = new Set(['showPlinth', 'plinthHeight']);
11
11
  const RUN_MODULE_SYNC_PATCH_KEYS = new Set([
@@ -15,6 +15,7 @@ const RUN_MODULE_SYNC_PATCH_KEYS = new Set([
15
15
  'handlePosition',
16
16
  ]);
17
17
  const RUN_DEPTH_PATCH_KEY = 'depth';
18
+ const PRESET_WIDTH_DEBT_KEY = 'cabinetPresetWidthDebtBySource';
18
19
  const FRONT_STYLE_OPTIONS = [
19
20
  { value: 'slab', label: 'Slab' },
20
21
  { value: 'shaker', label: 'Shaker' },
@@ -50,8 +51,35 @@ export function bumpRunLayoutRevisionViaStore(scene, run) {
50
51
  bumpCabinetRunLayoutRevision(createSceneApi(useScene), run);
51
52
  scene.markDirty(run.id);
52
53
  }
53
- export function reflowRunModules({ modules, parentRun, patch, scene, selected, }) {
54
- const reflowed = reflowCabinetRunModules(modules, selected.id, patch.width ?? selected.width);
54
+ function presetWidthDebt(module, sourceId) {
55
+ const value = cabinetMetadataRecord(module.metadata)[PRESET_WIDTH_DEBT_KEY];
56
+ if (!value || typeof value !== 'object' || Array.isArray(value))
57
+ return 0;
58
+ const debt = value[sourceId];
59
+ return typeof debt === 'number' && debt > 0 ? debt : 0;
60
+ }
61
+ function metadataWithPresetWidthDebt(module, sourceId, widthDelta) {
62
+ const metadata = cabinetMetadataRecord(module.metadata);
63
+ const value = metadata[PRESET_WIDTH_DEBT_KEY];
64
+ const debts = value && typeof value === 'object' && !Array.isArray(value)
65
+ ? { ...value }
66
+ : {};
67
+ const nextDebt = Math.max(0, presetWidthDebt(module, sourceId) - widthDelta);
68
+ if (nextDebt > 1e-4)
69
+ debts[sourceId] = nextDebt;
70
+ else
71
+ delete debts[sourceId];
72
+ if (Object.keys(debts).length > 0) {
73
+ return { ...metadata, [PRESET_WIDTH_DEBT_KEY]: debts };
74
+ }
75
+ const { [PRESET_WIDTH_DEBT_KEY]: _removed, ...rest } = metadata;
76
+ return rest;
77
+ }
78
+ export function reflowRunModules({ modules, parentRun, patch, preserveExtent = false, scene, selected, }) {
79
+ const reflowed = reflowCabinetRunModules(modules, selected.id, patch.width ?? selected.width, {
80
+ preserveExtent,
81
+ restorableWidthById: new Map(modules.map((module) => [module.id, presetWidthDebt(module, selected.id)])),
82
+ });
55
83
  if (reflowed.length === 0)
56
84
  return;
57
85
  const reflowById = new Map(reflowed.map((entry) => [entry.id, entry]));
@@ -60,7 +88,13 @@ export function reflowRunModules({ modules, parentRun, patch, scene, selected, }
60
88
  if (!reflow)
61
89
  continue;
62
90
  const isSelected = module.id === selected.id;
63
- const nextPatch = isSelected ? { ...patch } : {};
91
+ const nextPatch = isSelected
92
+ ? { ...patch, width: reflow.width }
93
+ : { width: reflow.width };
94
+ const widthDelta = reflow.width - module.width;
95
+ if (!isSelected && preserveExtent && Math.abs(widthDelta) > 1e-4) {
96
+ nextPatch.metadata = metadataWithPresetWidthDebt(module, selected.id, widthDelta);
97
+ }
64
98
  const nextPosition = [
65
99
  reflow.position[0],
66
100
  isSelected && patch.position ? patch.position[1] : reflow.position[1],
@@ -1,6 +1,6 @@
1
1
  import { resolveCabinetType } from './run-ops';
2
2
  import { COOKTOP_STANDARD_WIDTH, cooktopCabinetStack, DISHWASHER_STANDARD_HEIGHT, DISHWASHER_STANDARD_WIDTH, FRIDGE_COLUMN_WIDTH, FRIDGE_WIDE_WIDTH, fridgeCabinetStack, hoodCompartmentHeight, isCooktopCompartmentType, isFridgeCompartmentType, isHoodCompartmentType, MICROWAVE_STANDARD_WIDTH, PULL_OUT_PANTRY_STANDARD_WIDTH, replaceCabinetCompartmentStack, SINK_STANDARD_WIDTH, sinkCabinetStack, stackForCabinet, TALL_CABINET_CARCASS_HEIGHT, } from './stack';
3
- const BASE_MODULE_WIDTH = 0.6;
3
+ const BASE_MODULE_WIDTH = 0.5;
4
4
  const BASE_CARCASS_HEIGHT = 0.72;
5
5
  const WALL_CARCASS_HEIGHT = 0.72;
6
6
  const TALL_CARCASS_HEIGHT = TALL_CABINET_CARCASS_HEIGHT;
@@ -35,7 +35,7 @@ export function resolveCompartmentTransition({ node, parentRun, index, next, })
35
35
  : next.type === 'fridge-double'
36
36
  ? FRIDGE_WIDE_WIDTH
37
37
  : FRIDGE_COLUMN_WIDTH,
38
- depth: parentRun?.depth ?? 0.58,
38
+ depth: parentRun?.depth ?? 0.5,
39
39
  carcassHeight: TALL_CARCASS_HEIGHT,
40
40
  plinthHeight: 0.1,
41
41
  toeKickDepth: 0.075,
@@ -55,7 +55,7 @@ export function resolveCompartmentTransition({ node, parentRun, index, next, })
55
55
  : enteringCooktop
56
56
  ? COOKTOP_STANDARD_WIDTH
57
57
  : BASE_MODULE_WIDTH,
58
- depth: parentRun?.depth ?? 0.58,
58
+ depth: parentRun?.depth ?? 0.5,
59
59
  carcassHeight: parentRun?.carcassHeight ?? BASE_CARCASS_HEIGHT,
60
60
  plinthHeight: parentRun?.plinthHeight ?? 0.1,
61
61
  toeKickDepth: parentRun?.toeKickDepth ?? 0.075,
@@ -69,7 +69,7 @@ export function resolveCompartmentTransition({ node, parentRun, index, next, })
69
69
  ? {
70
70
  cabinetType: 'base',
71
71
  width: DISHWASHER_STANDARD_WIDTH,
72
- depth: parentRun?.depth ?? 0.58,
72
+ depth: parentRun?.depth ?? 0.5,
73
73
  carcassHeight: DISHWASHER_STANDARD_HEIGHT,
74
74
  plinthHeight: parentRun?.plinthHeight ?? 0.1,
75
75
  toeKickDepth: parentRun?.toeKickDepth ?? 0.075,
@@ -1 +1 @@
1
- {"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../src/cabinet/tool.tsx"],"names":[],"mappings":"AA2PA,QAAA,MAAM,WAAW,0CAm2BhB,CAAA;AAED,eAAe,WAAW,CAAA"}
1
+ {"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../src/cabinet/tool.tsx"],"names":[],"mappings":"AA+PA,QAAA,MAAM,WAAW,0CA29BhB,CAAA;AAED,eAAe,WAAW,CAAA"}
@@ -1,18 +1,19 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { CabinetModuleNode, CabinetNode, createSceneApi, emitter, getFloorPlacedFootprints, getWallThickness, isCurvedWall, nodeRegistry, spatialGridManager, useScene, } from '@pascal-app/core';
4
- import { clearPlacementSurface, getFloorStackPreviewPosition, getSideFromNormal, isGridSnapActive, isMagneticSnapActive, isValidWallSideFace, markToolCancelConsumed, movementSfxStepKey, PlacementBox, publishPlacementSurface, triggerSFX, useEditor, useFacingPose, usePlacementPreview, } from '@pascal-app/editor';
3
+ import { CabinetModuleNode, CabinetNode, collectAlignmentAnchors, createSceneApi, emitter, getFloorPlacedFootprints, getWallThickness, isCurvedWall, movingFootprintAnchors, nodeRegistry, resolveAlignment, resolveSupportSlabPatch, spatialGridManager, useScene, } from '@pascal-app/core';
4
+ import { clearPlacementSurface, getFloorStackPreviewPosition, getSideFromNormal, isAlignmentGuideActive, isGridSnapActive, isMagneticSnapActive, isValidWallSideFace, markToolCancelConsumed, movementSfxStepKey, PlacementBox, publishPlacementSurface, triggerSFX, useAlignmentGuides, useEditor, useFacingPose, usePlacementPreview, } from '@pascal-app/editor';
5
5
  import { useViewer } from '@pascal-app/viewer';
6
6
  import { Html } from '@react-three/drei';
7
7
  import { useFrame } from '@react-three/fiber';
8
8
  import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
9
9
  import { Mesh, Quaternion, Vector3 } from 'three';
10
- import { getLevelLocalSnappedPosition, stopPlacementCommitPropagation, subscribeFloorPlacementClicks, subscribeFloorPlacementDoubleClicks, } from '../shared/floor-placement';
10
+ import { FLOOR_PLACEMENT_ALIGNMENT_THRESHOLD_M, getLevelLocalSnappedPosition, stopPlacementCommitPropagation, subscribeFloorPlacementClicks, subscribeFloorPlacementDoubleClicks, } from '../shared/floor-placement';
11
11
  import { LevelOffsetGroup } from '../shared/level-offset-group';
12
12
  import { findClosestWallInPlan } from '../shared/wall-attach-target';
13
13
  import { cabinetStretchExitSide, chooseCabinetContinuousAnchor, createCabinetContinuousContinuation, isCabinetContinuousFollowUpClick, isForcePlacementEvent, planCabinetContinuousStretch, resolveCabinetContinuousValidity, } from './continuous-placement';
14
14
  import { bumpCabinetRunsNear, cabinetDefinition, cabinetModuleDefinition, cabinetRunFootprint, } from './definition';
15
15
  import { buildCabinetGeometry } from './geometry';
16
+ import { resolveCabinetGridPosition } from './placement-snap';
16
17
  import useCabinetPlacementStatus from './placement-status';
17
18
  import useCabinetPlacementType from './placement-type';
18
19
  import { cabinetPresetById } from './presets';
@@ -68,11 +69,6 @@ function buildCabinetPlacementPreviewNode({ island, position, previewModule, yaw
68
69
  }),
69
70
  });
70
71
  }
71
- function snap(value, step) {
72
- if (step <= 0)
73
- return value;
74
- return Math.round(value / step) * step;
75
- }
76
72
  // Cabinet wall attachment is a placement affordance, separate from floor-grid
77
73
  // quantization. Keep the long-standing behavior in grid and magnetic modes;
78
74
  // Off remains the explicit way to place without wall attachment.
@@ -143,6 +139,7 @@ const CabinetTool = () => {
143
139
  const previousWasWallSnapRef = useRef(false);
144
140
  const previousTickFrameRef = useRef(-1);
145
141
  const draftAnchorRef = useRef(null);
142
+ const lastRawPositionRef = useRef(null);
146
143
  const activeGhostRef = useRef(null);
147
144
  const surfacePointRef = useRef(new Vector3());
148
145
  const surfaceNormalRef = useRef(new Vector3(0, 1, 0));
@@ -262,6 +259,7 @@ const CabinetTool = () => {
262
259
  previousWasWallSnapRef.current = false;
263
260
  previousTickFrameRef.current = -1;
264
261
  draftAnchorRef.current = null;
262
+ let alignmentCandidates = collectAlignmentAnchors(useScene.getState().nodes, previewNode.id, activeLevelId);
265
263
  let lastWallEventTime = -1;
266
264
  let wallOwnedPointerAt = Number.NEGATIVE_INFINITY;
267
265
  const WALL_OWNS_POINTER_MS = 64;
@@ -284,6 +282,7 @@ const CabinetTool = () => {
284
282
  previousTickFrameRef.current = -1;
285
283
  clearPlacementSurface();
286
284
  useFacingPose.getState().clear();
285
+ useAlignmentGuides.getState().clear();
287
286
  useCabinetPlacementStatus.getState().setBlocked(false);
288
287
  };
289
288
  const applyPlacementType = (type) => {
@@ -323,7 +322,41 @@ const CabinetTool = () => {
323
322
  };
324
323
  const resolveGridPosition = (raw, bypassGrid = false) => {
325
324
  const step = !bypassGrid && isGridSnapActive() ? useEditor.getState().gridSnapStep : 0;
326
- return [snap(raw[0], step), 0, snap(raw[2], step)];
325
+ return resolveCabinetGridPosition({
326
+ raw,
327
+ dimensions: placementDimensions,
328
+ yaw: yawRef.current,
329
+ step,
330
+ });
331
+ };
332
+ const resolveAlignedCabinetPosition = ({ applyAlignmentSnap, position, width, yaw, }) => {
333
+ if (!isAlignmentGuideActive()) {
334
+ useAlignmentGuides.getState().clear();
335
+ return position;
336
+ }
337
+ const alignmentNode = buildCabinetPlacementPreviewNode({
338
+ island: islandModeRef.current,
339
+ position,
340
+ previewModule: previewNode,
341
+ yaw,
342
+ });
343
+ const moving = movingFootprintAnchors({
344
+ ...alignmentNode,
345
+ ...(width != null ? { width } : null),
346
+ }, position[0], position[2], yaw);
347
+ if (moving.length === 0 || alignmentCandidates.length === 0) {
348
+ useAlignmentGuides.getState().clear();
349
+ return position;
350
+ }
351
+ const result = resolveAlignment({
352
+ moving,
353
+ candidates: alignmentCandidates,
354
+ threshold: FLOOR_PLACEMENT_ALIGNMENT_THRESHOLD_M,
355
+ });
356
+ useAlignmentGuides.getState().set(result.guides);
357
+ if (!applyAlignmentSnap || !result.snap)
358
+ return position;
359
+ return [position[0] + result.snap.dx, position[1], position[2] + result.snap.dz];
327
360
  };
328
361
  const withPlacementValidity = (next, bypassCollision) => {
329
362
  if (bypassCollision)
@@ -397,19 +430,34 @@ const CabinetTool = () => {
397
430
  };
398
431
  const resolvePlacement = (event) => {
399
432
  const raw = resolveRawPosition(event);
433
+ lastRawPositionRef.current = raw;
400
434
  const forcePlacement = isForcePlacementEvent(event);
401
435
  const wallPlacement = islandModeRef.current ? null : resolveWallPlacement(raw);
402
- if (wallPlacement)
403
- return withPlacementValidity(wallPlacement, forcePlacement);
404
- return withPlacementValidity({
436
+ if (wallPlacement) {
437
+ return withPlacementValidity({
438
+ ...wallPlacement,
439
+ position: resolveAlignedCabinetPosition({
440
+ applyAlignmentSnap: false,
441
+ position: wallPlacement.position,
442
+ yaw: wallPlacement.yaw,
443
+ }),
444
+ }, forcePlacement);
445
+ }
446
+ const position = resolveAlignedCabinetPosition({
447
+ applyAlignmentSnap: isMagneticSnapActive(),
405
448
  position: resolveGridPosition(raw),
406
449
  yaw: yawRef.current,
450
+ });
451
+ return withPlacementValidity({
452
+ position,
453
+ yaw: yawRef.current,
407
454
  snappedToWall: false,
408
455
  }, forcePlacement);
409
456
  };
410
457
  // While stretching, the run is pinned at the anchored first module and
411
458
  // grows toward the cursor — the far end tracks the pointer smoothly.
412
459
  const resolveStretchedPlacement = (anchor, event) => {
460
+ useAlignmentGuides.getState().clear();
413
461
  const raw = resolveRawPosition(event);
414
462
  let stretch = planCabinetContinuousStretch({
415
463
  anchor,
@@ -532,6 +580,7 @@ const CabinetTool = () => {
532
580
  name: island ? 'Kitchen Island' : 'Modular Cabinet',
533
581
  position,
534
582
  rotation: yaw,
583
+ parentId: activeLevelId,
535
584
  depth: patch.depth ?? cabinetDefinition.defaults().depth,
536
585
  carcassHeight: patch.carcassHeight ?? cabinetDefinition.defaults().carcassHeight,
537
586
  ...(island && {
@@ -565,11 +614,13 @@ const CabinetTool = () => {
565
614
  const modules = segment.stretch.modules.map((m, index) => buildModule(m.x, m.width, index));
566
615
  for (const module of modules)
567
616
  sceneApi.upsert(module, cabinet.id);
617
+ const liveRun = sceneApi.get(cabinet.id) ?? cabinet;
618
+ sceneApi.update(liveRun.id, resolveSupportSlabPatch(liveRun, sceneApi.nodes()));
568
619
  bumpCabinetRunsNearNewRun(cabinet.id);
569
620
  sceneApi.resumeHistory();
570
621
  return {
571
622
  endModule: modules[modules.length - 1],
572
- run: sceneApi.get(cabinet.id) ?? cabinet,
623
+ run: sceneApi.get(cabinet.id) ?? liveRun,
573
624
  };
574
625
  }
575
626
  const connectedId = addCornerRun({
@@ -613,6 +664,13 @@ const CabinetTool = () => {
613
664
  anchorModule = added;
614
665
  }
615
666
  bumpCabinetRunsNearNewRun(nextRun.id);
667
+ const liveNextRun = sceneApi.get(nextRun.id) ?? nextRun;
668
+ sceneApi.update(liveNextRun.id, resolveSupportSlabPatch(liveNextRun, sceneApi.nodes()));
669
+ const rootRun = chainRootRunRef.current;
670
+ if (rootRun) {
671
+ const liveRoot = sceneApi.get(rootRun.id) ?? rootRun;
672
+ sceneApi.update(liveRoot.id, resolveSupportSlabPatch(liveRoot, sceneApi.nodes()));
673
+ }
616
674
  sceneApi.resumeHistory();
617
675
  return {
618
676
  endModule: anchorModule,
@@ -712,14 +770,20 @@ const CabinetTool = () => {
712
770
  }
713
771
  const { cabinet, buildModule } = buildRunNodes(next.position, next.yaw);
714
772
  const module = buildModule(0, previewNode.width, 0);
773
+ const nodes = { ...useScene.getState().nodes, [cabinet.id]: cabinet, [module.id]: module };
774
+ const committedCabinet = CabinetNode.parse({
775
+ ...cabinet,
776
+ ...resolveSupportSlabPatch(cabinet, nodes),
777
+ });
715
778
  useScene.getState().createNodes([
716
- { node: cabinet, parentId: activeLevelId },
717
- { node: module, parentId: cabinet.id },
779
+ { node: committedCabinet, parentId: activeLevelId },
780
+ { node: module, parentId: committedCabinet.id },
718
781
  ]);
719
- bumpCabinetRunsNearNewRun(cabinet.id);
782
+ bumpCabinetRunsNearNewRun(committedCabinet.id);
720
783
  useViewer.getState().setSelection({ selectedIds: [module.id] });
721
784
  useEditor.getState().setMode('select');
722
785
  triggerSFX('sfx:item-place');
786
+ useAlignmentGuides.getState().clear();
723
787
  usePlacementPreview.getState().clear();
724
788
  clearPlacementSurface();
725
789
  useFacingPose.getState().clear();
@@ -746,7 +810,20 @@ const CabinetTool = () => {
746
810
  if (placementRef.current &&
747
811
  !placementRef.current.snappedToWall &&
748
812
  !placementRef.current.stretch) {
749
- const next = { ...placementRef.current, yaw: yawRef.current };
813
+ const current = placementRef.current;
814
+ const { conflictIds: _conflictIds, valid: _valid, ...placementBase } = current;
815
+ const raw = lastRawPositionRef.current ?? current.position;
816
+ const position = resolveAlignedCabinetPosition({
817
+ applyAlignmentSnap: isMagneticSnapActive(),
818
+ position: resolveCabinetGridPosition({
819
+ raw,
820
+ dimensions: placementDimensions,
821
+ yaw: yawRef.current,
822
+ step: isGridSnapActive() ? useEditor.getState().gridSnapStep : 0,
823
+ }),
824
+ yaw: yawRef.current,
825
+ });
826
+ const next = withPlacementValidity({ ...placementBase, position, yaw: yawRef.current }, false);
750
827
  placementRef.current = next;
751
828
  setPlacement(next);
752
829
  publishFloorplanPreview(next);
@@ -780,6 +857,7 @@ const CabinetTool = () => {
780
857
  usePlacementPreview.getState().clear();
781
858
  clearPlacementSurface();
782
859
  useFacingPose.getState().clear();
860
+ useAlignmentGuides.getState().clear();
783
861
  useCabinetPlacementStatus.getState().setBlocked(false);
784
862
  };
785
863
  }, [activeLevelId, placementDimensions, previewNode, publishFloorplanPreview]);
@@ -1 +1 @@
1
- {"version":3,"file":"wall-snap.d.ts","sourceRoot":"","sources":["../../src/cabinet/wall-snap.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"wall-snap.d.ts","sourceRoot":"","sources":["../../src/cabinet/wall-snap.ts"],"names":[],"mappings":"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"}
@@ -1,15 +1,11 @@
1
1
  import { calculateLevelMiters, getWallPlanFootprint, getWallThickness, } from '@pascal-app/core';
2
2
  import { findClosestWallInPlan, projectWallLocalPointToPlan } from '../shared/wall-attach-target';
3
+ import { snapCabinetFootprintCenter } from './placement-snap';
3
4
  import { planToRunLocal, runLocalToPlan } from './run-layout';
4
5
  const EDGE_SNAP_THRESHOLD = 0.08;
5
6
  const FACE_MATCH_THRESHOLD = 0.12;
6
7
  const YAW_MATCH_THRESHOLD = 0.08;
7
8
  const WALL_FACE_EPSILON = 1e-5;
8
- function snap(value, step) {
9
- if (step <= 0)
10
- return value;
11
- return Math.round(value / step) * step;
12
- }
13
9
  function angleDelta(a, b) {
14
10
  return Math.atan2(Math.sin(a - b), Math.cos(a - b));
15
11
  }
@@ -135,7 +131,7 @@ export function resolveCabinetWallSnapPlacement({ depth, gridStep = 0, faceOffse
135
131
  if (hit.wallLength <= 1e-6)
136
132
  return null;
137
133
  const halfWidth = width / 2;
138
- const snappedLocalX = snap(hit.localX, gridStep);
134
+ const snappedLocalX = snapCabinetFootprintCenter(hit.localX, width, gridStep);
139
135
  const clampedLocalX = hit.wallLength > width
140
136
  ? Math.min(hit.wallLength - halfWidth, Math.max(halfWidth, snappedLocalX))
141
137
  : hit.wallLength / 2;
@@ -1 +1 @@
1
- {"version":3,"file":"boundary-editor.d.ts","sourceRoot":"","sources":["../../src/ceiling/boundary-editor.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,WAAW,EAAkD,MAAM,kBAAkB,CAAA;AAanG;;;;;;;;;;GAUG;AACH,eAAO,MAAM,qBAAqB,EAAE,KAAK,CAAC,EAAE,CAAC;IAAE,SAAS,EAAE,WAAW,CAAC,IAAI,CAAC,CAAA;CAAE,CAwJ5E,CAAA;AAED,eAAe,qBAAqB,CAAA"}
1
+ {"version":3,"file":"boundary-editor.d.ts","sourceRoot":"","sources":["../../src/ceiling/boundary-editor.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,WAAW,EAKjB,MAAM,kBAAkB,CAAA;AAazB;;;;;;;;;;GAUG;AACH,eAAO,MAAM,qBAAqB,EAAE,KAAK,CAAC,EAAE,CAAC;IAAE,SAAS,EAAE,WAAW,CAAC,IAAI,CAAC,CAAA;CAAE,CAwJ5E,CAAA;AAED,eAAe,qBAAqB,CAAA"}
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
- import { resolveLevelId, useLiveNodeOverrides, useScene } from '@pascal-app/core';
3
+ import { resolveCeilingHeight, resolveLevelId, useLiveNodeOverrides, useScene, } from '@pascal-app/core';
4
4
  import { boundaryReshapeScope, clearCeilingSnapFeedback, PolygonEditor, resolveCeilingPlanPointSnap, triggerSFX, useInteractionScope, } from '@pascal-app/editor';
5
5
  import { useViewer } from '@pascal-app/viewer';
6
6
  import { useCallback, useEffect, useMemo, useRef } from 'react';
@@ -113,6 +113,6 @@ export const CeilingBoundaryEditor = ({ ceilingId, }) => {
113
113
  }, [ceilingId]);
114
114
  if (!effectiveCeiling?.polygon || effectiveCeiling.polygon.length < 3)
115
115
  return null;
116
- return (_jsx(PolygonEditor, { allowEdgeMove: true, color: "#d4d4d4", highlightConnectedHandles: true, levelId: ceilingLevelId ?? undefined, minVertices: 3, onBeforeVertexDrag: handlePolygonEditorBeforeVertexDrag, onDragCommit: handlePolygonEditorDragCommit, onDragStart: handlePolygonEditorDragStart, onDragStateChange: handleDragStateChange, onEdgeHoverChange: handleHandleHoverChange, onMidpointHoverChange: handleHandleHoverChange, onPolygonChange: handlePolygonChange, onPolygonPreview: handlePolygonPreview, onVertexHoverChange: handleHandleHoverChange, polygon: effectiveCeiling.polygon, resolvePlanPoint: resolvePolygonEditorPlanPoint, surfaceHeight: effectiveCeiling.height ?? 2.5 }));
116
+ return (_jsx(PolygonEditor, { allowEdgeMove: true, color: "#d4d4d4", highlightConnectedHandles: true, levelId: ceilingLevelId ?? undefined, minVertices: 3, onBeforeVertexDrag: handlePolygonEditorBeforeVertexDrag, onDragCommit: handlePolygonEditorDragCommit, onDragStart: handlePolygonEditorDragStart, onDragStateChange: handleDragStateChange, onEdgeHoverChange: handleHandleHoverChange, onMidpointHoverChange: handleHandleHoverChange, onPolygonChange: handlePolygonChange, onPolygonPreview: handlePolygonPreview, onVertexHoverChange: handleHandleHoverChange, polygon: effectiveCeiling.polygon, resolvePlanPoint: resolvePolygonEditorPlanPoint, surfaceHeight: resolveCeilingHeight(effectiveCeiling, useScene.getState().nodes) }));
117
117
  };
118
118
  export default CeilingBoundaryEditor;
@@ -1,4 +1,4 @@
1
- import type { NodeDefinition } from '@pascal-app/core';
1
+ import { type NodeDefinition } from '@pascal-app/core';
2
2
  import { CeilingNode } from './schema';
3
3
  /**
4
4
  * Ceiling — Phase 5 batch kind, polygon-based. Structurally similar to
@@ -1 +1 @@
1
- {"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../src/ceiling/definition.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGV,cAAc,EACf,MAAM,kBAAkB,CAAA;AAYzB,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAiDtC;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,iBAAiB,EAAE,cAAc,CAAC,OAAO,WAAW,CAwGhE,CAAA"}
1
+ {"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../src/ceiling/definition.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,cAAc,EAIpB,MAAM,kBAAkB,CAAA;AAiBzB,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAmFtC;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,iBAAiB,EAAE,cAAc,CAAC,OAAO,WAAW,CA2GhE,CAAA"}
@@ -1,3 +1,5 @@
1
+ import { getCeilingClampBound, resolveCeilingHeight, useScene, } from '@pascal-app/core';
2
+ import { clearStructuralElevationGuide, publishStructuralElevationGuide, resolveStructuralElevationSnap, } from '@pascal-app/editor';
1
3
  import { polygonMeasurementFeatures } from '../shared/polygon-measurement';
2
4
  import { buildCeilingFloorplan } from './floorplan';
3
5
  import { ceilingAddVertexAffordance, ceilingDeleteVertexAffordance, ceilingMoveEdgeAffordance, ceilingMoveVertexAffordance, } from './floorplan-affordances';
@@ -8,6 +10,17 @@ import { CeilingNode } from './schema';
8
10
  import { ceilingSlots } from './slots';
9
11
  const HEIGHT_HANDLE_OFFSET = 0.22;
10
12
  const MIN_CEILING_HEIGHT = 0.5;
13
+ // Ceilings no longer drive the storey height; the stored level height
14
+ // does. Height writes clamp under min(storey plane, lowest underside of
15
+ // any covering slab from the level above) − CEILING_CLAMP_MARGIN, so a
16
+ // ceiling can poke into neither the level above nor a deck hanging from
17
+ // it (clamp, never ask).
18
+ function ceilingHeightBound(n, sceneApi) {
19
+ const parent = n.parentId ? sceneApi.get(n.parentId) : undefined;
20
+ return parent?.type === 'level'
21
+ ? getCeilingClampBound(parent.id, sceneApi.nodes(), n.polygon ?? [])
22
+ : Number.POSITIVE_INFINITY;
23
+ }
11
24
  function ceilingPolygonCenter(n) {
12
25
  const polygon = n.polygon ?? [];
13
26
  if (polygon.length === 0)
@@ -20,14 +33,25 @@ function ceilingPolygonCenter(n) {
20
33
  }
21
34
  return [cx / polygon.length, cz / polygon.length];
22
35
  }
36
+ function ceilingElevationGuideSource(n) {
37
+ return {
38
+ nodeId: n.id,
39
+ levelId: n.parentId,
40
+ anchor: ceilingPolygonCenter(n),
41
+ };
42
+ }
23
43
  // Ceiling height arrow — vertical chevron at the polygon centroid,
24
44
  // hovering just above the ceiling plane. Drags the `height` field
25
45
  // (the Y position of the ceiling surface). `anchor: 'min'` so dragging
26
46
  // the cursor upward grows the value directly. Live override + commit
27
47
  // flow comes from the shared registry arrow pipeline.
28
48
  //
49
+ // `currentValue` resolves through `resolveCeilingHeight`, and `apply`
50
+ // always writes `height` — so dragging a follows-mode ceiling converts
51
+ // it to an explicit custom height, mirroring the wall top-drag.
52
+ //
29
53
  // The placement Y is in *mesh-local* coords. CeilingSystem already
30
- // parks `mesh.position.y = ceiling.height - 0.01`, so the local Y is
54
+ // parks `mesh.position.y = resolved height - 0.01`, so the local Y is
31
55
  // just the offset above that plane (NOT `height + offset` — that
32
56
  // would double-add the height and push the arrow off-screen).
33
57
  function ceilingHeightHandle() {
@@ -36,7 +60,11 @@ function ceilingHeightHandle() {
36
60
  axis: 'y',
37
61
  anchor: 'min',
38
62
  min: MIN_CEILING_HEIGHT,
39
- currentValue: (n) => n.height ?? 2.5,
63
+ max: ceilingHeightBound,
64
+ currentValue: (n) => resolveCeilingHeight(n, useScene.getState().nodes),
65
+ magneticSnap: (n, newValue, sceneApi) => resolveStructuralElevationSnap(ceilingElevationGuideSource(n), newValue, sceneApi.nodes()),
66
+ onDrag: (n, sceneApi) => publishStructuralElevationGuide(ceilingElevationGuideSource(n), resolveCeilingHeight(n, sceneApi.nodes()), sceneApi.nodes()),
67
+ onDragEnd: (n) => clearStructuralElevationGuide(n.id),
40
68
  apply: (_n, newValue) => ({ height: newValue }),
41
69
  placement: {
42
70
  position: (n) => {
@@ -72,6 +100,8 @@ export const ceilingDefinition = {
72
100
  schema: CeilingNode,
73
101
  category: 'structure',
74
102
  surfaceRole: 'ceiling',
103
+ // Height-less on purpose: a new ceiling follows the level top until the
104
+ // user gives it an explicit custom height.
75
105
  defaults: () => ({
76
106
  object: 'node',
77
107
  parentId: null,
@@ -81,13 +111,14 @@ export const ceilingDefinition = {
81
111
  polygon: [],
82
112
  holes: [],
83
113
  holeMetadata: [],
84
- height: 2.5,
85
114
  autoFromWalls: false,
86
115
  }),
87
116
  capabilities: {
88
117
  selectable: { hitVolume: 'bbox' },
89
118
  surfaces: {
90
- top: { height: (n) => n.height },
119
+ top: {
120
+ height: (n) => resolveCeilingHeight(n, useScene.getState().nodes),
121
+ },
91
122
  },
92
123
  duplicable: true,
93
124
  deletable: true,
@@ -105,7 +136,7 @@ export const ceilingDefinition = {
105
136
  measurement: {
106
137
  features: (node) => polygonMeasurementFeatures({
107
138
  featurePrefix: 'ceiling',
108
- height: node.height,
139
+ height: resolveCeilingHeight(node, useScene.getState().nodes),
109
140
  label: 'Ceiling',
110
141
  polygon: node.polygon,
111
142
  }),
@@ -13,7 +13,6 @@ export declare const ceilingMoveVertexAffordance: import("@pascal-app/core").Flo
13
13
  stairId?: string | undefined;
14
14
  elevatorId?: string | undefined;
15
15
  }[];
16
- height: number;
17
16
  autoFromWalls: boolean;
18
17
  name?: string | undefined;
19
18
  camera?: {
@@ -42,6 +41,7 @@ export declare const ceilingMoveVertexAffordance: import("@pascal-app/core").Flo
42
41
  } | undefined;
43
42
  materialPreset?: string | undefined;
44
43
  slots?: Record<string, string> | undefined;
44
+ height?: number | undefined;
45
45
  }>;
46
46
  export declare const ceilingAddVertexAffordance: import("@pascal-app/core").FloorplanAffordance<{
47
47
  object: "node";
@@ -58,7 +58,6 @@ export declare const ceilingAddVertexAffordance: import("@pascal-app/core").Floo
58
58
  stairId?: string | undefined;
59
59
  elevatorId?: string | undefined;
60
60
  }[];
61
- height: number;
62
61
  autoFromWalls: boolean;
63
62
  name?: string | undefined;
64
63
  camera?: {
@@ -87,6 +86,7 @@ export declare const ceilingAddVertexAffordance: import("@pascal-app/core").Floo
87
86
  } | undefined;
88
87
  materialPreset?: string | undefined;
89
88
  slots?: Record<string, string> | undefined;
89
+ height?: number | undefined;
90
90
  }>;
91
91
  export declare const ceilingMoveEdgeAffordance: import("@pascal-app/core").FloorplanAffordance<{
92
92
  object: "node";
@@ -103,7 +103,6 @@ export declare const ceilingMoveEdgeAffordance: import("@pascal-app/core").Floor
103
103
  stairId?: string | undefined;
104
104
  elevatorId?: string | undefined;
105
105
  }[];
106
- height: number;
107
106
  autoFromWalls: boolean;
108
107
  name?: string | undefined;
109
108
  camera?: {
@@ -132,6 +131,7 @@ export declare const ceilingMoveEdgeAffordance: import("@pascal-app/core").Floor
132
131
  } | undefined;
133
132
  materialPreset?: string | undefined;
134
133
  slots?: Record<string, string> | undefined;
134
+ height?: number | undefined;
135
135
  }>;
136
136
  export declare const ceilingDeleteVertexAffordance: import("@pascal-app/core").FloorplanAffordance<{
137
137
  object: "node";
@@ -148,7 +148,6 @@ export declare const ceilingDeleteVertexAffordance: import("@pascal-app/core").F
148
148
  stairId?: string | undefined;
149
149
  elevatorId?: string | undefined;
150
150
  }[];
151
- height: number;
152
151
  autoFromWalls: boolean;
153
152
  name?: string | undefined;
154
153
  camera?: {
@@ -177,5 +176,6 @@ export declare const ceilingDeleteVertexAffordance: import("@pascal-app/core").F
177
176
  } | undefined;
178
177
  materialPreset?: string | undefined;
179
178
  slots?: Record<string, string> | undefined;
179
+ height?: number | undefined;
180
180
  }>;
181
181
  //# sourceMappingURL=floorplan-affordances.d.ts.map
@@ -1,12 +1,12 @@
1
- import type { CeilingNode, FloorplanMoveTarget } from '@pascal-app/core';
1
+ import { type CeilingNode, type FloorplanMoveTarget } from '@pascal-app/core';
2
2
  /**
3
3
  * 2D floor-plan move handler for ceiling. Delegates to the shared polygon
4
4
  * centroid-pivot mover (same pivot semantics as slab / items). See
5
5
  * `shared/polygon-centroid-move.ts` for the rationale.
6
6
  *
7
- * `meshY = height − 0.01`: `CeilingSystem` parks the ceiling group at that Y
8
- * on rebuild, so mirroring it during the drag avoids a vertical teleport in
9
- * split view.
7
+ * `meshY = resolved height − 0.01`: `CeilingSystem` parks the ceiling group
8
+ * at that Y on rebuild, so mirroring it during the drag avoids a vertical
9
+ * teleport in split view.
10
10
  */
11
11
  export declare const ceilingFloorplanMoveTarget: FloorplanMoveTarget<CeilingNode>;
12
12
  //# sourceMappingURL=floorplan-move.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"floorplan-move.d.ts","sourceRoot":"","sources":["../../src/ceiling/floorplan-move.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AAGxE;;;;;;;;GAQG;AACH,eAAO,MAAM,0BAA0B,EAAE,mBAAmB,CAAC,WAAW,CAMpE,CAAA"}
1
+ {"version":3,"file":"floorplan-move.d.ts","sourceRoot":"","sources":["../../src/ceiling/floorplan-move.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,mBAAmB,EAAwB,MAAM,kBAAkB,CAAA;AAGnG;;;;;;;;GAQG;AACH,eAAO,MAAM,0BAA0B,EAAE,mBAAmB,CAAC,WAAW,CAMpE,CAAA"}
@@ -1,16 +1,17 @@
1
+ import { resolveCeilingHeight } from '@pascal-app/core';
1
2
  import { createPolygonCentroidMoveTarget } from '../shared/polygon-centroid-move';
2
3
  /**
3
4
  * 2D floor-plan move handler for ceiling. Delegates to the shared polygon
4
5
  * centroid-pivot mover (same pivot semantics as slab / items). See
5
6
  * `shared/polygon-centroid-move.ts` for the rationale.
6
7
  *
7
- * `meshY = height − 0.01`: `CeilingSystem` parks the ceiling group at that Y
8
- * on rebuild, so mirroring it during the drag avoids a vertical teleport in
9
- * split view.
8
+ * `meshY = resolved height − 0.01`: `CeilingSystem` parks the ceiling group
9
+ * at that Y on rebuild, so mirroring it during the drag avoids a vertical
10
+ * teleport in split view.
10
11
  */
11
12
  export const ceilingFloorplanMoveTarget = ({ node, nodes }) => createPolygonCentroidMoveTarget({
12
13
  node,
13
14
  nodes,
14
- meshY: (node.height ?? 2.5) - 0.01,
15
+ meshY: resolveCeilingHeight(node, nodes) - 0.01,
15
16
  extraCommitData: node.autoFromWalls ? { autoFromWalls: false } : undefined,
16
17
  });
@@ -1 +1 @@
1
- {"version":3,"file":"hole-editor.d.ts","sourceRoot":"","sources":["../../src/ceiling/hole-editor.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,WAAW,EAAkD,MAAM,kBAAkB,CAAA;AAKnG;;GAEG;AACH,eAAO,MAAM,iBAAiB,EAAE,KAAK,CAAC,EAAE,CAAC;IACvC,SAAS,EAAE,WAAW,CAAC,IAAI,CAAC,CAAA;IAC5B,SAAS,EAAE,MAAM,CAAA;CAClB,CAwDA,CAAA;AAED,eAAe,iBAAiB,CAAA"}
1
+ {"version":3,"file":"hole-editor.d.ts","sourceRoot":"","sources":["../../src/ceiling/hole-editor.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,WAAW,EAKjB,MAAM,kBAAkB,CAAA;AAKzB;;GAEG;AACH,eAAO,MAAM,iBAAiB,EAAE,KAAK,CAAC,EAAE,CAAC;IACvC,SAAS,EAAE,WAAW,CAAC,IAAI,CAAC,CAAA;IAC5B,SAAS,EAAE,MAAM,CAAA;CAClB,CAwDA,CAAA;AAED,eAAe,iBAAiB,CAAA"}