@pascal-app/nodes 1.0.6 → 1.0.7
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 +1 -0
- package/dist/beam/actions/move-endpoint.d.ts +24 -0
- package/dist/beam/actions/move-endpoint.d.ts.map +1 -0
- package/dist/beam/actions/move-endpoint.js +54 -0
- package/dist/beam/definition.d.ts +14 -0
- package/dist/beam/definition.d.ts.map +1 -0
- package/dist/beam/definition.js +173 -0
- package/dist/beam/draft-settings.d.ts +17 -0
- package/dist/beam/draft-settings.d.ts.map +1 -0
- package/dist/beam/draft-settings.js +81 -0
- package/dist/beam/drafting.d.ts +35 -0
- package/dist/beam/drafting.d.ts.map +1 -0
- package/dist/beam/drafting.js +103 -0
- package/dist/beam/floorplan-affordances.d.ts +8 -0
- package/dist/beam/floorplan-affordances.d.ts.map +1 -0
- package/dist/beam/floorplan-affordances.js +40 -0
- package/dist/beam/floorplan-move.d.ts +11 -0
- package/dist/beam/floorplan-move.d.ts.map +1 -0
- package/dist/beam/floorplan-move.js +54 -0
- package/dist/beam/floorplan.d.ts +11 -0
- package/dist/beam/floorplan.d.ts.map +1 -0
- package/dist/beam/floorplan.js +91 -0
- package/dist/beam/geometry.d.ts +19 -0
- package/dist/beam/geometry.d.ts.map +1 -0
- package/dist/beam/geometry.js +63 -0
- package/dist/beam/index.d.ts +3 -0
- package/dist/beam/index.d.ts.map +1 -0
- package/dist/beam/index.js +2 -0
- package/dist/beam/move-endpoint-tool.d.ts +21 -0
- package/dist/beam/move-endpoint-tool.d.ts.map +1 -0
- package/dist/beam/move-endpoint-tool.js +49 -0
- package/dist/beam/move-tool.d.ts +12 -0
- package/dist/beam/move-tool.d.ts.map +1 -0
- package/dist/beam/move-tool.js +114 -0
- package/dist/beam/panel-model.d.ts +28 -0
- package/dist/beam/panel-model.d.ts.map +1 -0
- package/dist/beam/panel-model.js +123 -0
- package/dist/beam/panel.d.ts +13 -0
- package/dist/beam/panel.d.ts.map +1 -0
- package/dist/beam/panel.js +107 -0
- package/dist/beam/parametrics.d.ts +3 -0
- package/dist/beam/parametrics.d.ts.map +1 -0
- package/dist/beam/parametrics.js +4 -0
- package/dist/beam/renderer.d.ts +13 -0
- package/dist/beam/renderer.d.ts.map +1 -0
- package/dist/beam/renderer.js +36 -0
- package/dist/beam/schema.d.ts +2 -0
- package/dist/beam/schema.d.ts.map +1 -0
- package/dist/beam/schema.js +1 -0
- package/dist/beam/tool.d.ts +13 -0
- package/dist/beam/tool.d.ts.map +1 -0
- package/dist/beam/tool.js +152 -0
- package/dist/box-vent/panel.d.ts.map +1 -1
- package/dist/box-vent/panel.js +8 -7
- package/dist/cabinet/batchable.d.ts +10 -0
- package/dist/cabinet/batchable.d.ts.map +1 -0
- package/dist/cabinet/batchable.js +12 -0
- package/dist/cabinet/compartment-card.d.ts.map +1 -1
- package/dist/cabinet/compartment-card.js +142 -46
- package/dist/cabinet/countertop-layout.d.ts +5 -0
- package/dist/cabinet/countertop-layout.d.ts.map +1 -1
- package/dist/cabinet/definition.d.ts.map +1 -1
- package/dist/cabinet/definition.js +3 -0
- package/dist/cabinet/dimension-input.d.ts +6 -0
- package/dist/cabinet/dimension-input.d.ts.map +1 -0
- package/dist/cabinet/dimension-input.js +8 -0
- package/dist/cabinet/essential-controls.d.ts.map +1 -1
- package/dist/cabinet/essential-controls.js +82 -17
- package/dist/cabinet/index.d.ts +1 -1
- package/dist/cabinet/index.d.ts.map +1 -1
- package/dist/cabinet/index.js +1 -1
- package/dist/cabinet/kitchen-catalog.d.ts +17 -4
- package/dist/cabinet/kitchen-catalog.d.ts.map +1 -1
- package/dist/cabinet/kitchen-catalog.js +45 -7
- package/dist/cabinet/kitchen-collection.d.ts.map +1 -1
- package/dist/cabinet/kitchen-collection.js +21 -5
- package/dist/cabinet/kitchen-module-actions.d.ts.map +1 -1
- package/dist/cabinet/kitchen-module-actions.js +107 -14
- package/dist/cabinet/neighbor-placement.d.ts +10 -0
- package/dist/cabinet/neighbor-placement.d.ts.map +1 -1
- package/dist/cabinet/panel.d.ts.map +1 -1
- package/dist/cabinet/panel.js +127 -50
- package/dist/cabinet/run-finishing.d.ts +5 -0
- package/dist/cabinet/run-finishing.d.ts.map +1 -1
- package/dist/cabinet/run-ops.d.ts +5 -0
- package/dist/cabinet/run-ops.d.ts.map +1 -1
- package/dist/cabinet/run-panel.d.ts.map +1 -1
- package/dist/cabinet/run-panel.js +203 -52
- package/dist/cabinet/tool.d.ts.map +1 -1
- package/dist/cabinet/tool.js +8 -5
- package/dist/ceiling/build-up-section.d.ts +7 -0
- package/dist/ceiling/build-up-section.d.ts.map +1 -0
- package/dist/ceiling/build-up-section.js +57 -0
- package/dist/ceiling/definition.d.ts.map +1 -1
- package/dist/ceiling/definition.js +3 -1
- package/dist/ceiling/floorplan-affordances.d.ts +112 -0
- package/dist/ceiling/floorplan-affordances.d.ts.map +1 -1
- package/dist/ceiling/materials.d.ts +5 -0
- package/dist/ceiling/materials.d.ts.map +1 -1
- package/dist/ceiling/materials.js +17 -0
- package/dist/ceiling/panel-model.d.ts +13 -0
- package/dist/ceiling/panel-model.d.ts.map +1 -0
- package/dist/ceiling/panel-model.js +49 -0
- package/dist/ceiling/panel.d.ts.map +1 -1
- package/dist/ceiling/panel.js +82 -18
- package/dist/ceiling/renderer.d.ts.map +1 -1
- package/dist/ceiling/renderer.js +10 -4
- package/dist/ceiling/tool.d.ts.map +1 -1
- package/dist/ceiling/tool.js +24 -4
- package/dist/chimney/panel.d.ts.map +1 -1
- package/dist/chimney/panel.js +113 -41
- package/dist/column/definition.d.ts.map +1 -1
- package/dist/column/definition.js +3 -0
- package/dist/column/floorplan.d.ts.map +1 -1
- package/dist/column/floorplan.js +17 -0
- package/dist/column/hosted-resize.d.ts +28 -1
- package/dist/column/hosted-resize.d.ts.map +1 -1
- package/dist/column/panel.d.ts.map +1 -1
- package/dist/column/panel.js +125 -37
- package/dist/column/post-options.d.ts +10 -0
- package/dist/column/post-options.d.ts.map +1 -0
- package/dist/column/post-options.js +71 -0
- package/dist/column/post-placement.d.ts +78 -0
- package/dist/column/post-placement.d.ts.map +1 -0
- package/dist/column/post-placement.js +157 -0
- package/dist/column/post-section.d.ts +17 -0
- package/dist/column/post-section.d.ts.map +1 -0
- package/dist/column/post-section.js +95 -0
- package/dist/column/post-tool.d.ts +11 -0
- package/dist/column/post-tool.d.ts.map +1 -0
- package/dist/column/post-tool.js +94 -0
- package/dist/column/tool.d.ts +3 -10
- package/dist/column/tool.d.ts.map +1 -1
- package/dist/column/tool.js +13 -1
- package/dist/cupola/panel.d.ts.map +1 -1
- package/dist/cupola/panel.js +14 -7
- package/dist/door/actions.d.ts +7 -0
- package/dist/door/actions.d.ts.map +1 -0
- package/dist/door/actions.js +32 -0
- package/dist/door/contextual-dimensions.d.ts.map +1 -1
- package/dist/door/contextual-dimensions.js +11 -1
- package/dist/door/definition.d.ts.map +1 -1
- package/dist/door/definition.js +34 -7
- package/dist/door/floorplan-affordances.d.ts.map +1 -1
- package/dist/door/floorplan-affordances.js +5 -2
- package/dist/door/floorplan-move.d.ts.map +1 -1
- package/dist/door/floorplan-move.js +28 -6
- package/dist/door/floorplan.d.ts +2 -0
- package/dist/door/floorplan.d.ts.map +1 -1
- package/dist/door/floorplan.js +89 -16
- package/dist/door/move-tool.d.ts.map +1 -1
- package/dist/door/move-tool.js +60 -16
- package/dist/door/paint.d.ts +2 -7
- package/dist/door/paint.d.ts.map +1 -1
- package/dist/door/paint.js +26 -2
- package/dist/door/panel.d.ts.map +1 -1
- package/dist/door/panel.js +242 -90
- package/dist/door/parametrics.js +1 -1
- package/dist/door/placement.d.ts.map +1 -1
- package/dist/door/placement.js +9 -2
- package/dist/door/swing.d.ts +22 -0
- package/dist/door/swing.d.ts.map +1 -0
- package/dist/door/swing.js +36 -0
- package/dist/door/tool.d.ts.map +1 -1
- package/dist/door/tool.js +76 -29
- package/dist/dormer/panel-actions-section.d.ts.map +1 -1
- package/dist/dormer/panel-actions-section.js +3 -1
- package/dist/dormer/panel-position-section.d.ts.map +1 -1
- package/dist/dormer/panel-position-section.js +4 -3
- package/dist/dormer/panel-windows-section.d.ts.map +1 -1
- package/dist/dormer/panel-windows-section.js +38 -1
- package/dist/dormer/panel.d.ts.map +1 -1
- package/dist/dormer/panel.js +24 -18
- package/dist/downspout/inspector-editors.d.ts.map +1 -1
- package/dist/downspout/inspector-editors.js +3 -2
- package/dist/duct-fitting/inspector-editors.d.ts.map +1 -1
- package/dist/duct-fitting/inspector-editors.js +6 -1
- package/dist/duct-fitting/tool.d.ts.map +1 -1
- package/dist/duct-fitting/tool.js +11 -2
- package/dist/duct-terminal/tool.d.ts.map +1 -1
- package/dist/duct-terminal/tool.js +11 -2
- package/dist/elevator/panel.d.ts.map +1 -1
- package/dist/elevator/panel.js +41 -18
- package/dist/eyebrow-vent/panel.d.ts.map +1 -1
- package/dist/eyebrow-vent/panel.js +16 -6
- package/dist/fence/drafting.d.ts +2 -3
- package/dist/fence/drafting.d.ts.map +1 -1
- package/dist/fence/drafting.js +2 -3
- package/dist/fence/inspector-editors.d.ts.map +1 -1
- package/dist/fence/inspector-editors.js +64 -21
- package/dist/fence/move-endpoint-tool.d.ts.map +1 -1
- package/dist/fence/move-endpoint-tool.js +11 -2
- package/dist/fence/system.d.ts.map +1 -1
- package/dist/fence/system.js +13 -0
- package/dist/fence-feature/actions.d.ts.map +1 -1
- package/dist/fence-feature/actions.js +5 -2
- package/dist/fence-feature/inspector.d.ts.map +1 -1
- package/dist/fence-feature/inspector.js +150 -34
- package/dist/fence-feature/move-session.d.ts +1 -1
- package/dist/floor-opening/floorplan.d.ts +29 -6
- package/dist/floor-opening/floorplan.d.ts.map +1 -1
- package/dist/floor-opening/floorplan.js +172 -14
- package/dist/gutter/downspouts-panel.d.ts.map +1 -1
- package/dist/gutter/downspouts-panel.js +14 -2
- package/dist/hvac-equipment/tool.d.ts.map +1 -1
- package/dist/hvac-equipment/tool.js +3 -2
- package/dist/i18n/definition-messages.d.ts +5 -0
- package/dist/i18n/definition-messages.d.ts.map +1 -0
- package/dist/i18n/definition-messages.js +771 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -1
- package/dist/item/authored-params.d.ts.map +1 -1
- package/dist/item/authored-params.js +19 -4
- package/dist/item/floorplan.d.ts +1 -1
- package/dist/item/floorplan.d.ts.map +1 -1
- package/dist/item/panel.d.ts.map +1 -1
- package/dist/item/panel.js +9 -7
- package/dist/liquid-line/tool.d.ts.map +1 -1
- package/dist/liquid-line/tool.js +10 -3
- package/dist/measurement/tool.d.ts +1 -1
- package/dist/measurement/tool.d.ts.map +1 -1
- package/dist/measurement/tool.js +8 -8
- package/dist/pipe-fitting/tool.d.ts.map +1 -1
- package/dist/pipe-fitting/tool.js +3 -2
- package/dist/pipe-trap/tool.d.ts.map +1 -1
- package/dist/pipe-trap/tool.js +7 -2
- package/dist/procedural-item/renderer.d.ts.map +1 -1
- package/dist/procedural-item/renderer.js +8 -1
- package/dist/ridge-vent/panel.d.ts.map +1 -1
- package/dist/ridge-vent/panel.js +22 -9
- package/dist/roof/barrel-panel.d.ts.map +1 -1
- package/dist/roof/barrel-panel.js +7 -3
- package/dist/roof/definition.d.ts.map +1 -1
- package/dist/roof/definition.js +33 -3
- package/dist/roof/floorplan-overrides.d.ts +22 -0
- package/dist/roof/floorplan-overrides.d.ts.map +1 -0
- package/dist/roof/floorplan-overrides.js +46 -0
- package/dist/roof/floorplan-tool.d.ts +9 -0
- package/dist/roof/floorplan-tool.d.ts.map +1 -0
- package/dist/roof/floorplan-tool.js +168 -0
- package/dist/roof/floorplan.d.ts.map +1 -1
- package/dist/roof/floorplan.js +131 -41
- package/dist/roof/glazing-controls.d.ts +2 -1
- package/dist/roof/glazing-controls.d.ts.map +1 -1
- package/dist/roof/glazing-controls.js +51 -13
- package/dist/roof/glazing-panel-editor.d.ts.map +1 -1
- package/dist/roof/glazing-panel-editor.js +40 -13
- package/dist/roof/glazing-panel.d.ts.map +1 -1
- package/dist/roof/glazing-panel.js +73 -9
- package/dist/roof/paint.d.ts +19 -0
- package/dist/roof/paint.d.ts.map +1 -0
- package/dist/roof/paint.js +158 -0
- package/dist/roof/panel.d.ts.map +1 -1
- package/dist/roof/panel.js +90 -22
- package/dist/roof/renderer.d.ts.map +1 -1
- package/dist/roof/renderer.js +13 -2
- package/dist/roof/roof-footprint-source.d.ts +17 -0
- package/dist/roof/roof-footprint-source.d.ts.map +1 -1
- package/dist/roof/roof-footprint-source.js +14 -0
- package/dist/roof/roof-footprint.d.ts +36 -2
- package/dist/roof/roof-footprint.d.ts.map +1 -1
- package/dist/roof/roof-footprint.js +124 -2
- package/dist/roof/roof-materials.d.ts.map +1 -1
- package/dist/roof/roof-materials.js +10 -1
- package/dist/roof/roof-placement-mode.d.ts +0 -2
- package/dist/roof/roof-placement-mode.d.ts.map +1 -1
- package/dist/roof/roof-placement-mode.js +8 -6
- package/dist/roof/roof-plan-creases.d.ts +50 -0
- package/dist/roof/roof-plan-creases.d.ts.map +1 -0
- package/dist/roof/roof-plan-creases.js +194 -0
- package/dist/roof/roof-ridge-mode.d.ts +20 -0
- package/dist/roof/roof-ridge-mode.d.ts.map +1 -0
- package/dist/roof/roof-ridge-mode.js +16 -0
- package/dist/roof/tool.d.ts +17 -4
- package/dist/roof/tool.d.ts.map +1 -1
- package/dist/roof/tool.js +211 -113
- package/dist/roof/wall-catch.d.ts +106 -0
- package/dist/roof/wall-catch.d.ts.map +1 -0
- package/dist/roof/wall-catch.js +267 -0
- package/dist/roof-segment/build-up-section.d.ts +9 -0
- package/dist/roof-segment/build-up-section.d.ts.map +1 -0
- package/dist/roof-segment/build-up-section.js +191 -0
- package/dist/roof-segment/definition.d.ts.map +1 -1
- package/dist/roof-segment/definition.js +50 -5
- package/dist/roof-segment/floorplan-affordances.d.ts.map +1 -1
- package/dist/roof-segment/floorplan-affordances.js +68 -19
- package/dist/roof-segment/floorplan.d.ts.map +1 -1
- package/dist/roof-segment/floorplan.js +16 -12
- package/dist/roof-segment/paint.d.ts +3 -1
- package/dist/roof-segment/paint.d.ts.map +1 -1
- package/dist/roof-segment/paint.js +43 -2
- package/dist/roof-segment/panel-model.d.ts +23 -0
- package/dist/roof-segment/panel-model.d.ts.map +1 -0
- package/dist/roof-segment/panel-model.js +64 -0
- package/dist/roof-segment/panel.d.ts.map +1 -1
- package/dist/roof-segment/panel.js +96 -14
- package/dist/roof-segment/parametrics.d.ts.map +1 -1
- package/dist/roof-segment/parametrics.js +4 -0
- package/dist/roof-segment/renderer.d.ts.map +1 -1
- package/dist/roof-segment/renderer.js +26 -5
- package/dist/separator/definition.d.ts.map +1 -1
- package/dist/separator/definition.js +10 -12
- package/dist/separator/floorplan-affordances.d.ts +9 -0
- package/dist/separator/floorplan-affordances.d.ts.map +1 -0
- package/dist/separator/floorplan-affordances.js +23 -0
- package/dist/separator/floorplan.d.ts +9 -0
- package/dist/separator/floorplan.d.ts.map +1 -0
- package/dist/separator/floorplan.js +54 -0
- package/dist/separator/renderer.d.ts +4 -0
- package/dist/separator/renderer.d.ts.map +1 -1
- package/dist/separator/renderer.js +21 -6
- package/dist/separator/selection.d.ts +10 -0
- package/dist/separator/selection.d.ts.map +1 -0
- package/dist/separator/selection.js +35 -0
- package/dist/shared/build-up-controls.d.ts +88 -0
- package/dist/shared/build-up-controls.d.ts.map +1 -0
- package/dist/shared/build-up-controls.js +139 -0
- package/dist/shared/curtain-opening-limits.d.ts.map +1 -1
- package/dist/shared/curtain-opening-limits.js +44 -14
- package/dist/shared/item-interaction-actions.d.ts.map +1 -1
- package/dist/shared/item-interaction-actions.js +11 -2
- package/dist/shared/layer-thickness.d.ts +2 -0
- package/dist/shared/layer-thickness.d.ts.map +1 -0
- package/dist/shared/layer-thickness.js +3 -0
- package/dist/shared/move-roof-tool.d.ts.map +1 -1
- package/dist/shared/move-roof-tool.js +100 -5
- package/dist/shared/node-batch/batchable.d.ts +2 -0
- package/dist/shared/node-batch/batchable.d.ts.map +1 -1
- package/dist/shared/node-batch/batchable.js +4 -0
- package/dist/shared/node-batch/candidates.d.ts +21 -5
- package/dist/shared/node-batch/candidates.d.ts.map +1 -1
- package/dist/shared/node-batch/candidates.js +85 -50
- package/dist/shared/node-batch/system.d.ts.map +1 -1
- package/dist/shared/node-batch/system.js +24 -15
- package/dist/shared/opening-casing-move.d.ts +16 -0
- package/dist/shared/opening-casing-move.d.ts.map +1 -0
- package/dist/shared/opening-casing-move.js +33 -0
- package/dist/shared/opening-casing-section.d.ts +15 -0
- package/dist/shared/opening-casing-section.d.ts.map +1 -0
- package/dist/shared/opening-casing-section.js +38 -0
- package/dist/shared/opening-casing.d.ts +26 -0
- package/dist/shared/opening-casing.d.ts.map +1 -0
- package/dist/shared/opening-casing.js +80 -0
- package/dist/shared/opening-depth-position.d.ts +13 -0
- package/dist/shared/opening-depth-position.d.ts.map +1 -0
- package/dist/shared/opening-depth-position.js +34 -0
- package/dist/shared/opening-documentation.d.ts.map +1 -1
- package/dist/shared/opening-documentation.js +17 -8
- package/dist/shared/opening-guides-runtime.d.ts +2 -1
- package/dist/shared/opening-guides-runtime.d.ts.map +1 -1
- package/dist/shared/opening-guides-runtime.js +11 -7
- package/dist/shared/opening-labels.d.ts +11 -0
- package/dist/shared/opening-labels.d.ts.map +1 -0
- package/dist/shared/opening-labels.js +46 -0
- package/dist/shared/opening-placement-dimensions.d.ts.map +1 -1
- package/dist/shared/opening-placement-dimensions.js +11 -9
- package/dist/shared/opening-plane-offset.d.ts +4 -3
- package/dist/shared/opening-plane-offset.d.ts.map +1 -1
- package/dist/shared/opening-plane-offset.js +7 -4
- package/dist/shared/opening-swap.d.ts +8 -0
- package/dist/shared/opening-swap.d.ts.map +1 -0
- package/dist/shared/opening-swap.js +18 -0
- package/dist/shared/polygon-vertex-affordance.d.ts +19 -0
- package/dist/shared/polygon-vertex-affordance.d.ts.map +1 -1
- package/dist/shared/polygon-vertex-affordance.js +65 -6
- package/dist/shared/roof-opening-host.d.ts +2 -1
- package/dist/shared/roof-opening-host.d.ts.map +1 -1
- package/dist/shared/roof-opening-host.js +14 -5
- package/dist/shared/roof-wall-opening-cut.d.ts.map +1 -1
- package/dist/shared/roof-wall-opening-cut.js +14 -6
- package/dist/shared/roof-wall-opening-placement.d.ts +2 -1
- package/dist/shared/roof-wall-opening-placement.d.ts.map +1 -1
- package/dist/shared/roof-wall-opening-placement.js +6 -4
- package/dist/shared/run-hanger-inspector.d.ts.map +1 -1
- package/dist/shared/run-hanger-inspector.js +39 -5
- package/dist/shared/system-check-panel.d.ts.map +1 -1
- package/dist/shared/system-check-panel.js +94 -15
- package/dist/shared/wall-attach-target.d.ts.map +1 -1
- package/dist/shared/wall-attach-target.js +6 -3
- package/dist/shelf/definition.d.ts.map +1 -1
- package/dist/shelf/definition.js +2 -0
- package/dist/site/ground-hole.d.ts +3 -3
- package/dist/site/ground-hole.js +3 -3
- package/dist/site/ground-veil.d.ts +5 -12
- package/dist/site/ground-veil.d.ts.map +1 -1
- package/dist/site/ground-veil.js +9 -33
- package/dist/site/panel.d.ts.map +1 -1
- package/dist/site/panel.js +52 -12
- package/dist/site/renderer.d.ts.map +1 -1
- package/dist/site/renderer.js +52 -23
- package/dist/skylight/panel.d.ts.map +1 -1
- package/dist/skylight/panel.js +49 -19
- package/dist/slab/deck-geometry.d.ts +28 -0
- package/dist/slab/deck-geometry.d.ts.map +1 -0
- package/dist/slab/deck-geometry.js +320 -0
- package/dist/slab/definition.d.ts +2 -1
- package/dist/slab/definition.d.ts.map +1 -1
- package/dist/slab/definition.js +6 -1
- package/dist/slab/dependency-tracker.d.ts.map +1 -1
- package/dist/slab/dependency-tracker.js +3 -0
- package/dist/slab/floorplan-affordances.d.ts +500 -0
- package/dist/slab/floorplan-affordances.d.ts.map +1 -1
- package/dist/slab/geometry.d.ts.map +1 -1
- package/dist/slab/geometry.js +46 -9
- package/dist/slab/panel.d.ts.map +1 -1
- package/dist/slab/panel.js +97 -21
- package/dist/slab/renderer.d.ts +11 -0
- package/dist/slab/renderer.d.ts.map +1 -0
- package/dist/slab/renderer.js +19 -0
- package/dist/slab/system.d.ts.map +1 -1
- package/dist/slab/system.js +12 -1
- package/dist/solar-panel/panel.d.ts.map +1 -1
- package/dist/solar-panel/panel.js +49 -14
- package/dist/stair/construction-controls.d.ts +3 -1
- package/dist/stair/construction-controls.d.ts.map +1 -1
- package/dist/stair/construction-controls.js +75 -12
- package/dist/stair/paint.d.ts +6 -0
- package/dist/stair/paint.d.ts.map +1 -1
- package/dist/stair/panel.d.ts.map +1 -1
- package/dist/stair/panel.js +243 -51
- package/dist/stair/parametrics.d.ts.map +1 -1
- package/dist/stair/parametrics.js +7 -0
- package/dist/stair/placement-defaults.d.ts +18 -0
- package/dist/stair/placement-defaults.d.ts.map +1 -0
- package/dist/stair/placement-defaults.js +27 -0
- package/dist/stair/railing-controls.d.ts.map +1 -1
- package/dist/stair/railing-controls.js +78 -18
- package/dist/stair/renderer.d.ts.map +1 -1
- package/dist/stair/renderer.js +16 -10
- package/dist/stair/structure-controls.d.ts +18 -0
- package/dist/stair/structure-controls.d.ts.map +1 -0
- package/dist/stair/structure-controls.js +275 -0
- package/dist/stair/tool.d.ts.map +1 -1
- package/dist/stair/tool.js +13 -9
- package/dist/stair/use-stair-render-data.d.ts +41 -0
- package/dist/stair/use-stair-render-data.d.ts.map +1 -1
- package/dist/stair-segment/panel.d.ts.map +1 -1
- package/dist/stair-segment/panel.js +65 -18
- package/dist/turbine-vent/panel.d.ts.map +1 -1
- package/dist/turbine-vent/panel.js +14 -5
- package/dist/unit/unit-panel.d.ts.map +1 -1
- package/dist/unit/unit-panel.js +28 -12
- package/dist/wall/actions.d.ts +1 -1
- package/dist/wall/actions.d.ts.map +1 -1
- package/dist/wall/actions.js +17 -13
- package/dist/wall/construction-dimensions.d.ts +6 -0
- package/dist/wall/construction-dimensions.d.ts.map +1 -1
- package/dist/wall/construction-dimensions.js +8 -0
- package/dist/wall/contextual-dimensions.d.ts +6 -0
- package/dist/wall/contextual-dimensions.d.ts.map +1 -1
- package/dist/wall/contextual-dimensions.js +104 -17
- package/dist/wall/curtain-opening-frame.d.ts.map +1 -1
- package/dist/wall/curtain-opening-frame.js +6 -4
- package/dist/wall/curtain-wall-layout.d.ts +1 -1
- package/dist/wall/curtain-wall-layout.d.ts.map +1 -1
- package/dist/wall/curtain-wall-layout.js +6 -4
- package/dist/wall/curtain-wall-materials.d.ts.map +1 -1
- package/dist/wall/curtain-wall-materials.js +8 -3
- package/dist/wall/curtain-wall-panel.d.ts.map +1 -1
- package/dist/wall/curtain-wall-panel.js +241 -37
- package/dist/wall/curve-tool.d.ts.map +1 -1
- package/dist/wall/curve-tool.js +2 -3
- package/dist/wall/definition.d.ts.map +1 -1
- package/dist/wall/definition.js +20 -5
- package/dist/wall/floorplan-affordances.d.ts.map +1 -1
- package/dist/wall/floorplan-affordances.js +9 -6
- package/dist/wall/floorplan-move.d.ts.map +1 -1
- package/dist/wall/floorplan-move.js +66 -16
- package/dist/wall/floorplan.d.ts +4 -5
- package/dist/wall/floorplan.d.ts.map +1 -1
- package/dist/wall/floorplan.js +62 -46
- package/dist/wall/move-endpoint-tool.d.ts.map +1 -1
- package/dist/wall/move-endpoint-tool.js +1 -0
- package/dist/wall/move-tool.d.ts.map +1 -1
- package/dist/wall/move-tool.js +77 -12
- package/dist/wall/paint.d.ts +2 -2
- package/dist/wall/paint.d.ts.map +1 -1
- package/dist/wall/paint.js +11 -4
- package/dist/wall/panel-model.d.ts +17 -2
- package/dist/wall/panel-model.d.ts.map +1 -1
- package/dist/wall/panel-model.js +158 -18
- package/dist/wall/panel.d.ts +8 -0
- package/dist/wall/panel.d.ts.map +1 -1
- package/dist/wall/panel.js +228 -156
- package/dist/wall/parametrics.d.ts +1 -1
- package/dist/wall/parametrics.d.ts.map +1 -1
- package/dist/wall/parametrics.js +14 -1
- package/dist/wall/railing-wall-adapter.d.ts +7 -0
- package/dist/wall/railing-wall-adapter.d.ts.map +1 -0
- package/dist/wall/railing-wall-adapter.js +38 -0
- package/dist/wall/railing-wall-floorplan.d.ts +8 -0
- package/dist/wall/railing-wall-floorplan.d.ts.map +1 -0
- package/dist/wall/railing-wall-floorplan.js +27 -0
- package/dist/wall/railing-wall-geometry.d.ts +12 -0
- package/dist/wall/railing-wall-geometry.d.ts.map +1 -0
- package/dist/wall/railing-wall-geometry.js +51 -0
- package/dist/wall/railing-wall-guard.d.ts +81 -0
- package/dist/wall/railing-wall-guard.d.ts.map +1 -0
- package/dist/wall/railing-wall-guard.js +435 -0
- package/dist/wall/railing-wall-materials.d.ts +11 -0
- package/dist/wall/railing-wall-materials.d.ts.map +1 -0
- package/dist/wall/railing-wall-materials.js +31 -0
- package/dist/wall/railing-wall-panel-model.d.ts +30 -0
- package/dist/wall/railing-wall-panel-model.d.ts.map +1 -0
- package/dist/wall/railing-wall-panel-model.js +117 -0
- package/dist/wall/railing-wall-panel.d.ts +17 -0
- package/dist/wall/railing-wall-panel.d.ts.map +1 -0
- package/dist/wall/railing-wall-panel.js +42 -0
- package/dist/wall/rectangle-command.d.ts +79 -1
- package/dist/wall/rectangle-command.d.ts.map +1 -1
- package/dist/wall/rectangle-tool.d.ts.map +1 -1
- package/dist/wall/rectangle-tool.js +2 -0
- package/dist/wall/renderer.d.ts.map +1 -1
- package/dist/wall/renderer.js +3 -1
- package/dist/wall/skirting-floor-gaps.d.ts +8 -0
- package/dist/wall/skirting-floor-gaps.d.ts.map +1 -0
- package/dist/wall/skirting-floor-gaps.js +36 -0
- package/dist/wall/system.d.ts +0 -14
- package/dist/wall/system.d.ts.map +1 -1
- package/dist/wall/system.js +6 -1
- package/dist/wall/tool.d.ts +16 -0
- package/dist/wall/tool.d.ts.map +1 -1
- package/dist/wall/tool.js +160 -47
- package/dist/wall/treatments.d.ts +3 -0
- package/dist/wall/treatments.d.ts.map +1 -1
- package/dist/wall/treatments.js +30 -7
- package/dist/window/actions.d.ts +7 -0
- package/dist/window/actions.d.ts.map +1 -0
- package/dist/window/actions.js +29 -0
- package/dist/window/definition.d.ts.map +1 -1
- package/dist/window/definition.js +11 -2
- package/dist/window/floorplan-move.d.ts.map +1 -1
- package/dist/window/floorplan-move.js +5 -0
- package/dist/window/floorplan.d.ts +2 -0
- package/dist/window/floorplan.d.ts.map +1 -1
- package/dist/window/floorplan.js +58 -1
- package/dist/window/mechanism.d.ts.map +1 -1
- package/dist/window/mechanism.js +21 -1
- package/dist/window/move-tool.d.ts.map +1 -1
- package/dist/window/move-tool.js +10 -3
- package/dist/window/paint.d.ts +2 -7
- package/dist/window/paint.d.ts.map +1 -1
- package/dist/window/paint.js +31 -3
- package/dist/window/panel.d.ts.map +1 -1
- package/dist/window/panel.js +311 -69
- package/dist/window/placement.d.ts.map +1 -1
- package/dist/window/placement.js +5 -1
- package/dist/window/swing.d.ts +13 -0
- package/dist/window/swing.d.ts.map +1 -0
- package/dist/window/swing.js +16 -0
- package/dist/window/tool.d.ts.map +1 -1
- package/dist/window/tool.js +19 -14
- package/dist/zone/floorplan-affordances.d.ts +136 -0
- package/dist/zone/floorplan-affordances.d.ts.map +1 -1
- package/dist/zone/quantities-panel.d.ts.map +1 -1
- package/dist/zone/quantities-panel.js +34 -9
- package/dist/zone/renderer.d.ts.map +1 -1
- package/dist/zone/renderer.js +9 -5
- package/package.json +14 -14
- package/dist/site/generic-foundation-geometry.d.ts +0 -16
- package/dist/site/generic-foundation-geometry.d.ts.map +0 -1
- package/dist/site/generic-foundation-geometry.js +0 -75
- package/dist/site/generic-foundation.d.ts +0 -4
- package/dist/site/generic-foundation.d.ts.map +0 -1
- package/dist/site/generic-foundation.js +0 -91
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { createDefaultRidgeVentsForSegment, getConicalRoofCoverage, getRoofSegmentDeckReach, getSegmentSlopeFrame, isAutoGutterEnabled, isAutoRidgeVentEnabled, isDefaultRidgeVentNode, isGlazedRoofSegment, normalizeRoofSegmentTrim, ROOF_SHAPE_DEFAULTS, roofTypeHasRakes, useScene, } from '@pascal-app/core';
|
|
3
|
+
import { createDefaultRidgeVentsForSegment, getConicalRoofCoverage, getRoofSegmentDeckReach, getSegmentSlopeFrame, isAutoGutterEnabled, isAutoRidgeVentEnabled, isDefaultRidgeVentNode, isGlazedRoofSegment, normalizeRoofSegmentTrim, ROOF_SHAPE_DEFAULTS, roofBuildUpPatch, roofSegmentEaveProfile, roofTypeHasRakes, usePascalI18n, useScene, } from '@pascal-app/core';
|
|
4
4
|
import { ActionButton, ActionGroup, duplicateNodeAndPickUp, PanelSection, PanelWrapper, SegmentedControl, SliderControl, ToggleControl, triggerSFX, useEditor, } from '@pascal-app/editor';
|
|
5
5
|
import { useViewer } from '@pascal-app/viewer';
|
|
6
6
|
import { Check, Copy, Move, Pencil, RotateCcw, Trash2 } from 'lucide-react';
|
|
@@ -8,21 +8,42 @@ import { useCallback } from 'react';
|
|
|
8
8
|
import { BarrelRoofPanel } from '../roof/barrel-panel.js';
|
|
9
9
|
import { RoofGlazingPanel } from '../roof/glazing-panel.js';
|
|
10
10
|
import { commitSeatedRoofEdit } from '../roof/roof-level-target.js';
|
|
11
|
+
import { RoofBuildUpSection } from './build-up-section.js';
|
|
11
12
|
const ROOF_TYPE_OPTIONS = [
|
|
12
|
-
{ label: 'Hip', value: 'hip' },
|
|
13
|
-
{ label: 'Gable', value: 'gable' },
|
|
14
|
-
{ label: 'Shed', value: 'shed' },
|
|
13
|
+
{ label: /* i18n */ { id: 'node.roofSegment.panel.hip', message: 'Hip' }, value: 'hip' },
|
|
14
|
+
{ label: /* i18n */ { id: 'node.roofSegment.panel.gable', message: 'Gable' }, value: 'gable' },
|
|
15
|
+
{ label: /* i18n */ { id: 'node.roofSegment.panel.shed', message: 'Shed' }, value: 'shed' },
|
|
15
16
|
];
|
|
16
17
|
const ROOF_TYPE_OPTIONS_2 = [
|
|
17
|
-
{ label: 'Flat', value: 'flat' },
|
|
18
|
-
{
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
{ label: /* i18n */ { id: 'node.roofSegment.panel.flat', message: 'Flat' }, value: 'flat' },
|
|
19
|
+
{
|
|
20
|
+
label: /* i18n */ { id: 'node.roofSegment.panel.gambrel', message: 'Gambrel' },
|
|
21
|
+
value: 'gambrel',
|
|
22
|
+
},
|
|
23
|
+
{ label: /* i18n */ { id: 'node.roofSegment.panel.dutch', message: 'Dutch' }, value: 'dutch' },
|
|
24
|
+
{
|
|
25
|
+
label: /* i18n */ { id: 'node.roofSegment.panel.mansard', message: 'Mansard' },
|
|
26
|
+
value: 'mansard',
|
|
27
|
+
},
|
|
21
28
|
];
|
|
22
29
|
const ROOF_TYPE_OPTIONS_3 = [
|
|
23
|
-
{
|
|
24
|
-
|
|
30
|
+
{
|
|
31
|
+
label: /* i18n */ { id: 'node.roofSegment.panel.conical', message: 'Conical' },
|
|
32
|
+
value: 'conical',
|
|
33
|
+
},
|
|
34
|
+
{ label: /* i18n */ { id: 'node.roofSegment.panel.barrel', message: 'Barrel' }, value: 'barrel' },
|
|
25
35
|
];
|
|
36
|
+
// How the rafter tails are cut at the eaves, the fascia and soffit with them (core's `roofEaveProfile`).
|
|
37
|
+
const EAVE_CUT_OPTIONS = [
|
|
38
|
+
{ label: /* i18n */ { id: 'node.roofSegment.panel.plumb', message: 'Plumb' }, value: 'plumb' },
|
|
39
|
+
{ label: /* i18n */ { id: 'node.roofSegment.panel.square', message: 'Square' }, value: 'square' },
|
|
40
|
+
{
|
|
41
|
+
label: /* i18n */ { id: 'node.roofSegment.panel.plumbLevel', message: 'Plumb + level' },
|
|
42
|
+
value: 'plumb-level',
|
|
43
|
+
},
|
|
44
|
+
];
|
|
45
|
+
/** The sloped forms whose tails are cut at their eaves by the plane's eave cut. */
|
|
46
|
+
const EAVE_CUT_ROOF_TYPES = new Set(['gable', 'hip', 'shed']);
|
|
26
47
|
// Carpenter / roofer convention: rise over a 12" run, converted to degrees.
|
|
27
48
|
// atan(3/12) ≈ 14.04°, atan(6/12) ≈ 26.57°, atan(9/12) ≈ 36.87°, atan(12/12) = 45°.
|
|
28
49
|
const PITCH_PRESETS = [
|
|
@@ -49,6 +70,13 @@ const EMPTY_TRIM = {
|
|
|
49
70
|
backRightX: 0,
|
|
50
71
|
backRightZ: 0,
|
|
51
72
|
};
|
|
73
|
+
/** The planes of a roof that take layers: its segments, glazed ones aside. */
|
|
74
|
+
function roofLayerPlaneIds(children, nodes) {
|
|
75
|
+
return children.filter((id) => {
|
|
76
|
+
const child = nodes[id];
|
|
77
|
+
return child?.type === 'roof-segment' && !isGlazedRoofSegment(child);
|
|
78
|
+
});
|
|
79
|
+
}
|
|
52
80
|
function hasSegmentTrim(node) {
|
|
53
81
|
return Object.values(normalizeRoofSegmentTrim(node)).some((value) => value > 0);
|
|
54
82
|
}
|
|
@@ -66,11 +94,13 @@ function metadataRecord(metadata) {
|
|
|
66
94
|
return {};
|
|
67
95
|
}
|
|
68
96
|
export default function RoofSegmentPanel() {
|
|
97
|
+
const i18n = usePascalI18n();
|
|
69
98
|
const selectedId = useViewer((s) => s.selection.selectedIds[0]);
|
|
70
99
|
const setSelection = useViewer((s) => s.setSelection);
|
|
71
100
|
const updateNode = useScene((s) => s.updateNode);
|
|
72
101
|
const setMovingNode = useEditor((s) => s.setMovingNode);
|
|
73
102
|
const setRoofHostDragArmedId = useEditor((s) => s.setRoofHostDragArmedId);
|
|
103
|
+
const unit = useViewer((s) => s.unit);
|
|
74
104
|
const node = useScene((s) => selectedId ? s.nodes[selectedId] : undefined);
|
|
75
105
|
const autoRidgeVentEnabled = useScene((s) => {
|
|
76
106
|
const current = selectedId
|
|
@@ -80,6 +110,14 @@ export default function RoofSegmentPanel() {
|
|
|
80
110
|
return false;
|
|
81
111
|
return isAutoRidgeVentEnabled(current, s.nodes);
|
|
82
112
|
});
|
|
113
|
+
// How many planes of this roof take layers: "Apply to all planes" shows once there are two.
|
|
114
|
+
const roofPlaneCount = useScene((s) => {
|
|
115
|
+
const current = selectedId
|
|
116
|
+
? s.nodes[selectedId]
|
|
117
|
+
: undefined;
|
|
118
|
+
const roof = current?.parentId ? s.nodes[current.parentId] : undefined;
|
|
119
|
+
return roof?.type === 'roof' ? roofLayerPlaneIds(roof.children, s.nodes).length : 0;
|
|
120
|
+
});
|
|
83
121
|
const autoGutterEnabled = useScene((s) => {
|
|
84
122
|
const current = selectedId
|
|
85
123
|
? s.nodes[selectedId]
|
|
@@ -94,6 +132,17 @@ export default function RoofSegmentPanel() {
|
|
|
94
132
|
// Reshaped or moved onto the walls that carry it, its roof goes to the level above them.
|
|
95
133
|
commitSeatedRoofEdit([{ id: selectedId, data: updates }], selectedId);
|
|
96
134
|
}, [selectedId]);
|
|
135
|
+
const handleApplyToRoof = useCallback(() => {
|
|
136
|
+
const scene = useScene.getState();
|
|
137
|
+
const current = selectedId ? scene.nodes[selectedId] : undefined;
|
|
138
|
+
if (current?.type !== 'roof-segment' || !current.buildUp)
|
|
139
|
+
return;
|
|
140
|
+
const roof = current.parentId ? scene.nodes[current.parentId] : undefined;
|
|
141
|
+
if (roof?.type !== 'roof')
|
|
142
|
+
return;
|
|
143
|
+
const patch = roofBuildUpPatch(current.buildUp);
|
|
144
|
+
scene.updateNodes(roofLayerPlaneIds(roof.children, scene.nodes).map((id) => ({ id, data: patch })));
|
|
145
|
+
}, [selectedId]);
|
|
97
146
|
const handleRoofTypeChange = useCallback((roofType) => {
|
|
98
147
|
if (isManagedLeanToRoofSegment(node?.metadata))
|
|
99
148
|
return;
|
|
@@ -239,9 +288,42 @@ export default function RoofSegmentPanel() {
|
|
|
239
288
|
const reach = getRoofSegmentDeckReach(node);
|
|
240
289
|
const halfWall = node.wallThickness / 2;
|
|
241
290
|
const { cosTheta } = getSegmentSlopeFrame(node);
|
|
242
|
-
return (_jsxs(PanelWrapper, { icon: "/icons/roof.webp", onBack: handleBack, onClose: handleClose, title: node.name ||
|
|
291
|
+
return (_jsxs(PanelWrapper, { icon: "/icons/roof.webp", onBack: handleBack, onClose: handleClose, title: node.name || i18n._({ id: 'node.roofSegment.panel.roofSegment', message: 'Roof Segment' }), width: 300, children: [_jsx(RoofGlazingPanel, { segments: [node] }), _jsxs(PanelSection, { title: i18n._({ id: 'node.roofSegment.panel.roofType', message: 'Roof Type' }), children: [_jsx(SegmentedControl, { onChange: (v) => handleRoofTypeChange(v), options: ROOF_TYPE_OPTIONS.map((option) => ({ ...option, label: i18n._(option.label) })), value: node.roofType, disabled: managedLeanToRoofSegment }), _jsx(SegmentedControl, { onChange: (v) => handleRoofTypeChange(v), options: ROOF_TYPE_OPTIONS_2.map((option) => ({
|
|
292
|
+
...option,
|
|
293
|
+
label: i18n._(option.label),
|
|
294
|
+
})), value: node.roofType, disabled: managedLeanToRoofSegment }), _jsx(SegmentedControl, { onChange: (v) => handleRoofTypeChange(v), options: ROOF_TYPE_OPTIONS_3.map((option) => ({
|
|
295
|
+
...option,
|
|
296
|
+
label: i18n._(option.label),
|
|
297
|
+
})), value: node.roofType, disabled: managedLeanToRoofSegment })] }), node.roofType !== 'conical' && (_jsxs(PanelSection, { title: i18n._({ id: 'node.roofSegment.panel.trim', message: 'Trim' }), children: [_jsxs(ActionGroup, { children: [_jsx(ActionButton, { icon: showTrimPlanes ? (_jsx(Check, { className: "h-3.5 w-3.5" })) : (_jsx(Pencil, { className: "h-3.5 w-3.5" })), label: showTrimPlanes
|
|
298
|
+
? i18n._({ id: 'node.roofSegment.panel.doneEditing', message: 'Done editing' })
|
|
299
|
+
: i18n._({
|
|
300
|
+
id: 'node.roofSegment.panel.editFootprint',
|
|
301
|
+
message: 'Edit footprint',
|
|
302
|
+
}), onClick: () => (showTrimPlanes ? handleBack() : handleTrimEditing(true)) }), _jsx(ActionButton, { className: "disabled:cursor-not-allowed disabled:opacity-40", disabled: !hasSegmentTrim(node), icon: _jsx(RotateCcw, { className: "h-3.5 w-3.5" }), label: i18n._({ id: 'node.roofSegment.panel.reset', message: 'Reset' }), onClick: handleResetTrim })] }), node.roofType !== 'shed' && node.roofType !== 'flat' && node.roofType !== 'barrel' && (_jsx(ToggleControl, { checked: autoRidgeVentEnabled, label: i18n._({
|
|
303
|
+
id: 'node.roofSegment.panel.autoRidgeVent',
|
|
304
|
+
message: 'Auto ridge vent',
|
|
305
|
+
}), onChange: handleAutoRidgeVentToggle }))] })), node.roofType !== 'conical' && (_jsx(PanelSection, { title: i18n._({ id: 'node.roofSegment.panel.drainage', message: 'Drainage' }), children: _jsx(ToggleControl, { checked: autoGutterEnabled, label: i18n._({ id: 'node.roofSegment.panel.autoGutters', message: 'Auto gutters' }), onChange: handleAutoGutterToggle }) })), _jsx(PanelSection, { title: i18n._({ id: 'node.roofSegment.panel.footprint', message: 'Footprint' }), children: node.roofType === 'conical' ? (_jsx(SliderControl, { label: i18n._({ id: 'node.roofSegment.panel.diameter', message: 'Diameter' }), max: 1000, min: 0.5, onChange: (v) => handleUpdate({ width: v, depth: v }), precision: 2, step: 0.5, unit: "m", value: node.width })) : (_jsxs(_Fragment, { children: [_jsx(SliderControl, { label: node.roofType === 'barrel'
|
|
306
|
+
? i18n._({ id: 'node.roofSegment.panel.length', message: 'Length' })
|
|
307
|
+
: i18n._({ id: 'node.roofSegment.panel.width', message: 'Width' }), max: 1000, min: 0.5, onChange: (v) => handleUpdate({ width: v }), precision: 2, step: 0.5, unit: "m", value: node.width }), _jsx(SliderControl, { label: node.roofType === 'barrel'
|
|
308
|
+
? i18n._({ id: 'node.roofSegment.panel.span', message: 'Span' })
|
|
309
|
+
: i18n._({ id: 'node.roofSegment.panel.depth', message: 'Depth' }), max: 1000, min: 0.5, onChange: (v) => handleUpdate({ depth: v }), precision: 2, step: 0.5, unit: "m", value: node.depth })] })) }), node.roofType === 'conical' && (_jsxs(PanelSection, { title: i18n._({ id: 'node.roofSegment.panel.conicalShape', message: 'Conical Shape' }), children: [_jsx(ToggleControl, { checked: !conicalCoverage.fullCircle, label: i18n._({
|
|
310
|
+
id: 'node.roofSegment.panel.clippedVersion',
|
|
311
|
+
message: 'Clipped version',
|
|
312
|
+
}), onChange: (checked) => handleUpdate({ conicalFullCircle: !checked }) }), !conicalCoverage.fullCircle && (_jsxs(_Fragment, { children: [_jsx(SliderControl, { label: i18n._({ id: 'node.roofSegment.panel.startAngle', message: 'Start Angle' }), max: 180, min: -180, onChange: (degrees) => handleUpdate({ conicalStartAngle: (degrees * Math.PI) / 180 }), precision: 0, step: 1, unit: "\u00B0", value: Math.round((conicalCoverage.startAngle * 180) / Math.PI) }), _jsx(SliderControl, { label: i18n._({ id: 'node.roofSegment.panel.arc', message: 'Arc' }), max: 345, min: 15, onChange: (degrees) => handleUpdate({
|
|
243
313
|
conicalSweepAngle: (Math.sign(conicalCoverage.sweepAngle) * degrees * Math.PI) / 180,
|
|
244
|
-
}), precision: 0, step: 1, unit: "\u00B0", value: Math.round((Math.abs(conicalCoverage.sweepAngle) * 180) / Math.PI) })] }))] })), _jsx(PanelSection, { title:
|
|
314
|
+
}), precision: 0, step: 1, unit: "\u00B0", value: Math.round((Math.abs(conicalCoverage.sweepAngle) * 180) / Math.PI) })] }))] })), _jsx(PanelSection, { title: i18n._({ id: 'node.roofSegment.panel.wallHeight', message: 'Wall Height' }), children: _jsx(SliderControl, { label: i18n._({ id: 'node.roofSegment.panel.wall', message: 'Wall' }), max: 1000, min: 0, onChange: (v) => handleUpdate({ wallHeight: v }), precision: 2, step: 0.1, unit: "m", value: node.wallHeight }) }), node.roofType === 'barrel' ? (_jsx(BarrelRoofPanel, { node: node })) : (_jsxs(PanelSection, { title: i18n._({ id: 'node.roofSegment.panel.pitch', message: 'Pitch' }), children: [_jsx(SliderControl, { label: i18n._({ id: 'node.roofSegment.panel.angle', message: 'Angle' }), max: 60, min: 0, onChange: (v) => handleUpdate({ pitch: v }), precision: 0, step: 1, unit: "\u00B0", value: Math.round(node.pitch) }), _jsx("div", { className: "flex gap-1.5 px-1 pt-2 pb-1", children: PITCH_PRESETS.map((preset) => (_jsx(ActionButton, { label: preset.label, onClick: () => handleUpdate({ pitch: preset.deg }) }, preset.label))) })] })), node.roofType === 'gambrel' && (_jsxs(PanelSection, { title: i18n._({ id: 'node.roofSegment.panel.shape', message: 'Shape' }), children: [_jsx(SliderControl, { label: i18n._({ id: 'node.roofSegment.panel.kinkDepth', message: 'Kink Depth' }), max: 0.9, min: 0.1, onChange: (v) => handleUpdate({ gambrelLowerWidthRatio: v }), precision: 2, step: 0.01, unit: "", value: Math.round(node.gambrelLowerWidthRatio * 100) / 100 }), _jsx(SliderControl, { label: i18n._({ id: 'node.roofSegment.panel.kinkHeight', message: 'Kink Height' }), max: 0.9, min: 0.1, onChange: (v) => handleUpdate({ gambrelLowerHeightRatio: v }), precision: 2, step: 0.01, unit: "", value: Math.round(node.gambrelLowerHeightRatio * 100) / 100 })] })), node.roofType === 'mansard' && (_jsxs(PanelSection, { title: i18n._({ id: 'node.roofSegment.panel.shape', message: 'Shape' }), children: [_jsx(SliderControl, { label: i18n._({ id: 'node.roofSegment.panel.waistWidth', message: 'Waist Width' }), max: 0.45, min: 0.05, onChange: (v) => handleUpdate({ mansardSteepWidthRatio: v }), precision: 2, step: 0.01, unit: "", value: Math.round(node.mansardSteepWidthRatio * 100) / 100 }), _jsx(SliderControl, { label: i18n._({ id: 'node.roofSegment.panel.waistHeight', message: 'Waist Height' }), max: 0.9, min: 0.1, onChange: (v) => handleUpdate({ mansardSteepHeightRatio: v }), precision: 2, step: 0.01, unit: "", value: Math.round(node.mansardSteepHeightRatio * 100) / 100 })] })), node.roofType === 'dutch' && (_jsxs(PanelSection, { title: i18n._({ id: 'node.roofSegment.panel.shape', message: 'Shape' }), children: [_jsx(SliderControl, { label: i18n._({ id: 'node.roofSegment.panel.waistWidth', message: 'Waist Width' }), max: 0.45, min: 0.05, onChange: (v) => handleUpdate({ dutchHipWidthRatio: v }), precision: 2, step: 0.01, unit: "", value: Math.round(node.dutchHipWidthRatio * 100) / 100 }), _jsx(SliderControl, { label: i18n._({ id: 'node.roofSegment.panel.waistHeight', message: 'Waist Height' }), max: 0.9, min: 0.1, onChange: (v) => handleUpdate({ dutchHipHeightRatio: v }), precision: 2, step: 0.01, unit: "", value: Math.round(node.dutchHipHeightRatio * 100) / 100 }), _jsx(SliderControl, { label: i18n._({ id: 'node.roofSegment.panel.waistLength', message: 'Waist Length' }), max: 1, min: 0.1, onChange: (v) => handleUpdate({ dutchWaistLengthRatio: v }), precision: 2, step: 0.01, unit: "", value: Math.round((node.dutchWaistLengthRatio ?? ROOF_SHAPE_DEFAULTS.dutchWaistLengthRatio) * 100) / 100 }), _jsx(SliderControl, { label: i18n._({
|
|
315
|
+
id: 'node.roofSegment.panel.topRakeThick',
|
|
316
|
+
message: 'Top Rake Thick.',
|
|
317
|
+
}), max: 0.5, min: 0.01, onChange: (v) => handleUpdate({ dutchTopRakeThickness: v }), precision: 2, step: 0.01, unit: "m", value: node.dutchTopRakeThickness ?? ROOF_SHAPE_DEFAULTS.dutchTopRakeThickness }), _jsx(SliderControl, { label: i18n._({
|
|
318
|
+
id: 'node.roofSegment.panel.topRakeLength',
|
|
319
|
+
message: 'Top Rake Length',
|
|
320
|
+
}), max: 3, min: 0, onChange: (v) => handleUpdate({ dutchGabletRake: v }), precision: 2, step: 0.01, unit: "m", value: node.dutchGabletRake ?? ROOF_SHAPE_DEFAULTS.dutchGabletRake })] })), _jsxs(PanelSection, { title: i18n._({ id: 'node.roofSegment.panel.structure', message: 'Structure' }), children: [_jsx(SliderControl, { label: i18n._({ id: 'node.roofSegment.panel.wallThick', message: 'Wall Thick.' }), max: 1, min: 0.05, onChange: (v) => handleUpdate({ wallThickness: v }), precision: 2, step: 0.05, unit: "m", value: node.wallThickness }), !(isGlazedRoofSegment(node) || node.buildUp) && (_jsx(SliderControl, { label: i18n._({ id: 'node.roofSegment.panel.deckThick', message: 'Deck Thick.' }), max: 0.3, min: 0.04, onChange: (v) => handleUpdate({ deckThickness: v }), precision: 2, step: 0.01, unit: "m", value: node.deckThickness })), node.roofType === 'barrel' ? (_jsx(SliderControl, { label: i18n._({ id: 'node.roofSegment.panel.endOverhang', message: 'End overhang' }), max: 1, min: 0, onChange: (v) => handleUpdate({ overhang: v }), precision: 2, step: 0.05, unit: "m", value: reach.x - halfWall })) : (_jsx(SliderControl, { label: i18n._({ id: 'node.roofSegment.panel.eaveOverhang', message: 'Eave overhang' }), max: 1, min: 0, onChange: (v) => handleUpdate({ overhang: v / cosTheta }), precision: 2, step: 0.05, unit: "m", value: reach.z - halfWall })), roofTypeHasRakes(node.roofType) && (_jsx(SliderControl, { label: i18n._({
|
|
321
|
+
id: 'node.roofSegment.panel.gableOverhang',
|
|
322
|
+
message: 'Gable overhang',
|
|
323
|
+
}), max: 3, min: 0, onChange: (v) => handleUpdate({ gableOverhang: v }), precision: 2, step: 0.05, unit: "m", value: reach.x - halfWall })), !(isGlazedRoofSegment(node) || node.buildUp) && (_jsx(SliderControl, { label: i18n._({ id: 'node.roofSegment.panel.shingleThick', message: 'Shingle Thick.' }), max: 0.3, min: 0.02, onChange: (v) => handleUpdate({ shingleThickness: v }), precision: 2, step: 0.01, unit: "m", value: node.shingleThickness })), EAVE_CUT_ROOF_TYPES.has(node.roofType) && node.pitch > 0 && (_jsxs("div", { children: [_jsx("div", { className: "px-1 pb-1 text-[10px] text-muted-foreground uppercase tracking-wide", children: i18n._({ id: 'node.roofSegment.panel.eaveCut', message: 'Eave cut' }) }), _jsx(SegmentedControl, { onChange: (v) => handleUpdate({ eaveCut: v }), options: EAVE_CUT_OPTIONS.map((option) => ({
|
|
324
|
+
...option,
|
|
325
|
+
label: i18n._(option.label),
|
|
326
|
+
})), value: node.eaveCut ?? 'plumb' })] })), _jsx(ToggleControl, { checked: node.fascia ?? false, label: i18n._({ id: 'node.roofSegment.panel.fascia', message: 'Fascia' }), onChange: (checked) => handleUpdate({ fascia: checked }) }), node.fascia && (_jsx(SliderControl, { label: i18n._({ id: 'node.roofSegment.panel.fasciaHeight', message: 'Fascia height' }), max: 0.6, min: 0.1, onChange: (v) => handleUpdate({ fasciaHeight: v }), precision: 2, step: 0.01, unit: "m", value: node.fasciaHeight ?? roofSegmentEaveProfile(node).fascia.height }))] }), !isGlazedRoofSegment(node) && (_jsx(RoofBuildUpSection, { node: node, onApplyToRoof: roofPlaneCount > 1 ? handleApplyToRoof : undefined, onUpdate: handleUpdate, unit: unit })), _jsxs(PanelSection, { title: i18n._({ id: 'node.roofSegment.panel.position', message: 'Position' }), children: [_jsx(SliderControl, { label: "X", onChange: (v) => {
|
|
245
327
|
const pos = [...node.position];
|
|
246
328
|
pos[0] = v;
|
|
247
329
|
handleUpdate({ position: pos });
|
|
@@ -253,7 +335,7 @@ export default function RoofSegmentPanel() {
|
|
|
253
335
|
const pos = [...node.position];
|
|
254
336
|
pos[2] = v;
|
|
255
337
|
handleUpdate({ position: pos });
|
|
256
|
-
}, precision: 2, step: 0.05, unit: "m", value: node.position[2] }), (node.roofType !== 'conical' || !conicalCoverage.fullCircle) && (_jsxs(_Fragment, { children: [_jsx(SliderControl, { label:
|
|
338
|
+
}, precision: 2, step: 0.05, unit: "m", value: node.position[2] }), (node.roofType !== 'conical' || !conicalCoverage.fullCircle) && (_jsxs(_Fragment, { children: [_jsx(SliderControl, { label: i18n._({ id: 'node.roofSegment.panel.rotation', message: 'Rotation' }), max: 180, min: -180, onChange: (degrees) => {
|
|
257
339
|
handleUpdate({ rotation: (degrees * Math.PI) / 180 });
|
|
258
340
|
}, precision: 0, step: 1, unit: "\u00B0", value: Math.round((node.rotation * 180) / Math.PI) }), _jsxs("div", { className: "flex gap-1.5 px-1 pt-2 pb-1", children: [_jsx(ActionButton, { label: "-45\u00B0", onClick: () => {
|
|
259
341
|
triggerSFX('sfx:item-rotate');
|
|
@@ -261,5 +343,5 @@ export default function RoofSegmentPanel() {
|
|
|
261
343
|
} }), _jsx(ActionButton, { label: "+45\u00B0", onClick: () => {
|
|
262
344
|
triggerSFX('sfx:item-rotate');
|
|
263
345
|
handleUpdate({ rotation: node.rotation + Math.PI / 4 });
|
|
264
|
-
} })] })] }))] }), _jsx(PanelSection, { title:
|
|
346
|
+
} })] })] }))] }), _jsx(PanelSection, { title: i18n._({ id: 'node.roofSegment.panel.actions', message: 'Actions' }), children: _jsxs(ActionGroup, { children: [_jsx(ActionButton, { icon: _jsx(Move, { className: "h-3.5 w-3.5" }), label: i18n._({ id: 'node.roofSegment.panel.move', message: 'Move' }), onClick: handleMove }), _jsx(ActionButton, { icon: _jsx(Copy, { className: "h-3.5 w-3.5" }), label: i18n._({ id: 'node.roofSegment.panel.duplicate', message: 'Duplicate' }), onClick: handleDuplicate }), _jsx(ActionButton, { className: "hover:bg-red-500/20", icon: _jsx(Trash2, { className: "h-3.5 w-3.5 text-red-600 dark:text-red-400" }), label: i18n._({ id: 'node.roofSegment.panel.delete', message: 'Delete' }), onClick: handleDelete })] }) })] }));
|
|
265
347
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parametrics.d.ts","sourceRoot":"","sources":["../../src/roof-segment/parametrics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,oBAAoB,EAAE,KAAK,eAAe,EAAoB,MAAM,kBAAkB,CAAA;AAEpG,eAAO,MAAM,sBAAsB,EAAE,oBAAoB,CAAC,eAAe,
|
|
1
|
+
{"version":3,"file":"parametrics.d.ts","sourceRoot":"","sources":["../../src/roof-segment/parametrics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,oBAAoB,EAAE,KAAK,eAAe,EAAoB,MAAM,kBAAkB,CAAA;AAEpG,eAAO,MAAM,sBAAsB,EAAE,oBAAoB,CAAC,eAAe,CAiMxE,CAAA"}
|
|
@@ -140,6 +140,8 @@ export const roofSegmentParametrics = {
|
|
|
140
140
|
min: 0.04,
|
|
141
141
|
max: 0.3,
|
|
142
142
|
step: 0.01,
|
|
143
|
+
// Layers set it: edited here it would part from them.
|
|
144
|
+
visibleIf: (node) => !node.buildUp,
|
|
143
145
|
},
|
|
144
146
|
{ key: 'overhang', kind: 'number', unit: 'm', min: 0, max: 1, step: 0.05 },
|
|
145
147
|
{
|
|
@@ -160,6 +162,8 @@ export const roofSegmentParametrics = {
|
|
|
160
162
|
min: 0.02,
|
|
161
163
|
max: 0.3,
|
|
162
164
|
step: 0.01,
|
|
165
|
+
// Layers set it: edited here it would part from them.
|
|
166
|
+
visibleIf: (node) => !node.buildUp,
|
|
163
167
|
},
|
|
164
168
|
{
|
|
165
169
|
key: 'wallShell',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/roof-segment/renderer.tsx"],"names":[],"mappings":"AAEA,OAAO,
|
|
1
|
+
{"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/roof-segment/renderer.tsx"],"names":[],"mappings":"AAEA,OAAO,EASL,KAAK,eAAe,EAKrB,MAAM,kBAAkB,CAAA;AAkBzB,eAAO,MAAM,mBAAmB,yBAA0B;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,gCA4NlF,CAAA;eAEc,mBAAmB"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
-
import { getEffectiveNode, getEffectiveRoofSurfaceMaterial, getEffectiveSegmentSurfaceMaterial, getSegmentFasciaMaterial, isGlazedRoofSegment, useLiveNodeOverrides, useRegistry, useScene, } from '@pascal-app/core';
|
|
4
|
-
import { createMaterial, getRoofMaterialArray, levelWallCladdingRef, resolveMaterialRef, SHADOW_ONLY_LAYER, useNodeEvents, useViewer, } from '@pascal-app/viewer';
|
|
3
|
+
import { getEffectiveNode, getEffectiveRoofSurfaceMaterial, getEffectiveSegmentSurfaceMaterial, getRoofWallBandMaterial, getSegmentFasciaMaterial, isGlazedRoofSegment, useLiveNodeOverrides, useRegistry, useScene, } from '@pascal-app/core';
|
|
4
|
+
import { createMaterial, getRoofMaterialArray, levelWallCladdingRef, levelWallFaceRef, resolveMaterialRef, SHADOW_ONLY_LAYER, useNodeEvents, useViewer, } from '@pascal-app/viewer';
|
|
5
5
|
import { useEffect, useLayoutEffect, useMemo, useRef } from 'react';
|
|
6
6
|
import * as THREE from 'three';
|
|
7
7
|
import { syncGlazedRoofShadow } from '../roof/glazed-geometry.js';
|
|
@@ -51,8 +51,11 @@ export const RoofSegmentRenderer = ({ node: storedNode }) => {
|
|
|
51
51
|
// slot 1 → 'wall' (deck top & shingle eave bands)
|
|
52
52
|
// slot 2 → 'wall' (interior)
|
|
53
53
|
// slot 3 → 'top' (shingle / roof surface)
|
|
54
|
+
// slot 4 → the heel band (its own, the roof's, else the walls' below)
|
|
55
|
+
// slot 5 / 6 → the left / right gable (its own, else slot 0's)
|
|
54
56
|
// The gable band is clad like the walls below it (their assemblies).
|
|
55
57
|
const wallCladdingRef = useScene((state) => parentNode ? levelWallCladdingRef(state.nodes, parentNode) : null);
|
|
58
|
+
const wallFaceRef = useScene((state) => parentNode ? levelWallFaceRef(state.nodes, parentNode) : null);
|
|
56
59
|
// biome-ignore lint/correctness/useExhaustiveDependencies: deps deliberately list the build inputs; depending on the whole object would rebuild on unrelated field changes.
|
|
57
60
|
const customMaterial = useMemo(() => {
|
|
58
61
|
const resolveSlot = (role) => {
|
|
@@ -69,8 +72,15 @@ export const RoofSegmentRenderer = ({ node: storedNode }) => {
|
|
|
69
72
|
// Themed parent-roof array (per-role scene-theme colours) — used both as the
|
|
70
73
|
// full fallback and to fill any individual untextured slot below.
|
|
71
74
|
const themedArray = parentNode
|
|
72
|
-
? getRoofMaterialArray(parentNode, shading, textures, colorPreset, sceneTheme, wallCladdingRef, sceneMaterials)
|
|
75
|
+
? getRoofMaterialArray(parentNode, shading, textures, colorPreset, sceneTheme, wallCladdingRef, sceneMaterials, wallFaceRef)
|
|
73
76
|
: null;
|
|
77
|
+
const resolveSpec = (spec) => spec
|
|
78
|
+
? (resolveMaterialRef(spec.materialPreset, sceneMaterials, shading) ??
|
|
79
|
+
(spec.material !== undefined ? createMaterial(spec.material, shading) : null))
|
|
80
|
+
: null;
|
|
81
|
+
const heel = resolveSpec(getRoofWallBandMaterial(node, 'heel'));
|
|
82
|
+
const gableLeft = resolveSpec(getRoofWallBandMaterial(node, 'gable-left'));
|
|
83
|
+
const gableRight = resolveSpec(getRoofWallBandMaterial(node, 'gable-right'));
|
|
74
84
|
const edge = resolveSlot('edge');
|
|
75
85
|
const wall = resolveSlot('wall');
|
|
76
86
|
const top = resolveSlot('top');
|
|
@@ -80,7 +90,7 @@ export const RoofSegmentRenderer = ({ node: storedNode }) => {
|
|
|
80
90
|
? (resolveMaterialRef(fasciaSpec.materialPreset, sceneMaterials, shading) ??
|
|
81
91
|
(fasciaSpec.material !== undefined ? createMaterial(fasciaSpec.material, shading) : null))
|
|
82
92
|
: null;
|
|
83
|
-
if (!(edge || wall || top || fascia)) {
|
|
93
|
+
if (!(edge || wall || top || fascia || heel || gableLeft || gableRight)) {
|
|
84
94
|
return themedArray;
|
|
85
95
|
}
|
|
86
96
|
// Some slots have explicit materials; fill the rest from the themed array so
|
|
@@ -88,11 +98,15 @@ export const RoofSegmentRenderer = ({ node: storedNode }) => {
|
|
|
88
98
|
// Per-role only, then the themed parent slot — no cross-role fallback, so
|
|
89
99
|
// painting one segment surface never bleeds onto its other surfaces.
|
|
90
100
|
const slot = (i) => themedArray?.[i] ?? new THREE.MeshStandardMaterial();
|
|
101
|
+
const trim = edge ?? slot(0);
|
|
91
102
|
return [
|
|
92
|
-
|
|
103
|
+
trim,
|
|
93
104
|
wall ?? slot(1),
|
|
94
105
|
fascia ?? wall ?? slot(2),
|
|
95
106
|
top ?? slot(3),
|
|
107
|
+
heel ?? slot(4),
|
|
108
|
+
gableLeft ?? trim,
|
|
109
|
+
gableRight ?? trim,
|
|
96
110
|
];
|
|
97
111
|
}, [
|
|
98
112
|
node.material,
|
|
@@ -106,6 +120,13 @@ export const RoofSegmentRenderer = ({ node: storedNode }) => {
|
|
|
106
120
|
node.wallMaterialPreset,
|
|
107
121
|
node.fasciaMaterial,
|
|
108
122
|
node.fasciaMaterialPreset,
|
|
123
|
+
node.heelMaterial,
|
|
124
|
+
node.heelMaterialPreset,
|
|
125
|
+
node.gableLeftMaterial,
|
|
126
|
+
node.gableLeftMaterialPreset,
|
|
127
|
+
node.gableRightMaterial,
|
|
128
|
+
node.gableRightMaterialPreset,
|
|
129
|
+
wallFaceRef,
|
|
109
130
|
parentNode,
|
|
110
131
|
sceneMaterials,
|
|
111
132
|
shading,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../src/separator/definition.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;
|
|
1
|
+
{"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../src/separator/definition.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAIrE,eAAO,MAAM,mBAAmB,EAAE,cAAc,CAAC,OAAO,aAAa,CAiCpE,CAAA"}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { SeparatorNode } from '@pascal-app/core';
|
|
2
|
+
import { buildSeparatorFloorplan } from './floorplan.js';
|
|
3
|
+
import { separatorMoveEndpointAffordance } from './floorplan-affordances.js';
|
|
2
4
|
export const separatorDefinition = {
|
|
3
5
|
kind: 'separator',
|
|
6
|
+
// Its pushes and end drags snap as a wall's do.
|
|
7
|
+
snapProfile: 'structural',
|
|
4
8
|
bake: 'strip',
|
|
5
9
|
schemaVersion: 1,
|
|
6
10
|
schema: SeparatorNode,
|
|
@@ -18,18 +22,12 @@ export const separatorDefinition = {
|
|
|
18
22
|
dirtyTracking: false,
|
|
19
23
|
rendersChildren: false,
|
|
20
24
|
renderer: { kind: 'parametric', module: () => import('./renderer.js') },
|
|
21
|
-
floorplan:
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
stroke: '#818cf8',
|
|
28
|
-
strokeWidth: 2,
|
|
29
|
-
strokeDasharray: '6 4',
|
|
30
|
-
vectorEffect: 'non-scaling-stroke',
|
|
31
|
-
pointerEvents: 'stroke',
|
|
32
|
-
}),
|
|
25
|
+
floorplan: buildSeparatorFloorplan,
|
|
26
|
+
// An invisible wall moves as a wall does, taking the ones joined to it along:
|
|
27
|
+
// its side arrows push it (the plan's `move-arrow`s, the 3D selection
|
|
28
|
+
// handles) and its ends drag, on the plan and in 3D.
|
|
29
|
+
floorplanAffordances: { 'move-endpoint': separatorMoveEndpointAffordance },
|
|
30
|
+
affordanceTools: { selection: () => import('./selection.js') },
|
|
33
31
|
presentation: {
|
|
34
32
|
icon: { kind: 'iconify', name: 'lucide:split' },
|
|
35
33
|
label: 'Separator',
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { FloorplanAffordance, SeparatorNode } from '@pascal-app/core';
|
|
2
|
+
/**
|
|
3
|
+
* An invisible wall's end handle on the plan, the 2D twin of its 3D grip: the
|
|
4
|
+
* same snapping, preview and commit (`beginSeparatorEndDrag`), the pointer read
|
|
5
|
+
* by the floor plan. The invisible walls joined at that end follow it; Alt
|
|
6
|
+
* leaves them where they are.
|
|
7
|
+
*/
|
|
8
|
+
export declare const separatorMoveEndpointAffordance: FloorplanAffordance<SeparatorNode>;
|
|
9
|
+
//# sourceMappingURL=floorplan-affordances.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"floorplan-affordances.d.ts","sourceRoot":"","sources":["../../src/separator/floorplan-affordances.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,mBAAmB,EAEnB,aAAa,EACd,MAAM,kBAAkB,CAAA;AAKzB;;;;;GAKG;AACH,eAAO,MAAM,+BAA+B,EAAE,mBAAmB,CAAC,aAAa,CAe9E,CAAA"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { beginSeparatorEndDrag } from '@pascal-app/editor';
|
|
2
|
+
/**
|
|
3
|
+
* An invisible wall's end handle on the plan, the 2D twin of its 3D grip: the
|
|
4
|
+
* same snapping, preview and commit (`beginSeparatorEndDrag`), the pointer read
|
|
5
|
+
* by the floor plan. The invisible walls joined at that end follow it; Alt
|
|
6
|
+
* leaves them where they are.
|
|
7
|
+
*/
|
|
8
|
+
export const separatorMoveEndpointAffordance = {
|
|
9
|
+
start({ node, payload }) {
|
|
10
|
+
const { endpoint } = payload;
|
|
11
|
+
const drag = beginSeparatorEndDrag(node.id, endpoint);
|
|
12
|
+
return {
|
|
13
|
+
affectedIds: drag?.affectedIds ?? [node.id],
|
|
14
|
+
apply({ planPoint, modifiers }) {
|
|
15
|
+
drag?.move([planPoint[0], planPoint[1]], modifiers.altKey);
|
|
16
|
+
},
|
|
17
|
+
canCommit: () => drag?.canCommit() ?? false,
|
|
18
|
+
commit() {
|
|
19
|
+
drag?.commit();
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
},
|
|
23
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { FloorplanGeometry, GeometryContext, SeparatorNode } from '@pascal-app/core';
|
|
2
|
+
/**
|
|
3
|
+
* An invisible wall on the plan: a dashed line. Selected, it shows a wall's own
|
|
4
|
+
* handles — an end handle at each end (drag it; the invisible walls joined
|
|
5
|
+
* there follow) and a push arrow off each side (the wall push, the ones joined
|
|
6
|
+
* to it following).
|
|
7
|
+
*/
|
|
8
|
+
export declare function buildSeparatorFloorplan(node: SeparatorNode, ctx: GeometryContext): FloorplanGeometry;
|
|
9
|
+
//# sourceMappingURL=floorplan.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"floorplan.d.ts","sourceRoot":"","sources":["../../src/separator/floorplan.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAMzF;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,aAAa,EACnB,GAAG,EAAE,eAAe,GACnB,iBAAiB,CA2CnB"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { WALL_PUSH_AFFORDANCE } from '@pascal-app/editor';
|
|
2
|
+
/** How far off the line (m) a selected invisible wall's side arrows sit. */
|
|
3
|
+
const SIDE_ARROW_OFFSET = 0.12;
|
|
4
|
+
/**
|
|
5
|
+
* An invisible wall on the plan: a dashed line. Selected, it shows a wall's own
|
|
6
|
+
* handles — an end handle at each end (drag it; the invisible walls joined
|
|
7
|
+
* there follow) and a push arrow off each side (the wall push, the ones joined
|
|
8
|
+
* to it following).
|
|
9
|
+
*/
|
|
10
|
+
export function buildSeparatorFloorplan(node, ctx) {
|
|
11
|
+
const line = {
|
|
12
|
+
kind: 'line',
|
|
13
|
+
x1: node.start[0],
|
|
14
|
+
y1: node.start[1],
|
|
15
|
+
x2: node.end[0],
|
|
16
|
+
y2: node.end[1],
|
|
17
|
+
stroke: '#818cf8',
|
|
18
|
+
strokeWidth: 2,
|
|
19
|
+
strokeDasharray: '6 4',
|
|
20
|
+
vectorEffect: 'non-scaling-stroke',
|
|
21
|
+
pointerEvents: 'stroke',
|
|
22
|
+
};
|
|
23
|
+
if (!ctx.viewState?.selected)
|
|
24
|
+
return line;
|
|
25
|
+
const children = [line];
|
|
26
|
+
for (const endpoint of ['start', 'end'])
|
|
27
|
+
children.push({
|
|
28
|
+
kind: 'endpoint-handle',
|
|
29
|
+
point: [node[endpoint][0], node[endpoint][1]],
|
|
30
|
+
state: 'idle',
|
|
31
|
+
affordance: 'move-endpoint',
|
|
32
|
+
payload: { separatorId: node.id, endpoint },
|
|
33
|
+
});
|
|
34
|
+
const dx = node.end[0] - node.start[0];
|
|
35
|
+
const dz = node.end[1] - node.start[1];
|
|
36
|
+
const length = Math.hypot(dx, dz);
|
|
37
|
+
if (length > 1e-6) {
|
|
38
|
+
const middle = [(node.start[0] + node.end[0]) / 2, (node.start[1] + node.end[1]) / 2];
|
|
39
|
+
for (const side of ['a', 'b']) {
|
|
40
|
+
// Side `a` is the +normal one, as a wall's front.
|
|
41
|
+
const sign = side === 'a' ? 1 : -1;
|
|
42
|
+
const nx = (-dz / length) * sign;
|
|
43
|
+
const nz = (dx / length) * sign;
|
|
44
|
+
children.push({
|
|
45
|
+
kind: 'move-arrow',
|
|
46
|
+
point: [middle[0] + nx * SIDE_ARROW_OFFSET, middle[1] + nz * SIDE_ARROW_OFFSET],
|
|
47
|
+
angle: Math.atan2(nz, nx),
|
|
48
|
+
affordance: WALL_PUSH_AFFORDANCE,
|
|
49
|
+
payload: { wallId: node.id, side },
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return { kind: 'group', children };
|
|
54
|
+
}
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import { type SeparatorNode } from '@pascal-app/core';
|
|
2
|
+
/**
|
|
3
|
+
* An invisible wall in 3D: a dashed line on the floor, shown while its room or
|
|
4
|
+
* it is selected. A push or end drag moves it live (`useLiveNodeOverrides`).
|
|
5
|
+
*/
|
|
2
6
|
export default function SeparatorRenderer({ node }: {
|
|
3
7
|
node: SeparatorNode;
|
|
4
8
|
}): import("react").JSX.Element;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/separator/renderer.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,aAAa,
|
|
1
|
+
{"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/separator/renderer.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,aAAa,EAA+C,MAAM,kBAAkB,CAAA;AAUlG;;;GAGG;AACH,MAAM,CAAC,OAAO,UAAU,iBAAiB,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,+BAgE1E"}
|
|
@@ -1,26 +1,41 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { useRegistry, useScene } from '@pascal-app/core';
|
|
4
|
-
import { useEditor } from '@pascal-app/editor';
|
|
3
|
+
import { useLiveNodeOverrides, useRegistry, useScene } from '@pascal-app/core';
|
|
4
|
+
import { separatorFloorElevation, useEditor } from '@pascal-app/editor';
|
|
5
5
|
import { useNodeEvents, useViewer } from '@pascal-app/viewer';
|
|
6
6
|
import { useEffect, useMemo, useRef } from 'react';
|
|
7
7
|
import { BufferGeometry, Float32BufferAttribute } from 'three';
|
|
8
8
|
import { LineBasicNodeMaterial, MeshBasicNodeMaterial } from 'three/webgpu';
|
|
9
9
|
const separatorMaterial = new LineBasicNodeMaterial({ color: '#818cf8', depthWrite: false });
|
|
10
10
|
const hitMaterial = new MeshBasicNodeMaterial({ transparent: true, opacity: 0, depthWrite: false });
|
|
11
|
+
/**
|
|
12
|
+
* An invisible wall in 3D: a dashed line on the floor, shown while its room or
|
|
13
|
+
* it is selected. A push or end drag moves it live (`useLiveNodeOverrides`).
|
|
14
|
+
*/
|
|
11
15
|
export default function SeparatorRenderer({ node }) {
|
|
12
16
|
const ref = useRef(null);
|
|
13
17
|
useRegistry(node.id, 'separator', ref);
|
|
14
18
|
const roomId = useEditor((s) => s.room?.zoneId);
|
|
15
19
|
const viewerRoomId = useViewer((s) => s.selection.zoneId);
|
|
20
|
+
const selected = useViewer((s) => s.selection.selectedIds.includes(node.id));
|
|
16
21
|
const zone = useScene((s) => {
|
|
17
22
|
const id = roomId ?? viewerRoomId;
|
|
18
23
|
return id ? s.nodes[id] : undefined;
|
|
19
24
|
});
|
|
20
|
-
const
|
|
25
|
+
const inRoom = zone?.type === 'zone' && zone.boundarySeparatorIds.includes(node.id);
|
|
26
|
+
const visible = inRoom || selected;
|
|
27
|
+
// Selected on its own, it lies on the floor of a room it closes.
|
|
28
|
+
const ownFloor = useScene((s) => selected && !inRoom ? separatorFloorElevation(s.nodes, node.id) : null);
|
|
29
|
+
const live = useLiveNodeOverrides((s) => s.overrides.get(node.id));
|
|
30
|
+
const start = live?.start ?? node.start;
|
|
31
|
+
const end = live?.end ?? node.end;
|
|
21
32
|
const events = useNodeEvents(node, 'separator');
|
|
22
|
-
const y = zone?.type === 'zone'
|
|
23
|
-
|
|
33
|
+
const y = zone?.type === 'zone' && inRoom
|
|
34
|
+
? (zone.floor?.elevation ?? 0.05) + 0.02
|
|
35
|
+
: ownFloor !== null
|
|
36
|
+
? ownFloor + 0.02
|
|
37
|
+
: 0.07;
|
|
38
|
+
const dx = end[0] - start[0], dz = end[1] - start[1];
|
|
24
39
|
const length = Math.hypot(dx, dz);
|
|
25
40
|
const geometry = useMemo(() => {
|
|
26
41
|
const positions = [];
|
|
@@ -32,5 +47,5 @@ export default function SeparatorRenderer({ node }) {
|
|
|
32
47
|
return new BufferGeometry().setAttribute('position', new Float32BufferAttribute(positions, 3));
|
|
33
48
|
}, [length]);
|
|
34
49
|
useEffect(() => () => geometry.dispose(), [geometry]);
|
|
35
|
-
return (_jsx("group", { ref: ref, visible: visible, children: visible && (_jsxs(_Fragment, { children: [_jsx("lineSegments", { geometry: geometry, material: separatorMaterial, position: [
|
|
50
|
+
return (_jsx("group", { ref: ref, visible: visible, children: visible && (_jsxs(_Fragment, { children: [_jsx("lineSegments", { geometry: geometry, material: separatorMaterial, position: [start[0], y, start[1]], rotation: [0, -Math.atan2(dz, dx), 0], raycast: () => { } }), _jsx("mesh", { ...events, material: hitMaterial, position: [(start[0] + end[0]) / 2, y, (start[1] + end[1]) / 2], rotation: [0, -Math.atan2(dz, dx), 0], children: _jsx("boxGeometry", { args: [length, 0.03, 0.1] }) })] })) }));
|
|
36
51
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type SelectionAffordanceProps } from '@pascal-app/editor';
|
|
2
|
+
/**
|
|
3
|
+
* A selected invisible wall's 3D handles, the twins of its plan ones: a push
|
|
4
|
+
* arrow off each side (the wall push: the invisible walls joined to it follow
|
|
5
|
+
* and those T'd into it stretch) and a grip at each end (drag it across the
|
|
6
|
+
* floor; the ones joined there follow). They lie on the floor of the room it
|
|
7
|
+
* closes, where its dashed line is drawn, and hide while a drag runs.
|
|
8
|
+
*/
|
|
9
|
+
export default function SeparatorSelectionAffordance({ node, readOnly }: SelectionAffordanceProps): import("react").JSX.Element | null;
|
|
10
|
+
//# sourceMappingURL=selection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selection.d.ts","sourceRoot":"","sources":["../../src/separator/selection.tsx"],"names":[],"mappings":"AAGA,OAAO,EACL,KAAK,wBAAwB,EAO9B,MAAM,oBAAoB,CAAA;AAK3B;;;;;;GAMG;AACH,MAAM,CAAC,OAAO,UAAU,4BAA4B,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,wBAAwB,sCAmChG"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { sceneRegistry, useScene } from '@pascal-app/core';
|
|
4
|
+
import { SeparatorEndGrip, separatorFloorElevation, separatorPushHandles, useEditor, useInteractionScope, WallPushArrow, } from '@pascal-app/editor';
|
|
5
|
+
import { createPortal } from '@react-three/fiber';
|
|
6
|
+
import { useEffect, useState } from 'react';
|
|
7
|
+
/**
|
|
8
|
+
* A selected invisible wall's 3D handles, the twins of its plan ones: a push
|
|
9
|
+
* arrow off each side (the wall push: the invisible walls joined to it follow
|
|
10
|
+
* and those T'd into it stretch) and a grip at each end (drag it across the
|
|
11
|
+
* floor; the ones joined there follow). They lie on the floor of the room it
|
|
12
|
+
* closes, where its dashed line is drawn, and hide while a drag runs.
|
|
13
|
+
*/
|
|
14
|
+
export default function SeparatorSelectionAffordance({ node, readOnly }) {
|
|
15
|
+
const editing = useEditor((s) => s.mode === 'select' && !s.isFloorplanHovered);
|
|
16
|
+
const idle = useInteractionScope((s) => s.scope.kind === 'idle');
|
|
17
|
+
const floor = useScene((s) => separatorFloorElevation(s.nodes, node.id));
|
|
18
|
+
const levelId = node.parentId;
|
|
19
|
+
const [level, setLevel] = useState(null);
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
let frame = 0;
|
|
22
|
+
const resolve = () => {
|
|
23
|
+
const next = levelId ? (sceneRegistry.nodes.get(levelId) ?? null) : null;
|
|
24
|
+
setLevel((current) => (current === next ? current : next));
|
|
25
|
+
if (!next && levelId)
|
|
26
|
+
frame = window.requestAnimationFrame(resolve);
|
|
27
|
+
};
|
|
28
|
+
resolve();
|
|
29
|
+
return () => window.cancelAnimationFrame(frame);
|
|
30
|
+
}, [levelId]);
|
|
31
|
+
if (node.type !== 'separator' || readOnly || !editing || !idle || !level || !levelId)
|
|
32
|
+
return null;
|
|
33
|
+
const separator = node;
|
|
34
|
+
return createPortal(_jsxs(_Fragment, { children: [separatorPushHandles(separator, floor).map((handle) => (_jsx(WallPushArrow, { handle: handle, levelId: levelId }, handle.key))), ['start', 'end'].map((endpoint) => (_jsx(SeparatorEndGrip, { endpoint: endpoint, height: floor + 0.02, levelId: levelId, separator: separator }, endpoint)))] }), level);
|
|
35
|
+
}
|