@pascal-app/editor 1.0.3 → 1.0.5
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/README.md +106 -0
- package/package.json +42 -38
- package/src/components/editor/__bench__/room-label-placement.bench.ts +108 -0
- package/src/components/editor/action-menu-button.tsx +83 -0
- package/src/components/editor/bake-thumbnail.tsx +307 -5
- package/src/components/editor/capture-level-picker.tsx +72 -0
- package/src/components/editor/construction-reveal-audio.test.tsx +150 -0
- package/src/components/editor/construction-reveal-audio.tsx +40 -0
- package/src/components/editor/custom-camera-controls.tsx +275 -57
- package/src/components/editor/delete-confirmation-dialog.tsx +297 -7
- package/src/components/editor/duplicate-node.ts +244 -0
- package/src/components/editor/editor-layout-mobile.tsx +37 -26
- package/src/components/editor/editor-layout-v2.tsx +132 -59
- package/src/components/editor/export-manager.tsx +47 -26
- package/src/components/editor/first-person/build-collider-world.test.ts +320 -0
- package/src/components/editor/first-person/build-collider-world.ts +28 -7
- package/src/components/editor/first-person/ground-holes.test.ts +128 -0
- package/src/components/editor/first-person/ground-holes.ts +130 -0
- package/src/components/editor/first-person/mechanism-targets.test.ts +162 -0
- package/src/components/editor/first-person/mechanism-targets.ts +88 -0
- package/src/components/editor/first-person-controls.tsx +220 -9
- package/src/components/editor/floating-action-menu.tsx +63 -207
- package/src/components/editor/floor-aware-camera-controls.test.ts +466 -0
- package/src/components/editor/floor-aware-camera-controls.ts +324 -0
- package/src/components/editor/floor-openings-overlay.tsx +243 -0
- package/src/components/editor/floor-region-controls.tsx +846 -0
- package/src/components/editor/floor-region-webgpu-materials.test.ts +12 -0
- package/src/components/editor/floor-surface.test.ts +165 -0
- package/src/components/editor/floor-surface.ts +182 -0
- package/src/components/editor/floorplan-background-selection.test.ts +11 -2
- package/src/components/editor/floorplan-background-selection.ts +1 -3
- package/src/components/editor/floorplan-mode-coordinator.tsx +2 -2
- package/src/components/editor/floorplan-panel.tsx +414 -363
- package/src/components/editor/follow-pascal.test.tsx +912 -0
- package/src/components/editor/follow-pascal.tsx +354 -0
- package/src/components/editor/footprint-height-handle.tsx +204 -0
- package/src/components/editor/group-actions.ts +56 -2
- package/src/components/editor/group-move-3d.ts +2 -0
- package/src/components/editor/group-rotate-handle.tsx +2 -0
- package/src/components/editor/group-transform-shared.test.ts +460 -0
- package/src/components/editor/handles/handle-hit-priority.test.tsx +63 -0
- package/src/components/editor/handles/handle-hit-priority.tsx +37 -0
- package/src/components/editor/handles/swallow-next-click.test.ts +28 -0
- package/src/components/editor/handles/use-handle-drag.ts +269 -197
- package/src/components/editor/index.tsx +409 -197
- package/src/components/editor/join-walls-pill.tsx +44 -0
- package/src/components/editor/node-action-menu.tsx +68 -70
- package/src/components/editor/node-arrow-handles.tsx +25 -6
- package/src/components/editor/open-wall-ends-3d-layer.tsx +273 -0
- package/src/components/editor/open-wall-ends-hint.tsx +89 -0
- package/src/components/editor/quick-measurement-hud.tsx +3 -2
- package/src/components/editor/registry-action-contributions.test.tsx +63 -0
- package/src/components/editor/registry-action-contributions.tsx +80 -1
- package/src/components/editor/riser-diagram-panel.tsx +14 -7
- package/src/components/editor/room-controls.tsx +847 -0
- package/src/components/editor/room-floor-highlight.tsx +128 -0
- package/src/components/editor/room-handles-2d.tsx +354 -0
- package/src/components/editor/room-handles.tsx +675 -0
- package/src/components/editor/room-highlight.tsx +233 -0
- package/src/components/editor/room-labels.test.ts +850 -0
- package/src/components/editor/room-labels.tsx +1890 -0
- package/src/components/editor/room-transform-ghost.tsx +256 -0
- package/src/components/editor/room-webgpu-materials.test.ts +27 -0
- package/src/components/editor/selection-manager.tsx +474 -419
- package/src/components/editor/slab-hole-highlights.tsx +5 -2
- package/src/components/editor/snapshot-capture-overlay.tsx +7 -2
- package/src/components/editor/snapshot-capture.test.ts +119 -60
- package/src/components/editor/snapshot-capture.ts +36 -5
- package/src/components/editor/thumbnail-generator.test.ts +654 -0
- package/src/components/editor/thumbnail-generator.tsx +1103 -223
- package/src/components/editor/use-floorplan-background-placement.ts +34 -12
- package/src/components/editor/vector-edge-extractor.tsx +121 -0
- package/src/components/editor/views/host-view.tsx +61 -0
- package/src/components/editor/views/plugins-view.tsx +663 -0
- package/src/components/editor/views/scene-region.tsx +59 -0
- package/src/components/editor/views/use-editor-views.ts +57 -0
- package/src/components/editor/views/view-bar.test.tsx +54 -0
- package/src/components/editor/views/view-bar.tsx +343 -0
- package/src/components/editor/wall-justification.test.ts +140 -0
- package/src/components/editor/wall-move-side-handles.tsx +43 -142
- package/src/components/editor/wall-push-arrow.tsx +92 -0
- package/src/components/editor/wall-region-handles.tsx +509 -0
- package/src/components/editor/wall-snap-beacon-layer.tsx +8 -4
- package/src/components/editor-2d/floorplan-cursor-indicator-overlay.tsx +8 -4
- package/src/components/editor-2d/floorplan-group-move.tsx +3 -0
- package/src/components/editor-2d/floorplan-open-wall-ends-layer.test.tsx +86 -0
- package/src/components/editor-2d/floorplan-open-wall-ends-layer.tsx +290 -0
- package/src/components/editor-2d/floorplan-registered-tool-layer.tsx +2 -2
- package/src/components/editor-2d/floorplan-registry-action-menu.tsx +11 -1
- package/src/components/editor-2d/floorplan-registry-move-overlay.tsx +116 -106
- package/src/components/editor-2d/renderers/floorplan-dimension-edit-overlay.test.ts +156 -0
- package/src/components/editor-2d/renderers/floorplan-dimension-edit-overlay.tsx +278 -0
- package/src/components/editor-2d/renderers/floorplan-dimension-renderer.tsx +77 -0
- package/src/components/editor-2d/renderers/{floorplan-draft-wall-measurement.tsx → floorplan-draft-measurement.tsx} +8 -8
- package/src/components/editor-2d/renderers/floorplan-geometry-renderer.tsx +4 -1
- package/src/components/editor-2d/renderers/floorplan-registry-layer.test.ts +38 -8
- package/src/components/editor-2d/renderers/floorplan-registry-layer.tsx +319 -233
- package/src/components/editor-2d/renderers/floorplan-reveal.test.tsx +254 -0
- package/src/components/editor-2d/renderers/floorplan-reveal.ts +141 -0
- package/src/components/editor-2d/svg-paths.ts +12 -15
- package/src/components/point-ask/bubble.tsx +538 -0
- package/src/components/point-ask/hover-chip.tsx +91 -0
- package/src/components/point-ask/mode-pill.tsx +92 -0
- package/src/components/point-ask/optional-motion.ts +22 -0
- package/src/components/point-ask/outline-corners.tsx +93 -0
- package/src/components/point-ask/pins.tsx +711 -0
- package/src/components/point-ask/point-ask-layer.tsx +83 -0
- package/src/components/point-ask/point-ask-styles.ts +105 -0
- package/src/components/point-ask/region-marquee-styles.ts +15 -0
- package/src/components/point-ask/region-marquee.tsx +64 -0
- package/src/components/procedural-items/inspector.tsx +40 -15
- package/src/components/systems/ceiling/ceiling-bracket-batch.test.ts +12 -2
- package/src/components/systems/ceiling/ceiling-selection-affordance-system.test.ts +97 -14
- package/src/components/systems/ceiling/ceiling-selection-affordance-system.tsx +18 -18
- package/src/components/systems/roof/roof-edit-system.tsx +1 -0
- package/src/components/systems/zone/zone-system.test.ts +47 -0
- package/src/components/systems/zone/zone-system.tsx +29 -68
- package/src/components/tools/distribution/connection-compatibility.test.ts +34 -0
- package/src/components/tools/distribution/connection-compatibility.ts +43 -0
- package/src/components/tools/distribution/distribution-public.ts +9 -0
- package/src/components/tools/distribution/distribution-run-contract.test.ts +26 -0
- package/src/components/tools/distribution/distribution-run-contract.ts +94 -0
- package/src/components/tools/distribution/distribution-run-tool.test.ts +241 -0
- package/src/components/tools/distribution/distribution-run-tool.test.tsx +125 -0
- package/src/components/tools/distribution/distribution-run-tool.tsx +1323 -0
- package/src/components/tools/distribution/draw-alignment.ts +35 -0
- package/src/components/tools/distribution/ports.test.ts +56 -0
- package/src/components/tools/distribution/ports.ts +378 -0
- package/src/components/tools/distribution/run-cursor.test.ts +135 -0
- package/src/components/tools/distribution/run-cursor.ts +36 -0
- package/src/components/tools/distribution/run-direction-feedback.test.ts +60 -0
- package/src/components/tools/distribution/run-direction-feedback.tsx +251 -0
- package/src/components/tools/distribution/run-port-snap.test.ts +79 -0
- package/src/components/tools/distribution/run-port-snap.ts +25 -0
- package/src/components/tools/distribution/run-screen-direction.test.ts +23 -0
- package/src/components/tools/distribution/run-screen-direction.ts +30 -0
- package/src/components/tools/elevator/elevator-tool.tsx +3 -6
- package/src/components/tools/elevator/move-elevator-tool.tsx +2 -3
- package/src/components/tools/item/item-surface-strategy-resolver.test.ts +67 -68
- package/src/components/tools/item/placement-history.test.tsx +512 -0
- package/src/components/tools/item/placement-strategies.test.ts +46 -1
- package/src/components/tools/item/placement-strategies.ts +11 -10
- package/src/components/tools/item/shelf-surface-strategy-resolver.test.ts +56 -56
- package/src/components/tools/item/use-draft-node.test.tsx +432 -1
- package/src/components/tools/item/use-draft-node.ts +166 -95
- package/src/components/tools/item/use-placement-coordinator.tsx +148 -95
- package/src/components/tools/paint-region/use-paint-tint.ts +37 -0
- package/src/components/tools/paint-region/wall-paint-region-tool.tsx +466 -0
- package/src/components/tools/registry/item-surface-move.test.ts +62 -63
- package/src/components/tools/registry/item-surface-move.ts +2 -0
- package/src/components/tools/registry/item-surface-resolver.test.ts +26 -26
- package/src/components/tools/registry/move-registry-node-tool.test.ts +268 -1
- package/src/components/tools/registry/move-registry-node-tool.tsx +66 -30
- package/src/components/tools/select/box-select-tool.tsx +2 -12
- package/src/components/tools/select/plane-box-select-tool.test.tsx +79 -0
- package/src/components/tools/select/plane-box-select-tool.tsx +35 -22
- package/src/components/tools/select/select-candidates.test.ts +37 -4
- package/src/components/tools/select/select-candidates.ts +15 -11
- package/src/components/tools/shared/cursor-sphere.tsx +36 -12
- package/src/components/tools/site/site-boundary-editor.tsx +1 -2
- package/src/components/tools/tool-manager.tsx +59 -24
- package/src/components/tools/wall/wall-drafting.test.ts +175 -47
- package/src/components/tools/zone/zone-tool.tsx +4 -12
- package/src/components/ui/action-menu/action-button.tsx +9 -1
- package/src/components/ui/action-menu/camera-actions.tsx +9 -4
- package/src/components/ui/action-menu/control-modes.tsx +15 -42
- package/src/components/ui/action-menu/follow-pascal-pill.tsx +32 -0
- package/src/components/ui/action-menu/follow-pascal-toggle.tsx +36 -0
- package/src/components/ui/action-menu/index.tsx +56 -33
- package/src/components/ui/action-menu/measurement-control.tsx +14 -19
- package/src/components/ui/action-menu/placement.ts +20 -0
- package/src/components/ui/action-menu/point-ask-button.tsx +52 -0
- package/src/components/ui/action-menu/view-toggles.tsx +47 -42
- package/src/components/ui/build-panel/build-panel.tsx +242 -0
- package/src/components/ui/command-palette/editor-commands.tsx +7 -42
- package/src/components/ui/command-palette/index.tsx +50 -39
- package/src/components/ui/command-palette/ranked-groups.test.ts +31 -0
- package/src/components/ui/controls/action-button.tsx +5 -2
- package/src/components/ui/controls/finish-swatch.tsx +110 -0
- package/src/components/ui/controls/material-paint-panel.tsx +97 -26
- package/src/components/ui/controls/material-picker.tsx +4 -1
- package/src/components/ui/controls/metric-control.tsx +1 -1
- package/src/components/ui/controls/scene-material-list.tsx +4 -32
- package/src/components/ui/controls/segmented-control.tsx +21 -8
- package/src/components/ui/controls/select-control.tsx +65 -0
- package/src/components/ui/controls/slider-control.tsx +1 -1
- package/src/components/ui/controls/toggle-control.tsx +3 -3
- package/src/components/ui/controls/tool-options-panel.tsx +1 -1
- package/src/components/ui/floating-level-selector.tsx +159 -59
- package/src/components/ui/helpers/building-helper.tsx +4 -1
- package/src/components/ui/helpers/contextual-helper-panel.tsx +181 -72
- package/src/components/ui/helpers/helper-manager.test.tsx +121 -0
- package/src/components/ui/helpers/helper-manager.tsx +331 -14
- package/src/components/ui/helpers/item-helper.tsx +17 -1
- package/src/components/ui/helpers/registered-tool-helper.tsx +8 -1
- package/src/components/ui/icon-ref.tsx +45 -1
- package/src/components/ui/level-duplicate-dialog.tsx +1 -1
- package/src/components/ui/node-icon-image.tsx +16 -0
- package/src/components/ui/panels/collections/collections-popover.tsx +28 -22
- package/src/components/ui/panels/floor-foundation-panel.tsx +551 -0
- package/src/components/ui/panels/floor-opening-panel.tsx +143 -0
- package/src/components/ui/panels/mobile-panel-sheet.tsx +4 -4
- package/src/components/ui/panels/mobile-selection-bar.tsx +8 -5
- package/src/components/ui/panels/multi-field-value.test.ts +26 -3
- package/src/components/ui/panels/multi-field-value.ts +6 -3
- package/src/components/ui/panels/multi-parametric-inspector.tsx +52 -2
- package/src/components/ui/panels/multi-selection-panel.tsx +161 -5
- package/src/components/ui/panels/node-display.ts +8 -3
- package/src/components/ui/panels/panel-manager.tsx +103 -68
- package/src/components/ui/panels/panel-wrapper.tsx +130 -62
- package/src/components/ui/panels/parametric-field-control.tsx +3 -3
- package/src/components/ui/panels/parametric-inspector.tsx +7 -7
- package/src/components/ui/panels/reference-panel.tsx +2 -3
- package/src/components/ui/panels/room-construction-rows.tsx +774 -0
- package/src/components/ui/panels/room-name-options.test.ts +55 -0
- package/src/components/ui/panels/room-name-options.ts +47 -0
- package/src/components/ui/panels/room-openings-field.tsx +110 -0
- package/src/components/ui/panels/room-panel.tsx +790 -0
- package/src/components/ui/panels/shape-choice.tsx +58 -0
- package/src/components/ui/panels/wall-region-list.tsx +109 -0
- package/src/components/ui/primitives/badge.tsx +8 -0
- package/src/components/ui/primitives/color-dot.tsx +36 -24
- package/src/components/ui/primitives/sidebar.tsx +3 -1
- package/src/components/ui/right-stack.test.ts +29 -0
- package/src/components/ui/right-stack.tsx +164 -0
- package/src/components/ui/sidebar/app-sidebar.tsx +1 -1
- package/src/components/ui/sidebar/icon-rail.tsx +8 -3
- package/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx +1 -1
- package/src/components/ui/sidebar/panels/items-panel/index.tsx +6 -6
- package/src/components/ui/sidebar/panels/settings-panel/animation-speed-setting.tsx +40 -0
- package/src/components/ui/sidebar/panels/settings-panel/audio-settings-dialog.tsx +7 -8
- package/src/components/ui/sidebar/panels/settings-panel/construction-animation-setting.test.tsx +170 -0
- package/src/components/ui/sidebar/panels/settings-panel/construction-animation-setting.tsx +92 -0
- package/src/components/ui/sidebar/panels/settings-panel/index.tsx +138 -27
- package/src/components/ui/sidebar/panels/settings-panel/interface-theme.test.tsx +20 -0
- package/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx +5 -5
- package/src/components/ui/sidebar/panels/settings-panel/print-export-button.tsx +4 -10
- package/src/components/ui/sidebar/panels/site-panel/building-tree-node.tsx +3 -11
- package/src/components/ui/sidebar/panels/site-panel/ceiling-tree-node.tsx +4 -4
- package/src/components/ui/sidebar/panels/site-panel/chimney-tree-node.tsx +1 -5
- package/src/components/ui/sidebar/panels/site-panel/collection-tree-node.tsx +197 -0
- package/src/components/ui/sidebar/panels/site-panel/column-tree-node.tsx +1 -5
- package/src/components/ui/sidebar/panels/site-panel/door-tree-node.tsx +1 -5
- package/src/components/ui/sidebar/panels/site-panel/dormer-tree-node.tsx +1 -5
- package/src/components/ui/sidebar/panels/site-panel/elevator-tree-node.tsx +1 -5
- package/src/components/ui/sidebar/panels/site-panel/fence-tree-node.tsx +24 -11
- package/src/components/ui/sidebar/panels/site-panel/gutter-tree-node.tsx +1 -5
- package/src/components/ui/sidebar/panels/site-panel/index.tsx +181 -223
- package/src/components/ui/sidebar/panels/site-panel/inline-rename-input.tsx +30 -8
- package/src/components/ui/sidebar/panels/site-panel/item-tree-node.tsx +1 -3
- package/src/components/ui/sidebar/panels/site-panel/level-tree-node.tsx +4 -1
- package/src/components/ui/sidebar/panels/site-panel/registry-tree-node.tsx +1 -3
- package/src/components/ui/sidebar/panels/site-panel/roof-tree-node.tsx +1 -4
- package/src/components/ui/sidebar/panels/site-panel/shelf-tree-node.tsx +1 -3
- package/src/components/ui/sidebar/panels/site-panel/slab-tree-node.tsx +21 -13
- package/src/components/ui/sidebar/panels/site-panel/solar-panel-tree-node.tsx +1 -5
- package/src/components/ui/sidebar/panels/site-panel/spawn-tree-node.tsx +1 -5
- package/src/components/ui/sidebar/panels/site-panel/stair-tree-node.tsx +1 -5
- package/src/components/ui/sidebar/panels/site-panel/tree-node.tsx +13 -37
- package/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx +2 -3
- package/src/components/ui/sidebar/panels/site-panel/wall-tree-node.tsx +1 -5
- package/src/components/ui/sidebar/panels/site-panel/window-tree-node.tsx +1 -5
- package/src/components/ui/sidebar/panels/site-panel/zone-tree-node.tsx +9 -4
- package/src/components/ui/sidebar/panels/zone-panel/index.tsx +2 -4
- package/src/components/ui/sidebar/tab-bar.tsx +14 -4
- package/src/components/ui/sidebar/use-plugin-panels.tsx +15 -5
- package/src/components/viewer/floorplan-compass-button.tsx +9 -1
- package/src/components/viewer/floorplan-preview.tsx +5 -6
- package/src/components/viewer/viewer-controls-bar.tsx +18 -6
- package/src/components/viewer/viewer-hover-label.tsx +34 -0
- package/src/components/viewer/viewer-rooms.tsx +191 -0
- package/src/components/viewer/viewer-scene-header.tsx +181 -145
- package/src/components/viewer/viewer-selection-manager.tsx +124 -0
- package/src/components/viewer/viewer-stage.tsx +2 -2
- package/src/components/viewer-zone-system.tsx +3 -8
- package/src/hooks/use-auto-save.integration.test.tsx +215 -43
- package/src/hooks/use-auto-save.ts +60 -9
- package/src/hooks/use-ceiling-events.test.ts +123 -118
- package/src/hooks/use-grid-events.test.ts +105 -105
- package/src/hooks/use-keyboard.test.ts +243 -19
- package/src/hooks/use-keyboard.ts +118 -83
- package/src/hooks/use-open-wall-ends.test.ts +99 -0
- package/src/hooks/use-open-wall-ends.ts +238 -0
- package/src/hooks/use-placement-notice.test.ts +71 -0
- package/src/hooks/use-placement-notice.ts +73 -0
- package/src/hooks/use-selected-room.ts +143 -0
- package/src/index.tsx +312 -58
- package/src/lib/__fixtures__/owner-victor-seattle-parking.json +1 -0
- package/src/lib/__fixtures__/owner-villa-aurelia-basement.json +1 -0
- package/src/lib/add-storey.test.ts +177 -0
- package/src/lib/add-storey.ts +59 -0
- package/src/lib/below-grade.test.tsx +171 -0
- package/src/lib/below-grade.ts +133 -0
- package/src/lib/camera-facing.test.ts +24 -0
- package/src/lib/camera-facing.ts +24 -0
- package/src/lib/ceiling-edit-session.test.ts +321 -0
- package/src/lib/ceiling-edit-session.ts +206 -0
- package/src/lib/ceiling-region-session.test.ts +179 -0
- package/src/lib/continuation.test.ts +19 -1
- package/src/lib/continuation.ts +25 -4
- package/src/lib/direct-manipulation.ts +2 -0
- package/src/lib/door-interaction.ts +14 -0
- package/src/lib/download-project-file.ts +17 -0
- package/src/lib/editor-level-display.test.ts +96 -0
- package/src/lib/editor-level-display.ts +55 -0
- package/src/lib/editor-views.ts +178 -0
- package/src/lib/export-geometry-wait.test.ts +90 -0
- package/src/lib/export-texture-utils.ts +2 -4
- package/src/lib/floor-edit-session.ts +153 -0
- package/src/lib/floor-footprints.test.ts +563 -0
- package/src/lib/floor-footprints.ts +395 -0
- package/src/lib/floor-foundation-support.test.ts +284 -0
- package/src/lib/floor-opening-draft.ts +218 -0
- package/src/lib/floor-openings.test.ts +216 -0
- package/src/lib/floor-region-geometry.ts +191 -0
- package/src/lib/floor-region-session.test.ts +485 -0
- package/src/lib/floor-region-session.ts +589 -0
- package/src/lib/floor-region-snap.ts +101 -0
- package/src/lib/floor-step-hover.test.ts +32 -0
- package/src/lib/floorplan/annotation-visibility.ts +17 -0
- package/src/lib/floorplan/dimension-drive.test.ts +360 -0
- package/src/lib/floorplan/dimension-drive.ts +479 -0
- package/src/lib/floorplan/floorplan-export.test.ts +12 -8
- package/src/lib/floorplan/floorplan-export.tsx +32 -8
- package/src/lib/floorplan/floorplan-extension.ts +32 -0
- package/src/lib/floorplan/floorplan-mode.test.ts +4 -0
- package/src/lib/floorplan/floorplan-mode.ts +2 -0
- package/src/lib/floorplan/floorplan-pdfkit-document.ts +363 -27
- package/src/lib/floorplan/floorplan-pdfkit-renderer.test.ts +177 -8
- package/src/lib/floorplan/floorplan-pdfkit-renderer.ts +60 -25
- package/src/lib/floorplan/floorplan-plugin-install.test.tsx +138 -0
- package/src/lib/floorplan/floorplan-readonly.ts +6 -0
- package/src/lib/floorplan/geometry.ts +13 -6
- package/src/lib/floorplan/index.ts +0 -9
- package/src/lib/floorplan/items.ts +5 -2
- package/src/lib/floorplan/marks.test.ts +213 -0
- package/src/lib/floorplan/marks.ts +238 -0
- package/src/lib/floorplan/open-wall-ends.test.ts +268 -0
- package/src/lib/floorplan/open-wall-ends.ts +162 -0
- package/src/lib/floorplan/pdf-fonts/GeistMono-Bold.ttf +0 -0
- package/src/lib/floorplan/pdf-fonts/GeistMono-Regular.ttf +0 -0
- package/src/lib/floorplan/pdf-fonts/LICENSE-GeistMono.txt +92 -0
- package/src/lib/floorplan/pdf-fonts/LICENSE-LiberationSans.txt +102 -0
- package/src/lib/floorplan/pdf-fonts/LiberationSans-Bold.ttf +0 -0
- package/src/lib/floorplan/pdf-fonts/LiberationSans-Regular.ttf +0 -0
- package/src/lib/floorplan/pdfkit-standard-fonts.d.ts +5 -0
- package/src/lib/floorplan/schedules.test.ts +189 -0
- package/src/lib/floorplan/schedules.ts +339 -0
- package/src/lib/floorplan/sheet-export.test.ts +124 -0
- package/src/lib/floorplan/sheet-export.ts +318 -0
- package/src/lib/floorplan/site-plan/build-site-plan-drawing.ts +768 -0
- package/src/lib/floorplan/site-plan/contours.test.ts +43 -0
- package/src/lib/floorplan/site-plan/contributors.ts +97 -0
- package/src/lib/floorplan/site-plan/coverage.ts +230 -0
- package/src/lib/floorplan/site-plan/drawing-type-switch.test.ts +15 -0
- package/src/lib/floorplan/site-plan/drawing-type-switch.tsx +86 -0
- package/src/lib/floorplan/site-plan/front-edge.test.ts +103 -0
- package/src/lib/floorplan/site-plan/front-edge.ts +157 -0
- package/src/lib/floorplan/site-plan/geometry.test.ts +269 -0
- package/src/lib/floorplan/site-plan/geometry.ts +142 -0
- package/src/lib/floorplan/site-plan/index.ts +55 -0
- package/src/lib/floorplan/site-plan/site-annotations.test.ts +483 -0
- package/src/lib/floorplan/site-plan/site-annotations.ts +1084 -0
- package/src/lib/floorplan/site-plan/site-parts.ts +287 -0
- package/src/lib/floorplan/site-plan/site-plan-layer.tsx +138 -0
- package/src/lib/floorplan/site-plan/street-name.test.ts +69 -0
- package/src/lib/floorplan/site-plan/street-name.ts +302 -0
- package/src/lib/floorplan/site-plan/yards.test.ts +70 -0
- package/src/lib/floorplan/types.ts +1 -27
- package/src/lib/follow-pascal-exterior.test-fixture.ts +17 -0
- package/src/lib/follow-pascal-exterior.test.ts +171 -0
- package/src/lib/follow-pascal-exterior.ts +39 -0
- package/src/lib/follow-pascal-presentation.test.ts +203 -0
- package/src/lib/follow-pascal-presentation.ts +129 -0
- package/src/lib/follow-pascal-sight.ts +84 -0
- package/src/lib/follow-pascal-targets.test.ts +406 -0
- package/src/lib/follow-pascal-targets.ts +198 -0
- package/src/lib/follow-pascal.test.ts +350 -0
- package/src/lib/follow-pascal.ts +284 -0
- package/src/lib/fresh-planar-placement.test.ts +148 -0
- package/src/lib/fresh-planar-placement.ts +114 -37
- package/src/lib/geometry-script/author.ts +157 -0
- package/src/lib/geometry-script/client.ts +159 -0
- package/src/lib/geometry-script/finish-scripts.ts +127 -0
- package/src/lib/geometry-script/protocol.ts +13 -0
- package/src/lib/gesture-lifecycle.test.ts +595 -0
- package/src/lib/gesture-lifecycle.ts +290 -0
- package/src/lib/glb-export-zone-holes.test.ts +41 -0
- package/src/lib/glb-export.test.ts +636 -126
- package/src/lib/glb-export.ts +241 -120
- package/src/lib/history.test.ts +18 -7
- package/src/lib/history.ts +7 -0
- package/src/lib/hud-title.ts +109 -0
- package/src/lib/hydration-gated-storage.ts +49 -0
- package/src/lib/ifc-export.test.ts +174 -0
- package/src/lib/ifc-export.ts +201 -0
- package/src/lib/ifc-parts.ts +15 -0
- package/src/lib/inspector-expanded.test.ts +44 -0
- package/src/lib/inspector-expanded.ts +36 -0
- package/src/lib/interaction/scope.ts +22 -0
- package/src/lib/keyboard-pan.test.ts +129 -7
- package/src/lib/keyboard-pan.ts +161 -12
- package/src/lib/level-selection.test.ts +57 -0
- package/src/lib/level-selection.ts +16 -1
- package/src/lib/live-gesture-round-trip.test.ts +360 -0
- package/src/lib/lot/__fixtures__/map-dossier-miami-shores.json +1 -0
- package/src/lib/lot/__fixtures__/map-dossier-stpete.json +1 -0
- package/src/lib/lot/clean-ring.test.ts +187 -0
- package/src/lib/lot/clean-ring.ts +217 -0
- package/src/lib/lot/dossier.test.ts +202 -0
- package/src/lib/lot/dossier.ts +498 -0
- package/src/lib/lot/drop-in.test.ts +326 -0
- package/src/lib/lot/drop-in.ts +392 -0
- package/src/lib/lot/index.ts +43 -0
- package/src/lib/lot/lot-patch.test.ts +340 -0
- package/src/lib/lot/lot-patch.ts +394 -0
- package/src/lib/lot/parcel-provider.ts +43 -0
- package/src/lib/lot/terrain.test.ts +161 -0
- package/src/lib/lot/terrain.ts +266 -0
- package/src/lib/material-catalog-model.ts +3 -1
- package/src/lib/material-paint-panel-model.ts +9 -5
- package/src/lib/material-paint.ts +4 -0
- package/src/lib/measurement-kind.test.ts +6 -8
- package/src/lib/measurements.test.ts +23 -0
- package/src/lib/mezzanine-actions.test.ts +342 -0
- package/src/lib/mezzanine-draft.test.ts +501 -0
- package/src/lib/mezzanine-draft.ts +278 -0
- package/src/lib/mezzanine-messages.ts +26 -0
- package/src/lib/mezzanine-selection.test.ts +207 -0
- package/src/lib/mezzanine-stairs.ts +46 -0
- package/src/lib/model-export.ts +3 -1
- package/src/lib/node-action-movement.ts +17 -6
- package/src/lib/node-display-label.ts +37 -0
- package/src/lib/orbit-floor-clearance.test.ts +201 -0
- package/src/lib/orbit-floor-clearance.ts +154 -0
- package/src/lib/paint-commit-route.test.ts +37 -0
- package/src/lib/paint-commit-route.ts +17 -0
- package/src/lib/paint-eyedropper.test.tsx +165 -0
- package/src/lib/paint-eyedropper.ts +99 -0
- package/src/lib/paint-pass-through.test.ts +122 -0
- package/src/lib/paint-pass-through.ts +78 -0
- package/src/lib/paint-region-hover.ts +25 -0
- package/src/lib/paint-region-mode.ts +154 -0
- package/src/lib/paint-regions.test.ts +166 -0
- package/src/lib/paint-regions.ts +192 -0
- package/src/lib/paint-scope.test.ts +317 -35
- package/src/lib/paint-scope.ts +267 -25
- package/src/lib/panel-rows.ts +21 -0
- package/src/lib/parametric-node-update.ts +16 -7
- package/src/lib/plate-paint-affected.test.ts +300 -0
- package/src/lib/plate-paint-affected.ts +177 -0
- package/src/lib/plugin-chat.ts +65 -0
- package/src/lib/plugin-panels.test.ts +25 -0
- package/src/lib/plugin-panels.ts +94 -0
- package/src/lib/point-ask/__fixtures__/consumer-browser.tsx +76 -0
- package/src/lib/point-ask/__fixtures__/house.ts +81 -0
- package/src/lib/point-ask/ask-created.test.ts +195 -0
- package/src/lib/point-ask/ask-flow.test.ts +380 -0
- package/src/lib/point-ask/build-context.test.ts +173 -0
- package/src/lib/point-ask/build-context.ts +94 -0
- package/src/lib/point-ask/capture-crop.ts +129 -0
- package/src/lib/point-ask/choreography.ts +69 -0
- package/src/lib/point-ask/compare.test.ts +145 -0
- package/src/lib/point-ask/compare.ts +73 -0
- package/src/lib/point-ask/describe-target.test.ts +165 -0
- package/src/lib/point-ask/describe-target.ts +234 -0
- package/src/lib/point-ask/dictation.ts +79 -0
- package/src/lib/point-ask/edge-marker.test.ts +61 -0
- package/src/lib/point-ask/edge-marker.ts +27 -0
- package/src/lib/point-ask/frame-loop.ts +25 -0
- package/src/lib/point-ask/history-marks.test.ts +94 -0
- package/src/lib/point-ask/history-marks.ts +39 -0
- package/src/lib/point-ask/host-api.ts +32 -0
- package/src/lib/point-ask/outline-box.test.ts +30 -0
- package/src/lib/point-ask/outline-box.ts +11 -0
- package/src/lib/point-ask/overlay-metrics.ts +6 -0
- package/src/lib/point-ask/pick.test.ts +220 -0
- package/src/lib/point-ask/pick.ts +121 -0
- package/src/lib/point-ask/pin-machine.test.ts +494 -0
- package/src/lib/point-ask/pin-machine.ts +217 -0
- package/src/lib/point-ask/placement.test.ts +203 -0
- package/src/lib/point-ask/placement.ts +141 -0
- package/src/lib/point-ask/pointer-tracker.ts +34 -0
- package/src/lib/point-ask/projector.ts +83 -0
- package/src/lib/point-ask/region.test.ts +157 -0
- package/src/lib/point-ask/region.ts +136 -0
- package/src/lib/point-ask/retry.test.ts +217 -0
- package/src/lib/point-ask/retry.ts +37 -0
- package/src/lib/point-ask/scene-commit.test.ts +312 -0
- package/src/lib/point-ask/scene-commit.ts +32 -0
- package/src/lib/point-ask/session.ts +1391 -0
- package/src/lib/point-ask/spring-keyframes.test.ts +45 -0
- package/src/lib/point-ask/spring-keyframes.ts +38 -0
- package/src/lib/point-ask/spring.test.ts +63 -0
- package/src/lib/point-ask/spring.ts +107 -0
- package/src/lib/point-ask/suggestions.test.ts +80 -0
- package/src/lib/point-ask/suggestions.ts +125 -0
- package/src/lib/point-ask/target-scope.test.ts +622 -0
- package/src/lib/point-ask/target-scope.ts +338 -0
- package/src/lib/point-ask/types.ts +48 -0
- package/src/lib/portable-export.test.ts +34 -1
- package/src/lib/portable-export.ts +119 -53
- package/src/lib/print-feature-thickness.ts +10 -1
- package/src/lib/print-roof-solids.test.ts +39 -1
- package/src/lib/print-roof-solids.ts +43 -10
- package/src/lib/print-shell-compiler-manifold-core.ts +1 -1
- package/src/lib/print-shell-compiler.ts +1 -0
- package/src/lib/registered-draft-snap.ts +12 -0
- package/src/lib/roof-duplication.ts +10 -2
- package/src/lib/room-assembly-overlay.test.ts +275 -0
- package/src/lib/room-assembly-overlay.ts +265 -0
- package/src/lib/room-built-on.test.ts +379 -0
- package/src/lib/room-built-on.ts +138 -0
- package/src/lib/room-construction-commands.ts +712 -0
- package/src/lib/room-construction.test.ts +746 -0
- package/src/lib/room-construction.ts +385 -0
- package/src/lib/room-controls-phase6.test.ts +630 -0
- package/src/lib/room-divide-session.ts +523 -0
- package/src/lib/room-handle-drag.ts +1068 -0
- package/src/lib/room-name-catalog.test.ts +90 -0
- package/src/lib/room-name-catalog.ts +168 -0
- package/src/lib/room-push-dimensions.test.ts +311 -0
- package/src/lib/room-push-dimensions.ts +251 -0
- package/src/lib/room-selection-commands.ts +62 -0
- package/src/lib/room-selection.test.ts +1017 -0
- package/src/lib/room-selection.ts +417 -0
- package/src/lib/room-structure-commands.ts +94 -0
- package/src/lib/room-structure.test.ts +921 -0
- package/src/lib/room-transform-session.ts +570 -0
- package/src/lib/room-zone-routing.test.ts +294 -0
- package/src/lib/room-zone-routing.ts +197 -0
- package/src/lib/scene-clipboard.test.ts +610 -1
- package/src/lib/scene-clipboard.ts +269 -58
- package/src/lib/scene-material-refs.test.ts +79 -0
- package/src/lib/scene-material-refs.ts +79 -0
- package/src/lib/scene.test.ts +24 -36
- package/src/lib/scene.ts +33 -57
- package/src/lib/selection-routing.test.ts +129 -45
- package/src/lib/selection-routing.ts +54 -75
- package/src/lib/session-writes.test.ts +120 -0
- package/src/lib/session-writes.ts +205 -0
- package/src/lib/sfx-bus.ts +13 -0
- package/src/lib/sfx-player.test.ts +70 -9
- package/src/lib/sfx-player.ts +6 -0
- package/src/lib/sidebar-panel.ts +62 -0
- package/src/lib/site-boundary.test.ts +4 -6
- package/src/lib/site-boundary.ts +1 -1
- package/src/lib/snapping-mode.test.ts +4 -0
- package/src/lib/snapping-mode.ts +8 -1
- package/src/lib/stair-levels.test.ts +25 -0
- package/src/lib/stair-levels.ts +22 -3
- package/src/lib/terrace-draft.test.ts +145 -0
- package/src/lib/terrace-draft.ts +214 -0
- package/src/lib/tool-cursor-icon.test.ts +16 -0
- package/src/lib/tool-cursor-icon.ts +11 -0
- package/src/lib/typing-target.ts +9 -0
- package/src/lib/units.ts +77 -39
- package/src/lib/vector-edges.test.ts +58 -0
- package/src/lib/vector-edges.ts +400 -0
- package/src/lib/viewer-selection.test.ts +577 -0
- package/src/lib/viewer-selection.ts +580 -0
- package/src/lib/wall-draw-variant.test.ts +71 -0
- package/src/lib/wall-draw-variant.ts +91 -0
- package/src/lib/wall-paint-region-session.ts +246 -0
- package/src/lib/wall-paint-region.test.ts +373 -0
- package/src/lib/wall-placement-pointer.test.ts +42 -0
- package/src/lib/wall-placement-pointer.ts +57 -0
- package/src/lib/wall-polygon-draft.test.ts +262 -0
- package/src/lib/wall-polygon-draft.ts +286 -0
- package/src/lib/wall-push.test.ts +453 -0
- package/src/lib/wall-region-face.ts +352 -0
- package/src/lib/wall-region-handles.test.ts +304 -0
- package/src/lib/wall-region-handles.ts +368 -0
- package/src/lib/wall-region-list.test.ts +119 -0
- package/src/lib/wall-region-list.ts +136 -0
- package/src/lib/wall-region-snap.ts +110 -0
- package/src/lib/window-changes.ts +35 -0
- package/src/lib/window-interaction.ts +14 -0
- package/src/lib/zone-content.ts +4 -1
- package/src/lib/zone-name.test.ts +17 -0
- package/src/lib/zone-name.ts +17 -0
- package/src/store/opens-in-select-mode.test.ts +223 -0
- package/src/store/paint-mode.test.ts +188 -0
- package/src/store/terrain-sculpt-mode.test.ts +19 -21
- package/src/store/tool-mode.test.ts +137 -6
- package/src/store/use-audio.test.ts +146 -0
- package/src/store/use-audio.tsx +127 -3
- package/src/store/use-construction-reveal.test.ts +173 -0
- package/src/store/use-construction-reveal.ts +145 -0
- package/src/store/use-corner-snap-hint.test.ts +24 -0
- package/src/store/use-corner-snap-hint.ts +47 -0
- package/src/store/use-delete-confirmation.ts +28 -1
- package/src/store/use-drawing-view.test.ts +24 -3
- package/src/store/use-drawing-view.ts +29 -1
- package/src/store/use-editor.tsx +432 -321
- package/src/store/use-floorplan-draft-preview.ts +13 -0
- package/src/store/use-floorplan-marquee.ts +12 -2
- package/src/store/use-follow-pascal.test.ts +62 -0
- package/src/store/use-follow-pascal.ts +53 -0
- package/src/store/use-point-ask.ts +247 -0
- package/src/store/use-quick-measurement-hud.ts +3 -3
- package/src/store/use-stair-build-preview.ts +33 -5
- package/src/store/use-wall-move-ghosts.ts +4 -2
- package/src/store/use-wall-region-handles-selection.test.ts +222 -0
- package/src/store/use-wall-region-handles-selection.ts +139 -0
- package/src/store/view-layout.test.ts +201 -0
- package/src/store/view-layout.ts +199 -0
- package/src/test-utils/immediate-animation-frames.ts +16 -0
- package/src/test-utils/live-gesture-round-trip.ts +224 -0
- package/src/test-utils/render-current-markup.tsx +16 -0
- package/src/test-utils/selection-harness.ts +82 -0
- package/src/components/editor-2d/renderers/floorplan-stair-layer.tsx +0 -499
- package/src/components/systems/zone/zone-label-editor-system.tsx +0 -333
- package/src/components/tools/fence/fence-drafting.test.ts +0 -100
- package/src/components/tools/fence/fence-drafting.ts +0 -266
- package/src/components/tools/stair/stair-click-guard.test.ts +0 -58
- package/src/components/tools/stair/stair-click-guard.ts +0 -72
- package/src/components/tools/stair/stair-defaults.ts +0 -18
- package/src/components/tools/stair/stair-tool.tsx +0 -634
- package/src/components/ui/sidebar/panels/plugins-panel.tsx +0 -218
- package/src/components/viewer/viewer-units-panel.tsx +0 -116
- package/src/lib/floorplan/stairs.ts +0 -489
- package/src/lib/level-duplication.test.ts +0 -144
- package/src/lib/level-duplication.ts +0 -195
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
type AlignmentAnchor,
|
|
4
4
|
type AnyNode,
|
|
5
5
|
type AnyNodeId,
|
|
6
|
+
beginSceneHistoryPauseSession,
|
|
6
7
|
type CeilingEvent,
|
|
7
8
|
canHostSurfaceChild,
|
|
8
9
|
collectAlignmentAnchors,
|
|
@@ -10,6 +11,8 @@ import {
|
|
|
10
11
|
findLevelAncestorId,
|
|
11
12
|
type GridEvent,
|
|
12
13
|
getScaledDimensions,
|
|
14
|
+
getWallBodyCenterOffset,
|
|
15
|
+
getWallLocalFaceZ,
|
|
13
16
|
type ItemEvent,
|
|
14
17
|
movingFootprintAnchors,
|
|
15
18
|
type NodeEvent,
|
|
@@ -25,7 +28,6 @@ import {
|
|
|
25
28
|
useScene,
|
|
26
29
|
useSpatialQuery,
|
|
27
30
|
type WallEvent,
|
|
28
|
-
type WallNode,
|
|
29
31
|
} from '@pascal-app/core'
|
|
30
32
|
import { useViewer } from '@pascal-app/viewer'
|
|
31
33
|
import { Html } from '@react-three/drei'
|
|
@@ -55,8 +57,10 @@ import { sfxEmitter } from '../../../lib/sfx-bus'
|
|
|
55
57
|
import {
|
|
56
58
|
surfaceAttachmentId,
|
|
57
59
|
surfaceFramePose,
|
|
58
|
-
updateSurfaceNode,
|
|
60
|
+
updateSurfaceNode as writeSurfaceNode,
|
|
59
61
|
} from '../../../lib/surface-attachment'
|
|
62
|
+
import { isTypingTarget } from '../../../lib/typing-target'
|
|
63
|
+
import { createWallPointerTracker } from '../../../lib/wall-placement-pointer'
|
|
60
64
|
import {
|
|
61
65
|
projectAlignmentGuidesWorldToActiveBuildingLocal,
|
|
62
66
|
resolveAlignmentForActiveBuilding,
|
|
@@ -68,6 +72,7 @@ import useEditor, {
|
|
|
68
72
|
isMagneticSnapActive,
|
|
69
73
|
} from '../../../store/use-editor'
|
|
70
74
|
import useFacingPose from '../../../store/use-facing-pose'
|
|
75
|
+
import { getMovingNode } from '../../../store/use-interaction-scope'
|
|
71
76
|
import usePlacementPreview from '../../../store/use-placement-preview'
|
|
72
77
|
import {
|
|
73
78
|
createItemSurfaceGridDispatch,
|
|
@@ -99,6 +104,7 @@ import {
|
|
|
99
104
|
import {
|
|
100
105
|
getDetachedAttachmentPreviewLift,
|
|
101
106
|
getGridAlignedDimensions,
|
|
107
|
+
getSideFromNormal,
|
|
102
108
|
snapToGrid,
|
|
103
109
|
snapToHalf,
|
|
104
110
|
snapUpToGridStep,
|
|
@@ -116,7 +122,7 @@ import {
|
|
|
116
122
|
} from './placement-strategies'
|
|
117
123
|
import { resolveItemPlacementSurfaceNormal } from './placement-surface'
|
|
118
124
|
import type { PlacementState, TransitionResult } from './placement-types'
|
|
119
|
-
import type
|
|
125
|
+
import { type DraftNodeHandle, type ItemCopy, pausedDraftWrite } from './use-draft-node'
|
|
120
126
|
|
|
121
127
|
const DEFAULT_DIMENSIONS: [number, number, number] = [1, 1, 1]
|
|
122
128
|
|
|
@@ -262,20 +268,20 @@ basePlaneMaterial.opacityNode = radialOpacity
|
|
|
262
268
|
|
|
263
269
|
export interface PlacementCoordinatorConfig {
|
|
264
270
|
asset: AssetInput | null
|
|
271
|
+
/** Scale to use when lazily creating a draft (e.g. for wall/ceiling duplicates). Defaults to [1,1,1]. */
|
|
272
|
+
defaultScale?: [number, number, number]
|
|
265
273
|
draftNode: DraftNodeHandle
|
|
266
274
|
initDraft: (gridPosition: Vector3) => void
|
|
267
|
-
onCommitted: () => boolean
|
|
268
|
-
onCancel?: () => void
|
|
269
275
|
initialState?: PlacementState
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
/** Painted slot overrides to seed onto a lazily-created draft (wall/ceiling
|
|
273
|
-
* duplicates) so the duplicate keeps its materials. */
|
|
274
|
-
slots?: ItemNode['slots']
|
|
276
|
+
onCancel?: () => void
|
|
277
|
+
onCommitted: () => boolean
|
|
275
278
|
/** Move-mode sessions keep the grabbed item offset from the first surface hit
|
|
276
279
|
* (floor / wall / ceiling / item-surface / shelf) instead of snapping the
|
|
277
280
|
* item's origin under the cursor. */
|
|
278
281
|
preserveDragOffset?: boolean
|
|
282
|
+
/** The item a duplicate copies, for a lazily-created draft (wall/ceiling
|
|
283
|
+
* duplicates) to keep its materials and collections. */
|
|
284
|
+
copied?: ItemCopy
|
|
279
285
|
}
|
|
280
286
|
|
|
281
287
|
export function usePlacementCoordinator(config: PlacementCoordinatorConfig): React.ReactNode {
|
|
@@ -528,7 +534,14 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
|
|
|
528
534
|
|
|
529
535
|
useEffect(() => {
|
|
530
536
|
if (!asset) return
|
|
531
|
-
|
|
537
|
+
// History is paused only around the placement's own writes, never for the whole carry:
|
|
538
|
+
// the draft stays out of history snapshots (core's history-drafts), so writes others make
|
|
539
|
+
// mid-carry record as their own steps, with space detection. In split view the 2D move
|
|
540
|
+
// overlay co-owns the gesture (keyed by the moving node), and the drop's commitStep lifts
|
|
541
|
+
// its pause too.
|
|
542
|
+
const movingNodeId = getMovingNode()?.id
|
|
543
|
+
const updateSurfaceNode: typeof writeSurfaceNode = (...args) =>
|
|
544
|
+
pausedDraftWrite(() => writeSurfaceNode(...args))
|
|
532
545
|
|
|
533
546
|
const validators = { canPlaceOnFloor, canPlaceOnWall, canPlaceOnCeiling }
|
|
534
547
|
|
|
@@ -596,6 +609,29 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
|
|
|
596
609
|
if (mesh) reconcileDraftRaycast(mesh)
|
|
597
610
|
}
|
|
598
611
|
|
|
612
|
+
// Eat the click the browser fires after a pointer-up that committed, so it
|
|
613
|
+
// neither commits a second time through a surface `:click` handler nor reaches
|
|
614
|
+
// the grid, in select mode by then, as a click on empty ground.
|
|
615
|
+
const swallowNextClick = () => {
|
|
616
|
+
const swallow = (e: Event) => {
|
|
617
|
+
e.stopPropagation()
|
|
618
|
+
e.preventDefault()
|
|
619
|
+
}
|
|
620
|
+
window.addEventListener('click', swallow, { capture: true, once: true })
|
|
621
|
+
setTimeout(() => window.removeEventListener('click', swallow, { capture: true }), 300)
|
|
622
|
+
}
|
|
623
|
+
// True between a press's pointer-up and the click the browser fires after it.
|
|
624
|
+
// Surface `:click` events are synthesized on pointer-up (use-node-events), so a
|
|
625
|
+
// commit they trigger still has that click to come; a `grid:click` commit is
|
|
626
|
+
// that click.
|
|
627
|
+
let releasing = false
|
|
628
|
+
const onPointerUpCapture = () => {
|
|
629
|
+
releasing = true
|
|
630
|
+
}
|
|
631
|
+
const onClickCapture = () => {
|
|
632
|
+
releasing = false
|
|
633
|
+
}
|
|
634
|
+
|
|
599
635
|
const finishCommittedPlacement = (
|
|
600
636
|
committedId: string | null,
|
|
601
637
|
wasAdopted: boolean,
|
|
@@ -608,7 +644,6 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
|
|
|
608
644
|
}
|
|
609
645
|
|
|
610
646
|
useAlignmentGuides.getState().clear()
|
|
611
|
-
useScene.temporal.getState().resume()
|
|
612
647
|
if (committedId) {
|
|
613
648
|
useViewer.getState().setSelection({ selectedIds: [committedId as AnyNodeId] })
|
|
614
649
|
}
|
|
@@ -619,6 +654,7 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
|
|
|
619
654
|
// lands on the just-placed (now selected) node instead of a tool-less build
|
|
620
655
|
// limbo. Repeat placements took the early return above and stay armed.
|
|
621
656
|
useEditor.getState().setMode('select')
|
|
657
|
+
if (releasing) swallowNextClick()
|
|
622
658
|
}
|
|
623
659
|
|
|
624
660
|
const commitDraft = (
|
|
@@ -631,14 +667,22 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
|
|
|
631
667
|
) => {
|
|
632
668
|
const draftId = draftNode.current?.id ?? null
|
|
633
669
|
const wasAdopted = draftNode.isAdopted
|
|
634
|
-
const
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
670
|
+
const drop = beginSceneHistoryPauseSession(useScene, { gesture: movingNodeId })
|
|
671
|
+
let finalId: string | null
|
|
672
|
+
try {
|
|
673
|
+
finalId = drop.commitStep(() =>
|
|
674
|
+
draftNode.commit(nodeUpdate, {
|
|
675
|
+
...options,
|
|
676
|
+
onReject: (reason) => {
|
|
677
|
+
feedback.reject(reason)
|
|
678
|
+
edgeMaterial.color.setHex(0xef_44_44)
|
|
679
|
+
basePlaneMaterial.color.setHex(0xef_44_44)
|
|
680
|
+
},
|
|
681
|
+
}),
|
|
682
|
+
)
|
|
683
|
+
} finally {
|
|
684
|
+
drop.end()
|
|
685
|
+
}
|
|
642
686
|
if (finalId && draftId) {
|
|
643
687
|
useLiveTransforms.getState().clear(draftId)
|
|
644
688
|
useLiveNodeOverrides.getState().clearFields(draftId, faceHostClearFields(draftNode.current))
|
|
@@ -780,10 +824,13 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
|
|
|
780
824
|
// Alignment guides are floor-only; clear them when the cursor moves
|
|
781
825
|
// onto a wall / ceiling / item surface (only those paths call this).
|
|
782
826
|
useAlignmentGuides.getState().clear()
|
|
783
|
-
//
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
827
|
+
// A floor transition can be a hit gap; other hosted surfaces are a new anchor.
|
|
828
|
+
if (
|
|
829
|
+
result.stateUpdate.surface &&
|
|
830
|
+
result.stateUpdate.surface !== 'floor' &&
|
|
831
|
+
result.stateUpdate.surface !== 'wall'
|
|
832
|
+
)
|
|
833
|
+
grabForgotten = true
|
|
787
834
|
Object.assign(placementState.current, result.stateUpdate)
|
|
788
835
|
gridPosition.current.set(...result.gridPosition)
|
|
789
836
|
|
|
@@ -832,16 +879,15 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
|
|
|
832
879
|
asset,
|
|
833
880
|
initRotation,
|
|
834
881
|
configRef.current.defaultScale,
|
|
835
|
-
configRef.current.
|
|
882
|
+
configRef.current.copied,
|
|
836
883
|
)
|
|
837
884
|
|
|
838
885
|
const draft = draftNode.current
|
|
839
886
|
if (draft) {
|
|
840
887
|
Object.assign(draft, result.nodeUpdate)
|
|
841
888
|
// One-time setup: put node in the right parent so it renders correctly
|
|
842
|
-
if (result.surfaceId
|
|
843
|
-
|
|
844
|
-
else updateSurfaceNode(draft.id, result.nodeUpdate)
|
|
889
|
+
if (result.surfaceId === undefined) updateSurfaceNode(draft.id, result.nodeUpdate)
|
|
890
|
+
else draftNode.updateSurface(result.nodeUpdate, result.surfaceId)
|
|
845
891
|
disableDraftRaycastNow()
|
|
846
892
|
}
|
|
847
893
|
|
|
@@ -908,15 +954,12 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
|
|
|
908
954
|
// for a given host, then offsets every later move by
|
|
909
955
|
// `start + (raw - anchor)` — mirroring the floor path and the door/window
|
|
910
956
|
// move tools so the item tracks the grabbed point instead of teleporting
|
|
911
|
-
// its origin under the cursor.
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
startX: number
|
|
918
|
-
startY: number
|
|
919
|
-
} | null = null
|
|
957
|
+
// its origin under the cursor. Changing hosts or faces clears the offset.
|
|
958
|
+
const wallPointer = createWallPointerTracker(
|
|
959
|
+
preserveDragOffset && grabStartPosition
|
|
960
|
+
? { wallId: grabWallId, side: draftNode.current?.side, position: grabStartPosition }
|
|
961
|
+
: undefined,
|
|
962
|
+
)
|
|
920
963
|
let ceilingDragAnchor: {
|
|
921
964
|
ceilingId: string
|
|
922
965
|
rawX: number
|
|
@@ -1037,16 +1080,6 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
|
|
|
1037
1080
|
// replays it. Captured once at setup — a fresh coordinator mounts per move.
|
|
1038
1081
|
const dragMode = useEditor.getState().placementDragMode
|
|
1039
1082
|
let releaseCommit: (() => void) | null = null
|
|
1040
|
-
// Eat the click the browser fires after pointer-up so the surface
|
|
1041
|
-
// `:click` handlers don't commit a second time.
|
|
1042
|
-
const swallowNextClick = () => {
|
|
1043
|
-
const swallow = (e: Event) => {
|
|
1044
|
-
e.stopPropagation()
|
|
1045
|
-
e.preventDefault()
|
|
1046
|
-
}
|
|
1047
|
-
window.addEventListener('click', swallow, { capture: true, once: true })
|
|
1048
|
-
setTimeout(() => window.removeEventListener('click', swallow, { capture: true }), 300)
|
|
1049
|
-
}
|
|
1050
1083
|
const onReleaseCommit = () => {
|
|
1051
1084
|
gridDispatch.flush()
|
|
1052
1085
|
if (!releaseCommit) return
|
|
@@ -1134,6 +1167,8 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
|
|
|
1134
1167
|
if (!cursorGroupRef.current) return
|
|
1135
1168
|
const result = floorStrategy.move(getContext(), floorEvent)
|
|
1136
1169
|
if (!result) return
|
|
1170
|
+
// Attached items cannot land on the floor; its hit can be a gap in their host.
|
|
1171
|
+
if (!asset.attachTo) grabForgotten = true
|
|
1137
1172
|
|
|
1138
1173
|
// Figma-style alignment snap layered on top of the floor strategy's
|
|
1139
1174
|
// grid snap: when the draft's edge lines up (on X or Z) with another
|
|
@@ -1276,7 +1311,7 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
|
|
|
1276
1311
|
asset,
|
|
1277
1312
|
currentRotation,
|
|
1278
1313
|
configRef.current.defaultScale,
|
|
1279
|
-
configRef.current.
|
|
1314
|
+
configRef.current.copied,
|
|
1280
1315
|
)
|
|
1281
1316
|
const previewBounds = expandBoundsToGrid(
|
|
1282
1317
|
getFallbackPreviewBounds(draftNode.current, asset, asset.attachTo),
|
|
@@ -1363,28 +1398,13 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
|
|
|
1363
1398
|
|
|
1364
1399
|
let wallMoveEvent = event
|
|
1365
1400
|
if (preserveDragOffset && draftNode.current) {
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
// re-seeding from the carried-over position (the old behavior)
|
|
1374
|
-
// baked an arbitrary along-wall offset into the whole stay on that
|
|
1375
|
-
// wall. Once anchored elsewhere the grab is forgotten for good, so
|
|
1376
|
-
// re-entering the original wall centers under the cursor too.
|
|
1377
|
-
const preserveGrab = preserveGrabOn(event.node.id, grabWallId)
|
|
1378
|
-
wallDragAnchor = {
|
|
1379
|
-
wallId: event.node.id,
|
|
1380
|
-
rawX,
|
|
1381
|
-
rawY,
|
|
1382
|
-
startX: preserveGrab && grabStartPosition ? grabStartPosition[0] : rawX,
|
|
1383
|
-
startY: preserveGrab && grabStartPosition ? grabStartPosition[1] : rawY,
|
|
1384
|
-
}
|
|
1385
|
-
}
|
|
1386
|
-
const correctedX = wallDragAnchor.startX + (rawX - wallDragAnchor.rawX)
|
|
1387
|
-
const correctedY = wallDragAnchor.startY + (rawY - wallDragAnchor.rawY)
|
|
1401
|
+
preserveGrabOn(event.node.id, grabWallId)
|
|
1402
|
+
if (grabForgotten) wallPointer.forget()
|
|
1403
|
+
const [correctedX, correctedY] = wallPointer.resolve(
|
|
1404
|
+
event.node.id,
|
|
1405
|
+
getSideFromNormal(event.normal),
|
|
1406
|
+
[event.localPosition[0], event.localPosition[1]],
|
|
1407
|
+
)
|
|
1388
1408
|
wallMoveEvent = {
|
|
1389
1409
|
...event,
|
|
1390
1410
|
localPosition: [correctedX, correctedY, event.localPosition[2]],
|
|
@@ -1427,12 +1447,13 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
|
|
|
1427
1447
|
const rot = result.nodeUpdate?.rotation
|
|
1428
1448
|
if (rot) mesh.rotation.y = rot[1]
|
|
1429
1449
|
|
|
1430
|
-
|
|
1431
|
-
if (asset.attachTo === 'wall-side' && placementState.current.wallId) {
|
|
1450
|
+
if (placementState.current.wallId) {
|
|
1432
1451
|
const parentWall = useScene.getState().nodes[placementState.current.wallId as AnyNodeId]
|
|
1433
1452
|
if (parentWall?.type === 'wall') {
|
|
1434
|
-
|
|
1435
|
-
|
|
1453
|
+
mesh.position.z =
|
|
1454
|
+
asset.attachTo === 'wall-side'
|
|
1455
|
+
? getWallLocalFaceZ(parentWall, draft.side === 'front' ? 'a' : 'b')
|
|
1456
|
+
: draft.position[2] + getWallBodyCenterOffset(parentWall)
|
|
1436
1457
|
}
|
|
1437
1458
|
}
|
|
1438
1459
|
}
|
|
@@ -1486,7 +1507,7 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
|
|
|
1486
1507
|
}
|
|
1487
1508
|
|
|
1488
1509
|
const onWallLeave = (event: WallEvent) => {
|
|
1489
|
-
|
|
1510
|
+
wallPointer.leave()
|
|
1490
1511
|
const result = wallStrategy.leave(getContext())
|
|
1491
1512
|
if (!result) return
|
|
1492
1513
|
|
|
@@ -1600,7 +1621,7 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
|
|
|
1600
1621
|
const segment =
|
|
1601
1622
|
useScene.getState().nodes[placementState.current.roofSegmentId as AnyNodeId]
|
|
1602
1623
|
if (segment?.type === 'roof-segment') {
|
|
1603
|
-
mesh.position.z = (segment.wallThickness ?? 0.1
|
|
1624
|
+
mesh.position.z = getWallLocalFaceZ({ thickness: segment.wallThickness ?? 0.1 }, 'a')
|
|
1604
1625
|
}
|
|
1605
1626
|
}
|
|
1606
1627
|
const rot = result.nodeUpdate?.rotation
|
|
@@ -1640,10 +1661,12 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
|
|
|
1640
1661
|
applyTransition(result)
|
|
1641
1662
|
const draft = draftNode.current
|
|
1642
1663
|
if (draft) {
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1664
|
+
pausedDraftWrite(() =>
|
|
1665
|
+
useScene.getState().updateNode(draft.id, {
|
|
1666
|
+
parentId: result.nodeUpdate.parentId as string,
|
|
1667
|
+
roofSegmentId: undefined,
|
|
1668
|
+
}),
|
|
1669
|
+
)
|
|
1647
1670
|
}
|
|
1648
1671
|
} else {
|
|
1649
1672
|
// Create mode: destroy transient and reset state
|
|
@@ -1758,7 +1781,8 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
|
|
|
1758
1781
|
}
|
|
1759
1782
|
if (draftNode.isAdopted) {
|
|
1760
1783
|
applyTransition(result)
|
|
1761
|
-
if (draft)
|
|
1784
|
+
if (draft)
|
|
1785
|
+
pausedDraftWrite(() => useScene.getState().updateNode(draft.id, result.nodeUpdate))
|
|
1762
1786
|
} else {
|
|
1763
1787
|
draftNode.destroy()
|
|
1764
1788
|
gridPosition.current.set(...result.gridPosition)
|
|
@@ -1863,6 +1887,8 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
|
|
|
1863
1887
|
}
|
|
1864
1888
|
if (event.node.id === draftNode.current?.id) return
|
|
1865
1889
|
has3DPointerDrivenMoveRef.current = true
|
|
1890
|
+
// An authored object's underside takes ceiling items (a pendant under a vault).
|
|
1891
|
+
if (enterFaceHost(event)) return
|
|
1866
1892
|
const result = itemSurfaceStrategy.enter(surfaceContext(event, generic), event)
|
|
1867
1893
|
if (!result) return
|
|
1868
1894
|
feedback.clear()
|
|
@@ -1880,6 +1906,17 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
|
|
|
1880
1906
|
|
|
1881
1907
|
const onItemMove = (event: NodeEvent<AnyNode>, generic = false) => {
|
|
1882
1908
|
if (event.node.id === draftNode.current?.id) return
|
|
1909
|
+
if (
|
|
1910
|
+
placementState.current.surface === 'block-face' &&
|
|
1911
|
+
placementState.current.blockId === event.node.id
|
|
1912
|
+
) {
|
|
1913
|
+
onFaceHostMove(event)
|
|
1914
|
+
return
|
|
1915
|
+
}
|
|
1916
|
+
if (placementState.current.surface !== 'block-face' && enterFaceHost(event)) {
|
|
1917
|
+
releaseCommit = () => onFaceHostClick(event)
|
|
1918
|
+
return
|
|
1919
|
+
}
|
|
1883
1920
|
releaseCommit = () => onItemClick(event)
|
|
1884
1921
|
has3DPointerDrivenMoveRef.current = true
|
|
1885
1922
|
if (!cursorGroupRef.current) return
|
|
@@ -1931,9 +1968,9 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
|
|
|
1931
1968
|
}
|
|
1932
1969
|
|
|
1933
1970
|
const surfaceWorld =
|
|
1934
|
-
ctx.state.surfaceItemId
|
|
1935
|
-
?
|
|
1936
|
-
:
|
|
1971
|
+
ctx.state.surfaceItemId === null
|
|
1972
|
+
? null
|
|
1973
|
+
: resolveHostSurfaceWorld(ctx.state.surfaceItemId, event.position)
|
|
1937
1974
|
const itemMoveEvent = surfaceWorld ? { ...event, position: surfaceWorld } : event
|
|
1938
1975
|
lastRawPos.current.set(
|
|
1939
1976
|
itemMoveEvent.position[0],
|
|
@@ -1980,6 +2017,13 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
|
|
|
1980
2017
|
const onItemLeave = (event: NodeEvent<AnyNode>) => {
|
|
1981
2018
|
if (event.node.type === 'cabinet') return
|
|
1982
2019
|
if (event.node.id === draftNode.current?.id) return
|
|
2020
|
+
if (
|
|
2021
|
+
placementState.current.surface === 'block-face' &&
|
|
2022
|
+
placementState.current.blockId === event.node.id
|
|
2023
|
+
) {
|
|
2024
|
+
onFaceHostLeave(event)
|
|
2025
|
+
return
|
|
2026
|
+
}
|
|
1983
2027
|
if (placementState.current.surface !== 'item-surface') return
|
|
1984
2028
|
|
|
1985
2029
|
event.stopPropagation()
|
|
@@ -1995,6 +2039,13 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
|
|
|
1995
2039
|
const onItemClick = (event: NodeEvent<AnyNode>) => {
|
|
1996
2040
|
gridDispatch.flush()
|
|
1997
2041
|
if (feedback.reason) return
|
|
2042
|
+
if (
|
|
2043
|
+
placementState.current.surface === 'block-face' &&
|
|
2044
|
+
placementState.current.blockId === event.node.id
|
|
2045
|
+
) {
|
|
2046
|
+
onFaceHostClick(event)
|
|
2047
|
+
return
|
|
2048
|
+
}
|
|
1998
2049
|
// Click on the draft item itself. R3F dispatches click events to
|
|
1999
2050
|
// the closest intersected mesh only — when the draft is hovering
|
|
2000
2051
|
// on a host (shelf / table / etc.) the draft's mesh is *above*
|
|
@@ -2309,9 +2360,9 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
|
|
|
2309
2360
|
return
|
|
2310
2361
|
}
|
|
2311
2362
|
const shelfWorld =
|
|
2312
|
-
ctx.state.shelfId
|
|
2313
|
-
?
|
|
2314
|
-
:
|
|
2363
|
+
ctx.state.shelfId === null
|
|
2364
|
+
? null
|
|
2365
|
+
: resolveHostSurfaceWorld(ctx.state.shelfId, event.position)
|
|
2315
2366
|
const shelfMoveEvent = shelfWorld ? { ...event, position: shelfWorld } : event
|
|
2316
2367
|
const result = shelfSurfaceStrategy.move(ctx, shelfMoveEvent)
|
|
2317
2368
|
if (!result) return
|
|
@@ -2385,9 +2436,7 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
|
|
|
2385
2436
|
}
|
|
2386
2437
|
|
|
2387
2438
|
// Don't intercept keys when focus is inside a text input
|
|
2388
|
-
if (event.target
|
|
2389
|
-
return
|
|
2390
|
-
}
|
|
2439
|
+
if (isTypingTarget(event.target)) return
|
|
2391
2440
|
|
|
2392
2441
|
const draft = draftNode.current
|
|
2393
2442
|
if (!draft) return
|
|
@@ -2613,7 +2662,7 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
|
|
|
2613
2662
|
if (event.button !== 2) return
|
|
2614
2663
|
const down = rightDown
|
|
2615
2664
|
rightDown = null
|
|
2616
|
-
if (!down
|
|
2665
|
+
if (!(down && configRef.current.onCancel)) return
|
|
2617
2666
|
const movedSq = (event.clientX - down.x) ** 2 + (event.clientY - down.y) ** 2
|
|
2618
2667
|
const elapsed = performance.now() - down.t
|
|
2619
2668
|
if (movedSq <= RIGHT_CLICK_CANCEL_MAX_MOVE_PX ** 2 && elapsed <= RIGHT_CLICK_CANCEL_MAX_MS) {
|
|
@@ -2662,8 +2711,7 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
|
|
|
2662
2711
|
const draft = draftNode.current
|
|
2663
2712
|
if (draft === null) return
|
|
2664
2713
|
if (draft.id in useScene.getState().nodes) return
|
|
2665
|
-
|
|
2666
|
-
useScene.getState().createNode(draft, draft.parentId as AnyNodeId)
|
|
2714
|
+
pausedDraftWrite(() => useScene.getState().createNode(draft, draft.parentId as AnyNodeId))
|
|
2667
2715
|
})
|
|
2668
2716
|
})
|
|
2669
2717
|
|
|
@@ -2752,11 +2800,15 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
|
|
|
2752
2800
|
}
|
|
2753
2801
|
emitter.on('node:click', commitFloorOnSurfaceClick as never)
|
|
2754
2802
|
if (dragMode) window.addEventListener('pointerup', onReleaseCommit)
|
|
2803
|
+
window.addEventListener('pointerup', onPointerUpCapture, true)
|
|
2804
|
+
window.addEventListener('click', onClickCapture, true)
|
|
2755
2805
|
|
|
2756
2806
|
return () => {
|
|
2757
2807
|
tearingDown = true
|
|
2758
2808
|
feedback.clear()
|
|
2759
2809
|
if (dragMode) window.removeEventListener('pointerup', onReleaseCommit)
|
|
2810
|
+
window.removeEventListener('pointerup', onPointerUpCapture, true)
|
|
2811
|
+
window.removeEventListener('click', onClickCapture, true)
|
|
2760
2812
|
unsubDraftWatch()
|
|
2761
2813
|
useAlignmentGuides.getState().clear()
|
|
2762
2814
|
// Clear every live preview channel before restoring or deleting the draft.
|
|
@@ -2765,7 +2817,6 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
|
|
|
2765
2817
|
useLiveNodeOverrides.getState().clearFields(draftNode.current.id, ['rotation'])
|
|
2766
2818
|
}
|
|
2767
2819
|
draftNode.destroy()
|
|
2768
|
-
useScene.temporal.getState().resume()
|
|
2769
2820
|
gridDispatch.cancel()
|
|
2770
2821
|
emitter.off('grid:move', gridDispatch.schedule)
|
|
2771
2822
|
emitter.off('grid:click', onGridClick)
|
|
@@ -2862,7 +2913,9 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
|
|
|
2862
2913
|
)
|
|
2863
2914
|
return
|
|
2864
2915
|
draft.parentId = viewerLevelId
|
|
2865
|
-
|
|
2916
|
+
pausedDraftWrite(() =>
|
|
2917
|
+
useScene.getState().updateNode(draft.id as AnyNodeId, { parentId: viewerLevelId }),
|
|
2918
|
+
)
|
|
2866
2919
|
}, [viewerLevelId, draftNode, asset])
|
|
2867
2920
|
|
|
2868
2921
|
// Restore the draft mesh's raycast when the coordinator unmounts (tool change).
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getCatalogMaterialById,
|
|
3
|
+
parseMaterialRef,
|
|
4
|
+
type SceneMaterialId,
|
|
5
|
+
useScene,
|
|
6
|
+
} from '@pascal-app/core'
|
|
7
|
+
import { useMemo } from 'react'
|
|
8
|
+
import { usePaintRegionMode } from '../../../lib/paint-region-mode'
|
|
9
|
+
import useEditor from '../../../store/use-editor'
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* The paint material's colour for a region preview: a library preset's
|
|
13
|
+
* preview colour, a scene material's colour, or a plain material colour;
|
|
14
|
+
* `fallback` for the eraser or a material with no cheap colour.
|
|
15
|
+
*/
|
|
16
|
+
export function usePaintTint(fallback: string): string {
|
|
17
|
+
const active = useEditor((state) => state.activePaintMaterial)
|
|
18
|
+
const eraser = usePaintRegionMode((state) => state.mode) === 'erase'
|
|
19
|
+
const materials = useScene((state) => state.materials)
|
|
20
|
+
return useMemo(() => {
|
|
21
|
+
if (eraser) return fallback
|
|
22
|
+
const parsed = parseMaterialRef(active?.materialPreset)
|
|
23
|
+
if (parsed?.kind === 'library') {
|
|
24
|
+
const color = getCatalogMaterialById(parsed.id)?.previewColor
|
|
25
|
+
if (color) return color
|
|
26
|
+
}
|
|
27
|
+
if (parsed?.kind === 'scene') {
|
|
28
|
+
const color = materials[parsed.id as SceneMaterialId]?.material.properties?.color
|
|
29
|
+
if (color) return color
|
|
30
|
+
}
|
|
31
|
+
return (
|
|
32
|
+
active?.material?.properties?.color ??
|
|
33
|
+
getCatalogMaterialById(active?.material?.id)?.previewColor ??
|
|
34
|
+
fallback
|
|
35
|
+
)
|
|
36
|
+
}, [active, eraser, materials, fallback])
|
|
37
|
+
}
|