@pascal-app/editor 0.8.0 → 0.9.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 (350) hide show
  1. package/package.json +15 -13
  2. package/src/components/editor/alignment-3d-guide-layer.tsx +168 -0
  3. package/src/components/editor/bake-exporter.tsx +47 -0
  4. package/src/components/editor/custom-camera-controls.tsx +795 -28
  5. package/src/components/editor/editor-layout-mobile.tsx +8 -3
  6. package/src/components/editor/editor-layout-v2.tsx +76 -51
  7. package/src/components/editor/export-manager.tsx +69 -32
  8. package/src/components/editor/fence-tangent-lines-3d.tsx +87 -0
  9. package/src/components/editor/first-person/build-collider-world.test.ts +182 -0
  10. package/src/components/editor/first-person/build-collider-world.ts +228 -83
  11. package/src/components/editor/first-person-controls.tsx +943 -27
  12. package/src/components/editor/floating-action-menu.tsx +676 -208
  13. package/src/components/editor/floating-building-action-menu.tsx +2 -2
  14. package/src/components/editor/floorplan-background-selection.test.ts +58 -0
  15. package/src/components/editor/floorplan-background-selection.ts +3 -2
  16. package/src/components/editor/floorplan-panel.tsx +6916 -12137
  17. package/src/components/editor/grid.tsx +197 -36
  18. package/src/components/editor/group-actions.ts +457 -0
  19. package/src/components/editor/group-floating-action-menu.tsx +130 -0
  20. package/src/components/editor/group-move-3d.ts +397 -0
  21. package/src/components/editor/group-rotate-handle.tsx +420 -0
  22. package/src/components/editor/group-selection-box-3d.tsx +173 -0
  23. package/src/components/editor/group-transform-shared.test.ts +396 -0
  24. package/src/components/editor/group-transform-shared.ts +489 -0
  25. package/src/components/editor/handles/handle-arrow.tsx +581 -0
  26. package/src/components/editor/handles/use-handle-drag.ts +246 -0
  27. package/src/components/editor/index.tsx +412 -162
  28. package/src/components/editor/measurement-pill.tsx +115 -0
  29. package/src/components/editor/node-action-menu.tsx +14 -1
  30. package/src/components/editor/node-arrow-handles.tsx +1646 -0
  31. package/src/components/editor/opening-guides-3d-layer.tsx +144 -0
  32. package/src/components/editor/quick-measurement-card.tsx +70 -0
  33. package/src/components/editor/quick-measurement-hud.tsx +28 -0
  34. package/src/components/editor/riser-diagram-panel.tsx +137 -0
  35. package/src/components/editor/selection-manager.tsx +1106 -483
  36. package/src/components/editor/site-edge-labels.tsx +45 -21
  37. package/src/components/editor/slab-hole-highlights.tsx +474 -0
  38. package/src/components/editor/snapshot-capture-overlay.tsx +369 -155
  39. package/src/components/editor/three-context-bridge.ts +22 -0
  40. package/src/components/editor/thumbnail-generator.tsx +140 -41
  41. package/src/components/editor/use-floorplan-background-placement.ts +190 -35
  42. package/src/components/editor/use-floorplan-hit-testing.ts +24 -0
  43. package/src/components/editor/use-floorplan-scene-data.ts +19 -7
  44. package/src/components/editor/use-mesh-settle-epoch.ts +26 -0
  45. package/src/components/editor/wall-measurement-label.tsx +14 -19
  46. package/src/components/editor/wall-move-side-handles.tsx +870 -0
  47. package/src/components/editor/wall-opening-highlights.tsx +181 -0
  48. package/src/components/editor/wall-snap-beacon-layer.tsx +304 -0
  49. package/src/components/editor-2d/floorplan-action-menu-layer.tsx +15 -6
  50. package/src/components/editor-2d/floorplan-alignment-guide-layer.tsx +142 -0
  51. package/src/components/editor-2d/floorplan-cursor-indicator-overlay.tsx +5 -3
  52. package/src/components/editor-2d/floorplan-group-action-menu.tsx +87 -0
  53. package/src/components/editor-2d/floorplan-group-move.tsx +701 -0
  54. package/src/components/editor-2d/floorplan-measurement-tool-layer.test.ts +113 -0
  55. package/src/components/editor-2d/floorplan-measurement-tool-layer.tsx +1656 -0
  56. package/src/components/editor-2d/floorplan-quick-measure-layer.tsx +212 -0
  57. package/src/components/editor-2d/floorplan-registry-action-menu.tsx +392 -0
  58. package/src/components/editor-2d/floorplan-registry-move-overlay.tsx +857 -0
  59. package/src/components/editor-2d/floorplan-render-context.tsx +62 -0
  60. package/src/components/editor-2d/floorplan-snap-beacon-layer.tsx +77 -0
  61. package/src/components/editor-2d/floorplan-wall-move-ghost-layer.tsx +47 -0
  62. package/src/components/editor-2d/renderers/floorplan-geometry-renderer.tsx +266 -0
  63. package/src/components/editor-2d/renderers/floorplan-label-angle.test.ts +15 -0
  64. package/src/components/editor-2d/renderers/floorplan-label-angle.ts +14 -0
  65. package/src/components/editor-2d/renderers/floorplan-measurements-layer.tsx +108 -66
  66. package/src/components/editor-2d/renderers/floorplan-placement-preview-layer.tsx +62 -0
  67. package/src/components/editor-2d/renderers/floorplan-registry-layer.test.ts +308 -0
  68. package/src/components/editor-2d/renderers/floorplan-registry-layer.tsx +3325 -0
  69. package/src/components/editor-2d/renderers/floorplan-stair-layer.tsx +24 -9
  70. package/src/components/editor-2d/renderers/floorplan-voronoi-layer.tsx +128 -0
  71. package/src/components/editor-2d/svg-paths.ts +10 -2
  72. package/src/components/systems/ceiling/ceiling-selection-affordance-system.tsx +439 -57
  73. package/src/components/systems/ceiling/ceiling-system.tsx +109 -12
  74. package/src/components/systems/roof/roof-edit-system.tsx +1851 -22
  75. package/src/components/systems/selection-affordance-manager.tsx +38 -0
  76. package/src/components/systems/stair/stair-edit-system.tsx +1 -1
  77. package/src/components/systems/zone/zone-label-editor-system.tsx +14 -1
  78. package/src/components/systems/zone/zone-system.tsx +42 -13
  79. package/src/components/tools/elevator/elevator-defaults.ts +8 -0
  80. package/src/components/tools/elevator/elevator-tool.tsx +375 -0
  81. package/src/components/tools/elevator/move-elevator-tool.tsx +263 -0
  82. package/src/components/tools/fence/fence-drafting.ts +141 -27
  83. package/src/components/tools/item/move-tool.tsx +45 -105
  84. package/src/components/tools/item/placement-math.test.ts +22 -0
  85. package/src/components/tools/item/placement-math.ts +59 -7
  86. package/src/components/tools/item/placement-strategies.ts +432 -16
  87. package/src/components/tools/item/placement-types.ts +22 -1
  88. package/src/components/tools/item/use-draft-node.ts +51 -2
  89. package/src/components/tools/item/use-placement-coordinator.tsx +1399 -256
  90. package/src/components/tools/registry/move-registry-node-tool.tsx +1064 -0
  91. package/src/components/tools/roof/roof-tool.tsx +350 -28
  92. package/src/components/tools/select/box-select-state.ts +88 -0
  93. package/src/components/tools/select/box-select-tool.tsx +442 -520
  94. package/src/components/tools/select/marquee-geometry.test.ts +161 -0
  95. package/src/components/tools/select/marquee-geometry.ts +155 -0
  96. package/src/components/tools/select/plane-box-select-tool.tsx +570 -0
  97. package/src/components/tools/select/screen-rectangle-selection.ts +84 -0
  98. package/src/components/tools/select/select-candidates.test.ts +109 -0
  99. package/src/components/tools/select/select-candidates.ts +85 -0
  100. package/src/components/tools/shared/affordance-dispatch.ts +30 -0
  101. package/src/components/tools/shared/cursor-sphere.tsx +62 -26
  102. package/src/components/tools/shared/drag-bounding-box.tsx +195 -0
  103. package/src/components/tools/shared/facing-indicator.tsx +87 -0
  104. package/src/components/tools/shared/facing-pose-indicator.tsx +54 -0
  105. package/src/components/tools/shared/floor-stack-preview.ts +25 -0
  106. package/src/components/tools/shared/fresh-placement-visibility.ts +61 -0
  107. package/src/components/tools/shared/placement-box-geometry.ts +123 -0
  108. package/src/components/tools/shared/placement-box.tsx +305 -0
  109. package/src/components/tools/shared/polygon-editor.tsx +866 -175
  110. package/src/components/tools/shared/segment-angle.ts +56 -0
  111. package/src/components/tools/site/site-boundary-editor.tsx +520 -16
  112. package/src/components/tools/site/site-flag-model.ts +18 -0
  113. package/src/components/tools/stair/stair-defaults.ts +2 -1
  114. package/src/components/tools/stair/stair-tool.tsx +342 -37
  115. package/src/components/tools/tool-manager.tsx +239 -62
  116. package/src/components/tools/wall/wall-drafting.test.ts +330 -0
  117. package/src/components/tools/wall/wall-drafting.ts +248 -171
  118. package/src/components/tools/wall/wall-snap-geometry.test.ts +123 -0
  119. package/src/components/tools/wall/wall-snap-geometry.ts +331 -0
  120. package/src/components/tools/zone/zone-boundary-editor.tsx +5 -1
  121. package/src/components/tools/zone/zone-tool.tsx +86 -82
  122. package/src/components/ui/action-menu/action-button.tsx +21 -1
  123. package/src/components/ui/action-menu/camera-actions.tsx +24 -17
  124. package/src/components/ui/action-menu/control-modes.tsx +40 -170
  125. package/src/components/ui/action-menu/furnish-tools.tsx +5 -5
  126. package/src/components/ui/action-menu/index.tsx +3 -117
  127. package/src/components/ui/action-menu/measurement-control.tsx +188 -0
  128. package/src/components/ui/action-menu/structure-tools.tsx +27 -93
  129. package/src/components/ui/action-menu/view-toggles.tsx +279 -90
  130. package/src/components/ui/command-palette/editor-commands.tsx +20 -15
  131. package/src/components/ui/command-palette/index.tsx +5 -3
  132. package/src/components/ui/controls/material-paint-panel.tsx +152 -0
  133. package/src/components/ui/controls/material-picker.tsx +87 -177
  134. package/src/components/ui/controls/material-properties-editor.tsx +108 -0
  135. package/src/components/ui/controls/metric-control.tsx +142 -46
  136. package/src/components/ui/controls/scene-material-list.tsx +247 -0
  137. package/src/components/ui/controls/slider-control.tsx +88 -38
  138. package/src/components/ui/floating-level-selector.tsx +47 -10
  139. package/src/components/ui/helpers/building-helper.tsx +10 -23
  140. package/src/components/ui/helpers/contextual-helper-panel.tsx +428 -0
  141. package/src/components/ui/helpers/helper-manager.tsx +235 -23
  142. package/src/components/ui/helpers/item-helper.tsx +28 -32
  143. package/src/components/ui/helpers/registered-tool-helper.tsx +59 -0
  144. package/src/components/ui/helpers/roof-helper.tsx +10 -12
  145. package/src/components/ui/icon-ref.tsx +47 -0
  146. package/src/components/ui/item-catalog/catalog-items.tsx +40 -1
  147. package/src/components/ui/item-catalog/item-catalog.tsx +16 -36
  148. package/src/components/ui/level-duplicate-dialog.tsx +2 -1
  149. package/src/components/ui/panels/node-display.ts +17 -16
  150. package/src/components/ui/panels/panel-manager.tsx +55 -58
  151. package/src/components/ui/panels/panel-wrapper.tsx +238 -12
  152. package/src/components/ui/panels/parametric-inspector.tsx +482 -0
  153. package/src/components/ui/panels/reference-panel.tsx +54 -19
  154. package/src/components/ui/primitives/dropdown-menu.tsx +12 -8
  155. package/src/components/ui/primitives/shortcut-token.tsx +39 -3
  156. package/src/components/ui/primitives/sidebar.tsx +1 -0
  157. package/src/components/ui/scene-loader.tsx +1 -3
  158. package/src/components/ui/sidebar/app-sidebar.tsx +5 -1
  159. package/src/components/ui/sidebar/icon-rail.tsx +50 -31
  160. package/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx +263 -0
  161. package/src/components/ui/sidebar/panels/items-panel/index.tsx +82 -8
  162. package/src/components/ui/sidebar/panels/plugins-panel.tsx +218 -0
  163. package/src/components/ui/sidebar/panels/settings-panel/index.tsx +122 -41
  164. package/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx +66 -7
  165. package/src/components/ui/sidebar/panels/settings-panel/load-build-dialog.tsx +267 -0
  166. package/src/components/ui/sidebar/panels/site-panel/building-tree-node.tsx +3 -1
  167. package/src/components/ui/sidebar/panels/site-panel/ceiling-tree-node.tsx +9 -5
  168. package/src/components/ui/sidebar/panels/site-panel/chimney-tree-node.tsx +86 -0
  169. package/src/components/ui/sidebar/panels/site-panel/column-tree-node.tsx +1 -1
  170. package/src/components/ui/sidebar/panels/site-panel/door-tree-node.tsx +7 -2
  171. package/src/components/ui/sidebar/panels/site-panel/dormer-tree-node.tsx +92 -0
  172. package/src/components/ui/sidebar/panels/site-panel/elevator-tree-node.tsx +75 -0
  173. package/src/components/ui/sidebar/panels/site-panel/fence-tree-node.tsx +3 -3
  174. package/src/components/ui/sidebar/panels/site-panel/gutter-tree-node.tsx +86 -0
  175. package/src/components/ui/sidebar/panels/site-panel/index.tsx +42 -21
  176. package/src/components/ui/sidebar/panels/site-panel/item-tree-node.tsx +31 -17
  177. package/src/components/ui/sidebar/panels/site-panel/level-tree-node.tsx +2 -1
  178. package/src/components/ui/sidebar/panels/site-panel/registry-tree-node.tsx +140 -0
  179. package/src/components/ui/sidebar/panels/site-panel/roof-tree-node.tsx +48 -8
  180. package/src/components/ui/sidebar/panels/site-panel/shelf-tree-node.tsx +132 -0
  181. package/src/components/ui/sidebar/panels/site-panel/slab-tree-node.tsx +9 -5
  182. package/src/components/ui/sidebar/panels/site-panel/solar-panel-tree-node.tsx +86 -0
  183. package/src/components/ui/sidebar/panels/site-panel/spawn-tree-node.tsx +7 -1
  184. package/src/components/ui/sidebar/panels/site-panel/stair-tree-node.tsx +2 -2
  185. package/src/components/ui/sidebar/panels/site-panel/tree-node.tsx +112 -39
  186. package/src/components/ui/sidebar/panels/site-panel/tree-structure.ts +36 -0
  187. package/src/components/ui/sidebar/panels/site-panel/wall-tree-node.tsx +1 -1
  188. package/src/components/ui/sidebar/panels/site-panel/window-tree-node.tsx +7 -2
  189. package/src/components/ui/sidebar/panels/site-panel/zone-tree-node.tsx +3 -3
  190. package/src/components/ui/sidebar/panels/zone-panel/index.tsx +51 -2
  191. package/src/components/ui/sidebar/tab-bar.tsx +75 -1
  192. package/src/components/ui/sidebar/use-plugin-panels.tsx +132 -0
  193. package/src/components/ui/snap-target-badge.test.tsx +40 -0
  194. package/src/components/ui/snap-target-badge.tsx +88 -0
  195. package/src/components/viewer-overlay.tsx +253 -61
  196. package/src/components/viewer-zone-system.tsx +7 -2
  197. package/src/hooks/use-auto-save.test.ts +14 -0
  198. package/src/hooks/use-auto-save.ts +64 -10
  199. package/src/hooks/use-ceiling-events.ts +176 -0
  200. package/src/hooks/use-drag-action.ts +127 -0
  201. package/src/hooks/use-keyboard.ts +493 -95
  202. package/src/hooks/use-selection.ts +64 -0
  203. package/src/index.tsx +451 -6
  204. package/src/lib/active-placement-surface.ts +35 -0
  205. package/src/lib/ceiling-plan-snap.ts +24 -0
  206. package/src/lib/constants.ts +6 -2
  207. package/src/lib/contextual-help.test.ts +112 -0
  208. package/src/lib/contextual-help.ts +144 -0
  209. package/src/lib/continuation.ts +64 -0
  210. package/src/lib/direct-manipulation.test.ts +192 -0
  211. package/src/lib/direct-manipulation.ts +109 -0
  212. package/src/lib/editor-api.ts +50 -0
  213. package/src/lib/elevator-support.ts +96 -0
  214. package/src/lib/floorplan/apply-alignment.test.ts +25 -0
  215. package/src/lib/floorplan/apply-alignment.ts +117 -0
  216. package/src/lib/floorplan/floorplan-export.tsx +364 -0
  217. package/src/lib/floorplan/geometry.ts +53 -0
  218. package/src/lib/floorplan/index.ts +10 -0
  219. package/src/lib/floorplan/items.ts +5 -2
  220. package/src/lib/floorplan/plan-coords.ts +21 -0
  221. package/src/lib/floorplan/selection-tool.ts +40 -0
  222. package/src/lib/floorplan/stairs.ts +12 -1
  223. package/src/lib/fresh-planar-placement.test.ts +339 -0
  224. package/src/lib/fresh-planar-placement.ts +130 -0
  225. package/src/lib/glb-export.test.ts +441 -0
  226. package/src/lib/glb-export.ts +874 -0
  227. package/src/lib/history.ts +11 -1
  228. package/src/lib/interaction/hot-set.test.ts +133 -0
  229. package/src/lib/interaction/hot-set.ts +67 -0
  230. package/src/lib/interaction/overlay-policy.test.ts +51 -0
  231. package/src/lib/interaction/overlay-policy.ts +59 -0
  232. package/src/lib/interaction/scope.ts +211 -0
  233. package/src/lib/level-duplication.ts +54 -42
  234. package/src/lib/level-selection.ts +2 -2
  235. package/src/lib/material-paint.ts +227 -48
  236. package/src/lib/measurement-kind.test.ts +30 -0
  237. package/src/lib/measurement-kind.ts +19 -0
  238. package/src/lib/measurement-label.test.ts +47 -0
  239. package/src/lib/measurement-label.ts +68 -0
  240. package/src/lib/measurement-parser.ts +116 -0
  241. package/src/lib/measurements.test.ts +183 -0
  242. package/src/lib/measurements.ts +199 -0
  243. package/src/lib/paint-scope.test.ts +454 -0
  244. package/src/lib/paint-scope.ts +461 -0
  245. package/src/lib/placement-drag-release.ts +23 -0
  246. package/src/lib/placement-metadata.ts +29 -0
  247. package/src/lib/planar-cursor-placement.test.ts +100 -0
  248. package/src/lib/planar-cursor-placement.ts +42 -0
  249. package/src/lib/plugin-panels.test.ts +19 -0
  250. package/src/lib/plugin-panels.ts +91 -0
  251. package/src/lib/quick-measurement.test.ts +77 -0
  252. package/src/lib/quick-measurement.ts +109 -0
  253. package/src/lib/roof-duplication.ts +7 -7
  254. package/src/lib/roof-hover-outline-proxy.ts +22 -0
  255. package/src/lib/roof-wall-hit.ts +164 -0
  256. package/src/lib/scene-clipboard.test.ts +196 -0
  257. package/src/lib/scene-clipboard.ts +332 -0
  258. package/src/lib/scene.ts +40 -8
  259. package/src/lib/selection-routing.test.ts +298 -0
  260. package/src/lib/selection-routing.ts +175 -0
  261. package/src/lib/sfx/index.ts +1 -0
  262. package/src/lib/sfx/movement-tick.test.ts +65 -0
  263. package/src/lib/sfx/movement-tick.ts +18 -0
  264. package/src/lib/sfx-bus.ts +69 -10
  265. package/src/lib/sfx-player.test.ts +124 -0
  266. package/src/lib/sfx-player.ts +148 -55
  267. package/src/lib/site-boundary.ts +1 -0
  268. package/src/lib/slab-plan-snap.test.ts +93 -0
  269. package/src/lib/slab-plan-snap.ts +108 -0
  270. package/src/lib/snapping-mode.test.ts +138 -0
  271. package/src/lib/snapping-mode.ts +179 -0
  272. package/src/lib/stair-duplication.ts +4 -4
  273. package/src/lib/stair-levels.test.ts +146 -0
  274. package/src/lib/stair-levels.ts +177 -0
  275. package/src/lib/surface-plan-snap.test.ts +71 -0
  276. package/src/lib/surface-plan-snap.ts +256 -0
  277. package/src/lib/use-linear-display.ts +40 -0
  278. package/src/lib/world-grid-snap.ts +231 -0
  279. package/src/lib/zone-content.ts +130 -0
  280. package/src/store/use-alignment-guides.ts +21 -0
  281. package/src/store/use-direct-manipulation-feedback.ts +20 -0
  282. package/src/store/use-editor.tsx +767 -114
  283. package/src/store/use-facing-pose.ts +44 -0
  284. package/src/store/use-fence-curve-draft.ts +21 -0
  285. package/src/store/use-floorplan-draft-preview.ts +101 -0
  286. package/src/store/use-floorplan-marquee.ts +50 -0
  287. package/src/store/use-interaction-scope.test.ts +186 -0
  288. package/src/store/use-interaction-scope.ts +132 -0
  289. package/src/store/use-measurement-draft.test.ts +530 -0
  290. package/src/store/use-measurement-draft.ts +543 -0
  291. package/src/store/use-opening-guides.ts +41 -0
  292. package/src/store/use-placement-preview.ts +39 -0
  293. package/src/store/use-quick-measurement-hud.test.ts +53 -0
  294. package/src/store/use-quick-measurement-hud.ts +77 -0
  295. package/src/store/use-segment-draft-chain.ts +28 -0
  296. package/src/store/use-stair-build-preview.ts +43 -0
  297. package/src/store/use-wall-move-ghosts.ts +36 -0
  298. package/src/store/use-wall-snap-indicator.ts +34 -0
  299. package/src/components/editor/first-person/bvh-ecctrl.tsx +0 -860
  300. package/src/components/editor/preset-thumbnail-generator.tsx +0 -125
  301. package/src/components/editor-2d/renderers/floorplan-roof-layer.tsx +0 -113
  302. package/src/components/tools/building/move-building-tool.tsx +0 -157
  303. package/src/components/tools/ceiling/ceiling-boundary-editor.tsx +0 -43
  304. package/src/components/tools/ceiling/ceiling-hole-editor.tsx +0 -49
  305. package/src/components/tools/ceiling/ceiling-tool.tsx +0 -465
  306. package/src/components/tools/ceiling/move-ceiling-tool.tsx +0 -264
  307. package/src/components/tools/column/column-tool.tsx +0 -97
  308. package/src/components/tools/column/move-column-tool.tsx +0 -105
  309. package/src/components/tools/door/door-math.ts +0 -110
  310. package/src/components/tools/door/door-tool.tsx +0 -324
  311. package/src/components/tools/door/move-door-tool.tsx +0 -412
  312. package/src/components/tools/fence/curve-fence-tool.tsx +0 -178
  313. package/src/components/tools/fence/fence-tool.tsx +0 -346
  314. package/src/components/tools/fence/move-fence-endpoint-tool.tsx +0 -441
  315. package/src/components/tools/fence/move-fence-tool.tsx +0 -302
  316. package/src/components/tools/item/item-tool.tsx +0 -26
  317. package/src/components/tools/roof/move-roof-tool.tsx +0 -364
  318. package/src/components/tools/slab/move-slab-tool.tsx +0 -182
  319. package/src/components/tools/slab/slab-boundary-editor.tsx +0 -43
  320. package/src/components/tools/slab/slab-hole-editor.tsx +0 -49
  321. package/src/components/tools/slab/slab-tool.tsx +0 -322
  322. package/src/components/tools/spawn/move-spawn-tool.tsx +0 -101
  323. package/src/components/tools/spawn/spawn-tool.tsx +0 -130
  324. package/src/components/tools/wall/curve-wall-tool.tsx +0 -178
  325. package/src/components/tools/wall/move-wall-endpoint-tool.tsx +0 -426
  326. package/src/components/tools/wall/move-wall-tool.tsx +0 -358
  327. package/src/components/tools/wall/wall-tool.tsx +0 -332
  328. package/src/components/tools/window/move-window-tool.tsx +0 -447
  329. package/src/components/tools/window/window-math.ts +0 -117
  330. package/src/components/tools/window/window-tool.tsx +0 -332
  331. package/src/components/ui/helpers/ceiling-helper.tsx +0 -20
  332. package/src/components/ui/helpers/slab-helper.tsx +0 -20
  333. package/src/components/ui/helpers/wall-helper.tsx +0 -20
  334. package/src/components/ui/panels/ceiling-panel.tsx +0 -249
  335. package/src/components/ui/panels/column-panel.tsx +0 -759
  336. package/src/components/ui/panels/door-panel.tsx +0 -1299
  337. package/src/components/ui/panels/fence-panel.tsx +0 -222
  338. package/src/components/ui/panels/item-panel.tsx +0 -306
  339. package/src/components/ui/panels/paint-panel.tsx +0 -163
  340. package/src/components/ui/panels/presets/presets-popover.tsx +0 -511
  341. package/src/components/ui/panels/roof-panel.tsx +0 -280
  342. package/src/components/ui/panels/roof-segment-panel.tsx +0 -311
  343. package/src/components/ui/panels/slab-panel.tsx +0 -250
  344. package/src/components/ui/panels/spawn-panel.tsx +0 -161
  345. package/src/components/ui/panels/stair-panel.tsx +0 -577
  346. package/src/components/ui/panels/stair-segment-panel.tsx +0 -325
  347. package/src/components/ui/panels/wall-panel.tsx +0 -273
  348. package/src/components/ui/panels/window-panel.tsx +0 -968
  349. package/src/contexts/presets-context.tsx +0 -121
  350. package/src/hooks/use-contextual-tools.ts +0 -61
@@ -1,325 +0,0 @@
1
- 'use client'
2
-
3
- import {
4
- type AnyNode,
5
- type AnyNodeId,
6
- type AttachmentSide,
7
- type StairSegmentNode,
8
- StairSegmentNode as StairSegmentNodeSchema,
9
- type StairSegmentType,
10
- useScene,
11
- } from '@pascal-app/core'
12
- import { useViewer } from '@pascal-app/viewer'
13
- import { Copy, Move, Trash2 } from 'lucide-react'
14
- import { useCallback } from 'react'
15
- import { sfxEmitter } from '../../../lib/sfx-bus'
16
- import useEditor from '../../../store/use-editor'
17
- import { ActionButton, ActionGroup } from '../controls/action-button'
18
- import { PanelSection } from '../controls/panel-section'
19
- import { SegmentedControl } from '../controls/segmented-control'
20
- import { SliderControl } from '../controls/slider-control'
21
- import { PanelWrapper } from './panel-wrapper'
22
-
23
- const SEGMENT_TYPE_OPTIONS: { label: string; value: StairSegmentType }[] = [
24
- { label: 'Flight', value: 'stair' },
25
- { label: 'Landing', value: 'landing' },
26
- ]
27
-
28
- const ATTACHMENT_SIDE_OPTIONS: { label: string; value: AttachmentSide }[] = [
29
- { label: 'Front', value: 'front' },
30
- { label: 'Left', value: 'left' },
31
- { label: 'Right', value: 'right' },
32
- ]
33
-
34
- export function StairSegmentPanel() {
35
- const selectedId = useViewer((s) => s.selection.selectedIds[0])
36
- const setSelection = useViewer((s) => s.setSelection)
37
- const updateNode = useScene((s) => s.updateNode)
38
- const setMovingNode = useEditor((s) => s.setMovingNode)
39
-
40
- const node = useScene((s) =>
41
- selectedId ? (s.nodes[selectedId as AnyNode['id']] as StairSegmentNode | undefined) : undefined,
42
- )
43
-
44
- // Boolean selector — re-renders only when this segment's position among the
45
- // parent stair's children flips to/from "first".
46
- const isFirstSegment = useScene((s) => {
47
- if (!node?.parentId) return true
48
- const parent = s.nodes[node.parentId as AnyNodeId]
49
- if (!parent || parent.type !== 'stair') return true
50
- const children = (parent as any).children ?? []
51
- return children[0] === node.id
52
- })
53
-
54
- const handleUpdate = useCallback(
55
- (updates: Partial<StairSegmentNode>) => {
56
- if (!selectedId) return
57
- updateNode(selectedId as AnyNode['id'], updates)
58
- },
59
- [selectedId, updateNode],
60
- )
61
-
62
- const handleClose = useCallback(() => {
63
- setSelection({ selectedIds: [] })
64
- }, [setSelection])
65
-
66
- const handleBack = useCallback(() => {
67
- if (node?.parentId) {
68
- setSelection({ selectedIds: [node.parentId] })
69
- }
70
- }, [node?.parentId, setSelection])
71
-
72
- const handleDuplicate = useCallback(() => {
73
- if (!node?.parentId) return
74
- sfxEmitter.emit('sfx:item-pick')
75
-
76
- let duplicateInfo = structuredClone(node) as any
77
- delete duplicateInfo.id
78
- duplicateInfo.metadata = { ...duplicateInfo.metadata, isNew: true }
79
- duplicateInfo.position = [
80
- duplicateInfo.position[0] + 1,
81
- duplicateInfo.position[1],
82
- duplicateInfo.position[2] + 1,
83
- ]
84
-
85
- try {
86
- const duplicate = StairSegmentNodeSchema.parse(duplicateInfo)
87
- useScene.getState().createNode(duplicate, duplicate.parentId as AnyNodeId)
88
- setSelection({ selectedIds: [] })
89
- setMovingNode(duplicate)
90
- } catch (e) {
91
- console.error('Failed to duplicate stair segment', e)
92
- }
93
- }, [node, setSelection, setMovingNode])
94
-
95
- const handleMove = useCallback(() => {
96
- if (node) {
97
- sfxEmitter.emit('sfx:item-pick')
98
- setMovingNode(node)
99
- setSelection({ selectedIds: [] })
100
- }
101
- }, [node, setMovingNode, setSelection])
102
-
103
- const handleDelete = useCallback(() => {
104
- if (!(selectedId && node)) return
105
- sfxEmitter.emit('sfx:item-delete')
106
- const parentId = node.parentId
107
- useScene.getState().deleteNode(selectedId as AnyNodeId)
108
- if (parentId) {
109
- useScene.getState().dirtyNodes.add(parentId as AnyNodeId)
110
- setSelection({ selectedIds: [parentId] })
111
- } else {
112
- setSelection({ selectedIds: [] })
113
- }
114
- }, [selectedId, node, setSelection])
115
-
116
- if (!(node && node.type === 'stair-segment' && selectedId)) return null
117
-
118
- return (
119
- <PanelWrapper
120
- icon="/icons/stairs.png"
121
- onBack={handleBack}
122
- onClose={handleClose}
123
- title={node.name || 'Stair Segment'}
124
- width={300}
125
- >
126
- <PanelSection title="Type">
127
- <SegmentedControl
128
- onChange={(v) => {
129
- const updates: Partial<StairSegmentNode> = { segmentType: v }
130
- if (v === 'landing') {
131
- updates.height = 0
132
- updates.stepCount = 0
133
- updates.length = 1.0
134
- } else {
135
- updates.height = 2.5
136
- updates.stepCount = 10
137
- updates.length = 3.0
138
- }
139
- handleUpdate(updates)
140
- }}
141
- options={SEGMENT_TYPE_OPTIONS}
142
- value={node.segmentType}
143
- />
144
- </PanelSection>
145
-
146
- {!isFirstSegment && (
147
- <PanelSection title="Attachment">
148
- <SegmentedControl
149
- onChange={(v) => handleUpdate({ attachmentSide: v })}
150
- options={ATTACHMENT_SIDE_OPTIONS}
151
- value={node.attachmentSide}
152
- />
153
- </PanelSection>
154
- )}
155
-
156
- <PanelSection title="Dimensions">
157
- <SliderControl
158
- label="Width"
159
- max={5}
160
- min={0.5}
161
- onChange={(v) => handleUpdate({ width: v })}
162
- precision={2}
163
- step={0.1}
164
- unit="m"
165
- value={Math.round(node.width * 100) / 100}
166
- />
167
- <SliderControl
168
- label="Length"
169
- max={10}
170
- min={0.5}
171
- onChange={(v) => handleUpdate({ length: v })}
172
- precision={2}
173
- step={0.1}
174
- unit="m"
175
- value={Math.round(node.length * 100) / 100}
176
- />
177
- {node.segmentType === 'stair' && (
178
- <>
179
- <SliderControl
180
- label="Height"
181
- max={10}
182
- min={0.5}
183
- onChange={(v) => handleUpdate({ height: v })}
184
- precision={2}
185
- step={0.1}
186
- unit="m"
187
- value={Math.round(node.height * 100) / 100}
188
- />
189
- <SliderControl
190
- label="Steps"
191
- max={30}
192
- min={2}
193
- onChange={(v) => handleUpdate({ stepCount: Math.round(v) })}
194
- precision={0}
195
- step={1}
196
- unit=""
197
- value={node.stepCount}
198
- />
199
- </>
200
- )}
201
- </PanelSection>
202
-
203
- <PanelSection title="Structure">
204
- <div className="flex items-center justify-between px-1 py-1">
205
- <span className="text-muted-foreground text-xs">Fill to floor</span>
206
- <button
207
- className={`relative h-5 w-10 rounded-full transition-colors ${
208
- node.fillToFloor ? 'bg-blue-500' : 'bg-[#3e3e3e]'
209
- }`}
210
- onClick={() => handleUpdate({ fillToFloor: !node.fillToFloor })}
211
- type="button"
212
- >
213
- <div
214
- className={`absolute top-1 h-3 w-3 rounded-full bg-white transition-transform ${
215
- node.fillToFloor ? 'left-6' : 'left-1'
216
- }`}
217
- />
218
- </button>
219
- </div>
220
- {!node.fillToFloor && (
221
- <SliderControl
222
- label="Thickness"
223
- max={1}
224
- min={0.05}
225
- onChange={(v) => handleUpdate({ thickness: v })}
226
- precision={2}
227
- step={0.05}
228
- unit="m"
229
- value={Math.round((node.thickness ?? 0.25) * 100) / 100}
230
- />
231
- )}
232
- </PanelSection>
233
-
234
- <PanelSection title="Position">
235
- <SliderControl
236
- label="X"
237
- max={50}
238
- min={-50}
239
- onChange={(v) => {
240
- const pos = [...node.position] as [number, number, number]
241
- pos[0] = v
242
- handleUpdate({ position: pos })
243
- }}
244
- precision={2}
245
- step={0.05}
246
- unit="m"
247
- value={Math.round(node.position[0] * 100) / 100}
248
- />
249
- <SliderControl
250
- label="Y"
251
- max={50}
252
- min={-50}
253
- onChange={(v) => {
254
- const pos = [...node.position] as [number, number, number]
255
- pos[1] = v
256
- handleUpdate({ position: pos })
257
- }}
258
- precision={2}
259
- step={0.05}
260
- unit="m"
261
- value={Math.round(node.position[1] * 100) / 100}
262
- />
263
- <SliderControl
264
- label="Z"
265
- max={50}
266
- min={-50}
267
- onChange={(v) => {
268
- const pos = [...node.position] as [number, number, number]
269
- pos[2] = v
270
- handleUpdate({ position: pos })
271
- }}
272
- precision={2}
273
- step={0.05}
274
- unit="m"
275
- value={Math.round(node.position[2] * 100) / 100}
276
- />
277
- <SliderControl
278
- label="Rotation"
279
- max={180}
280
- min={-180}
281
- onChange={(degrees) => {
282
- handleUpdate({ rotation: (degrees * Math.PI) / 180 })
283
- }}
284
- precision={0}
285
- step={1}
286
- unit="°"
287
- value={Math.round((node.rotation * 180) / Math.PI)}
288
- />
289
- <div className="flex gap-1.5 px-1 pt-2 pb-1">
290
- <ActionButton
291
- label="-45°"
292
- onClick={() => {
293
- sfxEmitter.emit('sfx:item-rotate')
294
- handleUpdate({ rotation: node.rotation - Math.PI / 4 })
295
- }}
296
- />
297
- <ActionButton
298
- label="+45°"
299
- onClick={() => {
300
- sfxEmitter.emit('sfx:item-rotate')
301
- handleUpdate({ rotation: node.rotation + Math.PI / 4 })
302
- }}
303
- />
304
- </div>
305
- </PanelSection>
306
-
307
- <PanelSection title="Actions">
308
- <ActionGroup>
309
- <ActionButton icon={<Move className="h-3.5 w-3.5" />} label="Move" onClick={handleMove} />
310
- <ActionButton
311
- icon={<Copy className="h-3.5 w-3.5" />}
312
- label="Duplicate"
313
- onClick={handleDuplicate}
314
- />
315
- <ActionButton
316
- className="hover:bg-red-500/20"
317
- icon={<Trash2 className="h-3.5 w-3.5 text-red-400" />}
318
- label="Delete"
319
- onClick={handleDelete}
320
- />
321
- </ActionGroup>
322
- </PanelSection>
323
- </PanelWrapper>
324
- )
325
- }
@@ -1,273 +0,0 @@
1
- 'use client'
2
-
3
- import {
4
- type AnyNode,
5
- type AnyNodeId,
6
- getClampedWallCurveOffset,
7
- getEffectiveWallSurfaceMaterial,
8
- getMaxWallCurveOffset,
9
- getWallCurveLength,
10
- getWallSurfaceMaterialSignature,
11
- type MaterialSchema,
12
- normalizeWallCurveOffset,
13
- useScene,
14
- type WallNode,
15
- type WallSurfaceSide,
16
- } from '@pascal-app/core'
17
- import { useViewer } from '@pascal-app/viewer'
18
- import { Move, Spline } from 'lucide-react'
19
- import { useCallback, useMemo } from 'react'
20
- import { sfxEmitter } from '../../../lib/sfx-bus'
21
- import useEditor from '../../../store/use-editor'
22
- import { ActionButton, ActionGroup } from '../controls/action-button'
23
- import { MaterialPicker } from '../controls/material-picker'
24
- import { PanelSection } from '../controls/panel-section'
25
- import { SliderControl } from '../controls/slider-control'
26
- import { PanelWrapper } from './panel-wrapper'
27
-
28
- function buildWallSurfaceMaterialPatch(
29
- node: WallNode,
30
- targetSide: WallSurfaceSide | null,
31
- material: MaterialSchema | undefined,
32
- materialPreset: string | undefined,
33
- ): Partial<WallNode> {
34
- const nextSurfaceMaterial = { material, materialPreset }
35
- const nextInterior =
36
- targetSide === null || targetSide === 'interior'
37
- ? nextSurfaceMaterial
38
- : getEffectiveWallSurfaceMaterial(node, 'interior')
39
- const nextExterior =
40
- targetSide === null || targetSide === 'exterior'
41
- ? nextSurfaceMaterial
42
- : getEffectiveWallSurfaceMaterial(node, 'exterior')
43
-
44
- return {
45
- interiorMaterial: nextInterior.material,
46
- interiorMaterialPreset: nextInterior.materialPreset,
47
- exteriorMaterial: nextExterior.material,
48
- exteriorMaterialPreset: nextExterior.materialPreset,
49
- material: undefined,
50
- materialPreset: undefined,
51
- }
52
- }
53
-
54
- export function WallPanel() {
55
- const selectedId = useViewer((s) => s.selection.selectedIds[0])
56
- const setSelection = useViewer((s) => s.setSelection)
57
- const updateNode = useScene((s) => s.updateNode)
58
- const setMovingNode = useEditor((s) => s.setMovingNode)
59
- const setCurvingWall = useEditor((s) => s.setCurvingWall)
60
- const selectedMaterialTarget = useEditor((s) => s.selectedMaterialTarget)
61
-
62
- const node = useScene((s) =>
63
- selectedId ? (s.nodes[selectedId as AnyNode['id']] as WallNode | undefined) : undefined,
64
- )
65
-
66
- // Boolean selector — re-renders only when this specific wall's child
67
- // composition crosses the "has a door/window/wall-item" threshold.
68
- const hasWallChildrenBlockingCurve = useScene((s) => {
69
- if (!node) return false
70
- return (node.children ?? []).some((childId) => {
71
- const child = s.nodes[childId as AnyNodeId]
72
- if (!child) return false
73
- if (child.type === 'door' || child.type === 'window') return true
74
- if (child.type === 'item') {
75
- const attachTo = child.asset?.attachTo
76
- return attachTo === 'wall' || attachTo === 'wall-side'
77
- }
78
- return false
79
- })
80
- })
81
-
82
- const handleUpdate = useCallback(
83
- (updates: Partial<WallNode>) => {
84
- if (!selectedId) return
85
- updateNode(selectedId as AnyNode['id'], updates)
86
- useScene.getState().dirtyNodes.add(selectedId as AnyNodeId)
87
- },
88
- [selectedId, updateNode],
89
- )
90
-
91
- const effectiveInteriorMaterial = useMemo(
92
- () => (node ? getEffectiveWallSurfaceMaterial(node, 'interior') : {}),
93
- [node],
94
- )
95
- const effectiveExteriorMaterial = useMemo(
96
- () => (node ? getEffectiveWallSurfaceMaterial(node, 'exterior') : {}),
97
- [node],
98
- )
99
- const surfaceMaterialsMatch = useMemo(
100
- () =>
101
- getWallSurfaceMaterialSignature(effectiveInteriorMaterial) ===
102
- getWallSurfaceMaterialSignature(effectiveExteriorMaterial),
103
- [effectiveExteriorMaterial, effectiveInteriorMaterial],
104
- )
105
- const materialTargetSide =
106
- selectedMaterialTarget &&
107
- selectedMaterialTarget.nodeId === node?.id &&
108
- (selectedMaterialTarget.role === 'interior' || selectedMaterialTarget.role === 'exterior')
109
- ? selectedMaterialTarget.role
110
- : null
111
- const materialPickerValue =
112
- materialTargetSide === 'interior'
113
- ? effectiveInteriorMaterial
114
- : materialTargetSide === 'exterior'
115
- ? effectiveExteriorMaterial
116
- : surfaceMaterialsMatch
117
- ? effectiveInteriorMaterial
118
- : {}
119
-
120
- const handleUpdateLength = useCallback(
121
- (newLength: number) => {
122
- if (!node || newLength <= 0) return
123
-
124
- const dx = node.end[0] - node.start[0]
125
- const dz = node.end[1] - node.start[1]
126
- const currentLength = Math.sqrt(dx * dx + dz * dz)
127
-
128
- if (currentLength === 0) return
129
-
130
- const dirX = dx / currentLength
131
- const dirZ = dz / currentLength
132
-
133
- const newEnd: [number, number] = [
134
- node.start[0] + dirX * newLength,
135
- node.start[1] + dirZ * newLength,
136
- ]
137
-
138
- handleUpdate({ end: newEnd })
139
- },
140
- [node, handleUpdate],
141
- )
142
-
143
- const handleMaterialPresetChange = useCallback(
144
- (materialPreset: string) => {
145
- if (!(node && materialTargetSide)) return
146
- handleUpdate(
147
- buildWallSurfaceMaterialPatch(node, materialTargetSide, undefined, materialPreset),
148
- )
149
- },
150
- [handleUpdate, materialTargetSide, node],
151
- )
152
-
153
- const handleCustomMaterialChange = useCallback(
154
- (material: MaterialSchema) => {
155
- if (!(node && materialTargetSide)) return
156
- handleUpdate(buildWallSurfaceMaterialPatch(node, materialTargetSide, material, undefined))
157
- },
158
- [handleUpdate, materialTargetSide, node],
159
- )
160
-
161
- const handleClose = useCallback(() => {
162
- setSelection({ selectedIds: [] })
163
- }, [setSelection])
164
-
165
- const handleMove = useCallback(() => {
166
- if (!node) return
167
- sfxEmitter.emit('sfx:item-pick')
168
- setMovingNode(node)
169
- setSelection({ selectedIds: [] })
170
- }, [node, setMovingNode, setSelection])
171
-
172
- const handleCurve = useCallback(() => {
173
- if (!node) return
174
- sfxEmitter.emit('sfx:item-pick')
175
- setCurvingWall(node)
176
- setSelection({ selectedIds: [] })
177
- }, [node, setCurvingWall, setSelection])
178
-
179
- if (!(node && node.type === 'wall' && selectedId)) return null
180
-
181
- const dx = node.end[0] - node.start[0]
182
- const dz = node.end[1] - node.start[1]
183
- const length = getWallCurveLength(node)
184
-
185
- const height = node.height ?? 2.5
186
- const thickness = node.thickness ?? 0.1
187
- const curveOffset = getClampedWallCurveOffset(node)
188
- const maxCurveOffset = getMaxWallCurveOffset(node)
189
-
190
- return (
191
- <PanelWrapper
192
- icon="/icons/wall.png"
193
- onClose={handleClose}
194
- title={node.name || 'Wall'}
195
- width={280}
196
- >
197
- <PanelSection title="Dimensions">
198
- <SliderControl
199
- label="Length"
200
- max={20}
201
- min={0.1}
202
- onChange={handleUpdateLength}
203
- precision={2}
204
- step={0.01}
205
- unit="m"
206
- value={length}
207
- />
208
- <SliderControl
209
- label="Height"
210
- max={6}
211
- min={0.1}
212
- onChange={(v) => handleUpdate({ height: Math.max(0.1, v) })}
213
- precision={2}
214
- step={0.1}
215
- unit="m"
216
- value={Math.round(height * 100) / 100}
217
- />
218
- <SliderControl
219
- label="Thickness"
220
- max={1}
221
- min={0.05}
222
- onChange={(v) => handleUpdate({ thickness: Math.max(0.05, v) })}
223
- precision={3}
224
- step={0.01}
225
- unit="m"
226
- value={Math.round(thickness * 1000) / 1000}
227
- />
228
- {!hasWallChildrenBlockingCurve && (
229
- <SliderControl
230
- label="Curve"
231
- max={Math.max(0.01, maxCurveOffset)}
232
- min={-Math.max(0.01, maxCurveOffset)}
233
- onChange={(v) => handleUpdate({ curveOffset: normalizeWallCurveOffset(node, v) })}
234
- precision={2}
235
- step={0.1}
236
- unit="m"
237
- value={Math.round(curveOffset * 100) / 100}
238
- />
239
- )}
240
- </PanelSection>
241
-
242
- <PanelSection title="Material">
243
- {materialTargetSide ? null : (
244
- <div className="mb-3 rounded-lg border border-border/50 bg-[#2C2C2E] px-3 py-2 text-[11px] text-muted-foreground">
245
- Click the wall face you want to edit. Materials now apply to one side at a time.
246
- </div>
247
- )}
248
- <MaterialPicker
249
- disabled={!materialTargetSide}
250
- hideSideControl
251
- nodeType="wall"
252
- onChange={handleCustomMaterialChange}
253
- onSelectMaterialPreset={handleMaterialPresetChange}
254
- selectedMaterialPreset={materialPickerValue.materialPreset}
255
- value={materialPickerValue.material}
256
- />
257
- </PanelSection>
258
-
259
- <PanelSection title="Actions">
260
- <ActionGroup>
261
- <ActionButton icon={<Move className="h-3.5 w-3.5" />} label="Move" onClick={handleMove} />
262
- {!hasWallChildrenBlockingCurve && (
263
- <ActionButton
264
- icon={<Spline className="h-3.5 w-3.5" />}
265
- label="Curve"
266
- onClick={handleCurve}
267
- />
268
- )}
269
- </ActionGroup>
270
- </PanelSection>
271
- </PanelWrapper>
272
- )
273
- }