@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
@@ -0,0 +1,161 @@
1
+ import { describe, expect, test } from 'bun:test'
2
+ import {
3
+ convexHull2D,
4
+ type Point2,
5
+ polygonsIntersect,
6
+ rectIntersectsHull,
7
+ type ScreenRect,
8
+ segmentIntersectsPolygon,
9
+ } from './marquee-geometry'
10
+
11
+ const rect = (minX: number, minY: number, maxX: number, maxY: number): ScreenRect => ({
12
+ minX,
13
+ minY,
14
+ maxX,
15
+ maxY,
16
+ })
17
+
18
+ describe('convexHull2D', () => {
19
+ test('drops interior points and keeps the hull', () => {
20
+ const hull = convexHull2D([
21
+ [0, 0],
22
+ [4, 0],
23
+ [4, 4],
24
+ [0, 4],
25
+ [2, 2],
26
+ [1, 3],
27
+ ])
28
+ expect(hull).toHaveLength(4)
29
+ const set = new Set(hull.map((p) => p.join(',')))
30
+ expect(set).toEqual(new Set(['0,0', '4,0', '4,4', '0,4']))
31
+ })
32
+
33
+ test('passes degenerate inputs through', () => {
34
+ expect(convexHull2D([])).toEqual([])
35
+ expect(convexHull2D([[1, 2]])).toEqual([[1, 2]])
36
+ expect(
37
+ convexHull2D([
38
+ [0, 0],
39
+ [2, 2],
40
+ ]),
41
+ ).toHaveLength(2)
42
+ })
43
+ })
44
+
45
+ describe('rectIntersectsHull', () => {
46
+ // The regression case: a thin diagonal wall. Its world AABB spans the full
47
+ // square, so the old AABB test matched a marquee sitting in the empty
48
+ // corner; the hull test must not.
49
+ const diagonalWall: Point2[] = convexHull2D([
50
+ [0, 0],
51
+ [1, 0.6],
52
+ [10, 9.4],
53
+ [10, 10],
54
+ [9, 9.4],
55
+ [0, 0.6],
56
+ ])
57
+
58
+ test('marquee in the empty corner of a diagonal shape does not match', () => {
59
+ expect(rectIntersectsHull(rect(7, 0, 9, 2), diagonalWall)).toBe(false)
60
+ expect(rectIntersectsHull(rect(0, 7, 2, 9), diagonalWall)).toBe(false)
61
+ })
62
+
63
+ test('marquee crossing the diagonal matches', () => {
64
+ expect(rectIntersectsHull(rect(4, 4, 6, 6), diagonalWall)).toBe(true)
65
+ })
66
+
67
+ test('hull vertex inside the marquee matches', () => {
68
+ expect(rectIntersectsHull(rect(-1, -1, 0.5, 0.5), diagonalWall)).toBe(true)
69
+ })
70
+
71
+ test('marquee fully inside a large hull matches', () => {
72
+ const square: Point2[] = [
73
+ [0, 0],
74
+ [10, 0],
75
+ [10, 10],
76
+ [0, 10],
77
+ ]
78
+ expect(rectIntersectsHull(rect(4, 4, 5, 5), square)).toBe(true)
79
+ })
80
+
81
+ test('edge-only crossing (no vertices contained either way) matches', () => {
82
+ // Tall thin rect crossing a wide thin hull like a plus sign.
83
+ const bar: Point2[] = [
84
+ [0, 4],
85
+ [10, 4],
86
+ [10, 6],
87
+ [0, 6],
88
+ ]
89
+ expect(rectIntersectsHull(rect(4, 0, 6, 10), bar)).toBe(true)
90
+ })
91
+
92
+ test('disjoint shapes do not match', () => {
93
+ const tri: Point2[] = [
94
+ [0, 0],
95
+ [2, 0],
96
+ [1, 2],
97
+ ]
98
+ expect(rectIntersectsHull(rect(5, 5, 7, 7), tri)).toBe(false)
99
+ })
100
+
101
+ test('single projected point matches only when inside the rect', () => {
102
+ expect(rectIntersectsHull(rect(0, 0, 2, 2), [[1, 1]])).toBe(true)
103
+ expect(rectIntersectsHull(rect(0, 0, 2, 2), [[3, 3]])).toBe(false)
104
+ })
105
+ })
106
+
107
+ describe('segmentIntersectsPolygon', () => {
108
+ const quad: Point2[] = [
109
+ [0, 0],
110
+ [4, 0],
111
+ [4, 4],
112
+ [0, 4],
113
+ ]
114
+ test('crossing segment matches', () => {
115
+ expect(segmentIntersectsPolygon([-1, 2], [5, 2], quad)).toBe(true)
116
+ })
117
+ test('fully inside matches', () => {
118
+ expect(segmentIntersectsPolygon([1, 1], [2, 2], quad)).toBe(true)
119
+ })
120
+ test('outside segment does not match', () => {
121
+ expect(segmentIntersectsPolygon([5, 5], [7, 8], quad)).toBe(false)
122
+ })
123
+ })
124
+
125
+ describe('polygonsIntersect', () => {
126
+ const quad: Point2[] = [
127
+ [0, 0],
128
+ [4, 0],
129
+ [4, 4],
130
+ [0, 4],
131
+ ]
132
+ test('overlapping polygons match', () => {
133
+ expect(
134
+ polygonsIntersect(quad, [
135
+ [3, 3],
136
+ [6, 3],
137
+ [6, 6],
138
+ [3, 6],
139
+ ]),
140
+ ).toBe(true)
141
+ })
142
+ test('containment matches both ways', () => {
143
+ const inner: Point2[] = [
144
+ [1, 1],
145
+ [2, 1],
146
+ [2, 2],
147
+ ]
148
+ expect(polygonsIntersect(quad, inner)).toBe(true)
149
+ expect(polygonsIntersect(inner, quad)).toBe(true)
150
+ })
151
+ test('a rotated diamond beside the quad does not match', () => {
152
+ expect(
153
+ polygonsIntersect(quad, [
154
+ [7, 2],
155
+ [9, 0],
156
+ [11, 2],
157
+ [9, 4],
158
+ ]),
159
+ ).toBe(false)
160
+ })
161
+ })
@@ -0,0 +1,155 @@
1
+ // Pure 2D geometry for the screen-rect marquee's membership test. The
2
+ // marquee intersects each node's ORIENTED bounding box projected to screen —
3
+ // a convex hull — instead of a screen-space AABB of the world AABB, whose
4
+ // double inflation (world AABB around rotated geometry, then a 2D AABB
5
+ // around its projection) selected objects visually far from the cursor.
6
+
7
+ export type ScreenRect = {
8
+ minX: number
9
+ minY: number
10
+ maxX: number
11
+ maxY: number
12
+ }
13
+
14
+ export type Point2 = [number, number]
15
+
16
+ function cross(o: Point2, a: Point2, b: Point2): number {
17
+ return (a[0] - o[0]) * (b[1] - o[1]) - (a[1] - o[1]) * (b[0] - o[0])
18
+ }
19
+
20
+ /** Andrew monotone-chain convex hull. Returns CCW hull without the closing
21
+ * point; degenerate inputs (0–2 points, collinear sets) pass through. */
22
+ export function convexHull2D(points: readonly Point2[]): Point2[] {
23
+ if (points.length <= 2) return [...points]
24
+ const sorted = [...points].sort((a, b) => a[0] - b[0] || a[1] - b[1])
25
+ const lower: Point2[] = []
26
+ for (const p of sorted) {
27
+ while (lower.length >= 2 && cross(lower[lower.length - 2]!, lower[lower.length - 1]!, p) <= 0) {
28
+ lower.pop()
29
+ }
30
+ lower.push(p)
31
+ }
32
+ const upper: Point2[] = []
33
+ for (let i = sorted.length - 1; i >= 0; i--) {
34
+ const p = sorted[i]!
35
+ while (upper.length >= 2 && cross(upper[upper.length - 2]!, upper[upper.length - 1]!, p) <= 0) {
36
+ upper.pop()
37
+ }
38
+ upper.push(p)
39
+ }
40
+ lower.pop()
41
+ upper.pop()
42
+ const hull = [...lower, ...upper]
43
+ return hull.length > 0 ? hull : [sorted[0]!]
44
+ }
45
+
46
+ function pointInRect(p: Point2, rect: ScreenRect): boolean {
47
+ return p[0] >= rect.minX && p[0] <= rect.maxX && p[1] >= rect.minY && p[1] <= rect.maxY
48
+ }
49
+
50
+ /** Ray-crossing point-in-polygon — works for convex and degenerate hulls. */
51
+ function pointInPolygon(p: Point2, polygon: readonly Point2[]): boolean {
52
+ let inside = false
53
+ for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
54
+ const [xi, yi] = polygon[i]!
55
+ const [xj, yj] = polygon[j]!
56
+ if (yi > p[1] !== yj > p[1] && p[0] < ((xj - xi) * (p[1] - yi)) / (yj - yi) + xi) {
57
+ inside = !inside
58
+ }
59
+ }
60
+ return inside
61
+ }
62
+
63
+ function orientation(a: Point2, b: Point2, c: Point2): number {
64
+ const v = cross(a, b, c)
65
+ if (v > 0) return 1
66
+ if (v < 0) return -1
67
+ return 0
68
+ }
69
+
70
+ function onSegment(a: Point2, b: Point2, p: Point2): boolean {
71
+ return (
72
+ Math.min(a[0], b[0]) <= p[0] &&
73
+ p[0] <= Math.max(a[0], b[0]) &&
74
+ Math.min(a[1], b[1]) <= p[1] &&
75
+ p[1] <= Math.max(a[1], b[1])
76
+ )
77
+ }
78
+
79
+ function segmentsIntersect(a1: Point2, a2: Point2, b1: Point2, b2: Point2): boolean {
80
+ const o1 = orientation(a1, a2, b1)
81
+ const o2 = orientation(a1, a2, b2)
82
+ const o3 = orientation(b1, b2, a1)
83
+ const o4 = orientation(b1, b2, a2)
84
+ if (o1 !== o2 && o3 !== o4) return true
85
+ if (o1 === 0 && onSegment(a1, a2, b1)) return true
86
+ if (o2 === 0 && onSegment(a1, a2, b2)) return true
87
+ if (o3 === 0 && onSegment(b1, b2, a1)) return true
88
+ if (o4 === 0 && onSegment(b1, b2, a2)) return true
89
+ return false
90
+ }
91
+
92
+ /** Segment vs polygon (general, possibly concave): endpoint containment or
93
+ * any edge crossing. */
94
+ export function segmentIntersectsPolygon(
95
+ a: Point2,
96
+ b: Point2,
97
+ polygon: readonly Point2[],
98
+ ): boolean {
99
+ if (polygon.length === 0) return false
100
+ if (polygon.length === 1) return false
101
+ if (polygon.length >= 3 && (pointInPolygon(a, polygon) || pointInPolygon(b, polygon))) return true
102
+ for (let i = 0; i < polygon.length; i++) {
103
+ if (segmentsIntersect(a, b, polygon[i]!, polygon[(i + 1) % polygon.length]!)) return true
104
+ }
105
+ return false
106
+ }
107
+
108
+ /** Polygon vs polygon (general): containment either way or any edge crossing. */
109
+ export function polygonsIntersect(a: readonly Point2[], b: readonly Point2[]): boolean {
110
+ if (a.length === 0 || b.length === 0) return false
111
+ if (a.length >= 3 && b.some((p) => pointInPolygon(p, a))) return true
112
+ if (b.length >= 3 && a.some((p) => pointInPolygon(p, b))) return true
113
+ for (let i = 0; i < a.length; i++) {
114
+ const a1 = a[i]!
115
+ const a2 = a[(i + 1) % a.length]!
116
+ for (let j = 0; j < b.length; j++) {
117
+ if (segmentsIntersect(a1, a2, b[j]!, b[(j + 1) % b.length]!)) return true
118
+ }
119
+ }
120
+ return false
121
+ }
122
+
123
+ /**
124
+ * Does the axis-aligned marquee rect intersect the (convex) hull polygon?
125
+ * Covers all cases: hull vertex inside the rect, rect fully inside the hull,
126
+ * and pure edge crossings.
127
+ */
128
+ export function rectIntersectsHull(rect: ScreenRect, hull: readonly Point2[]): boolean {
129
+ if (hull.length === 0) return false
130
+ for (const p of hull) {
131
+ if (pointInRect(p, rect)) return true
132
+ }
133
+ if (hull.length === 1) return false
134
+ const rectCorners: Point2[] = [
135
+ [rect.minX, rect.minY],
136
+ [rect.maxX, rect.minY],
137
+ [rect.maxX, rect.maxY],
138
+ [rect.minX, rect.maxY],
139
+ ]
140
+ if (hull.length >= 3) {
141
+ for (const c of rectCorners) {
142
+ if (pointInPolygon(c, hull)) return true
143
+ }
144
+ }
145
+ for (let i = 0; i < hull.length; i++) {
146
+ const h1 = hull[i]!
147
+ const h2 = hull[(i + 1) % hull.length]!
148
+ for (let j = 0; j < 4; j++) {
149
+ const r1 = rectCorners[j]!
150
+ const r2 = rectCorners[(j + 1) % 4]!
151
+ if (segmentsIntersect(h1, h2, r1, r2)) return true
152
+ }
153
+ }
154
+ return false
155
+ }