@pascal-app/core 1.0.1 → 1.0.4
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/dist/agent-operations/__fixtures__/add-object-cases.d.ts +235 -0
- package/dist/agent-operations/__fixtures__/add-object-cases.d.ts.map +1 -0
- package/dist/agent-operations/__fixtures__/add-object-cases.js +129 -0
- package/dist/agent-operations/__fixtures__/build-room-cases.d.ts +4 -0
- package/dist/agent-operations/__fixtures__/build-room-cases.d.ts.map +1 -0
- package/dist/agent-operations/__fixtures__/build-room-cases.js +635 -0
- package/dist/agent-operations/__fixtures__/cases.d.ts +52 -0
- package/dist/agent-operations/__fixtures__/cases.d.ts.map +1 -0
- package/dist/agent-operations/__fixtures__/cases.js +689 -0
- package/dist/agent-operations/__fixtures__/find-by-type-cases.d.ts +7 -0
- package/dist/agent-operations/__fixtures__/find-by-type-cases.d.ts.map +1 -0
- package/dist/agent-operations/__fixtures__/find-by-type-cases.js +21 -0
- package/dist/agent-operations/__fixtures__/place-items-cases.d.ts +17 -0
- package/dist/agent-operations/__fixtures__/place-items-cases.d.ts.map +1 -0
- package/dist/agent-operations/__fixtures__/place-items-cases.js +506 -0
- package/dist/agent-operations/__fixtures__/room-cases.d.ts +3 -0
- package/dist/agent-operations/__fixtures__/room-cases.d.ts.map +1 -0
- package/dist/agent-operations/__fixtures__/room-cases.js +338 -0
- package/dist/agent-operations/__fixtures__/search-assets-cases.d.ts +5 -0
- package/dist/agent-operations/__fixtures__/search-assets-cases.d.ts.map +1 -0
- package/dist/agent-operations/__fixtures__/search-assets-cases.js +137 -0
- package/dist/agent-operations/__fixtures__/structure-cases.d.ts +6 -0
- package/dist/agent-operations/__fixtures__/structure-cases.d.ts.map +1 -0
- package/dist/agent-operations/__fixtures__/structure-cases.js +588 -0
- package/dist/agent-operations/__fixtures__/verify-scene-cases.d.ts +3 -0
- package/dist/agent-operations/__fixtures__/verify-scene-cases.d.ts.map +1 -0
- package/dist/agent-operations/__fixtures__/verify-scene-cases.js +302 -0
- package/dist/agent-operations/achieved.d.ts +16 -0
- package/dist/agent-operations/achieved.d.ts.map +1 -0
- package/dist/agent-operations/achieved.js +28 -0
- package/dist/agent-operations/add-column.d.ts +23 -0
- package/dist/agent-operations/add-column.d.ts.map +1 -0
- package/dist/agent-operations/add-column.js +97 -0
- package/dist/agent-operations/add-level.d.ts +14 -0
- package/dist/agent-operations/add-level.d.ts.map +1 -0
- package/dist/agent-operations/add-level.js +94 -0
- package/dist/agent-operations/add-object.d.ts +114 -0
- package/dist/agent-operations/add-object.d.ts.map +1 -0
- package/dist/agent-operations/add-object.js +361 -0
- package/dist/agent-operations/add-wall.d.ts +15 -0
- package/dist/agent-operations/add-wall.d.ts.map +1 -0
- package/dist/agent-operations/add-wall.js +47 -0
- package/dist/agent-operations/apply-changes.d.ts +16 -0
- package/dist/agent-operations/apply-changes.d.ts.map +1 -0
- package/dist/agent-operations/apply-changes.js +93 -0
- package/dist/agent-operations/apply-outcome.d.ts +15 -0
- package/dist/agent-operations/apply-outcome.d.ts.map +1 -0
- package/dist/agent-operations/apply-outcome.js +18 -0
- package/dist/agent-operations/collections.d.ts +28 -0
- package/dist/agent-operations/collections.d.ts.map +1 -0
- package/dist/agent-operations/collections.js +130 -0
- package/dist/agent-operations/create-room.d.ts +36 -0
- package/dist/agent-operations/create-room.d.ts.map +1 -0
- package/dist/agent-operations/create-room.js +177 -0
- package/dist/agent-operations/create-stair.d.ts +33 -0
- package/dist/agent-operations/create-stair.d.ts.map +1 -0
- package/dist/agent-operations/create-stair.js +247 -0
- package/dist/agent-operations/delete-node.d.ts +6 -0
- package/dist/agent-operations/delete-node.d.ts.map +1 -0
- package/dist/agent-operations/delete-node.js +9 -0
- package/dist/agent-operations/door-clearance.d.ts +135 -0
- package/dist/agent-operations/door-clearance.d.ts.map +1 -0
- package/dist/agent-operations/door-clearance.js +334 -0
- package/dist/agent-operations/duplicate-level.d.ts +12 -0
- package/dist/agent-operations/duplicate-level.d.ts.map +1 -0
- package/dist/agent-operations/duplicate-level.js +54 -0
- package/dist/agent-operations/find-by-type.d.ts +11 -0
- package/dist/agent-operations/find-by-type.d.ts.map +1 -0
- package/dist/agent-operations/find-by-type.js +94 -0
- package/dist/agent-operations/furnish-room.d.ts +18 -0
- package/dist/agent-operations/furnish-room.d.ts.map +1 -0
- package/dist/agent-operations/furnish-room.js +259 -0
- package/dist/agent-operations/get-node.d.ts +9 -0
- package/dist/agent-operations/get-node.d.ts.map +1 -0
- package/dist/agent-operations/get-node.js +33 -0
- package/dist/agent-operations/hosted-services.d.ts +13 -0
- package/dist/agent-operations/hosted-services.d.ts.map +1 -0
- package/dist/agent-operations/hosted-services.js +22 -0
- package/dist/agent-operations/index.d.ts +277 -0
- package/dist/agent-operations/index.d.ts.map +1 -0
- package/dist/agent-operations/index.js +80 -0
- package/dist/agent-operations/layout-clearance.d.ts +108 -0
- package/dist/agent-operations/layout-clearance.d.ts.map +1 -0
- package/dist/agent-operations/layout-clearance.js +190 -0
- package/dist/agent-operations/level-reads.d.ts +33 -0
- package/dist/agent-operations/level-reads.d.ts.map +1 -0
- package/dist/agent-operations/level-reads.js +161 -0
- package/dist/agent-operations/level-target.d.ts +11 -0
- package/dist/agent-operations/level-target.d.ts.map +1 -0
- package/dist/agent-operations/level-target.js +29 -0
- package/dist/agent-operations/list-levels.d.ts +4 -0
- package/dist/agent-operations/list-levels.d.ts.map +1 -0
- package/dist/agent-operations/list-levels.js +31 -0
- package/dist/agent-operations/material-preset.d.ts +11 -0
- package/dist/agent-operations/material-preset.d.ts.map +1 -0
- package/dist/agent-operations/material-preset.js +74 -0
- package/dist/agent-operations/material-refs.d.ts +24 -0
- package/dist/agent-operations/material-refs.d.ts.map +1 -0
- package/dist/agent-operations/material-refs.js +100 -0
- package/dist/agent-operations/node-patch.d.ts +3 -0
- package/dist/agent-operations/node-patch.d.ts.map +1 -0
- package/dist/agent-operations/node-patch.js +114 -0
- package/dist/agent-operations/paint.d.ts +21 -0
- package/dist/agent-operations/paint.d.ts.map +1 -0
- package/dist/agent-operations/paint.js +219 -0
- package/dist/agent-operations/place-items.d.ts +20 -0
- package/dist/agent-operations/place-items.d.ts.map +1 -0
- package/dist/agent-operations/place-items.js +226 -0
- package/dist/agent-operations/plan-geometry.d.ts +24 -0
- package/dist/agent-operations/plan-geometry.d.ts.map +1 -0
- package/dist/agent-operations/plan-geometry.js +94 -0
- package/dist/agent-operations/room-structure.d.ts +87 -0
- package/dist/agent-operations/room-structure.d.ts.map +1 -0
- package/dist/agent-operations/room-structure.js +144 -0
- package/dist/agent-operations/scene-materials.d.ts +15 -0
- package/dist/agent-operations/scene-materials.d.ts.map +1 -0
- package/dist/agent-operations/scene-materials.js +62 -0
- package/dist/agent-operations/scene-measure.d.ts +73 -0
- package/dist/agent-operations/scene-measure.d.ts.map +1 -0
- package/dist/agent-operations/scene-measure.js +73 -0
- package/dist/agent-operations/scene-queries.d.ts +4510 -0
- package/dist/agent-operations/scene-queries.d.ts.map +1 -0
- package/dist/agent-operations/scene-queries.js +84 -0
- package/dist/agent-operations/scene-view.d.ts +98 -0
- package/dist/agent-operations/scene-view.d.ts.map +1 -0
- package/dist/agent-operations/scene-view.js +559 -0
- package/dist/agent-operations/search-assets.d.ts +14 -0
- package/dist/agent-operations/search-assets.d.ts.map +1 -0
- package/dist/agent-operations/search-assets.js +42 -0
- package/dist/agent-operations/search-materials.d.ts +12 -0
- package/dist/agent-operations/search-materials.d.ts.map +1 -0
- package/dist/agent-operations/search-materials.js +111 -0
- package/dist/agent-operations/stairs.d.ts +5 -0
- package/dist/agent-operations/stairs.d.ts.map +1 -0
- package/dist/agent-operations/stairs.js +70 -0
- package/dist/agent-operations/types.d.ts +59 -0
- package/dist/agent-operations/types.d.ts.map +1 -0
- package/dist/agent-operations/types.js +1 -0
- package/dist/agent-operations/verify-scene.d.ts +50 -0
- package/dist/agent-operations/verify-scene.d.ts.map +1 -0
- package/dist/agent-operations/verify-scene.js +369 -0
- package/dist/agent-operations/wall-opening.d.ts +65 -0
- package/dist/agent-operations/wall-opening.d.ts.map +1 -0
- package/dist/agent-operations/wall-opening.js +55 -0
- package/dist/agent-tools/achieved.d.ts +9 -0
- package/dist/agent-tools/achieved.d.ts.map +1 -0
- package/dist/agent-tools/achieved.js +8 -0
- package/dist/agent-tools/add-object.d.ts +43 -0
- package/dist/agent-tools/add-object.d.ts.map +1 -0
- package/dist/agent-tools/add-object.js +86 -0
- package/dist/agent-tools/assets.d.ts +13 -0
- package/dist/agent-tools/assets.d.ts.map +1 -0
- package/dist/agent-tools/assets.js +18 -0
- package/dist/agent-tools/clear-scene.d.ts +10 -0
- package/dist/agent-tools/clear-scene.d.ts.map +1 -0
- package/dist/agent-tools/clear-scene.js +9 -0
- package/dist/agent-tools/collections.d.ts +35 -0
- package/dist/agent-tools/collections.d.ts.map +1 -0
- package/dist/agent-tools/collections.js +31 -0
- package/dist/agent-tools/columns.d.ts +44 -0
- package/dist/agent-tools/columns.d.ts.map +1 -0
- package/dist/agent-tools/columns.js +59 -0
- package/dist/agent-tools/contract.d.ts +68 -0
- package/dist/agent-tools/contract.d.ts.map +1 -0
- package/dist/agent-tools/contract.js +1 -0
- package/dist/agent-tools/create-room.d.ts +63 -0
- package/dist/agent-tools/create-room.d.ts.map +1 -0
- package/dist/agent-tools/create-room.js +90 -0
- package/dist/agent-tools/find-by-type.d.ts +11 -0
- package/dist/agent-tools/find-by-type.d.ts.map +1 -0
- package/dist/agent-tools/find-by-type.js +14 -0
- package/dist/agent-tools/furnish-room.d.ts +26 -0
- package/dist/agent-tools/furnish-room.d.ts.map +1 -0
- package/dist/agent-tools/furnish-room.js +35 -0
- package/dist/agent-tools/hosted-services.d.ts +402 -0
- package/dist/agent-tools/hosted-services.d.ts.map +1 -0
- package/dist/agent-tools/hosted-services.js +148 -0
- package/dist/agent-tools/index.d.ts +864 -0
- package/dist/agent-tools/index.d.ts.map +1 -0
- package/dist/agent-tools/index.js +82 -0
- package/dist/agent-tools/levels.d.ts +72 -0
- package/dist/agent-tools/levels.d.ts.map +1 -0
- package/dist/agent-tools/levels.js +76 -0
- package/dist/agent-tools/measurement.d.ts +37 -0
- package/dist/agent-tools/measurement.d.ts.map +1 -0
- package/dist/agent-tools/measurement.js +94 -0
- package/dist/agent-tools/node-id.d.ts +3 -0
- package/dist/agent-tools/node-id.d.ts.map +1 -0
- package/dist/agent-tools/node-id.js +2 -0
- package/dist/agent-tools/nodes.d.ts +17 -0
- package/dist/agent-tools/nodes.d.ts.map +1 -0
- package/dist/agent-tools/nodes.js +13 -0
- package/dist/agent-tools/paint.d.ts +46 -0
- package/dist/agent-tools/paint.d.ts.map +1 -0
- package/dist/agent-tools/paint.js +29 -0
- package/dist/agent-tools/place-items.d.ts +19 -0
- package/dist/agent-tools/place-items.d.ts.map +1 -0
- package/dist/agent-tools/place-items.js +29 -0
- package/dist/agent-tools/refusal.d.ts +20 -0
- package/dist/agent-tools/refusal.d.ts.map +1 -0
- package/dist/agent-tools/refusal.js +29 -0
- package/dist/agent-tools/room-structure.d.ts +438 -0
- package/dist/agent-tools/room-structure.d.ts.map +1 -0
- package/dist/agent-tools/room-structure.js +207 -0
- package/dist/agent-tools/search-materials.d.ts +20 -0
- package/dist/agent-tools/search-materials.d.ts.map +1 -0
- package/dist/agent-tools/search-materials.js +32 -0
- package/dist/agent-tools/stairs.d.ts +86 -0
- package/dist/agent-tools/stairs.d.ts.map +1 -0
- package/dist/agent-tools/stairs.js +103 -0
- package/dist/agent-tools/verify-scene.d.ts +13 -0
- package/dist/agent-tools/verify-scene.d.ts.map +1 -0
- package/dist/agent-tools/verify-scene.js +21 -0
- package/dist/agent-tools/view-scene.d.ts +43 -0
- package/dist/agent-tools/view-scene.d.ts.map +1 -0
- package/dist/agent-tools/view-scene.js +80 -0
- package/dist/agent-tools/wall-openings.d.ts +163 -0
- package/dist/agent-tools/wall-openings.d.ts.map +1 -0
- package/dist/agent-tools/wall-openings.js +144 -0
- package/dist/agent-tools/walls.d.ts +21 -0
- package/dist/agent-tools/walls.d.ts.map +1 -0
- package/dist/agent-tools/walls.js +30 -0
- package/dist/agent-tools/write-target.d.ts +12 -0
- package/dist/agent-tools/write-target.d.ts.map +1 -0
- package/dist/agent-tools/write-target.js +10 -0
- package/dist/building/__fixtures__/wall-opening-cases.d.ts +736 -0
- package/dist/building/__fixtures__/wall-opening-cases.d.ts.map +1 -0
- package/dist/building/__fixtures__/wall-opening-cases.js +307 -0
- package/dist/building/door-types.d.ts +22 -0
- package/dist/building/door-types.d.ts.map +1 -0
- package/dist/building/door-types.js +167 -0
- package/dist/building/floor-item-fit.d.ts +38 -0
- package/dist/building/floor-item-fit.d.ts.map +1 -0
- package/dist/building/floor-item-fit.js +47 -0
- package/dist/building/index.d.ts +7 -0
- package/dist/building/index.d.ts.map +1 -0
- package/dist/building/index.js +6 -0
- package/dist/building/level-duplication.d.ts +8983 -0
- package/dist/building/level-duplication.d.ts.map +1 -0
- package/dist/building/level-duplication.js +314 -0
- package/dist/building/opening-style-presets.d.ts +46 -0
- package/dist/building/opening-style-presets.d.ts.map +1 -0
- package/dist/building/opening-style-presets.js +195 -0
- package/dist/building/wall-openings.d.ts +445 -0
- package/dist/building/wall-openings.d.ts.map +1 -0
- package/dist/building/wall-openings.js +231 -0
- package/dist/building/window-types.d.ts +17 -0
- package/dist/building/window-types.d.ts.map +1 -0
- package/dist/building/window-types.js +31 -0
- package/dist/commands/structure/apply-zone-transform.d.ts +23 -0
- package/dist/commands/structure/apply-zone-transform.d.ts.map +1 -0
- package/dist/commands/structure/apply-zone-transform.js +55 -0
- package/dist/commands/structure/create-mezzanine.d.ts +12 -0
- package/dist/commands/structure/create-mezzanine.d.ts.map +1 -0
- package/dist/commands/structure/create-mezzanine.js +46 -0
- package/dist/commands/structure/create-zone.d.ts +32 -0
- package/dist/commands/structure/create-zone.d.ts.map +1 -0
- package/dist/commands/structure/create-zone.js +126 -0
- package/dist/commands/structure/delete-zone.d.ts +51 -0
- package/dist/commands/structure/delete-zone.d.ts.map +1 -0
- package/dist/commands/structure/delete-zone.js +354 -0
- package/dist/commands/structure/divide-zone.d.ts +38 -0
- package/dist/commands/structure/divide-zone.d.ts.map +1 -0
- package/dist/commands/structure/divide-zone.js +186 -0
- package/dist/commands/structure/duplicate-zone.d.ts +7 -0
- package/dist/commands/structure/duplicate-zone.d.ts.map +1 -0
- package/dist/commands/structure/duplicate-zone.js +21 -0
- package/dist/commands/structure/floor-opening.d.ts +36 -0
- package/dist/commands/structure/floor-opening.d.ts.map +1 -0
- package/dist/commands/structure/floor-opening.js +124 -0
- package/dist/commands/structure/index.d.ts +22 -0
- package/dist/commands/structure/index.d.ts.map +1 -0
- package/dist/commands/structure/index.js +20 -0
- package/dist/commands/structure/lock-outside-faces.d.ts +12 -0
- package/dist/commands/structure/lock-outside-faces.d.ts.map +1 -0
- package/dist/commands/structure/lock-outside-faces.js +32 -0
- package/dist/commands/structure/merge-zones.d.ts +5 -0
- package/dist/commands/structure/merge-zones.d.ts.map +1 -0
- package/dist/commands/structure/merge-zones.js +22 -0
- package/dist/commands/structure/mezzanine-content.d.ts +16 -0
- package/dist/commands/structure/mezzanine-content.d.ts.map +1 -0
- package/dist/commands/structure/mezzanine-content.js +109 -0
- package/dist/commands/structure/plan-mezzanine-stair.d.ts +7 -0
- package/dist/commands/structure/plan-mezzanine-stair.d.ts.map +1 -0
- package/dist/commands/structure/plan-mezzanine-stair.js +127 -0
- package/dist/commands/structure/plan-wall-deletion.d.ts +9 -0
- package/dist/commands/structure/plan-wall-deletion.d.ts.map +1 -0
- package/dist/commands/structure/plan-wall-deletion.js +151 -0
- package/dist/commands/structure/rebase-floor-reference.d.ts +7 -0
- package/dist/commands/structure/rebase-floor-reference.d.ts.map +1 -0
- package/dist/commands/structure/rebase-floor-reference.js +90 -0
- package/dist/commands/structure/resize-mezzanine.d.ts +8 -0
- package/dist/commands/structure/resize-mezzanine.d.ts.map +1 -0
- package/dist/commands/structure/resize-mezzanine.js +43 -0
- package/dist/commands/structure/rotate-zone.d.ts +8 -0
- package/dist/commands/structure/rotate-zone.d.ts.map +1 -0
- package/dist/commands/structure/rotate-zone.js +28 -0
- package/dist/commands/structure/set-floor-foundation.d.ts +62 -0
- package/dist/commands/structure/set-floor-foundation.d.ts.map +1 -0
- package/dist/commands/structure/set-floor-foundation.js +162 -0
- package/dist/commands/structure/set-room-floor-construction.d.ts +8 -0
- package/dist/commands/structure/set-room-floor-construction.d.ts.map +1 -0
- package/dist/commands/structure/set-room-floor-construction.js +72 -0
- package/dist/commands/structure/set-wall-geometry.d.ts +10 -0
- package/dist/commands/structure/set-wall-geometry.d.ts.map +1 -0
- package/dist/commands/structure/set-wall-geometry.js +52 -0
- package/dist/commands/structure/set-zone-edges.d.ts +14 -0
- package/dist/commands/structure/set-zone-edges.d.ts.map +1 -0
- package/dist/commands/structure/set-zone-edges.js +143 -0
- package/dist/commands/structure/set-zone-intent.d.ts +39 -0
- package/dist/commands/structure/set-zone-intent.d.ts.map +1 -0
- package/dist/commands/structure/set-zone-intent.js +125 -0
- package/dist/commands/structure/shared.d.ts +4512 -0
- package/dist/commands/structure/shared.d.ts.map +1 -0
- package/dist/commands/structure/shared.js +102 -0
- package/dist/commands/structure/transform-zone.d.ts +23 -0
- package/dist/commands/structure/transform-zone.d.ts.map +1 -0
- package/dist/commands/structure/transform-zone.js +472 -0
- package/dist/commands/structure/validate-mezzanine.d.ts +5 -0
- package/dist/commands/structure/validate-mezzanine.d.ts.map +1 -0
- package/dist/commands/structure/validate-mezzanine.js +46 -0
- package/dist/commands/structure/zone-crossings.d.ts +8 -0
- package/dist/commands/structure/zone-crossings.d.ts.map +1 -0
- package/dist/commands/structure/zone-crossings.js +162 -0
- package/dist/commands/structure/zone-drop.d.ts +4 -0
- package/dist/commands/structure/zone-drop.d.ts.map +1 -0
- package/dist/commands/structure/zone-drop.js +68 -0
- package/dist/commands/structure/zone-insertion.d.ts +4 -0
- package/dist/commands/structure/zone-insertion.d.ts.map +1 -0
- package/dist/commands/structure/zone-insertion.js +200 -0
- package/dist/commands/structure/zone-transform-content.d.ts +6 -0
- package/dist/commands/structure/zone-transform-content.d.ts.map +1 -0
- package/dist/commands/structure/zone-transform-content.js +117 -0
- package/dist/commands/structure/zone-wall-merge.d.ts +4977 -0
- package/dist/commands/structure/zone-wall-merge.d.ts.map +1 -0
- package/dist/commands/structure/zone-wall-merge.js +135 -0
- package/dist/contracts/reference-discovery.d.ts +18 -0
- package/dist/contracts/reference-discovery.d.ts.map +1 -0
- package/dist/contracts/reference-discovery.js +100 -0
- package/dist/contracts/reference-inventory.d.ts +44 -0
- package/dist/contracts/reference-inventory.d.ts.map +1 -0
- package/dist/contracts/reference-inventory.js +872 -0
- package/dist/events/bus.d.ts +70 -9
- package/dist/events/bus.d.ts.map +1 -1
- package/dist/hooks/scene-registry/item-clip-registry.d.ts +6 -3
- package/dist/hooks/scene-registry/item-clip-registry.d.ts.map +1 -1
- package/dist/hooks/scene-registry/item-clip-registry.js +2 -1
- package/dist/hooks/spatial-grid/floor-placed-elevation.d.ts.map +1 -1
- package/dist/hooks/spatial-grid/floor-placed-elevation.js +15 -1
- package/dist/hooks/spatial-grid/spatial-grid-manager.d.ts +3 -2
- package/dist/hooks/spatial-grid/spatial-grid-manager.d.ts.map +1 -1
- package/dist/hooks/spatial-grid/spatial-grid-manager.js +53 -66
- package/dist/hooks/spatial-grid/spatial-grid-sync.d.ts +1650 -131
- package/dist/hooks/spatial-grid/spatial-grid-sync.d.ts.map +1 -1
- package/dist/hooks/spatial-grid/spatial-grid-sync.js +86 -83
- package/dist/hooks/spatial-grid/support-host-patch.d.ts +1 -0
- package/dist/hooks/spatial-grid/support-host-patch.d.ts.map +1 -1
- package/dist/hooks/spatial-grid/support-host-patch.js +12 -5
- package/dist/index.d.ts +83 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +78 -11
- package/dist/lib/__bench__/near-linear-walls.d.ts +2 -0
- package/dist/lib/__bench__/near-linear-walls.d.ts.map +1 -0
- package/dist/lib/__bench__/near-linear-walls.js +24 -0
- package/dist/lib/__bench__/structure-preview.bench.d.ts +2 -0
- package/dist/lib/__bench__/structure-preview.bench.d.ts.map +1 -0
- package/dist/lib/__bench__/structure-preview.bench.js +72 -0
- package/dist/lib/__fixtures__/mezzanine.d.ts +13968 -0
- package/dist/lib/__fixtures__/mezzanine.d.ts.map +1 -0
- package/dist/lib/__fixtures__/mezzanine.js +43 -0
- package/dist/lib/absorb-wall-separators.d.ts +4483 -0
- package/dist/lib/absorb-wall-separators.d.ts.map +1 -0
- package/dist/lib/absorb-wall-separators.js +65 -0
- package/dist/lib/angle-accumulator.d.ts +3 -0
- package/dist/lib/angle-accumulator.d.ts.map +1 -0
- package/dist/lib/angle-accumulator.js +13 -0
- package/dist/lib/artifact-store.d.ts +31 -0
- package/dist/lib/artifact-store.d.ts.map +1 -0
- package/dist/lib/artifact-store.js +42 -0
- package/dist/lib/assembly-stack.d.ts +54 -0
- package/dist/lib/assembly-stack.d.ts.map +1 -0
- package/dist/lib/assembly-stack.js +52 -0
- package/dist/lib/asset-storage.d.ts.map +1 -1
- package/dist/lib/asset-storage.js +3 -0
- package/dist/lib/canonical-opening-ring.d.ts +3 -0
- package/dist/lib/canonical-opening-ring.d.ts.map +1 -0
- package/dist/lib/canonical-opening-ring.js +14 -0
- package/dist/lib/ceiling-children.d.ts +8 -0
- package/dist/lib/ceiling-children.d.ts.map +1 -0
- package/dist/lib/ceiling-children.js +36 -0
- package/dist/lib/ceiling-surface.d.ts +40 -0
- package/dist/lib/ceiling-surface.d.ts.map +1 -0
- package/dist/lib/ceiling-surface.js +65 -0
- package/dist/lib/cutter-host.d.ts +5 -0
- package/dist/lib/cutter-host.d.ts.map +1 -0
- package/dist/lib/cutter-host.js +30 -0
- package/dist/lib/floor-construction-lift.d.ts +4 -0
- package/dist/lib/floor-construction-lift.d.ts.map +1 -0
- package/dist/lib/floor-construction-lift.js +54 -0
- package/dist/lib/floor-footprint-key.d.ts +3 -0
- package/dist/lib/floor-footprint-key.d.ts.map +1 -0
- package/dist/lib/floor-footprint-key.js +9 -0
- package/dist/lib/floor-footprint-name.d.ts +11 -0
- package/dist/lib/floor-footprint-name.d.ts.map +1 -0
- package/dist/lib/floor-footprint-name.js +52 -0
- package/dist/lib/floor-foundation-datum.d.ts +31 -0
- package/dist/lib/floor-foundation-datum.d.ts.map +1 -0
- package/dist/lib/floor-foundation-datum.js +226 -0
- package/dist/lib/floor-foundation-stack.d.ts +16 -0
- package/dist/lib/floor-foundation-stack.d.ts.map +1 -0
- package/dist/lib/floor-foundation-stack.js +214 -0
- package/dist/lib/floor-intent-changes.d.ts +10 -0
- package/dist/lib/floor-intent-changes.d.ts.map +1 -0
- package/dist/lib/floor-intent-changes.js +461 -0
- package/dist/lib/floor-opening-footprints.d.ts +24 -0
- package/dist/lib/floor-opening-footprints.d.ts.map +1 -0
- package/dist/lib/floor-opening-footprints.js +127 -0
- package/dist/lib/floor-opening-intent.d.ts +16 -0
- package/dist/lib/floor-opening-intent.d.ts.map +1 -0
- package/dist/lib/floor-opening-intent.js +82 -0
- package/dist/lib/floor-plate-id.d.ts +5 -0
- package/dist/lib/floor-plate-id.d.ts.map +1 -0
- package/dist/lib/floor-plate-id.js +20 -0
- package/dist/lib/floor-plate-paint.d.ts +8 -0
- package/dist/lib/floor-plate-paint.d.ts.map +1 -0
- package/dist/lib/floor-plate-paint.js +11 -0
- package/dist/lib/floor-plates.d.ts +211 -0
- package/dist/lib/floor-plates.d.ts.map +1 -0
- package/dist/lib/floor-plates.js +729 -0
- package/dist/lib/floor-room-faces.d.ts +5 -0
- package/dist/lib/floor-room-faces.d.ts.map +1 -0
- package/dist/lib/floor-room-faces.js +29 -0
- package/dist/lib/floor-step-finish.d.ts +49 -0
- package/dist/lib/floor-step-finish.d.ts.map +1 -0
- package/dist/lib/floor-step-finish.js +128 -0
- package/dist/lib/geometry-script-node.d.ts +82 -0
- package/dist/lib/geometry-script-node.d.ts.map +1 -0
- package/dist/lib/geometry-script-node.js +147 -0
- package/dist/lib/geometry-surfaces.d.ts +61 -0
- package/dist/lib/geometry-surfaces.d.ts.map +1 -0
- package/dist/lib/geometry-surfaces.js +156 -0
- package/dist/lib/item-slab-support.d.ts +14 -0
- package/dist/lib/item-slab-support.d.ts.map +1 -0
- package/dist/lib/item-slab-support.js +40 -0
- package/dist/lib/level-footprints.d.ts +23 -0
- package/dist/lib/level-footprints.d.ts.map +1 -0
- package/dist/lib/level-footprints.js +398 -0
- package/dist/lib/level-name.d.ts +7 -0
- package/dist/lib/level-name.d.ts.map +1 -1
- package/dist/lib/level-name.js +11 -3
- package/dist/lib/new-zone.d.ts +10 -0
- package/dist/lib/new-zone.d.ts.map +1 -0
- package/dist/lib/new-zone.js +10 -0
- package/dist/lib/node-ancestry.d.ts +30 -0
- package/dist/lib/node-ancestry.d.ts.map +1 -0
- package/dist/lib/node-ancestry.js +76 -0
- package/dist/lib/node-visibility.d.ts +12 -0
- package/dist/lib/node-visibility.d.ts.map +1 -0
- package/dist/lib/node-visibility.js +12 -0
- package/dist/lib/object-cuts.d.ts +11 -0
- package/dist/lib/object-cuts.d.ts.map +1 -0
- package/dist/lib/object-cuts.js +63 -0
- package/dist/lib/opening-floor-datum.d.ts +24 -0
- package/dist/lib/opening-floor-datum.d.ts.map +1 -0
- package/dist/lib/opening-floor-datum.js +145 -0
- package/dist/lib/own-floor-intent.d.ts +15 -0
- package/dist/lib/own-floor-intent.d.ts.map +1 -0
- package/dist/lib/own-floor-intent.js +201 -0
- package/dist/lib/plate-reference.d.ts +3 -0
- package/dist/lib/plate-reference.d.ts.map +1 -0
- package/dist/lib/plate-reference.js +91 -0
- package/dist/lib/plate-surface.d.ts +120 -0
- package/dist/lib/plate-surface.d.ts.map +1 -0
- package/dist/lib/plate-surface.js +725 -0
- package/dist/lib/polygon-boolean.d.ts +17 -0
- package/dist/lib/polygon-boolean.d.ts.map +1 -0
- package/dist/lib/polygon-boolean.js +195 -0
- package/dist/lib/polygon-label.d.ts +7 -0
- package/dist/lib/polygon-label.d.ts.map +1 -0
- package/dist/lib/polygon-label.js +94 -0
- package/dist/lib/room-drawn-floor.d.ts +29 -0
- package/dist/lib/room-drawn-floor.d.ts.map +1 -0
- package/dist/lib/room-drawn-floor.js +88 -0
- package/dist/lib/room-floor-choices.d.ts +11 -0
- package/dist/lib/room-floor-choices.d.ts.map +1 -0
- package/dist/lib/room-floor-choices.js +60 -0
- package/dist/lib/room-floor-feasibility.d.ts +25 -0
- package/dist/lib/room-floor-feasibility.d.ts.map +1 -0
- package/dist/lib/room-floor-feasibility.js +293 -0
- package/dist/lib/room-floor-plate.d.ts +3 -0
- package/dist/lib/room-floor-plate.d.ts.map +1 -0
- package/dist/lib/room-floor-plate.js +4 -0
- package/dist/lib/room-graph.d.ts +79 -0
- package/dist/lib/room-graph.d.ts.map +1 -0
- package/dist/lib/room-graph.js +1265 -0
- package/dist/lib/room-name.d.ts +10 -0
- package/dist/lib/room-name.d.ts.map +1 -0
- package/dist/lib/room-name.js +22 -0
- package/dist/lib/room-topology-index.d.ts +53 -5
- package/dist/lib/room-topology-index.d.ts.map +1 -1
- package/dist/lib/room-topology-index.js +176 -30
- package/dist/lib/room-vertical-placement.d.ts +12 -0
- package/dist/lib/room-vertical-placement.d.ts.map +1 -0
- package/dist/lib/room-vertical-placement.js +28 -0
- package/dist/lib/room-zone-adoption.d.ts +74 -0
- package/dist/lib/room-zone-adoption.d.ts.map +1 -0
- package/dist/lib/room-zone-adoption.js +150 -0
- package/dist/lib/setback-envelope.d.ts +73 -0
- package/dist/lib/setback-envelope.d.ts.map +1 -0
- package/dist/lib/setback-envelope.js +506 -0
- package/dist/lib/slab-polygon.d.ts.map +1 -1
- package/dist/lib/slab-polygon.js +33 -12
- package/dist/lib/slots.d.ts +20 -0
- package/dist/lib/slots.d.ts.map +1 -1
- package/dist/lib/slots.js +44 -0
- package/dist/lib/space-detection.d.ts +14 -94
- package/dist/lib/space-detection.d.ts.map +1 -1
- package/dist/lib/space-detection.js +244 -1616
- package/dist/lib/structure-commit.d.ts +38 -0
- package/dist/lib/structure-commit.d.ts.map +1 -0
- package/dist/lib/structure-commit.js +52 -0
- package/dist/lib/structure-kernel.d.ts +66 -0
- package/dist/lib/structure-kernel.d.ts.map +1 -0
- package/dist/lib/structure-kernel.js +735 -0
- package/dist/lib/structure-reconcile.d.ts +15 -0
- package/dist/lib/structure-reconcile.d.ts.map +1 -0
- package/dist/lib/structure-reconcile.js +218 -0
- package/dist/lib/terrain-contours.d.ts +29 -0
- package/dist/lib/terrain-contours.d.ts.map +1 -0
- package/dist/lib/terrain-contours.js +199 -0
- package/dist/lib/terrain-source-persisted.d.ts +42 -0
- package/dist/lib/terrain-source-persisted.d.ts.map +1 -0
- package/dist/lib/terrain-source-persisted.js +68 -0
- package/dist/lib/terrain-source.d.ts +2 -40
- package/dist/lib/terrain-source.d.ts.map +1 -1
- package/dist/lib/terrain-source.js +2 -68
- package/dist/lib/terrain-support-query.d.ts +83 -0
- package/dist/lib/terrain-support-query.d.ts.map +1 -0
- package/dist/lib/terrain-support-query.js +187 -0
- package/dist/lib/terrain-support.d.ts +1 -77
- package/dist/lib/terrain-support.d.ts.map +1 -1
- package/dist/lib/terrain-support.js +3 -181
- package/dist/lib/unit-containment.js +2 -2
- package/dist/lib/unit-report.d.ts.map +1 -1
- package/dist/lib/unit-report.js +5 -4
- package/dist/lib/zone-colors.d.ts +11 -0
- package/dist/lib/zone-colors.d.ts.map +1 -0
- package/dist/lib/zone-colors.js +32 -0
- package/dist/lib/zone-quantities.d.ts.map +1 -1
- package/dist/lib/zone-quantities.js +113 -223
- package/dist/material-library.d.ts +9 -1
- package/dist/material-library.d.ts.map +1 -1
- package/dist/material-library.js +550 -1
- package/dist/node-slots/block.d.ts +7 -0
- package/dist/node-slots/block.d.ts.map +1 -0
- package/dist/node-slots/block.js +27 -0
- package/dist/node-slots/cabinet.d.ts +4 -0
- package/dist/node-slots/cabinet.d.ts.map +1 -0
- package/dist/node-slots/cabinet.js +24 -0
- package/dist/node-slots/ceiling.d.ts +6 -0
- package/dist/node-slots/ceiling.d.ts.map +1 -0
- package/dist/node-slots/ceiling.js +7 -0
- package/dist/node-slots/column.d.ts +9 -0
- package/dist/node-slots/column.d.ts.map +1 -0
- package/dist/node-slots/column.js +24 -0
- package/dist/node-slots/door.d.ts +9 -0
- package/dist/node-slots/door.d.ts.map +1 -0
- package/dist/node-slots/door.js +20 -0
- package/dist/node-slots/duct.d.ts +5 -0
- package/dist/node-slots/duct.d.ts.map +1 -0
- package/dist/node-slots/duct.js +5 -0
- package/dist/node-slots/elevator.d.ts +9 -0
- package/dist/node-slots/elevator.d.ts.map +1 -0
- package/dist/node-slots/elevator.js +17 -0
- package/dist/node-slots/fence.d.ts +10 -0
- package/dist/node-slots/fence.d.ts.map +1 -0
- package/dist/node-slots/fence.js +23 -0
- package/dist/node-slots/index.d.ts +25 -0
- package/dist/node-slots/index.d.ts.map +1 -0
- package/dist/node-slots/index.js +92 -0
- package/dist/node-slots/lean-to-extension.d.ts +5 -0
- package/dist/node-slots/lean-to-extension.d.ts.map +1 -0
- package/dist/node-slots/lean-to-extension.js +15 -0
- package/dist/node-slots/procedural-item.d.ts +4 -0
- package/dist/node-slots/procedural-item.d.ts.map +1 -0
- package/dist/node-slots/procedural-item.js +3 -0
- package/dist/node-slots/roof-accessories.d.ts +9 -0
- package/dist/node-slots/roof-accessories.d.ts.map +1 -0
- package/dist/node-slots/roof-accessories.js +34 -0
- package/dist/node-slots/shelf.d.ts +9 -0
- package/dist/node-slots/shelf.d.ts.map +1 -0
- package/dist/node-slots/shelf.js +30 -0
- package/dist/node-slots/slab.d.ts +7 -0
- package/dist/node-slots/slab.d.ts.map +1 -0
- package/dist/node-slots/slab.js +21 -0
- package/dist/node-slots/stair.d.ts +8 -0
- package/dist/node-slots/stair.d.ts.map +1 -0
- package/dist/node-slots/stair.js +17 -0
- package/dist/node-slots/wall.d.ts +12 -0
- package/dist/node-slots/wall.d.ts.map +1 -0
- package/dist/node-slots/wall.js +55 -0
- package/dist/node-slots/window.d.ts +5 -0
- package/dist/node-slots/window.d.ts.map +1 -0
- package/dist/node-slots/window.js +11 -0
- package/dist/procedural-items/design-placement.d.ts +49 -0
- package/dist/procedural-items/design-placement.d.ts.map +1 -0
- package/dist/procedural-items/design-placement.js +129 -0
- package/dist/procedural-items/design.d.ts +261 -0
- package/dist/procedural-items/design.d.ts.map +1 -0
- package/dist/procedural-items/design.js +707 -0
- package/dist/procedural-items/fixtures.d.ts +464 -24
- package/dist/procedural-items/fixtures.d.ts.map +1 -1
- package/dist/procedural-items/index.d.ts +5 -0
- package/dist/procedural-items/index.d.ts.map +1 -1
- package/dist/procedural-items/index.js +5 -0
- package/dist/procedural-items/integration.d.ts +127 -6
- package/dist/procedural-items/integration.d.ts.map +1 -1
- package/dist/procedural-items/joints.d.ts +56 -0
- package/dist/procedural-items/joints.d.ts.map +1 -0
- package/dist/procedural-items/joints.js +251 -0
- package/dist/procedural-items/library-colors.d.ts +12 -0
- package/dist/procedural-items/library-colors.d.ts.map +1 -1
- package/dist/procedural-items/library-colors.js +37 -3
- package/dist/procedural-items/motion-controller.d.ts +29 -0
- package/dist/procedural-items/motion-controller.d.ts.map +1 -0
- package/dist/procedural-items/motion-controller.js +130 -0
- package/dist/procedural-items/node.d.ts +490 -24
- package/dist/procedural-items/node.d.ts.map +1 -1
- package/dist/procedural-items/query.d.ts +19 -1
- package/dist/procedural-items/query.d.ts.map +1 -1
- package/dist/procedural-items/query.js +131 -48
- package/dist/procedural-items/recipe.d.ts +258 -14
- package/dist/procedural-items/recipe.d.ts.map +1 -1
- package/dist/procedural-items/recipe.js +933 -61
- package/dist/procedural-items/section.d.ts +27 -0
- package/dist/procedural-items/section.d.ts.map +1 -0
- package/dist/procedural-items/section.js +237 -0
- package/dist/procedural-items/spatial.d.ts +21 -0
- package/dist/procedural-items/spatial.d.ts.map +1 -1
- package/dist/procedural-items/spatial.js +90 -0
- package/dist/registry/handles.d.ts +30 -1
- package/dist/registry/handles.d.ts.map +1 -1
- package/dist/registry/index.d.ts +7 -5
- package/dist/registry/index.d.ts.map +1 -1
- package/dist/registry/index.js +4 -2
- package/dist/registry/mechanism.d.ts +9 -0
- package/dist/registry/mechanism.d.ts.map +1 -0
- package/dist/registry/mechanism.js +21 -0
- package/dist/registry/registry.d.ts +6 -3
- package/dist/registry/registry.d.ts.map +1 -1
- package/dist/registry/registry.js +59 -22
- package/dist/registry/scene-api.d.ts +20 -0
- package/dist/registry/scene-api.d.ts.map +1 -1
- package/dist/registry/scene-api.js +26 -13
- package/dist/registry/subtree.d.ts +8 -0
- package/dist/registry/subtree.d.ts.map +1 -1
- package/dist/registry/subtree.js +59 -0
- package/dist/registry/types.d.ts +352 -13
- package/dist/registry/types.d.ts.map +1 -1
- package/dist/schema/__fixtures__/node-fixtures.d.ts.map +1 -1
- package/dist/schema/__fixtures__/node-fixtures.js +2 -0
- package/dist/schema/assembly.d.ts +153 -0
- package/dist/schema/assembly.d.ts.map +1 -0
- package/dist/schema/assembly.js +155 -0
- package/dist/schema/asset-url.d.ts +2 -1
- package/dist/schema/asset-url.d.ts.map +1 -1
- package/dist/schema/asset-url.js +5 -2
- package/dist/schema/base.d.ts +26 -0
- package/dist/schema/base.d.ts.map +1 -1
- package/dist/schema/base.js +2 -0
- package/dist/schema/collection-templates.d.ts +46 -0
- package/dist/schema/collection-templates.d.ts.map +1 -0
- package/dist/schema/collection-templates.js +14 -0
- package/dist/schema/collections.d.ts +7 -0
- package/dist/schema/collections.d.ts.map +1 -1
- package/dist/schema/cut.d.ts +29 -0
- package/dist/schema/cut.d.ts.map +1 -0
- package/dist/schema/cut.js +50 -0
- package/dist/schema/geometry-metadata.d.ts +51 -0
- package/dist/schema/geometry-metadata.d.ts.map +1 -0
- package/dist/schema/geometry-metadata.js +57 -0
- package/dist/schema/geometry-source.d.ts +250 -0
- package/dist/schema/geometry-source.d.ts.map +1 -0
- package/dist/schema/geometry-source.js +130 -0
- package/dist/schema/index.d.ts +20 -7
- package/dist/schema/index.d.ts.map +1 -1
- package/dist/schema/index.js +22 -5
- package/dist/schema/nodes/block.d.ts +28 -2
- package/dist/schema/nodes/block.d.ts.map +1 -1
- package/dist/schema/nodes/block.js +22 -9
- package/dist/schema/nodes/box-vent.d.ts +26 -0
- package/dist/schema/nodes/box-vent.d.ts.map +1 -1
- package/dist/schema/nodes/building.d.ts +26 -0
- package/dist/schema/nodes/building.d.ts.map +1 -1
- package/dist/schema/nodes/cabinet.d.ts +61 -9
- package/dist/schema/nodes/cabinet.d.ts.map +1 -1
- package/dist/schema/nodes/ceiling.d.ts +37 -0
- package/dist/schema/nodes/ceiling.d.ts.map +1 -1
- package/dist/schema/nodes/ceiling.js +8 -0
- package/dist/schema/nodes/chimney.d.ts +26 -0
- package/dist/schema/nodes/chimney.d.ts.map +1 -1
- package/dist/schema/nodes/column.d.ts +126 -0
- package/dist/schema/nodes/column.d.ts.map +1 -1
- package/dist/schema/nodes/column.js +2 -0
- package/dist/schema/nodes/construction-dimension.d.ts +26 -0
- package/dist/schema/nodes/construction-dimension.d.ts.map +1 -1
- package/dist/schema/nodes/cupola.d.ts +26 -0
- package/dist/schema/nodes/cupola.d.ts.map +1 -1
- package/dist/schema/nodes/curtain-wall.d.ts +129 -0
- package/dist/schema/nodes/curtain-wall.d.ts.map +1 -0
- package/dist/schema/nodes/curtain-wall.js +49 -0
- package/dist/schema/nodes/door.d.ts +141 -22
- package/dist/schema/nodes/door.d.ts.map +1 -1
- package/dist/schema/nodes/door.js +18 -33
- package/dist/schema/nodes/dormer.d.ts +28 -2
- package/dist/schema/nodes/dormer.d.ts.map +1 -1
- package/dist/schema/nodes/downspout.d.ts +27 -1
- package/dist/schema/nodes/downspout.d.ts.map +1 -1
- package/dist/schema/nodes/duct-fitting.d.ts +27 -1
- package/dist/schema/nodes/duct-fitting.d.ts.map +1 -1
- package/dist/schema/nodes/duct-segment.d.ts +27 -1
- package/dist/schema/nodes/duct-segment.d.ts.map +1 -1
- package/dist/schema/nodes/duct-terminal.d.ts +26 -0
- package/dist/schema/nodes/duct-terminal.d.ts.map +1 -1
- package/dist/schema/nodes/elevator.d.ts +26 -0
- package/dist/schema/nodes/elevator.d.ts.map +1 -1
- package/dist/schema/nodes/eyebrow-vent.d.ts +26 -0
- package/dist/schema/nodes/eyebrow-vent.d.ts.map +1 -1
- package/dist/schema/nodes/fence-feature.d.ts +141 -0
- package/dist/schema/nodes/fence-feature.d.ts.map +1 -0
- package/dist/schema/nodes/fence-feature.js +21 -0
- package/dist/schema/nodes/fence.d.ts +186 -0
- package/dist/schema/nodes/fence.d.ts.map +1 -1
- package/dist/schema/nodes/fence.js +92 -7
- package/dist/schema/nodes/floor-opening.d.ts +61 -0
- package/dist/schema/nodes/floor-opening.d.ts.map +1 -0
- package/dist/schema/nodes/floor-opening.js +17 -0
- package/dist/schema/nodes/guide.d.ts +26 -0
- package/dist/schema/nodes/guide.d.ts.map +1 -1
- package/dist/schema/nodes/gutter.d.ts +26 -0
- package/dist/schema/nodes/gutter.d.ts.map +1 -1
- package/dist/schema/nodes/hvac-equipment.d.ts +26 -0
- package/dist/schema/nodes/hvac-equipment.d.ts.map +1 -1
- package/dist/schema/nodes/imported-mesh.d.ts +26 -0
- package/dist/schema/nodes/imported-mesh.d.ts.map +1 -1
- package/dist/schema/nodes/item.d.ts +153 -2
- package/dist/schema/nodes/item.d.ts.map +1 -1
- package/dist/schema/nodes/item.js +13 -0
- package/dist/schema/nodes/lean-to-extension.d.ts +26 -0
- package/dist/schema/nodes/lean-to-extension.d.ts.map +1 -1
- package/dist/schema/nodes/level.d.ts +27 -1
- package/dist/schema/nodes/level.d.ts.map +1 -1
- package/dist/schema/nodes/lineset.d.ts +26 -0
- package/dist/schema/nodes/lineset.d.ts.map +1 -1
- package/dist/schema/nodes/liquid-line.d.ts +26 -0
- package/dist/schema/nodes/liquid-line.d.ts.map +1 -1
- package/dist/schema/nodes/measurement.d.ts +26 -0
- package/dist/schema/nodes/measurement.d.ts.map +1 -1
- package/dist/schema/nodes/opening-types.d.ts +41 -0
- package/dist/schema/nodes/opening-types.d.ts.map +1 -0
- package/dist/schema/nodes/opening-types.js +48 -0
- package/dist/schema/nodes/pipe-fitting.d.ts +26 -0
- package/dist/schema/nodes/pipe-fitting.d.ts.map +1 -1
- package/dist/schema/nodes/pipe-segment.d.ts +26 -0
- package/dist/schema/nodes/pipe-segment.d.ts.map +1 -1
- package/dist/schema/nodes/pipe-trap.d.ts +26 -0
- package/dist/schema/nodes/pipe-trap.d.ts.map +1 -1
- package/dist/schema/nodes/ridge-vent.d.ts +26 -0
- package/dist/schema/nodes/ridge-vent.d.ts.map +1 -1
- package/dist/schema/nodes/roof-segment-walls.d.ts.map +1 -1
- package/dist/schema/nodes/roof-segment-walls.js +2 -1
- package/dist/schema/nodes/roof-segment.d.ts +30 -2
- package/dist/schema/nodes/roof-segment.d.ts.map +1 -1
- package/dist/schema/nodes/roof-segment.js +9 -0
- package/dist/schema/nodes/roof.d.ts +101 -0
- package/dist/schema/nodes/roof.d.ts.map +1 -1
- package/dist/schema/nodes/roof.js +6 -0
- package/dist/schema/nodes/scan.d.ts +26 -0
- package/dist/schema/nodes/scan.d.ts.map +1 -1
- package/dist/schema/nodes/separator.d.ts +50 -0
- package/dist/schema/nodes/separator.d.ts.map +1 -0
- package/dist/schema/nodes/separator.js +8 -0
- package/dist/schema/nodes/shelf.d.ts +26 -0
- package/dist/schema/nodes/shelf.d.ts.map +1 -1
- package/dist/schema/nodes/site.d.ts +192 -0
- package/dist/schema/nodes/site.d.ts.map +1 -1
- package/dist/schema/nodes/site.js +178 -1
- package/dist/schema/nodes/skylight.d.ts +30 -4
- package/dist/schema/nodes/skylight.d.ts.map +1 -1
- package/dist/schema/nodes/slab.d.ts +84 -0
- package/dist/schema/nodes/slab.d.ts.map +1 -1
- package/dist/schema/nodes/slab.js +37 -2
- package/dist/schema/nodes/solar-panel.d.ts +26 -0
- package/dist/schema/nodes/solar-panel.d.ts.map +1 -1
- package/dist/schema/nodes/spawn.d.ts +26 -0
- package/dist/schema/nodes/spawn.d.ts.map +1 -1
- package/dist/schema/nodes/stair-construction.d.ts +21 -0
- package/dist/schema/nodes/stair-construction.d.ts.map +1 -0
- package/dist/schema/nodes/stair-construction.js +13 -0
- package/dist/schema/nodes/stair-design-targets.d.ts +9 -0
- package/dist/schema/nodes/stair-design-targets.d.ts.map +1 -0
- package/dist/schema/nodes/stair-design-targets.js +7 -0
- package/dist/schema/nodes/stair-segment.d.ts +72 -4
- package/dist/schema/nodes/stair-segment.d.ts.map +1 -1
- package/dist/schema/nodes/stair-segment.js +13 -0
- package/dist/schema/nodes/stair.d.ts +119 -2
- package/dist/schema/nodes/stair.d.ts.map +1 -1
- package/dist/schema/nodes/stair.js +59 -2
- package/dist/schema/nodes/structural-grid.d.ts +26 -0
- package/dist/schema/nodes/structural-grid.d.ts.map +1 -1
- package/dist/schema/nodes/surface-hole-metadata.d.ts +3 -0
- package/dist/schema/nodes/surface-hole-metadata.d.ts.map +1 -1
- package/dist/schema/nodes/surface-hole-metadata.js +2 -1
- package/dist/schema/nodes/surface-paint-region.d.ts +14 -0
- package/dist/schema/nodes/surface-paint-region.d.ts.map +1 -0
- package/dist/schema/nodes/surface-paint-region.js +12 -0
- package/dist/schema/nodes/turbine-vent.d.ts +26 -0
- package/dist/schema/nodes/turbine-vent.d.ts.map +1 -1
- package/dist/schema/nodes/unit.d.ts +26 -0
- package/dist/schema/nodes/unit.d.ts.map +1 -1
- package/dist/schema/nodes/wall.d.ts +423 -59
- package/dist/schema/nodes/wall.d.ts.map +1 -1
- package/dist/schema/nodes/wall.js +188 -186
- package/dist/schema/nodes/window.d.ts +139 -20
- package/dist/schema/nodes/window.d.ts.map +1 -1
- package/dist/schema/nodes/window.js +12 -14
- package/dist/schema/nodes/zone.d.ts +69 -1
- package/dist/schema/nodes/zone.d.ts.map +1 -1
- package/dist/schema/nodes/zone.js +46 -0
- package/dist/schema/provenance.d.ts +118 -0
- package/dist/schema/provenance.d.ts.map +1 -0
- package/dist/schema/provenance.js +76 -0
- package/dist/schema/source-ref.d.ts +23 -0
- package/dist/schema/source-ref.d.ts.map +1 -0
- package/dist/schema/source-ref.js +29 -0
- package/dist/schema/types.d.ts +3389 -67
- package/dist/schema/types.d.ts.map +1 -1
- package/dist/schema/types.js +7 -0
- package/dist/services/__fixtures__/hosting.d.ts +3 -0
- package/dist/services/__fixtures__/hosting.d.ts.map +1 -0
- package/dist/services/__fixtures__/hosting.js +9 -0
- package/dist/services/__fixtures__/shelf-surface-rows.d.ts +4 -0
- package/dist/services/__fixtures__/shelf-surface-rows.d.ts.map +1 -0
- package/dist/services/__fixtures__/shelf-surface-rows.js +18 -0
- package/dist/services/alignment-anchors.d.ts +2 -1
- package/dist/services/alignment-anchors.d.ts.map +1 -1
- package/dist/services/alignment-anchors.js +9 -6
- package/dist/services/hosting.d.ts +3 -0
- package/dist/services/hosting.d.ts.map +1 -1
- package/dist/services/hosting.js +24 -7
- package/dist/services/index.d.ts +4 -4
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/index.js +4 -4
- package/dist/services/level-height.d.ts.map +1 -1
- package/dist/services/level-height.js +6 -4
- package/dist/services/snap.d.ts +3 -0
- package/dist/services/snap.d.ts.map +1 -1
- package/dist/services/snap.js +11 -0
- package/dist/services/storey.d.ts +21 -1
- package/dist/services/storey.d.ts.map +1 -1
- package/dist/services/storey.js +94 -8
- package/dist/services/surface-hosting.d.ts +6 -2
- package/dist/services/surface-hosting.d.ts.map +1 -1
- package/dist/services/surface-hosting.js +51 -11
- package/dist/store/actions/node-actions.d.ts +4563 -8
- package/dist/store/actions/node-actions.d.ts.map +1 -1
- package/dist/store/actions/node-actions.js +497 -269
- package/dist/store/derived-node-guard.d.ts +84 -0
- package/dist/store/derived-node-guard.d.ts.map +1 -0
- package/dist/store/derived-node-guard.js +586 -0
- package/dist/store/history-control.d.ts +34 -0
- package/dist/store/history-control.d.ts.map +1 -1
- package/dist/store/history-control.js +99 -1
- package/dist/store/history-drafts.d.ts +48 -0
- package/dist/store/history-drafts.d.ts.map +1 -0
- package/dist/store/history-drafts.js +403 -0
- package/dist/store/history-invalidation.d.ts.map +1 -1
- package/dist/store/history-invalidation.js +1 -0
- package/dist/store/item-interaction.d.ts +28 -0
- package/dist/store/item-interaction.d.ts.map +1 -0
- package/dist/store/item-interaction.js +34 -0
- package/dist/store/registered-node-defaults.d.ts +11 -0
- package/dist/store/registered-node-defaults.d.ts.map +1 -0
- package/dist/store/registered-node-defaults.js +25 -0
- package/dist/store/scene-annotations.d.ts +8969 -0
- package/dist/store/scene-annotations.d.ts.map +1 -0
- package/dist/store/scene-annotations.js +107 -0
- package/dist/store/use-interactive.d.ts +23 -1
- package/dist/store/use-interactive.d.ts.map +1 -1
- package/dist/store/use-interactive.js +128 -5
- package/dist/store/use-scene.d.ts +68 -12
- package/dist/store/use-scene.d.ts.map +1 -1
- package/dist/store/use-scene.js +429 -306
- package/dist/systems/elevator/elevator-opening-sync.d.ts.map +1 -1
- package/dist/systems/elevator/elevator-opening-sync.js +4 -6
- package/dist/systems/elevator/elevator-opening-system.d.ts.map +1 -1
- package/dist/systems/elevator/elevator-opening-system.js +12 -6
- package/dist/systems/elevator/elevator-service.d.ts.map +1 -1
- package/dist/systems/elevator/elevator-service.js +8 -3
- package/dist/systems/fence/fence-centerline.d.ts.map +1 -1
- package/dist/systems/fence/fence-centerline.js +6 -5
- package/dist/systems/fence/fence-features.d.ts +36 -0
- package/dist/systems/fence/fence-features.d.ts.map +1 -0
- package/dist/systems/fence/fence-features.js +105 -0
- package/dist/systems/fence/fence-spline.d.ts +8 -5
- package/dist/systems/fence/fence-spline.d.ts.map +1 -1
- package/dist/systems/fence/fence-spline.js +51 -16
- package/dist/systems/owned-floor-openings.d.ts +9 -0
- package/dist/systems/owned-floor-openings.d.ts.map +1 -0
- package/dist/systems/owned-floor-openings.js +326 -0
- package/dist/systems/reconcile-owned-floor-openings.d.ts +3 -0
- package/dist/systems/reconcile-owned-floor-openings.d.ts.map +1 -0
- package/dist/systems/reconcile-owned-floor-openings.js +25 -0
- package/dist/systems/slab/__fixtures__/doorway-steps.d.ts +8 -0
- package/dist/systems/slab/__fixtures__/doorway-steps.d.ts.map +1 -0
- package/dist/systems/slab/__fixtures__/doorway-steps.js +62 -0
- package/dist/systems/slab/__fixtures__/floor-step.d.ts +5636 -0
- package/dist/systems/slab/__fixtures__/floor-step.d.ts.map +1 -0
- package/dist/systems/slab/__fixtures__/floor-step.js +66 -0
- package/dist/systems/slab/__fixtures__/raised-room.d.ts +5775 -0
- package/dist/systems/slab/__fixtures__/raised-room.d.ts.map +1 -0
- package/dist/systems/slab/__fixtures__/raised-room.js +54 -0
- package/dist/systems/slab/ensure-slab-openings.d.ts +9 -0
- package/dist/systems/slab/ensure-slab-openings.d.ts.map +1 -0
- package/dist/systems/slab/ensure-slab-openings.js +41 -0
- package/dist/systems/slab/slab-support.d.ts +25 -6
- package/dist/systems/slab/slab-support.d.ts.map +1 -1
- package/dist/systems/slab/slab-support.js +471 -54
- package/dist/systems/stair/stair-base-elevation.d.ts +3 -0
- package/dist/systems/stair/stair-base-elevation.d.ts.map +1 -0
- package/dist/systems/stair/stair-base-elevation.js +49 -0
- package/dist/systems/stair/stair-clearance.d.ts +39 -0
- package/dist/systems/stair/stair-clearance.d.ts.map +1 -0
- package/dist/systems/stair/stair-clearance.js +508 -0
- package/dist/systems/stair/stair-construction.d.ts +37 -0
- package/dist/systems/stair/stair-construction.d.ts.map +1 -0
- package/dist/systems/stair/stair-construction.js +314 -0
- package/dist/systems/stair/stair-detail-budget.d.ts +13 -0
- package/dist/systems/stair/stair-detail-budget.d.ts.map +1 -0
- package/dist/systems/stair/stair-detail-budget.js +64 -0
- package/dist/systems/stair/stair-flight.d.ts +2 -2
- package/dist/systems/stair/stair-flight.d.ts.map +1 -1
- package/dist/systems/stair/stair-flight.js +4 -3
- package/dist/systems/stair/stair-floor-footprints.d.ts +7 -0
- package/dist/systems/stair/stair-floor-footprints.d.ts.map +1 -0
- package/dist/systems/stair/stair-floor-footprints.js +113 -0
- package/dist/systems/stair/stair-footprint.d.ts +3 -1
- package/dist/systems/stair/stair-footprint.d.ts.map +1 -1
- package/dist/systems/stair/stair-footprint.js +97 -44
- package/dist/systems/stair/stair-layout.d.ts +39 -0
- package/dist/systems/stair/stair-layout.d.ts.map +1 -0
- package/dist/systems/stair/stair-layout.js +58 -0
- package/dist/systems/stair/stair-opening-preview.d.ts +1650 -84
- package/dist/systems/stair/stair-opening-preview.d.ts.map +1 -1
- package/dist/systems/stair/stair-opening-sync.d.ts +8 -2
- package/dist/systems/stair/stair-opening-sync.d.ts.map +1 -1
- package/dist/systems/stair/stair-opening-sync.js +136 -315
- package/dist/systems/stair/stair-opening-system.d.ts.map +1 -1
- package/dist/systems/stair/stair-opening-system.js +40 -8
- package/dist/systems/stair/stair-presets.d.ts +276 -0
- package/dist/systems/stair/stair-presets.d.ts.map +1 -0
- package/dist/systems/stair/stair-presets.js +151 -0
- package/dist/systems/stair/stair-rail-budget.d.ts +6 -0
- package/dist/systems/stair/stair-rail-budget.d.ts.map +1 -0
- package/dist/systems/stair/stair-rail-budget.js +36 -0
- package/dist/systems/stair/stair-rail-path.d.ts +22 -0
- package/dist/systems/stair/stair-rail-path.d.ts.map +1 -0
- package/dist/systems/stair/stair-rail-path.js +497 -0
- package/dist/systems/stair/stair-rise-edit.d.ts +9 -0
- package/dist/systems/stair/stair-rise-edit.d.ts.map +1 -0
- package/dist/systems/stair/stair-rise-edit.js +46 -0
- package/dist/systems/stair/stair-rise-query.d.ts +24 -0
- package/dist/systems/stair/stair-rise-query.d.ts.map +1 -0
- package/dist/systems/stair/stair-rise-query.js +125 -0
- package/dist/systems/stair/stair-rise.d.ts +4 -19
- package/dist/systems/stair/stair-rise.d.ts.map +1 -1
- package/dist/systems/stair/stair-rise.js +8 -71
- package/dist/systems/stair/stair-sizing.d.ts +414 -0
- package/dist/systems/stair/stair-sizing.d.ts.map +1 -0
- package/dist/systems/stair/stair-sizing.js +255 -0
- package/dist/systems/stair/stair-sweep-edit.d.ts +7 -0
- package/dist/systems/stair/stair-sweep-edit.d.ts.map +1 -0
- package/dist/systems/stair/stair-sweep-edit.js +8 -0
- package/dist/systems/stair/stair-walking-line.d.ts +5 -0
- package/dist/systems/stair/stair-walking-line.d.ts.map +1 -0
- package/dist/systems/stair/stair-walking-line.js +91 -0
- package/dist/systems/stair/stair-winder.d.ts +36 -0
- package/dist/systems/stair/stair-winder.d.ts.map +1 -0
- package/dist/systems/stair/stair-winder.js +173 -0
- package/dist/systems/wall/wall-assembly.d.ts +234 -0
- package/dist/systems/wall/wall-assembly.d.ts.map +1 -0
- package/dist/systems/wall/wall-assembly.js +854 -0
- package/dist/systems/wall/wall-curve.d.ts +2 -1
- package/dist/systems/wall/wall-curve.d.ts.map +1 -1
- package/dist/systems/wall/wall-curve.js +21 -5
- package/dist/systems/wall/wall-finish.d.ts +102 -0
- package/dist/systems/wall/wall-finish.d.ts.map +1 -0
- package/dist/systems/wall/wall-finish.js +264 -0
- package/dist/systems/wall/wall-footprint.d.ts +3 -0
- package/dist/systems/wall/wall-footprint.d.ts.map +1 -1
- package/dist/systems/wall/wall-footprint.js +15 -13
- package/dist/systems/wall/wall-frame.d.ts +45 -0
- package/dist/systems/wall/wall-frame.d.ts.map +1 -0
- package/dist/systems/wall/wall-frame.js +162 -0
- package/dist/systems/wall/wall-layer-bands.d.ts +38 -0
- package/dist/systems/wall/wall-layer-bands.d.ts.map +1 -0
- package/dist/systems/wall/wall-layer-bands.js +109 -0
- package/dist/systems/wall/wall-merge.d.ts +57 -0
- package/dist/systems/wall/wall-merge.d.ts.map +1 -0
- package/dist/systems/wall/wall-merge.js +411 -0
- package/dist/systems/wall/wall-mitering.d.ts +6 -5
- package/dist/systems/wall/wall-mitering.d.ts.map +1 -1
- package/dist/systems/wall/wall-mitering.js +70 -20
- package/dist/systems/wall/wall-operations.d.ts +28 -0
- package/dist/systems/wall/wall-operations.d.ts.map +1 -0
- package/dist/systems/wall/wall-operations.js +146 -0
- package/dist/systems/wall/wall-paint-plan.d.ts +30 -0
- package/dist/systems/wall/wall-paint-plan.d.ts.map +1 -0
- package/dist/systems/wall/wall-paint-plan.js +167 -0
- package/dist/systems/wall/wall-room-sides.d.ts +6 -0
- package/dist/systems/wall/wall-room-sides.d.ts.map +1 -0
- package/dist/systems/wall/wall-room-sides.js +14 -0
- package/dist/systems/wall/wall-step-openings.d.ts +17 -0
- package/dist/systems/wall/wall-step-openings.d.ts.map +1 -0
- package/dist/systems/wall/wall-step-openings.js +32 -0
- package/dist/systems/wall/wall-top.d.ts +2 -6
- package/dist/systems/wall/wall-top.d.ts.map +1 -1
- package/dist/systems/wall/wall-top.js +3 -9
- package/dist/systems/wall/wall-topology.d.ts +28 -0
- package/dist/systems/wall/wall-topology.d.ts.map +1 -1
- package/dist/systems/wall/wall-topology.js +458 -9
- package/dist/utils/clone-scene-graph.d.ts +6 -0
- package/dist/utils/clone-scene-graph.d.ts.map +1 -1
- package/dist/utils/clone-scene-graph.js +123 -15
- package/dist/utils/ensure-scene-openings.d.ts +8965 -0
- package/dist/utils/ensure-scene-openings.d.ts.map +1 -0
- package/dist/utils/ensure-scene-openings.js +29 -0
- package/dist/utils/exterior-threshold-migration.d.ts +4 -0
- package/dist/utils/exterior-threshold-migration.d.ts.map +1 -0
- package/dist/utils/exterior-threshold-migration.js +114 -0
- package/dist/utils/floor-follow-migration.d.ts +3 -0
- package/dist/utils/floor-follow-migration.d.ts.map +1 -0
- package/dist/utils/floor-follow-migration.js +29 -0
- package/dist/utils/floor-opening-migration.d.ts +13 -0
- package/dist/utils/floor-opening-migration.d.ts.map +1 -0
- package/dist/utils/floor-opening-migration.js +148 -0
- package/dist/utils/floor-piece-adoption.d.ts +50 -0
- package/dist/utils/floor-piece-adoption.d.ts.map +1 -0
- package/dist/utils/floor-piece-adoption.js +182 -0
- package/dist/utils/floor-plate-migration.d.ts +4507 -0
- package/dist/utils/floor-plate-migration.d.ts.map +1 -0
- package/dist/utils/floor-plate-migration.js +1360 -0
- package/dist/utils/heal-plan-coordinates.d.ts +2 -0
- package/dist/utils/heal-plan-coordinates.d.ts.map +1 -0
- package/dist/utils/heal-plan-coordinates.js +69 -0
- package/dist/utils/heal-scene-graph.d.ts +20 -6
- package/dist/utils/heal-scene-graph.d.ts.map +1 -1
- package/dist/utils/heal-scene-graph.js +61 -16
- package/dist/utils/legacy-material-slots.d.ts +23 -0
- package/dist/utils/legacy-material-slots.d.ts.map +1 -0
- package/dist/utils/legacy-material-slots.js +120 -0
- package/dist/utils/legacy-opening-datums.d.ts +11 -0
- package/dist/utils/legacy-opening-datums.d.ts.map +1 -0
- package/dist/utils/legacy-opening-datums.js +92 -0
- package/dist/utils/legacy-wall-datums.d.ts +6 -0
- package/dist/utils/legacy-wall-datums.d.ts.map +1 -0
- package/dist/utils/legacy-wall-datums.js +199 -0
- package/dist/utils/load-migration.d.ts +28 -0
- package/dist/utils/load-migration.d.ts.map +1 -0
- package/dist/utils/load-migration.js +89 -0
- package/dist/utils/node-defaults.d.ts +37 -0
- package/dist/utils/node-defaults.d.ts.map +1 -0
- package/dist/utils/node-defaults.js +96 -0
- package/dist/utils/normalize-legacy-structure.d.ts +2 -0
- package/dist/utils/normalize-legacy-structure.d.ts.map +1 -0
- package/dist/utils/normalize-legacy-structure.js +61 -0
- package/dist/utils/omit-undefined.d.ts +2 -0
- package/dist/utils/omit-undefined.d.ts.map +1 -0
- package/dist/utils/omit-undefined.js +17 -0
- package/dist/utils/owned-floor-opening-migration.d.ts +4489 -0
- package/dist/utils/owned-floor-opening-migration.d.ts.map +1 -0
- package/dist/utils/owned-floor-opening-migration.js +365 -0
- package/dist/utils/reconcile-structure-on-load.d.ts +8965 -0
- package/dist/utils/reconcile-structure-on-load.d.ts.map +1 -0
- package/dist/utils/reconcile-structure-on-load.js +307 -0
- package/dist/utils/room-zone-migration.d.ts +18 -0
- package/dist/utils/room-zone-migration.d.ts.map +1 -0
- package/dist/utils/room-zone-migration.js +258 -0
- package/dist/utils/scene-migrations.d.ts +16 -1
- package/dist/utils/scene-migrations.d.ts.map +1 -1
- package/dist/utils/scene-migrations.js +15 -1
- package/dist/utils/structure-id.d.ts +4 -0
- package/dist/utils/structure-id.d.ts.map +1 -0
- package/dist/utils/structure-id.js +115 -0
- package/dist/utils/vertical-scene-migration.d.ts +8 -8
- package/dist/utils/vertical-scene-migration.d.ts.map +1 -1
- package/dist/utils/vertical-scene-migration.js +18 -8
- package/dist/utils/wall-assembly-migration.d.ts +14 -0
- package/dist/utils/wall-assembly-migration.d.ts.map +1 -0
- package/dist/utils/wall-assembly-migration.js +23 -0
- package/dist/utils/wall-face-migration.d.ts +23 -0
- package/dist/utils/wall-face-migration.d.ts.map +1 -0
- package/dist/utils/wall-face-migration.js +246 -0
- package/dist/validation/opening-bounds.d.ts +36 -0
- package/dist/validation/opening-bounds.d.ts.map +1 -0
- package/dist/validation/opening-bounds.js +34 -0
- package/dist/validation/validate-build-json.d.ts +2 -0
- package/dist/validation/validate-build-json.d.ts.map +1 -1
- package/dist/validation/validate-build-json.js +48 -1
- package/package.json +37 -4
- package/dist/services/surface-hosting-procedural-parity.fixtures.d.ts +0 -13
- package/dist/services/surface-hosting-procedural-parity.fixtures.d.ts.map +0 -1
- package/dist/services/surface-hosting-procedural-parity.fixtures.js +0 -4691
- package/dist/services/surface-hosting-shelf-parity.fixtures.d.ts +0 -1060
- package/dist/services/surface-hosting-shelf-parity.fixtures.d.ts.map +0 -1
- package/dist/services/surface-hosting-shelf-parity.fixtures.js +0 -3127
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import {
|
|
2
|
+
import { jointReach, partMoves, placeParts, usesPartTree, validatePartTree } from './joints.js';
|
|
3
|
+
import { extrusionTriangles, sectionRings, sectionThickness } from './section.js';
|
|
4
|
+
import { boundsOf, boxCorners, composePoses, eulerPose, frame, hingePose, IDENTITY_POSE, matrixEuler, posePoint, rotateVector, transformPoint, } from './spatial.js';
|
|
3
5
|
const id = z.string().regex(/^[a-z][a-z0-9_]{0,47}$/);
|
|
4
6
|
const finite = z.number().finite().min(-1000).max(1000);
|
|
5
7
|
const expression = z.lazy(() => z.union([
|
|
@@ -10,17 +12,168 @@ const expression = z.lazy(() => z.union([
|
|
|
10
12
|
args: z.array(expression).min(2).max(8),
|
|
11
13
|
}),
|
|
12
14
|
z.strictObject({
|
|
13
|
-
op: z.enum(['floor', 'ceil', 'round', 'abs']),
|
|
15
|
+
op: z.enum(['floor', 'ceil', 'round', 'abs', 'sin', 'cos']),
|
|
14
16
|
args: z.tuple([expression]),
|
|
15
17
|
}),
|
|
16
18
|
z.strictObject({
|
|
17
19
|
op: z.literal('mod'),
|
|
18
20
|
args: z.tuple([expression, expression]),
|
|
19
21
|
}),
|
|
22
|
+
z.strictObject({
|
|
23
|
+
op: z.literal('select'),
|
|
24
|
+
args: z.array(expression).min(2).max(65),
|
|
25
|
+
}),
|
|
20
26
|
]));
|
|
27
|
+
export const ExpressionSchema = expression;
|
|
21
28
|
const vector = z.tuple([expression, expression, expression]);
|
|
22
|
-
|
|
23
|
-
|
|
29
|
+
const sectionRing = z
|
|
30
|
+
.array(z.tuple([expression, expression]))
|
|
31
|
+
.min(3)
|
|
32
|
+
.max(64);
|
|
33
|
+
// An F1 section whose numbers may be expressions; it evaluates to a ResolvedSectionProfile.
|
|
34
|
+
const section = z.discriminatedUnion('kind', [
|
|
35
|
+
z.strictObject({
|
|
36
|
+
kind: z.literal('rectangle'),
|
|
37
|
+
width: expression,
|
|
38
|
+
depth: expression,
|
|
39
|
+
corner: expression.optional(),
|
|
40
|
+
}),
|
|
41
|
+
z.strictObject({ kind: z.literal('round'), radius: expression, wall: expression.optional() }),
|
|
42
|
+
z.strictObject({ kind: z.literal('oval'), width: expression, depth: expression }),
|
|
43
|
+
z.strictObject({
|
|
44
|
+
kind: z.literal('section'),
|
|
45
|
+
family: z.enum(['I', 'C', 'L', 'T', 'Z', 'rect-tube']),
|
|
46
|
+
width: expression,
|
|
47
|
+
depth: expression,
|
|
48
|
+
web: expression,
|
|
49
|
+
flange: expression,
|
|
50
|
+
}),
|
|
51
|
+
z.strictObject({
|
|
52
|
+
kind: z.literal('polygon'),
|
|
53
|
+
outer: sectionRing,
|
|
54
|
+
holes: z.array(sectionRing).max(16).optional(),
|
|
55
|
+
}),
|
|
56
|
+
]);
|
|
57
|
+
const timing = {
|
|
58
|
+
delay: expression.optional(),
|
|
59
|
+
duration: expression.optional(),
|
|
60
|
+
easing: z.enum(['linear', 'smooth', 'soft']).optional(),
|
|
61
|
+
};
|
|
62
|
+
const cutCenter = z.tuple([expression, expression]).optional();
|
|
63
|
+
const cut = z.discriminatedUnion('shape', [
|
|
64
|
+
z.strictObject({
|
|
65
|
+
shape: z.literal('rect'),
|
|
66
|
+
size: z.tuple([expression, expression]),
|
|
67
|
+
center: cutCenter,
|
|
68
|
+
}),
|
|
69
|
+
z.strictObject({ shape: z.literal('circle'), diameter: expression, center: cutCenter }),
|
|
70
|
+
]);
|
|
71
|
+
const motion = z.discriminatedUnion('kind', [
|
|
72
|
+
z.strictObject({
|
|
73
|
+
kind: z.literal('hinge'),
|
|
74
|
+
pivot: vector,
|
|
75
|
+
axis: z.enum(['x', 'y', 'z']),
|
|
76
|
+
angle: expression,
|
|
77
|
+
...timing,
|
|
78
|
+
}),
|
|
79
|
+
z.strictObject({
|
|
80
|
+
kind: z.literal('slide'),
|
|
81
|
+
axis: z.enum(['x', 'y', 'z']),
|
|
82
|
+
distance: expression,
|
|
83
|
+
...timing,
|
|
84
|
+
}),
|
|
85
|
+
z.strictObject({
|
|
86
|
+
kind: z.literal('spin'),
|
|
87
|
+
pivot: vector,
|
|
88
|
+
axis: z.enum(['x', 'y', 'z']),
|
|
89
|
+
radiansPerSecond: expression,
|
|
90
|
+
}),
|
|
91
|
+
]);
|
|
92
|
+
// Version 2 lifts the part caps; triangles (counted as three.js builds them), bytes, repeat
|
|
93
|
+
// counts, expressions and the structural budget bound the rest.
|
|
94
|
+
// Inline v2 designs stay under R7's 24 KiB until pinned definitions (P-05) store larger ones.
|
|
95
|
+
export const RECIPE_V2_LIMITS = {
|
|
96
|
+
parts: 64,
|
|
97
|
+
partShapes: 512,
|
|
98
|
+
shapes: 512,
|
|
99
|
+
bytes: 24 * 1024,
|
|
100
|
+
};
|
|
101
|
+
export const RECIPE_LIMITS = {
|
|
102
|
+
bytes: 131072,
|
|
103
|
+
depth: 24,
|
|
104
|
+
expressions: 50000,
|
|
105
|
+
shapes: 256,
|
|
106
|
+
triangles: 100000,
|
|
107
|
+
dimension: 30,
|
|
108
|
+
motionParts: 8,
|
|
109
|
+
motionGroups: 32,
|
|
110
|
+
lights: 12,
|
|
111
|
+
};
|
|
112
|
+
// Shape keys keep v1's order (id, primitive, slot, size, position, …), so parsed v1 recipes
|
|
113
|
+
// serialize byte for byte as before.
|
|
114
|
+
const shapeTail = {
|
|
115
|
+
support: z.boolean().optional(),
|
|
116
|
+
// v2: the shape is built only where this evaluates to nonzero.
|
|
117
|
+
when: expression.optional(),
|
|
118
|
+
};
|
|
119
|
+
// Sized primitives keep a required size (R1: v1 consumers narrow on primitive and read it).
|
|
120
|
+
const solidShape = z.strictObject({
|
|
121
|
+
id,
|
|
122
|
+
primitive: z.enum(['box', 'roundedBox', 'cylinder', 'ellipsoid']),
|
|
123
|
+
slot: id,
|
|
124
|
+
size: vector,
|
|
125
|
+
position: vector,
|
|
126
|
+
rotation: vector.optional(),
|
|
127
|
+
radius: expression.optional(),
|
|
128
|
+
topScale: expression.optional(),
|
|
129
|
+
// v2 cylinders: side count (absent = 24), no end caps, hollow wall (inner radius as a
|
|
130
|
+
// fraction of the outer), and a partial sweep in radians from local +Z toward +X, closed
|
|
131
|
+
// by flat wedge sides unless open.
|
|
132
|
+
segments: z.number().int().min(3).max(64).optional(),
|
|
133
|
+
open: z.boolean().optional(),
|
|
134
|
+
inner: expression.optional(),
|
|
135
|
+
arc: expression.optional(),
|
|
136
|
+
...shapeTail,
|
|
137
|
+
});
|
|
138
|
+
// v2 extrude: a section in local x/y, extruded along local z by length, centred.
|
|
139
|
+
const extrudeShape = z.strictObject({
|
|
140
|
+
id,
|
|
141
|
+
primitive: z.literal('extrude'),
|
|
142
|
+
slot: id,
|
|
143
|
+
section,
|
|
144
|
+
length: expression,
|
|
145
|
+
bevel: expression.optional(),
|
|
146
|
+
position: vector,
|
|
147
|
+
rotation: vector.optional(),
|
|
148
|
+
...shapeTail,
|
|
149
|
+
});
|
|
150
|
+
// v2 revolve: [radius, height] points turned about local Y (segments and arc as on
|
|
151
|
+
// cylinders); the shape is closed where the profile meets the axis at both ends.
|
|
152
|
+
const revolveShape = z.strictObject({
|
|
153
|
+
id,
|
|
154
|
+
primitive: z.literal('revolve'),
|
|
155
|
+
slot: id,
|
|
156
|
+
profile: z
|
|
157
|
+
.array(z.tuple([expression, expression]))
|
|
158
|
+
.min(2)
|
|
159
|
+
.max(64),
|
|
160
|
+
segments: z.number().int().min(3).max(64).optional(),
|
|
161
|
+
arc: expression.optional(),
|
|
162
|
+
position: vector,
|
|
163
|
+
rotation: vector.optional(),
|
|
164
|
+
...shapeTail,
|
|
165
|
+
});
|
|
166
|
+
/** The sized-primitive fields of a shape (none for an extrude). */
|
|
167
|
+
function solidFields(shape) {
|
|
168
|
+
if (shape.primitive === 'extrude')
|
|
169
|
+
return {};
|
|
170
|
+
if (shape.primitive === 'revolve')
|
|
171
|
+
return { segments: shape.segments, arc: shape.arc };
|
|
172
|
+
return shape;
|
|
173
|
+
}
|
|
174
|
+
const RecipeObject = z.strictObject({
|
|
175
|
+
// Version 2 marks content that older readers cannot evaluate; v2-only fields require it.
|
|
176
|
+
version: z.union([z.literal(1), z.literal(2)]),
|
|
24
177
|
name: z.string().min(1).max(100),
|
|
25
178
|
description: z.string().max(600),
|
|
26
179
|
classification: z
|
|
@@ -33,6 +186,11 @@ export const RecipeSchema = z.strictObject({
|
|
|
33
186
|
mounting: z
|
|
34
187
|
.strictObject({ attachTo: z.enum(['wall-side', 'ceiling']), reference: id })
|
|
35
188
|
.optional(),
|
|
189
|
+
// v2, floor designs: the design-space height that rests on the host floor.
|
|
190
|
+
base: expression.optional(),
|
|
191
|
+
// v2, ceiling designs: an opening in the host ceiling, drawn in the mounting reference's x/z
|
|
192
|
+
// plane around it. The design may rise above the reference only inside its cut.
|
|
193
|
+
cuts: z.array(cut).min(1).max(1).optional(),
|
|
36
194
|
surfaces: z
|
|
37
195
|
.array(z.strictObject({
|
|
38
196
|
id,
|
|
@@ -52,7 +210,9 @@ export const RecipeSchema = z.strictObject({
|
|
|
52
210
|
min: finite,
|
|
53
211
|
max: finite,
|
|
54
212
|
step: z.number().positive().max(100),
|
|
55
|
-
|
|
213
|
+
// v2: 'bool' is 0 | 1; 'choice' is an index into `options`.
|
|
214
|
+
unit: z.enum(['m', 'count', 'rad', 's', 'bool', 'choice']),
|
|
215
|
+
options: z.array(z.string().min(1).max(60)).min(2).max(16).optional(),
|
|
56
216
|
part: id.optional(),
|
|
57
217
|
axis: z.enum(['x', 'y', 'z']).optional(),
|
|
58
218
|
}))
|
|
@@ -72,22 +232,45 @@ export const RecipeSchema = z.strictObject({
|
|
|
72
232
|
id,
|
|
73
233
|
label: z.string().min(1).max(60),
|
|
74
234
|
count: expression,
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
235
|
+
// v2 part tree: the part moves with `parent` (repeating once, or exactly as often,
|
|
236
|
+
// bound by index) and its shapes, light and joint are authored in `frame`.
|
|
237
|
+
parent: id.optional(),
|
|
238
|
+
frame: z.strictObject({ position: vector, rotation: vector.optional() }).optional(),
|
|
239
|
+
// v2: a repeat is built only where this evaluates to nonzero.
|
|
240
|
+
when: expression.optional(),
|
|
241
|
+
motion: motion.optional(),
|
|
242
|
+
light: z
|
|
243
|
+
.strictObject({
|
|
81
244
|
position: vector,
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
245
|
+
color: z.string().regex(/^#[0-9a-fA-F]{6}$/),
|
|
246
|
+
intensity: z.number().finite().gt(0).max(10).optional(),
|
|
247
|
+
distance: z.number().finite().min(0.1).max(10).optional(),
|
|
248
|
+
emissiveSlot: id.optional(),
|
|
249
|
+
})
|
|
250
|
+
.optional(),
|
|
251
|
+
shapes: z
|
|
252
|
+
.array(z.discriminatedUnion('primitive', [solidShape, extrudeShape, revolveShape]))
|
|
86
253
|
.min(1)
|
|
87
|
-
.max(
|
|
254
|
+
.max(RECIPE_V2_LIMITS.partShapes),
|
|
88
255
|
}))
|
|
89
256
|
.min(1)
|
|
90
|
-
.max(
|
|
257
|
+
.max(RECIPE_V2_LIMITS.parts),
|
|
258
|
+
// v2: at most one joint per part, keyed by the child part; origin and axis are in the part's
|
|
259
|
+
// frame. Values are radians (revolute, continuous speed per second) or metres (prismatic).
|
|
260
|
+
joints: z
|
|
261
|
+
.array(z.strictObject({
|
|
262
|
+
child: id,
|
|
263
|
+
kind: z.enum(['fixed', 'revolute', 'continuous', 'prismatic']),
|
|
264
|
+
origin: vector,
|
|
265
|
+
axis: vector,
|
|
266
|
+
open: expression.optional(),
|
|
267
|
+
rest: expression.optional(),
|
|
268
|
+
range: z.tuple([expression, expression]).optional(),
|
|
269
|
+
speed: expression.optional(),
|
|
270
|
+
...timing,
|
|
271
|
+
}))
|
|
272
|
+
.max(64)
|
|
273
|
+
.optional(),
|
|
91
274
|
constraints: z
|
|
92
275
|
.array(z.strictObject({
|
|
93
276
|
left: expression,
|
|
@@ -97,14 +280,11 @@ export const RecipeSchema = z.strictObject({
|
|
|
97
280
|
}))
|
|
98
281
|
.max(24),
|
|
99
282
|
});
|
|
100
|
-
export const
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
triangles: 100000,
|
|
106
|
-
dimension: 30,
|
|
107
|
-
};
|
|
283
|
+
export const RecipeSchema = RecipeObject.superRefine((recipe, ctx) => {
|
|
284
|
+
const issue = versionIssue(recipe);
|
|
285
|
+
if (issue)
|
|
286
|
+
ctx.addIssue({ code: 'custom', message: issue });
|
|
287
|
+
});
|
|
108
288
|
function guardTree(value, depth = 0, budget = { count: 0 }) {
|
|
109
289
|
if (++budget.count > 12000 || depth > RECIPE_LIMITS.depth)
|
|
110
290
|
throw new Error('Recipe exceeds structural budget');
|
|
@@ -116,11 +296,75 @@ function guardTree(value, depth = 0, budget = { count: 0 }) {
|
|
|
116
296
|
}
|
|
117
297
|
}
|
|
118
298
|
}
|
|
299
|
+
function movingParts(recipe) {
|
|
300
|
+
return (recipe.parts.filter((part) => part.motion).length +
|
|
301
|
+
(recipe.joints ?? []).filter((joint) => joint.kind !== 'fixed').length);
|
|
302
|
+
}
|
|
303
|
+
function findV2Feature(recipe) {
|
|
304
|
+
for (const primitive of ['extrude', 'revolve'])
|
|
305
|
+
if (recipe.parts.some((part) => part.shapes.some((shape) => shape.primitive === primitive)))
|
|
306
|
+
return primitive;
|
|
307
|
+
if (recipe.parts.some((part) => part.shapes.some((shape) => [
|
|
308
|
+
solidFields(shape).segments,
|
|
309
|
+
solidFields(shape).open,
|
|
310
|
+
solidFields(shape).inner,
|
|
311
|
+
solidFields(shape).arc,
|
|
312
|
+
].some((v) => v !== undefined))))
|
|
313
|
+
return 'Cylinder segments, open, inner and arc';
|
|
314
|
+
if (usesPartTree(recipe))
|
|
315
|
+
return 'Part trees and joints';
|
|
316
|
+
if (recipe.parameters.some((p) => p.unit === 'bool' || p.unit === 'choice' || p.options))
|
|
317
|
+
return 'Bool and choice parameters';
|
|
318
|
+
if (recipe.parts.some((part) => part.when !== undefined || part.shapes.some((s) => s.when !== undefined)))
|
|
319
|
+
return 'when';
|
|
320
|
+
const selects = (value) => Array.isArray(value)
|
|
321
|
+
? value.some(selects)
|
|
322
|
+
: Boolean(value && typeof value === 'object') &&
|
|
323
|
+
(value.op === 'select' ||
|
|
324
|
+
Object.values(value).some(selects));
|
|
325
|
+
return selects(recipe) ? 'select' : null;
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Version rules the exported schema, parseRecipe and evaluateRecipe all enforce: content
|
|
329
|
+
* only a v2 reader understands must say `version: 2`.
|
|
330
|
+
*/
|
|
331
|
+
function versionIssue(recipe) {
|
|
332
|
+
if (recipe.base !== undefined) {
|
|
333
|
+
if (recipe.version !== 2)
|
|
334
|
+
return 'A declared base requires recipe version 2';
|
|
335
|
+
if (recipe.mounting)
|
|
336
|
+
return 'A declared base applies to floor designs; mounted designs use their reference';
|
|
337
|
+
}
|
|
338
|
+
if (recipe.version === 1) {
|
|
339
|
+
const feature = findV2Feature(recipe);
|
|
340
|
+
if (feature)
|
|
341
|
+
return `${feature} requires recipe version 2`;
|
|
342
|
+
}
|
|
343
|
+
if (recipe.version === 1 && recipe.parts.length > 16)
|
|
344
|
+
return 'More than 16 parts requires recipe version 2';
|
|
345
|
+
if (recipe.version === 1 && recipe.parts.some((part) => part.shapes.length > 24))
|
|
346
|
+
return 'More than 24 shapes in a part requires recipe version 2';
|
|
347
|
+
if (recipe.version === 2 && recipeBytes(recipe) > RECIPE_V2_LIMITS.bytes)
|
|
348
|
+
return 'A version 2 recipe above 24 KiB needs a pinned definition (P-05); keep it inline under 24 KiB';
|
|
349
|
+
if (recipe.cuts !== undefined) {
|
|
350
|
+
if (recipe.version !== 2)
|
|
351
|
+
return 'Cuts require recipe version 2';
|
|
352
|
+
if (recipe.mounting?.attachTo !== 'ceiling')
|
|
353
|
+
return 'Cuts need a ceiling-mounted design';
|
|
354
|
+
}
|
|
355
|
+
return null;
|
|
356
|
+
}
|
|
357
|
+
/** UTF-8 bytes of a recipe's compact JSON: what every inline size cap measures. */
|
|
358
|
+
export function recipeBytes(recipe) {
|
|
359
|
+
return new TextEncoder().encode(JSON.stringify(recipe)).length;
|
|
360
|
+
}
|
|
119
361
|
export function parseRecipe(input) {
|
|
120
362
|
guardTree(input);
|
|
121
363
|
if (JSON.stringify(input).length > RECIPE_LIMITS.bytes)
|
|
122
364
|
throw new Error('Recipe is too large');
|
|
123
365
|
const recipe = RecipeSchema.parse(input);
|
|
366
|
+
if (usesPartTree(recipe))
|
|
367
|
+
validatePartTree(recipe);
|
|
124
368
|
for (const list of [recipe.parameters, recipe.slots, recipe.parts]) {
|
|
125
369
|
if (new Set(list.map((x) => x.id)).size !== list.length)
|
|
126
370
|
throw new Error('IDs must be unique within each section');
|
|
@@ -130,22 +374,53 @@ export function parseRecipe(input) {
|
|
|
130
374
|
throw new Error(`Invalid parameter ${p.id}`);
|
|
131
375
|
if (p.unit === 'count' && ![p.min, p.max, p.default, p.step].every(Number.isInteger))
|
|
132
376
|
throw new Error(`Count ${p.id} must be integral`);
|
|
377
|
+
if ((p.unit === 'bool' || p.unit === 'choice') &&
|
|
378
|
+
(p.min !== 0 ||
|
|
379
|
+
p.step !== 1 ||
|
|
380
|
+
p.axis ||
|
|
381
|
+
!Number.isInteger(p.default) ||
|
|
382
|
+
p.max !== (p.unit === 'bool' ? 1 : (p.options?.length ?? 0) - 1)))
|
|
383
|
+
throw new Error(`${p.unit === 'bool' ? 'Bool' : 'Choice'} ${p.id} must run 0..${p.unit === 'bool' ? 1 : 'options - 1'} in steps of 1 with no handle`);
|
|
384
|
+
if (p.options && p.unit !== 'choice')
|
|
385
|
+
throw new Error(`Only choice parameters have options (${p.id})`);
|
|
133
386
|
if (p.part && !recipe.parts.some((part) => part.id === p.part))
|
|
134
387
|
throw new Error(`Unknown part ${p.part}`);
|
|
135
388
|
}
|
|
136
389
|
for (const part of recipe.parts) {
|
|
137
390
|
if (new Set(part.shapes.map((s) => s.id)).size !== part.shapes.length)
|
|
138
391
|
throw new Error(`Duplicate shape in ${part.id}`);
|
|
139
|
-
for (const shape of part.shapes)
|
|
392
|
+
for (const shape of part.shapes) {
|
|
140
393
|
if (!recipe.slots.some((s) => s.id === shape.slot))
|
|
141
394
|
throw new Error(`Unknown slot ${shape.slot}`);
|
|
395
|
+
const f = solidFields(shape);
|
|
396
|
+
if (f.topScale !== undefined && shape.primitive !== 'cylinder')
|
|
397
|
+
throw new Error(`topScale is only allowed on cylinders (${part.id}/${shape.id})`);
|
|
398
|
+
if ((shape.primitive === 'extrude' || shape.primitive === 'revolve') && shape.support)
|
|
399
|
+
throw new Error(`${shape.primitive} ${part.id}/${shape.id} cannot be a support surface`);
|
|
400
|
+
const cylinderOptions = [f.segments, f.open, f.inner, f.arc];
|
|
401
|
+
if (cylinderOptions.some((option) => option !== undefined)) {
|
|
402
|
+
if (shape.primitive !== 'cylinder' && shape.primitive !== 'revolve')
|
|
403
|
+
throw new Error(`segments, open, inner and arc apply to cylinders (${part.id}/${shape.id})`);
|
|
404
|
+
if (shape.support && (f.inner !== undefined || f.arc !== undefined || f.open))
|
|
405
|
+
throw new Error(`Support shape ${part.id}/${shape.id} cannot be hollow, open or partial`);
|
|
406
|
+
}
|
|
407
|
+
if (shape.support && partMoves(recipe, part.id))
|
|
408
|
+
throw new Error(`Moving part ${part.id} cannot contain support shapes`);
|
|
409
|
+
if (shape.primitive === 'ellipsoid' && shape.support)
|
|
410
|
+
throw new Error(`Ellipsoid ${part.id}/${shape.id} cannot be a support surface`);
|
|
411
|
+
}
|
|
142
412
|
}
|
|
413
|
+
if (movingParts(recipe) > RECIPE_LIMITS.motionParts)
|
|
414
|
+
throw new Error(`Recipe exceeds ${RECIPE_LIMITS.motionParts} moving parts`);
|
|
143
415
|
const surfaceIds = (recipe.surfaces ?? []).map((s) => s.id);
|
|
144
416
|
if (new Set(surfaceIds).size !== surfaceIds.length)
|
|
145
417
|
throw new Error('Duplicate surface ID');
|
|
146
|
-
for (const surface of recipe.surfaces ?? [])
|
|
418
|
+
for (const surface of recipe.surfaces ?? []) {
|
|
147
419
|
if (surface.part && !recipe.parts.some((p) => p.id === surface.part))
|
|
148
420
|
throw new Error('Unknown surface part');
|
|
421
|
+
if (surface.part && partMoves(recipe, surface.part))
|
|
422
|
+
throw new Error(`Named surface ${surface.id} cannot belong to moving part ${surface.part}`);
|
|
423
|
+
}
|
|
149
424
|
if (recipe.mounting &&
|
|
150
425
|
!(recipe.surfaces ?? []).some((s) => s.id === recipe.mounting.reference && !s.part))
|
|
151
426
|
throw new Error('Mounting requires one named, non-repeated reference surface');
|
|
@@ -155,7 +430,197 @@ export function parseRecipe(input) {
|
|
|
155
430
|
evaluateRecipe(recipe);
|
|
156
431
|
return recipe;
|
|
157
432
|
}
|
|
433
|
+
function shapeCorners(size, position, rotation) {
|
|
434
|
+
const localMin = size.map((v) => -v / 2);
|
|
435
|
+
const localMax = size.map((v) => v / 2);
|
|
436
|
+
const shapeFrame = frame(position, rotation);
|
|
437
|
+
return boxCorners(localMin, localMax).map((point) => transformPoint(shapeFrame, point));
|
|
438
|
+
}
|
|
439
|
+
/** Axis-aligned bounds of one evaluated shape in the design frame. */
|
|
440
|
+
export function shapeBounds(shape) {
|
|
441
|
+
if (shape.primitive !== 'ellipsoid')
|
|
442
|
+
return boundsOf(shapeCorners(shape.size, shape.position, shape.rotation));
|
|
443
|
+
const axes = [0, 1, 2].map((axis) => rotateVector([0, 1, 2].map((j) => (j === axis ? 1 : 0)), shape.rotation));
|
|
444
|
+
const extent = [0, 1, 2].map((k) => Math.hypot(...axes.map((axis, j) => (axis[k] * shape.size[j]) / 2)));
|
|
445
|
+
return boundsOf([
|
|
446
|
+
shape.position.map((v, k) => v - extent[k]),
|
|
447
|
+
shape.position.map((v, k) => v + extent[k]),
|
|
448
|
+
]);
|
|
449
|
+
}
|
|
450
|
+
// Points whose hull contains the shape: a cylinder's rim vertices (as rendered), otherwise the
|
|
451
|
+
// corners of its oriented box (exact for boxes, conservative for the rest).
|
|
452
|
+
function shapeFootprint(shape) {
|
|
453
|
+
if (shape.primitive === 'revolve') {
|
|
454
|
+
// Each profile point's ring as rendered, along the arc.
|
|
455
|
+
const f = frame(shape.position, shape.rotation);
|
|
456
|
+
const n = shape.segments ?? 24, arc = shape.arc ?? 2 * Math.PI;
|
|
457
|
+
const steps = arc < 2 * Math.PI - 1e-9 ? n + 1 : n;
|
|
458
|
+
return shape.profile.flatMap(([r, y]) => Array.from({ length: steps }, (_, k) => {
|
|
459
|
+
const theta = (arc * k) / n;
|
|
460
|
+
return transformPoint(f, [r * Math.sin(theta), y, r * Math.cos(theta)]);
|
|
461
|
+
}));
|
|
462
|
+
}
|
|
463
|
+
if (shape.primitive !== 'cylinder')
|
|
464
|
+
return shapeCorners(shape.size, shape.position, shape.rotation);
|
|
465
|
+
const f = frame(shape.position, shape.rotation);
|
|
466
|
+
const n = shape.segments ?? 24, arc = shape.arc ?? 2 * Math.PI;
|
|
467
|
+
const partial = arc < 2 * Math.PI - 1e-9;
|
|
468
|
+
// Rim vertices as rendered, along the arc; a hollow arc adds its inner rim; a closed
|
|
469
|
+
// partial solid (wedge sides through the axis) adds the axis.
|
|
470
|
+
const rims = shape.inner === undefined ? [1] : [1, shape.inner];
|
|
471
|
+
return [-0.5, 0.5].flatMap((y) => {
|
|
472
|
+
const r = y > 0 ? 0.5 * shape.topScale : 0.5;
|
|
473
|
+
const points = rims.flatMap((scale) => Array.from({ length: partial ? n + 1 : n }, (_, k) => {
|
|
474
|
+
const theta = (arc * k) / n;
|
|
475
|
+
return transformPoint(f, [
|
|
476
|
+
scale * r * Math.sin(theta) * shape.size[0],
|
|
477
|
+
y * shape.size[1],
|
|
478
|
+
scale * r * Math.cos(theta) * shape.size[2],
|
|
479
|
+
]);
|
|
480
|
+
}));
|
|
481
|
+
return partial && shape.inner === undefined && !shape.open
|
|
482
|
+
? [...points, transformPoint(f, [0, y * shape.size[1], 0])]
|
|
483
|
+
: points;
|
|
484
|
+
});
|
|
485
|
+
}
|
|
486
|
+
/** Where a flat motion has carried its group at `fraction` of its travel. */
|
|
487
|
+
function motionPose(motion, fraction) {
|
|
488
|
+
const axis = [0, 1, 2].map((k) => (['x', 'y', 'z'][k] === motion.axis ? 1 : 0));
|
|
489
|
+
if (motion.kind === 'slide')
|
|
490
|
+
return { r: IDENTITY_POSE.r, t: axis.map((v) => v * motion.amount * fraction) };
|
|
491
|
+
const angle = motion.kind === 'spin' ? 2 * Math.PI * fraction : motion.amount * fraction;
|
|
492
|
+
return hingePose(motion.pivot, axis, angle);
|
|
493
|
+
}
|
|
494
|
+
const LEGACY_TRIANGLE_CHARGE = { box: 12, roundedBox: 588, cylinder: 96, ellipsoid: 720 };
|
|
495
|
+
/** A revolve that meets the axis at both ends over a full turn encloses a solid. */
|
|
496
|
+
export function revolveIsClosed(shape) {
|
|
497
|
+
const profile = shape.profile;
|
|
498
|
+
return (profile[0][0] <= 1e-9 &&
|
|
499
|
+
profile.at(-1)[0] <= 1e-9 &&
|
|
500
|
+
(shape.arc === undefined || shape.arc >= 2 * Math.PI - 1e-9));
|
|
501
|
+
}
|
|
502
|
+
/** Triangles of the geometry the renderer builds for an evaluated shape (non-indexed). */
|
|
503
|
+
export function shapeTriangles(shape) {
|
|
504
|
+
switch (shape.primitive) {
|
|
505
|
+
case 'box':
|
|
506
|
+
return 12;
|
|
507
|
+
case 'roundedBox':
|
|
508
|
+
return 300; // RoundedBoxGeometry(…, 2): a 5 × 5 grid on each face
|
|
509
|
+
case 'cylinder': {
|
|
510
|
+
// Per side: one torso triangle per nonzero radius, one cap triangle per nonzero radius
|
|
511
|
+
// (two for a tube's ring), plus two triangles per wedge side of a closed partial sweep.
|
|
512
|
+
const n = shape.segments ?? 24, ends = shape.topScale > 0 ? 2 : 1;
|
|
513
|
+
const wedges = shape.arc !== undefined && shape.arc < 2 * Math.PI - 1e-9 && !shape.open;
|
|
514
|
+
// A hollow wall draws its inner face; an open solid draws its back face instead, since
|
|
515
|
+
// materials are front-sided.
|
|
516
|
+
const walls = shape.inner !== undefined || shape.open ? 2 : 1;
|
|
517
|
+
const caps = shape.open ? 0 : (shape.inner === undefined ? 1 : 2) * n * ends;
|
|
518
|
+
return walls * n * ends + caps + (wedges ? 4 : 0);
|
|
519
|
+
}
|
|
520
|
+
case 'ellipsoid':
|
|
521
|
+
return 720; // SphereGeometry(…, 24, 16) without the degenerate pole triangles
|
|
522
|
+
case 'extrude':
|
|
523
|
+
return extrusionTriangles(sectionRings(shape.section), shape.bevel ? 2 : 0);
|
|
524
|
+
case 'revolve': {
|
|
525
|
+
// LatheGeometry: two per segment per profile edge; an open surface also draws its back.
|
|
526
|
+
const n = shape.segments ?? 24, profile = shape.profile;
|
|
527
|
+
return 2 * n * (profile.length - 1) * (revolveIsClosed(shape) ? 1 : 2);
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
/**
|
|
532
|
+
* Triangles a shape charges against the recipe budget: v1 keeps its original, conservative
|
|
533
|
+
* charges so its acceptance never changes; v2 charges what the renderer builds.
|
|
534
|
+
*/
|
|
535
|
+
export function triangleCharge(recipe, shape, built = shapeTriangles(shape)) {
|
|
536
|
+
return recipe.version === 1
|
|
537
|
+
? LEGACY_TRIANGLE_CHARGE[shape.primitive]
|
|
538
|
+
: built;
|
|
539
|
+
}
|
|
540
|
+
function resolveSection(section, value) {
|
|
541
|
+
const length = (e, what) => {
|
|
542
|
+
const v = value(e);
|
|
543
|
+
if (!(v >= 0.001 && v <= RECIPE_LIMITS.dimension))
|
|
544
|
+
throw new Error(`Invalid section ${what}`);
|
|
545
|
+
return v;
|
|
546
|
+
};
|
|
547
|
+
switch (section.kind) {
|
|
548
|
+
case 'rectangle': {
|
|
549
|
+
const width = length(section.width, 'width'), depth = length(section.depth, 'depth');
|
|
550
|
+
const corner = section.corner === undefined ? 0 : value(section.corner);
|
|
551
|
+
if (!(corner >= 0 && corner <= Math.min(width, depth) / 2))
|
|
552
|
+
throw new Error('A section corner must be within 0..half its smaller side');
|
|
553
|
+
return corner
|
|
554
|
+
? { kind: 'rectangle', width, depth, corner }
|
|
555
|
+
: { kind: 'rectangle', width, depth };
|
|
556
|
+
}
|
|
557
|
+
case 'round': {
|
|
558
|
+
const radius = length(section.radius, 'radius');
|
|
559
|
+
const wall = section.wall === undefined ? undefined : value(section.wall);
|
|
560
|
+
if (wall !== undefined && !(wall > 0 && wall < radius))
|
|
561
|
+
throw new Error('A round section wall must be within (0, radius)');
|
|
562
|
+
return wall === undefined ? { kind: 'round', radius } : { kind: 'round', radius, wall };
|
|
563
|
+
}
|
|
564
|
+
case 'oval':
|
|
565
|
+
return {
|
|
566
|
+
kind: 'oval',
|
|
567
|
+
width: length(section.width, 'width'),
|
|
568
|
+
depth: length(section.depth, 'depth'),
|
|
569
|
+
};
|
|
570
|
+
case 'section':
|
|
571
|
+
return {
|
|
572
|
+
kind: 'section',
|
|
573
|
+
family: section.family,
|
|
574
|
+
width: length(section.width, 'width'),
|
|
575
|
+
depth: length(section.depth, 'depth'),
|
|
576
|
+
web: length(section.web, 'web'),
|
|
577
|
+
flange: length(section.flange, 'flange'),
|
|
578
|
+
};
|
|
579
|
+
case 'polygon': {
|
|
580
|
+
const point = ([x, y]) => {
|
|
581
|
+
const p = [value(x), value(y)];
|
|
582
|
+
if (p.some((v) => Math.abs(v) > RECIPE_LIMITS.dimension))
|
|
583
|
+
throw new Error('Invalid section point');
|
|
584
|
+
return p;
|
|
585
|
+
};
|
|
586
|
+
return {
|
|
587
|
+
kind: 'polygon',
|
|
588
|
+
outer: section.outer.map(point),
|
|
589
|
+
...(section.holes && { holes: section.holes.map((hole) => hole.map(point)) }),
|
|
590
|
+
};
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
}
|
|
158
594
|
export function evaluateRecipe(recipe, values = {}) {
|
|
595
|
+
const issue = versionIssue(recipe);
|
|
596
|
+
if (issue)
|
|
597
|
+
throw new Error(issue);
|
|
598
|
+
const slotColors = new Map();
|
|
599
|
+
for (const part of recipe.parts) {
|
|
600
|
+
const light = part.light;
|
|
601
|
+
if (!light)
|
|
602
|
+
continue;
|
|
603
|
+
if (!/^#[0-9a-fA-F]{6}$/.test(light.color) ||
|
|
604
|
+
(light.intensity !== undefined &&
|
|
605
|
+
(!Number.isFinite(light.intensity) || light.intensity <= 0 || light.intensity > 10)) ||
|
|
606
|
+
(light.distance !== undefined &&
|
|
607
|
+
(!Number.isFinite(light.distance) || light.distance < 0.1 || light.distance > 10)))
|
|
608
|
+
throw new Error(`Invalid light for ${part.id}`);
|
|
609
|
+
if (!light.emissiveSlot)
|
|
610
|
+
continue;
|
|
611
|
+
if (!recipe.slots.some((slot) => slot.id === light.emissiveSlot))
|
|
612
|
+
throw new Error(`Unknown emissive slot ${light.emissiveSlot}`);
|
|
613
|
+
const previous = slotColors.get(light.emissiveSlot);
|
|
614
|
+
// v2 checks the lights it actually builds (below), so exclusive variants may differ.
|
|
615
|
+
if (recipe.version === 1 && previous && previous !== light.color.toLowerCase())
|
|
616
|
+
throw new Error(`Conflicting light colors on ${light.emissiveSlot}`);
|
|
617
|
+
slotColors.set(light.emissiveSlot, light.color.toLowerCase());
|
|
618
|
+
}
|
|
619
|
+
if (movingParts(recipe) > RECIPE_LIMITS.motionParts)
|
|
620
|
+
throw new Error(`Recipe exceeds ${RECIPE_LIMITS.motionParts} moving parts`);
|
|
621
|
+
for (const surface of recipe.surfaces ?? [])
|
|
622
|
+
if (surface.part && partMoves(recipe, surface.part))
|
|
623
|
+
throw new Error(`Named surface ${surface.id} cannot belong to moving part ${surface.part}`);
|
|
159
624
|
const parameters = Object.create(null);
|
|
160
625
|
for (const key of Object.keys(values))
|
|
161
626
|
if (!recipe.parameters.some((p) => p.id === key))
|
|
@@ -165,7 +630,7 @@ export function evaluateRecipe(recipe, values = {}) {
|
|
|
165
630
|
if (!Number.isFinite(v) ||
|
|
166
631
|
v < p.min ||
|
|
167
632
|
v > p.max ||
|
|
168
|
-
(p.unit === 'count' && !Number.isInteger(v)))
|
|
633
|
+
((p.unit === 'count' || p.unit === 'bool' || p.unit === 'choice') && !Number.isInteger(v)))
|
|
169
634
|
throw new Error(`${p.label} must be between ${p.min} and ${p.max}`);
|
|
170
635
|
parameters[p.id] = v;
|
|
171
636
|
}
|
|
@@ -182,6 +647,12 @@ export function evaluateRecipe(recipe, values = {}) {
|
|
|
182
647
|
throw new Error(`Unknown expression reference ${e}`);
|
|
183
648
|
return parameters[e];
|
|
184
649
|
}
|
|
650
|
+
if (e.op === 'select') {
|
|
651
|
+
const i = expr(e.args[0], index, depth + 1);
|
|
652
|
+
if (!Number.isInteger(i) || i < 0 || i >= e.args.length - 1)
|
|
653
|
+
throw new Error(`select index ${i} is outside 0..${e.args.length - 2}`);
|
|
654
|
+
return expr(e.args[i + 1], index, depth + 1);
|
|
655
|
+
}
|
|
185
656
|
const a = e.args.map((x) => expr(x, index, depth + 1));
|
|
186
657
|
let result;
|
|
187
658
|
switch (e.op) {
|
|
@@ -209,6 +680,12 @@ export function evaluateRecipe(recipe, values = {}) {
|
|
|
209
680
|
case 'abs':
|
|
210
681
|
result = Math.abs(a[0]);
|
|
211
682
|
break;
|
|
683
|
+
case 'sin':
|
|
684
|
+
result = Math.sin(a[0]);
|
|
685
|
+
break;
|
|
686
|
+
case 'cos':
|
|
687
|
+
result = Math.cos(a[0]);
|
|
688
|
+
break;
|
|
212
689
|
case 'mod': {
|
|
213
690
|
const divisor = a[1];
|
|
214
691
|
if (divisor <= 0)
|
|
@@ -235,24 +712,200 @@ export function evaluateRecipe(recipe, values = {}) {
|
|
|
235
712
|
if (c.relation === 'lte' ? a > b + 1e-8 : a < b - 1e-8)
|
|
236
713
|
throw new Error(c.message);
|
|
237
714
|
}
|
|
238
|
-
|
|
715
|
+
// The datum that rests on the host: design y = 0, or a v2 floor design's declared base.
|
|
716
|
+
// v2 ceiling designs hang from their top reference; their host bounds them against the floor.
|
|
717
|
+
const base = recipe.version === 2 && recipe.base !== undefined ? expr(recipe.base) : 0;
|
|
718
|
+
const hangsFromCeiling = recipe.version === 2 && recipe.mounting?.attachTo === 'ceiling';
|
|
719
|
+
const shapes = [], motions = [], lights = [], surfaces = [];
|
|
720
|
+
const motionGroupByInstance = Object.create(null);
|
|
721
|
+
const motionSignatures = new Map();
|
|
239
722
|
const min = [Infinity, Infinity, Infinity], max = [-Infinity, -Infinity, -Infinity];
|
|
240
|
-
let triangles = 0;
|
|
723
|
+
let triangles = 0, charged = 0;
|
|
724
|
+
const shapeLimit = recipe.version === 2 ? RECIPE_V2_LIMITS.shapes : RECIPE_LIMITS.shapes;
|
|
725
|
+
// Counts are settled before anything is expanded, so a huge count costs one expression.
|
|
726
|
+
const counts = new Map();
|
|
241
727
|
for (const part of recipe.parts) {
|
|
242
728
|
const count = expr(part.count);
|
|
243
729
|
if (!Number.isInteger(count) || count < 0 || count > 64)
|
|
244
730
|
throw new Error(`Invalid repeat count for ${part.label}`);
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
731
|
+
counts.set(part.id, count);
|
|
732
|
+
}
|
|
733
|
+
const placements = recipe.version === 2 && usesPartTree(recipe) ? placeParts(recipe, expr, counts) : null;
|
|
734
|
+
const jointGroups = new Set();
|
|
735
|
+
// Part repeats that built geometry; only these carry the part's named surfaces.
|
|
736
|
+
const builtRepeats = new Set();
|
|
737
|
+
for (const part of recipe.parts) {
|
|
738
|
+
const count = counts.get(part.id);
|
|
739
|
+
for (let i = 0; i < count; i++) {
|
|
740
|
+
if (part.when !== undefined && expr(part.when, i) === 0)
|
|
741
|
+
continue;
|
|
742
|
+
const placement = placements?.get(`${part.id}:${i}`);
|
|
743
|
+
if (placements && !placement)
|
|
744
|
+
continue;
|
|
745
|
+
// A joint is kept even where `when` skips all its part's shapes, since its children
|
|
746
|
+
// still ride it; joints that end up carrying nothing are dropped after the loop.
|
|
747
|
+
if (placement?.motion) {
|
|
748
|
+
if (motions.length >= RECIPE_LIMITS.motionGroups)
|
|
749
|
+
throw new Error(`Recipe exceeds ${RECIPE_LIMITS.motionGroups} evaluated motion groups`);
|
|
750
|
+
motions.push(placement.motion);
|
|
751
|
+
jointGroups.add(placement.motion.id);
|
|
752
|
+
motionGroupByInstance[`${part.id}:${i}`] = placement.motion.id;
|
|
753
|
+
}
|
|
754
|
+
const kept = part.shapes.filter((s) => s.when === undefined || expr(s.when, i) !== 0);
|
|
755
|
+
if (!kept.length)
|
|
756
|
+
continue;
|
|
757
|
+
builtRepeats.add(`${part.id}:${i}`);
|
|
758
|
+
// A part-tree pose re-expresses the part's frame in design space.
|
|
759
|
+
const pose = placement?.pose ?? IDENTITY_POSE;
|
|
760
|
+
const place = (position, rotation) => {
|
|
761
|
+
if (pose === IDENTITY_POSE)
|
|
762
|
+
return { position, rotation };
|
|
763
|
+
const placed = composePoses(pose, eulerPose(position, rotation));
|
|
764
|
+
return { position: placed.t, rotation: matrixEuler(placed.r) };
|
|
765
|
+
};
|
|
766
|
+
const vec = (v) => v.map((x) => expr(x, i));
|
|
767
|
+
const instanceMin = [Infinity, Infinity, Infinity];
|
|
768
|
+
const instanceMax = [-Infinity, -Infinity, -Infinity];
|
|
769
|
+
let motionGroup = placement?.group;
|
|
770
|
+
if (part.motion) {
|
|
771
|
+
const motion = part.motion;
|
|
772
|
+
const pivot = motion.kind === 'slide' ? [0, 0, 0] : vec(motion.pivot);
|
|
773
|
+
const amount = expr(motion.kind === 'hinge'
|
|
774
|
+
? motion.angle
|
|
775
|
+
: motion.kind === 'slide'
|
|
776
|
+
? motion.distance
|
|
777
|
+
: motion.radiansPerSecond, i);
|
|
778
|
+
const limit = motion.kind === 'hinge' ? Math.PI : motion.kind === 'slide' ? 5 : 20;
|
|
779
|
+
if (Math.abs(amount) <= 0 || Math.abs(amount) > limit)
|
|
780
|
+
throw new Error(`Invalid ${motion.kind} amount for ${part.id}: expected 0 < absolute value <= ${limit}`);
|
|
781
|
+
const rounded = (n) => Math.round(n * 1e6) / 1e6;
|
|
782
|
+
const delay = motion.kind === 'spin' ? 0 : expr(motion.delay ?? 0, i);
|
|
783
|
+
const duration = motion.kind === 'spin' ? 0 : expr(motion.duration ?? 0.45, i);
|
|
784
|
+
const easing = motion.kind === 'spin' ? 'linear' : (motion.easing ?? 'smooth');
|
|
785
|
+
if (!Number.isFinite(delay) ||
|
|
786
|
+
!Number.isFinite(duration) ||
|
|
787
|
+
delay < 0 ||
|
|
788
|
+
delay > 1 ||
|
|
789
|
+
!['linear', 'smooth', 'soft'].includes(easing) ||
|
|
790
|
+
(motion.kind !== 'spin' && (duration < 0.1 || duration > 2)))
|
|
791
|
+
throw new Error(`Invalid timing for ${part.id}`);
|
|
792
|
+
const signature = JSON.stringify([
|
|
793
|
+
part.id,
|
|
794
|
+
motion.kind,
|
|
795
|
+
motion.axis,
|
|
796
|
+
...pivot.map(rounded),
|
|
797
|
+
rounded(amount),
|
|
798
|
+
delay,
|
|
799
|
+
duration,
|
|
800
|
+
easing,
|
|
801
|
+
]);
|
|
802
|
+
// A part gated by `when` names groups by repeat index, so skipped repeats never
|
|
803
|
+
// renumber the survivors.
|
|
804
|
+
const gated = part.when !== undefined || part.shapes.some((shape) => shape.when !== undefined);
|
|
805
|
+
motionGroup = gated ? undefined : motionSignatures.get(signature);
|
|
806
|
+
if (!motionGroup) {
|
|
807
|
+
if (motions.length >= RECIPE_LIMITS.motionGroups)
|
|
808
|
+
throw new Error(`Recipe exceeds ${RECIPE_LIMITS.motionGroups} evaluated motion groups`);
|
|
809
|
+
const ordinal = gated ? i : motions.filter((m) => m.partId === part.id).length;
|
|
810
|
+
motionGroup = ordinal ? `${part.id}~${ordinal}` : part.id;
|
|
811
|
+
motionSignatures.set(signature, motionGroup);
|
|
812
|
+
motions.push({
|
|
813
|
+
id: motionGroup,
|
|
814
|
+
partId: part.id,
|
|
815
|
+
kind: motion.kind,
|
|
816
|
+
axis: motion.axis,
|
|
817
|
+
pivot,
|
|
818
|
+
amount,
|
|
819
|
+
delay,
|
|
820
|
+
duration,
|
|
821
|
+
easing,
|
|
822
|
+
});
|
|
823
|
+
}
|
|
824
|
+
motionGroupByInstance[`${part.id}:${i}`] = motionGroup;
|
|
825
|
+
}
|
|
826
|
+
for (const s of kept) {
|
|
827
|
+
if (shapes.length >= shapeLimit)
|
|
248
828
|
throw new Error('Expanded shape budget exceeded');
|
|
249
|
-
|
|
250
|
-
|
|
829
|
+
let position = vec(s.position);
|
|
830
|
+
let rotation = vec(s.rotation ?? [0, 0, 0]);
|
|
831
|
+
let size;
|
|
832
|
+
let extrusion = {};
|
|
833
|
+
if (s.primitive === 'revolve') {
|
|
834
|
+
// Points that coincide with the previous one (a feature collapsed to zero) are dropped.
|
|
835
|
+
const points = [];
|
|
836
|
+
for (const [re, ye] of s.profile) {
|
|
837
|
+
const [r, y] = [expr(re, i), expr(ye, i)];
|
|
838
|
+
if (!(r >= 0 &&
|
|
839
|
+
r <= RECIPE_LIMITS.dimension / 2 &&
|
|
840
|
+
Math.abs(y) <= RECIPE_LIMITS.dimension))
|
|
841
|
+
throw new Error(`Invalid revolve profile for ${part.id}/${s.id}`);
|
|
842
|
+
const last = points.at(-1);
|
|
843
|
+
if (!last || Math.hypot(r - last[0], y - last[1]) > 1e-6)
|
|
844
|
+
points.push([r, y]);
|
|
845
|
+
}
|
|
846
|
+
if (points.length < 2)
|
|
847
|
+
throw new Error(`Invalid revolve profile for ${part.id}/${s.id}`);
|
|
848
|
+
const radius = Math.max(...points.map(([r]) => r));
|
|
849
|
+
const low = Math.min(...points.map(([, y]) => y)), high = Math.max(...points.map(([, y]) => y));
|
|
850
|
+
size = [2 * radius, high - low, 2 * radius];
|
|
851
|
+
const middle = (low + high) / 2;
|
|
852
|
+
position = position.map((v, k) => v + rotateVector([0, middle, 0], rotation)[k]);
|
|
853
|
+
extrusion = { profile: points.map(([r, y]) => [r, y - middle]) };
|
|
854
|
+
if (!(size[0] >= 0.001))
|
|
855
|
+
throw new Error(`Revolve profile for ${part.id}/${s.id} needs a radius`);
|
|
856
|
+
}
|
|
857
|
+
else if (s.primitive === 'extrude') {
|
|
858
|
+
const resolved = resolveSection(s.section, (e) => expr(e, i));
|
|
859
|
+
const rings = sectionRings(resolved);
|
|
860
|
+
const b = boundsOf(rings.outer.map(([x, y]) => [x, y, 0]));
|
|
861
|
+
const center = b.min.map((v, k) => (v + b.max[k]) / 2);
|
|
862
|
+
const length = expr(s.length, i);
|
|
863
|
+
const bevel = s.bevel === undefined ? 0 : expr(s.bevel, i);
|
|
864
|
+
// The bevel insets every contour, so it must stay under the section's thinnest wall.
|
|
865
|
+
if (!(bevel >= 0 &&
|
|
866
|
+
bevel <= Math.min(length / 4, 0.05) &&
|
|
867
|
+
(bevel === 0 || bevel <= sectionThickness(rings) / 2.5 + 1e-9)))
|
|
868
|
+
throw new Error(`bevel for ${part.id}/${s.id} must be within 0..min(length / 4, 5 cm, thinnest wall / 2.5)`);
|
|
869
|
+
size = [b.dimensions[0], b.dimensions[1], length];
|
|
870
|
+
// Evaluated shapes are centred in their box, so bounds and handles read them as boxes.
|
|
871
|
+
position = position.map((v, k) => v + rotateVector(center, rotation)[k]);
|
|
872
|
+
extrusion = {
|
|
873
|
+
section: resolved.kind === 'polygon'
|
|
874
|
+
? {
|
|
875
|
+
kind: 'polygon',
|
|
876
|
+
outer: resolved.outer.map(([x, y]) => [x - center[0], y - center[1]]),
|
|
877
|
+
...(resolved.holes && {
|
|
878
|
+
holes: resolved.holes.map((hole) => hole.map(([x, y]) => [x - center[0], y - center[1]])),
|
|
879
|
+
}),
|
|
880
|
+
}
|
|
881
|
+
: resolved,
|
|
882
|
+
...(bevel > 0 && { bevel }),
|
|
883
|
+
};
|
|
884
|
+
}
|
|
885
|
+
else
|
|
886
|
+
size = vec(s.size);
|
|
887
|
+
const f = solidFields(s);
|
|
251
888
|
if (size.some((x) => x < 0.001 || x > RECIPE_LIMITS.dimension))
|
|
252
889
|
throw new Error(`Invalid dimensions for ${part.id}/${s.id}`);
|
|
253
|
-
const radius = s.primitive === 'roundedBox' ? expr(
|
|
890
|
+
const radius = s.primitive === 'roundedBox' ? expr(f.radius ?? 0.02, i) : 0;
|
|
254
891
|
if (radius < 0 || radius > Math.min(...size) / 2)
|
|
255
892
|
throw new Error(`Invalid rounding for ${s.id}`);
|
|
893
|
+
if (f.topScale !== undefined && s.primitive !== 'cylinder')
|
|
894
|
+
throw new Error(`topScale is only allowed on cylinders (${part.id}/${s.id})`);
|
|
895
|
+
const topScale = f.topScale === undefined ? 1 : expr(f.topScale, i);
|
|
896
|
+
if (topScale < 0 || topScale > 1)
|
|
897
|
+
throw new Error(`topScale for ${part.id}/${s.id} must be within [0, 1]`);
|
|
898
|
+
if (s.support && (s.primitive === 'ellipsoid' || topScale < 1))
|
|
899
|
+
throw new Error(`Support surface ${part.id}/${s.id} cannot be ellipsoid or tapered cylinder`);
|
|
900
|
+
if (s.support && motionGroup)
|
|
901
|
+
throw new Error(`Moving part ${part.id} cannot contain support shapes`);
|
|
902
|
+
const inner = f.inner === undefined ? undefined : expr(f.inner, i);
|
|
903
|
+
if (inner !== undefined && !(inner > 0 && inner < 1))
|
|
904
|
+
throw new Error(`inner for ${part.id}/${s.id} must be within (0, 1)`);
|
|
905
|
+
const arc = f.arc === undefined ? undefined : expr(f.arc, i);
|
|
906
|
+
if (arc !== undefined && !(arc > 0 && arc <= 2 * Math.PI + 1e-9))
|
|
907
|
+
throw new Error(`arc for ${part.id}/${s.id} must be within (0, 2π]`);
|
|
908
|
+
({ position, rotation } = place(position, rotation));
|
|
256
909
|
const shapeId = `${part.id}:${i}:${s.id}`;
|
|
257
910
|
shapes.push({
|
|
258
911
|
id: shapeId,
|
|
@@ -263,28 +916,29 @@ export function evaluateRecipe(recipe, values = {}) {
|
|
|
263
916
|
position,
|
|
264
917
|
rotation,
|
|
265
918
|
radius,
|
|
919
|
+
topScale,
|
|
920
|
+
...(f.segments === undefined ? {} : { segments: f.segments }),
|
|
921
|
+
...(f.open ? { open: true } : {}),
|
|
922
|
+
...(inner === undefined ? {} : { inner }),
|
|
923
|
+
...(arc === undefined ? {} : { arc }),
|
|
924
|
+
...extrusion,
|
|
925
|
+
motionGroup,
|
|
266
926
|
});
|
|
267
|
-
|
|
268
|
-
|
|
927
|
+
const built = shapeTriangles(shapes.at(-1));
|
|
928
|
+
triangles += built;
|
|
929
|
+
charged += triangleCharge(recipe, shapes.at(-1), built);
|
|
930
|
+
if (charged > RECIPE_LIMITS.triangles)
|
|
269
931
|
throw new Error('Triangle budget exceeded');
|
|
270
|
-
|
|
271
|
-
for (
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
const point = [
|
|
278
|
-
x2 + position[0],
|
|
279
|
-
y1 * Math.cos(rx) - z2 * Math.sin(rx) + position[1],
|
|
280
|
-
y1 * Math.sin(rx) + z2 * Math.cos(rx) + position[2],
|
|
281
|
-
];
|
|
282
|
-
for (let k = 0; k < 3; k++) {
|
|
283
|
-
min[k] = Math.min(min[k], point[k]);
|
|
284
|
-
max[k] = Math.max(max[k], point[k]);
|
|
285
|
-
}
|
|
286
|
-
}
|
|
932
|
+
const bounds = shapeBounds({ primitive: s.primitive, size, position, rotation });
|
|
933
|
+
for (let k = 0; k < 3; k++) {
|
|
934
|
+
min[k] = Math.min(min[k], bounds.min[k]);
|
|
935
|
+
max[k] = Math.max(max[k], bounds.max[k]);
|
|
936
|
+
instanceMin[k] = Math.min(instanceMin[k], bounds.min[k]);
|
|
937
|
+
instanceMax[k] = Math.max(instanceMax[k], bounds.max[k]);
|
|
938
|
+
}
|
|
287
939
|
if (s.support) {
|
|
940
|
+
if (surfaces.length >= 256)
|
|
941
|
+
throw new Error('Surface budget exceeded');
|
|
288
942
|
if (rotation.some((v) => v !== 0))
|
|
289
943
|
throw new Error('Support surfaces must be horizontal and unrotated in v1');
|
|
290
944
|
surfaces.push({
|
|
@@ -297,17 +951,63 @@ export function evaluateRecipe(recipe, values = {}) {
|
|
|
297
951
|
});
|
|
298
952
|
}
|
|
299
953
|
}
|
|
954
|
+
// A repeat whose shapes `when` all skipped builds no light either.
|
|
955
|
+
if (part.light && instanceMin[0] !== Infinity) {
|
|
956
|
+
if (lights.length >= RECIPE_LIMITS.lights)
|
|
957
|
+
throw new Error('Evaluated light budget exceeded');
|
|
958
|
+
const position = pose === IDENTITY_POSE
|
|
959
|
+
? vec(part.light.position)
|
|
960
|
+
: posePoint(pose, vec(part.light.position));
|
|
961
|
+
if (position.some((value) => !Number.isFinite(value)))
|
|
962
|
+
throw new Error(`Invalid light position for ${part.id}`);
|
|
963
|
+
if (position.some((value, axis) => value < instanceMin[axis] - 0.02 || value > instanceMax[axis] + 0.02))
|
|
964
|
+
throw new Error(`Light for ${part.id}:${i} is outside its resting bounds`);
|
|
965
|
+
lights.push({
|
|
966
|
+
id: `${part.id}:${i}`,
|
|
967
|
+
partId: part.id,
|
|
968
|
+
index: i,
|
|
969
|
+
motionGroup,
|
|
970
|
+
position,
|
|
971
|
+
color: part.light.color,
|
|
972
|
+
intensity: part.light.intensity ?? 2,
|
|
973
|
+
distance: part.light.distance ?? 5,
|
|
974
|
+
emissiveSlot: part.light.emissiveSlot,
|
|
975
|
+
});
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
if (jointGroups.size) {
|
|
980
|
+
const carrying = new Set();
|
|
981
|
+
for (let group of shapes.map((shape) => shape.motionGroup))
|
|
982
|
+
while (group && !carrying.has(group)) {
|
|
983
|
+
carrying.add(group);
|
|
984
|
+
group = motions.find((motion) => motion.id === group)?.parent;
|
|
985
|
+
}
|
|
986
|
+
for (let k = motions.length - 1; k >= 0; k--) {
|
|
987
|
+
const id = motions[k].id;
|
|
988
|
+
if (carrying.has(id))
|
|
989
|
+
continue;
|
|
990
|
+
motions.splice(k, 1);
|
|
991
|
+
jointGroups.delete(id);
|
|
992
|
+
for (const [instance, group] of Object.entries(motionGroupByInstance))
|
|
993
|
+
if (group === id)
|
|
994
|
+
delete motionGroupByInstance[instance];
|
|
995
|
+
}
|
|
300
996
|
}
|
|
301
997
|
for (const surface of recipe.surfaces ?? []) {
|
|
302
998
|
const part = recipe.parts.find((p) => p.id === surface.part);
|
|
303
|
-
const count = part ?
|
|
999
|
+
const count = part ? counts.get(part.id) : 1;
|
|
304
1000
|
for (let i = 0; i < count; i++) {
|
|
1001
|
+
if (part && !builtRepeats.has(`${part.id}:${i}`))
|
|
1002
|
+
continue;
|
|
305
1003
|
if (surfaces.length >= 256)
|
|
306
1004
|
throw new Error('Surface budget exceeded');
|
|
307
1005
|
const rotation = (surface.rotation ?? [0, 0, 0]).map((e) => expr(e, i));
|
|
308
1006
|
const size = surface.size.map((e) => expr(e, i));
|
|
309
1007
|
const position = surface.position.map((e) => expr(e, i));
|
|
310
|
-
|
|
1008
|
+
// Bounded where consumers read it: design space with the resting datum at y = 0.
|
|
1009
|
+
if (size.some((v) => v < 0.001 || v > 30) ||
|
|
1010
|
+
position.some((v, k) => Math.abs(k === 1 ? v - base : v) > 30))
|
|
311
1011
|
throw new Error('Invalid surface region');
|
|
312
1012
|
surfaces.push({
|
|
313
1013
|
id: part ? `${surface.id}:${i}` : surface.id,
|
|
@@ -319,6 +1019,9 @@ export function evaluateRecipe(recipe, values = {}) {
|
|
|
319
1019
|
});
|
|
320
1020
|
}
|
|
321
1021
|
}
|
|
1022
|
+
const cuts = [];
|
|
1023
|
+
// Recessed designs: whether a design-space [x, z] lies inside one of their cuts.
|
|
1024
|
+
let insideCut = null;
|
|
322
1025
|
if (recipe.mounting) {
|
|
323
1026
|
const reference = surfaces.find((s) => s.id === recipe.mounting.reference);
|
|
324
1027
|
if (!reference || reference.id.includes(':'))
|
|
@@ -326,20 +1029,189 @@ export function evaluateRecipe(recipe, values = {}) {
|
|
|
326
1029
|
if (recipe.mounting.attachTo === 'ceiling') {
|
|
327
1030
|
if (Math.abs(reference.normal[1] - 1) > 1e-6)
|
|
328
1031
|
throw new Error('Ceiling mounting reference must face local +Y');
|
|
329
|
-
|
|
1032
|
+
const recessed = recipe.version === 2 && recipe.cuts !== undefined;
|
|
1033
|
+
if (recessed
|
|
1034
|
+
? reference.position[1] > max[1] + 1e-6
|
|
1035
|
+
: Math.abs(reference.position[1] - max[1]) > 1e-6)
|
|
330
1036
|
throw new Error('Ceiling mounting reference must lie at the top of the design');
|
|
1037
|
+
if (recessed) {
|
|
1038
|
+
const u = rotateVector([1, 0, 0], reference.rotation), v = rotateVector([0, 0, 1], reference.rotation);
|
|
1039
|
+
const inside = [];
|
|
1040
|
+
for (const c of recipe.cuts) {
|
|
1041
|
+
const [cu, cv] = (c.center ?? [0, 0]).map((e) => expr(e));
|
|
1042
|
+
const cx = reference.position[0] + u[0] * cu + v[0] * cv, cz = reference.position[2] + u[2] * cu + v[2] * cv;
|
|
1043
|
+
const half = c.shape === 'rect'
|
|
1044
|
+
? c.size.map((e) => expr(e) / 2)
|
|
1045
|
+
: [expr(c.diameter) / 2, expr(c.diameter) / 2];
|
|
1046
|
+
if (half.some((h) => !(h >= 0.005 && h <= 15)))
|
|
1047
|
+
throw new Error('Invalid cut size');
|
|
1048
|
+
const local = c.shape === 'rect'
|
|
1049
|
+
? [
|
|
1050
|
+
[-half[0], -half[1]],
|
|
1051
|
+
[half[0], -half[1]],
|
|
1052
|
+
[half[0], half[1]],
|
|
1053
|
+
[-half[0], half[1]],
|
|
1054
|
+
]
|
|
1055
|
+
: Array.from({ length: 32 }, (_, k) => [
|
|
1056
|
+
half[0] * Math.cos((k * Math.PI) / 16),
|
|
1057
|
+
half[0] * Math.sin((k * Math.PI) / 16),
|
|
1058
|
+
]);
|
|
1059
|
+
cuts.push({
|
|
1060
|
+
host: 'ceiling',
|
|
1061
|
+
ring: local.map(([a, b]) => [cx + u[0] * a + v[0] * b, cz + u[2] * a + v[2] * b]),
|
|
1062
|
+
});
|
|
1063
|
+
inside.push((x, z) => {
|
|
1064
|
+
const a = (x - cx) * u[0] + (z - cz) * u[2], b = (x - cx) * v[0] + (z - cz) * v[2];
|
|
1065
|
+
return c.shape === 'rect'
|
|
1066
|
+
? Math.abs(a) <= half[0] + 1e-6 && Math.abs(b) <= half[1] + 1e-6
|
|
1067
|
+
: Math.hypot(a, b) <= half[0] + 1e-6;
|
|
1068
|
+
});
|
|
1069
|
+
}
|
|
1070
|
+
for (const shape of shapes) {
|
|
1071
|
+
if (shapeBounds(shape).max[1] <= reference.position[1] + 1e-6)
|
|
1072
|
+
continue;
|
|
1073
|
+
const footprint = shapeFootprint(shape);
|
|
1074
|
+
if (!inside.some((test) => footprint.every(([x, , z]) => test(x, z))))
|
|
1075
|
+
throw new Error(`${shape.partId} rises above the ceiling reference outside its cut`);
|
|
1076
|
+
}
|
|
1077
|
+
insideCut = (x, z) => inside.some((test) => test(x, z));
|
|
1078
|
+
}
|
|
331
1079
|
}
|
|
332
1080
|
else if (Math.abs(reference.normal[2] + 1) > 1e-6)
|
|
333
1081
|
throw new Error('Wall-side mounting reference must face local -Z');
|
|
334
1082
|
}
|
|
1083
|
+
const reference = recipe.mounting && surfaces.find((s) => s.id === recipe.mounting.reference);
|
|
1084
|
+
const reach = insideCut ? { min: [...min], max: [...max] } : undefined;
|
|
1085
|
+
for (const { motion, bounds } of jointReach(motions.filter((m) => jointGroups.has(m.id)), shapes, shapeBounds)) {
|
|
1086
|
+
if (reach)
|
|
1087
|
+
for (let k = 0; k < 3; k++) {
|
|
1088
|
+
reach.min[k] = Math.min(reach.min[k], bounds.min[k]);
|
|
1089
|
+
reach.max[k] = Math.max(reach.max[k], bounds.max[k]);
|
|
1090
|
+
}
|
|
1091
|
+
if (!recipe.mounting && bounds.min[1] < base - 0.001)
|
|
1092
|
+
throw new Error(`Motion envelope for ${motion.partId} extends below the floor`);
|
|
1093
|
+
if (recipe.mounting?.attachTo === 'wall-side' &&
|
|
1094
|
+
reference &&
|
|
1095
|
+
bounds.min[2] < reference.position[2] - 0.001)
|
|
1096
|
+
throw new Error(`Motion envelope for ${motion.partId} crosses behind the wall reference`);
|
|
1097
|
+
if (recipe.mounting?.attachTo === 'ceiling' &&
|
|
1098
|
+
reference &&
|
|
1099
|
+
bounds.max[1] > reference.position[1] + 0.001 &&
|
|
1100
|
+
!boxCorners(bounds.min, bounds.max).every(([x, , z]) => insideCut?.(x, z)))
|
|
1101
|
+
throw new Error(`Motion envelope for ${motion.partId} rises above the ceiling reference`);
|
|
1102
|
+
}
|
|
1103
|
+
for (const motion of motions) {
|
|
1104
|
+
if (jointGroups.has(motion.id))
|
|
1105
|
+
continue;
|
|
1106
|
+
const steps = motion.kind === 'slide' ? 1 : motion.kind === 'hinge' ? 8 : 16;
|
|
1107
|
+
const poses = Array.from({ length: steps + 1 }, (_, step) => motionPose(motion, step / steps));
|
|
1108
|
+
for (const shape of shapes) {
|
|
1109
|
+
if (shape.motionGroup !== motion.id)
|
|
1110
|
+
continue;
|
|
1111
|
+
// Inside a cut, sample the rendered footprint so round parts may turn in round cuts.
|
|
1112
|
+
const points = insideCut
|
|
1113
|
+
? shapeFootprint(shape)
|
|
1114
|
+
: shapeCorners(shape.size, shape.position, shape.rotation);
|
|
1115
|
+
for (const corner of points)
|
|
1116
|
+
for (const { r, t } of poses) {
|
|
1117
|
+
const [x, y, z] = corner;
|
|
1118
|
+
const point = [
|
|
1119
|
+
r[0] * x + r[1] * y + r[2] * z + t[0],
|
|
1120
|
+
r[3] * x + r[4] * y + r[5] * z + t[1],
|
|
1121
|
+
r[6] * x + r[7] * y + r[8] * z + t[2],
|
|
1122
|
+
];
|
|
1123
|
+
if (reach)
|
|
1124
|
+
for (let k = 0; k < 3; k++) {
|
|
1125
|
+
reach.min[k] = Math.min(reach.min[k], point[k]);
|
|
1126
|
+
reach.max[k] = Math.max(reach.max[k], point[k]);
|
|
1127
|
+
}
|
|
1128
|
+
if (!recipe.mounting && point[1] < base - 0.001)
|
|
1129
|
+
throw new Error(`Motion envelope for ${shape.partId} extends below the floor`);
|
|
1130
|
+
if (recipe.mounting?.attachTo === 'wall-side' &&
|
|
1131
|
+
reference &&
|
|
1132
|
+
point[2] < reference.position[2] - 0.001)
|
|
1133
|
+
throw new Error(`Motion envelope for ${shape.partId} crosses behind the wall reference`);
|
|
1134
|
+
if (recipe.mounting?.attachTo === 'ceiling' &&
|
|
1135
|
+
reference &&
|
|
1136
|
+
point[1] > reference.position[1] + 0.001 &&
|
|
1137
|
+
!insideCut?.(point[0], point[2]))
|
|
1138
|
+
throw new Error(`Motion envelope for ${shape.partId} rises above the ceiling reference`);
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
335
1142
|
if (!shapes.length)
|
|
336
1143
|
throw new Error('The item must contain geometry');
|
|
1144
|
+
const emitted = new Map();
|
|
1145
|
+
for (const light of lights) {
|
|
1146
|
+
if (!light.emissiveSlot)
|
|
1147
|
+
continue;
|
|
1148
|
+
const previous = emitted.get(light.emissiveSlot);
|
|
1149
|
+
if (previous && previous !== light.color.toLowerCase())
|
|
1150
|
+
throw new Error(`Conflicting light colors on ${light.emissiveSlot}`);
|
|
1151
|
+
emitted.set(light.emissiveSlot, light.color.toLowerCase());
|
|
1152
|
+
}
|
|
1153
|
+
if (base !== 0) {
|
|
1154
|
+
// Consumers keep reading design space with the resting datum at y = 0.
|
|
1155
|
+
const lower = (point) => [point[0], point[1] - base, point[2]];
|
|
1156
|
+
for (const shape of shapes)
|
|
1157
|
+
shape.position = lower(shape.position);
|
|
1158
|
+
for (const light of lights)
|
|
1159
|
+
light.position = lower(light.position);
|
|
1160
|
+
for (const surface of surfaces)
|
|
1161
|
+
surface.position = lower(surface.position);
|
|
1162
|
+
// A slide's pivot is the origin of its group, not a point of the design.
|
|
1163
|
+
for (const motion of motions)
|
|
1164
|
+
if (motion.kind !== 'slide')
|
|
1165
|
+
motion.pivot = lower(motion.pivot);
|
|
1166
|
+
min[1] -= base;
|
|
1167
|
+
max[1] -= base;
|
|
1168
|
+
}
|
|
337
1169
|
const dimensions = max.map((x, i) => x - min[i]);
|
|
338
1170
|
if (dimensions.some((x) => x > 30) || [...min, ...max].some((x) => Math.abs(x) > 30))
|
|
339
1171
|
throw new Error('Item exceeds 30 m bounds');
|
|
340
|
-
if (min[1] < -0.001)
|
|
341
|
-
throw new Error(
|
|
342
|
-
|
|
1172
|
+
if (!hangsFromCeiling && min[1] < -0.001)
|
|
1173
|
+
throw new Error(recipe.base === undefined
|
|
1174
|
+
? 'Geometry extends below the ground; base must be at y=0'
|
|
1175
|
+
: 'Geometry extends below the declared base');
|
|
1176
|
+
return {
|
|
1177
|
+
shapes,
|
|
1178
|
+
motions,
|
|
1179
|
+
lights,
|
|
1180
|
+
motionGroupByInstance,
|
|
1181
|
+
surfaces,
|
|
1182
|
+
cuts,
|
|
1183
|
+
min,
|
|
1184
|
+
max,
|
|
1185
|
+
dimensions,
|
|
1186
|
+
parameters,
|
|
1187
|
+
triangles,
|
|
1188
|
+
...(reach && motions.length > 0 && { reach }),
|
|
1189
|
+
};
|
|
1190
|
+
}
|
|
1191
|
+
export const EASINGS = {
|
|
1192
|
+
linear: (u) => u,
|
|
1193
|
+
smooth: (u) => 3 * u * u - 2 * u * u * u,
|
|
1194
|
+
soft: (u) => 6 * u ** 5 - 15 * u ** 4 + 10 * u ** 3,
|
|
1195
|
+
};
|
|
1196
|
+
export function finitePoseFraction(motion, time) {
|
|
1197
|
+
const u = Math.max(0, Math.min(1, (time - motion.delay) / motion.duration));
|
|
1198
|
+
return EASINGS[motion.easing](u);
|
|
1199
|
+
}
|
|
1200
|
+
export function motionTimeline(evaluation) {
|
|
1201
|
+
const perPart = Object.create(null);
|
|
1202
|
+
let T = 0;
|
|
1203
|
+
for (const motion of evaluation.motions) {
|
|
1204
|
+
if (motion.kind === 'spin')
|
|
1205
|
+
continue;
|
|
1206
|
+
const end = motion.delay + motion.duration;
|
|
1207
|
+
T = Math.max(T, end);
|
|
1208
|
+
const part = perPart[motion.partId];
|
|
1209
|
+
perPart[motion.partId] = {
|
|
1210
|
+
A: Math.min(part?.A ?? Infinity, motion.delay),
|
|
1211
|
+
B: Math.max(part?.B ?? 0, end),
|
|
1212
|
+
};
|
|
1213
|
+
}
|
|
1214
|
+
return { T, perPart };
|
|
343
1215
|
}
|
|
344
1216
|
export function sweepRecipe(recipe) {
|
|
345
1217
|
const cases = [{}];
|