@pascal-app/core 1.0.0-beta.5 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +23 -0
- package/dist/capture/index.d.ts +3 -0
- package/dist/capture/index.d.ts.map +1 -0
- package/dist/capture/index.js +2 -0
- package/dist/capture/schema.d.ts +417 -0
- package/dist/capture/schema.d.ts.map +1 -0
- package/dist/capture/schema.js +350 -0
- package/dist/capture/source.d.ts +60 -0
- package/dist/capture/source.d.ts.map +1 -0
- package/dist/capture/source.js +254 -0
- package/dist/events/bus.d.ts +58 -7
- package/dist/events/bus.d.ts.map +1 -1
- package/dist/events/hidden-wall-pointer-hold.d.ts +28 -0
- package/dist/events/hidden-wall-pointer-hold.d.ts.map +1 -0
- package/dist/events/hidden-wall-pointer-hold.js +37 -0
- package/dist/hooks/spatial-grid/floor-placed-elevation.d.ts +4 -4
- package/dist/hooks/spatial-grid/floor-placed-elevation.d.ts.map +1 -1
- package/dist/hooks/spatial-grid/floor-placed-elevation.js +7 -12
- package/dist/hooks/spatial-grid/floor-placed-footprints.d.ts +4 -0
- package/dist/hooks/spatial-grid/floor-placed-footprints.d.ts.map +1 -0
- package/dist/hooks/spatial-grid/floor-placed-footprints.js +7 -0
- package/dist/hooks/spatial-grid/spatial-grid-manager.d.ts +5 -8
- package/dist/hooks/spatial-grid/spatial-grid-manager.d.ts.map +1 -1
- package/dist/hooks/spatial-grid/spatial-grid-manager.js +23 -106
- package/dist/hooks/spatial-grid/spatial-grid-sync.d.ts +2931 -2
- package/dist/hooks/spatial-grid/spatial-grid-sync.d.ts.map +1 -1
- package/dist/hooks/spatial-grid/spatial-grid-sync.js +207 -30
- package/dist/hooks/spatial-grid/support-host-patch.d.ts +45 -1
- package/dist/hooks/spatial-grid/support-host-patch.d.ts.map +1 -1
- package/dist/hooks/spatial-grid/support-host-patch.js +174 -9
- package/dist/hooks/spatial-grid/use-spatial-query.d.ts +1 -1
- package/dist/hooks/spatial-grid/use-spatial-query.js +1 -1
- package/dist/index.d.ts +74 -64
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +74 -61
- package/dist/lib/asset-storage.d.ts.map +1 -1
- package/dist/lib/asset-storage.js +4 -1
- package/dist/lib/door-operation.d.ts +1 -1
- package/dist/lib/item-polygon-overlap.d.ts +6 -0
- package/dist/lib/item-polygon-overlap.d.ts.map +1 -0
- package/dist/lib/item-polygon-overlap.js +67 -0
- package/dist/lib/level-name.d.ts +1 -1
- package/dist/lib/measurement-geometry.d.ts +4 -4
- package/dist/lib/plan-footprint.d.ts +41 -0
- package/dist/lib/plan-footprint.d.ts.map +1 -0
- package/dist/lib/plan-footprint.js +58 -0
- package/dist/lib/polygon-union.d.ts +4 -0
- package/dist/lib/polygon-union.d.ts.map +1 -0
- package/dist/lib/polygon-union.js +306 -0
- package/dist/lib/roof-overlap.d.ts +32 -0
- package/dist/lib/roof-overlap.d.ts.map +1 -0
- package/dist/lib/roof-overlap.js +72 -0
- package/dist/lib/room-topology-index.d.ts +1 -1
- package/dist/lib/room-topology-index.js +1 -1
- package/dist/lib/selection-proxy.d.ts +1 -1
- package/dist/lib/slab-polygon.d.ts +36 -3
- package/dist/lib/slab-polygon.d.ts.map +1 -1
- package/dist/lib/slab-polygon.js +135 -29
- package/dist/lib/space-detection.d.ts +12 -1
- package/dist/lib/space-detection.d.ts.map +1 -1
- package/dist/lib/space-detection.js +58 -25
- package/dist/lib/terrain-brush.d.ts +1 -1
- package/dist/lib/terrain-brush.js +1 -1
- package/dist/lib/terrain-codec.d.ts +2 -2
- package/dist/lib/terrain-codec.js +1 -1
- package/dist/lib/terrain-raycast.d.ts +1 -1
- package/dist/lib/terrain-raycast.js +1 -1
- package/dist/lib/terrain-source.d.ts +3 -3
- package/dist/lib/terrain-source.js +3 -3
- package/dist/lib/terrain-support.d.ts +1 -1
- package/dist/lib/terrain-support.js +3 -3
- package/dist/lib/unit-containment.d.ts +19 -0
- package/dist/lib/unit-containment.d.ts.map +1 -0
- package/dist/lib/unit-containment.js +158 -0
- package/dist/lib/unit-report.d.ts +19 -0
- package/dist/lib/unit-report.d.ts.map +1 -0
- package/dist/lib/unit-report.js +36 -0
- package/dist/lib/wall-distance.d.ts +2 -2
- package/dist/lib/wall-distance.js +1 -1
- package/dist/lib/zone-quantities.d.ts +1 -1
- package/dist/lib/zone-quantities.js +7 -7
- package/dist/material-library.d.ts +1 -1
- package/dist/material-library.js +1 -1
- package/dist/procedural-items/fixtures.d.ts +261 -0
- package/dist/procedural-items/fixtures.d.ts.map +1 -0
- package/dist/procedural-items/fixtures.js +349 -0
- package/dist/procedural-items/index.d.ts +10 -0
- package/dist/procedural-items/index.d.ts.map +1 -0
- package/dist/procedural-items/index.js +9 -0
- package/dist/procedural-items/integration.d.ts +92 -0
- package/dist/procedural-items/integration.d.ts.map +1 -0
- package/dist/procedural-items/integration.js +19 -0
- package/dist/procedural-items/library-colors.d.ts +56 -0
- package/dist/procedural-items/library-colors.d.ts.map +1 -0
- package/dist/procedural-items/library-colors.js +84 -0
- package/dist/procedural-items/materials.d.ts +5 -0
- package/dist/procedural-items/materials.d.ts.map +1 -0
- package/dist/procedural-items/materials.js +47 -0
- package/dist/procedural-items/node.d.ts +280 -0
- package/dist/procedural-items/node.d.ts.map +1 -0
- package/dist/procedural-items/node.js +71 -0
- package/dist/procedural-items/placement.d.ts +7 -0
- package/dist/procedural-items/placement.d.ts.map +1 -0
- package/dist/procedural-items/placement.js +48 -0
- package/dist/procedural-items/query.d.ts +50 -0
- package/dist/procedural-items/query.d.ts.map +1 -0
- package/dist/procedural-items/query.js +298 -0
- package/dist/procedural-items/recipe.d.ts +144 -0
- package/dist/procedural-items/recipe.d.ts.map +1 -0
- package/dist/procedural-items/recipe.js +372 -0
- package/dist/procedural-items/spatial.d.ts +19 -0
- package/dist/procedural-items/spatial.d.ts.map +1 -0
- package/dist/procedural-items/spatial.js +39 -0
- package/dist/registry/__bench__/relations-resolver.bench.js +2 -2
- package/dist/registry/handles.d.ts +36 -7
- package/dist/registry/handles.d.ts.map +1 -1
- package/dist/registry/index.d.ts +6 -7
- package/dist/registry/index.d.ts.map +1 -1
- package/dist/registry/index.js +4 -5
- package/dist/registry/registry.d.ts +13 -6
- package/dist/registry/registry.d.ts.map +1 -1
- package/dist/registry/registry.js +37 -4
- package/dist/registry/relations-resolver.d.ts +2 -2
- package/dist/registry/relations-resolver.js +1 -1
- package/dist/registry/scene-api.d.ts +18 -2
- package/dist/registry/scene-api.d.ts.map +1 -1
- package/dist/registry/scene-api.js +50 -2
- package/dist/registry/subtree.d.ts +1 -1
- package/dist/registry/subtree.js +2 -2
- package/dist/registry/types.d.ts +246 -21
- package/dist/registry/types.d.ts.map +1 -1
- package/dist/registry/use-registry-version.js +1 -1
- package/dist/registry/validate-relations.d.ts +4 -0
- package/dist/registry/validate-relations.d.ts.map +1 -0
- package/dist/registry/validate-relations.js +22 -0
- package/dist/schema/__bench__/node-parsers.bench.d.ts +24 -0
- package/dist/schema/__bench__/node-parsers.bench.d.ts.map +1 -0
- package/dist/schema/__bench__/node-parsers.bench.js +314 -0
- package/dist/schema/__fixtures__/node-fixtures.d.ts +28 -0
- package/dist/schema/__fixtures__/node-fixtures.d.ts.map +1 -0
- package/dist/schema/__fixtures__/node-fixtures.js +127 -0
- package/dist/schema/base.d.ts +1 -1
- package/dist/schema/base.d.ts.map +1 -1
- package/dist/schema/base.js +9 -2
- package/dist/schema/collections.d.ts +1 -1
- package/dist/schema/collections.js +1 -1
- package/dist/schema/compiled-node-parsers.d.ts +40 -0
- package/dist/schema/compiled-node-parsers.d.ts.map +1 -0
- package/dist/schema/compiled-node-parsers.js +95 -0
- package/dist/schema/index.d.ts +73 -66
- package/dist/schema/index.d.ts.map +1 -1
- package/dist/schema/index.js +65 -57
- package/dist/schema/material.d.ts +1 -0
- package/dist/schema/material.d.ts.map +1 -1
- package/dist/schema/material.js +2 -1
- package/dist/schema/nodes/automatic-downspout.d.ts +17 -0
- package/dist/schema/nodes/automatic-downspout.d.ts.map +1 -0
- package/dist/schema/nodes/automatic-downspout.js +237 -0
- package/dist/schema/nodes/block.d.ts +107 -0
- package/dist/schema/nodes/block.d.ts.map +1 -0
- package/dist/schema/nodes/block.js +206 -0
- package/dist/schema/nodes/box-vent.d.ts +8 -2
- package/dist/schema/nodes/box-vent.d.ts.map +1 -1
- package/dist/schema/nodes/box-vent.js +4 -2
- package/dist/schema/nodes/building.d.ts +2 -2
- package/dist/schema/nodes/building.d.ts.map +1 -1
- package/dist/schema/nodes/building.js +8 -5
- package/dist/schema/nodes/cabinet.d.ts +26 -4
- package/dist/schema/nodes/cabinet.d.ts.map +1 -1
- package/dist/schema/nodes/cabinet.js +29 -8
- package/dist/schema/nodes/ceiling.d.ts +2 -2
- package/dist/schema/nodes/ceiling.js +5 -5
- package/dist/schema/nodes/chimney.d.ts +2 -2
- package/dist/schema/nodes/chimney.js +2 -2
- package/dist/schema/nodes/column.d.ts +7 -6
- package/dist/schema/nodes/column.d.ts.map +1 -1
- package/dist/schema/nodes/column.js +3 -2
- package/dist/schema/nodes/construction-dimension.d.ts +1 -1
- package/dist/schema/nodes/construction-dimension.js +2 -2
- package/dist/schema/nodes/cupola.d.ts +9 -1
- package/dist/schema/nodes/cupola.d.ts.map +1 -1
- package/dist/schema/nodes/cupola.js +4 -2
- package/dist/schema/nodes/door.d.ts +1 -1
- package/dist/schema/nodes/door.js +2 -2
- package/dist/schema/nodes/dormer.d.ts +45 -2
- package/dist/schema/nodes/dormer.d.ts.map +1 -1
- package/dist/schema/nodes/dormer.js +133 -9
- package/dist/schema/nodes/downspout.d.ts +11 -1
- package/dist/schema/nodes/downspout.d.ts.map +1 -1
- package/dist/schema/nodes/downspout.js +26 -2
- package/dist/schema/nodes/duct-fitting.d.ts +18 -1
- package/dist/schema/nodes/duct-fitting.d.ts.map +1 -1
- package/dist/schema/nodes/duct-fitting.js +26 -5
- package/dist/schema/nodes/duct-segment.d.ts +23 -1
- package/dist/schema/nodes/duct-segment.d.ts.map +1 -1
- package/dist/schema/nodes/duct-segment.js +21 -1
- package/dist/schema/nodes/duct-terminal.d.ts +1 -1
- package/dist/schema/nodes/duct-terminal.js +1 -1
- package/dist/schema/nodes/elevator.d.ts +1 -1
- package/dist/schema/nodes/elevator.js +2 -2
- package/dist/schema/nodes/eyebrow-vent.d.ts +8 -2
- package/dist/schema/nodes/eyebrow-vent.d.ts.map +1 -1
- package/dist/schema/nodes/eyebrow-vent.js +4 -2
- package/dist/schema/nodes/fence.d.ts +1 -1
- package/dist/schema/nodes/fence.js +2 -2
- package/dist/schema/nodes/guide.d.ts +1 -1
- package/dist/schema/nodes/guide.js +2 -2
- package/dist/schema/nodes/gutter.d.ts +36 -2
- package/dist/schema/nodes/gutter.d.ts.map +1 -1
- package/dist/schema/nodes/gutter.js +310 -3
- package/dist/schema/nodes/hanger-overrides.d.ts +7 -0
- package/dist/schema/nodes/hanger-overrides.d.ts.map +1 -0
- package/dist/schema/nodes/hanger-overrides.js +6 -0
- package/dist/schema/nodes/hvac-equipment.d.ts +1 -1
- package/dist/schema/nodes/hvac-equipment.js +1 -1
- package/dist/schema/nodes/imported-mesh.d.ts +40 -0
- package/dist/schema/nodes/imported-mesh.d.ts.map +1 -0
- package/dist/schema/nodes/imported-mesh.js +27 -0
- package/dist/schema/nodes/item.d.ts +3 -2
- package/dist/schema/nodes/item.d.ts.map +1 -1
- package/dist/schema/nodes/item.js +8 -3
- package/dist/schema/nodes/lean-to-extension.d.ts +212 -0
- package/dist/schema/nodes/lean-to-extension.d.ts.map +1 -0
- package/dist/schema/nodes/lean-to-extension.js +114 -0
- package/dist/schema/nodes/level.d.ts +2 -2
- package/dist/schema/nodes/level.d.ts.map +1 -1
- package/dist/schema/nodes/level.js +1 -1
- package/dist/schema/nodes/lineset.d.ts +1 -1
- package/dist/schema/nodes/lineset.js +1 -1
- package/dist/schema/nodes/liquid-line.d.ts +1 -1
- package/dist/schema/nodes/liquid-line.js +1 -1
- package/dist/schema/nodes/measurement.d.ts +1 -1
- package/dist/schema/nodes/measurement.js +2 -2
- package/dist/schema/nodes/pipe-fitting.d.ts +10 -2
- package/dist/schema/nodes/pipe-fitting.d.ts.map +1 -1
- package/dist/schema/nodes/pipe-fitting.js +7 -3
- package/dist/schema/nodes/pipe-segment.d.ts +24 -2
- package/dist/schema/nodes/pipe-segment.d.ts.map +1 -1
- package/dist/schema/nodes/pipe-segment.js +21 -1
- package/dist/schema/nodes/pipe-trap.d.ts +2 -2
- package/dist/schema/nodes/pipe-trap.js +1 -1
- package/dist/schema/nodes/ridge-vent.d.ts +2 -2
- package/dist/schema/nodes/ridge-vent.d.ts.map +1 -1
- package/dist/schema/nodes/ridge-vent.js +7 -4
- package/dist/schema/nodes/roof-segment-shape.d.ts +5 -1
- package/dist/schema/nodes/roof-segment-shape.d.ts.map +1 -1
- package/dist/schema/nodes/roof-segment-shape.js +65 -2
- package/dist/schema/nodes/roof-segment-walls.d.ts +4 -2
- package/dist/schema/nodes/roof-segment-walls.d.ts.map +1 -1
- package/dist/schema/nodes/roof-segment-walls.js +2 -2
- package/dist/schema/nodes/roof-segment.d.ts +42 -2
- package/dist/schema/nodes/roof-segment.d.ts.map +1 -1
- package/dist/schema/nodes/roof-segment.js +81 -4
- package/dist/schema/nodes/roof.d.ts +23 -2
- package/dist/schema/nodes/roof.d.ts.map +1 -1
- package/dist/schema/nodes/roof.js +17 -3
- package/dist/schema/nodes/scan.d.ts +19 -2
- package/dist/schema/nodes/scan.d.ts.map +1 -1
- package/dist/schema/nodes/scan.js +13 -3
- package/dist/schema/nodes/shelf.d.ts +3 -3
- package/dist/schema/nodes/shelf.d.ts.map +1 -1
- package/dist/schema/nodes/shelf.js +3 -4
- package/dist/schema/nodes/site.d.ts +1 -1
- package/dist/schema/nodes/site.js +2 -2
- package/dist/schema/nodes/skylight.d.ts +5 -5
- package/dist/schema/nodes/skylight.js +2 -2
- package/dist/schema/nodes/slab.d.ts +1 -1
- package/dist/schema/nodes/slab.js +3 -3
- package/dist/schema/nodes/solar-panel.d.ts +1 -1
- package/dist/schema/nodes/solar-panel.js +3 -3
- package/dist/schema/nodes/spawn.d.ts +1 -1
- package/dist/schema/nodes/spawn.js +1 -1
- package/dist/schema/nodes/stair-segment.d.ts +1 -1
- package/dist/schema/nodes/stair-segment.js +2 -2
- package/dist/schema/nodes/stair.d.ts +2 -2
- package/dist/schema/nodes/stair.js +3 -3
- package/dist/schema/nodes/structural-grid.d.ts +1 -1
- package/dist/schema/nodes/structural-grid.js +1 -1
- package/dist/schema/nodes/turbine-vent.d.ts +8 -2
- package/dist/schema/nodes/turbine-vent.d.ts.map +1 -1
- package/dist/schema/nodes/turbine-vent.js +4 -2
- package/dist/schema/nodes/unit.d.ts +33 -0
- package/dist/schema/nodes/unit.d.ts.map +1 -0
- package/dist/schema/nodes/unit.js +13 -0
- package/dist/schema/nodes/wall.d.ts +5 -5
- package/dist/schema/nodes/wall.d.ts.map +1 -1
- package/dist/schema/nodes/wall.js +13 -6
- package/dist/schema/nodes/window.d.ts +10 -3
- package/dist/schema/nodes/window.d.ts.map +1 -1
- package/dist/schema/nodes/window.js +6 -2
- package/dist/schema/nodes/zone.d.ts +2 -2
- package/dist/schema/nodes/zone.js +2 -2
- package/dist/schema/scene-material.js +2 -2
- package/dist/schema/types.d.ts +815 -118
- package/dist/schema/types.d.ts.map +1 -1
- package/dist/schema/types.js +79 -46
- package/dist/services/alignment-anchors.d.ts +6 -11
- package/dist/services/alignment-anchors.d.ts.map +1 -1
- package/dist/services/alignment-anchors.js +7 -34
- package/dist/services/drag-session.d.ts +4 -4
- package/dist/services/drag-session.js +1 -1
- package/dist/services/hosting.d.ts +4 -10
- package/dist/services/hosting.d.ts.map +1 -1
- package/dist/services/hosting.js +6 -16
- package/dist/services/index.d.ts +16 -13
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/index.js +16 -13
- package/dist/services/level-height.d.ts +2 -2
- package/dist/services/level-height.js +3 -3
- package/dist/services/movement.d.ts +3 -3
- package/dist/services/movement.js +2 -2
- package/dist/services/port-connectivity.d.ts +1 -1
- package/dist/services/port-connectivity.js +1 -1
- package/dist/services/riser-diagram.d.ts +1 -1
- package/dist/services/shelf-board.d.ts +5 -0
- package/dist/services/shelf-board.d.ts.map +1 -0
- package/dist/services/shelf-board.js +15 -0
- package/dist/services/storey.d.ts +2 -2
- package/dist/services/storey.js +2 -2
- package/dist/services/surface-hosting-procedural-parity.fixtures.d.ts +13 -0
- package/dist/services/surface-hosting-procedural-parity.fixtures.d.ts.map +1 -0
- package/dist/services/surface-hosting-procedural-parity.fixtures.js +4691 -0
- package/dist/services/surface-hosting-shelf-parity.fixtures.d.ts +1060 -0
- package/dist/services/surface-hosting-shelf-parity.fixtures.d.ts.map +1 -0
- package/dist/services/surface-hosting-shelf-parity.fixtures.js +3127 -0
- package/dist/services/surface-hosting.d.ts +88 -0
- package/dist/services/surface-hosting.d.ts.map +1 -0
- package/dist/services/surface-hosting.js +268 -0
- package/dist/services/surface-region.d.ts +8 -0
- package/dist/services/surface-region.d.ts.map +1 -0
- package/dist/services/surface-region.js +44 -0
- package/dist/services/system-graph.d.ts +12 -1
- package/dist/services/system-graph.d.ts.map +1 -1
- package/dist/services/system-graph.js +36 -6
- package/dist/services/validate-dwv.d.ts +1 -1
- package/dist/services/validate-dwv.js +1 -1
- package/dist/store/actions/node-actions.d.ts +9 -2
- package/dist/store/actions/node-actions.d.ts.map +1 -1
- package/dist/store/actions/node-actions.js +475 -24
- package/dist/store/history-control.d.ts +3 -3
- package/dist/store/history-invalidation.d.ts +3 -0
- package/dist/store/history-invalidation.d.ts.map +1 -0
- package/dist/store/history-invalidation.js +72 -0
- package/dist/store/scene-hydration.d.ts +5 -0
- package/dist/store/scene-hydration.d.ts.map +1 -0
- package/dist/store/scene-hydration.js +57 -0
- package/dist/store/use-interactive.d.ts +2 -2
- package/dist/store/use-live-terrain.d.ts +1 -1
- package/dist/store/use-scene.d.ts +7 -4
- package/dist/store/use-scene.d.ts.map +1 -1
- package/dist/store/use-scene.js +361 -87
- package/dist/systems/elevator/elevator-dispatch.d.ts +2 -2
- package/dist/systems/elevator/elevator-dispatch.js +1 -1
- package/dist/systems/elevator/elevator-geometry.d.ts +1 -1
- package/dist/systems/elevator/elevator-opening-sync.d.ts +1 -1
- package/dist/systems/elevator/elevator-opening-sync.js +2 -2
- package/dist/systems/elevator/elevator-opening-system.js +3 -3
- package/dist/systems/elevator/elevator-runtime.d.ts +3 -3
- package/dist/systems/elevator/elevator-runtime.js +3 -3
- package/dist/systems/elevator/elevator-service.d.ts +1 -1
- package/dist/systems/elevator/elevator-service.js +1 -1
- package/dist/systems/fence/fence-centerline.d.ts +2 -2
- package/dist/systems/fence/fence-centerline.js +2 -2
- package/dist/systems/fence/fence-spline.d.ts +2 -2
- package/dist/systems/roof/roof-elevation-system.d.ts +3 -0
- package/dist/systems/roof/roof-elevation-system.d.ts.map +1 -0
- package/dist/systems/roof/roof-elevation-system.js +94 -0
- package/dist/systems/roof/roof-elevation.d.ts +4 -0
- package/dist/systems/roof/roof-elevation.d.ts.map +1 -0
- package/dist/systems/roof/roof-elevation.js +95 -0
- package/dist/systems/roof/roof-footprint.d.ts +17 -0
- package/dist/systems/roof/roof-footprint.d.ts.map +1 -0
- package/dist/systems/roof/roof-footprint.js +83 -0
- package/dist/systems/slab/slab-placement.d.ts +1 -1
- package/dist/systems/slab/slab-support.d.ts +1 -1
- package/dist/systems/slab/slab-support.js +4 -4
- package/dist/systems/stair/stair-flight.d.ts +17 -0
- package/dist/systems/stair/stair-flight.d.ts.map +1 -0
- package/dist/systems/stair/stair-flight.js +27 -0
- package/dist/systems/stair/stair-footprint.d.ts +1 -1
- package/dist/systems/stair/stair-opening-preview.d.ts +1621 -1267
- package/dist/systems/stair/stair-opening-preview.d.ts.map +1 -1
- package/dist/systems/stair/stair-opening-preview.js +2 -2
- package/dist/systems/stair/stair-opening-sync.d.ts +1 -1
- package/dist/systems/stair/stair-opening-sync.js +6 -6
- package/dist/systems/stair/stair-opening-system.d.ts +1 -0
- package/dist/systems/stair/stair-opening-system.d.ts.map +1 -1
- package/dist/systems/stair/stair-opening-system.js +100 -103
- package/dist/systems/stair/stair-rise.d.ts +1 -1
- package/dist/systems/stair/stair-rise.d.ts.map +1 -1
- package/dist/systems/stair/stair-rise.js +23 -24
- package/dist/systems/wall/wall-curve.d.ts +3 -2
- package/dist/systems/wall/wall-curve.d.ts.map +1 -1
- package/dist/systems/wall/wall-curve.js +73 -0
- package/dist/systems/wall/wall-footprint.d.ts +3 -2
- package/dist/systems/wall/wall-footprint.d.ts.map +1 -1
- package/dist/systems/wall/wall-footprint.js +3 -2
- package/dist/systems/wall/wall-mitering.d.ts +1 -1
- package/dist/systems/wall/wall-mitering.js +1 -1
- package/dist/systems/wall/wall-move.d.ts +1 -1
- package/dist/systems/wall/wall-top.d.ts +1 -1
- package/dist/systems/wall/wall-topology.d.ts +2 -2
- package/dist/systems/wall/wall-topology.js +4 -4
- package/dist/utils/clone-scene-graph.d.ts +3 -3
- package/dist/utils/clone-scene-graph.d.ts.map +1 -1
- package/dist/utils/clone-scene-graph.js +35 -3
- package/dist/utils/scene-migrations.d.ts +3 -3
- package/dist/utils/scene-migrations.js +3 -3
- package/dist/utils/vertical-scene-migration.js +5 -5
- package/dist/validation/validate-build-json.d.ts +7 -1
- package/dist/validation/validate-build-json.d.ts.map +1 -1
- package/dist/validation/validate-build-json.js +92 -4
- package/package.json +23 -5
- package/dist/systems/elevator/elevator-runtime-system.d.ts +0 -2
- package/dist/systems/elevator/elevator-runtime-system.d.ts.map +0 -1
- package/dist/systems/elevator/elevator-runtime-system.js +0 -8
package/dist/store/use-scene.js
CHANGED
|
@@ -1,30 +1,37 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { temporal } from 'zundo';
|
|
3
3
|
import { create } from 'zustand';
|
|
4
|
-
import { parseMaterialRef, toSceneMaterialRef } from '../material-library';
|
|
5
|
-
import { getNodePluginId, isNodeKindEnabled, nodeRegistry } from '../registry/registry';
|
|
6
|
-
import { BuildingNode } from '../schema';
|
|
7
|
-
import { generateCollectionId } from '../schema/collections';
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
import
|
|
25
|
-
import {
|
|
26
|
-
import
|
|
27
|
-
import
|
|
4
|
+
import { parseMaterialRef, toSceneMaterialRef } from '../material-library.js';
|
|
5
|
+
import { getNodePluginId, isNodeKindEnabled, nodeRegistry } from '../registry/registry.js';
|
|
6
|
+
import { BuildingNode } from '../schema/index.js';
|
|
7
|
+
import { generateCollectionId } from '../schema/collections.js';
|
|
8
|
+
import { compiledNodeSchema } from '../schema/compiled-node-parsers.js';
|
|
9
|
+
import { DoorNode as DoorNodeSchema } from '../schema/nodes/door.js';
|
|
10
|
+
import { createDormerDefaultWindow, DormerNode as DormerNodeSchema, getDormerDefaultWindowFace, } from '../schema/nodes/dormer.js';
|
|
11
|
+
import { ElevatorNode as ElevatorNodeSchema } from '../schema/nodes/elevator.js';
|
|
12
|
+
import { LevelNode, normalizeLevelBaseElevation } from '../schema/nodes/level.js';
|
|
13
|
+
import { getPitchFromActiveRoofHeight, } from '../schema/nodes/roof-segment.js';
|
|
14
|
+
import { segmentPointToRoofWallFace } from '../schema/nodes/roof-segment-walls.js';
|
|
15
|
+
import { ShelfNode as ShelfNodeSchema } from '../schema/nodes/shelf.js';
|
|
16
|
+
import { SiteNode } from '../schema/nodes/site.js';
|
|
17
|
+
import { getEffectiveStairSurfaceMaterial, StairNode as StairNodeSchema, } from '../schema/nodes/stair.js';
|
|
18
|
+
import { StairSegmentNode as StairSegmentNodeSchema } from '../schema/nodes/stair-segment.js';
|
|
19
|
+
import { getEffectiveWallSurfaceMaterial } from '../schema/nodes/wall.js';
|
|
20
|
+
import { WindowNode as WindowNodeSchema } from '../schema/nodes/window.js';
|
|
21
|
+
import { generateSceneMaterialId, SceneMaterial, } from '../schema/scene-material.js';
|
|
22
|
+
import { AnyNode as AnyNodeSchema } from '../schema/types.js';
|
|
23
|
+
import { syncAutoElevatorOpenings } from '../systems/elevator/elevator-opening-sync.js';
|
|
24
|
+
import { syncAutoStairOpenings } from '../systems/stair/stair-opening-sync.js';
|
|
25
|
+
import { syncStairRises } from '../systems/stair/stair-rise.js';
|
|
26
|
+
import { healSceneNodes } from '../utils/heal-scene-graph.js';
|
|
27
|
+
import { removeRetiredDrawingSheetNodes } from '../utils/retired-scene-nodes.js';
|
|
28
|
+
import { migrateVerticalSceneNodes } from '../utils/vertical-scene-migration.js';
|
|
29
|
+
import * as nodeActions from './actions/node-actions.js';
|
|
30
|
+
import { areSceneSnapshotsEqual, getSceneHistoryPauseDepth, notifySceneCommit, pauseSceneHistory, resetSceneHistoryPauseDepth, resumeSceneHistory, runWithSceneCommitNodeIds, } from './history-control.js';
|
|
31
|
+
import { getHistoryDirtyNodeIds } from './history-invalidation.js';
|
|
32
|
+
import { invalidatePendingHydration, isHydrationNormalization, queueSceneNormalization, runSceneHydration, } from './scene-hydration.js';
|
|
33
|
+
import useLiveNodeOverrides from './use-live-node-overrides.js';
|
|
34
|
+
import useLiveTransforms from './use-live-transforms.js';
|
|
28
35
|
function getFiniteNumber(value, fallback) {
|
|
29
36
|
return typeof value === 'number' && Number.isFinite(value) ? value : fallback;
|
|
30
37
|
}
|
|
@@ -82,7 +89,7 @@ function normalizeStairNode(node) {
|
|
|
82
89
|
railingHeight: getFiniteNumber(node.railingHeight, 0.92),
|
|
83
90
|
children: getStringArray(node.children),
|
|
84
91
|
};
|
|
85
|
-
const parsed = StairNodeSchema.safeParse(sanitized);
|
|
92
|
+
const parsed = compiledNodeSchema(StairNodeSchema).safeParse(sanitized);
|
|
86
93
|
if (!parsed.success)
|
|
87
94
|
return null;
|
|
88
95
|
if (hasTotalRise)
|
|
@@ -107,18 +114,18 @@ function normalizeStairSegmentNode(node) {
|
|
|
107
114
|
fillToFloor: getBoolean(node.fillToFloor, true),
|
|
108
115
|
thickness: getFiniteNumber(node.thickness, 0.25),
|
|
109
116
|
};
|
|
110
|
-
const parsed = StairSegmentNodeSchema.safeParse(sanitized);
|
|
117
|
+
const parsed = compiledNodeSchema(StairSegmentNodeSchema).safeParse(sanitized);
|
|
111
118
|
return parsed.success ? parsed.data : null;
|
|
112
119
|
}
|
|
113
120
|
function normalizeDoorNode(node) {
|
|
114
|
-
const parsed = DoorNodeSchema.safeParse(node);
|
|
121
|
+
const parsed = compiledNodeSchema(DoorNodeSchema).safeParse(node);
|
|
115
122
|
return parsed.success ? { ...node, ...parsed.data } : null;
|
|
116
123
|
}
|
|
117
124
|
// Windows saved before a schema field existed (e.g. `columnRatios`/`rowRatios`/
|
|
118
125
|
// `frameThickness`) load without it; the mesh builder then reads undefined and
|
|
119
126
|
// throws every frame. Zod-parse on load so schema defaults land, like doors.
|
|
120
127
|
function normalizeWindowNode(node) {
|
|
121
|
-
const parsed = WindowNodeSchema.safeParse(node);
|
|
128
|
+
const parsed = compiledNodeSchema(WindowNodeSchema).safeParse(node);
|
|
122
129
|
return parsed.success ? { ...node, ...parsed.data } : null;
|
|
123
130
|
}
|
|
124
131
|
function normalizeShelfNode(node) {
|
|
@@ -139,7 +146,7 @@ function normalizeShelfNode(node) {
|
|
|
139
146
|
withBottom: getBoolean(node.withBottom, false),
|
|
140
147
|
bracketStyle: getEnumValue(node.bracketStyle, ['minimal', 'industrial', 'hidden'], 'minimal'),
|
|
141
148
|
};
|
|
142
|
-
const parsed = ShelfNodeSchema.safeParse(sanitized);
|
|
149
|
+
const parsed = compiledNodeSchema(ShelfNodeSchema).safeParse(sanitized);
|
|
143
150
|
return parsed.success ? parsed.data : null;
|
|
144
151
|
}
|
|
145
152
|
function normalizeElevatorNode(node) {
|
|
@@ -165,7 +172,7 @@ function normalizeElevatorNode(node) {
|
|
|
165
172
|
doorDurationMs: getFiniteNumber(node.doorDurationMs, 900),
|
|
166
173
|
dwellMs: getFiniteNumber(node.dwellMs, 1400),
|
|
167
174
|
};
|
|
168
|
-
const parsed = ElevatorNodeSchema.safeParse(sanitized);
|
|
175
|
+
const parsed = compiledNodeSchema(ElevatorNodeSchema).safeParse(sanitized);
|
|
169
176
|
return parsed.success ? parsed.data : null;
|
|
170
177
|
}
|
|
171
178
|
function findBuildingIdForLevel(levelId, nodes) {
|
|
@@ -295,6 +302,42 @@ function migrateSingleMaterialSlots(node, slotIds, mintedMaterials) {
|
|
|
295
302
|
slots[slotId] = ref;
|
|
296
303
|
return { ...node, slots, material: undefined, materialPreset: undefined };
|
|
297
304
|
}
|
|
305
|
+
function migrateRoleMaterialSlots(node, roles, mintedMaterials) {
|
|
306
|
+
const slots = { ...(node.slots ?? {}) };
|
|
307
|
+
const next = { ...node };
|
|
308
|
+
let changed = false;
|
|
309
|
+
for (const role of roles) {
|
|
310
|
+
if (slots[role] === undefined) {
|
|
311
|
+
const ref = legacySpecToMaterialRef({
|
|
312
|
+
material: node[`${role}Material`] ?? node.material,
|
|
313
|
+
materialPreset: node[`${role}MaterialPreset`] ?? node.materialPreset,
|
|
314
|
+
}, mintedMaterials);
|
|
315
|
+
if (ref) {
|
|
316
|
+
slots[role] = ref;
|
|
317
|
+
changed = true;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
if (`${role}Material` in next || `${role}MaterialPreset` in next)
|
|
321
|
+
changed = true;
|
|
322
|
+
delete next[`${role}Material`];
|
|
323
|
+
delete next[`${role}MaterialPreset`];
|
|
324
|
+
}
|
|
325
|
+
return changed ? { ...next, slots } : node;
|
|
326
|
+
}
|
|
327
|
+
function migrateRenamedSlot(node, previousId, nextId) {
|
|
328
|
+
if (!node.slots || node.slots[previousId] === undefined)
|
|
329
|
+
return node;
|
|
330
|
+
const slots = { ...node.slots };
|
|
331
|
+
if (slots[nextId] === undefined)
|
|
332
|
+
slots[nextId] = slots[previousId];
|
|
333
|
+
delete slots[previousId];
|
|
334
|
+
return { ...node, slots };
|
|
335
|
+
}
|
|
336
|
+
function migrateCupolaLouverSlot(node) {
|
|
337
|
+
if (!node.slots || node.slots.louvers !== undefined || node.slots.body === undefined)
|
|
338
|
+
return node;
|
|
339
|
+
return { ...node, slots: { ...node.slots, louvers: node.slots.body } };
|
|
340
|
+
}
|
|
298
341
|
// Stair carries per-role legacy fields (`treadMaterial*` / `sideMaterial*` /
|
|
299
342
|
// `railingMaterial*`) plus a catch-all. Map each to its slot via the same
|
|
300
343
|
// fallback chain the renderer uses (`getEffectiveStairSurfaceMaterial`):
|
|
@@ -482,6 +525,39 @@ function migrateWallAssembly(node) {
|
|
|
482
525
|
const { assemblyLayers: _assemblyLayers, ...wall } = node;
|
|
483
526
|
return assemblyThickness > 0 ? { ...wall, thickness: assemblyThickness } : wall;
|
|
484
527
|
}
|
|
528
|
+
function migrateBlockRename(id, node, nodes) {
|
|
529
|
+
if (node.type !== 'custom-mesh')
|
|
530
|
+
return [id, node];
|
|
531
|
+
const desiredId = id.startsWith('custom-mesh_') ? `block_${id.slice('custom-mesh_'.length)}` : id;
|
|
532
|
+
let nextId = desiredId;
|
|
533
|
+
let suffix = 1;
|
|
534
|
+
while (nextId !== id && nodes[nextId]) {
|
|
535
|
+
nextId = `${desiredId}_${suffix}`;
|
|
536
|
+
suffix += 1;
|
|
537
|
+
}
|
|
538
|
+
const nextNode = { ...node, id: nextId, type: 'block' };
|
|
539
|
+
if (nextId !== id) {
|
|
540
|
+
for (const candidate of Object.values(nodes)) {
|
|
541
|
+
if (!candidate || typeof candidate !== 'object')
|
|
542
|
+
continue;
|
|
543
|
+
if (candidate.parentId === id)
|
|
544
|
+
candidate.parentId = nextId;
|
|
545
|
+
if (Array.isArray(candidate.children)) {
|
|
546
|
+
candidate.children = candidate.children.map((childId) => childId === id ? nextId : childId);
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
return [nextId, nextNode];
|
|
551
|
+
}
|
|
552
|
+
function migrateBlockHostedItem(node) {
|
|
553
|
+
if (node.type !== 'item' ||
|
|
554
|
+
node.blockFaceId !== undefined ||
|
|
555
|
+
node.customMeshFaceId === undefined) {
|
|
556
|
+
return node;
|
|
557
|
+
}
|
|
558
|
+
const { customMeshFaceId, ...item } = node;
|
|
559
|
+
return { ...item, blockFaceId: customMeshFaceId };
|
|
560
|
+
}
|
|
485
561
|
function migrateNodes(nodes) {
|
|
486
562
|
// Repair pre-existing corruption (null children, zero-length walls) before
|
|
487
563
|
// any per-type migration runs, so already-saved scenes load cleanly.
|
|
@@ -490,6 +566,13 @@ function migrateNodes(nodes) {
|
|
|
490
566
|
// Scene materials minted while moving legacy wall fields onto `node.slots`;
|
|
491
567
|
// merged into the scene material map by the caller (`setScene`).
|
|
492
568
|
const mintedMaterials = {};
|
|
569
|
+
for (const [id, node] of Object.entries(patchedNodes)) {
|
|
570
|
+
const [nextId, nextNode] = migrateBlockRename(id, node, patchedNodes);
|
|
571
|
+
if (nextId !== id) {
|
|
572
|
+
delete patchedNodes[id];
|
|
573
|
+
}
|
|
574
|
+
patchedNodes[nextId] = migrateBlockHostedItem(nextNode);
|
|
575
|
+
}
|
|
493
576
|
// Pass 1: all node types except elevator.
|
|
494
577
|
// Elevator migration (migrateElevatorParent) mutates level.children to remove
|
|
495
578
|
// the elevator ID. If the elevator is processed before its parent level in
|
|
@@ -578,6 +661,34 @@ function migrateNodes(nodes) {
|
|
|
578
661
|
patchedNodes[id] = normalized;
|
|
579
662
|
}
|
|
580
663
|
}
|
|
664
|
+
// Dormers originally rendered one inline parametric window. Promote that
|
|
665
|
+
// default to a real hosted WindowNode so additional windows can use the
|
|
666
|
+
// regular window tool and inspector without changing the old appearance.
|
|
667
|
+
if (node.type === 'dormer') {
|
|
668
|
+
const hasLegacyInlineWindow = !Array.isArray(patchedNodes[id].children);
|
|
669
|
+
if (!hasLegacyInlineWindow)
|
|
670
|
+
continue;
|
|
671
|
+
const dormer = DormerNodeSchema.parse({
|
|
672
|
+
...patchedNodes[id],
|
|
673
|
+
children: getStringArray(patchedNodes[id].children),
|
|
674
|
+
});
|
|
675
|
+
const children = getStringArray(dormer.children);
|
|
676
|
+
const hasHostedWindow = children.some((childId) => patchedNodes[childId]?.type === 'window');
|
|
677
|
+
if (!hasHostedWindow) {
|
|
678
|
+
const baseWindowId = `window_${id.replace(/^dormer_/, '')}_default`;
|
|
679
|
+
let windowId = baseWindowId;
|
|
680
|
+
let suffix = 1;
|
|
681
|
+
while (patchedNodes[windowId]) {
|
|
682
|
+
windowId = `${baseWindowId}_${suffix}`;
|
|
683
|
+
suffix += 1;
|
|
684
|
+
}
|
|
685
|
+
const host = dormer.roofSegmentId ? patchedNodes[dormer.roofSegmentId] : undefined;
|
|
686
|
+
const hostSegment = host?.type === 'roof-segment' ? host : undefined;
|
|
687
|
+
const window = createDormerDefaultWindow(dormer, windowId, getDormerDefaultWindowFace(dormer, hostSegment));
|
|
688
|
+
patchedNodes[windowId] = window;
|
|
689
|
+
patchedNodes[id] = { ...dormer, children: [...children, window.id] };
|
|
690
|
+
}
|
|
691
|
+
}
|
|
581
692
|
if (node.type === 'construction-dimension') {
|
|
582
693
|
patchedNodes[id] = migrateConstructionDimension(node);
|
|
583
694
|
}
|
|
@@ -635,6 +746,26 @@ function migrateNodes(nodes) {
|
|
|
635
746
|
if (node.type === 'column') {
|
|
636
747
|
patchedNodes[id] = migrateSingleMaterialSlots(patchedNodes[id], ['shaft', 'base', 'capital', 'frame'], mintedMaterials);
|
|
637
748
|
}
|
|
749
|
+
if (node.type === 'gutter') {
|
|
750
|
+
patchedNodes[id] = migrateRenamedSlot(patchedNodes[id], 'surface', 'gutter');
|
|
751
|
+
patchedNodes[id] = migrateSingleMaterialSlots(patchedNodes[id], ['gutter'], mintedMaterials);
|
|
752
|
+
}
|
|
753
|
+
if (node.type === 'downspout') {
|
|
754
|
+
patchedNodes[id] = migrateSingleMaterialSlots(patchedNodes[id], ['surface'], mintedMaterials);
|
|
755
|
+
}
|
|
756
|
+
if (node.type === 'box-vent') {
|
|
757
|
+
patchedNodes[id] = migrateRoleMaterialSlots(patchedNodes[id], ['base', 'top'], mintedMaterials);
|
|
758
|
+
}
|
|
759
|
+
if (node.type === 'cupola') {
|
|
760
|
+
patchedNodes[id] = migrateCupolaLouverSlot(patchedNodes[id]);
|
|
761
|
+
patchedNodes[id] = migrateRoleMaterialSlots(patchedNodes[id], ['base', 'body', 'roof', 'louvers'], mintedMaterials);
|
|
762
|
+
}
|
|
763
|
+
if (node.type === 'eyebrow-vent') {
|
|
764
|
+
patchedNodes[id] = migrateRoleMaterialSlots(patchedNodes[id], ['hood', 'front'], mintedMaterials);
|
|
765
|
+
}
|
|
766
|
+
if (node.type === 'turbine-vent') {
|
|
767
|
+
patchedNodes[id] = migrateRoleMaterialSlots(patchedNodes[id], ['base', 'head'], mintedMaterials);
|
|
768
|
+
}
|
|
638
769
|
if (node.type === 'shelf') {
|
|
639
770
|
const normalized = normalizeShelfNode(node);
|
|
640
771
|
if (normalized) {
|
|
@@ -743,6 +874,12 @@ function migrateNodes(nodes) {
|
|
|
743
874
|
children: validChildren,
|
|
744
875
|
};
|
|
745
876
|
}
|
|
877
|
+
// These kinds are not all schema-parsed on load, so defaults must also
|
|
878
|
+
// reach saved hosts that predate their children field.
|
|
879
|
+
if (['shelf', 'cabinet', 'cabinet-module', 'block', 'item', 'column'].includes(node.type) &&
|
|
880
|
+
patchedNodes[id].children === undefined) {
|
|
881
|
+
patchedNodes[id] = { ...patchedNodes[id], children: [] };
|
|
882
|
+
}
|
|
746
883
|
}
|
|
747
884
|
// Pass 2: elevator migration.
|
|
748
885
|
// migrateElevatorParent mutates the parent level's children array (removes
|
|
@@ -885,13 +1022,99 @@ function sceneHistorySnapshotFromState(state) {
|
|
|
885
1022
|
installedPlugins,
|
|
886
1023
|
};
|
|
887
1024
|
}
|
|
888
|
-
|
|
1025
|
+
/**
|
|
1026
|
+
* A dirty mark is a promise that some system will rebuild the node and clear
|
|
1027
|
+
* the mark, so marks are only accepted for kinds with a dirty consumer: kinds
|
|
1028
|
+
* with `dirtyTracking: false` (and kinds of disabled plugins) have none, and
|
|
1029
|
+
* a mark for them would sit in the set for the whole session and defeat every
|
|
1030
|
+
* consumer's empty-set early exit. Ids without a node pass: tools mark nodes
|
|
1031
|
+
* they are about to create.
|
|
1032
|
+
*/
|
|
1033
|
+
function isDirtyTrackable(id, scene) {
|
|
1034
|
+
const node = scene.nodes[id];
|
|
1035
|
+
if (!node)
|
|
1036
|
+
return true;
|
|
1037
|
+
if (!isNodeKindEnabled(node.type, scene.installedPlugins))
|
|
1038
|
+
return false;
|
|
1039
|
+
return nodeRegistry.get(node.type)?.dirtyTracking !== false;
|
|
1040
|
+
}
|
|
1041
|
+
/**
|
|
1042
|
+
* `markDirty` always applied the consumer-kind guard, but many call sites add
|
|
1043
|
+
* to the raw set directly (that is how stuck `level` marks got in) — enforcing
|
|
1044
|
+
* it in `add` itself keeps them all honest.
|
|
1045
|
+
*/
|
|
1046
|
+
class GuardedDirtySet extends Set {
|
|
1047
|
+
getScene;
|
|
1048
|
+
constructor(getScene, from) {
|
|
1049
|
+
super();
|
|
1050
|
+
this.getScene = getScene;
|
|
1051
|
+
if (from)
|
|
1052
|
+
for (const id of from)
|
|
1053
|
+
this.add(id);
|
|
1054
|
+
}
|
|
1055
|
+
add(id) {
|
|
1056
|
+
if (!isDirtyTrackable(id, this.getScene()))
|
|
1057
|
+
return this;
|
|
1058
|
+
return super.add(id);
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
function createSceneStore(config) {
|
|
1062
|
+
const hydratedConfig = (set, get, store) => {
|
|
1063
|
+
const setWithHydration = (partial, replace) => {
|
|
1064
|
+
const state = get();
|
|
1065
|
+
let next = typeof partial === 'function' ? partial(state) : partial;
|
|
1066
|
+
const documentChanged = ['nodes', 'rootNodeIds', 'materials', 'collections', 'installedPlugins'].some((key) => (replace || key in next) && next[key] !== state[key]);
|
|
1067
|
+
if (documentChanged && !isHydrationNormalization()) {
|
|
1068
|
+
invalidatePendingHydration();
|
|
1069
|
+
if (state.hydrationToken)
|
|
1070
|
+
next = { ...next, hydrationToken: null };
|
|
1071
|
+
}
|
|
1072
|
+
if (replace)
|
|
1073
|
+
set(next, true);
|
|
1074
|
+
else
|
|
1075
|
+
set(next);
|
|
1076
|
+
};
|
|
1077
|
+
store.setState = setWithHydration;
|
|
1078
|
+
return config(setWithHydration, get, store);
|
|
1079
|
+
};
|
|
1080
|
+
return create()(hydratedConfig);
|
|
1081
|
+
}
|
|
1082
|
+
function runTemporalJump(target, jump) {
|
|
1083
|
+
if (!target?.nodes) {
|
|
1084
|
+
jump();
|
|
1085
|
+
return;
|
|
1086
|
+
}
|
|
1087
|
+
const before = useScene.getState().nodes;
|
|
1088
|
+
const changed = new Set();
|
|
1089
|
+
for (const id of new Set([...Object.keys(before), ...Object.keys(target.nodes)])) {
|
|
1090
|
+
const nodeId = id;
|
|
1091
|
+
const previous = before[nodeId];
|
|
1092
|
+
const next = target.nodes[nodeId];
|
|
1093
|
+
if (previous === next)
|
|
1094
|
+
continue;
|
|
1095
|
+
// Structural hierarchy changes keep the full-level reconciliation fallback.
|
|
1096
|
+
if ([previous, next].some((node) => node && ['site', 'building', 'level'].includes(node.type))) {
|
|
1097
|
+
jump();
|
|
1098
|
+
return;
|
|
1099
|
+
}
|
|
1100
|
+
changed.add(nodeId);
|
|
1101
|
+
}
|
|
1102
|
+
runWithSceneCommitNodeIds(changed, jump);
|
|
1103
|
+
}
|
|
1104
|
+
const useScene = createSceneStore(temporal((set, get) => ({
|
|
889
1105
|
// 1. Flat dictionary of all nodes
|
|
890
1106
|
nodes: {},
|
|
891
1107
|
// 2. Root node IDs
|
|
892
1108
|
rootNodeIds: [],
|
|
893
1109
|
// 3. Dirty set
|
|
894
|
-
dirtyNodes: new
|
|
1110
|
+
dirtyNodes: new GuardedDirtySet(get),
|
|
1111
|
+
hydrationToken: null,
|
|
1112
|
+
hydrationId: null,
|
|
1113
|
+
invalidateHydration: () => {
|
|
1114
|
+
invalidatePendingHydration();
|
|
1115
|
+
if (get().hydrationToken)
|
|
1116
|
+
set({ hydrationToken: null });
|
|
1117
|
+
},
|
|
895
1118
|
// 4. Collections
|
|
896
1119
|
collections: {},
|
|
897
1120
|
materials: {},
|
|
@@ -901,10 +1124,13 @@ const useScene = create()(temporal((set, get) => ({
|
|
|
901
1124
|
readOnly: false,
|
|
902
1125
|
setReadOnly: (readOnly) => set({ readOnly }),
|
|
903
1126
|
unloadScene: () => {
|
|
1127
|
+
invalidatePendingHydration();
|
|
904
1128
|
set({
|
|
1129
|
+
hydrationToken: null,
|
|
1130
|
+
hydrationId: null,
|
|
905
1131
|
nodes: {},
|
|
906
1132
|
rootNodeIds: [],
|
|
907
|
-
dirtyNodes: new
|
|
1133
|
+
dirtyNodes: new GuardedDirtySet(get),
|
|
908
1134
|
collections: {},
|
|
909
1135
|
materials: {},
|
|
910
1136
|
installedPlugins: [],
|
|
@@ -947,26 +1173,65 @@ const useScene = create()(temporal((set, get) => ({
|
|
|
947
1173
|
// pre-write state onto `pastStates`. Writing the scene in two steps
|
|
948
1174
|
// (as this used to) exposed a half-normalized intermediate state —
|
|
949
1175
|
// and the pre-load (possibly empty) state — as undo targets.
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
1176
|
+
const hydrationId = {};
|
|
1177
|
+
runSceneHydration(() => {
|
|
1178
|
+
set({
|
|
1179
|
+
hydrationToken: null,
|
|
1180
|
+
hydrationId,
|
|
1181
|
+
nodes: cleanedNodes,
|
|
1182
|
+
rootNodeIds: normalizedRootNodeIds,
|
|
1183
|
+
dirtyNodes: new GuardedDirtySet(get),
|
|
1184
|
+
collections: extra?.collections ?? {},
|
|
1185
|
+
materials,
|
|
1186
|
+
installedPlugins: Array.from(new Set(extra?.installedPlugins ?? [])),
|
|
1187
|
+
hasExplicitPluginInstallState: extra?.hasExplicitPluginInstallState ?? false,
|
|
1188
|
+
});
|
|
1189
|
+
const applyNormalization = (updates) => {
|
|
1190
|
+
if (updates.length > 0)
|
|
1191
|
+
get().updateNodes(updates);
|
|
1192
|
+
};
|
|
1193
|
+
const hydratedNodes = Object.values(get().nodes);
|
|
1194
|
+
if (!get().readOnly) {
|
|
1195
|
+
pauseSceneHistory(useScene);
|
|
1196
|
+
try {
|
|
1197
|
+
if (hydratedNodes.some((node) => node.type === 'elevator')) {
|
|
1198
|
+
applyNormalization(syncAutoElevatorOpenings(get().nodes));
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
finally {
|
|
1202
|
+
resumeSceneHistory(useScene);
|
|
1203
|
+
}
|
|
1204
|
+
if (hydratedNodes.some((node) => node.type === 'stair')) {
|
|
1205
|
+
// Spatial-grid subscribers must settle first. Owning this pass
|
|
1206
|
+
// here also covers opening systems that mount after the load.
|
|
1207
|
+
queueSceneNormalization(() => {
|
|
1208
|
+
if (get().hydrationId !== hydrationId)
|
|
1209
|
+
return;
|
|
1210
|
+
pauseSceneHistory(useScene);
|
|
1211
|
+
try {
|
|
1212
|
+
applyNormalization(syncStairRises(get().nodes));
|
|
1213
|
+
applyNormalization(syncAutoStairOpenings(get().nodes));
|
|
1214
|
+
}
|
|
1215
|
+
finally {
|
|
1216
|
+
resumeSceneHistory(useScene);
|
|
1217
|
+
}
|
|
1218
|
+
});
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
// Mark all nodes as dirty to trigger re-validation
|
|
1222
|
+
Object.values(get().nodes).forEach((node) => {
|
|
1223
|
+
get().markDirty(node.id);
|
|
1224
|
+
});
|
|
1225
|
+
}, () => set({ hydrationToken: hydrationId }));
|
|
963
1226
|
},
|
|
964
1227
|
setInstalledPlugins: (pluginIds, options) => {
|
|
965
1228
|
if (get().readOnly)
|
|
966
1229
|
return;
|
|
967
1230
|
const nextInstalledPlugins = Array.from(new Set(pluginIds));
|
|
968
1231
|
const previousInstalledPlugins = get().installedPlugins;
|
|
969
|
-
|
|
1232
|
+
// Guard against the *next* plugin list: the store still holds the old
|
|
1233
|
+
// one, and re-marks for newly enabled kinds must pass the guard.
|
|
1234
|
+
const dirtyNodes = new GuardedDirtySet(() => ({ nodes: get().nodes, installedPlugins: nextInstalledPlugins }), get().dirtyNodes);
|
|
970
1235
|
for (const node of Object.values(get().nodes)) {
|
|
971
1236
|
if (!getNodePluginId(node.type))
|
|
972
1237
|
continue;
|
|
@@ -1017,10 +1282,9 @@ const useScene = create()(temporal((set, get) => ({
|
|
|
1017
1282
|
set({ nodes, rootNodeIds });
|
|
1018
1283
|
},
|
|
1019
1284
|
markDirty: (id) => {
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
if (node && nodeRegistry.get(node.type)?.dirtyTracking === false)
|
|
1285
|
+
// Guarded here too, not just in GuardedDirtySet.add — tests (and any
|
|
1286
|
+
// setState caller) can swap in a plain Set.
|
|
1287
|
+
if (!isDirtyTrackable(id, get()))
|
|
1024
1288
|
return;
|
|
1025
1289
|
get().dirtyNodes.add(id);
|
|
1026
1290
|
},
|
|
@@ -1170,8 +1434,27 @@ const useScene = create()(temporal((set, get) => ({
|
|
|
1170
1434
|
current: sceneHistorySnapshotFromState(currentState),
|
|
1171
1435
|
});
|
|
1172
1436
|
},
|
|
1437
|
+
wrapTemporal: (config) => (set, get, store) => {
|
|
1438
|
+
const state = config(set, get, store);
|
|
1439
|
+
return {
|
|
1440
|
+
...state,
|
|
1441
|
+
undo: (steps = 1) => runTemporalJump(get().pastStates.slice().splice(-steps, steps)[0], () => state.undo(steps)),
|
|
1442
|
+
redo: (steps = 1) => runTemporalJump(get().futureStates.slice().splice(-steps, steps)[0], () => state.redo(steps)),
|
|
1443
|
+
};
|
|
1444
|
+
},
|
|
1173
1445
|
limit: 50, // Limit to last 50 actions
|
|
1174
1446
|
}));
|
|
1447
|
+
// Live state belongs to the hydration owner so even a lazy consumer cannot
|
|
1448
|
+
// miss an override that was set and cleared before its first frame.
|
|
1449
|
+
const invalidateForLiveState = () => {
|
|
1450
|
+
if (useLiveNodeOverrides.getState().overrides.size ||
|
|
1451
|
+
useLiveTransforms.getState().transforms.size) {
|
|
1452
|
+
useScene.getState().invalidateHydration();
|
|
1453
|
+
}
|
|
1454
|
+
};
|
|
1455
|
+
useLiveNodeOverrides.subscribe(invalidateForLiveState);
|
|
1456
|
+
useLiveTransforms.subscribe(invalidateForLiveState);
|
|
1457
|
+
useScene.subscribe(invalidateForLiveState);
|
|
1175
1458
|
export default useScene;
|
|
1176
1459
|
let sceneReadOnlyLeaseCount = 0;
|
|
1177
1460
|
let sceneReadOnlyLeaseBaseline = false;
|
|
@@ -1543,6 +1826,8 @@ export function applySceneSnapshot(snapshot, options) {
|
|
|
1543
1826
|
if (!temporalState.isTracking || getSceneHistoryPauseDepth() > 0) {
|
|
1544
1827
|
throw new Error('Cannot replace the scene snapshot during an active interaction');
|
|
1545
1828
|
}
|
|
1829
|
+
useLiveNodeOverrides.getState().clearAll();
|
|
1830
|
+
useLiveTransforms.getState().clearAll();
|
|
1546
1831
|
pauseSceneHistory(useScene);
|
|
1547
1832
|
try {
|
|
1548
1833
|
useScene.getState().setScene(snapshot.nodes, snapshot.rootNodeIds, {
|
|
@@ -1555,18 +1840,15 @@ export function applySceneSnapshot(snapshot, options) {
|
|
|
1555
1840
|
finally {
|
|
1556
1841
|
resumeSceneHistory(useScene);
|
|
1557
1842
|
}
|
|
1558
|
-
useLiveNodeOverrides.getState().clearAll();
|
|
1559
|
-
useLiveTransforms.getState().clearAll();
|
|
1560
1843
|
const current = sceneHistorySnapshotFromState(useScene.getState());
|
|
1561
1844
|
if (areSceneSnapshotsEqual(before, current))
|
|
1562
1845
|
return false;
|
|
1563
1846
|
notifySceneCommit({ origin: options.origin, before, current });
|
|
1564
1847
|
return true;
|
|
1565
1848
|
}
|
|
1566
|
-
// Track previous temporal state lengths
|
|
1849
|
+
// Track previous temporal state lengths for identifying history jumps
|
|
1567
1850
|
let prevPastLength = 0;
|
|
1568
1851
|
let prevFutureLength = 0;
|
|
1569
|
-
let prevNodesSnapshot = null;
|
|
1570
1852
|
export function clearSceneHistory() {
|
|
1571
1853
|
resetSceneHistoryPauseDepth();
|
|
1572
1854
|
// Resetting the pause-depth counter without resuming would strand the
|
|
@@ -1578,10 +1860,14 @@ export function clearSceneHistory() {
|
|
|
1578
1860
|
useScene.temporal.getState().clear();
|
|
1579
1861
|
prevPastLength = 0;
|
|
1580
1862
|
prevFutureLength = 0;
|
|
1581
|
-
prevNodesSnapshot = null;
|
|
1582
1863
|
}
|
|
1583
1864
|
// Subscribe to the temporal store (Undo/Redo events)
|
|
1584
|
-
useScene.temporal.subscribe((state) => {
|
|
1865
|
+
useScene.temporal.subscribe((state, previousState) => {
|
|
1866
|
+
// Zundo mutates its source stack before writing the scene. Reconciliation's
|
|
1867
|
+
// pause/resume notifications must not advance our pre-jump stack lengths.
|
|
1868
|
+
if (state.pastStates === previousState.pastStates &&
|
|
1869
|
+
state.futureStates === previousState.futureStates)
|
|
1870
|
+
return;
|
|
1585
1871
|
const currentPastLength = state.pastStates.length;
|
|
1586
1872
|
const currentFutureLength = state.futureStates.length;
|
|
1587
1873
|
// Undo: futureStates increases (state moved from past to future)
|
|
@@ -1589,40 +1875,21 @@ useScene.temporal.subscribe((state) => {
|
|
|
1589
1875
|
const didUndo = currentFutureLength > prevFutureLength;
|
|
1590
1876
|
const didRedo = currentPastLength > prevPastLength && currentFutureLength < prevFutureLength;
|
|
1591
1877
|
if (didUndo || didRedo) {
|
|
1592
|
-
// Capture
|
|
1593
|
-
|
|
1878
|
+
// Capture both layouts before another synchronous jump can replace them.
|
|
1879
|
+
// The state pushed onto the opposite stack includes history-paused derived
|
|
1880
|
+
// writes (such as stair rise), unlike a snapshot saved at the last edit.
|
|
1881
|
+
const snapshotBefore = didUndo
|
|
1882
|
+
? state.futureStates[prevFutureLength]?.nodes
|
|
1883
|
+
: state.pastStates[prevPastLength]?.nodes;
|
|
1884
|
+
const snapshotAfter = useScene.getState().nodes;
|
|
1594
1885
|
// Defer to a microtask so the scene store has settled before we diff,
|
|
1595
1886
|
// but still mark walls/items dirty before the next paint.
|
|
1596
1887
|
queueMicrotask(() => {
|
|
1597
1888
|
const currentNodes = useScene.getState().nodes;
|
|
1598
1889
|
const { markDirty } = useScene.getState();
|
|
1599
1890
|
if (snapshotBefore) {
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
if (snapshotBefore[id] !== node) {
|
|
1603
|
-
markDirty(id);
|
|
1604
|
-
// Also mark parent so merged geometries update
|
|
1605
|
-
if (node.parentId)
|
|
1606
|
-
markDirty(node.parentId);
|
|
1607
|
-
}
|
|
1608
|
-
}
|
|
1609
|
-
// Nodes that were deleted (exist in prev but not current)
|
|
1610
|
-
for (const [id, node] of Object.entries(snapshotBefore)) {
|
|
1611
|
-
if (!currentNodes[id]) {
|
|
1612
|
-
const parentId = node.parentId;
|
|
1613
|
-
if (parentId) {
|
|
1614
|
-
markDirty(parentId);
|
|
1615
|
-
// Mark sibling nodes dirty so they can update their geometry
|
|
1616
|
-
// (e.g. adjacent walls need to recalculate miter/junction geometry)
|
|
1617
|
-
const parent = currentNodes[parentId];
|
|
1618
|
-
if (parent && 'children' in parent && Array.isArray(parent.children)) {
|
|
1619
|
-
for (const childId of parent.children) {
|
|
1620
|
-
markDirty(childId);
|
|
1621
|
-
}
|
|
1622
|
-
}
|
|
1623
|
-
}
|
|
1624
|
-
}
|
|
1625
|
-
}
|
|
1891
|
+
for (const id of getHistoryDirtyNodeIds(snapshotBefore, snapshotAfter))
|
|
1892
|
+
markDirty(id);
|
|
1626
1893
|
}
|
|
1627
1894
|
else {
|
|
1628
1895
|
// No snapshot to diff against — fall back to marking all
|
|
@@ -1630,10 +1897,17 @@ useScene.temporal.subscribe((state) => {
|
|
|
1630
1897
|
markDirty(node.id);
|
|
1631
1898
|
}
|
|
1632
1899
|
}
|
|
1900
|
+
// Undo/redo rewrites `nodes` without going through the delete actions,
|
|
1901
|
+
// so marks for nodes that no longer exist would sit in the set for the
|
|
1902
|
+
// rest of the session — no system clears a mark whose node is gone.
|
|
1903
|
+
const { dirtyNodes, clearDirty } = useScene.getState();
|
|
1904
|
+
for (const id of [...dirtyNodes]) {
|
|
1905
|
+
if (!currentNodes[id])
|
|
1906
|
+
clearDirty(id);
|
|
1907
|
+
}
|
|
1633
1908
|
});
|
|
1634
1909
|
}
|
|
1635
|
-
// Update tracked lengths
|
|
1910
|
+
// Update tracked lengths
|
|
1636
1911
|
prevPastLength = currentPastLength;
|
|
1637
1912
|
prevFutureLength = currentFutureLength;
|
|
1638
|
-
prevNodesSnapshot = useScene.getState().nodes;
|
|
1639
1913
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { AnyNode, AnyNodeId } from '../../schema';
|
|
2
|
-
import type { ElevatorInteractiveState } from '../../store/use-interactive';
|
|
1
|
+
import type { AnyNode, AnyNodeId } from '../../schema/index.js';
|
|
2
|
+
import type { ElevatorInteractiveState } from '../../store/use-interactive.js';
|
|
3
3
|
type ElevatorRuntimeMap = Record<AnyNodeId, ElevatorInteractiveState>;
|
|
4
4
|
type ResolveElevatorDispatchTargetArgs = {
|
|
5
5
|
elevators: ElevatorRuntimeMap;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { resolveElevatorServiceLevels } from './elevator-service';
|
|
1
|
+
import { resolveElevatorServiceLevels } from './elevator-service.js';
|
|
2
2
|
function getRuntimeLevelId(runtime, elevator) {
|
|
3
3
|
return runtime?.currentLevelId ?? elevator.defaultLevelId ?? elevator.fromLevelId ?? null;
|
|
4
4
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ElevatorDoorPanelStyle, ElevatorDoorStyle, ElevatorNode, ElevatorShaftStyle } from '../../schema';
|
|
1
|
+
import type { ElevatorDoorPanelStyle, ElevatorDoorStyle, ElevatorNode, ElevatorShaftStyle } from '../../schema/index.js';
|
|
2
2
|
export type ElevatorDoorSide = 'left' | 'right';
|
|
3
3
|
export declare function getResolvedElevatorDoorStyle(doorStyle: ElevatorNode['doorStyle'] | undefined): ElevatorDoorStyle;
|
|
4
4
|
export declare function getResolvedElevatorDoorPanelStyle(doorPanelStyle: ElevatorNode['doorPanelStyle'] | undefined): ElevatorDoorPanelStyle;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AnyNode, AnyNodeId, CeilingNode, SlabNode } from '../../schema';
|
|
1
|
+
import type { AnyNode, AnyNodeId, CeilingNode, SlabNode } from '../../schema/index.js';
|
|
2
2
|
export declare function syncAutoElevatorOpenings(nodes: Record<string, AnyNode>): {
|
|
3
3
|
id: AnyNodeId;
|
|
4
4
|
data: Partial<SlabNode | CeilingNode>;
|