@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,125 +0,0 @@
1
- 'use client'
2
-
3
- import { emitter, sceneRegistry } from '@pascal-app/core'
4
- import { useThree } from '@react-three/fiber'
5
- import { useCallback, useEffect } from 'react'
6
- import * as THREE from 'three'
7
- import { usePresetsAdapter } from '../../contexts/presets-context'
8
-
9
- const THUMBNAIL_SIZE = 1080
10
- const CAMERA_FOV = 45
11
-
12
- export const PresetThumbnailGenerator = () => {
13
- const gl = useThree((state) => state.gl)
14
- const scene = useThree((state) => state.scene)
15
- const adapter = usePresetsAdapter()
16
-
17
- const generate = useCallback(
18
- async ({ presetId, nodeId }: { presetId: string; nodeId: string }) => {
19
- const target = sceneRegistry.nodes.get(nodeId)
20
- if (!target) {
21
- console.error('❌ PresetThumbnail: node not found', nodeId)
22
- return
23
- }
24
-
25
- // Compute each mesh's transform relative to the target node (cancels world
26
- // position/rotation), so the item is always rendered at origin with a known
27
- // neutral orientation regardless of where it's placed in the scene.
28
- target.updateWorldMatrix(true, true)
29
- const targetInverse = new THREE.Matrix4().copy(target.matrixWorld).invert()
30
- const relMatrix = new THREE.Matrix4()
31
-
32
- const clones: THREE.Object3D[] = []
33
- target.traverse((obj) => {
34
- if (
35
- !(obj instanceof THREE.Mesh || obj instanceof THREE.Line || obj instanceof THREE.Points)
36
- )
37
- return
38
- const c = obj.clone(false) // shallow clone: copies geometry, material, visible — no children
39
- relMatrix.multiplyMatrices(targetInverse, obj.matrixWorld)
40
- relMatrix.decompose(c.position, c.quaternion, c.scale)
41
- scene.add(c)
42
- clones.push(c)
43
- })
44
-
45
- if (clones.length === 0) {
46
- console.error('❌ PresetThumbnail: no renderable objects found', nodeId)
47
- return
48
- }
49
-
50
- // Combined bounding box across all clones
51
- const box = new THREE.Box3()
52
- for (const c of clones) box.expandByObject(c)
53
-
54
- if (box.isEmpty()) {
55
- for (const c of clones) scene.remove(c)
56
- console.error('❌ PresetThumbnail: empty bounding box', nodeId)
57
- return
58
- }
59
-
60
- const sphere = new THREE.Sphere()
61
- box.getBoundingSphere(sphere)
62
-
63
- // Camera: aspect matches canvas (center-cropped to square after render)
64
- const { width, height } = gl.domElement
65
- const camera = new THREE.PerspectiveCamera(CAMERA_FOV, width / height, 0.01, 1000)
66
- const dir = new THREE.Vector3(-0.5, 0.5, 0.5).normalize()
67
- const fovRad = (CAMERA_FOV * Math.PI) / 180
68
- const dist = (sphere.radius / Math.tan(fovRad / 2)) * 1.3
69
- camera.position.copy(sphere.center).addScaledVector(dir, dist)
70
- camera.lookAt(sphere.center)
71
- camera.updateProjectionMatrix()
72
-
73
- // Hide all scene geometry except the clones — leave lights, cameras, etc. intact
74
- const cloneSet = new Set<THREE.Object3D>(clones)
75
- const snapshot = new Map<THREE.Object3D, boolean>()
76
- scene.traverse((obj) => {
77
- if (cloneSet.has(obj)) return
78
- if (
79
- !(obj instanceof THREE.Mesh || obj instanceof THREE.Line || obj instanceof THREE.Points)
80
- )
81
- return
82
- snapshot.set(obj, obj.visible)
83
- obj.visible = false
84
- })
85
-
86
- gl.render(scene, camera)
87
-
88
- // Restore visibility and remove clones
89
- snapshot.forEach((wasVisible, obj) => {
90
- obj.visible = wasVisible
91
- })
92
- for (const c of clones) scene.remove(c)
93
-
94
- // Center-crop to square and scale to THUMBNAIL_SIZE
95
- const minDim = Math.min(width, height)
96
- const sx = Math.round((width - minDim) / 2)
97
- const sy = Math.round((height - minDim) / 2)
98
- const offscreen = document.createElement('canvas')
99
- offscreen.width = THUMBNAIL_SIZE
100
- offscreen.height = THUMBNAIL_SIZE
101
- const ctx = offscreen.getContext('2d')!
102
- ctx.drawImage(gl.domElement, sx, sy, minDim, minDim, 0, 0, THUMBNAIL_SIZE, THUMBNAIL_SIZE)
103
-
104
- offscreen.toBlob(async (blob) => {
105
- if (!blob) {
106
- console.error('❌ PresetThumbnail: failed to create blob')
107
- return
108
- }
109
- if (!adapter.uploadPresetThumbnail) return
110
- const thumbnailUrl = await adapter.uploadPresetThumbnail(presetId, blob)
111
- if (thumbnailUrl) {
112
- emitter.emit('preset:thumbnail-updated', { presetId, thumbnailUrl })
113
- }
114
- }, 'image/png')
115
- },
116
- [gl, scene, adapter],
117
- )
118
-
119
- useEffect(() => {
120
- emitter.on('preset:generate-thumbnail', generate)
121
- return () => emitter.off('preset:generate-thumbnail', generate)
122
- }, [generate])
123
-
124
- return null
125
- }
@@ -1,113 +0,0 @@
1
- 'use client'
2
-
3
- import type { Point2D, RoofNode, RoofSegmentNode } from '@pascal-app/core'
4
- import { memo } from 'react'
5
- import { toSvgX, toSvgY } from '../svg-paths'
6
-
7
- type FloorplanLineSegment = {
8
- start: Point2D
9
- end: Point2D
10
- }
11
-
12
- type FloorplanRoofSegmentEntry = {
13
- segment: RoofSegmentNode
14
- points: string
15
- ridgeLine: FloorplanLineSegment | null
16
- }
17
-
18
- type FloorplanRoofEntry = {
19
- roof: RoofNode
20
- segments: FloorplanRoofSegmentEntry[]
21
- }
22
-
23
- type FloorplanRoofPalette = {
24
- roofFill: string
25
- roofActiveFill: string
26
- roofSelectedFill: string
27
- roofStroke: string
28
- roofActiveStroke: string
29
- roofSelectedStroke: string
30
- roofRidgeStroke: string
31
- roofSelectedRidgeStroke: string
32
- }
33
-
34
- type FloorplanRoofLayerProps = {
35
- highlightedIdSet: ReadonlySet<string>
36
- palette: FloorplanRoofPalette
37
- roofEntries: FloorplanRoofEntry[]
38
- selectedIdSet: ReadonlySet<string>
39
- }
40
-
41
- export const FloorplanRoofLayer = memo(function FloorplanRoofLayer({
42
- highlightedIdSet,
43
- palette,
44
- roofEntries,
45
- selectedIdSet,
46
- }: FloorplanRoofLayerProps) {
47
- if (roofEntries.length === 0) {
48
- return null
49
- }
50
-
51
- return (
52
- <>
53
- {roofEntries.map(({ roof, segments }) => {
54
- const roofSelected = selectedIdSet.has(roof.id)
55
- const roofHighlighted = highlightedIdSet.has(roof.id)
56
- const hasSelectedSegment = segments.some(({ segment }) => selectedIdSet.has(segment.id))
57
- const hasHighlightedSegment = segments.some(({ segment }) =>
58
- highlightedIdSet.has(segment.id),
59
- )
60
- const isRoofActive =
61
- roofSelected || roofHighlighted || hasSelectedSegment || hasHighlightedSegment
62
-
63
- return (
64
- <g key={roof.id} pointerEvents="none">
65
- {segments.map(({ points, ridgeLine, segment }) => {
66
- const isSegmentSelected = selectedIdSet.has(segment.id)
67
- const isSegmentHighlighted = highlightedIdSet.has(segment.id)
68
- const isSegmentActive = isSegmentSelected || isSegmentHighlighted
69
-
70
- return (
71
- <g key={segment.id}>
72
- <polygon
73
- fill={
74
- isSegmentActive
75
- ? palette.roofSelectedFill
76
- : isRoofActive
77
- ? palette.roofActiveFill
78
- : palette.roofFill
79
- }
80
- points={points}
81
- stroke={
82
- isSegmentActive
83
- ? palette.roofSelectedStroke
84
- : isRoofActive
85
- ? palette.roofActiveStroke
86
- : palette.roofStroke
87
- }
88
- strokeWidth={isSegmentActive ? '2.25' : isRoofActive ? '1.75' : '1.1'}
89
- vectorEffect="non-scaling-stroke"
90
- />
91
- {ridgeLine ? (
92
- <line
93
- fill="none"
94
- stroke={
95
- isSegmentActive ? palette.roofSelectedRidgeStroke : palette.roofRidgeStroke
96
- }
97
- strokeWidth={isSegmentActive ? '2' : '1.4'}
98
- vectorEffect="non-scaling-stroke"
99
- x1={toSvgX(ridgeLine.start.x)}
100
- x2={toSvgX(ridgeLine.end.x)}
101
- y1={toSvgY(ridgeLine.start.y)}
102
- y2={toSvgY(ridgeLine.end.y)}
103
- />
104
- ) : null}
105
- </g>
106
- )
107
- })}
108
- </g>
109
- )
110
- })}
111
- </>
112
- )
113
- })
@@ -1,157 +0,0 @@
1
- 'use client'
2
-
3
- import {
4
- type BuildingNode,
5
- emitter,
6
- type GridEvent,
7
- sceneRegistry,
8
- useScene,
9
- } from '@pascal-app/core'
10
- import { useViewer } from '@pascal-app/viewer'
11
- import { useFrame } from '@react-three/fiber'
12
- import { useCallback, useEffect, useRef, useState } from 'react'
13
- import * as THREE from 'three'
14
- import { markToolCancelConsumed } from '../../../hooks/use-keyboard'
15
- import { sfxEmitter } from '../../../lib/sfx-bus'
16
- import useEditor from '../../../store/use-editor'
17
- import { CursorSphere } from '../shared/cursor-sphere'
18
-
19
- export function MoveBuildingContent({ node }: { node: BuildingNode }) {
20
- const previousGridPosRef = useRef<[number, number] | null>(null)
21
-
22
- // Stable refs so the effect never needs node in its dependency array
23
- const nodeIdRef = useRef(node.id)
24
- const originalPositionRef = useRef<[number, number, number]>([...node.position] as [
25
- number,
26
- number,
27
- number,
28
- ])
29
- const originalRotationRef = useRef<number>(node.rotation[1] ?? 0)
30
- const pendingRotationRef = useRef<number>(node.rotation[1] ?? 0)
31
-
32
- const [cursorWorldPos, setCursorWorldPos] = useState<[number, number, number]>(() => {
33
- const obj = sceneRegistry.nodes.get(node.id)
34
- if (obj) {
35
- const pos = new THREE.Vector3()
36
- obj.getWorldPosition(pos)
37
- return [pos.x, pos.y, pos.z]
38
- }
39
- return [node.position[0], node.position[1], node.position[2]]
40
- })
41
-
42
- const exitMoveMode = useCallback(() => {
43
- useEditor.getState().setMovingNode(null)
44
- }, [])
45
-
46
- useEffect(() => {
47
- const nodeId = nodeIdRef.current
48
- const originalPosition = originalPositionRef.current
49
-
50
- useScene.temporal.getState().pause()
51
-
52
- let wasCommitted = false
53
-
54
- const onKeyDown = (event: KeyboardEvent) => {
55
- if (event.target instanceof HTMLInputElement || event.target instanceof HTMLTextAreaElement) {
56
- return
57
- }
58
-
59
- const ROTATION_STEP = Math.PI / 2
60
- let rotationDelta = 0
61
- if (event.key === 'r' || event.key === 'R') rotationDelta = ROTATION_STEP
62
- else if (event.key === 't' || event.key === 'T') rotationDelta = -ROTATION_STEP
63
-
64
- if (rotationDelta !== 0) {
65
- event.preventDefault()
66
- sfxEmitter.emit('sfx:item-rotate')
67
- pendingRotationRef.current += rotationDelta
68
-
69
- const mesh = sceneRegistry.nodes.get(nodeId)
70
- if (mesh) mesh.rotation.y = pendingRotationRef.current
71
- }
72
- }
73
-
74
- const onGridMove = (event: GridEvent) => {
75
- const gridX = Math.round(event.position[0] * 2) / 2
76
- const gridZ = Math.round(event.position[2] * 2) / 2
77
-
78
- if (
79
- previousGridPosRef.current &&
80
- (gridX !== previousGridPosRef.current[0] || gridZ !== previousGridPosRef.current[1])
81
- ) {
82
- sfxEmitter.emit('sfx:grid-snap')
83
- }
84
-
85
- previousGridPosRef.current = [gridX, gridZ]
86
- setCursorWorldPos([gridX, 0, gridZ])
87
-
88
- // Directly update the Three.js group — no store update during drag
89
- const mesh = sceneRegistry.nodes.get(nodeId)
90
- if (mesh) {
91
- mesh.position.x = gridX
92
- mesh.position.z = gridZ
93
- }
94
- }
95
-
96
- const onGridClick = (event: GridEvent) => {
97
- const gridX = Math.round(event.position[0] * 2) / 2
98
- const gridZ = Math.round(event.position[2] * 2) / 2
99
-
100
- wasCommitted = true
101
-
102
- useScene.temporal.getState().resume()
103
- useScene.getState().updateNode(nodeId, {
104
- position: [gridX, originalPosition[1], gridZ],
105
- rotation: [0, pendingRotationRef.current, 0],
106
- })
107
- useScene.temporal.getState().pause()
108
-
109
- sfxEmitter.emit('sfx:item-place')
110
- useViewer.getState().setSelection({ buildingId: nodeId as BuildingNode['id'] })
111
- exitMoveMode()
112
- event.nativeEvent?.stopPropagation?.()
113
- }
114
-
115
- const onCancel = () => {
116
- // Revert mesh position and rotation immediately
117
- const mesh = sceneRegistry.nodes.get(nodeId)
118
- if (mesh) {
119
- mesh.position.x = originalPosition[0]
120
- mesh.position.z = originalPosition[2]
121
- mesh.rotation.y = originalRotationRef.current
122
- }
123
- pendingRotationRef.current = originalRotationRef.current
124
- // Restore building selection
125
- useViewer.getState().setSelection({ buildingId: nodeId as BuildingNode['id'] })
126
- useScene.temporal.getState().resume()
127
- // Tell the keyboard handler we handled this, so it doesn't also clear the selection
128
- markToolCancelConsumed()
129
- exitMoveMode()
130
- }
131
-
132
- emitter.on('grid:move', onGridMove)
133
- emitter.on('grid:click', onGridClick)
134
- emitter.on('tool:cancel', onCancel)
135
- window.addEventListener('keydown', onKeyDown)
136
-
137
- return () => {
138
- if (!wasCommitted) {
139
- useScene.getState().updateNode(nodeId, {
140
- position: originalPosition,
141
- rotation: [0, originalRotationRef.current, 0],
142
- })
143
- }
144
- useScene.temporal.getState().resume()
145
- emitter.off('grid:move', onGridMove)
146
- emitter.off('grid:click', onGridClick)
147
- emitter.off('tool:cancel', onCancel)
148
- window.removeEventListener('keydown', onKeyDown)
149
- }
150
- }, [exitMoveMode]) // stable — node values captured via refs at mount
151
-
152
- return (
153
- <group>
154
- <CursorSphere position={cursorWorldPos} showTooltip={false} />
155
- </group>
156
- )
157
- }
@@ -1,43 +0,0 @@
1
- import { type CeilingNode, resolveLevelId, useScene } from '@pascal-app/core'
2
- import { useViewer } from '@pascal-app/viewer'
3
- import { useCallback } from 'react'
4
- import { PolygonEditor } from '../shared/polygon-editor'
5
-
6
- interface CeilingBoundaryEditorProps {
7
- ceilingId: CeilingNode['id']
8
- }
9
-
10
- /**
11
- * Ceiling boundary editor - allows editing ceiling polygon vertices for a specific ceiling
12
- * Uses the generic PolygonEditor component
13
- */
14
- export const CeilingBoundaryEditor: React.FC<CeilingBoundaryEditorProps> = ({ ceilingId }) => {
15
- const ceilingNode = useScene((state) => state.nodes[ceilingId])
16
- const updateNode = useScene((state) => state.updateNode)
17
- const setSelection = useViewer((state) => state.setSelection)
18
-
19
- const ceiling = ceilingNode?.type === 'ceiling' ? (ceilingNode as CeilingNode) : null
20
-
21
- const handlePolygonChange = useCallback(
22
- (newPolygon: Array<[number, number]>) => {
23
- updateNode(ceilingId, { polygon: newPolygon })
24
- // Re-assert selection so the ceiling stays selected after the edit
25
- setSelection({ selectedIds: [ceilingId] })
26
- },
27
- [ceilingId, updateNode, setSelection],
28
- )
29
-
30
- if (!ceiling?.polygon || ceiling.polygon.length < 3) return null
31
-
32
- return (
33
- <PolygonEditor
34
- allowEdgeMove
35
- color="#d4d4d4"
36
- levelId={resolveLevelId(ceiling, useScene.getState().nodes)}
37
- minVertices={3}
38
- onPolygonChange={handlePolygonChange}
39
- polygon={ceiling.polygon}
40
- surfaceHeight={ceiling.height ?? 2.5}
41
- />
42
- )
43
- }
@@ -1,49 +0,0 @@
1
- import { type CeilingNode, resolveLevelId, useScene } from '@pascal-app/core'
2
- import { useViewer } from '@pascal-app/viewer'
3
- import { useCallback } from 'react'
4
- import { PolygonEditor } from '../shared/polygon-editor'
5
-
6
- interface CeilingHoleEditorProps {
7
- ceilingId: CeilingNode['id']
8
- holeIndex: number
9
- }
10
-
11
- /**
12
- * Ceiling hole editor - allows editing a specific hole polygon within a ceiling
13
- * Uses the generic PolygonEditor component
14
- */
15
- export const CeilingHoleEditor: React.FC<CeilingHoleEditorProps> = ({ ceilingId, holeIndex }) => {
16
- const ceilingNode = useScene((state) => state.nodes[ceilingId])
17
- const updateNode = useScene((state) => state.updateNode)
18
- const setSelection = useViewer((state) => state.setSelection)
19
-
20
- const ceiling = ceilingNode?.type === 'ceiling' ? (ceilingNode as CeilingNode) : null
21
- const holes = ceiling?.holes || []
22
- const hole = holes[holeIndex]
23
-
24
- const handlePolygonChange = useCallback(
25
- (newPolygon: Array<[number, number]>) => {
26
- const updatedHoles = [...holes]
27
- updatedHoles[holeIndex] = newPolygon
28
- updateNode(ceilingId, { holes: updatedHoles })
29
- // Re-assert selection so the ceiling stays selected after the edit
30
- setSelection({ selectedIds: [ceilingId] })
31
- },
32
- [ceilingId, holeIndex, holes, updateNode, setSelection],
33
- )
34
-
35
- if (!(ceiling && hole) || hole.length < 3) return null
36
-
37
- return (
38
- <PolygonEditor
39
- allowEdgeMove
40
- allowPolygonMove
41
- color="#ef4444"
42
- levelId={resolveLevelId(ceiling, useScene.getState().nodes)} // red for holes
43
- minVertices={3}
44
- onPolygonChange={handlePolygonChange}
45
- polygon={hole}
46
- surfaceHeight={ceiling.height ?? 2.5}
47
- />
48
- )
49
- }