@pascal-app/editor 0.9.1 → 1.0.0-beta.1
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.
- package/package.json +14 -9
- package/src/components/editor/alignment-3d-guide-layer.tsx +10 -2
- package/src/components/editor/bake-exporter.tsx +49 -0
- package/src/components/editor/bake-thumbnail.tsx +95 -0
- package/src/components/editor/camera-dragging-lifecycle.test.ts +49 -0
- package/src/components/editor/camera-dragging-lifecycle.ts +41 -0
- package/src/components/editor/custom-camera-controls.tsx +332 -199
- package/src/components/editor/delete-confirmation-dialog.tsx +54 -0
- package/src/components/editor/editor-layout-mobile.tsx +5 -0
- package/src/components/editor/editor-layout-v2.tsx +18 -0
- package/src/components/editor/elevation-3d-guide-layer.tsx +120 -0
- package/src/components/editor/export-manager.tsx +71 -63
- package/src/components/editor/fence-tangent-lines-3d.tsx +87 -0
- package/src/components/editor/first-person/build-collider-world.test.ts +102 -5
- package/src/components/editor/first-person/build-collider-world.ts +52 -5
- package/src/components/editor/first-person/terrain-collider.test.ts +132 -0
- package/src/components/editor/first-person/terrain-collider.ts +212 -0
- package/src/components/editor/first-person-controls.tsx +410 -136
- package/src/components/editor/floating-action-menu.tsx +435 -64
- package/src/components/editor/floating-building-action-menu.tsx +1 -1
- package/src/components/editor/floorplan-background-selection.test.ts +72 -0
- package/src/components/editor/floorplan-background-selection.ts +7 -20
- package/src/components/editor/floorplan-camera-sync.test.ts +249 -0
- package/src/components/editor/floorplan-camera-sync.ts +213 -0
- package/src/components/editor/floorplan-mode-coordinator.tsx +82 -0
- package/src/components/editor/floorplan-navigation-presentation.test.ts +142 -0
- package/src/components/editor/floorplan-navigation-presentation.ts +156 -0
- package/src/components/editor/floorplan-panel.tsx +2517 -1492
- package/src/components/editor/grid.tsx +166 -39
- package/src/components/editor/group-actions.ts +597 -0
- package/src/components/editor/group-floating-action-menu.tsx +130 -0
- package/src/components/editor/group-move-3d.ts +397 -0
- package/src/components/editor/group-rotate-handle.tsx +102 -64
- package/src/components/editor/group-selection-box-3d.tsx +173 -0
- package/src/components/editor/group-transform-shared.test.ts +192 -1
- package/src/components/editor/group-transform-shared.ts +240 -7
- package/src/components/editor/handles/handle-arrow.tsx +81 -23
- package/src/components/editor/handles/handle-drag-history.test.ts +96 -0
- package/src/components/editor/handles/handle-drag-history.ts +14 -0
- package/src/components/editor/handles/preview-overrides.test.ts +26 -0
- package/src/components/editor/handles/preview-overrides.ts +13 -0
- package/src/components/editor/handles/resize-snap.test.ts +52 -0
- package/src/components/editor/handles/resize-snap.ts +23 -0
- package/src/components/editor/handles/use-handle-drag.ts +49 -6
- package/src/components/editor/index.tsx +289 -35
- package/src/components/editor/measurement-pill.tsx +68 -23
- package/src/components/editor/node-action-menu.tsx +14 -1
- package/src/components/editor/node-arrow-handles.tsx +409 -180
- package/src/components/editor/opening-guides-3d-layer.tsx +144 -0
- package/src/components/editor/quick-measurement-card.tsx +76 -0
- package/src/components/editor/quick-measurement-hud.tsx +34 -0
- package/src/components/editor/riser-diagram-panel.tsx +137 -0
- package/src/components/editor/selection-manager.tsx +814 -466
- package/src/components/editor/site-edge-labels.tsx +28 -6
- package/src/components/editor/slab-hole-highlights.tsx +13 -5
- package/src/components/editor/snapshot-capture-overlay.tsx +258 -115
- package/src/components/editor/three-context-bridge.ts +22 -0
- package/src/components/editor/thumbnail-generator.tsx +118 -253
- package/src/components/editor/use-floorplan-background-placement.ts +113 -45
- package/src/components/editor/use-floorplan-hit-testing.test.ts +82 -0
- package/src/components/editor/use-floorplan-hit-testing.ts +144 -161
- package/src/components/editor/use-floorplan-scene-data.ts +5 -5
- package/src/components/editor/use-mesh-settle-epoch.ts +27 -0
- package/src/components/editor/wall-measurement-label.tsx +10 -28
- package/src/components/editor/wall-move-side-handles.tsx +229 -39
- package/src/components/editor/wall-opening-highlights.tsx +63 -32
- package/src/components/editor/wall-snap-beacon-layer.tsx +162 -6
- package/src/components/editor-2d/floorplan-action-menu-layer.tsx +9 -5
- package/src/components/editor-2d/floorplan-alignment-guide-layer.tsx +2 -1
- package/src/components/editor-2d/floorplan-cursor-indicator-overlay.tsx +40 -9
- package/src/components/editor-2d/floorplan-cursor-indicator-position.test.ts +31 -0
- package/src/components/editor-2d/floorplan-cursor-indicator-position.ts +39 -0
- package/src/components/editor-2d/floorplan-group-action-menu.tsx +87 -0
- package/src/components/editor-2d/floorplan-group-move.tsx +744 -0
- package/src/components/editor-2d/floorplan-measurement-tool-layer.test.ts +113 -0
- package/src/components/editor-2d/floorplan-measurement-tool-layer.tsx +1672 -0
- package/src/components/editor-2d/floorplan-quick-measure-layer.tsx +212 -0
- package/src/components/editor-2d/floorplan-registered-tool-layer.tsx +72 -0
- package/src/components/editor-2d/floorplan-registry-action-menu.tsx +219 -20
- package/src/components/editor-2d/floorplan-registry-move-overlay.tsx +327 -59
- package/src/components/editor-2d/floorplan-render-context.test.ts +27 -0
- package/src/components/editor-2d/floorplan-render-context.tsx +113 -8
- package/src/components/editor-2d/floorplan-snap-beacon-layer.tsx +5 -3
- package/src/components/editor-2d/renderers/floorplan-annotation-layout.test.ts +285 -0
- package/src/components/editor-2d/renderers/floorplan-annotation-layout.ts +516 -0
- package/src/components/editor-2d/renderers/floorplan-dimension-renderer.test.tsx +236 -0
- package/src/components/editor-2d/renderers/floorplan-dimension-renderer.tsx +618 -0
- package/src/components/editor-2d/renderers/floorplan-geometry-renderer.test.tsx +369 -0
- package/src/components/editor-2d/renderers/floorplan-geometry-renderer.tsx +431 -32
- package/src/components/editor-2d/renderers/floorplan-label-angle.test.ts +89 -0
- package/src/components/editor-2d/renderers/floorplan-label-angle.ts +106 -0
- package/src/components/editor-2d/renderers/floorplan-placement-preview-layer.tsx +94 -26
- package/src/components/editor-2d/renderers/floorplan-registry-layer.test.ts +587 -0
- package/src/components/editor-2d/renderers/floorplan-registry-layer.tsx +2280 -578
- package/src/components/editor-2d/renderers/floorplan-stair-layer.tsx +20 -10
- package/src/components/editor-2d/renderers/floorplan-voronoi-layer.tsx +128 -0
- package/src/components/systems/ceiling/ceiling-selection-affordance-system.tsx +425 -61
- package/src/components/systems/ceiling/ceiling-system.tsx +97 -4
- package/src/components/systems/roof/roof-edit-system.tsx +1768 -13
- package/src/components/systems/selection-affordance-manager.tsx +38 -0
- package/src/components/systems/zone/zone-label-editor-system.tsx +14 -1
- package/src/components/systems/zone/zone-system.tsx +42 -13
- package/src/components/tools/elevator/elevator-tool.tsx +34 -8
- package/src/components/tools/elevator/move-elevator-tool.tsx +13 -2
- package/src/components/tools/fence/fence-drafting.ts +107 -8
- package/src/components/tools/item/move-tool.tsx +17 -13
- package/src/components/tools/item/placement-math.test.ts +13 -1
- package/src/components/tools/item/placement-math.ts +28 -2
- package/src/components/tools/item/placement-strategies.ts +246 -5
- package/src/components/tools/item/placement-types.ts +13 -1
- package/src/components/tools/item/use-draft-node.ts +146 -57
- package/src/components/tools/item/use-placement-coordinator.tsx +813 -125
- package/src/components/tools/registry/move-registry-node-tool.tsx +636 -103
- package/src/components/tools/roof/roof-tool.tsx +336 -94
- package/src/components/tools/select/box-select-state.ts +18 -7
- package/src/components/tools/select/box-select-tool.tsx +176 -40
- package/src/components/tools/select/marquee-geometry.test.ts +161 -0
- package/src/components/tools/select/marquee-geometry.ts +155 -0
- package/src/components/tools/select/plane-box-select-tool.tsx +1 -8
- package/src/components/tools/select/select-candidates.ts +1 -1
- package/src/components/tools/shared/cursor-sphere.tsx +62 -26
- package/src/components/tools/shared/drag-bounding-box.tsx +28 -4
- package/src/components/tools/shared/facing-indicator.tsx +87 -0
- package/src/components/tools/shared/facing-pose-indicator.tsx +54 -0
- package/src/components/tools/shared/floor-stack-preview.ts +4 -0
- package/src/components/tools/shared/horizontal-construction-plane.ts +123 -0
- package/src/components/tools/shared/placement-box.tsx +183 -1
- package/src/components/tools/shared/pointer-support-cap.test.ts +98 -0
- package/src/components/tools/shared/pointer-support-cap.ts +273 -0
- package/src/components/tools/shared/polygon-editor.tsx +276 -35
- package/src/components/tools/site/site-boundary-editor.tsx +101 -42
- package/src/components/tools/site/stroke-pointer-ownership.test.ts +91 -0
- package/src/components/tools/site/stroke-pointer-ownership.ts +57 -0
- package/src/components/tools/site/terrain-brush-cursor.tsx +247 -0
- package/src/components/tools/site/terrain-sculpt-grid.tsx +192 -0
- package/src/components/tools/site/terrain-sculpt-tool.tsx +356 -0
- package/src/components/tools/stair/stair-click-guard.test.ts +58 -0
- package/src/components/tools/stair/stair-click-guard.ts +72 -0
- package/src/components/tools/stair/stair-defaults.ts +1 -0
- package/src/components/tools/stair/stair-tool.tsx +164 -42
- package/src/components/tools/tool-manager.tsx +149 -30
- package/src/components/tools/wall/wall-drafting.test.ts +447 -0
- package/src/components/tools/wall/wall-drafting.ts +304 -108
- package/src/components/tools/wall/wall-snap-geometry.test.ts +52 -0
- package/src/components/tools/wall/wall-snap-geometry.ts +137 -9
- package/src/components/tools/zone/zone-boundary-editor.tsx +5 -1
- package/src/components/tools/zone/zone-tool.tsx +98 -88
- package/src/components/ui/action-menu/camera-actions.tsx +24 -17
- package/src/components/ui/action-menu/control-modes.tsx +44 -94
- package/src/components/ui/action-menu/furnish-tools.tsx +5 -5
- package/src/components/ui/action-menu/index.tsx +2 -4
- package/src/components/ui/action-menu/measurement-control.tsx +267 -0
- package/src/components/ui/action-menu/structure-tools.tsx +22 -13
- package/src/components/ui/action-menu/view-toggles.tsx +42 -90
- package/src/components/ui/command-palette/editor-commands.tsx +16 -3
- package/src/components/ui/command-palette/index.tsx +4 -3
- package/src/components/ui/controls/material-paint-panel.tsx +93 -18
- package/src/components/ui/controls/material-picker.tsx +162 -152
- package/src/components/ui/controls/material-properties-editor.tsx +108 -0
- package/src/components/ui/controls/metric-control.tsx +118 -44
- package/src/components/ui/controls/scene-material-list.tsx +247 -0
- package/src/components/ui/controls/slider-control.tsx +88 -38
- package/src/components/ui/controls/terrain-sculpt-panel.tsx +193 -0
- package/src/components/ui/floating-level-selector.tsx +74 -20
- package/src/components/ui/helpers/building-helper.tsx +10 -23
- package/src/components/ui/helpers/contextual-helper-panel.tsx +428 -0
- package/src/components/ui/helpers/helper-manager.tsx +273 -14
- package/src/components/ui/helpers/item-helper.tsx +28 -32
- package/src/components/ui/helpers/registered-tool-helper.tsx +45 -11
- package/src/components/ui/helpers/roof-helper.tsx +10 -12
- package/src/components/ui/icon-ref.tsx +47 -0
- package/src/components/ui/item-catalog/catalog-items.tsx +39 -1
- package/src/components/ui/item-catalog/item-catalog.tsx +13 -36
- package/src/components/ui/level-duplicate-dialog.tsx +1 -1
- package/src/components/ui/panels/multi-selection-panel.tsx +57 -0
- package/src/components/ui/panels/node-display.ts +17 -17
- package/src/components/ui/panels/panel-manager.tsx +36 -14
- package/src/components/ui/panels/panel-wrapper.tsx +24 -3
- package/src/components/ui/panels/parametric-inspector.tsx +19 -4
- package/src/components/ui/panels/reference-panel.tsx +54 -19
- package/src/components/ui/panels/selection-breakdown.test.ts +24 -0
- package/src/components/ui/panels/selection-breakdown.ts +20 -0
- package/src/components/ui/primitives/shortcut-token.tsx +39 -3
- package/src/components/ui/primitives/sidebar.tsx +1 -0
- package/src/components/ui/sidebar/app-sidebar.tsx +5 -1
- package/src/components/ui/sidebar/icon-rail.tsx +50 -31
- package/src/components/ui/sidebar/panels/plugins-panel.tsx +218 -0
- package/src/components/ui/sidebar/panels/settings-panel/index.tsx +82 -41
- package/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx +76 -6
- package/src/components/ui/sidebar/panels/settings-panel/load-build-dialog.tsx +12 -4
- package/src/components/ui/sidebar/panels/site-panel/building-tree-node.tsx +2 -1
- package/src/components/ui/sidebar/panels/site-panel/ceiling-tree-node.tsx +4 -3
- package/src/components/ui/sidebar/panels/site-panel/chimney-tree-node.tsx +10 -7
- package/src/components/ui/sidebar/panels/site-panel/column-tree-node.tsx +1 -1
- package/src/components/ui/sidebar/panels/site-panel/door-tree-node.tsx +7 -2
- package/src/components/ui/sidebar/panels/site-panel/dormer-tree-node.tsx +10 -7
- package/src/components/ui/sidebar/panels/site-panel/elevator-tree-node.tsx +1 -1
- package/src/components/ui/sidebar/panels/site-panel/fence-tree-node.tsx +1 -1
- package/src/components/ui/sidebar/panels/site-panel/gutter-tree-node.tsx +10 -7
- package/src/components/ui/sidebar/panels/site-panel/index.tsx +42 -17
- package/src/components/ui/sidebar/panels/site-panel/item-tree-node.tsx +31 -17
- package/src/components/ui/sidebar/panels/site-panel/level-tree-node.tsx +1 -1
- package/src/components/ui/sidebar/panels/site-panel/registry-tree-node.tsx +72 -25
- package/src/components/ui/sidebar/panels/site-panel/roof-tree-node.tsx +7 -3
- package/src/components/ui/sidebar/panels/site-panel/shelf-tree-node.tsx +12 -8
- package/src/components/ui/sidebar/panels/site-panel/slab-tree-node.tsx +4 -3
- package/src/components/ui/sidebar/panels/site-panel/solar-panel-tree-node.tsx +10 -7
- package/src/components/ui/sidebar/panels/site-panel/spawn-tree-node.tsx +1 -1
- package/src/components/ui/sidebar/panels/site-panel/stair-tree-node.tsx +2 -2
- package/src/components/ui/sidebar/panels/site-panel/tree-node.tsx +44 -3
- package/src/components/ui/sidebar/panels/site-panel/tree-structure.ts +36 -0
- package/src/components/ui/sidebar/panels/site-panel/wall-tree-node.tsx +1 -1
- package/src/components/ui/sidebar/panels/site-panel/window-tree-node.tsx +7 -2
- package/src/components/ui/sidebar/panels/site-panel/zone-tree-node.tsx +3 -3
- package/src/components/ui/sidebar/tab-bar.tsx +42 -28
- package/src/components/ui/sidebar/use-plugin-panels.tsx +132 -0
- package/src/components/ui/snap-target-badge.test.tsx +40 -0
- package/src/components/ui/snap-target-badge.tsx +88 -0
- package/src/components/viewer/viewer-controls-bar.tsx +466 -0
- package/src/components/viewer/viewer-scene-header.tsx +235 -0
- package/src/components/viewer-overlay.tsx +36 -596
- package/src/components/viewer-zone-system.tsx +6 -1
- package/src/components/walkthrough-hud.tsx +111 -0
- package/src/hooks/use-auto-save.test.ts +14 -0
- package/src/hooks/use-auto-save.ts +54 -7
- package/src/hooks/use-ceiling-events.ts +3 -2
- package/src/hooks/use-drag-action.ts +4 -1
- package/src/hooks/use-grid-events.ts +24 -0
- package/src/hooks/use-keyboard.ts +438 -70
- package/src/index.tsx +355 -9
- package/src/lib/active-placement-surface.test.ts +24 -0
- package/src/lib/active-placement-surface.ts +42 -0
- package/src/lib/camera-pose.test.ts +237 -0
- package/src/lib/camera-pose.ts +172 -0
- package/src/lib/ceiling-plan-snap.ts +24 -0
- package/src/lib/contextual-help.test.ts +112 -0
- package/src/lib/contextual-help.ts +144 -0
- package/src/lib/continuation.ts +64 -0
- package/src/lib/direct-manipulation.test.ts +275 -0
- package/src/lib/direct-manipulation.ts +118 -0
- package/src/lib/door-interaction.ts +1 -1
- package/src/lib/editor-api.ts +23 -35
- package/src/lib/elevation-guides.test.ts +107 -0
- package/src/lib/elevation-guides.ts +236 -0
- package/src/lib/floorplan/annotation-visibility.test.ts +327 -0
- package/src/lib/floorplan/annotation-visibility.ts +133 -0
- package/src/lib/floorplan/apply-alignment.test.ts +25 -0
- package/src/lib/floorplan/apply-alignment.ts +18 -12
- package/src/lib/floorplan/drawing-coordination.test.ts +46 -0
- package/src/lib/floorplan/drawing-coordination.ts +13 -0
- package/src/lib/floorplan/floorplan-export.test.ts +319 -0
- package/src/lib/floorplan/floorplan-export.tsx +978 -0
- package/src/lib/floorplan/floorplan-extension.test.ts +43 -0
- package/src/lib/floorplan/floorplan-extension.ts +181 -0
- package/src/lib/floorplan/floorplan-mode.test.ts +120 -0
- package/src/lib/floorplan/floorplan-mode.ts +73 -0
- package/src/lib/floorplan/floorplan-pdfkit-document.ts +194 -0
- package/src/lib/floorplan/floorplan-pdfkit-renderer.test.ts +107 -0
- package/src/lib/floorplan/floorplan-pdfkit-renderer.ts +680 -0
- package/src/lib/floorplan/geometry.ts +52 -0
- package/src/lib/floorplan/index.ts +3 -0
- package/src/lib/floorplan/items.ts +5 -2
- package/src/lib/floorplan/plan-coords.ts +21 -0
- package/src/lib/fresh-planar-placement.test.ts +283 -3
- package/src/lib/fresh-planar-placement.ts +85 -1
- package/src/lib/glb-export.test.ts +556 -0
- package/src/lib/glb-export.ts +1071 -0
- package/src/lib/ground-surface.ts +95 -0
- package/src/lib/history.test.ts +96 -0
- package/src/lib/history.ts +31 -0
- package/src/lib/interaction/hot-set.test.ts +133 -0
- package/src/lib/interaction/hot-set.ts +67 -0
- package/src/lib/interaction/overlay-policy.test.ts +52 -0
- package/src/lib/interaction/overlay-policy.ts +59 -0
- package/src/lib/interaction/scope.ts +243 -0
- package/src/lib/level-duplication.test.ts +2 -1
- package/src/lib/level-selection.ts +2 -2
- package/src/lib/material-paint.ts +36 -49
- package/src/lib/measurement-kind.test.ts +30 -0
- package/src/lib/measurement-kind.ts +19 -0
- package/src/lib/measurement-label.test.ts +47 -0
- package/src/lib/measurement-label.ts +68 -0
- package/src/lib/measurement-parser.ts +116 -0
- package/src/lib/measurements.test.ts +188 -0
- package/src/lib/measurements.ts +210 -0
- package/src/lib/paint-scope.test.ts +454 -0
- package/src/lib/paint-scope.ts +461 -0
- package/src/lib/placement-drag-release.ts +23 -0
- package/src/lib/planar-cursor-placement.test.ts +57 -0
- package/src/lib/plugin-panels.test.ts +19 -0
- package/src/lib/plugin-panels.ts +91 -0
- package/src/lib/quick-action-feedback.ts +33 -0
- package/src/lib/quick-action-nodes.test.ts +94 -0
- package/src/lib/quick-action-nodes.ts +47 -0
- package/src/lib/quick-measurement.test.ts +77 -0
- package/src/lib/quick-measurement.ts +109 -0
- package/src/lib/roof-duplication.ts +6 -6
- package/src/lib/roof-hover-outline-proxy.ts +22 -0
- package/src/lib/roof-wall-hit.ts +164 -0
- package/src/lib/scene-clipboard.test.ts +325 -0
- package/src/lib/scene-clipboard.ts +310 -21
- package/src/lib/scene.ts +28 -5
- package/src/lib/selection-routing.test.ts +313 -0
- package/src/lib/selection-routing.ts +180 -0
- package/src/lib/sfx/index.ts +1 -0
- package/src/lib/sfx/movement-tick.test.ts +65 -0
- package/src/lib/sfx/movement-tick.ts +18 -0
- package/src/lib/sfx-bus.ts +82 -14
- package/src/lib/sfx-player.test.ts +266 -0
- package/src/lib/sfx-player.ts +262 -69
- package/src/lib/site-boundary.test.ts +53 -0
- package/src/lib/site-boundary.ts +27 -0
- package/src/lib/slab-plan-snap.test.ts +93 -0
- package/src/lib/slab-plan-snap.ts +108 -0
- package/src/lib/snapping-mode.test.ts +165 -0
- package/src/lib/snapping-mode.ts +191 -0
- package/src/lib/stair-duplication.test.ts +103 -0
- package/src/lib/stair-duplication.ts +58 -86
- package/src/lib/stair-levels.ts +2 -0
- package/src/lib/surface-plan-snap.test.ts +71 -0
- package/src/lib/surface-plan-snap.ts +256 -0
- package/src/lib/terrain-sculpt.test.ts +429 -0
- package/src/lib/terrain-sculpt.ts +301 -0
- package/src/lib/terrain-verb-color.test.ts +51 -0
- package/src/lib/terrain-verb-color.ts +58 -0
- package/src/lib/touch-gesture-priority.test.ts +45 -0
- package/src/lib/touch-gesture-priority.ts +30 -0
- package/src/lib/use-linear-display.ts +40 -0
- package/src/lib/window-interaction.ts +1 -1
- package/src/lib/world-grid-snap.ts +37 -5
- package/src/store/camera-pose-store.test.ts +29 -0
- package/src/store/camera-pose-store.ts +27 -0
- package/src/store/live-draft-preview-stores.test.ts +136 -0
- package/src/store/navigation-sync-pose-store.test.ts +34 -0
- package/src/store/navigation-sync-pose-store.ts +27 -0
- package/src/store/terrain-sculpt-mode.test.ts +223 -0
- package/src/store/use-delete-confirmation.ts +27 -0
- package/src/store/use-direct-manipulation-feedback.ts +20 -0
- package/src/store/use-drawing-view.test.ts +23 -0
- package/src/store/use-drawing-view.ts +84 -0
- package/src/store/use-editor.tsx +665 -126
- package/src/store/use-elevation-guides.ts +40 -0
- package/src/store/use-facing-pose.ts +44 -0
- package/src/store/use-fence-curve-draft.ts +51 -0
- package/src/store/use-first-person-hud.ts +40 -0
- package/src/store/use-floorplan-annotation-visibility.ts +60 -0
- package/src/store/use-floorplan-draft-preview.ts +151 -0
- package/src/store/use-floorplan-marquee.ts +50 -0
- package/src/store/use-floorplan-mode.ts +110 -0
- package/src/store/use-interaction-scope.test.ts +206 -0
- package/src/store/use-interaction-scope.ts +140 -0
- package/src/store/use-measurement-draft.test.ts +559 -0
- package/src/store/use-measurement-draft.ts +570 -0
- package/src/store/use-opening-guides.ts +41 -0
- package/src/store/use-path-draft-preview.ts +90 -0
- package/src/store/use-placement-preview.ts +11 -3
- package/src/store/use-quick-measurement-hud.test.ts +53 -0
- package/src/store/use-quick-measurement-hud.ts +77 -0
- package/src/store/use-segment-draft-chain.ts +28 -0
- package/src/store/use-stair-build-preview.ts +53 -0
- package/src/store/use-wall-snap-indicator.ts +2 -0
- package/src/components/editor/first-person/bvh-ecctrl.tsx +0 -860
- package/src/components/editor/group-move-handle.tsx +0 -316
- package/src/components/ui/panels/paint-panel.tsx +0 -163
- package/src/lib/floorplan/selection-tool.ts +0 -271
- package/src/lib/level-name.ts +0 -11
|
@@ -1,21 +1,40 @@
|
|
|
1
1
|
import {
|
|
2
|
+
type AnyNodeDefinition,
|
|
2
3
|
type AnyNodeId,
|
|
3
4
|
type BuildingNode,
|
|
4
5
|
type CeilingNode,
|
|
6
|
+
type FenceNode,
|
|
5
7
|
nodeRegistry,
|
|
6
8
|
type SlabNode,
|
|
7
9
|
useScene,
|
|
10
|
+
type WallNode,
|
|
8
11
|
} from '@pascal-app/core'
|
|
9
12
|
import { useViewer } from '@pascal-app/viewer'
|
|
10
|
-
import { type ComponentType, lazy, Suspense } from 'react'
|
|
13
|
+
import { type ComponentType, lazy, Suspense, useMemo } from 'react'
|
|
14
|
+
import { siteBoundaryHandlesEnabled } from '../../lib/site-boundary'
|
|
11
15
|
import useEditor, { type Phase, type Tool } from '../../store/use-editor'
|
|
16
|
+
import {
|
|
17
|
+
useControlPointReshape,
|
|
18
|
+
useEditingHole,
|
|
19
|
+
useEndpointReshape,
|
|
20
|
+
useIsCurveReshape,
|
|
21
|
+
useIsFloorplanDrivenReshape,
|
|
22
|
+
useIsToolDrivenReshape,
|
|
23
|
+
useMovingNode,
|
|
24
|
+
useReshapingNode,
|
|
25
|
+
useTangentReshape,
|
|
26
|
+
} from '../../store/use-interaction-scope'
|
|
12
27
|
import { Alignment3DGuideLayer } from '../editor/alignment-3d-guide-layer'
|
|
28
|
+
import { Elevation3DGuideLayer } from '../editor/elevation-3d-guide-layer'
|
|
29
|
+
import { OpeningGuides3DLayer } from '../editor/opening-guides-3d-layer'
|
|
13
30
|
import { WallSnapBeaconLayer } from '../editor/wall-snap-beacon-layer'
|
|
14
31
|
import { ElevatorTool } from './elevator/elevator-tool'
|
|
15
32
|
import { MoveTool } from './item/move-tool'
|
|
16
33
|
import { RoofTool } from './roof/roof-tool'
|
|
17
34
|
import { getRegistryAffordanceTool } from './shared/affordance-dispatch'
|
|
35
|
+
import { FacingPoseIndicator } from './shared/facing-pose-indicator'
|
|
18
36
|
import { SiteBoundaryEditor } from './site/site-boundary-editor'
|
|
37
|
+
import { TerrainSculptTool } from './site/terrain-sculpt-tool'
|
|
19
38
|
import { StairTool } from './stair/stair-tool'
|
|
20
39
|
import { ZoneBoundaryEditor } from './zone/zone-boundary-editor'
|
|
21
40
|
import { ZoneTool } from './zone/zone-tool'
|
|
@@ -23,6 +42,29 @@ import { ZoneTool } from './zone/zone-tool'
|
|
|
23
42
|
// Cache lazy tool components keyed by their loader so React.lazy isn't
|
|
24
43
|
// re-invoked across renders.
|
|
25
44
|
const lazyToolCache = new WeakMap<() => Promise<unknown>, ComponentType>()
|
|
45
|
+
const registryToolPreloadCache = new WeakMap<AnyNodeDefinition, Promise<void>>()
|
|
46
|
+
|
|
47
|
+
export function preloadRegistryToolModules(tool: string | null): Promise<void> {
|
|
48
|
+
if (!tool) return Promise.resolve()
|
|
49
|
+
const def = nodeRegistry.get(tool)
|
|
50
|
+
if (!def) return Promise.resolve()
|
|
51
|
+
const cached = registryToolPreloadCache.get(def)
|
|
52
|
+
if (cached) return cached
|
|
53
|
+
|
|
54
|
+
const loaders: Array<() => Promise<unknown>> = []
|
|
55
|
+
if (def.tool) loaders.push(def.tool)
|
|
56
|
+
if (def.preview) loaders.push(def.preview)
|
|
57
|
+
if (def.renderer?.kind === 'parametric') loaders.push(def.renderer.module)
|
|
58
|
+
if (def.system) loaders.push(def.system.module)
|
|
59
|
+
if (def.parametrics?.customPanel) loaders.push(def.parametrics.customPanel)
|
|
60
|
+
if (def.parametrics?.trailingSection) loaders.push(def.parametrics.trailingSection)
|
|
61
|
+
const moveTool = def.affordanceTools?.move
|
|
62
|
+
if (moveTool) loaders.push(moveTool)
|
|
63
|
+
|
|
64
|
+
const preload = Promise.allSettled(loaders.map((loader) => loader())).then(() => undefined)
|
|
65
|
+
registryToolPreloadCache.set(def, preload)
|
|
66
|
+
return preload
|
|
67
|
+
}
|
|
26
68
|
|
|
27
69
|
function getRegistryTool(tool: Tool | null): ComponentType | null {
|
|
28
70
|
if (!tool) return null
|
|
@@ -30,7 +72,13 @@ function getRegistryTool(tool: Tool | null): ComponentType | null {
|
|
|
30
72
|
if (!def?.tool) return null
|
|
31
73
|
const cached = lazyToolCache.get(def.tool)
|
|
32
74
|
if (cached) return cached
|
|
33
|
-
const Comp = lazy(
|
|
75
|
+
const Comp = lazy(async () => {
|
|
76
|
+
// Placement can only begin once the node's preview, committed renderer,
|
|
77
|
+
// inspector, and move contribution are warm. This keeps the click itself
|
|
78
|
+
// synchronous even under Next.js dev-time on-demand compilation.
|
|
79
|
+
await preloadRegistryToolModules(tool)
|
|
80
|
+
return def.tool!() as Promise<{ default: ComponentType }>
|
|
81
|
+
})
|
|
34
82
|
lazyToolCache.set(def.tool, Comp)
|
|
35
83
|
return Comp
|
|
36
84
|
}
|
|
@@ -54,12 +102,39 @@ export const ToolManager: React.FC = () => {
|
|
|
54
102
|
const phase = useEditor((state) => state.phase)
|
|
55
103
|
const mode = useEditor((state) => state.mode)
|
|
56
104
|
const tool = useEditor((state) => state.tool)
|
|
57
|
-
const movingNode =
|
|
58
|
-
const
|
|
59
|
-
const
|
|
60
|
-
const
|
|
61
|
-
const
|
|
62
|
-
const
|
|
105
|
+
const movingNode = useMovingNode()
|
|
106
|
+
const movingNodeOrigin = useEditor((state) => state.movingNodeOrigin)
|
|
107
|
+
const endpointReshape = useEndpointReshape()
|
|
108
|
+
const controlPointReshape = useControlPointReshape()
|
|
109
|
+
const tangentReshape = useTangentReshape()
|
|
110
|
+
const isCurveReshape = useIsCurveReshape()
|
|
111
|
+
const isToolDrivenReshape = useIsToolDrivenReshape()
|
|
112
|
+
const isFloorplanDrivenReshape = useIsFloorplanDrivenReshape()
|
|
113
|
+
const reshapingNode = useReshapingNode()
|
|
114
|
+
// The endpoint affordance tool's `target` is kind-specific
|
|
115
|
+
// (`{ wall | fence, endpoint }`); rebuild it from the (frozen) reshaped node +
|
|
116
|
+
// the scope's endpoint. Memoised so it stays referentially stable across the
|
|
117
|
+
// scene-write re-renders during the drag — otherwise a fresh object each frame
|
|
118
|
+
// re-fires the tool's setup effect (endpoint drag would loop / freeze).
|
|
119
|
+
const endpointTarget = useMemo(() => {
|
|
120
|
+
if (!(endpointReshape && reshapingNode)) return null
|
|
121
|
+
return reshapingNode.type === 'fence'
|
|
122
|
+
? { fence: reshapingNode as FenceNode, endpoint: endpointReshape.endpoint }
|
|
123
|
+
: { wall: reshapingNode as WallNode, endpoint: endpointReshape.endpoint }
|
|
124
|
+
}, [endpointReshape, reshapingNode])
|
|
125
|
+
const controlPointTarget = useMemo(() => {
|
|
126
|
+
if (!(controlPointReshape && reshapingNode?.type === 'fence')) return null
|
|
127
|
+
return { fence: reshapingNode as FenceNode, index: controlPointReshape.index }
|
|
128
|
+
}, [controlPointReshape, reshapingNode])
|
|
129
|
+
const tangentTarget = useMemo(() => {
|
|
130
|
+
if (!(tangentReshape && reshapingNode?.type === 'fence')) return null
|
|
131
|
+
return {
|
|
132
|
+
fence: reshapingNode as FenceNode,
|
|
133
|
+
index: tangentReshape.index,
|
|
134
|
+
side: tangentReshape.side,
|
|
135
|
+
}
|
|
136
|
+
}, [reshapingNode, tangentReshape])
|
|
137
|
+
const editingHole = useEditingHole()
|
|
63
138
|
const selectedZoneId = useViewer((state) => state.selection.zoneId)
|
|
64
139
|
const selectedIds = useViewer((state) => state.selection.selectedIds)
|
|
65
140
|
const buildingId = useViewer((state) => state.selection.buildingId)
|
|
@@ -90,15 +165,27 @@ export const ToolManager: React.FC = () => {
|
|
|
90
165
|
| CeilingNode['id']
|
|
91
166
|
| undefined
|
|
92
167
|
|
|
93
|
-
//
|
|
94
|
-
//
|
|
95
|
-
|
|
168
|
+
// Site boundary handles normally share one 2D/3D rule. Sculpt is the deliberate
|
|
169
|
+
// 3D exception: the brush only owns this canvas, where PolygonEditor can hand
|
|
170
|
+
// off its pointer before a boundary drag starts.
|
|
171
|
+
const sculpting = mode === 'terrain-sculpt'
|
|
172
|
+
// Sculpt keeps the 3D property controls visible. PolygonEditor marks its
|
|
173
|
+
// pointer before the canvas-level brush listener runs, and activating one
|
|
174
|
+
// exits sculpt mode before starting the boundary drag.
|
|
175
|
+
const showSiteBoundaryEditor = sculpting || siteBoundaryHandlesEnabled({ mode, phase })
|
|
176
|
+
|
|
177
|
+
// A multi-selection is manipulated as one rigid group (drag / R / T), so
|
|
178
|
+
// per-node reshape chrome — the slab / ceiling boundary editors' vertex and
|
|
179
|
+
// edge handles — mounts only for a sole selection.
|
|
180
|
+
const isSoleSelection = selectedIds.length === 1
|
|
96
181
|
|
|
97
182
|
// Show slab boundary editor when in structure/select mode with a slab selected (but not editing a hole)
|
|
98
183
|
const showSlabBoundaryEditor =
|
|
99
184
|
phase === 'structure' &&
|
|
100
185
|
mode === 'select' &&
|
|
186
|
+
isSoleSelection &&
|
|
101
187
|
selectedSlabId !== undefined &&
|
|
188
|
+
!isFloorplanDrivenReshape &&
|
|
102
189
|
!editingSlabHoleIsManual
|
|
103
190
|
|
|
104
191
|
// Show slab hole editor when editing a hole on the selected slab
|
|
@@ -106,20 +193,24 @@ export const ToolManager: React.FC = () => {
|
|
|
106
193
|
selectedSlabId !== undefined &&
|
|
107
194
|
editingHole !== null &&
|
|
108
195
|
editingHole.nodeId === selectedSlabId &&
|
|
196
|
+
!isFloorplanDrivenReshape &&
|
|
109
197
|
editingSlabHoleIsManual
|
|
110
198
|
|
|
111
199
|
// Show ceiling boundary editor when in structure/select mode with a ceiling selected (but not editing a hole)
|
|
112
200
|
const showCeilingBoundaryEditor =
|
|
113
201
|
phase === 'structure' &&
|
|
114
202
|
mode === 'select' &&
|
|
203
|
+
isSoleSelection &&
|
|
115
204
|
selectedCeilingId !== undefined &&
|
|
205
|
+
!isFloorplanDrivenReshape &&
|
|
116
206
|
(!editingHole || editingHole.nodeId !== selectedCeilingId)
|
|
117
207
|
|
|
118
208
|
// Show ceiling hole editor when editing a hole on the selected ceiling
|
|
119
209
|
const showCeilingHoleEditor =
|
|
120
210
|
selectedCeilingId !== undefined &&
|
|
121
211
|
editingHole !== null &&
|
|
122
|
-
editingHole.nodeId === selectedCeilingId
|
|
212
|
+
editingHole.nodeId === selectedCeilingId &&
|
|
213
|
+
!isFloorplanDrivenReshape
|
|
123
214
|
|
|
124
215
|
// Show zone boundary editor when in structure/select mode with a zone selected
|
|
125
216
|
// Hide when editing a slab or ceiling to avoid overlapping handles
|
|
@@ -127,12 +218,23 @@ export const ToolManager: React.FC = () => {
|
|
|
127
218
|
phase === 'structure' &&
|
|
128
219
|
mode === 'select' &&
|
|
129
220
|
selectedZoneId !== null &&
|
|
221
|
+
!isFloorplanDrivenReshape &&
|
|
130
222
|
!showSlabBoundaryEditor &&
|
|
131
223
|
!showCeilingBoundaryEditor
|
|
132
224
|
|
|
133
225
|
// Show build tools when in build mode
|
|
134
226
|
const showBuildTool = mode === 'build' && tool !== null
|
|
135
227
|
|
|
228
|
+
// A move initiated from the 2D floor-plan (orange move-dot) is owned end-to-
|
|
229
|
+
// end by `FloorplanRegistryMoveOverlay`, which marks the origin `'2d'` at
|
|
230
|
+
// dot-down. Mounting the 3D affordance mover alongside it would adopt the
|
|
231
|
+
// same node and, on its unmount, restore the adopt-time position — snapping
|
|
232
|
+
// the committed 2D move back to its start. Gate the 3D mover off for 2D moves
|
|
233
|
+
// (the scene writes the overlay makes still mirror into the 3D view). A
|
|
234
|
+
// 3D-initiated move leaves the origin null until its own commit, so this only
|
|
235
|
+
// suppresses the 3D tool for genuinely 2D-owned moves.
|
|
236
|
+
const showMover = movingNode != null && movingNodeOrigin !== '2d'
|
|
237
|
+
|
|
136
238
|
// Registry-first: if the active tool's kind has a NodeDefinition with a
|
|
137
239
|
// tool contribution, the registry-driven tool takes over.
|
|
138
240
|
const RegistryToolComponent = showBuildTool ? getRegistryTool(tool) : null
|
|
@@ -162,7 +264,11 @@ export const ToolManager: React.FC = () => {
|
|
|
162
264
|
<>
|
|
163
265
|
{/* World-space tools: site boundary and building movement operate in world coordinates */}
|
|
164
266
|
{showSiteBoundaryEditor && <SiteBoundaryEditor />}
|
|
165
|
-
{
|
|
267
|
+
{/* Terrain sculpting is a mode rather than a `tools[phase][tool]` entry —
|
|
268
|
+
it places no node — so it gets its own gate here. World-space, because
|
|
269
|
+
the ground is not building-local. */}
|
|
270
|
+
{sculpting && <TerrainSculptTool />}
|
|
271
|
+
{showMover && movingNode?.type === 'building' && (
|
|
166
272
|
<MoveTool onNodeMoved={handlePlacedNodeSelected} onSpawnMoved={handlePlacedNodeSelected} />
|
|
167
273
|
)}
|
|
168
274
|
|
|
@@ -216,49 +322,52 @@ export const ToolManager: React.FC = () => {
|
|
|
216
322
|
</Suspense>
|
|
217
323
|
) : null
|
|
218
324
|
})()}
|
|
219
|
-
{
|
|
325
|
+
{isToolDrivenReshape &&
|
|
326
|
+
endpointTarget &&
|
|
327
|
+
reshapingNode &&
|
|
220
328
|
(() => {
|
|
221
329
|
const RegistryAffordance = getRegistryAffordanceTool(
|
|
222
|
-
|
|
330
|
+
reshapingNode.type,
|
|
223
331
|
'move-endpoint',
|
|
224
332
|
)
|
|
225
333
|
return RegistryAffordance ? (
|
|
226
334
|
<Suspense fallback={null}>
|
|
227
|
-
<RegistryAffordance target={
|
|
335
|
+
<RegistryAffordance target={endpointTarget} />
|
|
228
336
|
</Suspense>
|
|
229
337
|
) : null
|
|
230
338
|
})()}
|
|
231
|
-
{
|
|
339
|
+
{isToolDrivenReshape &&
|
|
340
|
+
isCurveReshape &&
|
|
341
|
+
reshapingNode &&
|
|
232
342
|
(() => {
|
|
233
|
-
const RegistryAffordance = getRegistryAffordanceTool(
|
|
234
|
-
movingFenceEndpoint.fence.type,
|
|
235
|
-
'move-endpoint',
|
|
236
|
-
)
|
|
343
|
+
const RegistryAffordance = getRegistryAffordanceTool(reshapingNode.type, 'curve')
|
|
237
344
|
return RegistryAffordance ? (
|
|
238
345
|
<Suspense fallback={null}>
|
|
239
|
-
<RegistryAffordance
|
|
346
|
+
<RegistryAffordance node={reshapingNode} />
|
|
240
347
|
</Suspense>
|
|
241
348
|
) : null
|
|
242
349
|
})()}
|
|
243
|
-
{
|
|
350
|
+
{isToolDrivenReshape &&
|
|
351
|
+
controlPointTarget &&
|
|
244
352
|
(() => {
|
|
245
|
-
const
|
|
246
|
-
return
|
|
353
|
+
const RegistryAffordance = getRegistryAffordanceTool('fence', 'move-control-point')
|
|
354
|
+
return RegistryAffordance ? (
|
|
247
355
|
<Suspense fallback={null}>
|
|
248
|
-
<
|
|
356
|
+
<RegistryAffordance target={controlPointTarget} />
|
|
249
357
|
</Suspense>
|
|
250
358
|
) : null
|
|
251
359
|
})()}
|
|
252
|
-
{
|
|
360
|
+
{isToolDrivenReshape &&
|
|
361
|
+
tangentTarget &&
|
|
253
362
|
(() => {
|
|
254
|
-
const RegistryAffordance = getRegistryAffordanceTool(
|
|
363
|
+
const RegistryAffordance = getRegistryAffordanceTool('fence', 'move-tangent')
|
|
255
364
|
return RegistryAffordance ? (
|
|
256
365
|
<Suspense fallback={null}>
|
|
257
|
-
<RegistryAffordance
|
|
366
|
+
<RegistryAffordance target={tangentTarget} />
|
|
258
367
|
</Suspense>
|
|
259
368
|
) : null
|
|
260
369
|
})()}
|
|
261
|
-
{
|
|
370
|
+
{showMover && movingNode.type !== 'building' && (
|
|
262
371
|
<MoveTool
|
|
263
372
|
onNodeMoved={handlePlacedNodeSelected}
|
|
264
373
|
onSpawnMoved={handlePlacedNodeSelected}
|
|
@@ -283,6 +392,16 @@ export const ToolManager: React.FC = () => {
|
|
|
283
392
|
tools above. Lives inside the building-local group so the
|
|
284
393
|
building-local guide coords render at the right world position. */}
|
|
285
394
|
<Alignment3DGuideLayer />
|
|
395
|
+
{/* The one forward-facing triangle renderer. Placement/move tools
|
|
396
|
+
publish their ghost pose to `useFacingPose`; this draws it. Mounted
|
|
397
|
+
here so it shares the building-local frame the tools publish in. */}
|
|
398
|
+
<FacingPoseIndicator />
|
|
399
|
+
{/* Wall-plane proximity / sill / equal-spacing guides for openings,
|
|
400
|
+
published by the door/window move tools in the same world frame. */}
|
|
401
|
+
<OpeningGuides3DLayer />
|
|
402
|
+
{/* Structural Y-datum feedback for slab, ceiling, wall, and fence
|
|
403
|
+
elevation handles. Ephemeral editor chrome; never scene data. */}
|
|
404
|
+
<Elevation3DGuideLayer />
|
|
286
405
|
{/* "Magnetic" beacon at the active wall-draft snap point. */}
|
|
287
406
|
<WallSnapBeaconLayer />
|
|
288
407
|
</group>
|