@pascal-app/nodes 1.0.3 → 1.0.4

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 (708) hide show
  1. package/dist/block/definition.d.ts.map +1 -1
  2. package/dist/block/definition.js +18 -3
  3. package/dist/block/floorplan.d.ts +11 -1
  4. package/dist/block/floorplan.d.ts.map +1 -1
  5. package/dist/block/floorplan.js +81 -13
  6. package/dist/block/geometry.d.ts +2 -2
  7. package/dist/block/geometry.d.ts.map +1 -1
  8. package/dist/block/geometry.js +39 -24
  9. package/dist/block/hosted-edit.d.ts.map +1 -1
  10. package/dist/block/hosted-edit.js +25 -0
  11. package/dist/block/material-slots.d.ts +1 -3
  12. package/dist/block/material-slots.d.ts.map +1 -1
  13. package/dist/block/material-slots.js +1 -11
  14. package/dist/block/paint.d.ts.map +1 -1
  15. package/dist/block/paint.js +4 -10
  16. package/dist/block/panel.d.ts.map +1 -1
  17. package/dist/block/panel.js +8 -3
  18. package/dist/block/selection.d.ts.map +1 -1
  19. package/dist/block/selection.js +2 -2
  20. package/dist/box-vent/definition.d.ts.map +1 -1
  21. package/dist/box-vent/definition.js +2 -5
  22. package/dist/box-vent/panel.d.ts.map +1 -1
  23. package/dist/box-vent/panel.js +5 -28
  24. package/dist/cabinet/countertop-layout.d.ts +13 -2
  25. package/dist/cabinet/countertop-layout.d.ts.map +1 -1
  26. package/dist/cabinet/definition.d.ts.map +1 -1
  27. package/dist/cabinet/definition.js +1 -2
  28. package/dist/cabinet/floorplan.d.ts.map +1 -1
  29. package/dist/cabinet/floorplan.js +125 -28
  30. package/dist/cabinet/geometry/shared.d.ts +1 -2
  31. package/dist/cabinet/geometry/shared.d.ts.map +1 -1
  32. package/dist/cabinet/geometry/shared.js +1 -2
  33. package/dist/cabinet/run-layout.d.ts.map +1 -1
  34. package/dist/cabinet/run-layout.js +8 -5
  35. package/dist/cabinet/run-ops.d.ts +13 -2
  36. package/dist/cabinet/run-ops.d.ts.map +1 -1
  37. package/dist/cabinet/tool.d.ts.map +1 -1
  38. package/dist/cabinet/tool.js +22 -24
  39. package/dist/cabinet/wall-snap.d.ts.map +1 -1
  40. package/dist/cabinet/wall-snap.js +8 -8
  41. package/dist/ceiling/boundary-editor.d.ts.map +1 -1
  42. package/dist/ceiling/boundary-editor.js +5 -3
  43. package/dist/ceiling/definition.d.ts +4 -4
  44. package/dist/ceiling/definition.d.ts.map +1 -1
  45. package/dist/ceiling/definition.js +15 -15
  46. package/dist/ceiling/floorplan-affordances.d.ts +84 -4
  47. package/dist/ceiling/floorplan-affordances.d.ts.map +1 -1
  48. package/dist/ceiling/floorplan-affordances.js +0 -1
  49. package/dist/ceiling/floorplan-move.d.ts.map +1 -1
  50. package/dist/ceiling/floorplan-move.js +0 -1
  51. package/dist/ceiling/floorplan.d.ts +1 -1
  52. package/dist/ceiling/floorplan.d.ts.map +1 -1
  53. package/dist/ceiling/floorplan.js +2 -1
  54. package/dist/ceiling/height-bounds.d.ts +19 -0
  55. package/dist/ceiling/height-bounds.d.ts.map +1 -0
  56. package/dist/ceiling/height-bounds.js +24 -0
  57. package/dist/ceiling/hole-editor.d.ts.map +1 -1
  58. package/dist/ceiling/hole-editor.js +3 -4
  59. package/dist/ceiling/materials.d.ts +1 -1
  60. package/dist/ceiling/materials.d.ts.map +1 -1
  61. package/dist/ceiling/materials.js +10 -3
  62. package/dist/ceiling/paint.d.ts +2 -8
  63. package/dist/ceiling/paint.d.ts.map +1 -1
  64. package/dist/ceiling/paint.js +121 -24
  65. package/dist/ceiling/panel.d.ts.map +1 -1
  66. package/dist/ceiling/panel.js +40 -23
  67. package/dist/ceiling/renderer.d.ts.map +1 -1
  68. package/dist/ceiling/renderer.js +41 -5
  69. package/dist/chimney/move-tool.d.ts.map +1 -1
  70. package/dist/chimney/move-tool.js +8 -2
  71. package/dist/chimney/paint.d.ts.map +1 -1
  72. package/dist/chimney/paint.js +3 -10
  73. package/dist/column/definition.d.ts.map +1 -1
  74. package/dist/column/definition.js +24 -2
  75. package/dist/column/floorplan-affordances.d.ts.map +1 -1
  76. package/dist/column/floorplan-affordances.js +5 -0
  77. package/dist/column/floorplan.d.ts +1 -1
  78. package/dist/column/floorplan.d.ts.map +1 -1
  79. package/dist/column/floorplan.js +47 -2
  80. package/dist/column/hosted-resize.d.ts +101 -2
  81. package/dist/column/hosted-resize.d.ts.map +1 -1
  82. package/dist/column/panel.d.ts.map +1 -1
  83. package/dist/column/panel.js +147 -146
  84. package/dist/column/renderer.d.ts.map +1 -1
  85. package/dist/column/renderer.js +6 -4
  86. package/dist/column/surface.d.ts.map +1 -1
  87. package/dist/column/surface.js +7 -0
  88. package/dist/construction-dimension/floorplan.js +7 -3
  89. package/dist/cupola/definition.d.ts.map +1 -1
  90. package/dist/cupola/definition.js +2 -8
  91. package/dist/cupola/panel.d.ts.map +1 -1
  92. package/dist/cupola/panel.js +5 -23
  93. package/dist/door/definition.d.ts.map +1 -1
  94. package/dist/door/definition.js +12 -3
  95. package/dist/door/door-math.d.ts +5 -10
  96. package/dist/door/door-math.d.ts.map +1 -1
  97. package/dist/door/door-math.js +14 -15
  98. package/dist/door/floorplan-move.d.ts.map +1 -1
  99. package/dist/door/floorplan-move.js +3 -1
  100. package/dist/door/floorplan.d.ts.map +1 -1
  101. package/dist/door/floorplan.js +55 -21
  102. package/dist/door/mechanism.d.ts +4 -0
  103. package/dist/door/mechanism.d.ts.map +1 -0
  104. package/dist/door/mechanism.js +24 -0
  105. package/dist/door/move-tool.d.ts.map +1 -1
  106. package/dist/door/move-tool.js +72 -48
  107. package/dist/door/paint.d.ts.map +1 -1
  108. package/dist/door/paint.js +3 -0
  109. package/dist/door/panel.d.ts.map +1 -1
  110. package/dist/door/panel.js +34 -259
  111. package/dist/door/placement.d.ts +45 -0
  112. package/dist/door/placement.d.ts.map +1 -0
  113. package/dist/door/placement.js +51 -0
  114. package/dist/door/preview.d.ts.map +1 -1
  115. package/dist/door/preview.js +2 -0
  116. package/dist/door/renderer.d.ts.map +1 -1
  117. package/dist/door/renderer.js +3 -2
  118. package/dist/door/tool.d.ts.map +1 -1
  119. package/dist/door/tool.js +92 -21
  120. package/dist/dormer/csg-geometry.d.ts.map +1 -1
  121. package/dist/dormer/csg-geometry.js +2 -0
  122. package/dist/dormer/paint.d.ts.map +1 -1
  123. package/dist/dormer/paint.js +2 -5
  124. package/dist/dormer/panel.d.ts.map +1 -1
  125. package/dist/dormer/panel.js +4 -14
  126. package/dist/downspout/definition.d.ts.map +1 -1
  127. package/dist/downspout/definition.js +2 -2
  128. package/dist/duct-fitting/definition.d.ts.map +1 -1
  129. package/dist/duct-fitting/definition.js +2 -1
  130. package/dist/duct-fitting/geometry.d.ts.map +1 -1
  131. package/dist/duct-fitting/geometry.js +1 -1
  132. package/dist/duct-fitting/move-tool.d.ts.map +1 -1
  133. package/dist/duct-fitting/move-tool.js +8 -2
  134. package/dist/duct-segment/definition.d.ts.map +1 -1
  135. package/dist/duct-segment/definition.js +2 -2
  136. package/dist/duct-segment/geometry.d.ts.map +1 -1
  137. package/dist/duct-segment/geometry.js +1 -1
  138. package/dist/duct-segment/move-tool.d.ts.map +1 -1
  139. package/dist/duct-segment/move-tool.js +8 -2
  140. package/dist/elevator/definition.d.ts.map +1 -1
  141. package/dist/elevator/definition.js +1 -2
  142. package/dist/elevator/panel.d.ts.map +1 -1
  143. package/dist/elevator/panel.js +5 -27
  144. package/dist/elevator/parametrics.js +1 -1
  145. package/dist/elevator/renderer.d.ts.map +1 -1
  146. package/dist/elevator/renderer.js +3 -4
  147. package/dist/eyebrow-vent/definition.d.ts.map +1 -1
  148. package/dist/eyebrow-vent/definition.js +2 -5
  149. package/dist/eyebrow-vent/paint.d.ts.map +1 -1
  150. package/dist/eyebrow-vent/paint.js +3 -6
  151. package/dist/eyebrow-vent/panel.d.ts.map +1 -1
  152. package/dist/eyebrow-vent/panel.js +5 -23
  153. package/dist/fence/actions/move-endpoint.d.ts +1 -1
  154. package/dist/fence/actions/move-endpoint.d.ts.map +1 -1
  155. package/dist/fence/actions/move-endpoint.js +2 -1
  156. package/dist/fence/definition.d.ts +2 -1
  157. package/dist/fence/definition.d.ts.map +1 -1
  158. package/dist/fence/definition.js +83 -28
  159. package/dist/fence/drafting.d.ts +36 -0
  160. package/dist/fence/drafting.d.ts.map +1 -0
  161. package/dist/fence/drafting.js +210 -0
  162. package/dist/fence/feature-tool.d.ts +4 -0
  163. package/dist/fence/feature-tool.d.ts.map +1 -0
  164. package/dist/fence/feature-tool.js +140 -0
  165. package/dist/fence/features.d.ts +2 -0
  166. package/dist/fence/features.d.ts.map +1 -0
  167. package/dist/fence/features.js +12 -0
  168. package/dist/fence/floorplan-affordances.d.ts.map +1 -1
  169. package/dist/fence/floorplan-affordances.js +2 -1
  170. package/dist/fence/floorplan.d.ts +2 -3
  171. package/dist/fence/floorplan.d.ts.map +1 -1
  172. package/dist/fence/floorplan.js +131 -71
  173. package/dist/fence/geometry-parts.d.ts +50 -0
  174. package/dist/fence/geometry-parts.d.ts.map +1 -0
  175. package/dist/fence/geometry-parts.js +1144 -0
  176. package/dist/fence/geometry.d.ts +2 -3
  177. package/dist/fence/geometry.d.ts.map +1 -1
  178. package/dist/fence/geometry.js +84 -7
  179. package/dist/fence/index.d.ts +1 -0
  180. package/dist/fence/index.d.ts.map +1 -1
  181. package/dist/fence/index.js +1 -0
  182. package/dist/fence/inspector-editors.d.ts +15 -0
  183. package/dist/fence/inspector-editors.d.ts.map +1 -1
  184. package/dist/fence/inspector-editors.js +128 -3
  185. package/dist/fence/lift.d.ts.map +1 -1
  186. package/dist/fence/lift.js +5 -2
  187. package/dist/fence/move-tool.js +2 -1
  188. package/dist/fence/panel-model.d.ts +4 -0
  189. package/dist/fence/panel-model.d.ts.map +1 -0
  190. package/dist/fence/panel-model.js +12 -0
  191. package/dist/fence/parametrics.d.ts +0 -12
  192. package/dist/fence/parametrics.d.ts.map +1 -1
  193. package/dist/fence/parametrics.js +185 -18
  194. package/dist/fence/system.d.ts.map +1 -1
  195. package/dist/fence/system.js +141 -31
  196. package/dist/fence/tool.d.ts.map +1 -1
  197. package/dist/fence/tool.js +256 -47
  198. package/dist/fence-feature/actions.d.ts +7 -0
  199. package/dist/fence-feature/actions.d.ts.map +1 -0
  200. package/dist/fence-feature/actions.js +26 -0
  201. package/dist/fence-feature/definition.d.ts +4 -0
  202. package/dist/fence-feature/definition.d.ts.map +1 -0
  203. package/dist/fence-feature/definition.js +112 -0
  204. package/dist/fence-feature/floorplan-affordances.d.ts +3 -0
  205. package/dist/fence-feature/floorplan-affordances.d.ts.map +1 -0
  206. package/dist/fence-feature/floorplan-affordances.js +37 -0
  207. package/dist/fence-feature/floorplan.d.ts +4 -0
  208. package/dist/fence-feature/floorplan.d.ts.map +1 -0
  209. package/dist/fence-feature/floorplan.js +120 -0
  210. package/dist/fence-feature/geometry.d.ts +5 -0
  211. package/dist/fence-feature/geometry.d.ts.map +1 -0
  212. package/dist/fence-feature/geometry.js +43 -0
  213. package/dist/fence-feature/handles.d.ts +5 -0
  214. package/dist/fence-feature/handles.d.ts.map +1 -0
  215. package/dist/fence-feature/handles.js +84 -0
  216. package/dist/fence-feature/inspector.d.ts +6 -0
  217. package/dist/fence-feature/inspector.d.ts.map +1 -0
  218. package/dist/fence-feature/inspector.js +214 -0
  219. package/dist/fence-feature/interaction.d.ts +3 -0
  220. package/dist/fence-feature/interaction.d.ts.map +1 -0
  221. package/dist/fence-feature/interaction.js +41 -0
  222. package/dist/fence-feature/move-session.d.ts +9 -0
  223. package/dist/fence-feature/move-session.d.ts.map +1 -0
  224. package/dist/fence-feature/move-session.js +48 -0
  225. package/dist/fence-feature/move-tool.d.ts +5 -0
  226. package/dist/fence-feature/move-tool.d.ts.map +1 -0
  227. package/dist/fence-feature/move-tool.js +58 -0
  228. package/dist/fence-feature/pick-target.d.ts +7 -0
  229. package/dist/fence-feature/pick-target.d.ts.map +1 -0
  230. package/dist/fence-feature/pick-target.js +52 -0
  231. package/dist/floor-opening/definition.d.ts +3 -0
  232. package/dist/floor-opening/definition.d.ts.map +1 -0
  233. package/dist/floor-opening/definition.js +41 -0
  234. package/dist/floor-opening/floorplan.d.ts +156 -0
  235. package/dist/floor-opening/floorplan.d.ts.map +1 -0
  236. package/dist/floor-opening/floorplan.js +63 -0
  237. package/dist/gutter/definition.d.ts.map +1 -1
  238. package/dist/gutter/definition.js +2 -2
  239. package/dist/imported-mesh/definition.d.ts.map +1 -1
  240. package/dist/imported-mesh/definition.js +2 -0
  241. package/dist/imported-mesh/geometry.d.ts +1 -1
  242. package/dist/imported-mesh/geometry.d.ts.map +1 -1
  243. package/dist/imported-mesh/geometry.js +40 -12
  244. package/dist/index.d.ts +13 -2
  245. package/dist/index.d.ts.map +1 -1
  246. package/dist/index.js +20 -2
  247. package/dist/item/authored-face-host.d.ts +10 -0
  248. package/dist/item/authored-face-host.d.ts.map +1 -0
  249. package/dist/item/authored-face-host.js +87 -0
  250. package/dist/item/authored-params.d.ts +15 -0
  251. package/dist/item/authored-params.d.ts.map +1 -0
  252. package/dist/item/authored-params.js +72 -0
  253. package/dist/item/definition.d.ts +2 -2
  254. package/dist/item/definition.d.ts.map +1 -1
  255. package/dist/item/definition.js +33 -4
  256. package/dist/item/floorplan.d.ts +1 -1
  257. package/dist/item/floorplan.d.ts.map +1 -1
  258. package/dist/item/floorplan.js +35 -5
  259. package/dist/item/index.d.ts +1 -0
  260. package/dist/item/index.d.ts.map +1 -1
  261. package/dist/item/index.js +1 -0
  262. package/dist/item/model-loader.d.ts +2 -0
  263. package/dist/item/model-loader.d.ts.map +1 -1
  264. package/dist/item/model-loader.js +55 -23
  265. package/dist/item/move-tool.js +4 -4
  266. package/dist/item/paint.d.ts.map +1 -1
  267. package/dist/item/paint.js +5 -24
  268. package/dist/item/panel.d.ts +1 -3
  269. package/dist/item/panel.d.ts.map +1 -1
  270. package/dist/item/panel.js +20 -24
  271. package/dist/item/placement-notice.d.ts +14 -0
  272. package/dist/item/placement-notice.d.ts.map +1 -0
  273. package/dist/item/placement-notice.js +38 -0
  274. package/dist/item/plan-symbols.d.ts +67 -0
  275. package/dist/item/plan-symbols.d.ts.map +1 -0
  276. package/dist/item/plan-symbols.js +407 -0
  277. package/dist/item/renderer.d.ts +10 -0
  278. package/dist/item/renderer.d.ts.map +1 -1
  279. package/dist/item/renderer.js +64 -38
  280. package/dist/item/script-param-defaults.d.ts +12 -0
  281. package/dist/item/script-param-defaults.d.ts.map +1 -0
  282. package/dist/item/script-param-defaults.js +34 -0
  283. package/dist/lean-to-extension/definition.d.ts.map +1 -1
  284. package/dist/lean-to-extension/definition.js +1 -2
  285. package/dist/lean-to-extension/geometry.d.ts.map +1 -1
  286. package/dist/lean-to-extension/geometry.js +1 -1
  287. package/dist/lean-to-extension/layout.d.ts.map +1 -1
  288. package/dist/lean-to-extension/layout.js +2 -3
  289. package/dist/lean-to-extension/placement-validation.d.ts.map +1 -1
  290. package/dist/lean-to-extension/placement-validation.js +5 -5
  291. package/dist/lean-to-extension/tool.d.ts.map +1 -1
  292. package/dist/lean-to-extension/tool.js +5 -5
  293. package/dist/lineset/move-tool.d.ts.map +1 -1
  294. package/dist/lineset/move-tool.js +8 -2
  295. package/dist/liquid-line/move-tool.d.ts.map +1 -1
  296. package/dist/liquid-line/move-tool.js +8 -2
  297. package/dist/measurement/definition.js +1 -1
  298. package/dist/pipe-fitting/move-tool.d.ts.map +1 -1
  299. package/dist/pipe-fitting/move-tool.js +8 -2
  300. package/dist/pipe-segment/move-tool.d.ts.map +1 -1
  301. package/dist/pipe-segment/move-tool.js +8 -2
  302. package/dist/procedural-item/animation.d.ts +8 -0
  303. package/dist/procedural-item/animation.d.ts.map +1 -0
  304. package/dist/procedural-item/animation.js +116 -0
  305. package/dist/procedural-item/definition.d.ts.map +1 -1
  306. package/dist/procedural-item/definition.js +74 -8
  307. package/dist/procedural-item/geometry.d.ts +5 -1
  308. package/dist/procedural-item/geometry.d.ts.map +1 -1
  309. package/dist/procedural-item/geometry.js +239 -15
  310. package/dist/procedural-item/renderer.d.ts.map +1 -1
  311. package/dist/procedural-item/renderer.js +272 -23
  312. package/dist/ridge-vent/panel.d.ts.map +1 -1
  313. package/dist/ridge-vent/panel.js +5 -23
  314. package/dist/ridge-vent/renderer.d.ts.map +1 -1
  315. package/dist/ridge-vent/renderer.js +9 -8
  316. package/dist/roof/definition.d.ts.map +1 -1
  317. package/dist/roof/definition.js +4 -1
  318. package/dist/roof/floorplan.d.ts +8 -0
  319. package/dist/roof/floorplan.d.ts.map +1 -1
  320. package/dist/roof/floorplan.js +194 -18
  321. package/dist/roof/panel-model.d.ts.map +1 -1
  322. package/dist/roof/panel-model.js +10 -6
  323. package/dist/roof/panel.d.ts.map +1 -1
  324. package/dist/roof/panel.js +3 -10
  325. package/dist/roof/renderer.d.ts.map +1 -1
  326. package/dist/roof/renderer.js +5 -2
  327. package/dist/roof-segment/panel.d.ts.map +1 -1
  328. package/dist/roof-segment/panel.js +5 -24
  329. package/dist/roof-segment/renderer.d.ts.map +1 -1
  330. package/dist/roof-segment/renderer.js +17 -8
  331. package/dist/separator/definition.d.ts +3 -0
  332. package/dist/separator/definition.d.ts.map +1 -0
  333. package/dist/separator/definition.js +39 -0
  334. package/dist/separator/renderer.d.ts +5 -0
  335. package/dist/separator/renderer.d.ts.map +1 -0
  336. package/dist/separator/renderer.js +36 -0
  337. package/dist/shared/duct-body-paint.d.ts +0 -4
  338. package/dist/shared/duct-body-paint.d.ts.map +1 -1
  339. package/dist/shared/duct-body-paint.js +1 -5
  340. package/dist/shared/item-interaction-actions.d.ts +6 -0
  341. package/dist/shared/item-interaction-actions.d.ts.map +1 -0
  342. package/dist/shared/item-interaction-actions.js +27 -0
  343. package/dist/shared/item-interactions.d.ts +9 -0
  344. package/dist/shared/item-interactions.d.ts.map +1 -0
  345. package/dist/shared/item-interactions.js +74 -0
  346. package/dist/shared/item-light-placement.d.ts +2 -0
  347. package/dist/shared/item-light-placement.d.ts.map +1 -0
  348. package/dist/shared/item-light-placement.js +3 -0
  349. package/dist/shared/move-roof-tool.js +2 -1
  350. package/dist/shared/node-batch/batchable.d.ts +12 -0
  351. package/dist/shared/node-batch/batchable.d.ts.map +1 -0
  352. package/dist/shared/node-batch/batchable.js +41 -0
  353. package/dist/shared/node-batch/candidates.d.ts +7 -5
  354. package/dist/shared/node-batch/candidates.d.ts.map +1 -1
  355. package/dist/shared/node-batch/candidates.js +43 -59
  356. package/dist/shared/node-batch/release.d.ts +8 -0
  357. package/dist/shared/node-batch/release.d.ts.map +1 -0
  358. package/dist/shared/node-batch/release.js +16 -0
  359. package/dist/shared/node-batch/system.d.ts.map +1 -1
  360. package/dist/shared/node-batch/system.js +17 -12
  361. package/dist/shared/node-batch/types.d.ts +4 -1
  362. package/dist/shared/node-batch/types.d.ts.map +1 -1
  363. package/dist/shared/opening-documentation.d.ts +13 -1
  364. package/dist/shared/opening-documentation.d.ts.map +1 -1
  365. package/dist/shared/opening-documentation.js +245 -59
  366. package/dist/shared/opening-guides-runtime.d.ts.map +1 -1
  367. package/dist/shared/opening-guides-runtime.js +17 -14
  368. package/dist/shared/opening-placement-dimensions.d.ts.map +1 -1
  369. package/dist/shared/opening-placement-dimensions.js +3 -3
  370. package/dist/shared/opening-plane-offset.d.ts +23 -0
  371. package/dist/shared/opening-plane-offset.d.ts.map +1 -0
  372. package/dist/shared/opening-plane-offset.js +24 -0
  373. package/dist/shared/polygon-centroid-move.d.ts.map +1 -1
  374. package/dist/shared/polygon-centroid-move.js +4 -1
  375. package/dist/shared/polygon-vertex-affordance.d.ts.map +1 -1
  376. package/dist/shared/polygon-vertex-affordance.js +19 -15
  377. package/dist/shared/run-hangers.d.ts.map +1 -1
  378. package/dist/shared/run-hangers.js +5 -4
  379. package/dist/shared/scripted-opening-handles.d.ts +18 -0
  380. package/dist/shared/scripted-opening-handles.d.ts.map +1 -0
  381. package/dist/shared/scripted-opening-handles.js +53 -0
  382. package/dist/shared/scripted-opening.d.ts +25 -0
  383. package/dist/shared/scripted-opening.d.ts.map +1 -0
  384. package/dist/shared/scripted-opening.js +72 -0
  385. package/dist/shared/slot-paint.d.ts +14 -2
  386. package/dist/shared/slot-paint.d.ts.map +1 -1
  387. package/dist/shared/slot-paint.js +29 -29
  388. package/dist/shared/surface-paint.d.ts.map +1 -1
  389. package/dist/shared/surface-paint.js +2 -5
  390. package/dist/shared/swap-preview-material.d.ts +11 -0
  391. package/dist/shared/swap-preview-material.d.ts.map +1 -0
  392. package/dist/shared/swap-preview-material.js +16 -0
  393. package/dist/shared/system-checks.d.ts.map +1 -1
  394. package/dist/shared/system-checks.js +5 -3
  395. package/dist/shared/wall-attach-target.d.ts +3 -10
  396. package/dist/shared/wall-attach-target.d.ts.map +1 -1
  397. package/dist/shared/wall-attach-target.js +3 -63
  398. package/dist/shared/wall-opening-ceiling.d.ts +5 -15
  399. package/dist/shared/wall-opening-ceiling.d.ts.map +1 -1
  400. package/dist/shared/wall-opening-ceiling.js +10 -18
  401. package/dist/shelf/definition.d.ts.map +1 -1
  402. package/dist/shelf/definition.js +1 -1
  403. package/dist/shelf/geometry.d.ts.map +1 -1
  404. package/dist/shelf/geometry.js +1 -2
  405. package/dist/shelf/paint.d.ts.map +1 -1
  406. package/dist/shelf/paint.js +4 -10
  407. package/dist/site/line-ribbon.d.ts +31 -0
  408. package/dist/site/line-ribbon.d.ts.map +1 -0
  409. package/dist/site/line-ribbon.js +117 -0
  410. package/dist/site/lot-mask.d.ts +18 -0
  411. package/dist/site/lot-mask.d.ts.map +1 -0
  412. package/dist/site/lot-mask.js +35 -0
  413. package/dist/site/panel.d.ts +10 -0
  414. package/dist/site/panel.d.ts.map +1 -0
  415. package/dist/site/panel.js +155 -0
  416. package/dist/site/parametrics.d.ts +7 -0
  417. package/dist/site/parametrics.d.ts.map +1 -1
  418. package/dist/site/parametrics.js +8 -0
  419. package/dist/site/recessed-slab-ground-holes.d.ts.map +1 -1
  420. package/dist/site/recessed-slab-ground-holes.js +5 -2
  421. package/dist/site/renderer.d.ts.map +1 -1
  422. package/dist/site/renderer.js +150 -19
  423. package/dist/site/setbacks.d.ts +33 -0
  424. package/dist/site/setbacks.d.ts.map +1 -0
  425. package/dist/site/setbacks.js +204 -0
  426. package/dist/site/terrain-geometry.d.ts +28 -1
  427. package/dist/site/terrain-geometry.d.ts.map +1 -1
  428. package/dist/site/terrain-geometry.js +78 -4
  429. package/dist/site/terrain-holes.d.ts +15 -0
  430. package/dist/site/terrain-holes.d.ts.map +1 -0
  431. package/dist/site/terrain-holes.js +74 -0
  432. package/dist/site/terrain-mesh.d.ts +9 -2
  433. package/dist/site/terrain-mesh.d.ts.map +1 -1
  434. package/dist/site/terrain-mesh.js +36 -9
  435. package/dist/site/terrain-renderer.d.ts +9 -2
  436. package/dist/site/terrain-renderer.d.ts.map +1 -1
  437. package/dist/site/terrain-renderer.js +14 -4
  438. package/dist/slab/boundary-editor.d.ts +1 -1
  439. package/dist/slab/boundary-editor.d.ts.map +1 -1
  440. package/dist/slab/boundary-editor.js +13 -13
  441. package/dist/slab/definition.d.ts.map +1 -1
  442. package/dist/slab/definition.js +19 -3
  443. package/dist/slab/dependency-tracker.d.ts.map +1 -1
  444. package/dist/slab/dependency-tracker.js +67 -7
  445. package/dist/slab/elevation-limit.d.ts.map +1 -1
  446. package/dist/slab/elevation-limit.js +2 -2
  447. package/dist/slab/floorplan-affordances.d.ts +176 -4
  448. package/dist/slab/floorplan-affordances.d.ts.map +1 -1
  449. package/dist/slab/floorplan-affordances.js +0 -1
  450. package/dist/slab/floorplan-move.d.ts.map +1 -1
  451. package/dist/slab/floorplan-move.js +3 -4
  452. package/dist/slab/floorplan.d.ts +7 -0
  453. package/dist/slab/floorplan.d.ts.map +1 -1
  454. package/dist/slab/floorplan.js +22 -5
  455. package/dist/slab/geometry.d.ts.map +1 -1
  456. package/dist/slab/geometry.js +186 -76
  457. package/dist/slab/move-tool.js +7 -6
  458. package/dist/slab/paint.d.ts +18 -5
  459. package/dist/slab/paint.d.ts.map +1 -1
  460. package/dist/slab/paint.js +458 -9
  461. package/dist/slab/panel.d.ts.map +1 -1
  462. package/dist/slab/panel.js +28 -9
  463. package/dist/slab/placement-ownership.d.ts +2 -1
  464. package/dist/slab/placement-ownership.d.ts.map +1 -1
  465. package/dist/slab/placement-ownership.js +2 -2
  466. package/dist/slab/surface-split.d.ts +24 -0
  467. package/dist/slab/surface-split.d.ts.map +1 -0
  468. package/dist/slab/surface-split.js +389 -0
  469. package/dist/slab/tool.d.ts.map +1 -1
  470. package/dist/slab/tool.js +3 -3
  471. package/dist/stair/baluster-geometry.d.ts +21 -0
  472. package/dist/stair/baluster-geometry.d.ts.map +1 -0
  473. package/dist/stair/baluster-geometry.js +74 -0
  474. package/dist/stair/baluster-guard.d.ts +50 -0
  475. package/dist/stair/baluster-guard.d.ts.map +1 -0
  476. package/dist/stair/baluster-guard.js +71 -0
  477. package/dist/stair/boards-guard.d.ts +37 -0
  478. package/dist/stair/boards-guard.d.ts.map +1 -0
  479. package/dist/stair/boards-guard.js +61 -0
  480. package/dist/stair/cable-guard.d.ts +39 -0
  481. package/dist/stair/cable-guard.d.ts.map +1 -0
  482. package/dist/stair/cable-guard.js +105 -0
  483. package/dist/stair/construction-controls.d.ts +15 -0
  484. package/dist/stair/construction-controls.d.ts.map +1 -0
  485. package/dist/stair/construction-controls.js +29 -0
  486. package/dist/stair/continuous-railings.d.ts +10 -0
  487. package/dist/stair/continuous-railings.d.ts.map +1 -0
  488. package/dist/stair/continuous-railings.js +159 -0
  489. package/dist/stair/definition.d.ts.map +1 -1
  490. package/dist/stair/definition.js +16 -37
  491. package/dist/stair/documentation.d.ts +1 -1
  492. package/dist/stair/documentation.d.ts.map +1 -1
  493. package/dist/stair/documentation.js +10 -17
  494. package/dist/stair/floorplan-affordances.d.ts.map +1 -1
  495. package/dist/stair/floorplan-affordances.js +9 -25
  496. package/dist/stair/floorplan.d.ts +1 -23
  497. package/dist/stair/floorplan.d.ts.map +1 -1
  498. package/dist/stair/floorplan.js +102 -86
  499. package/dist/stair/glass-guard.d.ts +72 -0
  500. package/dist/stair/glass-guard.d.ts.map +1 -0
  501. package/dist/stair/glass-guard.js +167 -0
  502. package/dist/stair/guard-path.d.ts +119 -0
  503. package/dist/stair/guard-path.d.ts.map +1 -0
  504. package/dist/stair/guard-path.js +208 -0
  505. package/dist/stair/materials.d.ts +11 -0
  506. package/dist/stair/materials.d.ts.map +1 -0
  507. package/dist/stair/materials.js +51 -0
  508. package/dist/stair/metal-guard.d.ts +38 -0
  509. package/dist/stair/metal-guard.d.ts.map +1 -0
  510. package/dist/stair/metal-guard.js +79 -0
  511. package/dist/stair/paint.d.ts +32 -0
  512. package/dist/stair/paint.d.ts.map +1 -1
  513. package/dist/stair/paint.js +75 -36
  514. package/dist/stair/panel.d.ts.map +1 -1
  515. package/dist/stair/panel.js +154 -17
  516. package/dist/stair/parametrics.d.ts +1 -1
  517. package/dist/stair/parametrics.d.ts.map +1 -1
  518. package/dist/stair/parametrics.js +32 -15
  519. package/dist/stair/plan-entry.d.ts +31 -0
  520. package/dist/stair/plan-entry.d.ts.map +1 -0
  521. package/dist/stair/plan-entry.js +325 -0
  522. package/dist/stair/post-and-rail-guard.d.ts +31 -0
  523. package/dist/stair/post-and-rail-guard.d.ts.map +1 -0
  524. package/dist/stair/post-and-rail-guard.js +63 -0
  525. package/dist/stair/railing-controls.d.ts +9 -0
  526. package/dist/stair/railing-controls.d.ts.map +1 -0
  527. package/dist/stair/railing-controls.js +49 -0
  528. package/dist/stair/renderer.d.ts.map +1 -1
  529. package/dist/stair/renderer.js +259 -259
  530. package/dist/stair/use-stair-render-data.d.ts +317 -0
  531. package/dist/stair/use-stair-render-data.d.ts.map +1 -0
  532. package/dist/stair/use-stair-render-data.js +73 -0
  533. package/dist/stair-segment/definition.d.ts.map +1 -1
  534. package/dist/stair-segment/definition.js +51 -10
  535. package/dist/stair-segment/panel.d.ts.map +1 -1
  536. package/dist/stair-segment/panel.js +36 -42
  537. package/dist/stair-segment/parametrics.d.ts +1 -1
  538. package/dist/stair-segment/parametrics.d.ts.map +1 -1
  539. package/dist/stair-segment/parametrics.js +21 -8
  540. package/dist/stair-segment/renderer.d.ts.map +1 -1
  541. package/dist/stair-segment/renderer.js +16 -28
  542. package/dist/turbine-vent/definition.d.ts.map +1 -1
  543. package/dist/turbine-vent/definition.js +2 -5
  544. package/dist/turbine-vent/paint.d.ts.map +1 -1
  545. package/dist/turbine-vent/paint.js +2 -5
  546. package/dist/turbine-vent/panel.d.ts.map +1 -1
  547. package/dist/turbine-vent/panel.js +5 -23
  548. package/dist/unit/unit-panel.d.ts.map +1 -1
  549. package/dist/unit/unit-panel.js +6 -1
  550. package/dist/wall/actions.d.ts.map +1 -1
  551. package/dist/wall/actions.js +7 -2
  552. package/dist/wall/construction-dimensions.js +8 -5
  553. package/dist/wall/contextual-dimensions.js +4 -4
  554. package/dist/wall/curtain-wall-materials.d.ts +1 -1
  555. package/dist/wall/curtain-wall-materials.d.ts.map +1 -1
  556. package/dist/wall/curtain-wall-materials.js +2 -2
  557. package/dist/wall/curve-tool.d.ts.map +1 -1
  558. package/dist/wall/curve-tool.js +4 -0
  559. package/dist/wall/definition.d.ts.map +1 -1
  560. package/dist/wall/definition.js +41 -17
  561. package/dist/wall/floorplan-move.d.ts +1 -1
  562. package/dist/wall/floorplan-move.d.ts.map +1 -1
  563. package/dist/wall/floorplan-move.js +20 -83
  564. package/dist/wall/floorplan-tool.d.ts.map +1 -1
  565. package/dist/wall/floorplan-tool.js +10 -11
  566. package/dist/wall/floorplan.d.ts +3 -1
  567. package/dist/wall/floorplan.d.ts.map +1 -1
  568. package/dist/wall/floorplan.js +184 -21
  569. package/dist/wall/measurement.d.ts.map +1 -1
  570. package/dist/wall/measurement.js +5 -5
  571. package/dist/wall/move-endpoint-tool.d.ts.map +1 -1
  572. package/dist/wall/move-endpoint-tool.js +20 -7
  573. package/dist/wall/move-shared.d.ts.map +1 -1
  574. package/dist/wall/move-shared.js +11 -7
  575. package/dist/wall/move-tool.d.ts.map +1 -1
  576. package/dist/wall/move-tool.js +118 -148
  577. package/dist/wall/paint.d.ts +26 -15
  578. package/dist/wall/paint.d.ts.map +1 -1
  579. package/dist/wall/paint.js +306 -117
  580. package/dist/wall/panel-model.d.ts +18 -0
  581. package/dist/wall/panel-model.d.ts.map +1 -1
  582. package/dist/wall/panel-model.js +77 -19
  583. package/dist/wall/panel.d.ts.map +1 -1
  584. package/dist/wall/panel.js +217 -41
  585. package/dist/wall/parametrics.d.ts.map +1 -1
  586. package/dist/wall/parametrics.js +3 -0
  587. package/dist/wall/rectangle-command.d.ts +111 -12
  588. package/dist/wall/rectangle-command.d.ts.map +1 -1
  589. package/dist/wall/rectangle-tool.d.ts.map +1 -1
  590. package/dist/wall/rectangle-tool.js +26 -8
  591. package/dist/wall/renderer.d.ts.map +1 -1
  592. package/dist/wall/renderer.js +4 -2
  593. package/dist/wall/split-floorplan-layer.d.ts.map +1 -1
  594. package/dist/wall/split-floorplan-layer.js +7 -7
  595. package/dist/wall/split-session.d.ts.map +1 -1
  596. package/dist/wall/split-session.js +7 -1
  597. package/dist/wall/system.d.ts.map +1 -1
  598. package/dist/wall/system.js +36 -4
  599. package/dist/wall/tool.d.ts.map +1 -1
  600. package/dist/wall/tool.js +105 -49
  601. package/dist/wall/treatment-level-data.d.ts +3 -2
  602. package/dist/wall/treatment-level-data.d.ts.map +1 -1
  603. package/dist/wall/treatment-level-data.js +17 -13
  604. package/dist/wall/treatments.d.ts +10 -10
  605. package/dist/wall/treatments.d.ts.map +1 -1
  606. package/dist/wall/treatments.js +67 -54
  607. package/dist/wall/wall-batch-system.d.ts +7 -0
  608. package/dist/wall/wall-batch-system.d.ts.map +1 -1
  609. package/dist/wall/wall-batch-system.js +35 -3
  610. package/dist/wall/wall-batch.d.ts +6 -0
  611. package/dist/wall/wall-batch.d.ts.map +1 -1
  612. package/dist/wall/wall-batch.js +7 -1
  613. package/dist/window/definition.d.ts.map +1 -1
  614. package/dist/window/definition.js +12 -4
  615. package/dist/window/floorplan-move.d.ts.map +1 -1
  616. package/dist/window/floorplan-move.js +3 -1
  617. package/dist/window/floorplan.d.ts.map +1 -1
  618. package/dist/window/floorplan.js +145 -60
  619. package/dist/window/mechanism.d.ts +4 -0
  620. package/dist/window/mechanism.d.ts.map +1 -0
  621. package/dist/window/mechanism.js +20 -0
  622. package/dist/window/move-tool.d.ts.map +1 -1
  623. package/dist/window/move-tool.js +79 -48
  624. package/dist/window/paint.d.ts.map +1 -1
  625. package/dist/window/paint.js +3 -0
  626. package/dist/window/panel.d.ts.map +1 -1
  627. package/dist/window/panel.js +32 -88
  628. package/dist/window/placement.d.ts +23 -0
  629. package/dist/window/placement.d.ts.map +1 -0
  630. package/dist/window/placement.js +66 -0
  631. package/dist/window/preview.d.ts.map +1 -1
  632. package/dist/window/preview.js +2 -0
  633. package/dist/window/renderer.d.ts.map +1 -1
  634. package/dist/window/renderer.js +3 -2
  635. package/dist/window/tool.d.ts.map +1 -1
  636. package/dist/window/tool.js +96 -24
  637. package/dist/window/window-math.d.ts +6 -14
  638. package/dist/window/window-math.d.ts.map +1 -1
  639. package/dist/window/window-math.js +14 -20
  640. package/dist/zone/contextual-dimensions.d.ts.map +1 -1
  641. package/dist/zone/contextual-dimensions.js +6 -28
  642. package/dist/zone/definition.d.ts.map +1 -1
  643. package/dist/zone/definition.js +3 -3
  644. package/dist/zone/floorplan-affordances.d.ts +200 -0
  645. package/dist/zone/floorplan-affordances.d.ts.map +1 -1
  646. package/dist/zone/floorplan.d.ts +1 -1
  647. package/dist/zone/floorplan.d.ts.map +1 -1
  648. package/dist/zone/floorplan.js +93 -53
  649. package/dist/zone/quantities-panel.d.ts.map +1 -1
  650. package/dist/zone/quantities-panel.js +3 -14
  651. package/dist/zone/quick-measurement.d.ts +2 -2
  652. package/dist/zone/quick-measurement.d.ts.map +1 -1
  653. package/dist/zone/quick-measurement.js +6 -5
  654. package/dist/zone/renderer.d.ts +1 -1
  655. package/dist/zone/renderer.d.ts.map +1 -1
  656. package/dist/zone/renderer.js +58 -146
  657. package/dist/zone/room-clear-dimensions.js +3 -3
  658. package/dist/zone/room-documentation.d.ts.map +1 -1
  659. package/dist/zone/room-documentation.js +2 -6
  660. package/package.json +11 -11
  661. package/dist/block/slots.d.ts +0 -4
  662. package/dist/block/slots.d.ts.map +0 -1
  663. package/dist/block/slots.js +0 -17
  664. package/dist/cabinet/slots.d.ts +0 -4
  665. package/dist/cabinet/slots.d.ts.map +0 -1
  666. package/dist/cabinet/slots.js +0 -24
  667. package/dist/ceiling/slots.d.ts +0 -6
  668. package/dist/ceiling/slots.d.ts.map +0 -1
  669. package/dist/ceiling/slots.js +0 -7
  670. package/dist/column/slots.d.ts +0 -9
  671. package/dist/column/slots.d.ts.map +0 -1
  672. package/dist/column/slots.js +0 -19
  673. package/dist/door/slots.d.ts +0 -9
  674. package/dist/door/slots.d.ts.map +0 -1
  675. package/dist/door/slots.js +0 -20
  676. package/dist/elevator/slots.d.ts +0 -8
  677. package/dist/elevator/slots.d.ts.map +0 -1
  678. package/dist/elevator/slots.js +0 -17
  679. package/dist/fence/slots.d.ts +0 -10
  680. package/dist/fence/slots.d.ts.map +0 -1
  681. package/dist/fence/slots.js +0 -23
  682. package/dist/item/__fixtures__/main-floorplan.d.ts +0 -26
  683. package/dist/item/__fixtures__/main-floorplan.d.ts.map +0 -1
  684. package/dist/item/__fixtures__/main-floorplan.js +0 -297
  685. package/dist/lean-to-extension/slots.d.ts +0 -5
  686. package/dist/lean-to-extension/slots.d.ts.map +0 -1
  687. package/dist/lean-to-extension/slots.js +0 -15
  688. package/dist/shelf/slots.d.ts +0 -9
  689. package/dist/shelf/slots.d.ts.map +0 -1
  690. package/dist/shelf/slots.js +0 -30
  691. package/dist/slab/slots.d.ts +0 -10
  692. package/dist/slab/slots.d.ts.map +0 -1
  693. package/dist/slab/slots.js +0 -20
  694. package/dist/stair/floor-stack.d.ts +0 -10
  695. package/dist/stair/floor-stack.d.ts.map +0 -1
  696. package/dist/stair/floor-stack.js +0 -115
  697. package/dist/stair/slots.d.ts +0 -7
  698. package/dist/stair/slots.d.ts.map +0 -1
  699. package/dist/stair/slots.js +0 -13
  700. package/dist/wall/drawing-mode.d.ts +0 -12
  701. package/dist/wall/drawing-mode.d.ts.map +0 -1
  702. package/dist/wall/drawing-mode.js +0 -38
  703. package/dist/wall/slots.d.ts +0 -10
  704. package/dist/wall/slots.d.ts.map +0 -1
  705. package/dist/wall/slots.js +0 -92
  706. package/dist/window/slots.d.ts +0 -5
  707. package/dist/window/slots.d.ts.map +0 -1
  708. package/dist/window/slots.js +0 -11
@@ -1,26 +1,50 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
- import { calculateLevelMiters, collectAlignmentAnchors, emitter, getTwoPointFenceCurveTangents, getWallMiterBoundaryPoints, resolveAlignment, sampleFenceSpline, useScene, } from '@pascal-app/core';
4
- import { CursorSphere, clearPlacementSurface, createFenceOnCurrentLevel, createSplineFenceOnCurrentLevel, DraftMeasurementLabel, EDITOR_LAYER, formatAngleRadians, formatLinearMeasurement, getAngleArcToSegmentReference, getAngleToSegmentReference, getSegmentAngleReferenceAtPoint, getSegmentGridStep, isAlignmentGuideActive, isAngleSnapActive, isGridSnapActive, isMagneticSnapActive, markToolCancelConsumed, publishPlacementSurface, resolvePointerSupportSurface, snapFenceDraftPoint, snapScalarToGrid, triggerSFX, useAlignmentGuides, useEditor, useFenceCurveDraft, useFloorplanDraftPreview, useSegmentDraftChain, } from '@pascal-app/editor';
5
- import { getSceneTheme, useViewer } from '@pascal-app/viewer';
3
+ import { calculateLevelMiters, collectAlignmentAnchors, emitter, FenceNode, GROUND_SUPPORT_ID, getWallMiterBoundaryPoints, levelBaseElevationAt, resolveAlignment, sampleFenceSpline, sceneRegistry, spatialGridManager, useScene, } from '@pascal-app/core';
4
+ import { CursorSphere, clearPlacementSurface, DraftMeasurementLabel, EDITOR_LAYER, formatAngleRadians, formatLinearMeasurement, getAngleArcToSegmentReference, getAngleToSegmentReference, getSegmentAngleReferenceAtPoint, getSegmentGridStep, isAlignmentGuideActive, isAngleSnapActive, isGridSnapActive, isMagneticSnapActive, markToolCancelConsumed, publishPlacementSurface, resolvePointerSupportSurface, snapScalarToGrid, triggerSFX, useAlignmentGuides, useEditor, useFenceCurveDraft, useFloorplanDraftPreview, usePlacementPreview, useRegistryToolContext, useSegmentDraftChain, } from '@pascal-app/editor';
5
+ import { createSceneSupportHeightSampler, getSceneTheme, useViewer } from '@pascal-app/viewer';
6
6
  import { useThree } from '@react-three/fiber';
7
7
  import { useEffect, useMemo, useRef, useState } from 'react';
8
8
  import { BufferGeometry, DoubleSide, Vector3 } from 'three';
9
9
  import { DraftAngleArc, DraftAxisGuides, getNearestAxisAngleLabel, } from '../shared/draft-axis-guides';
10
+ import { createFenceOnCurrentLevel, createSplineFenceOnCurrentLevel, getFenceInheritedDefaults, snapFenceDraftPoint, } from './drafting';
11
+ import FenceFeatureTool from './feature-tool';
12
+ import { createFenceRailHeightSampler, generateFenceGeometry } from './geometry-parts';
10
13
  const FENCE_PREVIEW_HEIGHT = 1.8;
11
14
  const FENCE_PREVIEW_THICKNESS = 0.08;
12
15
  // Grid-plane surface publish (pointer-decided): scratch + constant normal so
13
16
  // per-move publishes don't allocate.
14
17
  const SURFACE_UP = new Vector3(0, 1, 0);
15
18
  const surfacePointScratch = new Vector3();
16
- // The walking surface the pointer actually aims at (deck top when over the
17
- // deck, floor/ground underneath it) — only for genuine 3D pointer events.
18
- // The 2D floor plan emits synthetic grid events with no camera ray behind
19
- // them; those keep the uncapped max election and leave the grid plane alone.
20
19
  function pointedSurfaceFor(camera, event) {
21
- return event.nativeEvent?.target instanceof HTMLCanvasElement
22
- ? resolvePointerSupportSurface(camera, event.position, { includeNodeTopSurfaces: true })
23
- : null;
20
+ if (event.localRay) {
21
+ return resolvePointerSupportSurface(camera, event.position, { includeNodeTopSurfaces: true });
22
+ }
23
+ const levelId = useViewer.getState().selection.levelId;
24
+ if (!levelId)
25
+ return null;
26
+ const [x, , z] = event.localPosition;
27
+ const pointed = spatialGridManager.getPointedSupportSurface(levelId, [x, 10_000, z], [0, -1, 0]);
28
+ const nodes = useScene.getState().nodes;
29
+ const supportSlabId = pointed.slabId ?? GROUND_SUPPORT_ID;
30
+ const elevation = pointed.slabId ? pointed.elevation : levelBaseElevationAt(nodes, levelId, x, z);
31
+ const levelMesh = sceneRegistry.nodes.get(levelId);
32
+ const world = levelMesh
33
+ ? levelMesh.localToWorld(new Vector3(x, elevation, z))
34
+ : new Vector3(event.position[0], event.position[1] + elevation - event.localPosition[1], event.position[2]);
35
+ const buildingId = useViewer.getState().selection.buildingId;
36
+ const buildingMesh = buildingId ? sceneRegistry.nodes.get(buildingId) : null;
37
+ const local = buildingMesh
38
+ ? buildingMesh.worldToLocal(world.clone())
39
+ : new Vector3(x, elevation, z);
40
+ return {
41
+ elevation,
42
+ supportSlabId,
43
+ sourceNodeId: null,
44
+ worldY: world.y,
45
+ worldPoint: [world.x, world.y, world.z],
46
+ localPoint: [local.x, local.y, local.z],
47
+ };
24
48
  }
25
49
  /** Figma-style alignment-snap threshold (meters), matching the move tools. */
26
50
  const ALIGNMENT_THRESHOLD_M = 0.08;
@@ -280,12 +304,19 @@ function getCurrentLevelElements() {
280
304
  }
281
305
  export const FenceTool = () => {
282
306
  const fenceMode = useEditor((s) => s.continuationByContext.fence);
307
+ const feature = useEditor((s) => s.toolDefaults.fence?.featurePlacement);
308
+ if (feature === 'gate' || feature === 'opening')
309
+ return _jsx(FenceFeatureTool, { kind: feature });
283
310
  if (fenceMode === 'curved') {
284
311
  return _jsx(SplineFenceDraft, {});
285
312
  }
313
+ if (fenceMode === 'freehand')
314
+ return _jsx(SplineFenceDraft, { freehand: true });
286
315
  return _jsx(StraightFenceTool, {});
287
316
  };
288
317
  const StraightFenceTool = () => {
318
+ const { activeLevelId, sceneApi } = useRegistryToolContext();
319
+ const draftContext = useMemo(() => ({ sceneApi, levelId: activeLevelId }), [sceneApi, activeLevelId]);
289
320
  const unit = useViewer((state) => state.unit);
290
321
  const metricNotation = useViewer((state) => state.metricNotation);
291
322
  const isDark = useViewer((state) => getSceneTheme(state.sceneTheme).appearance === 'dark');
@@ -294,8 +325,16 @@ const StraightFenceTool = () => {
294
325
  // than the generic fallbacks. Read through refs so the live event
295
326
  // handlers below see the latest values without re-subscribing.
296
327
  const fenceDefaults = useEditor((s) => s.toolDefaults.fence);
297
- const previewHeight = typeof fenceDefaults?.height === 'number' ? fenceDefaults.height : FENCE_PREVIEW_HEIGHT;
298
- const previewThickness = typeof fenceDefaults?.thickness === 'number' ? fenceDefaults.thickness : FENCE_PREVIEW_THICKNESS;
328
+ const startingPoint = useRef(new Vector3(0, 0, 0));
329
+ const buildingState = useRef(0);
330
+ const inheritedPreview = buildingState.current === 1
331
+ ? getFenceInheritedDefaults([startingPoint.current.x, startingPoint.current.z], draftContext)
332
+ : null;
333
+ const effectiveDefaults = { ...fenceDefaults, ...inheritedPreview };
334
+ const previewHeight = typeof effectiveDefaults.height === 'number' ? effectiveDefaults.height : FENCE_PREVIEW_HEIGHT;
335
+ const previewThickness = typeof effectiveDefaults.thickness === 'number'
336
+ ? effectiveDefaults.thickness
337
+ : FENCE_PREVIEW_THICKNESS;
299
338
  const previewHeightRef = useRef(previewHeight);
300
339
  previewHeightRef.current = previewHeight;
301
340
  const previewThicknessRef = useRef(previewThickness);
@@ -307,10 +346,8 @@ const StraightFenceTool = () => {
307
346
  cameraRef.current = camera;
308
347
  const cursorRef = useRef(null);
309
348
  const previewRef = useRef(null);
310
- const startingPoint = useRef(new Vector3(0, 0, 0));
311
349
  const endingPoint = useRef(new Vector3(0, 0, 0));
312
350
  const constructionSurface = useRef(null);
313
- const buildingState = useRef(0);
314
351
  const [draftMeasurement, setDraftMeasurement] = useState(null);
315
352
  const [axisGuide, setAxisGuide] = useState(null);
316
353
  const measurementColor = isDark ? '#ffffff' : '#111111';
@@ -318,7 +355,10 @@ const StraightFenceTool = () => {
318
355
  // Scope seeded defaults to this tool session: clear on deactivation so a
319
356
  // later manual fence draw isn't drawn with a stale preset's parameters.
320
357
  // Unmount-only (empty deps) — the [unit] effect below must not clear it.
321
- useEffect(() => () => useEditor.getState().setToolDefaults('fence', null), []);
358
+ useEffect(() => () => {
359
+ if (!useEditor.getState().toolDefaults.fence?.featurePlacement)
360
+ useEditor.getState().setToolDefaults('fence', null);
361
+ }, []);
322
362
  useEffect(() => {
323
363
  let previousFenceEnd = null;
324
364
  // Alignment candidates — anchors of every alignable object. Refreshed
@@ -478,7 +518,7 @@ const StraightFenceTool = () => {
478
518
  supportCap: pointedSurface?.elevation ?? null,
479
519
  preferredSupportSlabId: pointedSurface?.supportSlabId ?? null,
480
520
  constructionElevation: pointedSurface?.sourceNodeId ? pointedSurface.elevation : null,
481
- });
521
+ }, draftContext);
482
522
  if (!createdFence)
483
523
  return;
484
524
  // The new segment is now a real node — make it an alignment target
@@ -534,16 +574,66 @@ const StraightFenceTool = () => {
534
574
  draftPreview.setFenceDraftStart(null);
535
575
  draftPreview.setFenceDraftEnd(null);
536
576
  };
537
- }, [unit, metricNotation]);
577
+ }, [unit, metricNotation, draftContext]);
538
578
  return (_jsxs("group", { children: [_jsx(DraftAxisGuides, { guide: axisGuide, labelColor: measurementColor, labelShadowColor: measurementShadowColor }), _jsx(CursorSphere, { height: previewHeight, ref: cursorRef }), _jsxs("mesh", { layers: EDITOR_LAYER, ref: previewRef, renderOrder: 1, visible: false, children: [_jsx("boxGeometry", {}), _jsx("meshBasicMaterial", { color: "#ffffff", depthTest: false, depthWrite: false, opacity: 0.45, side: DoubleSide, transparent: true })] }), draftMeasurement && (_jsxs(_Fragment, { children: [_jsx(DraftMeasurementLabel, { color: measurementColor, label: draftMeasurement.lengthLabel, position: draftMeasurement.lengthPosition, shadowColor: measurementShadowColor }), draftMeasurement.angleLabels.map((angleLabel) => (_jsxs("group", { children: [_jsx(DraftAngleArc, { arc: angleLabel.arc, color: measurementColor }), _jsx(DraftMeasurementLabel, { color: measurementColor, label: angleLabel.label, position: angleLabel.position, shadowColor: measurementShadowColor })] }, angleLabel.id)))] }))] }));
539
579
  };
540
580
  const SPLINE_PREVIEW_COLOR = '#8381ed';
541
581
  const SPLINE_PREVIEW_SEGMENTS = 40;
542
- const SplineFenceDraft = () => {
543
- const previewHeight = typeof useEditor.getState().toolDefaults.fence?.height === 'number'
544
- ? useEditor.getState().toolDefaults.fence?.height
545
- : FENCE_PREVIEW_HEIGHT;
582
+ const FREEHAND_SAMPLE_DISTANCE = 0.2;
583
+ const FREEHAND_SIMPLIFY_TOLERANCE = 0.08;
584
+ const FREEHAND_MAX_CONTROL_POINTS = 64;
585
+ function simplifyFreehandPath(points, tolerance = FREEHAND_SIMPLIFY_TOLERANCE) {
586
+ if (points.length <= 2)
587
+ return points;
588
+ let threshold = tolerance * tolerance;
589
+ while (true) {
590
+ const keep = new Uint8Array(points.length);
591
+ keep[0] = 1;
592
+ keep[points.length - 1] = 1;
593
+ const ranges = [[0, points.length - 1]];
594
+ while (ranges.length > 0) {
595
+ const [start, end] = ranges.pop();
596
+ const a = points[start];
597
+ const b = points[end];
598
+ const dx = b[0] - a[0];
599
+ const dz = b[1] - a[1];
600
+ const lengthSquared = dx * dx + dz * dz;
601
+ let farthestIndex = -1;
602
+ let farthestDistanceSquared = threshold;
603
+ for (let index = start + 1; index < end; index += 1) {
604
+ const point = points[index];
605
+ const t = lengthSquared > 1e-9
606
+ ? Math.max(0, Math.min(1, ((point[0] - a[0]) * dx + (point[1] - a[1]) * dz) / lengthSquared))
607
+ : 0;
608
+ const offsetX = point[0] - (a[0] + dx * t);
609
+ const offsetZ = point[1] - (a[1] + dz * t);
610
+ const distanceSquared = offsetX * offsetX + offsetZ * offsetZ;
611
+ if (distanceSquared > farthestDistanceSquared) {
612
+ farthestDistanceSquared = distanceSquared;
613
+ farthestIndex = index;
614
+ }
615
+ }
616
+ if (farthestIndex >= 0) {
617
+ keep[farthestIndex] = 1;
618
+ ranges.push([start, farthestIndex], [farthestIndex, end]);
619
+ }
620
+ }
621
+ const simplified = points.filter((_, index) => keep[index] === 1);
622
+ if (simplified.length <= FREEHAND_MAX_CONTROL_POINTS)
623
+ return simplified;
624
+ threshold *= 2.25;
625
+ }
626
+ }
627
+ const SplineFenceDraft = ({ freehand = false }) => {
628
+ const { activeLevelId, sceneApi } = useRegistryToolContext();
629
+ const draftContext = useMemo(() => ({ sceneApi, levelId: activeLevelId }), [sceneApi, activeLevelId]);
630
+ const fenceDefaults = useEditor((state) => state.toolDefaults.fence);
631
+ const sceneNodes = useScene((state) => state.nodes);
632
+ const levelId = useViewer((state) => state.selection.levelId);
546
633
  const [draftPoints, setDraftPoints] = useState([]);
634
+ const inheritedPreview = useMemo(() => draftPoints[0] ? getFenceInheritedDefaults(draftPoints[0], draftContext, sceneNodes) : null, [draftPoints[0], sceneNodes, draftContext]);
635
+ const effectiveDefaults = useMemo(() => ({ ...fenceDefaults, ...inheritedPreview }), [fenceDefaults, inheritedPreview]);
636
+ const previewHeight = typeof effectiveDefaults.height === 'number' ? effectiveDefaults.height : FENCE_PREVIEW_HEIGHT;
547
637
  const [cursor, setCursor] = useState(null);
548
638
  // Building-local Y of the grid plane (rides the pointed surface — see
549
639
  // `pointedSurfaceFor`), so the spline preview draws on the deck top when
@@ -552,10 +642,9 @@ const SplineFenceDraft = () => {
552
642
  const camera = useThree((state) => state.camera);
553
643
  const cameraRef = useRef(camera);
554
644
  cameraRef.current = camera;
555
- // Pointer cap for the commit (Enter / double-click carry no useful grid
556
- // event of their own) — last resolved on move/click.
557
- const supportSurfaceRef = useRef(null);
558
645
  const draftRef = useRef(draftPoints);
646
+ const freehandSamplesRef = useRef([]);
647
+ const isSketchingRef = useRef(false);
559
648
  draftRef.current = draftPoints;
560
649
  // Mirror the full transient curve so additional preview surfaces observe
561
650
  // the same snapped control points as the local preview.
@@ -563,24 +652,22 @@ const SplineFenceDraft = () => {
563
652
  useFenceCurveDraft.getState().setDraft(draftPoints, cursor);
564
653
  }, [cursor, draftPoints]);
565
654
  useEffect(() => () => useFenceCurveDraft.getState().reset(), []);
566
- useEffect(() => () => useEditor.getState().setToolDefaults('fence', null), []);
655
+ useEffect(() => () => {
656
+ if (!useEditor.getState().toolDefaults.fence?.featurePlacement)
657
+ useEditor.getState().setToolDefaults('fence', null);
658
+ }, []);
567
659
  useEffect(() => {
568
660
  const snapPoint = (local) => {
661
+ if (freehand)
662
+ return local;
569
663
  const step = isGridSnapActive() ? getSegmentGridStep() : 0;
570
664
  if (step <= 0)
571
665
  return local;
572
666
  return [snapScalarToGrid(local[0], step), snapScalarToGrid(local[1], step)];
573
667
  };
574
- const commit = () => {
575
- const points = draftRef.current;
668
+ const commit = (points = draftRef.current) => {
576
669
  if (points.length >= 2) {
577
- const created = createSplineFenceOnCurrentLevel(points, undefined, {
578
- supportCap: supportSurfaceRef.current?.elevation ?? null,
579
- preferredSupportSlabId: supportSurfaceRef.current?.supportSlabId ?? null,
580
- constructionElevation: supportSurfaceRef.current?.sourceNodeId
581
- ? supportSurfaceRef.current.elevation
582
- : null,
583
- });
670
+ const created = createSplineFenceOnCurrentLevel(points, undefined, draftContext);
584
671
  if (created) {
585
672
  triggerSFX('sfx:item-place');
586
673
  // Once the new curve fence is selected for direct editing, leave
@@ -590,28 +677,77 @@ const SplineFenceDraft = () => {
590
677
  useEditor.getState().setMode('select');
591
678
  }
592
679
  }
680
+ draftRef.current = [];
681
+ freehandSamplesRef.current = [];
682
+ isSketchingRef.current = false;
593
683
  setDraftPoints([]);
594
684
  setCursor(null);
595
685
  };
596
686
  const trackPointedSurface = (event) => {
597
687
  const pointed = pointedSurfaceFor(cameraRef.current, event);
598
- if (!pointed)
688
+ const activeSurface = pointed;
689
+ if (!activeSurface)
599
690
  return null;
600
- if (draftRef.current.length === 0)
601
- supportSurfaceRef.current = pointed;
602
- const activeSurface = supportSurfaceRef.current ?? pointed;
603
691
  publishPlacementSurface(surfacePointScratch.set(event.position[0], activeSurface.worldY, event.position[2]), SURFACE_UP);
604
692
  setLiftY(activeSurface.localPoint?.[1] ?? event.localPosition[1]);
605
693
  return pointed;
606
694
  };
607
695
  const onMove = (event) => {
608
696
  const pointed = trackPointedSurface(event);
609
- setCursor(snapPoint([
697
+ const point = snapPoint([
698
+ pointed?.localPoint?.[0] ?? event.localPosition[0],
699
+ pointed?.localPoint?.[2] ?? event.localPosition[2],
700
+ ]);
701
+ setCursor(point);
702
+ if (freehand && isSketchingRef.current) {
703
+ const last = freehandSamplesRef.current.at(-1);
704
+ if (last &&
705
+ Math.hypot(point[0] - last[0], point[1] - last[1]) >= FREEHAND_SAMPLE_DISTANCE) {
706
+ const samples = [...freehandSamplesRef.current, point];
707
+ freehandSamplesRef.current = samples;
708
+ const next = simplifyFreehandPath(samples);
709
+ draftRef.current = next;
710
+ setDraftPoints(next);
711
+ }
712
+ }
713
+ };
714
+ const onPointerDown = (event) => {
715
+ if (!freehand || event.nativeEvent.button !== 0)
716
+ return;
717
+ const pointed = trackPointedSurface(event);
718
+ const point = snapPoint([
719
+ pointed?.localPoint?.[0] ?? event.localPosition[0],
720
+ pointed?.localPoint?.[2] ?? event.localPosition[2],
721
+ ]);
722
+ isSketchingRef.current = true;
723
+ freehandSamplesRef.current = [point];
724
+ draftRef.current = [point];
725
+ setDraftPoints([point]);
726
+ setCursor(point);
727
+ };
728
+ const onPointerUp = (event) => {
729
+ if (!freehand || !isSketchingRef.current)
730
+ return;
731
+ isSketchingRef.current = false;
732
+ const pointed = trackPointedSurface(event);
733
+ const point = snapPoint([
610
734
  pointed?.localPoint?.[0] ?? event.localPosition[0],
611
735
  pointed?.localPoint?.[2] ?? event.localPosition[2],
612
- ]));
736
+ ]);
737
+ const previous = freehandSamplesRef.current;
738
+ const last = previous.at(-1);
739
+ const samples = last && Math.hypot(point[0] - last[0], point[1] - last[1]) < 0.03
740
+ ? previous
741
+ : [...previous, point];
742
+ freehandSamplesRef.current = samples;
743
+ const next = simplifyFreehandPath(samples);
744
+ draftRef.current = next;
745
+ setDraftPoints(next);
746
+ commit(next);
613
747
  };
614
748
  const onClick = (event) => {
749
+ if (freehand)
750
+ return;
615
751
  const pointed = trackPointedSurface(event);
616
752
  if (event.nativeEvent.detail >= 2) {
617
753
  commit();
@@ -632,27 +768,100 @@ const SplineFenceDraft = () => {
632
768
  if (draftRef.current.length === 0)
633
769
  return;
634
770
  markToolCancelConsumed();
771
+ isSketchingRef.current = false;
772
+ if (freehand) {
773
+ draftRef.current = [];
774
+ freehandSamplesRef.current = [];
775
+ setDraftPoints([]);
776
+ setCursor(null);
777
+ return;
778
+ }
635
779
  setDraftPoints((prev) => prev.slice(0, -1));
636
780
  };
637
781
  emitter.on('grid:move', onMove);
638
782
  emitter.on('grid:click', onClick);
783
+ emitter.on('grid:pointerdown', onPointerDown);
784
+ emitter.on('grid:pointerup', onPointerUp);
639
785
  emitter.on('tool:cancel', onCancel);
640
786
  window.addEventListener('keydown', onKeyDown);
641
787
  return () => {
642
788
  emitter.off('grid:move', onMove);
643
789
  emitter.off('grid:click', onClick);
790
+ emitter.off('grid:pointerdown', onPointerDown);
791
+ emitter.off('grid:pointerup', onPointerUp);
644
792
  emitter.off('tool:cancel', onCancel);
645
793
  clearPlacementSurface();
646
794
  window.removeEventListener('keydown', onKeyDown);
647
795
  };
648
- }, []);
649
- const previewPoints = cursor ? [...draftPoints, cursor] : draftPoints;
650
- const curveGeometry = useMemo(() => {
796
+ }, [freehand, draftContext]);
797
+ const previewPoints = useMemo(() => {
798
+ const last = draftPoints.at(-1);
799
+ return cursor && last && !pointMatches(last, cursor) ? [...draftPoints, cursor] : draftPoints;
800
+ }, [cursor, draftPoints]);
801
+ const previewNode = useMemo(() => {
651
802
  if (previewPoints.length < 2)
652
803
  return null;
653
- const sampled = sampleFenceSpline(previewPoints, getTwoPointFenceCurveTangents(previewPoints), SPLINE_PREVIEW_SEGMENTS);
654
- return new BufferGeometry().setFromPoints(sampled.map((point) => new Vector3(point.x, liftY + previewHeight, point.y)));
655
- }, [liftY, previewHeight, previewPoints]);
656
- return (_jsxs("group", { children: [cursor && _jsx(CursorSphere, { height: previewHeight, position: [cursor[0], liftY, cursor[1]] }), draftPoints.map((point, index) => (_jsxs("mesh", { layers: EDITOR_LAYER, position: [point[0], liftY + previewHeight, point[1]], children: [_jsx("sphereGeometry", { args: [0.07, 16, 12] }), _jsx("meshBasicMaterial", { color: SPLINE_PREVIEW_COLOR, depthTest: false })] }, `fence-spline-pt-${index}`))), curveGeometry && (_jsx("line", { frustumCulled: false, geometry: curveGeometry, layers: EDITOR_LAYER, renderOrder: 2, children: _jsx("lineBasicNodeMaterial", { color: SPLINE_PREVIEW_COLOR, depthTest: false, depthWrite: false, linewidth: 2, opacity: 0.95, transparent: true }) }))] }));
804
+ return FenceNode.parse({
805
+ ...effectiveDefaults,
806
+ id: 'fence_curve_preview',
807
+ start: previewPoints[0],
808
+ end: previewPoints.at(-1),
809
+ path: previewPoints,
810
+ tangents: undefined,
811
+ });
812
+ }, [effectiveDefaults, previewPoints]);
813
+ const previewGroundAt = useMemo(() => {
814
+ if (!levelId || !previewNode)
815
+ return null;
816
+ const selectedHost = previewNode.surfaceMode === 'selected'
817
+ ? (previewNode.supportSurfaceNodeId ?? previewNode.supportSlabId)
818
+ : undefined;
819
+ const sampledSupport = createSceneSupportHeightSampler(sceneNodes, levelId, selectedHost);
820
+ const startHeight = sampledSupport(previewNode.start[0], previewNode.start[1]);
821
+ const samples = new Map();
822
+ return (x, z) => {
823
+ const key = `${x},${z}`;
824
+ const cached = samples.get(key);
825
+ if (cached !== undefined)
826
+ return cached;
827
+ const height = previewNode.surfaceMode === 'level' ? startHeight : sampledSupport(x, z);
828
+ samples.set(key, height);
829
+ return height;
830
+ };
831
+ }, [levelId, previewNode, sceneNodes]);
832
+ const previewStartGround = previewNode
833
+ ? (previewGroundAt?.(previewNode.start[0], previewNode.start[1]) ?? 0)
834
+ : 0;
835
+ const previewLift = previewGroundAt ? previewStartGround : liftY;
836
+ const ghostGeometry = useMemo(() => previewNode
837
+ ? generateFenceGeometry(previewNode, previewGroundAt ? (x, z) => previewGroundAt(x, z) - previewStartGround : undefined)
838
+ : null, [previewNode, previewGroundAt, previewStartGround]);
839
+ useEffect(() => () => ghostGeometry?.dispose(), [ghostGeometry]);
840
+ useEffect(() => {
841
+ usePlacementPreview.getState().set(previewNode);
842
+ }, [previewNode]);
843
+ useEffect(() => () => usePlacementPreview.getState().clear(), []);
844
+ const curveGeometry = useMemo(() => {
845
+ if (previewPoints.length < 2 || previewNode?.transitionMode !== 'slope')
846
+ return null;
847
+ const sampled = sampleFenceSpline(previewPoints, undefined, SPLINE_PREVIEW_SEGMENTS);
848
+ const railHeightAt = previewGroundAt
849
+ ? createFenceRailHeightSampler(previewNode, (x, z) => previewGroundAt(x, z) - previewStartGround)
850
+ : null;
851
+ return new BufferGeometry().setFromPoints(sampled.map((point) => new Vector3(point.x, previewLift + previewHeight + (railHeightAt?.(point.x, point.y) ?? 0), point.y)));
852
+ }, [previewLift, previewGroundAt, previewHeight, previewNode, previewPoints, previewStartGround]);
853
+ useEffect(() => () => curveGeometry?.dispose(), [curveGeometry]);
854
+ return (_jsxs("group", { children: [ghostGeometry && (_jsx("mesh", { geometry: ghostGeometry, layers: EDITOR_LAYER, position: [0, previewLift + (previewNode?.supportOffset ?? 0), 0], raycast: () => { }, renderOrder: 1, children: _jsx("meshBasicMaterial", { color: "#ffffff", depthWrite: false, opacity: 0.45, transparent: true }) })), cursor && (_jsx(CursorSphere, { height: previewHeight, position: [
855
+ cursor[0],
856
+ previewLift +
857
+ (previewGroundAt ? previewGroundAt(cursor[0], cursor[1]) - previewStartGround : 0),
858
+ cursor[1],
859
+ ] })), draftPoints.map((point, index) => (_jsxs("mesh", { layers: EDITOR_LAYER, position: [
860
+ point[0],
861
+ previewLift +
862
+ (previewGroundAt ? previewGroundAt(point[0], point[1]) - previewStartGround : 0) +
863
+ previewHeight,
864
+ point[1],
865
+ ], children: [_jsx("sphereGeometry", { args: [0.07, 16, 12] }), _jsx("meshBasicMaterial", { color: SPLINE_PREVIEW_COLOR, depthTest: false })] }, `fence-spline-pt-${index}`))), curveGeometry && (_jsx("line", { frustumCulled: false, geometry: curveGeometry, layers: EDITOR_LAYER, renderOrder: 2, children: _jsx("lineBasicNodeMaterial", { color: SPLINE_PREVIEW_COLOR, depthTest: false, depthWrite: false, linewidth: 2, opacity: 0.95, transparent: true }) }))] }));
657
866
  };
658
867
  export default FenceTool;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Open/Close for a single selected gate, the door's button in the action menu.
3
+ * Not a `mechanism`: a gate's open angle is saved on the node, and mechanisms
4
+ * never write the node.
5
+ */
6
+ export default function FenceGateActions(): import("react").JSX.Element | null;
7
+ //# sourceMappingURL=actions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../src/fence-feature/actions.tsx"],"names":[],"mappings":"AAOA;;;;GAIG;AACH,MAAM,CAAC,OAAO,UAAU,gBAAgB,uCAqBvC"}
@@ -0,0 +1,26 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { useScene } from '@pascal-app/core';
4
+ import { ActionMenuButton } from '@pascal-app/editor';
5
+ import { useViewer } from '@pascal-app/viewer';
6
+ import { DoorClosed, DoorOpen } from 'lucide-react';
7
+ import { toggleFenceGate } from './interaction';
8
+ /**
9
+ * Open/Close for a single selected gate, the door's button in the action menu.
10
+ * Not a `mechanism`: a gate's open angle is saved on the node, and mechanisms
11
+ * never write the node.
12
+ */
13
+ export default function FenceGateActions() {
14
+ const selected = useViewer((s) => s.selection.selectedIds);
15
+ const gate = useScene((s) => {
16
+ const node = selected.length === 1 ? s.nodes[selected[0]] : undefined;
17
+ return node?.type === 'fence-gate' ? node : undefined;
18
+ });
19
+ if (!gate)
20
+ return null;
21
+ const open = (gate.openAngle ?? 0) > 0.01;
22
+ return (_jsx(ActionMenuButton, { keys: ['E'], label: open ? 'Close' : 'Open', onClick: (event) => {
23
+ event.stopPropagation();
24
+ toggleFenceGate(gate.id);
25
+ }, pressed: open, children: open ? _jsx(DoorClosed, { className: "h-4 w-4" }) : _jsx(DoorOpen, { className: "h-4 w-4" }) }));
26
+ }
@@ -0,0 +1,4 @@
1
+ import { FenceGateNode, FenceOpeningNode, type NodeDefinition } from '@pascal-app/core';
2
+ export declare const fenceGateDefinition: NodeDefinition<typeof FenceGateNode | typeof FenceOpeningNode>;
3
+ export declare const fenceOpeningDefinition: NodeDefinition<typeof FenceGateNode | typeof FenceOpeningNode>;
4
+ //# sourceMappingURL=definition.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../src/fence-feature/definition.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,aAAa,EACb,gBAAgB,EAGhB,KAAK,cAAc,EAEpB,MAAM,kBAAkB,CAAA;AAuDzB,eAAO,MAAM,mBAAmB,EAAE,cAAc,CAAC,OAAO,aAAa,GAAG,OAAO,gBAAgB,CA4B9F,CAAA;AAyBD,eAAO,MAAM,sBAAsB,EAAE,cAAc,CACjD,OAAO,aAAa,GAAG,OAAO,gBAAgB,CAgB/C,CAAA"}
@@ -0,0 +1,112 @@
1
+ import { FenceGateNode, FenceOpeningNode, findLevelAncestorId, } from '@pascal-app/core';
2
+ import { useViewer } from '@pascal-app/viewer';
3
+ import { AnimationClip, QuaternionKeyframeTrack } from 'three';
4
+ import { buildFenceFeatureFloorplan } from './floorplan';
5
+ import { fenceFeatureAffordance } from './floorplan-affordances';
6
+ import { buildFenceFeatureGeometry } from './geometry';
7
+ import { fenceFeatureHandles } from './handles';
8
+ import { FenceFeatureEditor } from './inspector';
9
+ import { toggleFenceGate } from './interaction';
10
+ import { createFenceFeatureMoveSession } from './move-session';
11
+ const floorplanMoveTarget = ({ node, sceneApi }) => {
12
+ if (!sceneApi)
13
+ throw new Error('Fence feature move requires SceneApi');
14
+ const levelId = findLevelAncestorId(node.id, sceneApi.nodes()) ?? null;
15
+ const session = createFenceFeatureMoveSession(node, sceneApi, levelId, (id) => useViewer.getState().setSelection({ selectedIds: [id] }));
16
+ return {
17
+ affectedIds: session.affectedIds,
18
+ apply: ({ planPoint }) => session.update(planPoint),
19
+ canCommit: session.canCommit,
20
+ commit: session.commit,
21
+ };
22
+ };
23
+ const parametrics = {
24
+ groups: [
25
+ {
26
+ label: 'Settings',
27
+ fields: [{ key: 'center', kind: 'custom', component: FenceFeatureEditor }],
28
+ },
29
+ ],
30
+ };
31
+ const shared = {
32
+ schemaVersion: 1,
33
+ category: 'structure',
34
+ capabilities: { selectable: { hitVolume: 'bbox' }, deletable: true },
35
+ geometry: buildFenceFeatureGeometry,
36
+ floorplan: buildFenceFeatureFloorplan,
37
+ floorplanDependencies: (node) => node.parentId ? [node.parentId] : [],
38
+ floorplanAffordances: { 'move-feature': fenceFeatureAffordance },
39
+ handles: fenceFeatureHandles,
40
+ floorplanMoveTarget,
41
+ affordanceTools: { move: () => import('./move-tool') },
42
+ affordanceHints: {
43
+ move: [
44
+ { key: 'Left click', label: 'Place on a fence' },
45
+ { key: 'Esc', label: 'Cancel move' },
46
+ ],
47
+ },
48
+ parametrics,
49
+ };
50
+ export const fenceGateDefinition = {
51
+ ...shared,
52
+ kind: 'fence-gate',
53
+ keyboardActions: {
54
+ e: {
55
+ appliesTo: (node) => node.type === 'fence-gate',
56
+ run: (node) => toggleFenceGate(node.id),
57
+ },
58
+ },
59
+ schema: FenceGateNode,
60
+ extensions: {
61
+ 'pascal:editor/floorplan': {
62
+ actionMenu: { actions: () => import('./actions') },
63
+ },
64
+ },
65
+ exportAnimation: ({ node, object }) => node.type === 'fence-gate' ? bakeFenceGateClip(node.id, object) : null,
66
+ defaults: () => {
67
+ const { id, type, ...rest } = FenceGateNode.parse({});
68
+ return rest;
69
+ },
70
+ presentation: {
71
+ label: 'Gate',
72
+ description: 'A gate hosted by a fence.',
73
+ icon: { kind: 'url', src: '/icons/fence.webp' },
74
+ paletteSection: 'structure',
75
+ hidden: true,
76
+ },
77
+ };
78
+ function bakeFenceGateClip(id, object) {
79
+ const tracks = [];
80
+ object.traverse((part) => {
81
+ const marker = part.userData.pascalFenceGateLeaf;
82
+ if (typeof marker?.openRotationY !== 'number' || Math.abs(marker.openRotationY) < 1e-5)
83
+ return;
84
+ part.rotation.y = 0;
85
+ const closed = part.quaternion.clone();
86
+ part.rotation.y = marker.openRotationY;
87
+ const open = part.quaternion.clone();
88
+ part.rotation.y = 0;
89
+ tracks.push(new QuaternionKeyframeTrack(`${part.uuid}.quaternion`, [0, 1], [...closed.toArray(), ...open.toArray()]));
90
+ });
91
+ if (tracks.length === 0)
92
+ return null;
93
+ const clip = new AnimationClip(`${id}: open`, 1, tracks);
94
+ clip.userData = { loop: false };
95
+ return clip;
96
+ }
97
+ export const fenceOpeningDefinition = {
98
+ ...shared,
99
+ kind: 'fence-opening',
100
+ schema: FenceOpeningNode,
101
+ defaults: () => {
102
+ const { id, type, ...rest } = FenceOpeningNode.parse({});
103
+ return rest;
104
+ },
105
+ presentation: {
106
+ label: 'Open Passage',
107
+ description: 'An intentional opening in a fence.',
108
+ icon: { kind: 'url', src: '/icons/door.webp' },
109
+ paletteSection: 'structure',
110
+ hidden: true,
111
+ },
112
+ };
@@ -0,0 +1,3 @@
1
+ import { type FenceFeatureNode, type FloorplanAffordance } from '@pascal-app/core';
2
+ export declare const fenceFeatureAffordance: FloorplanAffordance<FenceFeatureNode>;
3
+ //# sourceMappingURL=floorplan-affordances.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"floorplan-affordances.d.ts","sourceRoot":"","sources":["../../src/fence-feature/floorplan-affordances.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EAMzB,MAAM,kBAAkB,CAAA;AAEzB,eAAO,MAAM,sBAAsB,EAAE,mBAAmB,CAAC,gBAAgB,CAmCxE,CAAA"}
@@ -0,0 +1,37 @@
1
+ import { canPlaceFenceFeature, fenceFeatureData, fenceWithFeatures, projectPointToFence, useLiveNodeOverrides, useScene, } from '@pascal-app/core';
2
+ export const fenceFeatureAffordance = {
3
+ start({ node, payload, nodes }) {
4
+ const host = node.parentId ? nodes[node.parentId] : undefined;
5
+ const edge = payload.edge;
6
+ let patch = {};
7
+ return {
8
+ affectedIds: [node.id],
9
+ apply({ planPoint }) {
10
+ if (host?.type !== 'fence')
11
+ return;
12
+ const distance = projectPointToFence(host, planPoint).center;
13
+ let center = distance;
14
+ let width = node.width;
15
+ if (edge !== 'center') {
16
+ const fixed = node.center + ((edge === 'start' ? 1 : -1) * node.width) / 2;
17
+ if (edge === 'start' ? distance > fixed - 0.35 : distance < fixed + 0.35)
18
+ return;
19
+ width = Math.abs(fixed - distance);
20
+ center = (fixed + distance) / 2;
21
+ }
22
+ const fence = fenceWithFeatures(host, (host.children ?? []).map((id) => nodes[id]).filter(Boolean));
23
+ if (!canPlaceFenceFeature(fence, { ...fenceFeatureData(node), center, width }))
24
+ return;
25
+ patch = { center, width };
26
+ useLiveNodeOverrides.getState().set(node.id, patch);
27
+ useScene.getState().markDirty(node.id);
28
+ useScene.getState().markDirty(host.id);
29
+ },
30
+ canCommit: () => Object.keys(patch).length > 0,
31
+ commit() {
32
+ useScene.getState().updateNode(node.id, patch);
33
+ useLiveNodeOverrides.getState().clear(node.id);
34
+ },
35
+ };
36
+ },
37
+ };
@@ -0,0 +1,4 @@
1
+ import { type FenceFeatureData, type FenceFeatureNode, type FenceNode, type FloorplanGeometry, type GeometryContext } from '@pascal-app/core';
2
+ export declare function buildFenceFeatureFloorplan(child: FenceFeatureNode, ctx: GeometryContext): FloorplanGeometry | null;
3
+ export declare function buildFenceFeatureSymbol(data: FenceFeatureData, node: FenceNode, ctx: GeometryContext, interactive?: boolean): FloorplanGeometry;
4
+ //# sourceMappingURL=floorplan.d.ts.map