@weasel-js/core 1.13.0 → 1.14.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +326 -0
- package/README.md +8 -12
- package/dist/affordances/hitAffordanceRegions.js +1 -1
- package/dist/affordances/hitAffordanceRegions.js.map +1 -1
- package/dist/affordances/pathAnchors.js.map +1 -1
- package/dist/animation/clipTargets.js +1 -1
- package/dist/animation/clipTargets.js.map +1 -1
- package/dist/animation/poseTarget.js +5 -32
- package/dist/animation/poseTarget.js.map +1 -1
- package/dist/{autoPoseDescriptor-CZ1eXbzY.d.ts → autoPoseDescriptor-C25QVb0W.d.ts} +1 -1
- package/dist/barrel/canvas.js +8 -8
- package/dist/barrel/chrome.js +9 -9
- package/dist/barrel/input.js +1 -1
- package/dist/barrel/interactions.js +3 -3
- package/dist/barrel/paint.js +2 -2
- package/dist/barrel/paths.js +19 -17
- package/dist/barrel/renderer.js +11 -7
- package/dist/barrel/routing.js +4 -1
- package/dist/barrel/scene.js +16 -12
- package/dist/barrel/text.js +5 -5
- package/dist/barrel/viewport.js +8 -8
- package/dist/canvas/Canvas.js +2 -2
- package/dist/canvas/Canvas.js.map +1 -1
- package/dist/canvas/CanvasView.js +20 -14
- package/dist/canvas/CanvasView.js.map +1 -1
- package/dist/canvas/GestureReason.js +64 -0
- package/dist/canvas/GestureReason.js.map +1 -0
- package/dist/canvas/GestureReason.module.js +7 -0
- package/dist/canvas/GestureReason.module.js.map +1 -0
- package/dist/canvas/LeanSceneCanvas.js +3 -1
- package/dist/canvas/LeanSceneCanvas.js.map +1 -1
- package/dist/canvas/NodeShape.js +2 -0
- package/dist/canvas/NodeShape.js.map +1 -1
- package/dist/canvas/PickHud.js +7 -3
- package/dist/canvas/PickHud.js.map +1 -1
- package/dist/canvas/SceneCanvas/CanvasKitProviders.js +1 -1
- package/dist/canvas/SceneCanvas/CanvasKitProviders.js.map +1 -1
- package/dist/canvas/SceneCanvas/DevHuds.js +2 -2
- package/dist/canvas/SceneCanvas/DevHuds.js.map +1 -1
- package/dist/canvas/SceneCanvas/PointerProviderIfRoot.js +4 -2
- package/dist/canvas/SceneCanvas/PointerProviderIfRoot.js.map +1 -1
- package/dist/canvas/SceneCanvas/SceneCanvasInput.js +3 -1
- package/dist/canvas/SceneCanvas/SceneCanvasInput.js.map +1 -1
- package/dist/canvas/SceneCanvas/brushOverlay.js.map +1 -1
- package/dist/canvas/SceneCanvas/builtinToolSets.js +17 -9
- package/dist/canvas/SceneCanvas/builtinToolSets.js.map +1 -1
- package/dist/canvas/SceneCanvas/canvasPassThrough.js +2 -1
- package/dist/canvas/SceneCanvas/canvasPassThrough.js.map +1 -1
- package/dist/canvas/SceneCanvas/defaultNodeProperties.js +75 -19
- package/dist/canvas/SceneCanvas/defaultNodeProperties.js.map +1 -1
- package/dist/canvas/SceneCanvas/defaultNodeRouting.js +7 -1
- package/dist/canvas/SceneCanvas/defaultNodeRouting.js.map +1 -1
- package/dist/canvas/SceneCanvas/defaultTextEditor.js +108 -0
- package/dist/canvas/SceneCanvas/defaultTextEditor.js.map +1 -0
- package/dist/canvas/SceneCanvas/describePresets.js +47 -0
- package/dist/canvas/SceneCanvas/describePresets.js.map +1 -0
- package/dist/canvas/SceneCanvas/features.js +57 -16
- package/dist/canvas/SceneCanvas/features.js.map +1 -1
- package/dist/canvas/SceneCanvas/mergeLayers.js +10 -1
- package/dist/canvas/SceneCanvas/mergeLayers.js.map +1 -1
- package/dist/canvas/SceneCanvas/namedPresets.js +52 -24
- package/dist/canvas/SceneCanvas/namedPresets.js.map +1 -1
- package/dist/canvas/SceneCanvas/presets/arrange.js +35 -10
- package/dist/canvas/SceneCanvas/presets/arrange.js.map +1 -1
- package/dist/canvas/SceneCanvas/presets/baseline.js +9 -0
- package/dist/canvas/SceneCanvas/presets/baseline.js.map +1 -0
- package/dist/canvas/SceneCanvas/presets/chrome.js.map +1 -1
- package/dist/canvas/SceneCanvas/presets/composites.js +43 -0
- package/dist/canvas/SceneCanvas/presets/composites.js.map +1 -0
- package/dist/canvas/SceneCanvas/presets/edit.js +79 -26
- package/dist/canvas/SceneCanvas/presets/edit.js.map +1 -1
- package/dist/canvas/SceneCanvas/presets/ingest.js +1 -0
- package/dist/canvas/SceneCanvas/presets/ingest.js.map +1 -1
- package/dist/canvas/SceneCanvas/presets/paths.js +58 -16
- package/dist/canvas/SceneCanvas/presets/paths.js.map +1 -1
- package/dist/canvas/SceneCanvas/presets/select.js +4 -2
- package/dist/canvas/SceneCanvas/presets/select.js.map +1 -1
- package/dist/canvas/SceneCanvas/presets/tools.js +24 -0
- package/dist/canvas/SceneCanvas/presets/tools.js.map +1 -0
- package/dist/canvas/SceneCanvas/presets/transform.js +4 -0
- package/dist/canvas/SceneCanvas/presets/transform.js.map +1 -1
- package/dist/canvas/SceneCanvas/presets/view.js +3 -1
- package/dist/canvas/SceneCanvas/presets/view.js.map +1 -1
- package/dist/canvas/SceneCanvas/props.js.map +1 -1
- package/dist/canvas/SceneCanvas/shapeGeneratorProperties.js +1 -1
- package/dist/canvas/SceneCanvas/shapeGeneratorProperties.js.map +1 -1
- package/dist/canvas/SceneCanvas/toolRegistry.js +5 -4
- package/dist/canvas/SceneCanvas/toolRegistry.js.map +1 -1
- package/dist/canvas/SceneCanvas/useCanvasTools.js +26 -10
- package/dist/canvas/SceneCanvas/useCanvasTools.js.map +1 -1
- package/dist/canvas/SceneCanvas/useContributionRoles.js +15 -2
- package/dist/canvas/SceneCanvas/useContributionRoles.js.map +1 -1
- package/dist/canvas/SceneCanvas/useDepartureGhostLayer.js +5 -4
- package/dist/canvas/SceneCanvas/useDepartureGhostLayer.js.map +1 -1
- package/dist/canvas/SceneCanvas/useDispatcherOverlayLayer.js +1 -1
- package/dist/canvas/SceneCanvas/useNodeAtPoint.js.map +1 -1
- package/dist/canvas/SceneCanvas/useSceneCanvasLayers.js +9 -8
- package/dist/canvas/SceneCanvas/useSceneCanvasLayers.js.map +1 -1
- package/dist/canvas/SceneCanvas/useSceneCanvasPathEdit.js +2 -2
- package/dist/canvas/SceneCanvas/useSceneCanvasPathEdit.js.map +1 -1
- package/dist/canvas/SceneCanvas/useSceneCanvasTools.js +4 -1
- package/dist/canvas/SceneCanvas/useSceneCanvasTools.js.map +1 -1
- package/dist/canvas/SceneCanvas/useSceneChrome.js +7 -4
- package/dist/canvas/SceneCanvas/useSceneChrome.js.map +1 -1
- package/dist/canvas/SceneCanvas/useSceneGestureDispatcher.js +9 -9
- package/dist/canvas/SceneCanvas/useSceneGestureDispatcher.js.map +1 -1
- package/dist/canvas/SceneCanvas/useScenePicking.js +4 -7
- package/dist/canvas/SceneCanvas/useScenePicking.js.map +1 -1
- package/dist/canvas/SceneCanvas/useSceneRedrawSources.js +2 -1
- package/dist/canvas/SceneCanvas/useSceneRedrawSources.js.map +1 -1
- package/dist/canvas/SceneCanvas/useSceneSelectTool.js +6 -6
- package/dist/canvas/SceneCanvas/useSceneSelectTool.js.map +1 -1
- package/dist/canvas/SceneCanvas/useSceneStandardActions.js +2 -2
- package/dist/canvas/SceneCanvas/useSceneStandardActions.js.map +1 -1
- package/dist/canvas/SceneCanvas/useSelectionOverlayLayer.js +1 -1
- package/dist/canvas/SceneCanvas/useSelectionOverlayLayer.js.map +1 -1
- package/dist/canvas/SceneCanvas/useSurfaceViewInputs.js.map +1 -1
- package/dist/canvas/SceneCanvas/useToolKeybindings.js +2 -2
- package/dist/canvas/SceneCanvas/useToolKeybindings.js.map +1 -1
- package/dist/canvas/SceneCanvas/useViewportActions.js +5 -2
- package/dist/canvas/SceneCanvas/useViewportActions.js.map +1 -1
- package/dist/canvas/SceneCanvas/worldPointAt.js.map +1 -1
- package/dist/canvas/SceneCanvas.js +22 -11
- package/dist/canvas/SceneCanvas.js.map +1 -1
- package/dist/canvas/SceneViewCanvas.js +1 -0
- package/dist/canvas/SceneViewCanvas.js.map +1 -1
- package/dist/canvas/ViewMarker.js.map +1 -1
- package/dist/canvas/accentColor.js +14 -1
- package/dist/canvas/accentColor.js.map +1 -1
- package/dist/canvas/affordanceAt.js +2 -2
- package/dist/canvas/affordanceAt.js.map +1 -1
- package/dist/canvas/buildSceneTree.js +5 -3
- package/dist/canvas/buildSceneTree.js.map +1 -1
- package/dist/canvas/deps/editAnchors.js +4 -4
- package/dist/canvas/deps/editAnchors.js.map +1 -1
- package/dist/canvas/deps/enteredGroup.js +14 -5
- package/dist/canvas/deps/enteredGroup.js.map +1 -1
- package/dist/canvas/deps/ingestion.js +5 -1
- package/dist/canvas/deps/ingestion.js.map +1 -1
- package/dist/canvas/deps/insert.js.map +1 -1
- package/dist/canvas/deps/insertSite.js +5 -3
- package/dist/canvas/deps/insertSite.js.map +1 -1
- package/dist/canvas/deps/nodeAtPoint.js +1 -12
- package/dist/canvas/deps/nodeAtPoint.js.map +1 -1
- package/dist/canvas/deps/pathEditCommits.js +3 -3
- package/dist/canvas/deps/pathEditCommits.js.map +1 -1
- package/dist/canvas/deps/slice.js +16 -2
- package/dist/canvas/deps/slice.js.map +1 -1
- package/dist/canvas/deps/snap.js +5 -5
- package/dist/canvas/deps/snap.js.map +1 -1
- package/dist/canvas/deps/textEdit.js +5 -6
- package/dist/canvas/deps/textEdit.js.map +1 -1
- package/dist/canvas/derivedPath.js +8 -3
- package/dist/canvas/derivedPath.js.map +1 -1
- package/dist/canvas/getNodeAtPoint.js +2 -2
- package/dist/canvas/getNodeAtPoint.js.map +1 -1
- package/dist/canvas/insertPreviewExtent.js.map +1 -1
- package/dist/canvas/layerSlots.js.map +1 -1
- package/dist/canvas/nodeShapes/measurePainter.js +1 -1
- package/dist/canvas/nodeShapes/measurePainter.js.map +1 -1
- package/dist/canvas/nodeShapes/strokedBounds.js +5 -3
- package/dist/canvas/nodeShapes/strokedBounds.js.map +1 -1
- package/dist/canvas/overlayRoleStrokes.js +6 -0
- package/dist/canvas/overlayRoleStrokes.js.map +1 -1
- package/dist/canvas/pickIndex/scenePickIndex.js +10 -12
- package/dist/canvas/pickIndex/scenePickIndex.js.map +1 -1
- package/dist/canvas/sceneAdapter.js +10 -19
- package/dist/canvas/sceneAdapter.js.map +1 -1
- package/dist/canvas/sceneClipboard.js +17 -4
- package/dist/canvas/sceneClipboard.js.map +1 -1
- package/dist/canvas/sceneViewRender.js +3 -2
- package/dist/canvas/sceneViewRender.js.map +1 -1
- package/dist/canvas/surfaceContribution.js.map +1 -1
- package/dist/canvas/useCanvasPaint.js +10 -4
- package/dist/canvas/useCanvasPaint.js.map +1 -1
- package/dist/canvas/useHitObserver.js +1 -1
- package/dist/canvas/useHitObserver.js.map +1 -1
- package/dist/canvas/useViewAim.js +1 -1
- package/dist/canvas/useViewAim.js.map +1 -1
- package/dist/canvas/useViewHelpers.js +8 -5
- package/dist/canvas/useViewHelpers.js.map +1 -1
- package/dist/canvas/useViewNesting.js +39 -12
- package/dist/canvas/useViewNesting.js.map +1 -1
- package/dist/canvas/viewInputs.js.map +1 -1
- package/dist/canvas/viewMarkers.js +2 -2
- package/dist/canvas/viewMarkers.js.map +1 -1
- package/dist/canvas/viewRegistry.js +2 -2
- package/dist/canvas/viewRegistry.js.map +1 -1
- package/dist/canvas/viewSnap.js +67 -0
- package/dist/canvas/viewSnap.js.map +1 -0
- package/dist/clipboard.d.ts +6 -12
- package/dist/{clone-qb2e1F5p.d.ts → clone-Bz4iqGfE.d.ts} +10 -5
- package/dist/clone.d.ts +5 -5
- package/dist/core/geometry/booleanOfPaths.js +23 -0
- package/dist/core/geometry/booleanOfPaths.js.map +1 -0
- package/dist/core/geometry/pathPoseDescriptor.js +12 -9
- package/dist/core/geometry/pathPoseDescriptor.js.map +1 -1
- package/dist/core/geometry/poseDescriptor.js +12 -3
- package/dist/core/geometry/poseDescriptor.js.map +1 -1
- package/dist/core/geometry/targetFrame.js +2 -13
- package/dist/core/geometry/targetFrame.js.map +1 -1
- package/dist/core/layers/render.js +2 -1
- package/dist/core/layers/render.js.map +1 -1
- package/dist/core/layers/retain.js +5 -3
- package/dist/core/layers/retain.js.map +1 -1
- package/dist/core/ops/setPath.js +3 -0
- package/dist/core/ops/setPath.js.map +1 -1
- package/dist/core/paint/meshKindLazy.js.map +1 -1
- package/dist/core/paint/paintKindEntry.js.map +1 -1
- package/dist/core/paint/paintKinds.js +8 -1
- package/dist/core/paint/paintKinds.js.map +1 -1
- package/dist/core/scene/NodeProperties.js.map +1 -1
- package/dist/core/scene/NodeRouting.js.map +1 -1
- package/dist/core/scene/booleanGroup.js +33 -0
- package/dist/core/scene/booleanGroup.js.map +1 -0
- package/dist/core/scene/booleanOfChildren.js +53 -0
- package/dist/core/scene/booleanOfChildren.js.map +1 -0
- package/dist/core/scene/carryDescendants.js +18 -6
- package/dist/core/scene/carryDescendants.js.map +1 -1
- package/dist/core/scene/composeFrame.js +42 -5
- package/dist/core/scene/composeFrame.js.map +1 -1
- package/dist/core/scene/composePose.js +35 -16
- package/dist/core/scene/composePose.js.map +1 -1
- package/dist/core/scene/depMemo.js +36 -18
- package/dist/core/scene/depMemo.js.map +1 -1
- package/dist/core/scene/derivedParts.js +2 -23
- package/dist/core/scene/derivedParts.js.map +1 -1
- package/dist/core/scene/effectivePose.js +10 -0
- package/dist/core/scene/effectivePose.js.map +1 -1
- package/dist/core/scene/historyForm.js +5 -4
- package/dist/core/scene/historyForm.js.map +1 -1
- package/dist/core/scene/kitOps.js +5 -71
- package/dist/core/scene/kitOps.js.map +1 -1
- package/dist/core/scene/kitRegistry.js +5 -0
- package/dist/core/scene/kitRegistry.js.map +1 -1
- package/dist/core/scene/layerOps.js +82 -0
- package/dist/core/scene/layerOps.js.map +1 -0
- package/dist/core/scene/layoutPass.js +14 -12
- package/dist/core/scene/layoutPass.js.map +1 -1
- package/dist/core/scene/lockGuard.js +9 -3
- package/dist/core/scene/lockGuard.js.map +1 -1
- package/dist/core/scene/nestedHit.js +5 -5
- package/dist/core/scene/nestedHit.js.map +1 -1
- package/dist/core/scene/nodeFlags.js +8 -2
- package/dist/core/scene/nodeFlags.js.map +1 -1
- package/dist/core/scene/nodeGates.js +31 -2
- package/dist/core/scene/nodeGates.js.map +1 -1
- package/dist/core/scene/pathEffects/effects.js +22 -3
- package/dist/core/scene/pathEffects/effects.js.map +1 -1
- package/dist/core/scene/pathEffects/textAlong.js +16 -3
- package/dist/core/scene/pathEffects/textAlong.js.map +1 -1
- package/dist/core/scene/pathEffects/textAlongBands.js +65 -0
- package/dist/core/scene/pathEffects/textAlongBands.js.map +1 -0
- package/dist/core/scene/reconcileSpecs.js +1 -1
- package/dist/core/scene/reconcileSpecs.js.map +1 -1
- package/dist/core/scene/scene.js +11 -5
- package/dist/core/scene/scene.js.map +1 -1
- package/dist/core/scene/sceneEdits.js +5 -2
- package/dist/core/scene/sceneEdits.js.map +1 -1
- package/dist/core/scene/scenePoseAdapter.js +10 -1
- package/dist/core/scene/scenePoseAdapter.js.map +1 -1
- package/dist/core/scene/scrollOffsets.js +93 -0
- package/dist/core/scene/scrollOffsets.js.map +1 -0
- package/dist/core/scene/serialization.js +15 -5
- package/dist/core/scene/serialization.js.map +1 -1
- package/dist/core/scene/statedFields.js +2 -1
- package/dist/core/scene/statedFields.js.map +1 -1
- package/dist/core/scene/strategyView.js +35 -0
- package/dist/core/scene/strategyView.js.map +1 -0
- package/dist/core/scene/types.js.map +1 -1
- package/dist/core/scene/useScene.js +2 -0
- package/dist/core/scene/useScene.js.map +1 -1
- package/dist/core/scene/worldSave.js +87 -0
- package/dist/core/scene/worldSave.js.map +1 -0
- package/dist/core/selection/selectionTarget.js +1 -1
- package/dist/core/selection/selectionTarget.js.map +1 -1
- package/dist/{cornerHandles-CNCb7aTY.d.ts → cornerHandles-DpmQM_z5.d.ts} +1 -1
- package/dist/{depSchema-CpIQzKWQ.d.ts → depSchema-C3BwxitB.d.ts} +119 -99
- package/dist/devtools-protocol.d.ts +2 -2
- package/dist/devtools.d.ts +2 -2
- package/dist/{features → domains}/chrome-caps/buildChromeCtx.js +1 -1
- package/dist/domains/chrome-caps/buildChromeCtx.js.map +1 -0
- package/dist/{features → domains}/chrome-caps/conditions.js +1 -1
- package/dist/domains/chrome-caps/conditions.js.map +1 -0
- package/dist/{features → domains}/chrome-caps/defaults.js +1 -1
- package/dist/domains/chrome-caps/defaults.js.map +1 -0
- package/dist/{features → domains}/chrome-caps/resolve.js +1 -1
- package/dist/domains/chrome-caps/resolve.js.map +1 -0
- package/dist/{features → domains}/chrome-caps/useChromeCaps.js +1 -1
- package/dist/domains/chrome-caps/useChromeCaps.js.map +1 -0
- package/dist/{features → domains}/chrome-caps/useHoverTracking.js +1 -1
- package/dist/domains/chrome-caps/useHoverTracking.js.map +1 -0
- package/dist/{features → domains}/ingestion/contentHandlers.js +20 -3
- package/dist/domains/ingestion/contentHandlers.js.map +1 -0
- package/dist/domains/ingestion/ghost.js +56 -0
- package/dist/domains/ingestion/ghost.js.map +1 -0
- package/dist/{features → domains}/ingestion/imageHandler.js +1 -1
- package/dist/domains/ingestion/imageHandler.js.map +1 -0
- package/dist/domains/ingestion/kitHandlers.js +22 -0
- package/dist/domains/ingestion/kitHandlers.js.map +1 -0
- package/dist/{features → domains}/ingestion/openFilePicker.js +1 -1
- package/dist/domains/ingestion/openFilePicker.js.map +1 -0
- package/dist/{features → domains}/ingestion/placement.js +1 -1
- package/dist/domains/ingestion/placement.js.map +1 -0
- package/dist/{features → domains}/ingestion/svgHandler.js +1 -1
- package/dist/domains/ingestion/svgHandler.js.map +1 -0
- package/dist/{features → domains}/ingestion/textHandler.js +9 -7
- package/dist/domains/ingestion/textHandler.js.map +1 -0
- package/dist/{features → domains}/ingestion/useCanvasIngestion.js +13 -15
- package/dist/domains/ingestion/useCanvasIngestion.js.map +1 -0
- package/dist/{features → domains}/ingestion/weaselJsonHandler.js +1 -1
- package/dist/domains/ingestion/weaselJsonHandler.js.map +1 -0
- package/dist/{features → domains}/longPress/longPressFeedback.js +1 -1
- package/dist/domains/longPress/longPressFeedback.js.map +1 -0
- package/dist/{features → domains}/measure/actionIds.js +1 -1
- package/dist/domains/measure/actionIds.js.map +1 -0
- package/dist/{features → domains}/measure/measureCommands.js +1 -1
- package/dist/domains/measure/measureCommands.js.map +1 -0
- package/dist/{features → domains}/measure/measureContribution.js +1 -1
- package/dist/domains/measure/measureContribution.js.map +1 -0
- package/dist/{features → domains}/measure/measureEdits.js +1 -1
- package/dist/domains/measure/measureEdits.js.map +1 -0
- package/dist/{features → domains}/measure/measureGestures.js +4 -7
- package/dist/domains/measure/measureGestures.js.map +1 -0
- package/dist/{features → domains}/measure/measureHit.js +1 -1
- package/dist/domains/measure/measureHit.js.map +1 -0
- package/dist/{features → domains}/measure/measureLayer.js +1 -1
- package/dist/domains/measure/measureLayer.js.map +1 -0
- package/dist/{features → domains}/measure/measurement.js +1 -1
- package/dist/domains/measure/measurement.js.map +1 -0
- package/dist/{features → domains}/measure/measurements.js +2 -2
- package/dist/domains/measure/measurements.js.map +1 -0
- package/dist/{features → domains}/modes/modeLayers.js +1 -1
- package/dist/domains/modes/modeLayers.js.map +1 -0
- package/dist/{features → domains}/modes/modeTriggers.js +3 -6
- package/dist/domains/modes/modeTriggers.js.map +1 -0
- package/dist/{features → domains}/pathEffects/effectSources.js +1 -1
- package/dist/domains/pathEffects/effectSources.js.map +1 -0
- package/dist/{features → domains}/pathEffects/index.js +1 -1
- package/dist/domains/pathEffects/index.js.map +1 -0
- package/dist/{features → domains}/pathEffects/readSource.js +1 -1
- package/dist/domains/pathEffects/readSource.js.map +1 -0
- package/dist/{features → domains}/pathEffects/textItems.js +11 -2
- package/dist/domains/pathEffects/textItems.js.map +1 -0
- package/dist/{features → domains}/pathEffects/useEffectSourcesLayer.js +1 -1
- package/dist/domains/pathEffects/useEffectSourcesLayer.js.map +1 -0
- package/dist/{features → domains}/paths/anchorData.js +1 -1
- package/dist/domains/paths/anchorData.js.map +1 -0
- package/dist/{features → domains}/paths/anchorMarkers.js +9 -7
- package/dist/domains/paths/anchorMarkers.js.map +1 -0
- package/dist/{features → domains}/paths/editablePath.js +1 -1
- package/dist/domains/paths/editablePath.js.map +1 -0
- package/dist/{features → domains}/paths/index.js +3 -3
- package/dist/{features → domains}/paths/originProjection.js +1 -1
- package/dist/domains/paths/originProjection.js.map +1 -0
- package/dist/{features → domains}/paths/pathEditExtension.js +1 -1
- package/dist/domains/paths/pathEditExtension.js.map +1 -0
- package/dist/{features → domains}/paths/pathEditState.js +1 -1
- package/dist/domains/paths/pathEditState.js.map +1 -0
- package/dist/{features → domains}/paths/pathEditingOverlayLayer.js +1 -1
- package/dist/domains/paths/pathEditingOverlayLayer.js.map +1 -0
- package/dist/{features → domains}/paths/pathLayer.js +1 -1
- package/dist/domains/paths/pathLayer.js.map +1 -0
- package/dist/{features → domains}/paths/pathRepresentation.js +1 -1
- package/dist/domains/paths/pathRepresentation.js.map +1 -0
- package/dist/{features → domains}/paths/pathSnap/glyphs.js +1 -1
- package/dist/domains/paths/pathSnap/glyphs.js.map +1 -0
- package/dist/{features → domains}/paths/pathSnap/pathSnapSource.js +1 -1
- package/dist/domains/paths/pathSnap/pathSnapSource.js.map +1 -0
- package/dist/{features → domains}/paths/pathSnap/sceneIndex.js +1 -1
- package/dist/domains/paths/pathSnap/sceneIndex.js.map +1 -0
- package/dist/{features → domains}/paths/pathSnap/snapGeometry.js +3 -2
- package/dist/domains/paths/pathSnap/snapGeometry.js.map +1 -0
- package/dist/{features → domains}/paths/penPreviewLayer.js +1 -1
- package/dist/domains/paths/penPreviewLayer.js.map +1 -0
- package/dist/{features → domains}/paths/shapeGenerator.js +6 -4
- package/dist/domains/paths/shapeGenerator.js.map +1 -0
- package/dist/{features → domains}/paths/strokeOutline.js +1 -1
- package/dist/domains/paths/strokeOutline.js.map +1 -0
- package/dist/{features → domains}/paths/useAnchorFields.js +1 -1
- package/dist/domains/paths/useAnchorFields.js.map +1 -0
- package/dist/{features → domains}/paths/usePathEdit.js +1 -1
- package/dist/domains/paths/usePathEdit.js.map +1 -0
- package/dist/{features → domains}/poseRun/usePoseRun.js +1 -1
- package/dist/domains/poseRun/usePoseRun.js.map +1 -0
- package/dist/{features → domains}/selection/enteredGroupFrame.js +49 -10
- package/dist/domains/selection/enteredGroupFrame.js.map +1 -0
- package/dist/{features → domains}/selection/enteredGroupScope.js +1 -1
- package/dist/domains/selection/enteredGroupScope.js.map +1 -0
- package/dist/domains/selection/enteredOperands.js +29 -0
- package/dist/domains/selection/enteredOperands.js.map +1 -0
- package/dist/{features → domains}/selection/handleCommands.js +1 -1
- package/dist/domains/selection/handleCommands.js.map +1 -0
- package/dist/{features → domains}/selection/overlay.js +1 -1
- package/dist/domains/selection/overlay.js.map +1 -0
- package/dist/{features → domains}/selection/selectionPose.js +1 -1
- package/dist/domains/selection/selectionPose.js.map +1 -0
- package/dist/{features → domains}/snap/angle2d.js +1 -1
- package/dist/domains/snap/angle2d.js.map +1 -0
- package/dist/{features → domains}/snap/debugCandidates.js +1 -1
- package/dist/domains/snap/debugCandidates.js.map +1 -0
- package/dist/{features → domains}/snap/gather.js +1 -1
- package/dist/domains/snap/gather.js.map +1 -0
- package/dist/{features → domains}/snap/inputSubspace.js +1 -1
- package/dist/domains/snap/inputSubspace.js.map +1 -0
- package/dist/{features → domains}/snap/lazySession.js +1 -1
- package/dist/domains/snap/lazySession.js.map +1 -0
- package/dist/{features → domains}/snap/marks.js +1 -1
- package/dist/domains/snap/marks.js.map +1 -0
- package/dist/{features → domains}/snap/outcomeStore.js +1 -1
- package/dist/domains/snap/outcomeStore.js.map +1 -0
- package/dist/{features → domains}/snap/pointSnap.js +1 -1
- package/dist/domains/snap/pointSnap.js.map +1 -0
- package/dist/{features → domains}/snap/probes2d.js +1 -1
- package/dist/domains/snap/probes2d.js.map +1 -0
- package/dist/{features → domains}/snap/readoutDraw.js +1 -1
- package/dist/domains/snap/readoutDraw.js.map +1 -0
- package/dist/{features → domains}/snap/readoutLayer.js +1 -1
- package/dist/domains/snap/readoutLayer.js.map +1 -0
- package/dist/{features → domains}/snap/registry.js +1 -1
- package/dist/domains/snap/registry.js.map +1 -0
- package/dist/{features → domains}/snap/resizeBox.js +1 -1
- package/dist/domains/snap/resizeBox.js.map +1 -0
- package/dist/{features → domains}/snap/roles.js +1 -1
- package/dist/domains/snap/roles.js.map +1 -0
- package/dist/{features → domains}/snap/rotationSource.js +1 -1
- package/dist/domains/snap/rotationSource.js.map +1 -0
- package/dist/{features → domains}/snap/sceneReads.js +24 -3
- package/dist/domains/snap/sceneReads.js.map +1 -0
- package/dist/{features → domains}/snap/sceneSession2d.js +3 -2
- package/dist/domains/snap/sceneSession2d.js.map +1 -0
- package/dist/{features → domains}/snap/screen.js +1 -1
- package/dist/domains/snap/screen.js.map +1 -0
- package/dist/{features → domains}/snap/session2d.js +3 -2
- package/dist/domains/snap/session2d.js.map +1 -0
- package/dist/{features → domains}/snap/spanSnap.js +1 -1
- package/dist/domains/snap/spanSnap.js.map +1 -0
- package/dist/{features → domains}/snap/stepAngles.js +1 -1
- package/dist/domains/snap/stepAngles.js.map +1 -0
- package/dist/{features → domains}/text/editingDrawOne.js +4 -4
- package/dist/domains/text/editingDrawOne.js.map +1 -0
- package/dist/domains/text/hostTextEditors.js +24 -0
- package/dist/domains/text/hostTextEditors.js.map +1 -0
- package/dist/{features → domains}/text/index.js +1 -1
- package/dist/{features → domains}/text/sceneTextDrafts.js +1 -1
- package/dist/domains/text/sceneTextDrafts.js.map +1 -0
- package/dist/{features → domains}/text/textHitAt.js +18 -2
- package/dist/domains/text/textHitAt.js.map +1 -0
- package/dist/{features → domains}/text/textLayer.js +1 -1
- package/dist/domains/text/textLayer.js.map +1 -0
- package/dist/{features → domains}/text/useSceneTextEdit.js +11 -3
- package/dist/domains/text/useSceneTextEdit.js.map +1 -0
- package/dist/{features → domains}/viewports/aim.js +1 -1
- package/dist/domains/viewports/aim.js.map +1 -0
- package/dist/{features → domains}/viewports/viewMarker.js +23 -5
- package/dist/domains/viewports/viewMarker.js.map +1 -0
- package/dist/{features → domains}/viewports/viewMarkerDrag.js +3 -3
- package/dist/domains/viewports/viewMarkerDrag.js.map +1 -0
- package/dist/{features → domains}/viewports/viewResolver.js +1 -1
- package/dist/domains/viewports/viewResolver.js.map +1 -0
- package/dist/{features → domains}/viewports/viewportLayer.js +1 -1
- package/dist/domains/viewports/viewportLayer.js.map +1 -0
- package/dist/icons.table.js +1 -1
- package/dist/icons.table.js.map +1 -1
- package/dist/icons.table.json +106 -6
- package/dist/index.d.ts +1441 -1050
- package/dist/index.js +90 -77
- package/dist/interactions/actions/admitsChild.js +6 -2
- package/dist/interactions/actions/admitsChild.js.map +1 -1
- package/dist/interactions/actions/align/align.js +1 -4
- package/dist/interactions/actions/align/align.js.map +1 -1
- package/dist/interactions/actions/booleans/booleanGroupAction.js +66 -0
- package/dist/interactions/actions/booleans/booleanGroupAction.js.map +1 -0
- package/dist/interactions/actions/booleans/keymap.js +52 -0
- package/dist/interactions/actions/booleans/keymap.js.map +1 -0
- package/dist/interactions/actions/booleans/operands.js +1 -1
- package/dist/interactions/actions/booleans/pieces.js +4 -11
- package/dist/interactions/actions/booleans/pieces.js.map +1 -1
- package/dist/interactions/actions/clipboard/action.js +3 -7
- package/dist/interactions/actions/clipboard/action.js.map +1 -1
- package/dist/interactions/actions/clipboard/clipboardOps.js +1 -1
- package/dist/interactions/actions/clipboard/clipboardOps.js.map +1 -1
- package/dist/interactions/actions/clipboard/materializePaste.js.map +1 -1
- package/dist/interactions/actions/defaults/anchorEditing.js +6 -6
- package/dist/interactions/actions/defaults/anchorEditing.js.map +1 -1
- package/dist/interactions/actions/defaults/bendSegment.js +1 -1
- package/dist/interactions/actions/defaults/bendSegment.js.map +1 -1
- package/dist/interactions/actions/defaults/containerScroll.js +170 -0
- package/dist/interactions/actions/defaults/containerScroll.js.map +1 -0
- package/dist/interactions/actions/defaults/contextMenu.js +2 -5
- package/dist/interactions/actions/defaults/contextMenu.js.map +1 -1
- package/dist/interactions/actions/defaults/delete.js +1 -1
- package/dist/interactions/actions/defaults/delete.js.map +1 -1
- package/dist/interactions/actions/defaults/duplicate.js +1 -3
- package/dist/interactions/actions/defaults/duplicate.js.map +1 -1
- package/dist/interactions/actions/defaults/enterGroup.js +7 -12
- package/dist/interactions/actions/defaults/enterGroup.js.map +1 -1
- package/dist/interactions/actions/defaults/enterPathEdit.js +4 -8
- package/dist/interactions/actions/defaults/enterPathEdit.js.map +1 -1
- package/dist/interactions/actions/defaults/group.js +12 -24
- package/dist/interactions/actions/defaults/group.js.map +1 -1
- package/dist/interactions/actions/defaults/ingest.js +18 -10
- package/dist/interactions/actions/defaults/ingest.js.map +1 -1
- package/dist/interactions/actions/defaults/insertPathAnchor.js +3 -3
- package/dist/interactions/actions/defaults/insertPathAnchor.js.map +1 -1
- package/dist/interactions/actions/defaults/nudgeSteps.js +3 -21
- package/dist/interactions/actions/defaults/nudgeSteps.js.map +1 -1
- package/dist/interactions/actions/defaults/pathEditMarks.js.map +1 -1
- package/dist/interactions/actions/defaults/selectDeep.js +2 -2
- package/dist/interactions/actions/defaults/selectDeep.js.map +1 -1
- package/dist/interactions/actions/distribute/distribute.js.map +1 -1
- package/dist/interactions/actions/dropVerdict.js +9 -0
- package/dist/interactions/actions/dropVerdict.js.map +1 -0
- package/dist/interactions/actions/edit-anchors/action.js +2 -2
- package/dist/interactions/actions/edit-anchors/action.js.map +1 -1
- package/dist/interactions/actions/edit-anchors/extensionDrags.js.map +1 -1
- package/dist/interactions/actions/edit-anchors/geometry.js +8 -6
- package/dist/interactions/actions/edit-anchors/geometry.js.map +1 -1
- package/dist/interactions/actions/edit-anchors/handleDrag.js.map +1 -1
- package/dist/interactions/actions/edit-anchors/preview.js +1 -1
- package/dist/interactions/actions/edit-anchors/preview.js.map +1 -1
- package/dist/interactions/actions/flip/action.js +3 -2
- package/dist/interactions/actions/flip/action.js.map +1 -1
- package/dist/interactions/actions/geometryProjection.js +8 -3
- package/dist/interactions/actions/geometryProjection.js.map +1 -1
- package/dist/interactions/actions/gestureFrames.js +1 -0
- package/dist/interactions/actions/gestureFrames.js.map +1 -1
- package/dist/interactions/actions/insert/action.js +6 -2
- package/dist/interactions/actions/insert/action.js.map +1 -1
- package/dist/interactions/actions/insert/frame.js +1 -1
- package/dist/interactions/actions/insert/frame.js.map +1 -1
- package/dist/interactions/actions/insert/placeAction.js +6 -8
- package/dist/interactions/actions/insert/placeAction.js.map +1 -1
- package/dist/interactions/actions/insert/session.js +2 -2
- package/dist/interactions/actions/insert/session.js.map +1 -1
- package/dist/interactions/actions/move/action.js +6 -15
- package/dist/interactions/actions/move/action.js.map +1 -1
- package/dist/interactions/actions/move/behaviors/layoutDrop.js +12 -2
- package/dist/interactions/actions/move/behaviors/layoutDrop.js.map +1 -1
- package/dist/interactions/actions/move/behaviors/reparentOnDrop.js +29 -10
- package/dist/interactions/actions/move/behaviors/reparentOnDrop.js.map +1 -1
- package/dist/interactions/actions/move/behaviors/snapToContainer.js +42 -6
- package/dist/interactions/actions/move/behaviors/snapToContainer.js.map +1 -1
- package/dist/interactions/actions/move/capture.js +4 -8
- package/dist/interactions/actions/move/capture.js.map +1 -1
- package/dist/interactions/actions/move/commit/index.js.map +1 -1
- package/dist/interactions/actions/move/commit/layoutDrop.js +4 -3
- package/dist/interactions/actions/move/commit/layoutDrop.js.map +1 -1
- package/dist/interactions/actions/move/commit/layoutRelease.js +15 -9
- package/dist/interactions/actions/move/commit/layoutRelease.js.map +1 -1
- package/dist/interactions/actions/move/commit/reparent.js +19 -13
- package/dist/interactions/actions/move/commit/reparent.js.map +1 -1
- package/dist/interactions/actions/move/delta.js +51 -5
- package/dist/interactions/actions/move/delta.js.map +1 -1
- package/dist/interactions/actions/move/frame.js +8 -4
- package/dist/interactions/actions/move/frame.js.map +1 -1
- package/dist/interactions/actions/move/layout/container.js +19 -9
- package/dist/interactions/actions/move/layout/container.js.map +1 -1
- package/dist/interactions/actions/move/layout/dragged.js +2 -2
- package/dist/interactions/actions/move/layout/dragged.js.map +1 -1
- package/dist/interactions/actions/move/layout/dropPass.js +36 -18
- package/dist/interactions/actions/move/layout/dropPass.js.map +1 -1
- package/dist/interactions/actions/move/layout/exits.js +2 -2
- package/dist/interactions/actions/move/layout/exits.js.map +1 -1
- package/dist/interactions/actions/move/layout/glide.js +5 -5
- package/dist/interactions/actions/move/layout/glide.js.map +1 -1
- package/dist/interactions/actions/move/layout/view.js +55 -0
- package/dist/interactions/actions/move/layout/view.js.map +1 -0
- package/dist/interactions/actions/move/refusal.js +52 -0
- package/dist/interactions/actions/move/refusal.js.map +1 -0
- package/dist/interactions/actions/move/session.js +9 -8
- package/dist/interactions/actions/move/session.js.map +1 -1
- package/dist/interactions/actions/move/translate.js +10 -4
- package/dist/interactions/actions/move/translate.js.map +1 -1
- package/dist/interactions/actions/moveNodes.js +21 -5
- package/dist/interactions/actions/moveNodes.js.map +1 -1
- package/dist/interactions/actions/pathCommands/pathNodes.js +3 -3
- package/dist/interactions/actions/pathCommands/pathNodes.js.map +1 -1
- package/dist/interactions/actions/planeInput.js +14 -13
- package/dist/interactions/actions/planeInput.js.map +1 -1
- package/dist/interactions/actions/poseFrame.js +21 -8
- package/dist/interactions/actions/poseFrame.js.map +1 -1
- package/dist/interactions/actions/resize/action.js +1 -1
- package/dist/interactions/actions/resize/action.js.map +1 -1
- package/dist/interactions/actions/resize/aspect.js +1 -1
- package/dist/interactions/actions/resize/aspect.js.map +1 -1
- package/dist/interactions/actions/resize/commit.js +10 -1
- package/dist/interactions/actions/resize/commit.js.map +1 -1
- package/dist/interactions/actions/resize/frame.js +3 -2
- package/dist/interactions/actions/resize/frame.js.map +1 -1
- package/dist/interactions/actions/resize/held.js +44 -0
- package/dist/interactions/actions/resize/held.js.map +1 -0
- package/dist/interactions/actions/resize/session.js +3 -1
- package/dist/interactions/actions/resize/session.js.map +1 -1
- package/dist/interactions/actions/resolveOverlays.js +9 -0
- package/dist/interactions/actions/resolveOverlays.js.map +1 -1
- package/dist/interactions/actions/resolvePreviews.js +23 -7
- package/dist/interactions/actions/resolvePreviews.js.map +1 -1
- package/dist/interactions/actions/rotate/action.js +1 -1
- package/dist/interactions/actions/rotate/action.js.map +1 -1
- package/dist/interactions/actions/rotate/frame.js +1 -1
- package/dist/interactions/actions/rotate/frame.js.map +1 -1
- package/dist/interactions/actions/rotate/session.js +2 -2
- package/dist/interactions/actions/rotate/session.js.map +1 -1
- package/dist/interactions/actions/selectionSubtree.js +2 -4
- package/dist/interactions/actions/selectionSubtree.js.map +1 -1
- package/dist/interactions/actions/spatialReference.js +4 -9
- package/dist/interactions/actions/spatialReference.js.map +1 -1
- package/dist/interactions/gestures/dragRadial/dragRadial.js.map +1 -1
- package/dist/interactions/gestures/dragRect/dragRect.js.map +1 -1
- package/dist/kitSettingsSchema.js +2 -2
- package/dist/kitSettingsSchema.js.map +1 -1
- package/dist/{math-C_elShP_.d.ts → math-B_unOnF4.d.ts} +2 -2
- package/dist/math.d.ts +3 -3
- package/dist/move.d.ts +6 -6
- package/dist/{options-ClEm3SEl.d.ts → options-DAjkhbcs.d.ts} +5 -5
- package/dist/{poseDescriptor-DN2yfnq_.d.ts → poseDescriptor-CvSxVhCd.d.ts} +17 -4
- package/dist/resize.d.ts +6 -6
- package/dist/style.css +14 -0
- package/dist/test-seams.d.ts +11 -15
- package/dist/test-seams.js +1 -1
- package/dist/tools/builtin/eyedropper/useEyedropperTool.js +3 -6
- package/dist/tools/builtin/eyedropper/useEyedropperTool.js.map +1 -1
- package/dist/tools/builtin/line/useLineTool.js.map +1 -1
- package/dist/tools/builtin/measure/useMeasureTool.js +2 -2
- package/dist/tools/builtin/measure/useMeasureTool.js.map +1 -1
- package/dist/tools/builtin/pen/penHandle.js +2 -2
- package/dist/tools/builtin/pen/penHandle.js.map +1 -1
- package/dist/tools/builtin/pen/usePenTool.js +13 -19
- package/dist/tools/builtin/pen/usePenTool.js.map +1 -1
- package/dist/tools/builtin/polygon/usePolygonTool.js +1 -1
- package/dist/tools/builtin/polygon/usePolygonTool.js.map +1 -1
- package/dist/tools/builtin/select/groupEntry.js +1 -1
- package/dist/tools/builtin/select/groupEntry.js.map +1 -1
- package/dist/tools/builtin/select/selectionContributions.js +1 -1
- package/dist/tools/builtin/select/selectionContributions.js.map +1 -1
- package/dist/tools/builtin/select/useSelectTool.js +7 -7
- package/dist/tools/builtin/select/useSelectTool.js.map +1 -1
- package/dist/tools/builtin/slice/useSliceTool.js +5 -8
- package/dist/tools/builtin/slice/useSliceTool.js.map +1 -1
- package/dist/tools/builtin/star/useStarTool.js +1 -1
- package/dist/tools/builtin/star/useStarTool.js.map +1 -1
- package/dist/tools/index.js +2 -1
- package/dist/{types-49uYJN3j.d.ts → types-A_sNJYRd.d.ts} +8 -0
- package/dist/{types-BEdRIhNc.d.ts → types-DW14eu9B.d.ts} +131 -36
- package/dist/{types-p2alu-R1.d.ts → types-VCtfchp-.d.ts} +4 -6
- package/dist/util/color.js +12 -14
- package/dist/util/color.js.map +1 -1
- package/dist/version.js +1 -1
- package/package.json +25 -24
- package/dist/canvas/poseCascade.js +0 -65
- package/dist/canvas/poseCascade.js.map +0 -1
- package/dist/features/chrome-caps/buildChromeCtx.js.map +0 -1
- package/dist/features/chrome-caps/conditions.js.map +0 -1
- package/dist/features/chrome-caps/defaults.js.map +0 -1
- package/dist/features/chrome-caps/resolve.js.map +0 -1
- package/dist/features/chrome-caps/useChromeCaps.js.map +0 -1
- package/dist/features/chrome-caps/useHoverTracking.js.map +0 -1
- package/dist/features/ingestion/contentHandlers.js.map +0 -1
- package/dist/features/ingestion/imageHandler.js.map +0 -1
- package/dist/features/ingestion/openFilePicker.js.map +0 -1
- package/dist/features/ingestion/placement.js.map +0 -1
- package/dist/features/ingestion/registerKitHandlers.js +0 -43
- package/dist/features/ingestion/registerKitHandlers.js.map +0 -1
- package/dist/features/ingestion/svgHandler.js.map +0 -1
- package/dist/features/ingestion/textHandler.js.map +0 -1
- package/dist/features/ingestion/useCanvasIngestion.js.map +0 -1
- package/dist/features/ingestion/weaselJsonHandler.js.map +0 -1
- package/dist/features/longPress/longPressFeedback.js.map +0 -1
- package/dist/features/measure/actionIds.js.map +0 -1
- package/dist/features/measure/measureCommands.js.map +0 -1
- package/dist/features/measure/measureContribution.js.map +0 -1
- package/dist/features/measure/measureEdits.js.map +0 -1
- package/dist/features/measure/measureGestures.js.map +0 -1
- package/dist/features/measure/measureHit.js.map +0 -1
- package/dist/features/measure/measureLayer.js.map +0 -1
- package/dist/features/measure/measurement.js.map +0 -1
- package/dist/features/measure/measurements.js.map +0 -1
- package/dist/features/modes/modeLayers.js.map +0 -1
- package/dist/features/modes/modeTriggers.js.map +0 -1
- package/dist/features/pathEffects/effectSources.js.map +0 -1
- package/dist/features/pathEffects/index.js.map +0 -1
- package/dist/features/pathEffects/readSource.js.map +0 -1
- package/dist/features/pathEffects/textItems.js.map +0 -1
- package/dist/features/pathEffects/useEffectSourcesLayer.js.map +0 -1
- package/dist/features/paths/anchorData.js.map +0 -1
- package/dist/features/paths/anchorMarkers.js.map +0 -1
- package/dist/features/paths/editablePath.js.map +0 -1
- package/dist/features/paths/originProjection.js.map +0 -1
- package/dist/features/paths/pathEditExtension.js.map +0 -1
- package/dist/features/paths/pathEditState.js.map +0 -1
- package/dist/features/paths/pathEditingOverlayLayer.js.map +0 -1
- package/dist/features/paths/pathLayer.js.map +0 -1
- package/dist/features/paths/pathRepresentation.js.map +0 -1
- package/dist/features/paths/pathSnap/glyphs.js.map +0 -1
- package/dist/features/paths/pathSnap/pathSnapSource.js.map +0 -1
- package/dist/features/paths/pathSnap/sceneIndex.js.map +0 -1
- package/dist/features/paths/pathSnap/snapGeometry.js.map +0 -1
- package/dist/features/paths/penPreviewLayer.js.map +0 -1
- package/dist/features/paths/shapeGenerator.js.map +0 -1
- package/dist/features/paths/strokeOutline.js.map +0 -1
- package/dist/features/paths/useAnchorFields.js.map +0 -1
- package/dist/features/paths/usePathEdit.js.map +0 -1
- package/dist/features/poseRun/usePoseRun.js.map +0 -1
- package/dist/features/selection/enteredGroupFrame.js.map +0 -1
- package/dist/features/selection/enteredGroupScope.js.map +0 -1
- package/dist/features/selection/handleCommands.js.map +0 -1
- package/dist/features/selection/overlay.js.map +0 -1
- package/dist/features/selection/selectionPose.js.map +0 -1
- package/dist/features/snap/angle2d.js.map +0 -1
- package/dist/features/snap/debugCandidates.js.map +0 -1
- package/dist/features/snap/gather.js.map +0 -1
- package/dist/features/snap/inputSubspace.js.map +0 -1
- package/dist/features/snap/lazySession.js.map +0 -1
- package/dist/features/snap/marks.js.map +0 -1
- package/dist/features/snap/outcomeStore.js.map +0 -1
- package/dist/features/snap/pointSnap.js.map +0 -1
- package/dist/features/snap/probes2d.js.map +0 -1
- package/dist/features/snap/readoutDraw.js.map +0 -1
- package/dist/features/snap/readoutLayer.js.map +0 -1
- package/dist/features/snap/registry.js.map +0 -1
- package/dist/features/snap/resizeBox.js.map +0 -1
- package/dist/features/snap/roles.js.map +0 -1
- package/dist/features/snap/rotationSource.js.map +0 -1
- package/dist/features/snap/sceneReads.js.map +0 -1
- package/dist/features/snap/sceneSession2d.js.map +0 -1
- package/dist/features/snap/screen.js.map +0 -1
- package/dist/features/snap/session2d.js.map +0 -1
- package/dist/features/snap/spanSnap.js.map +0 -1
- package/dist/features/snap/stepAngles.js.map +0 -1
- package/dist/features/text/editingDrawOne.js.map +0 -1
- package/dist/features/text/sceneTextDrafts.js.map +0 -1
- package/dist/features/text/textHitAt.js.map +0 -1
- package/dist/features/text/textLayer.js.map +0 -1
- package/dist/features/text/useSceneTextEdit.js.map +0 -1
- package/dist/features/viewports/aim.js.map +0 -1
- package/dist/features/viewports/viewMarker.js.map +0 -1
- package/dist/features/viewports/viewMarkerDrag.js.map +0 -1
- package/dist/features/viewports/viewResolver.js.map +0 -1
- package/dist/features/viewports/viewportLayer.js.map +0 -1
- /package/dist/{features → domains}/chrome-caps/index.js +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handleCommands.js","names":[],"sources":["../../../src/domains/selection/handleCommands.ts"],"sourcesContent":["/**\n * The selection overlay's resize handles: their style, where the kit puts\n * them, and the commands that paint them.\n */\n\nimport type { DrawCommand, GlMat3 } from '@weasel-js/renderer';\nimport { alignedStrokeRect, type CommandStroke, type CommandFill } from '@weasel-js/paint';\nimport { resolveStrokeWidth } from '@weasel-js/stroke';\nimport { screenAngleOf } from '@weasel-js/geom';\nimport { angleOf, localToWorld, targetTransformOf } from 'core/geometry/targetFrame';\nimport type { Bounds } from 'core/viewport/fitViewToBounds';\nimport type { View } from 'core/viewport/view';\nimport { viewToTransform } from 'core/viewport/view';\nimport { worldToScreen } from 'core/viewport/viewTransform';\nimport { HANDLE_BASE_PX } from 'core/device/targets';\nimport {\n handlePoint, resizeHandlesFor, type ResizeHandleLayout,\n} from 'interactions/actions/resize/cornerHandles';\n\nexport type { ResizeHandleLayout };\n\nconst DEFAULT_HANDLE_FILL: CommandFill = { paint: { kind: 'solid', color: '#d4c4a8' } };\nconst DEFAULT_HANDLE_OUTLINE: CommandStroke = {\n paint: { kind: 'solid', color: '#1a130d' },\n width: 1,\n};\nconst DEFAULT_HANDLE_SIZE = HANDLE_BASE_PX;\n\n\n/** Handle visuals, as a consumer supplies them. */\nexport interface SelectionHandleStyle {\n size?: number;\n fill?: CommandFill;\n outline?: CommandStroke;\n}\n\nexport interface ResolvedHandles {\n size: number;\n fill: CommandFill;\n outline: CommandStroke;\n}\n\nexport function resolveHandles(opts?: SelectionHandleStyle): ResolvedHandles {\n return {\n size: opts?.size ?? DEFAULT_HANDLE_SIZE,\n fill: opts?.fill ?? DEFAULT_HANDLE_FILL,\n outline: opts?.outline ?? DEFAULT_HANDLE_OUTLINE,\n };\n}\n\n/** GL helper: emit a closed rect path (kind:'rect'). */\nexport function rectPathFor(x: number, y: number, width: number, height: number): { kind: 'rect'; x: number; y: number; width: number; height: number } {\n return { kind: 'rect', x, y, width, height };\n}\n\n/**\n * GL helper: build the matrix `translate(cx, cy) * rotate(θ) * translate(-cx, -cy)`\n * used to wrap rotated outline / handle commands.\n */\nfunction rotateAroundMat3(cx: number, cy: number, theta: number): GlMat3 {\n const c = Math.cos(theta);\n const s = Math.sin(theta);\n // Composed in column-major (matches mat3 helpers): T(cx,cy) · R(θ) · T(-cx,-cy).\n // After expansion: a=c, b=s, c'=-s, d=c, tx=cx - c*cx + s*cy, ty=cy - s*cx - c*cy.\n const tx = cx - c * cx + s * cy;\n const ty = cy - s * cx - c * cy;\n return new Float32Array([\n c, s, 0,\n -s, c, 0,\n tx, ty, 1,\n ]) as GlMat3;\n}\n\n/** GL helper: emit handle fill+stroke commands for one bounds entry. */\nexport function handleCommandsFor(\n ids: readonly string[],\n resolveBounds: (id: string) => Bounds | null,\n handles: ResolvedHandles,\n handlesOf: ((b: Bounds) => { x: number; y: number }[]) | undefined,\n layoutOpts: Partial<ResizeHandleLayout> | undefined,\n view: View,\n): DrawCommand[] {\n const layout: ResizeHandleLayout = { edges: true, hitRadiusPx: HANDLE_BASE_PX, ...layoutOpts };\n const out: DrawCommand[] = [];\n const half = handles.size / 2;\n const handleAlign = handles.outline.align ?? 'center';\n const handleWidth = resolveStrokeWidth(handles.outline.width ?? 1, 1);\n for (const id of ids) {\n const worldB = resolveBounds(id);\n if (!worldB) continue;\n // Framed in world, then projected: turning the projected point instead\n // lands somewhere else under non-uniform zoom.\n const xf = targetTransformOf(worldB);\n const t = viewToTransform(view);\n const angle = screenAngleOf(angleOf(xf), view.scale);\n const at = handlesOf\n ? handlesOf(worldB)\n : resizeHandlesFor(layout, worldB, xf, view.scale).map((c) => handlePoint(worldB, c));\n for (const hLocal of at) {\n const hWorld = localToWorld(xf, hLocal.x, hLocal.y);\n const [hsx, hsy] = worldToScreen(hWorld.x, hWorld.y, t);\n const center = { x: hsx, y: hsy };\n const baseRect = {\n x: center.x - half,\n y: center.y - half,\n width: handles.size,\n height: handles.size,\n };\n const sr = alignedStrokeRect(baseRect, handleAlign, handleWidth);\n const fillCmd: DrawCommand = {\n kind: 'path',\n path: rectPathFor(baseRect.x, baseRect.y, baseRect.width, baseRect.height),\n fill: handles.fill,\n };\n const strokeCmd: DrawCommand = {\n kind: 'path',\n path: rectPathFor(sr.x, sr.y, sr.width, sr.height),\n stroke: handles.outline,\n };\n if (angle === 0) {\n out.push(fillCmd, strokeCmd);\n } else {\n out.push({\n kind: 'group',\n transform: rotateAroundMat3(center.x, center.y, angle),\n children: [fillCmd, strokeCmd],\n });\n }\n }\n }\n return out;\n}\n"],"mappings":";;;;;;;;;;AAqBA,IAAM,sBAAmC,EAAE,OAAO;CAAE,MAAM;CAAS,OAAO;AAAU,EAAE;AACtF,IAAM,yBAAwC;CAC5C,OAAO;EAAE,MAAM;EAAS,OAAO;CAAU;CACzC,OAAO;AACT;AACA,IAAM,sBAAsB;AAgB5B,SAAgB,eAAe,MAA8C;CAC3E,OAAO;EACL,MAAM,MAAM,QAAQ;EACpB,MAAM,MAAM,QAAQ;EACpB,SAAS,MAAM,WAAW;CAC5B;AACF;;AAGA,SAAgB,YAAY,GAAW,GAAW,OAAe,QAAuF;CACtJ,OAAO;EAAE,MAAM;EAAQ;EAAG;EAAG;EAAO;CAAO;AAC7C;;;;;AAMA,SAAS,iBAAiB,IAAY,IAAY,OAAuB;CACvE,MAAM,IAAI,KAAK,IAAI,KAAK;CACxB,MAAM,IAAI,KAAK,IAAI,KAAK;CAGxB,MAAM,KAAK,KAAK,IAAI,KAAK,IAAI;CAC7B,MAAM,KAAK,KAAK,IAAI,KAAK,IAAI;CAC7B,OAAO,IAAI,aAAa;EACtB;EAAG;EAAG;EACN,CAAC;EAAG;EAAG;EACP;EAAI;EAAI;CACV,CAAC;AACH;;AAGA,SAAgB,kBACd,KACA,eACA,SACA,WACA,YACA,MACe;CACf,MAAM,SAA6B;EAAE,OAAO;EAAM,aAAa;EAAgB,GAAG;CAAW;CAC7F,MAAM,MAAqB,CAAC;CAC5B,MAAM,OAAO,QAAQ,OAAO;CAC5B,MAAM,cAAc,QAAQ,QAAQ,SAAS;CAC7C,MAAM,cAAc,mBAAmB,QAAQ,QAAQ,SAAS,GAAG,CAAC;CACpE,KAAK,MAAM,MAAM,KAAK;EACpB,MAAM,SAAS,cAAc,EAAE;EAC/B,IAAI,CAAC,QAAQ;EAGb,MAAM,KAAK,kBAAkB,MAAM;EACnC,MAAM,IAAI,gBAAgB,IAAI;EAC9B,MAAM,QAAQ,cAAc,QAAQ,EAAE,GAAG,KAAK,KAAK;EACnD,MAAM,KAAK,YACP,UAAU,MAAM,IAChB,iBAAiB,QAAQ,QAAQ,IAAI,KAAK,KAAK,CAAC,CAAC,KAAK,MAAM,YAAY,QAAQ,CAAC,CAAC;EACtF,KAAK,MAAM,UAAU,IAAI;GACvB,MAAM,SAAS,aAAa,IAAI,OAAO,GAAG,OAAO,CAAC;GAClD,MAAM,CAAC,KAAK,OAAO,cAAc,OAAO,GAAG,OAAO,GAAG,CAAC;GACtD,MAAM,SAAS;IAAE,GAAG;IAAK,GAAG;GAAI;GAChC,MAAM,WAAW;IACf,GAAG,OAAO,IAAI;IACd,GAAG,OAAO,IAAI;IACd,OAAO,QAAQ;IACf,QAAQ,QAAQ;GAClB;GACA,MAAM,KAAK,kBAAkB,UAAU,aAAa,WAAW;GAC/D,MAAM,UAAuB;IAC3B,MAAM;IACN,MAAM,YAAY,SAAS,GAAG,SAAS,GAAG,SAAS,OAAO,SAAS,MAAM;IACzE,MAAM,QAAQ;GAChB;GACA,MAAM,YAAyB;IAC7B,MAAM;IACN,MAAM,YAAY,GAAG,GAAG,GAAG,GAAG,GAAG,OAAO,GAAG,MAAM;IACjD,QAAQ,QAAQ;GAClB;GACA,IAAI,UAAU,GACZ,IAAI,KAAK,SAAS,SAAS;QAE3B,IAAI,KAAK;IACP,MAAM;IACN,WAAW,iBAAiB,OAAO,GAAG,OAAO,GAAG,KAAK;IACrD,UAAU,CAAC,SAAS,SAAS;GAC/B,CAAC;EAEL;CACF;CACA,OAAO;AACT"}
|
|
@@ -11,7 +11,7 @@ import { PATH_L, PATH_M, PATH_Z } from "@weasel-js/geom";
|
|
|
11
11
|
import { alignedStrokeRect } from "@weasel-js/paint";
|
|
12
12
|
import { resolveStrokeWidth } from "@weasel-js/stroke";
|
|
13
13
|
|
|
14
|
-
//#region src/
|
|
14
|
+
//#region src/domains/selection/overlay.ts
|
|
15
15
|
/** Project world AABB into screen-space AABB using the active view. */
|
|
16
16
|
function projectBounds(b, view) {
|
|
17
17
|
const t = viewToTransform(view);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"overlay.js","names":[],"sources":["../../../src/domains/selection/overlay.ts"],"sourcesContent":["/**\n * Selection overlay primitives — render layers for drawing selection\n * outlines and resize handles.\n *\n * **Pose shape:** TPose is generic; callers pass `poseDescriptor` for poses\n * `AUTO_POSE_DESCRIPTOR` can't read. Container ids reduce via `unionAABB`\n * over the projected AABBs.\n */\n\nimport type { DrawCommand } from '@weasel-js/renderer';\nimport { mat3, type GlMat3 } from '@weasel-js/renderer';\nimport type { NodeId } from 'core/scene/types';\nimport type { RenderLayer } from 'core/layers/render';\nimport type { PoseDescriptor } from 'core/geometry/poseDescriptor';\nimport type { DrawnBoundsScene } from 'canvas/drawnBounds';\nimport { containerAwareBoundsResolver } from './selectionPose';\nimport { targetCorners, targetTransformOf, type TargetTransform } from 'core/geometry/targetFrame';\nimport { AUTO_POSE_DESCRIPTOR } from 'core/geometry/autoPoseDescriptor';\nimport { alignedStrokeRect, type CommandStroke } from '@weasel-js/paint';\nimport { resolveStrokeWidth } from '@weasel-js/stroke';\nimport {\n rotationHandle,\n DEFAULT_ROTATION_HANDLE_DISTANCE,\n} from 'interactions/actions/rotate/handle';\nimport type { Bounds } from 'core/viewport/fitViewToBounds';\nimport type { ChromeState } from 'core/selection/chromeState';\nimport { MULTI_RESIZE_TARGET_ID } from 'core/selection/selectionTarget';\nimport type { View } from 'core/viewport/view';\nimport { viewToTransform } from 'core/viewport/view';\nimport { worldToScreen } from 'core/viewport/viewTransform';\nimport { PATH_L, PATH_M, PATH_Z, type PolygonPath } from '@weasel-js/geom';\nimport {\n handleCommandsFor, rectPathFor, resolveHandles, type ResizeHandleLayout, type ResolvedHandles, type SelectionHandleStyle,\n} from './handleCommands';\n\nexport type { SelectionHandleStyle };\n\nexport { composeSelectionPose, type ComposeSelectionPoseOpts } from './selectionPose';\n\n/** Project world AABB into screen-space AABB using the active view. */\nfunction projectBounds<B extends Bounds>(b: B, view: View): B {\n const t = viewToTransform(view);\n const [sx, sy] = worldToScreen(b.x, b.y, t);\n return { ...b, x: sx, y: sy, width: b.width * view.scale.x, height: b.height * view.scale.y };\n}\n\n\n/** Options every selection layer shares. `getSelection` and `getPose` are\n * declared on {@link SelectionOverlayLayerOpts}, which makes both optional —\n * omitted, they come off the draw envelope. */\ninterface SelectionLayerCommon<TPose> {\n /** How to read poses. Default `AUTO_POSE_DESCRIPTOR`. */\n poseDescriptor?: PoseDescriptor<TPose>;\n /** Walk a container's direct children (e.g. `scene.childrenOf`). When\n * supplied with `isContainer`, any id that resolves to a container is\n * rendered using the union bounds of all its transitive leaves. */\n getChildren?: (id: string) => readonly string[];\n /** True when `id` is a structural container. */\n isContainer?: (id: string) => boolean;\n /** The nodes behind the ids `getPose` answers for. With it, a stroked\n * node's chrome sits on its stroke (`drawnBoundsOf`); without, on its\n * pose box. Ignored when bounds come off the draw envelope. */\n scene?: DrawnBoundsScene;\n}\n\n/** Options for `createSelectionOutlineLayer`. The overlay layer's options\n * minus the handle visuals — the two run the same body. */\nexport type SelectionOutlineLayerOpts<TPose> =\n Omit<SelectionOverlayLayerOpts<TPose>, 'handles' | 'handlesOf' | 'resizeHandles' | 'rotationHandle'>;\n\n/** Options for `createSelectionHandlesLayer`. The overlay layer's options\n * minus the outline stroke — the two run the same body. */\nexport type SelectionHandlesLayerOpts<TPose> =\n Omit<SelectionOverlayLayerOpts<TPose>, 'outline'>;\n\n/** Options for `createSelectionOverlayLayer`. */\nexport interface SelectionOverlayLayerOpts<TPose>\n extends SelectionLayerCommon<TPose> {\n /**\n * Which ids to draw chrome for. Omit to take them from the `ChromeState` on\n * the draw envelope, which is what makes one canvas's several views each\n * outline their own selection — the layer is shared, the envelope is not.\n */\n getSelection?: () => readonly NodeId[];\n /**\n * Resolve an id to the pose to draw chrome around. Return null to skip an\n * id. Omit to take bounds from the same envelope `getSelection` omitted\n * takes ids from.\n *\n * Takes `string` rather than `NodeId` because the container-aware resolver\n * walks expanded leaf ids via `getChildren`, which is generic over strings.\n */\n getPose?: (id: string) => TPose | null;\n outline?: CommandStroke & { pad?: number };\n /** Pass `false` to render outlines only. */\n handles?: SelectionHandleStyle | false;\n /** Where to paint handles, in the bounds' own frame. Replaces the kit's\n * layout, `resizeHandles` included. */\n handlesOf?: (bounds: Bounds) => { x: number; y: number }[];\n /** The layout the resize affordance hits by: its `hitRadiusPx`, never\n * `handles.size`, decides which edge handles are painted. Default: edges on,\n * at the kit's default hit radius. */\n resizeHandles?: Partial<ResizeHandleLayout>;\n /** Draw a rotate badge above the selection's top edge. `true` places it at\n * the default offset; `distance` sets the offset in screen pixels. Off by\n * default. */\n rotationHandle?:\n | boolean\n | {\n distance?: number;\n };\n /** Optional separate id list for the per-item outline pass, for a\n * multi-selection whose handle pass works against a synthetic union id\n * (e.g. `MULTI_RESIZE_TARGET_ID`) while each real member is outlined.\n * When omitted, the outline pass uses the handle pass's ids. */\n getOutlineIds?: () => readonly NodeId[];\n /** Optional set of ids to suppress entirely — both outline and handles\n * are skipped. */\n getSuppressedIds?: () => ReadonlySet<string>;\n}\n\nconst DEFAULT_OUTLINE: Required<Pick<CommandStroke, 'paint' | 'width'>> & { pad: number } = {\n paint: { kind: 'solid', color: '#f0e0a8' },\n width: 2,\n pad: 1,\n};\nfunction resolveOutlineStroke(opts?: CommandStroke & { pad?: number }): {\n stroke: CommandStroke;\n pad: number;\n} {\n if (!opts) {\n return {\n stroke: { paint: DEFAULT_OUTLINE.paint, width: DEFAULT_OUTLINE.width },\n pad: DEFAULT_OUTLINE.pad,\n };\n }\n return {\n stroke: {\n paint: opts.paint,\n width: opts.width ?? DEFAULT_OUTLINE.width,\n dash: opts.dash,\n cap: opts.cap,\n join: opts.join,\n align: opts.align,\n },\n pad: opts.pad ?? DEFAULT_OUTLINE.pad,\n };\n}\n\n/** GL helper: emit an outline command for one bounds entry. */\nfunction outlineCommandsFor(\n ids: readonly string[],\n resolveBounds: (id: string) => Bounds | null,\n stroke: CommandStroke,\n pad: number,\n view: View,\n): DrawCommand[] {\n const out: DrawCommand[] = [];\n const align = stroke.align ?? 'center';\n const width = resolveStrokeWidth(stroke.width ?? 1, 1);\n for (const id of ids) {\n const worldB = resolveBounds(id);\n if (!worldB) continue;\n const b = projectBounds(worldB, view);\n const padded = {\n x: b.x - pad,\n y: b.y - pad,\n width: b.width + pad * 2,\n height: b.height + pad * 2,\n };\n const xf = targetTransformOf(worldB);\n if (xf.identity) {\n const r = alignedStrokeRect(padded, align, width);\n out.push({ kind: 'path', path: rectPathFor(r.x, r.y, r.width, r.height), stroke });\n continue;\n }\n // Turned or skewed, the target lands on screen as a parallelogram, so the\n // outline is traced through its projected corners. `alignedStrokeRect`'s\n // shift is folded into the offset so the ribbon lands where it would.\n const shift = align === 'outer' ? width / 2 : align === 'inner' ? -width / 2 : 0;\n const q = screenCorners(worldB, xf, view, pad + shift);\n out.push({\n kind: 'path',\n path: {\n kind: 'polygon',\n commands: new Uint8Array([PATH_M, PATH_L, PATH_L, PATH_L, PATH_Z]),\n coords: new Float32Array([q[0].x, q[0].y, q[1].x, q[1].y, q[2].x, q[2].y, q[3].x, q[3].y]),\n fillRule: 'nonzero',\n },\n stroke: { ...stroke, align: 'center' },\n });\n }\n return out;\n}\n\n/**\n * A framed target's corners on screen, TL/TR/BR/BL, each pushed `pad` screen\n * pixels out from both edges that meet there.\n */\nfunction screenCorners(\n worldB: Bounds,\n xf: TargetTransform,\n view: View,\n pad: number,\n): { x: number; y: number }[] {\n const t = viewToTransform(view);\n const q = targetCorners(worldB, xf).map((w) => {\n const [x, y] = worldToScreen(w.x, w.y, t);\n return { x, y };\n });\n if (pad === 0) return q;\n const [ccx, ccy] = worldToScreen(worldB.x + worldB.width / 2, worldB.y + worldB.height / 2, t);\n const normal = (a: { x: number; y: number }, b: { x: number; y: number }) => {\n let nx = -(b.y - a.y), ny = b.x - a.x;\n const l = Math.hypot(nx, ny) || 1;\n nx /= l; ny /= l;\n const mx = (a.x + b.x) / 2 - ccx, my = (a.y + b.y) / 2 - ccy;\n return nx * mx + ny * my < 0 ? { x: -nx, y: -ny } : { x: nx, y: ny };\n };\n return q.map((c, i) => {\n const n1 = normal(q[(i + 3) % 4], c);\n const n2 = normal(c, q[(i + 1) % 4]);\n // The point `pad` off both edge lines.\n const k = pad / (1 + n1.x * n2.x + n1.y * n2.y);\n return { x: c.x + (n1.x + n2.x) * k, y: c.y + (n1.y + n2.y) * k };\n });\n}\n\n/** GL helper: emit a curved double-headed arrow, the rotate badge above the\n * rect. The arc opens *toward* the object (apex on top, mouth pointing\n * down), with an arrowhead at each endpoint pointing along the tangent. */\nfunction rotationHandleCommands(\n worldB: Bounds,\n handles: ResolvedHandles,\n distance: number,\n view: View,\n): DrawCommand[] {\n const hWorld = rotationHandle(worldB, distance, view.scale);\n const rotation = hWorld.angle;\n const t = viewToTransform(view);\n const [scx, scy] = worldToScreen(hWorld.cx, hWorld.cy, t);\n const size = handles.size;\n const arcRadius = size;\n const ARC_HALF_ANGLE = (Math.PI * 240) / 360 / 2; // 120°\n const N_SEGS = 18;\n const arcWidth = resolveStrokeWidth(handles.outline.width ?? 1, 1) * 1.5;\n const stroke: CommandStroke = {\n paint: handles.fill.paint,\n width: arcWidth,\n cap: 'round',\n join: 'round',\n };\n // The arc as a polyline in handle-local coords, centered on the handle\n // anchor: apex at -y, endpoints at +y near the rect side.\n const cmds: number[] = [PATH_M];\n const xs: number[] = [];\n const ys: number[] = [];\n for (let i = 0; i <= N_SEGS; i++) {\n const t = i / N_SEGS;\n const angle = ARC_HALF_ANGLE - t * ARC_HALF_ANGLE * 2;\n xs.push(arcRadius * Math.sin(angle));\n ys.push(-arcRadius * Math.cos(angle));\n if (i > 0) cmds.push(PATH_L);\n }\n const arcCoords: number[] = [];\n for (let i = 0; i < xs.length; i++) {\n arcCoords.push(xs[i], ys[i]);\n }\n const arcPath: PolygonPath = {\n kind: 'polygon',\n commands: new Uint8Array(cmds),\n coords: new Float32Array(arcCoords),\n fillRule: 'nonzero',\n };\n // Arrowheads: small filled triangles at each endpoint, pointing along\n // the tangent (away from the arc body).\n const headLen = size * 0.6;\n const headWidth = size * 0.4;\n const arrowHead = (endX: number, endY: number, tx: number, ty: number): PolygonPath => {\n // Normalize tangent.\n const len = Math.hypot(tx, ty) || 1;\n const ux = tx / len;\n const uy = ty / len;\n // Perpendicular (rotate tangent 90° CCW).\n const px = -uy;\n const py = ux;\n // Triangle: tip is endX+ux*headLen, base is endX (with +/- headWidth/2 along p).\n const tipX = endX + ux * headLen;\n const tipY = endY + uy * headLen;\n const baseLeftX = endX + px * (headWidth / 2);\n const baseLeftY = endY + py * (headWidth / 2);\n const baseRightX = endX - px * (headWidth / 2);\n const baseRightY = endY - py * (headWidth / 2);\n return {\n kind: 'polygon',\n commands: new Uint8Array([PATH_M, PATH_L, PATH_L, PATH_L]),\n coords: new Float32Array([tipX, tipY, baseLeftX, baseLeftY, baseRightX, baseRightY, tipX, tipY]),\n fillRule: 'nonzero',\n };\n };\n // Endpoint A (right side, angle = +ARC_HALF_ANGLE). Arc point:\n // (sin(a)·R, -cos(a)·R). Tangent (d/da) = (cos(a)·R, sin(a)·R).\n const angleA = ARC_HALF_ANGLE;\n const endAX = arcRadius * Math.sin(angleA);\n const endAY = -arcRadius * Math.cos(angleA);\n const tangentAX = Math.cos(angleA);\n const tangentAY = Math.sin(angleA);\n // Endpoint B (left side, angle = -ARC_HALF_ANGLE): tangent in the\n // outward direction is the negation of the above.\n const angleB = -ARC_HALF_ANGLE;\n const endBX = arcRadius * Math.sin(angleB);\n const endBY = -arcRadius * Math.cos(angleB);\n const tangentBX = -Math.cos(angleB);\n const tangentBY = -Math.sin(angleB);\n const headA = arrowHead(endAX, endAY, tangentAX, tangentAY);\n const headB = arrowHead(endBX, endBY, tangentBX, tangentBY);\n // Build transform: translate(scx, scy) [* rotate(rotation)].\n let transform = mat3.translated(mat3.identity(), scx, scy);\n if (rotation !== 0) {\n const c = Math.cos(rotation);\n const s = Math.sin(rotation);\n const rot = new Float32Array([c, s, 0, -s, c, 0, 0, 0, 1]) as GlMat3;\n transform = mat3.multiply(transform, rot);\n }\n return [\n {\n kind: 'group',\n transform,\n children: [\n { kind: 'path', path: arcPath, stroke },\n { kind: 'path', path: headA, fill: handles.fill },\n { kind: 'path', path: headB, fill: handles.fill },\n ],\n },\n ];\n}\n\n/** Which passes a selection layer runs. The three exported factories differ\n * only in this — everything else they do is shared, so a fix to one is a fix\n * to all three. */\ninterface SelectionPasses {\n readonly id: string;\n readonly label: string;\n readonly outline: boolean;\n readonly handles: boolean;\n}\n\nfunction buildSelectionLayer<TPose>(\n opts: SelectionOverlayLayerOpts<TPose>,\n passes: SelectionPasses,\n): RenderLayer<unknown> {\n const { stroke, pad } = resolveOutlineStroke(opts.outline);\n const handlesEnabled = passes.handles && opts.handles !== false;\n const handles = handlesEnabled ? resolveHandles(opts.handles || undefined) : null;\n const { handlesOf, resizeHandles } = opts;\n const d = (opts.poseDescriptor ?? AUTO_POSE_DESCRIPTOR) as PoseDescriptor<TPose>;\n const getPose = opts.getPose;\n const poseBounds = getPose\n ? containerAwareBoundsResolver(getPose, d, opts.getChildren, opts.isContainer, opts.scene)\n : null;\n const rotationHandleDistance = passes.handles\n ? rotationBadgeOf(opts)?.distancePx ?? null\n : null;\n\n return {\n id: passes.id,\n label: passes.label,\n space: 'screen',\n draw: (data, view) => {\n // The synthetic multi-resize id resolves to `ChromeState.unionBounds`,\n // the same value the affordance hit-tester reads, so painted chrome\n // and its hit region stay in agreement. With no chromeState on the\n // draw envelope, fall through to the supplied resolver.\n const chromeState = asChromeState(data);\n const allIds = opts.getSelection\n ? opts.getSelection()\n : chromeSelectionIds(chromeState);\n if (allIds.length === 0) return [];\n const suppressed = opts.getSuppressedIds?.();\n const ids = suppressed && suppressed.size > 0\n ? allIds.filter((id) => !suppressed.has(id as unknown as string))\n : allIds;\n if (ids.length === 0) return [];\n // Chrome-caps: gate each pass on its canonical id. When no\n // `getIsVisible` is wired, every pass runs.\n const isVisible = asIsVisible(data);\n const showOutline = passes.outline && (isVisible ? isVisible('selection.outline') : true);\n const showHandles = isVisible ? isVisible('selection.resize-handles') : true;\n const showRotation = isVisible ? isVisible('selection.rotation-handle') : true;\n\n const resolveBounds = poseBounds\n ? (id: string) => poseBounds(id, view.scale)\n : (id: string) => chromeState?.boundsOf(id) ?? null;\n const resolveTargetBounds = (id: string): Bounds | null => {\n if (id === MULTI_RESIZE_TARGET_ID && chromeState?.unionBounds != null) {\n return chromeState.unionBounds;\n }\n return resolveBounds(id);\n };\n\n const out: DrawCommand[] = [];\n if (showOutline) {\n const outlineIdsRaw = opts.getOutlineIds\n ? opts.getOutlineIds()\n : (opts.getSelection ? ids : (chromeState?.selection ?? ids));\n const outlineIds = suppressed && suppressed.size > 0\n ? outlineIdsRaw.filter((id) => !suppressed.has(id as unknown as string))\n : outlineIdsRaw;\n for (const cmd of outlineCommandsFor(outlineIds, resolveTargetBounds, stroke, pad, view)) out.push(cmd);\n }\n if (!handles) return out;\n if (showHandles) {\n for (const cmd of handleCommandsFor(ids, resolveTargetBounds, handles, handlesOf, resizeHandles, view)) out.push(cmd);\n }\n if (showRotation && rotationHandleDistance !== null) {\n for (const id of ids) {\n const b = resolveTargetBounds(id);\n if (!b) continue;\n for (const cmd of rotationHandleCommands(b, handles, rotationHandleDistance, view)) {\n out.push(cmd);\n }\n }\n }\n return out;\n },\n };\n}\n\n/** Where the overlay paints its rotate badge and how big it is, in screen\n * pixels, or `null` when it paints none. The badge's grab region and its\n * slops halo read this too, so all three agree on it. */\nexport function rotationBadgeOf(\n opts: Pick<SelectionOverlayLayerOpts<unknown>, 'handles' | 'rotationHandle'>,\n): { distancePx: number; sizePx: number } | null {\n const r = opts.rotationHandle;\n if (!r || opts.handles === false) return null;\n return {\n distancePx: r === true ? DEFAULT_ROTATION_HANDLE_DISTANCE : r.distance ?? DEFAULT_ROTATION_HANDLE_DISTANCE,\n sizePx: resolveHandles(opts.handles || undefined).size,\n };\n}\n/**\n * `RenderLayer` that draws selection outlines only. Stack alongside\n * `createSelectionHandlesLayer` (or use `createSelectionOverlayLayer`, which\n * runs both passes in one layer) when both are wanted.\n */\nexport function createSelectionOutlineLayer<TPose>(\n opts: SelectionOutlineLayerOpts<TPose>,\n): RenderLayer<unknown> {\n return buildSelectionLayer(opts, {\n id: 'selection-outline',\n label: 'Selection outline',\n outline: true,\n handles: false,\n });\n}\n\n/**\n * `RenderLayer` that draws selection handles only. Stack on top of\n * `createSelectionOutlineLayer` (handles render on top of the outline).\n */\nexport function createSelectionHandlesLayer<TPose>(\n opts: SelectionHandlesLayerOpts<TPose>,\n): RenderLayer<unknown> {\n return buildSelectionLayer(opts, {\n id: 'selection-handles',\n label: 'Selection handles',\n outline: false,\n handles: true,\n });\n}\n\n/**\n * Draws outlines then handles in a single layer. Exactly equivalent to\n * stacking `createSelectionOutlineLayer` and `createSelectionHandlesLayer` —\n * all three run the same body. Pass `handles: false` to render outlines only.\n */\nexport function createSelectionOverlayLayer<TPose>(\n opts: SelectionOverlayLayerOpts<TPose>,\n): RenderLayer<unknown> {\n return buildSelectionLayer(opts, {\n id: 'selection-overlay',\n label: 'Selection',\n outline: true,\n handles: true,\n });\n}\n\n/** Pull a chrome-caps visibility predicate off the draw `data` envelope.\n * Returns `null` when the caller passed bare data (no `getIsVisible`\n * thunk) — the layer then renders unconditionally. */\nfunction asIsVisible(data: unknown): ((id: string) => boolean) | null {\n const maybe = data as { getIsVisible?: () => (id: string) => boolean };\n if (typeof maybe?.getIsVisible === 'function') return maybe.getIsVisible();\n return null;\n}\n\n/** The ids the handle pass works against when the layer takes its selection\n * from the envelope: the synthetic union id for a multi-selection, the\n * selection itself otherwise. */\nfunction chromeSelectionIds(state: ChromeState | null): readonly NodeId[] {\n if (!state) return [];\n if (state.multiActive) return [MULTI_RESIZE_TARGET_ID as NodeId];\n return state.selection;\n}\n\n/** Pull live `ChromeState` off the draw `data` envelope. Returns `null` for\n * callers that pass plain data with no `getChromeState` thunk — the layer\n * then resolves the multi-union via the supplied `getPose` resolver. */\nfunction asChromeState(data: unknown): ChromeState | null {\n const maybe = data as { getChromeState?: () => ChromeState };\n if (typeof maybe?.getChromeState === 'function') return maybe.getChromeState();\n return null;\n}\n"],"mappings":"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"}
|
|
@@ -3,7 +3,7 @@ import { framedBounds, visualBoundsViaDescriptor } from "../../core/geometry/pos
|
|
|
3
3
|
import { AUTO_POSE_DESCRIPTOR } from "../../core/geometry/autoPoseDescriptor.js";
|
|
4
4
|
import { drawnAABBOf, drawnBoundsOf } from "../../canvas/drawnBounds.js";
|
|
5
5
|
|
|
6
|
-
//#region src/
|
|
6
|
+
//#region src/domains/selection/selectionPose.ts
|
|
7
7
|
/**
|
|
8
8
|
* Transitive leaf ids under `id`. A childless node is a leaf only if it is not
|
|
9
9
|
* itself a container: an empty container contributes no bounds, and its own
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selectionPose.js","names":[],"sources":["../../../src/domains/selection/selectionPose.ts"],"sourcesContent":["/**\n * The pose and box a selection's chrome is drawn around: precedence between\n * the in-flight overlays and the stored pose, a container's union over its\n * leaves, and the drawn box a scene supplies.\n */\nimport type { Scale2 } from '@weasel-js/geom';\nimport { drawnAABBOf, drawnBoundsOf, type DrawnBoundsScene } from 'canvas/drawnBounds';\nimport { unionAABB } from 'core/geometry/unionBounds';\nimport { framedBounds, visualBoundsViaDescriptor, type PoseDescriptor } from 'core/geometry/poseDescriptor';\nimport { AUTO_POSE_DESCRIPTOR } from 'core/geometry/autoPoseDescriptor';\nimport type { NodeId } from 'core/scene/types';\nimport type { Bounds } from 'core/viewport/fitViewToBounds';\n\n/**\n * Transitive leaf ids under `id`. A childless node is a leaf only if it is not\n * itself a container: an empty container contributes no bounds, and its own\n * stored pose is at its most stale when no children are left to have moved it.\n */\nfunction leavesOf(\n id: string,\n getChildren: (id: string) => readonly string[],\n isContainer: (id: string) => boolean,\n): string[] {\n if (!isContainer(id)) return [id];\n const out: string[] = [];\n const visit = (nid: string) => {\n const kids = getChildren(nid);\n if (kids.length === 0) { if (!isContainer(nid)) out.push(nid); return; }\n for (const k of kids) visit(k);\n };\n visit(id);\n return out;\n}\n\n/** How one id's pose becomes a box: the pose box, or with a scene the box the\n * node is drawn with. Each id is read as a leaf — the pose already says where\n * a container is, so its members' stored poses are not consulted again. */\nfunction boxReader<TPose>(\n d: PoseDescriptor<TPose>,\n scene: DrawnBoundsScene | undefined,\n): { framed(id: string, pose: TPose, scale?: number | Scale2): Bounds; aabb(id: string, pose: TPose, scale?: number | Scale2): Bounds } {\n if (!scene) {\n return {\n framed: (_id, pose) => framedBounds(pose, d),\n aabb: (_id, pose) => visualBoundsViaDescriptor(pose, d),\n };\n }\n const leaves: DrawnBoundsScene = {\n get: (id) => scene.get(id),\n ...(scene.derivedPathOf ? { derivedPathOf: (id: NodeId) => scene.derivedPathOf!(id) } : {}),\n };\n const opts = (scale: number | Scale2 | undefined) => ({\n descriptor: d as PoseDescriptor<unknown>,\n ...(scale !== undefined ? { scale } : {}),\n });\n return {\n framed: (id, pose, scale) => drawnBoundsOf(leaves, id as NodeId, pose, opts(scale)),\n aabb: (id, pose, scale) => drawnAABBOf(leaves, id as NodeId, pose, opts(scale)),\n };\n}\n\n/** Options for `composeSelectionPose`. */\nexport interface ComposeSelectionPoseOpts<TPose> {\n /** Move overlay; when present its `poses` map wins over everything else. */\n moveOverlay?: { poses: Map<string, TPose> } | null;\n /**\n * Resize overlay; consulted only when move overlay does not own the id.\n * For container resize, `leafPoses` (when present) maps each leaf id under\n * the container to its overlay pose. If absent the container falls back to\n * stored leaf poses.\n */\n resizeOverlay?: {\n id: string;\n currentPose: TPose;\n leafPoses?: Map<string, TPose>;\n } | null;\n /** Fallback pose lookup (typically the stored/committed pose). */\n getStoredPose: (id: string) => TPose;\n /** How to read poses. Default `AUTO_POSE_DESCRIPTOR`. */\n poseDescriptor?: PoseDescriptor<TPose>;\n /** Walk a container's direct children (e.g. `scene.childrenOf`). With\n * `isContainer`, a selected container resolves to the union AABB of its\n * transitive leaf poses instead of its own stored pose. */\n getChildren?: (id: string) => readonly string[];\n /** True when `id` is a structural container. */\n isContainer?: (id: string) => boolean;\n /** The nodes behind the ids. With it, a container's union takes each leaf\n * as drawn, stroke included (`drawnBoundsOf`); without, its pose box. */\n scene?: DrawnBoundsScene;\n /** View scale a screen-pixel stroke is resolved at. Default 1. */\n viewScale?: () => number | Scale2;\n}\n\n/**\n * Build a pose resolver for a selection. Precedence per id:\n * move overlay > resize overlay > stored. When `getChildren`/`isContainer`\n * are supplied and the id resolves to a container, the resolver returns the\n * union AABB of all transitive leaf poses (each leaf still subject to the\n * precedence rules). Containers with no leaves resolve to `null`.\n */\nexport function composeSelectionPose<TPose>(\n opts: ComposeSelectionPoseOpts<TPose>,\n): (id: string) => TPose | null {\n const { moveOverlay, resizeOverlay, getStoredPose, getChildren, isContainer } = opts;\n const d = (opts.poseDescriptor ?? AUTO_POSE_DESCRIPTOR) as PoseDescriptor<TPose>;\n const boxes = boxReader(d, opts.scene);\n\n const selectionLeaves = (id: string): string[] =>\n getChildren && isContainer ? leavesOf(id, getChildren, isContainer) : [id];\n\n const resolveLeaf = (id: string): TPose => {\n const moved = moveOverlay?.poses.get(id);\n if (moved !== undefined) return moved;\n if (resizeOverlay && resizeOverlay.id === id) return resizeOverlay.currentPose;\n return getStoredPose(id);\n };\n\n return (id: string): TPose | null => {\n if (isContainer?.(id)) {\n const leaves = selectionLeaves(id);\n if (leaves.length === 0) return null;\n const containerResizeLeafPoses =\n resizeOverlay && resizeOverlay.id === id ? resizeOverlay.leafPoses : undefined;\n const scale = opts.viewScale?.();\n const leafBounds: Bounds[] = [];\n for (const leafId of leaves) {\n const pose = moveOverlay?.poses.get(leafId)\n ?? containerResizeLeafPoses?.get(leafId)\n ?? getStoredPose(leafId);\n leafBounds.push(boxes.aabb(leafId, pose, scale));\n }\n const u = unionAABB(leafBounds);\n if (u === null) return null;\n return d.fromBounds(u, getStoredPose(leaves[0]!));\n }\n return resolveLeaf(id);\n };\n}\n\n/**\n * Build a bounds resolver that handles container ids by computing the union\n * AABB of every leaf's bounds. Non-container ids pass through directly. When\n * `getChildren`/`isContainer` are omitted, every id is treated as a leaf.\n * With a scene, each leaf is boxed as drawn at the view's scale.\n */\nexport function containerAwareBoundsResolver<TPose>(\n getPose: (id: string) => TPose | null,\n d: PoseDescriptor<TPose>,\n getChildren: ((id: string) => readonly string[]) | undefined,\n isContainer: ((id: string) => boolean) | undefined,\n scene: DrawnBoundsScene | undefined,\n): (id: string, scale: Scale2) => Bounds | null {\n const boxes = boxReader(d, scene);\n const leaf = (id: string, scale: Scale2): Bounds | null => {\n const p = getPose(id);\n return p === null ? null : boxes.framed(id, p, scale);\n };\n if (getChildren === undefined || isContainer === undefined) return leaf;\n return (id, scale) => {\n if (!isContainer(id)) return leaf(id, scale);\n const leaves = leavesOf(id, getChildren, isContainer);\n if (leaves.length === 0) return null;\n const leafBounds: Bounds[] = [];\n for (const leafId of leaves) {\n const p = getPose(leafId);\n if (p !== null) leafBounds.push(boxes.aabb(leafId, p, scale));\n }\n if (leafBounds.length === 0) return null;\n return unionAABB(leafBounds);\n };\n}\n"],"mappings":"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"}
|
|
@@ -3,7 +3,7 @@ import { screenOf } from "./screen.js";
|
|
|
3
3
|
import { stepAngles } from "./stepAngles.js";
|
|
4
4
|
import { resolveSnap } from "@weasel-js/geom/nd";
|
|
5
5
|
|
|
6
|
-
//#region src/
|
|
6
|
+
//#region src/domains/snap/angle2d.ts
|
|
7
7
|
/** A snap session's one-dimensional path: an angle about a pivot, snapped by
|
|
8
8
|
* the same resolver as a point, with reach carried through the radius. */
|
|
9
9
|
var TURN = Math.PI * 2;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"angle2d.js","names":[],"sources":["../../../src/domains/snap/angle2d.ts"],"sourcesContent":["/** A snap session's one-dimensional path: an angle about a pivot, snapped by\n * the same resolver as a point, with reach carried through the radius. */\nimport { resolveSnap, type SnapCandidate } from '@weasel-js/geom/nd';\nimport type { SnapMods } from 'interactions/actions/snapDep';\nimport { distinct, markFromPlane } from './marks';\nimport { screenOf } from './screen';\nimport { stepAngles } from './stepAngles';\nimport type { Session2dInputs } from './session2d';\nimport type { AngleCollect, SnapMark, SnapMarks, SnapSource } from './types';\n\nconst TURN = Math.PI * 2;\nconst PROBE = 'angle';\n/** A press near the pivot turns px reach into a wide angle; it reaches no\n * further than this. */\nconst MAX_REACH_RAD = Math.PI / 6;\n\n/** Where `theta` lands, and what it met. Writes the marks to the store. */\nexport function angleAt(\n inputs: Session2dInputs, sources: readonly SnapSource[], theta: number, mods: SnapMods,\n): { theta: number; marks: readonly SnapMark[] } {\n const { req, store } = inputs;\n // Screen px per radian, or 1 when the gesture gives its reach in radians.\n const scale = req.reachRad !== undefined ? 1 : pressRadiusPx(inputs);\n const reachOf = (s: SnapSource) => req.reachRad\n ?? Math.min(s.reachPx ?? inputs.reachPx, MAX_REACH_RAD * scale);\n const candidates = collectAngles(inputs, sources, theta, mods, reachOf);\n if (candidates.length === 0) {\n store.set([]);\n return { theta, marks: [] };\n }\n const res = resolveSnap({\n probes: [{ id: PROBE, at: [0], role: 'pointer' }],\n input: { at: [0], dirs: [[1]] },\n delta0: [theta],\n candidates,\n // No radius, no reach: only a required angle can win.\n toScreen: ([t]) => [scale > 0 ? t * scale : NaN],\n });\n const out = res.delta[0];\n const marks = distinct(res.satisfied.flatMap((c) => {\n const m = c.mark ?? rayMarks(inputs, out);\n return 'kind' in m ? [m] : m;\n }));\n const plane = req.plane?.() ?? null;\n store.set(plane ? marks.map((m) => markFromPlane(m, plane)) : marks);\n return { theta: out, marks };\n}\n\nfunction collectAngles(\n inputs: Session2dInputs, sources: readonly SnapSource[], theta: number, mods: SnapMods,\n reachOf: (s: SnapSource) => number,\n): SnapCandidate<SnapMarks>[] {\n const { req } = inputs;\n const out: SnapCandidate<SnapMarks>[] = [];\n const c = req.constrain;\n if (mods.constrain && typeof c === 'object' && c.step > 0) {\n for (const at of stepAngles(theta, c.step)) {\n out.push({ probe: PROBE, locus: { at: [at], dirs: [] }, source: 'constrain', order: -1, tier: 'target', reachPx: 0, required: true });\n }\n }\n const theta0 = req.theta0 ?? 0;\n if (mods.hold) {\n const at = theta0 + TURN * Math.round((theta - theta0) / TURN);\n out.push({ probe: PROBE, locus: { at: [at], dirs: [] }, source: 'hold', order: -1, tier: 'target', reachPx: 0, required: true, mark: [] });\n }\n if (mods.suspend) return out;\n const q: AngleCollect = {\n pivot: req.pivot ?? req.press,\n press: req.press,\n theta0,\n theta,\n ids: req.ids ?? [],\n exclude: inputs.exclude ?? req.ids ?? [],\n mods,\n ...(req.also ? { also: req.also } : {}),\n ...(inputs.scene ? { scene: inputs.scene } : {}),\n ...(inputs.rotationOf ? { rotationOf: inputs.rotationOf } : {}),\n };\n // Runs across sources and their yields: an earlier source, then an earlier\n // yield, wins a tie.\n let order = 0;\n sources.forEach((source) => {\n if (!source.angles) return;\n const reachPx = reachOf(source);\n for (const a of source.angles(q)) {\n // The whole turn of the angle nearest `theta`: 0 catches 359°.\n const at = a.angle + TURN * Math.round((theta - a.angle) / TURN);\n out.push({\n probe: PROBE, locus: { at: [at], dirs: [] }, source: source.id, order: order++, tier: source.tier ?? 'target', reachPx,\n ...(a.required ? { required: true } : {}),\n ...(a.mark ? { mark: a.mark } : {}),\n });\n }\n });\n return out;\n}\n\n/** The screen distance from the pivot to the press: what turns reach in px\n * into radians. */\nfunction pressRadiusPx(inputs: Session2dInputs): number {\n const { req } = inputs;\n const pivot = req.pivot ?? req.press;\n const toScreen = screenOf(inputs.view(), req.plane?.() ?? null);\n const [ax, ay] = toScreen([pivot.x, pivot.y]);\n const [bx, by] = toScreen([req.press.x, req.press.y]);\n return Math.hypot(bx - ax, by - ay);\n}\n\n/** A ray from the pivot out to the press radius, along where the pointer\n * lands at `theta`, labeled with `theta` in degrees. */\nfunction rayMarks(inputs: Session2dInputs, theta: number): SnapMark[] {\n const { req } = inputs;\n const pivot = req.pivot ?? req.press;\n const r = Math.hypot(req.press.x - pivot.x, req.press.y - pivot.y);\n const dir = Math.atan2(req.press.y - pivot.y, req.press.x - pivot.x) + theta - (req.theta0 ?? 0);\n const end = { x: pivot.x + r * Math.cos(dir), y: pivot.y + r * Math.sin(dir) };\n const deg = ((Math.round(theta * 180 / Math.PI) % 360) + 360) % 360;\n return [\n { kind: 'line', from: pivot, to: end },\n { kind: 'point', at: end, glyph: 'quadrant', label: `${deg}°` },\n ];\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { fromPlane } from "../../core/viewport/parallax.js";
|
|
2
2
|
import { closestOnFlat } from "@weasel-js/geom/nd";
|
|
3
3
|
|
|
4
|
-
//#region src/
|
|
4
|
+
//#region src/domains/snap/debugCandidates.ts
|
|
5
5
|
/** Replaces the sink's snap records with one frame's candidates: where each
|
|
6
6
|
* would put its probe, accepted when the result meets it. Camera world. */
|
|
7
7
|
function recordSnapCandidates(debug, candidates, satisfied, probes, delta0, plane) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"debugCandidates.js","names":[],"sources":["../../../src/domains/snap/debugCandidates.ts"],"sourcesContent":["import { closestOnFlat, type SnapCandidate } from '@weasel-js/geom/nd';\nimport type { DebugSink } from '@weasel-js/routing';\nimport { fromPlane, type PlaneMap } from 'core/viewport/parallax';\nimport type { SnapProbeAt } from './types';\nimport type { Point } from '@weasel-js/geom';\n\n/** Replaces the sink's snap records with one frame's candidates: where each\n * would put its probe, accepted when the result meets it. Camera world. */\nexport function recordSnapCandidates(\n debug: DebugSink,\n candidates: readonly SnapCandidate<unknown>[],\n satisfied: readonly SnapCandidate<unknown>[],\n probes: readonly SnapProbeAt[],\n delta0: Point,\n plane: PlaneMap | null,\n): void {\n debug.clearSnap();\n const met = new Set(satisfied);\n const at = new Map(probes.map((q) => [q.id, [q.at.x + delta0.x, q.at.y + delta0.y]]));\n for (const c of candidates) {\n const p = at.get(c.probe);\n if (!p) continue;\n const [x, y] = closestOnFlat(c.locus, p);\n debug.recordSnapCandidate(plane ? fromPlane(plane, { x, y }) : { x, y }, met.has(c));\n }\n}\n"],"mappings":";;;;;;AAQA,SAAgB,qBACd,OACA,YACA,WACA,QACA,QACA,OACM;CACN,MAAM,UAAU;CAChB,MAAM,MAAM,IAAI,IAAI,SAAS;CAC7B,MAAM,KAAK,IAAI,IAAI,OAAO,KAAK,MAAM,CAAC,EAAE,IAAI,CAAC,EAAE,GAAG,IAAI,OAAO,GAAG,EAAE,GAAG,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC;CACpF,KAAK,MAAM,KAAK,YAAY;EAC1B,MAAM,IAAI,GAAG,IAAI,EAAE,KAAK;EACxB,IAAI,CAAC,GAAG;EACR,MAAM,CAAC,GAAG,KAAK,cAAc,EAAE,OAAO,CAAC;EACvC,MAAM,oBAAoB,QAAQ,UAAU,OAAO;GAAE;GAAG;EAAE,CAAC,IAAI;GAAE;GAAG;EAAE,GAAG,IAAI,IAAI,CAAC,CAAC;CACrF;AACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gather.js","names":[],"sources":["../../../src/domains/snap/gather.ts"],"sourcesContent":["import type { SnapCandidate, Vec } from '@weasel-js/geom/nd';\nimport { distinct } from './marks';\nimport type { SnapCollect, SnapGesture, SnapMark, SnapProbeAt, SnapSource, SourceCandidate } from './types';\n\nconst DEFAULT_GESTURES: readonly SnapGesture[] = ['point', 'move', 'resize'];\n\n/** The sources that answer `gesture`: those naming it, and, for one naming none, point, move and resize. */\nexport function snapSourcesFor<S extends Pick<SnapSource<unknown>, 'gestures'>>(sources: readonly S[], gesture: SnapGesture): S[] {\n return sources.filter((s) => (s.gestures ?? DEFAULT_GESTURES).includes(gesture));\n}\n\n/** Throws if two of `sources` share an id: one would silently replace the other. */\nexport function assertSnapSourceIds(sources: readonly Pick<SnapSource<unknown>, 'id'>[]): void {\n const seen = new Set<string>();\n for (const { id } of sources) {\n if (seen.has(id)) {\n throw new Error(`[snap] two snap sources share the id '${id}'. Give one its own id, or drop one.`);\n }\n seen.add(id);\n }\n}\n\n/** What a candidate draws when the result meets it. */\nexport type SnapCandidateMark<P> = NonNullable<SourceCandidate<P>['mark']>;\n\n/** How near `origin` a point target counts as on it, relative to its magnitude. */\nconst ORIGIN_EPS = 1e-9;\n\n/** How `gatherSnapCandidates` reads a host's points. */\nexport interface GatherSnapOptions<P> {\n /** `p` as a resolver tuple. */\n toVec(p: P): Vec;\n /** The reach of a source that sets none, in screen px. */\n reachPx: number;\n /** Where the geometry being drawn starts: no point target on it is offered. */\n origin?: P;\n}\n\n/**\n * One frame's resolver candidates: each source is asked, through `ask`, about\n * the probes whose role it matches and the reach that applies to it (its\n * own `reachPx`, else `opts.reachPx`), and what it answers for a probe it was\n * not offered, or a point on `origin`, is dropped. Sources run in order, and\n * an earlier source, then an earlier yield, wins a full tie. The building\n * block of a host's own snap session over `resolveSnap`.\n */\nexport function gatherSnapCandidates<P>(\n sources: readonly SnapSource<P>[],\n probes: readonly SnapProbeAt<P>[],\n ask: (source: SnapSource<P>, offered: SnapProbeAt<P>[], reachPx: number) => SnapCollect<P>,\n opts: GatherSnapOptions<P>,\n): SnapCandidate<SnapCandidateMark<P>>[] {\n const origin = opts.origin === undefined ? null : opts.toVec(opts.origin);\n const out: SnapCandidate<SnapCandidateMark<P>>[] = [];\n let order = 0;\n for (const source of sources) {\n const offered = probes.filter((q) => source.roles.includes(q.role));\n if (offered.length === 0) continue;\n const ids = new Set(offered.map((q) => q.id));\n const reachPx = source.reachPx ?? opts.reachPx;\n for (const c of source.collect(ask(source, offered, reachPx))) {\n if (!ids.has(c.probe)) continue;\n const at = opts.toVec(c.locus.at);\n if (origin && c.locus.dirs.length === 0 && same(at, origin)) continue;\n out.push({\n probe: c.probe, locus: { at, dirs: c.locus.dirs.map(opts.toVec) },\n ...(c.locus.span ? { span: c.locus.span } : {}),\n source: source.id, order: order++, tier: source.tier ?? 'target', reachPx,\n ...(c.required ? { required: true } : {}),\n ...(c.mark ? { mark: c.mark } : {}),\n });\n }\n }\n return out;\n}\n\nfunction same(a: Vec, b: Vec): boolean {\n const eps = ORIGIN_EPS * Math.max(1, ...b.map(Math.abs));\n return a.every((v, i) => Math.abs(v - b[i]) <= eps);\n}\n\n/** The marks of the candidates a result meets, with `delta` the resolved\n * move, and repeats dropped so a target several probes meet is drawn once. */\nexport function resolvedSnapMarks<P>(\n satisfied: readonly { mark?: SnapCandidateMark<P> }[], delta: P,\n): SnapMark<P>[] {\n return distinct(satisfied.flatMap((c) => marksOf(c.mark, delta)));\n}\n\nfunction marksOf<P>(mark: SnapCandidateMark<P> | undefined, delta: P): readonly SnapMark<P>[] {\n if (!mark) return [];\n const m = typeof mark === 'function' ? mark(delta) : mark;\n return 'kind' in m ? [m as SnapMark<P>] : (m as readonly SnapMark<P>[]);\n}\n"],"mappings":";;;AAIA,IAAM,mBAA2C;CAAC;CAAS;CAAQ;AAAQ;;AAG3E,SAAgB,eAAgE,SAAuB,SAA2B;CAChI,OAAO,QAAQ,QAAQ,OAAO,EAAE,YAAY,iBAAA,CAAkB,SAAS,OAAO,CAAC;AACjF;;AAGA,SAAgB,oBAAoB,SAA2D;CAC7F,MAAM,uBAAO,IAAI,IAAY;CAC7B,KAAK,MAAM,EAAE,QAAQ,SAAS;EAC5B,IAAI,KAAK,IAAI,EAAE,GACb,MAAM,IAAI,MAAM,yCAAyC,GAAG,qCAAqC;EAEnG,KAAK,IAAI,EAAE;CACb;AACF;;AAMA,IAAM,aAAa;;;;;;;;;AAoBnB,SAAgB,qBACd,SACA,QACA,KACA,MACuC;CACvC,MAAM,SAAS,KAAK,WAAW,SAAY,OAAO,KAAK,MAAM,KAAK,MAAM;CACxE,MAAM,MAA6C,CAAC;CACpD,IAAI,QAAQ;CACZ,KAAK,MAAM,UAAU,SAAS;EAC5B,MAAM,UAAU,OAAO,QAAQ,MAAM,OAAO,MAAM,SAAS,EAAE,IAAI,CAAC;EAClE,IAAI,QAAQ,WAAW,GAAG;EAC1B,MAAM,MAAM,IAAI,IAAI,QAAQ,KAAK,MAAM,EAAE,EAAE,CAAC;EAC5C,MAAM,UAAU,OAAO,WAAW,KAAK;EACvC,KAAK,MAAM,KAAK,OAAO,QAAQ,IAAI,QAAQ,SAAS,OAAO,CAAC,GAAG;GAC7D,IAAI,CAAC,IAAI,IAAI,EAAE,KAAK,GAAG;GACvB,MAAM,KAAK,KAAK,MAAM,EAAE,MAAM,EAAE;GAChC,IAAI,UAAU,EAAE,MAAM,KAAK,WAAW,KAAK,KAAK,IAAI,MAAM,GAAG;GAC7D,IAAI,KAAK;IACP,OAAO,EAAE;IAAO,OAAO;KAAE;KAAI,MAAM,EAAE,MAAM,KAAK,IAAI,KAAK,KAAK;IAAE;IAChE,GAAI,EAAE,MAAM,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,QAAQ,OAAO;IAAI,OAAO;IAAS,MAAM,OAAO,QAAQ;IAAU;IAClE,GAAI,EAAE,WAAW,EAAE,UAAU,KAAK,IAAI,CAAC;IACvC,GAAI,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;GACnC,CAAC;EACH;CACF;CACA,OAAO;AACT;AAEA,SAAS,KAAK,GAAQ,GAAiB;CACrC,MAAM,MAAM,aAAa,KAAK,IAAI,GAAG,GAAG,EAAE,IAAI,KAAK,GAAG,CAAC;CACvD,OAAO,EAAE,OAAO,GAAG,MAAM,KAAK,IAAI,IAAI,EAAE,EAAE,KAAK,GAAG;AACpD;;;AAIA,SAAgB,kBACd,WAAuD,OACxC;CACf,OAAO,SAAS,UAAU,SAAS,MAAM,QAAQ,EAAE,MAAM,KAAK,CAAC,CAAC;AAClE;AAEA,SAAS,QAAW,MAAwC,OAAkC;CAC5F,IAAI,CAAC,MAAM,OAAO,CAAC;CACnB,MAAM,IAAI,OAAO,SAAS,aAAa,KAAK,KAAK,IAAI;CACrD,OAAO,UAAU,IAAI,CAAC,CAAgB,IAAK;AAC7C"}
|
|
@@ -2,7 +2,7 @@ import { SNAP_AXIS_STEP } from "./roles.js";
|
|
|
2
2
|
import { diagonal, edgeAxis } from "./resizeBox.js";
|
|
3
3
|
import { stepLine } from "@weasel-js/geom/nd";
|
|
4
4
|
|
|
5
|
-
//#region src/
|
|
5
|
+
//#region src/domains/snap/inputSubspace.ts
|
|
6
6
|
var PLANE = {
|
|
7
7
|
at: [0, 0],
|
|
8
8
|
dirs: [[1, 0], [0, 1]]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inputSubspace.js","names":[],"sources":["../../../src/domains/snap/inputSubspace.ts"],"sourcesContent":["import { stepLine, type Flat } from '@weasel-js/geom/nd';\nimport type { SnapBegin, SnapMods } from 'interactions/actions/snapDep';\nimport { diagonal, edgeAxis, type ResizeSubject } from './resizeBox';\nimport { SNAP_AXIS_STEP } from './roles';\nimport type { Point } from '@weasel-js/geom';\n\nconst PLANE: Flat = { at: [0, 0], dirs: [[1, 0], [0, 1]] };\nconst AXES = [[1, 0], [0, 1]] as const;\n\n/** `H`: the subspace of δ = pointer − press that the gesture's result stays\n * in. `resize` is the box a resize drags, which an edge handle's axis and an\n * aspect lock are read from; without it they run along the ctx axes. */\nexport function inputFlat(req: SnapBegin, mods: SnapMods, delta0: Point, resize?: ResizeSubject | null): Flat {\n const h = req.handle;\n if (h && (h.x === 'free') !== (h.y === 'free')) {\n const axis = resize ? edgeAxis(resize)! : h.y === 'free' ? { x: 1, y: 0 } : { x: 0, y: 1 };\n return { at: [0, 0], dirs: [[axis.x, axis.y]] };\n }\n const c = req.constrain;\n if (!mods.constrain || c === undefined) return PLANE;\n if (c === 'axis') return stepLine([0, 0], [delta0.x, delta0.y], AXES, SNAP_AXIS_STEP);\n if (c === 'aspect') {\n if (!resize || !h) return PLANE;\n const d = diagonal(resize);\n return { at: [0, 0], dirs: [[d.x, d.y]] };\n }\n const origin = req.origin ?? req.press;\n return stepLine([origin.x - req.press.x, origin.y - req.press.y], [delta0.x, delta0.y], AXES, c.step);\n}\n"],"mappings":";;;;;AAMA,IAAM,QAAc;CAAE,IAAI,CAAC,GAAG,CAAC;CAAG,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAAE;AACzD,IAAM,OAAO,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;;;;AAK5B,SAAgB,UAAU,KAAgB,MAAgB,QAAe,QAAqC;CAC5G,MAAM,IAAI,IAAI;CACd,IAAI,KAAM,EAAE,MAAM,YAAa,EAAE,MAAM,SAAS;EAC9C,MAAM,OAAO,SAAS,SAAS,MAAM,IAAK,EAAE,MAAM,SAAS;GAAE,GAAG;GAAG,GAAG;EAAE,IAAI;GAAE,GAAG;GAAG,GAAG;EAAE;EACzF,OAAO;GAAE,IAAI,CAAC,GAAG,CAAC;GAAG,MAAM,CAAC,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC;EAAE;CAChD;CACA,MAAM,IAAI,IAAI;CACd,IAAI,CAAC,KAAK,aAAa,MAAM,QAAW,OAAO;CAC/C,IAAI,MAAM,QAAQ,OAAO,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,GAAG,OAAO,CAAC,GAAG,MAAM,cAAc;CACpF,IAAI,MAAM,UAAU;EAClB,IAAI,CAAC,UAAU,CAAC,GAAG,OAAO;EAC1B,MAAM,IAAI,SAAS,MAAM;EACzB,OAAO;GAAE,IAAI,CAAC,GAAG,CAAC;GAAG,MAAM,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;EAAE;CAC1C;CACA,MAAM,SAAS,IAAI,UAAU,IAAI;CACjC,OAAO,SAAS,CAAC,OAAO,IAAI,IAAI,MAAM,GAAG,OAAO,IAAI,IAAI,MAAM,CAAC,GAAG,CAAC,OAAO,GAAG,OAAO,CAAC,GAAG,MAAM,EAAE,IAAI;AACtG"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//#region src/
|
|
1
|
+
//#region src/domains/snap/lazySession.ts
|
|
2
2
|
/** A session of `dep` that begins on its first `at` or `angle`, so a press
|
|
3
3
|
* that never moves reads nothing of the scene. Null without a dep. */
|
|
4
4
|
function lazySnapSession(dep, req) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lazySession.js","names":[],"sources":["../../../src/domains/snap/lazySession.ts"],"sourcesContent":["import type { SnapBegin, SnapDep, SnapSession } from 'interactions/actions/snapDep';\n\n/** A session of `dep` that begins on its first `at` or `angle`, so a press\n * that never moves reads nothing of the scene. Null without a dep. */\nexport function lazySnapSession(dep: SnapDep | undefined, req: SnapBegin): SnapSession | null {\n if (!dep) return null;\n let begun: SnapSession | null = null;\n const session = () => (begun ??= dep.begin(req));\n return {\n at: (p, mods) => session().at(p, mods),\n angle: (theta, mods) => session().angle(theta, mods),\n end: () => begun?.end(),\n };\n}\n"],"mappings":";;;AAIA,SAAgB,gBAAgB,KAA0B,KAAoC;CAC5F,IAAI,CAAC,KAAK,OAAO;CACjB,IAAI,QAA4B;CAChC,MAAM,gBAAiB,UAAU,IAAI,MAAM,GAAG;CAC9C,OAAO;EACL,KAAK,GAAG,SAAS,QAAQ,CAAC,CAAC,GAAG,GAAG,IAAI;EACrC,QAAQ,OAAO,SAAS,QAAQ,CAAC,CAAC,MAAM,OAAO,IAAI;EACnD,WAAW,OAAO,IAAI;CACxB;AACF"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { fromPlane } from "../../core/viewport/parallax.js";
|
|
2
2
|
|
|
3
|
-
//#region src/
|
|
3
|
+
//#region src/domains/snap/marks.ts
|
|
4
4
|
/** `marks` with repeats dropped, so a target several probes meet is drawn once. */
|
|
5
5
|
function distinct(marks) {
|
|
6
6
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"marks.js","names":[],"sources":["../../../src/domains/snap/marks.ts"],"sourcesContent":["import { fromPlane, type PlaneMap } from 'core/viewport/parallax';\nimport type { SnapMark } from './types';\nimport type { Point } from '@weasel-js/geom';\n\n/** `marks` with repeats dropped, so a target several probes meet is drawn once. */\nexport function distinct<P>(marks: readonly SnapMark<P>[]): SnapMark<P>[] {\n // A string key keeps this linear: comparing every pair field by field more\n // than doubled a crowded row's frame time (culling.test.ts, 2026-10-18).\n const seen = new Set<string>();\n return marks.filter((m) => {\n const key = JSON.stringify(m);\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n });\n}\n\n/** `m` carried out of a plane into the camera's world, where the readout draws. */\nexport function markFromPlane(m: SnapMark, plane: PlaneMap): SnapMark {\n const pt = (p: Point) => fromPlane(plane, p);\n return m.kind === 'point' ? { ...m, at: pt(m.at) } : { ...m, from: pt(m.from), to: pt(m.to) };\n}\n"],"mappings":";;;;AAKA,SAAgB,SAAY,OAA8C;CAGxE,MAAM,uBAAO,IAAI,IAAY;CAC7B,OAAO,MAAM,QAAQ,MAAM;EACzB,MAAM,MAAM,KAAK,UAAU,CAAC;EAC5B,IAAI,KAAK,IAAI,GAAG,GAAG,OAAO;EAC1B,KAAK,IAAI,GAAG;EACZ,OAAO;CACT,CAAC;AACH;;AAGA,SAAgB,cAAc,GAAa,OAA2B;CACpE,MAAM,MAAM,MAAa,UAAU,OAAO,CAAC;CAC3C,OAAO,EAAE,SAAS,UAAU;EAAE,GAAG;EAAG,IAAI,GAAG,EAAE,EAAE;CAAE,IAAI;EAAE,GAAG;EAAG,MAAM,GAAG,EAAE,IAAI;EAAG,IAAI,GAAG,EAAE,EAAE;CAAE;AAC9F"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outcomeStore.js","names":[],"sources":["../../../src/domains/snap/outcomeStore.ts"],"sourcesContent":["import type { SnapMark } from './types';\nimport type { Point } from '@weasel-js/geom';\n\n/** The marks of the snap in flight, for the readout to draw. */\nexport interface SnapOutcomeStore<P = Point> {\n get(): readonly SnapMark<P>[];\n set(marks: readonly SnapMark<P>[]): void;\n subscribe(listener: () => void): () => void;\n}\n\nconst NONE: readonly never[] = [];\n\n/** An empty outcome store, which notifies only when the marks change. */\nexport function createSnapOutcomeStore<P = Point>(): SnapOutcomeStore<P> {\n let marks: readonly SnapMark<P>[] = NONE;\n const listeners = new Set<() => void>();\n return {\n get: () => marks,\n set(next) {\n if (next.length === 0 && marks.length === 0) return;\n marks = next.length === 0 ? NONE : next;\n for (const l of [...listeners]) l();\n },\n subscribe(listener) {\n listeners.add(listener);\n return () => { listeners.delete(listener); };\n },\n };\n}\n"],"mappings":";AAUA,IAAM,OAAyB,CAAC;;AAGhC,SAAgB,yBAAyD;CACvE,IAAI,QAAgC;CACpC,MAAM,4BAAY,IAAI,IAAgB;CACtC,OAAO;EACL,WAAW;EACX,IAAI,MAAM;GACR,IAAI,KAAK,WAAW,KAAK,MAAM,WAAW,GAAG;GAC7C,QAAQ,KAAK,WAAW,IAAI,OAAO;GACnC,KAAK,MAAM,KAAK,CAAC,GAAG,SAAS,GAAG,EAAE;EACpC;EACA,UAAU,UAAU;GAClB,UAAU,IAAI,QAAQ;GACtB,aAAa;IAAE,UAAU,OAAO,QAAQ;GAAG;EAC7C;CACF;AACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pointSnap.js","names":[],"sources":["../../../src/domains/snap/pointSnap.ts"],"sourcesContent":["import type { SnapBegin, SnapDep, SnapMods, SnapOutcome, SnapSession } from 'interactions/actions/snapDep';\nimport { inputSession } from './session2d';\nimport type { Point } from '@weasel-js/geom';\n\nconst FREE: SnapMods = { suspend: false, constrain: false };\n\n/** A drawing tool's point snapping: the points it places one by one, and the\n * cursor it trails from the last of them. */\nexport interface PointSnap {\n /** Where a point placed at `p` lands, in a `point` session of its own\n * whose `origin` is the point placed before. */\n place(dep: SnapDep | undefined, p: Point, mods: SnapMods, origin?: Point): SnapOutcome;\n /** Where the cursor at `p` lands. One session runs while `dep` and\n * `origin` stay the same, and its marks stay drawn until {@link stop}. */\n trail(dep: SnapDep | undefined, p: Point, origin?: Point): Point;\n /** End the cursor's session, clearing its marks. */\n stop(): void;\n}\n\n/** A {@link PointSnap}. With no `snap` dep, or one that runs no sessions,\n * every point lands where it is. */\nexport function pointSnap(): PointSnap {\n let live: { session: SnapSession; dep: SnapDep | undefined; origin: Point | undefined } | null = null;\n const begin = (dep: SnapDep | undefined, req: SnapBegin) => dep?.begin(req) ?? inputSession(req);\n const request = (p: Point, origin: Point | undefined): SnapBegin => ({ gesture: 'point', press: p, ...(origin ? { origin } : {}) });\n const stop = () => {\n live?.session.end();\n live = null;\n };\n return {\n place(dep, p, mods, origin) {\n const session = begin(dep, request(p, origin));\n try {\n return session.at(p, mods);\n } finally {\n session.end();\n }\n },\n trail(dep, p, origin) {\n if (!live || live.dep !== dep || live.origin?.x !== origin?.x || live.origin?.y !== origin?.y) {\n stop();\n live = { session: begin(dep, request(p, origin)), dep, origin: origin && { ...origin } };\n }\n return live.session.at(p, FREE).point;\n },\n stop,\n };\n}\n"],"mappings":";;;AAIA,IAAM,OAAiB;CAAE,SAAS;CAAO,WAAW;AAAM;;;AAiB1D,SAAgB,YAAuB;CACrC,IAAI,OAA6F;CACjG,MAAM,SAAS,KAA0B,QAAmB,KAAK,MAAM,GAAG,KAAK,aAAa,GAAG;CAC/F,MAAM,WAAW,GAAU,YAA0C;EAAE,SAAS;EAAS,OAAO;EAAG,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;CAAG;CACjI,MAAM,aAAa;EACjB,MAAM,QAAQ,IAAI;EAClB,OAAO;CACT;CACA,OAAO;EACL,MAAM,KAAK,GAAG,MAAM,QAAQ;GAC1B,MAAM,UAAU,MAAM,KAAK,QAAQ,GAAG,MAAM,CAAC;GAC7C,IAAI;IACF,OAAO,QAAQ,GAAG,GAAG,IAAI;GAC3B,UAAU;IACR,QAAQ,IAAI;GACd;EACF;EACA,MAAM,KAAK,GAAG,QAAQ;GACpB,IAAI,CAAC,QAAQ,KAAK,QAAQ,OAAO,KAAK,QAAQ,MAAM,QAAQ,KAAK,KAAK,QAAQ,MAAM,QAAQ,GAAG;IAC7F,KAAK;IACL,OAAO;KAAE,SAAS,MAAM,KAAK,QAAQ,GAAG,MAAM,CAAC;KAAG;KAAK,QAAQ,UAAU,EAAE,GAAG,OAAO;IAAE;GACzF;GACA,OAAO,KAAK,QAAQ,GAAG,GAAG,IAAI,CAAC,CAAC;EAClC;EACA;CACF;AACF"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { unionBounds } from "../../core/geometry/unionBounds.js";
|
|
2
2
|
import { resizeProbes, resizeSubject } from "./resizeBox.js";
|
|
3
3
|
|
|
4
|
-
//#region src/
|
|
4
|
+
//#region src/domains/snap/probes2d.ts
|
|
5
5
|
/** The union drawn box of the subjects, or null when none is left. */
|
|
6
6
|
function subjectBox(ids, reads) {
|
|
7
7
|
const boxes = [];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"probes2d.js","names":[],"sources":["../../../src/domains/snap/probes2d.ts"],"sourcesContent":["import { unionBounds } from 'core/geometry/unionBounds';\nimport type { Bounds } from 'core/viewport/fitViewToBounds';\nimport type { SnapBegin } from 'interactions/actions/snapDep';\nimport type { SnapProbeAt } from './types';\nimport { resizeProbes, resizeSubject, type ResizeSubject } from './resizeBox';\nimport type { Point } from '@weasel-js/geom';\n\n/** How a 2D session reads its subject at press. */\nexport interface ProbeReads {\n /** `id`'s world pose now, or undefined when it is gone. */\n pose(id: string): unknown;\n /** The axis-aligned box `id` is drawn with at `pose`, stroke included. */\n drawnBox(id: string, pose: unknown): Bounds;\n /** The point of `pose` a grid rounds: its `OriginProjection` origin. */\n origin(pose: unknown): Point;\n /** The point of the subject's own geometry nearest `press`, or null. */\n geometryAt?(press: Point, ids: readonly string[]): Point | null;\n}\n\n/** The union drawn box of the subjects, or null when none is left. */\nexport function subjectBox(ids: readonly string[], reads: ProbeReads): Bounds | null {\n const boxes: Bounds[] = [];\n for (const id of ids) {\n const pose = reads.pose(id);\n if (pose !== undefined) boxes.push(reads.drawnBox(id, pose));\n }\n return unionBounds(boxes);\n}\n\n/** What a gesture drags, read once at press. */\nexport interface Subject2d {\n /** A move's subjects' union drawn box. */\n box: Bounds | null;\n /** A resize's box and frame: the one it names, else the subjects' drawn\n * box, axis-aligned. */\n resize: ResizeSubject | null;\n}\n\n/** The subject of `req`, null where the gesture has none or nothing is left. */\nexport function subjectOf(req: SnapBegin, reads: ProbeReads): Subject2d {\n if (req.gesture === 'move') return { box: subjectBox(req.ids ?? [], reads), resize: null };\n if (req.gesture !== 'resize' || !req.handle) return { box: null, resize: null };\n if (req.box) return { box: null, resize: resizeSubject(req.box, req.handle) };\n const bounds = subjectBox(req.ids ?? [], reads);\n return { box: null, resize: bounds ? resizeSubject({ bounds }, req.handle) : null };\n}\n\n/** The probes a gesture snaps, where they are at press. */\nexport function buildProbes(req: SnapBegin, reads: ProbeReads, subject = subjectOf(req, reads)): SnapProbeAt[] {\n const ids = req.ids ?? [];\n switch (req.gesture) {\n case 'point':\n return [{ id: 'pointer', at: req.press, role: 'pointer' }];\n case 'resize':\n return subject.resize ? resizeProbes(subject.resize) : [{ id: 'pointer', at: req.press, role: 'pointer' }];\n case 'move':\n return moveProbes(req.press, ids, reads, subject.box);\n case 'rotate':\n case 'handle':\n return [];\n }\n}\n\nfunction moveProbes(press: Point, ids: readonly string[], reads: ProbeReads, box: Bounds | null): SnapProbeAt[] {\n const out: SnapProbeAt[] = [];\n for (const id of ids) {\n const pose = reads.pose(id);\n if (pose !== undefined) out.push({ id: `origin:${id}`, at: reads.origin(pose), role: 'origin' });\n }\n if (box) {\n out.push(\n { id: 'box.min', at: { x: box.x, y: box.y }, role: 'box' },\n { id: 'box.center', at: { x: box.x + box.width / 2, y: box.y + box.height / 2 }, role: 'box' },\n { id: 'box.max', at: { x: box.x + box.width, y: box.y + box.height }, role: 'box' },\n );\n }\n const geometry = reads.geometryAt?.(press, ids) ?? press;\n out.push({ id: 'geometry', at: { x: geometry.x, y: geometry.y }, role: 'geometry' });\n return out;\n}\n"],"mappings":";;;;;AAoBA,SAAgB,WAAW,KAAwB,OAAkC;CACnF,MAAM,QAAkB,CAAC;CACzB,KAAK,MAAM,MAAM,KAAK;EACpB,MAAM,OAAO,MAAM,KAAK,EAAE;EAC1B,IAAI,SAAS,QAAW,MAAM,KAAK,MAAM,SAAS,IAAI,IAAI,CAAC;CAC7D;CACA,OAAO,YAAY,KAAK;AAC1B;;AAYA,SAAgB,UAAU,KAAgB,OAA8B;CACtE,IAAI,IAAI,YAAY,QAAQ,OAAO;EAAE,KAAK,WAAW,IAAI,OAAO,CAAC,GAAG,KAAK;EAAG,QAAQ;CAAK;CACzF,IAAI,IAAI,YAAY,YAAY,CAAC,IAAI,QAAQ,OAAO;EAAE,KAAK;EAAM,QAAQ;CAAK;CAC9E,IAAI,IAAI,KAAK,OAAO;EAAE,KAAK;EAAM,QAAQ,cAAc,IAAI,KAAK,IAAI,MAAM;CAAE;CAC5E,MAAM,SAAS,WAAW,IAAI,OAAO,CAAC,GAAG,KAAK;CAC9C,OAAO;EAAE,KAAK;EAAM,QAAQ,SAAS,cAAc,EAAE,OAAO,GAAG,IAAI,MAAM,IAAI;CAAK;AACpF;;AAGA,SAAgB,YAAY,KAAgB,OAAmB,UAAU,UAAU,KAAK,KAAK,GAAkB;CAC7G,MAAM,MAAM,IAAI,OAAO,CAAC;CACxB,QAAQ,IAAI,SAAZ;EACE,KAAK,SACH,OAAO,CAAC;GAAE,IAAI;GAAW,IAAI,IAAI;GAAO,MAAM;EAAU,CAAC;EAC3D,KAAK,UACH,OAAO,QAAQ,SAAS,aAAa,QAAQ,MAAM,IAAI,CAAC;GAAE,IAAI;GAAW,IAAI,IAAI;GAAO,MAAM;EAAU,CAAC;EAC3G,KAAK,QACH,OAAO,WAAW,IAAI,OAAO,KAAK,OAAO,QAAQ,GAAG;EACtD,KAAK;EACL,KAAK,UACH,OAAO,CAAC;CACZ;AACF;AAEA,SAAS,WAAW,OAAc,KAAwB,OAAmB,KAAmC;CAC9G,MAAM,MAAqB,CAAC;CAC5B,KAAK,MAAM,MAAM,KAAK;EACpB,MAAM,OAAO,MAAM,KAAK,EAAE;EAC1B,IAAI,SAAS,QAAW,IAAI,KAAK;GAAE,IAAI,UAAU;GAAM,IAAI,MAAM,OAAO,IAAI;GAAG,MAAM;EAAS,CAAC;CACjG;CACA,IAAI,KACF,IAAI,KACF;EAAE,IAAI;EAAW,IAAI;GAAE,GAAG,IAAI;GAAG,GAAG,IAAI;EAAE;EAAG,MAAM;CAAM,GACzD;EAAE,IAAI;EAAc,IAAI;GAAE,GAAG,IAAI,IAAI,IAAI,QAAQ;GAAG,GAAG,IAAI,IAAI,IAAI,SAAS;EAAE;EAAG,MAAM;CAAM,GAC7F;EAAE,IAAI;EAAW,IAAI;GAAE,GAAG,IAAI,IAAI,IAAI;GAAO,GAAG,IAAI,IAAI,IAAI;EAAO;EAAG,MAAM;CAAM,CACpF;CAEF,MAAM,WAAW,MAAM,aAAa,OAAO,GAAG,KAAK;CACnD,IAAI,KAAK;EAAE,IAAI;EAAY,IAAI;GAAE,GAAG,SAAS;GAAG,GAAG,SAAS;EAAE;EAAG,MAAM;CAAW,CAAC;CACnF,OAAO;AACT"}
|
|
@@ -2,7 +2,7 @@ import { pathSnapGlyph } from "../paths/pathSnap/glyphs.js";
|
|
|
2
2
|
import { textCommand, textCommandFromRuns } from "@weasel-js/renderer";
|
|
3
3
|
import { PATH_L, PATH_M, pathFromD, rectPath } from "@weasel-js/geom";
|
|
4
4
|
|
|
5
|
-
//#region src/
|
|
5
|
+
//#region src/domains/snap/readoutDraw.ts
|
|
6
6
|
/**
|
|
7
7
|
* The screen-space drawing the snap readout and the guides overlay share:
|
|
8
8
|
* ticked segments, number pills, and the glyph-and-label of a point mark.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"readoutDraw.js","names":[],"sources":["../../../src/domains/snap/readoutDraw.ts"],"sourcesContent":["/**\n * The screen-space drawing the snap readout and the guides overlay share:\n * ticked segments, number pills, and the glyph-and-label of a point mark.\n */\nimport { PATH_L, PATH_M, pathFromD, rectPath, type PolygonPath, type PathSnapKind } from '@weasel-js/geom';\nimport { textCommand, textCommandFromRuns, type CommandStroke, type DrawCommand } from '@weasel-js/renderer';\nimport { pathSnapGlyph } from 'domains/paths/pathSnap/glyphs';\n\nconst PILL_FONT = { fontSize: 10 };\n// No text measurer in a layer: a 10px digit advances about 6px.\nconst PILL_CHAR_W = 6;\nconst PILL_H = 14;\nconst PILL_PAD_X = 4;\n\n/** A straight segment from (x0, y0) to (x1, y1), with a tick of length `t`\n * across each end. Screen px. */\nexport function tickedSegment(x0: number, y0: number, x1: number, y1: number, t: number): PolygonPath {\n const h = t / 2;\n const len = Math.hypot(x1 - x0, y1 - y0);\n // Across the segment: the pixel axes when it runs along one, else its normal.\n const [nx, ny] = x0 === x1 ? [1, 0] : y0 === y1 || len === 0 ? [0, 1] : [-(y1 - y0) / len, (x1 - x0) / len];\n const ends = t <= 0 ? [] : [\n x0 - nx * h, y0 - ny * h, x0 + nx * h, y0 + ny * h,\n x1 - nx * h, y1 - ny * h, x1 + nx * h, y1 + ny * h,\n ];\n const coords = [x0, y0, x1, y1, ...ends];\n const commands: number[] = [];\n for (let i = 0; i < coords.length; i += 4) commands.push(PATH_M, PATH_L);\n return {\n kind: 'polygon',\n commands: new Uint8Array(commands),\n coords: new Float32Array(coords),\n fillRule: 'nonzero',\n };\n}\n\n/** `text` on a filled pill centered at (cx, cy), in white on `color`. */\nexport function pillCommands(cx: number, cy: number, text: string, color: string): DrawCommand[] {\n const w = text.length * PILL_CHAR_W + PILL_PAD_X * 2;\n const left = cx - w / 2;\n const top = cy - PILL_H / 2;\n return [\n { kind: 'path', path: rectPath(left, top, w, PILL_H), fill: { paint: { kind: 'solid', color } } },\n textCommandFromRuns(left + PILL_PAD_X, top + 2, [{ text, fill: { paint: { kind: 'solid', color: '#fff' } } }], PILL_FONT),\n ];\n}\n\n/** A ticked segment between two screen points, with `label` on a pill at its middle. */\nexport function measuredSegmentCommands(\n x0: number, y0: number, x1: number, y1: number,\n ticks: number, stroke: CommandStroke, label: string | null, color: string,\n): DrawCommand[] {\n const out: DrawCommand[] = [{ kind: 'path', path: tickedSegment(x0, y0, x1, y1, ticks), stroke }];\n if (label !== null) out.push(...pillCommands((x0 + x1) / 2, (y0 + y1) / 2, label, color));\n return out;\n}\n\n/** The glyph for `glyph` on (x, y), `r` from center to edge, with `label`\n * above and to its right. An unknown glyph name draws as `anchor`. */\nexport function glyphCommands(\n glyph: string, x: number, y: number, label: string | undefined, color: string, r = 5, fontSize = 11,\n): DrawCommand[] {\n const d = pathSnapGlyph(glyph as PathSnapKind, x, y, r) ?? pathSnapGlyph('anchor', x, y, r);\n const out: DrawCommand[] = [\n { kind: 'path', path: pathFromD(d), stroke: { paint: { color }, width: 1.5 } },\n ];\n if (label) {\n out.push(textCommand(x + r + 3, y - r - fontSize - 2, label, { fontSize }, undefined, undefined, undefined, {\n fill: { paint: { color } },\n }));\n }\n return out;\n}\n"],"mappings":";;;;;;;;;AAQA,IAAM,YAAY,EAAE,UAAU,GAAG;AAEjC,IAAM,cAAc;AACpB,IAAM,SAAS;AACf,IAAM,aAAa;;;AAInB,SAAgB,cAAc,IAAY,IAAY,IAAY,IAAY,GAAwB;CACpG,MAAM,IAAI,IAAI;CACd,MAAM,MAAM,KAAK,MAAM,KAAK,IAAI,KAAK,EAAE;CAEvC,MAAM,CAAC,IAAI,MAAM,OAAO,KAAK,CAAC,GAAG,CAAC,IAAI,OAAO,MAAM,QAAQ,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,KAAK,MAAM,MAAM,KAAK,MAAM,GAAG;CAK1G,MAAM,SAAS;EAAC;EAAI;EAAI;EAAI;EAAI,GAJnB,KAAK,IAAI,CAAC,IAAI;GACzB,KAAK,KAAK;GAAG,KAAK,KAAK;GAAG,KAAK,KAAK;GAAG,KAAK,KAAK;GACjD,KAAK,KAAK;GAAG,KAAK,KAAK;GAAG,KAAK,KAAK;GAAG,KAAK,KAAK;EACnD;CACuC;CACvC,MAAM,WAAqB,CAAC;CAC5B,KAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK,GAAG,SAAS,KAAK,QAAQ,MAAM;CACvE,OAAO;EACL,MAAM;EACN,UAAU,IAAI,WAAW,QAAQ;EACjC,QAAQ,IAAI,aAAa,MAAM;EAC/B,UAAU;CACZ;AACF;;AAGA,SAAgB,aAAa,IAAY,IAAY,MAAc,OAA8B;CAC/F,MAAM,IAAI,KAAK,SAAS,cAAc;CACtC,MAAM,OAAO,KAAK,IAAI;CACtB,MAAM,MAAM,KAAK,SAAS;CAC1B,OAAO,CACL;EAAE,MAAM;EAAQ,MAAM,SAAS,MAAM,KAAK,GAAG,MAAM;EAAG,MAAM,EAAE,OAAO;GAAE,MAAM;GAAS;EAAM,EAAE;CAAE,GAChG,oBAAoB,OAAO,YAAY,MAAM,GAAG,CAAC;EAAE;EAAM,MAAM,EAAE,OAAO;GAAE,MAAM;GAAS,OAAO;EAAO,EAAE;CAAE,CAAC,GAAG,SAAS,CAC1H;AACF;;AAGA,SAAgB,wBACd,IAAY,IAAY,IAAY,IACpC,OAAe,QAAuB,OAAsB,OAC7C;CACf,MAAM,MAAqB,CAAC;EAAE,MAAM;EAAQ,MAAM,cAAc,IAAI,IAAI,IAAI,IAAI,KAAK;EAAG;CAAO,CAAC;CAChG,IAAI,UAAU,MAAM,IAAI,KAAK,GAAG,cAAc,KAAK,MAAM,IAAI,KAAK,MAAM,GAAG,OAAO,KAAK,CAAC;CACxF,OAAO;AACT;;;AAIA,SAAgB,cACd,OAAe,GAAW,GAAW,OAA2B,OAAe,IAAI,GAAG,WAAW,IAClF;CACf,MAAM,IAAI,cAAc,OAAuB,GAAG,GAAG,CAAC,KAAK,cAAc,UAAU,GAAG,GAAG,CAAC;CAC1F,MAAM,MAAqB,CACzB;EAAE,MAAM;EAAQ,MAAM,UAAU,CAAC;EAAG,QAAQ;GAAE,OAAO,EAAE,MAAM;GAAG,OAAO;EAAI;CAAE,CAC/E;CACA,IAAI,OACF,IAAI,KAAK,YAAY,IAAI,IAAI,GAAG,IAAI,IAAI,WAAW,GAAG,OAAO,EAAE,SAAS,GAAG,QAAW,QAAW,QAAW,EAC1G,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,EAC3B,CAAC,CAAC;CAEJ,OAAO;AACT"}
|
|
@@ -2,7 +2,7 @@ import { viewToTransform } from "../../core/viewport/view.js";
|
|
|
2
2
|
import { worldToScreen } from "../../core/viewport/viewTransform.js";
|
|
3
3
|
import { glyphCommands, measuredSegmentCommands } from "./readoutDraw.js";
|
|
4
4
|
|
|
5
|
-
//#region src/
|
|
5
|
+
//#region src/domains/snap/readoutLayer.ts
|
|
6
6
|
var TICK = 6;
|
|
7
7
|
/** A screen-space layer drawing the marks in `store`, redrawn when they change. */
|
|
8
8
|
function createSnapReadoutLayer(store, style = {}) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"readoutLayer.js","names":[],"sources":["../../../src/domains/snap/readoutLayer.ts"],"sourcesContent":["/** The one layer that draws what a snap won: every mark in the outcome store. */\nimport type { DrawCommand } from '@weasel-js/renderer';\nimport type { RenderLayer } from 'core/layers/render';\nimport { viewToTransform } from 'core/viewport/view';\nimport { worldToScreen } from 'core/viewport/viewTransform';\nimport type { SnapOutcomeStore } from './outcomeStore';\nimport { glyphCommands, measuredSegmentCommands } from './readoutDraw';\nimport type { SnapReadoutStyle } from './types';\n\nconst TICK = 6;\n\n/** A screen-space layer drawing the marks in `store`, redrawn when they change. */\nexport function createSnapReadoutLayer(\n store: SnapOutcomeStore,\n style: SnapReadoutStyle = {},\n): RenderLayer<unknown> {\n const color = style.color ?? '#e8742c';\n const gapColor = style.gapColor ?? '#3aa0ff';\n const width = style.lineWidth ?? 1;\n const strokeOf = (c: string) => ({ paint: { kind: 'solid' as const, color: c }, width });\n return {\n id: 'snap-readout',\n label: 'Snap readout',\n space: 'screen',\n alwaysOn: true,\n subscribe: (repaint) => store.subscribe(repaint),\n draw: (_data, view) => {\n const marks = store.get();\n if (marks.length === 0) return [];\n const t = viewToTransform(view);\n const out: DrawCommand[] = [];\n for (const m of marks) {\n const measured = m.kind === 'gap' || m.kind === 'distance';\n const c = m.color ?? (measured ? gapColor : color);\n if (m.kind === 'point') {\n const [x, y] = worldToScreen(m.at.x, m.at.y, t);\n out.push(...glyphCommands(m.glyph, x, y, m.label, c));\n continue;\n }\n const [x0, y0] = worldToScreen(m.from.x, m.from.y, t);\n const [x1, y1] = worldToScreen(m.to.x, m.to.y, t);\n out.push(...measuredSegmentCommands(\n x0, y0, x1, y1, measured ? TICK : 0, strokeOf(c), measured ? String(Math.round(m.value)) : null, c,\n ));\n }\n return out;\n },\n };\n}\n"],"mappings":";;;;;AASA,IAAM,OAAO;;AAGb,SAAgB,uBACd,OACA,QAA0B,CAAC,GACL;CACtB,MAAM,QAAQ,MAAM,SAAS;CAC7B,MAAM,WAAW,MAAM,YAAY;CACnC,MAAM,QAAQ,MAAM,aAAa;CACjC,MAAM,YAAY,OAAe;EAAE,OAAO;GAAE,MAAM;GAAkB,OAAO;EAAE;EAAG;CAAM;CACtF,OAAO;EACL,IAAI;EACJ,OAAO;EACP,OAAO;EACP,UAAU;EACV,YAAY,YAAY,MAAM,UAAU,OAAO;EAC/C,OAAO,OAAO,SAAS;GACrB,MAAM,QAAQ,MAAM,IAAI;GACxB,IAAI,MAAM,WAAW,GAAG,OAAO,CAAC;GAChC,MAAM,IAAI,gBAAgB,IAAI;GAC9B,MAAM,MAAqB,CAAC;GAC5B,KAAK,MAAM,KAAK,OAAO;IACrB,MAAM,WAAW,EAAE,SAAS,SAAS,EAAE,SAAS;IAChD,MAAM,IAAI,EAAE,UAAU,WAAW,WAAW;IAC5C,IAAI,EAAE,SAAS,SAAS;KACtB,MAAM,CAAC,GAAG,KAAK,cAAc,EAAE,GAAG,GAAG,EAAE,GAAG,GAAG,CAAC;KAC9C,IAAI,KAAK,GAAG,cAAc,EAAE,OAAO,GAAG,GAAG,EAAE,OAAO,CAAC,CAAC;KACpD;IACF;IACA,MAAM,CAAC,IAAI,MAAM,cAAc,EAAE,KAAK,GAAG,EAAE,KAAK,GAAG,CAAC;IACpD,MAAM,CAAC,IAAI,MAAM,cAAc,EAAE,GAAG,GAAG,EAAE,GAAG,GAAG,CAAC;IAChD,IAAI,KAAK,GAAG,wBACV,IAAI,IAAI,IAAI,IAAI,WAAW,OAAO,GAAG,SAAS,CAAC,GAAG,WAAW,OAAO,KAAK,MAAM,EAAE,KAAK,CAAC,IAAI,MAAM,CACnG,CAAC;GACH;GACA,OAAO;EACT;CACF;AACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","names":[],"sources":["../../../src/domains/snap/registry.ts"],"sourcesContent":["import { createContext, useContext, useEffect } from 'react';\nimport type { SnapSource } from './types';\n\n/** The sources contributed to one canvas by {@link useSnapSource}, in mount order. */\nexport interface SnapSourceRegistry {\n list(): readonly SnapSource[];\n add(source: SnapSource): () => void;\n}\n\nexport function createSnapSourceRegistry(): SnapSourceRegistry {\n let sources: readonly SnapSource[] = [];\n return {\n list: () => sources,\n add(source) {\n sources = [...sources, source];\n return () => { sources = sources.filter((s) => s !== source); };\n },\n };\n}\n\nexport const SnapSourceRegistryContext = createContext<SnapSourceRegistry | null>(null);\n\n/** Adds `source` to the enclosing `<SceneCanvas>`'s snapping while mounted.\n * Pass a stable object: a new one each render re-registers it. */\nexport function useSnapSource(source: SnapSource): void {\n const registry = useContext(SnapSourceRegistryContext);\n if (!registry) throw new Error('[useSnapSource] call it under a <SceneCanvas>');\n useEffect(() => registry.add(source), [registry, source]);\n}\n"],"mappings":";;;AASA,SAAgB,2BAA+C;CAC7D,IAAI,UAAiC,CAAC;CACtC,OAAO;EACL,YAAY;EACZ,IAAI,QAAQ;GACV,UAAU,CAAC,GAAG,SAAS,MAAM;GAC7B,aAAa;IAAE,UAAU,QAAQ,QAAQ,MAAM,MAAM,MAAM;GAAG;EAChE;CACF;AACF;AAEA,IAAa,4BAA4B,cAAyC,IAAI;;;AAItF,SAAgB,cAAc,QAA0B;CACtD,MAAM,WAAW,WAAW,yBAAyB;CACrD,IAAI,CAAC,UAAU,MAAM,IAAI,MAAM,+CAA+C;CAC9E,gBAAgB,SAAS,IAAI,MAAM,GAAG,CAAC,UAAU,MAAM,CAAC;AAC1D"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { fixedCornerOf, movedEdges, movingPoint } from "../../interactions/actions/resize/cornerHandles.js";
|
|
2
2
|
|
|
3
|
-
//#region src/
|
|
3
|
+
//#region src/domains/snap/resizeBox.ts
|
|
4
4
|
var EPS = 1e-9;
|
|
5
5
|
function resizeSubject(box, handle) {
|
|
6
6
|
const at = box.toWorld ?? ((p) => p);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resizeBox.js","names":[],"sources":["../../../src/domains/snap/resizeBox.ts"],"sourcesContent":["import type { ResizeAnchor } from '@weasel-js/routing';\nimport type { Bounds } from 'core/viewport/fitViewToBounds';\nimport { fixedCornerOf, movedEdges, movingPoint } from 'interactions/actions/resize/cornerHandles';\nimport type { SnapResizeBox } from 'interactions/actions/snapDep';\nimport type { SnapEdge, SnapEdges, SnapProbeAt } from './types';\nimport type { Point } from '@weasel-js/geom';\n\nexport const EPS = 1e-9;\n\n/** A resize's box with its frame read out, in ctx coordinates. */\nexport interface ResizeSubject {\n /** In the box's own frame. */\n bounds: Bounds;\n handle: ResizeAnchor;\n at(p: Point): Point;\n /** Where the frame's unit axes point. */\n ex: Point;\n ey: Point;\n}\n\nexport function resizeSubject(box: SnapResizeBox, handle: ResizeAnchor): ResizeSubject {\n const at = box.toWorld ?? ((p: Point) => p);\n const o = at({ x: 0, y: 0 });\n const ax = at({ x: 1, y: 0 });\n const ay = at({ x: 0, y: 1 });\n return { bounds: box.bounds, handle, at, ex: { x: ax.x - o.x, y: ax.y - o.y }, ey: { x: ay.x - o.x, y: ay.y - o.y } };\n}\n\n/** The dragged corner or edge midpoint as `pointer`, and as `box` the dragged\n * corner or both ends of the dragged edge: the points a drag δ moves by δ. */\nexport function resizeProbes(s: ResizeSubject): SnapProbeAt[] {\n const { bounds: b, handle } = s;\n const out: SnapProbeAt[] = [{ id: 'pointer', at: s.at(movingPoint(b, handle)), role: 'pointer' }];\n const sides = (pin: ResizeAnchor['x'], lo: number, size: number): number[] =>\n pin === 'min' ? [lo + size] : pin === 'max' ? [lo] : [lo, lo + size];\n const xs = sides(handle.x, b.x, b.width);\n const ys = sides(handle.y, b.y, b.height);\n if (xs.length === 2 && ys.length === 2) return out;\n for (const x of xs) for (const y of ys) out.push({ id: `box.${out.length - 1}`, at: s.at({ x, y }), role: 'box' });\n return out;\n}\n\n/** The direction an edge handle's edge moves along; null for a corner. */\nexport function edgeAxis(s: ResizeSubject): Point | null {\n const { x, y } = s.handle;\n if ((x === 'free') === (y === 'free')) return null;\n return y === 'free' ? s.ex : s.ey;\n}\n\n/** From the fixed corner to the dragged one. */\nexport function diagonal(s: ResizeSubject): Point {\n const f = s.at(fixedCornerOf(s.bounds, s.handle));\n const m = s.at(movingPoint(s.bounds, s.handle));\n return { x: m.x - f.x, y: m.y - f.y };\n}\n\n/** The box in its own frame once the handle has moved by `delta`. */\nfunction movedBox(s: ResizeSubject, delta: Point): Bounds {\n const det = s.ex.x * s.ey.y - s.ey.x * s.ex.y;\n const local = Math.abs(det) < EPS\n ? { x: 0, y: 0 }\n : { x: (s.ey.y * delta.x - s.ey.x * delta.y) / det, y: (s.ex.x * delta.y - s.ex.y * delta.x) / det };\n return movedEdges(s.bounds, s.handle, local.x, local.y);\n}\n\n/** The box's axis-aligned extent once the handle has moved by `delta`. */\nexport function resizedBox(s: ResizeSubject, delta: Point): Bounds {\n const b = movedBox(s, delta);\n const corners = [\n s.at({ x: b.x, y: b.y }), s.at({ x: b.x + b.width, y: b.y }),\n s.at({ x: b.x, y: b.y + b.height }), s.at({ x: b.x + b.width, y: b.y + b.height }),\n ];\n const xs = corners.map((c) => c.x);\n const ys = corners.map((c) => c.y);\n const x = Math.min(...xs);\n const y = Math.min(...ys);\n return { x, y, width: Math.max(...xs) - x, height: Math.max(...ys) - y };\n}\n\n/** The sides of {@link resizedBox} a drag of `delta` moves: the side across\n * from the pinned one, or the pinned side's once the drag has flipped the\n * box past it. A frame that turns or flips the box moves no side of its\n * extent alone. */\nexport function resizeEdges(s: ResizeSubject, delta: Point): SnapEdges {\n const square = Math.abs(s.ex.y) < EPS && Math.abs(s.ey.x) < EPS && s.ex.x > 0 && s.ey.y > 0;\n if (!square) return { x: null, y: null };\n const b = movedBox(s, delta);\n const moved = (pin: ResizeAnchor['x'], size: number): SnapEdge => {\n if (pin === 'free') return null;\n const far = pin === 'min' ? 'max' : 'min';\n return size >= 0 ? far : pin;\n };\n return { x: moved(s.handle.x, b.width), y: moved(s.handle.y, b.height) };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"roles.js","names":[],"sources":["../../../src/domains/snap/roles.ts"],"sourcesContent":["import { roleReader, type ModifierRoles, type ModifierState } from '@weasel-js/routing';\nimport type { SnapMods } from 'interactions/actions/snapDep';\n\n/** The modifier roles a snapping action declares. */\nexport const SNAP_ROLES = {\n 'snap.suspend': { label: 'Suspend snapping', keys: ['ctrl'] },\n 'snap.constrain': { label: 'Constrain', keys: ['shift'] },\n} as const satisfies ModifierRoles;\n\n/** The angle step `snap.constrain` (Shift) holds a direction to: a line, a\n * measurement, a rotate, a symmetry axis. 15 degrees. */\nexport const SNAP_ANGLE_STEP = Math.PI / 12;\n\n/** The step an `'axis'` lock holds a move or an anchor drag to, and Shift a\n * pen handle: the axes and the diagonals. */\nexport const SNAP_AXIS_STEP = Math.PI / 4;\n\nconst held = roleReader(SNAP_ROLES);\n\n/** The snap roles `ctx` holds. */\nexport function snapMods(ctx: { roles?: Readonly<Record<string, boolean>>; modifiers: ModifierState }): SnapMods {\n return { suspend: held(ctx, 'snap.suspend'), constrain: held(ctx, 'snap.constrain') };\n}\n"],"mappings":";;;;AAIA,IAAa,aAAa;CACxB,gBAAgB;EAAE,OAAO;EAAoB,MAAM,CAAC,MAAM;CAAE;CAC5D,kBAAkB;EAAE,OAAO;EAAa,MAAM,CAAC,OAAO;CAAE;AAC1D;;;AAIA,IAAa,kBAAkB,KAAK,KAAK;;;AAIzC,IAAa,iBAAiB,KAAK,KAAK;AAExC,IAAM,OAAO,WAAW,UAAU;;AAGlC,SAAgB,SAAS,KAAwF;CAC/G,OAAO;EAAE,SAAS,KAAK,KAAK,cAAc;EAAG,WAAW,KAAK,KAAK,gBAAgB;CAAE;AACtF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rotationSource.js","names":[],"sources":["../../../src/domains/snap/rotationSource.ts"],"sourcesContent":["import type { NodeId } from 'core/scene/types';\nimport type { AngleCandidate, AngleCollect, SnapSource } from './types';\n\nconst QUARTER = Math.PI / 2;\n\n/**\n * A rotate's angle targets: every quarter turn, and the world rotation of\n * every other visible node that can turn. Shift's step is the rotate's own.\n * Every `<SceneCanvas>` asks it, under the id `'rotation'`.\n */\nexport function rotationSnapSource(): SnapSource {\n let cached: { key: readonly unknown[]; angles: number[] } | null = null;\n const nodeAngles = (q: AngleCollect): readonly number[] => {\n const { scene, rotationOf } = q;\n if (!scene || !rotationOf) return [];\n const key = [scene, scene.getVersion(), rotationOf, q.exclude];\n if (cached && key.every((k, i) => k === cached!.key[i])) return cached.angles;\n const exclude = new Set(q.exclude);\n const angles: number[] = [];\n for (const id of scene.nodes.keys()) {\n if (exclude.has(id) || scene.isHidden(id as NodeId)) continue;\n const angle = rotationOf(id);\n if (angle !== undefined && Number.isFinite(angle)) angles.push(angle);\n }\n cached = { key, angles };\n return angles;\n };\n return {\n id: 'rotation',\n roles: [],\n gestures: ['rotate'],\n collect: () => [],\n *angles(q): Iterable<AngleCandidate> {\n for (let k = 0; k < 4; k++) yield { angle: k * QUARTER };\n for (const angle of nodeAngles(q)) yield { angle };\n },\n };\n}\n"],"mappings":";AAGA,IAAM,UAAU,KAAK,KAAK;;;;;;AAO1B,SAAgB,qBAAiC;CAC/C,IAAI,SAA+D;CACnE,MAAM,cAAc,MAAuC;EACzD,MAAM,EAAE,OAAO,eAAe;EAC9B,IAAI,CAAC,SAAS,CAAC,YAAY,OAAO,CAAC;EACnC,MAAM,MAAM;GAAC;GAAO,MAAM,WAAW;GAAG;GAAY,EAAE;EAAO;EAC7D,IAAI,UAAU,IAAI,OAAO,GAAG,MAAM,MAAM,OAAQ,IAAI,EAAE,GAAG,OAAO,OAAO;EACvE,MAAM,UAAU,IAAI,IAAI,EAAE,OAAO;EACjC,MAAM,SAAmB,CAAC;EAC1B,KAAK,MAAM,MAAM,MAAM,MAAM,KAAK,GAAG;GACnC,IAAI,QAAQ,IAAI,EAAE,KAAK,MAAM,SAAS,EAAY,GAAG;GACrD,MAAM,QAAQ,WAAW,EAAE;GAC3B,IAAI,UAAU,UAAa,OAAO,SAAS,KAAK,GAAG,OAAO,KAAK,KAAK;EACtE;EACA,SAAS;GAAE;GAAK;EAAO;EACvB,OAAO;CACT;CACA,OAAO;EACL,IAAI;EACJ,OAAO,CAAC;EACR,UAAU,CAAC,QAAQ;EACnB,eAAe,CAAC;EAChB,CAAC,OAAO,GAA6B;GACnC,KAAK,IAAI,IAAI,GAAG,IAAI,GAAG,KAAK,MAAM,EAAE,OAAO,IAAI,QAAQ;GACvD,KAAK,MAAM,SAAS,WAAW,CAAC,GAAG,MAAM,EAAE,MAAM;EACnD;CACF;AACF"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { scenePoseFrame } from "../../interactions/actions/poseFrame.js";
|
|
1
|
+
import { sceneBoxFrames, scenePoseFrame } from "../../interactions/actions/poseFrame.js";
|
|
2
2
|
import { nodeDescriptors, poseDescriptorOf } from "../../interactions/actions/poseDescriptorDep.js";
|
|
3
3
|
import { AUTO_ORIGIN_PROJECTION } from "../../interactions/gestures/shared/originProjection.js";
|
|
4
|
+
import { applyToPoint, invert } from "@weasel-js/geom";
|
|
4
5
|
|
|
5
|
-
//#region src/
|
|
6
|
+
//#region src/domains/snap/sceneReads.ts
|
|
6
7
|
/** {@link ProbeReads} over a canvas's scene, read when a session begins.
|
|
7
8
|
* `boxes` is the canvas's `drawnBoxes`, which alignment measures with too. */
|
|
8
9
|
function sceneProbeReads(args) {
|
|
@@ -28,6 +29,26 @@ function sceneRotations(scene, descriptor) {
|
|
|
28
29
|
return d.getRotation(frame.world(id));
|
|
29
30
|
};
|
|
30
31
|
}
|
|
32
|
+
/** Each node's box frame, as `SnapCollect.frameOf` hands it to a source. */
|
|
33
|
+
function sceneSnapFrames(scene) {
|
|
34
|
+
const boxes = sceneBoxFrames(scene);
|
|
35
|
+
return (id) => {
|
|
36
|
+
const m = boxes(id);
|
|
37
|
+
if (!m) return void 0;
|
|
38
|
+
const back = invert(m);
|
|
39
|
+
const through = (t, p) => {
|
|
40
|
+
const [x, y] = applyToPoint(t, p.x, p.y);
|
|
41
|
+
return {
|
|
42
|
+
x,
|
|
43
|
+
y
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
return {
|
|
47
|
+
toWorld: (p) => through(m, p),
|
|
48
|
+
toLocal: (p) => back ? through(back, p) : null
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
}
|
|
31
52
|
/** `ids` and every node under them: what a gesture moving `ids` carries. */
|
|
32
53
|
function withSubtrees(scene, ids) {
|
|
33
54
|
const out = /* @__PURE__ */ new Set();
|
|
@@ -41,5 +62,5 @@ function withSubtrees(scene, ids) {
|
|
|
41
62
|
}
|
|
42
63
|
|
|
43
64
|
//#endregion
|
|
44
|
-
export { sceneProbeReads, sceneRotations, withSubtrees };
|
|
65
|
+
export { sceneProbeReads, sceneRotations, sceneSnapFrames, withSubtrees };
|
|
45
66
|
//# sourceMappingURL=sceneReads.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sceneReads.js","names":[],"sources":["../../../src/domains/snap/sceneReads.ts"],"sourcesContent":["import { applyToPoint, invert, type Point } from '@weasel-js/geom';\nimport type { WorldPoint } from '@weasel-js/routing';\nimport type { NodeId, Scene } from 'core/scene/types';\nimport type { DrawnBoxes } from 'interactions/actions/drawnBoxes';\nimport { nodeDescriptors, poseDescriptorOf } from 'interactions/actions/poseDescriptorDep';\nimport { sceneBoxFrames, scenePoseFrame } from 'interactions/actions/poseFrame';\nimport type { PoseDescriptor } from 'interactions/actions/resize/geometry';\nimport { AUTO_ORIGIN_PROJECTION, type OriginProjection } from 'interactions/gestures/shared/originProjection';\nimport type { ProbeReads } from './probes2d';\nimport type { SnapFrame } from './types';\n\n/** {@link ProbeReads} over a canvas's scene, read when a session begins.\n * `boxes` is the canvas's `drawnBoxes`, which alignment measures with too. */\nexport function sceneProbeReads(args: {\n scene: Scene<unknown, string, unknown>;\n boxes: DrawnBoxes;\n geometryAt?: (press: WorldPoint, ids: readonly string[]) => WorldPoint | null;\n /** How a pose's origin is read. Default `AUTO_ORIGIN_PROJECTION`. */\n originProjection?: OriginProjection<unknown>;\n}): ProbeReads {\n const { scene } = args;\n const frame = scenePoseFrame(scene);\n return {\n pose: (id) => (scene.get(id as NodeId) === undefined ? undefined : frame.world(id as NodeId)),\n drawnBox: (id, pose) => args.boxes.aabb(id, pose),\n origin: (pose) => (args.originProjection ?? AUTO_ORIGIN_PROJECTION).getOrigin(pose),\n ...(args.geometryAt ? { geometryAt: args.geometryAt } : {}),\n };\n}\n\n/** Each node's world rotation, read through its own descriptor the way a\n * rotate reads its subject; undefined for a node that cannot turn. */\nexport function sceneRotations(\n scene: Scene<unknown, string, unknown>,\n descriptor?: PoseDescriptor<unknown>,\n): (id: string) => number | undefined {\n const frame = scenePoseFrame(scene);\n const descriptorOf = nodeDescriptors(scene, poseDescriptorOf(descriptor));\n return (id) => {\n const node = scene.get(id as NodeId);\n if (!node) return undefined;\n const d = descriptorOf(id);\n if (!d.withRotation || !d.getRotation || d.supportsRotation?.(node.pose) === false) return undefined;\n return d.getRotation(frame.world(id as NodeId));\n };\n}\n\n/** Each node's box frame, as `SnapCollect.frameOf` hands it to a source. */\nexport function sceneSnapFrames(scene: Scene<unknown, string, unknown>): (id: string) => SnapFrame | undefined {\n const boxes = sceneBoxFrames(scene);\n return (id) => {\n const m = boxes(id);\n if (!m) return undefined;\n const back = invert(m);\n const through = (t: typeof m, p: Point): Point => {\n const [x, y] = applyToPoint(t, p.x, p.y);\n return { x, y };\n };\n return { toWorld: (p) => through(m, p), toLocal: (p) => (back ? through(back, p) : null) };\n };\n}\n\n/** `ids` and every node under them: what a gesture moving `ids` carries. */\nexport function withSubtrees(scene: Scene<unknown, string, unknown>, ids: readonly string[]): string[] {\n const out = new Set<string>();\n const walk = (id: string): void => {\n if (out.has(id)) return;\n out.add(id);\n if (scene.get(id as NodeId) !== undefined) for (const c of scene.childrenOf(id as NodeId)) walk(c);\n };\n for (const id of ids) walk(id);\n return [...out];\n}\n"],"mappings":";;;;;;;;AAaA,SAAgB,gBAAgB,MAMjB;CACb,MAAM,EAAE,UAAU;CAClB,MAAM,QAAQ,eAAe,KAAK;CAClC,OAAO;EACL,OAAO,OAAQ,MAAM,IAAI,EAAY,MAAM,SAAY,SAAY,MAAM,MAAM,EAAY;EAC3F,WAAW,IAAI,SAAS,KAAK,MAAM,KAAK,IAAI,IAAI;EAChD,SAAS,UAAU,KAAK,oBAAoB,uBAAA,CAAwB,UAAU,IAAI;EAClF,GAAI,KAAK,aAAa,EAAE,YAAY,KAAK,WAAW,IAAI,CAAC;CAC3D;AACF;;;AAIA,SAAgB,eACd,OACA,YACoC;CACpC,MAAM,QAAQ,eAAe,KAAK;CAClC,MAAM,eAAe,gBAAgB,OAAO,iBAAiB,UAAU,CAAC;CACxE,QAAQ,OAAO;EACb,MAAM,OAAO,MAAM,IAAI,EAAY;EACnC,IAAI,CAAC,MAAM,OAAO;EAClB,MAAM,IAAI,aAAa,EAAE;EACzB,IAAI,CAAC,EAAE,gBAAgB,CAAC,EAAE,eAAe,EAAE,mBAAmB,KAAK,IAAI,MAAM,OAAO,OAAO;EAC3F,OAAO,EAAE,YAAY,MAAM,MAAM,EAAY,CAAC;CAChD;AACF;;AAGA,SAAgB,gBAAgB,OAA+E;CAC7G,MAAM,QAAQ,eAAe,KAAK;CAClC,QAAQ,OAAO;EACb,MAAM,IAAI,MAAM,EAAE;EAClB,IAAI,CAAC,GAAG,OAAO;EACf,MAAM,OAAO,OAAO,CAAC;EACrB,MAAM,WAAW,GAAa,MAAoB;GAChD,MAAM,CAAC,GAAG,KAAK,aAAa,GAAG,EAAE,GAAG,EAAE,CAAC;GACvC,OAAO;IAAE;IAAG;GAAE;EAChB;EACA,OAAO;GAAE,UAAU,MAAM,QAAQ,GAAG,CAAC;GAAG,UAAU,MAAO,OAAO,QAAQ,MAAM,CAAC,IAAI;EAAM;CAC3F;AACF;;AAGA,SAAgB,aAAa,OAAwC,KAAkC;CACrG,MAAM,sBAAM,IAAI,IAAY;CAC5B,MAAM,QAAQ,OAAqB;EACjC,IAAI,IAAI,IAAI,EAAE,GAAG;EACjB,IAAI,IAAI,EAAE;EACV,IAAI,MAAM,IAAI,EAAY,MAAM,QAAW,KAAK,MAAM,KAAK,MAAM,WAAW,EAAY,GAAG,KAAK,CAAC;CACnG;CACA,KAAK,MAAM,MAAM,KAAK,KAAK,EAAE;CAC7B,OAAO,CAAC,GAAG,GAAG;AAChB"}
|
|
@@ -2,9 +2,9 @@ import { drawnBoxes } from "../../interactions/actions/drawnBoxes.js";
|
|
|
2
2
|
import { createSnapOutcomeStore } from "./outcomeStore.js";
|
|
3
3
|
import { DEFAULT_SNAP_PX, createSession2d } from "./session2d.js";
|
|
4
4
|
import { buildProbes, subjectOf } from "./probes2d.js";
|
|
5
|
-
import { sceneProbeReads, sceneRotations, withSubtrees } from "./sceneReads.js";
|
|
5
|
+
import { sceneProbeReads, sceneRotations, sceneSnapFrames, withSubtrees } from "./sceneReads.js";
|
|
6
6
|
|
|
7
|
-
//#region src/
|
|
7
|
+
//#region src/domains/snap/sceneSession2d.ts
|
|
8
8
|
/** A 2D session whose probes are the subject's, read from the scene at press. */
|
|
9
9
|
function sceneSession2d(i) {
|
|
10
10
|
const reads = sceneProbeReads({
|
|
@@ -29,6 +29,7 @@ function sceneSession2d(i) {
|
|
|
29
29
|
reachPx: i.reachPx,
|
|
30
30
|
scene: i.scene,
|
|
31
31
|
rotationOf: sceneRotations(i.scene, i.poseDescriptor),
|
|
32
|
+
frameOf: sceneSnapFrames(i.scene),
|
|
32
33
|
store: i.store,
|
|
33
34
|
...i.debug ? { debug: i.debug } : {}
|
|
34
35
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sceneSession2d.js","names":[],"sources":["../../../src/domains/snap/sceneSession2d.ts"],"sourcesContent":["import type { ResizeAnchor, WorldPoint } from '@weasel-js/routing';\nimport type { View } from '@weasel-js/geom';\nimport type { DebugSink } from '@weasel-js/routing';\nimport type { PoseDescriptor } from 'core/geometry/poseDescriptor';\nimport type { Scene } from 'core/scene/types';\nimport type { PlaneMap } from 'core/viewport/parallax';\nimport type { OriginProjection } from 'interactions/gestures/shared/originProjection';\nimport { drawnBoxes, type DrawnBoxes } from 'interactions/actions/drawnBoxes';\nimport type { SnapBegin, SnapConstrain, SnapGeometry, SnapResizeBox, SnapSession } from 'interactions/actions/snapDep';\nimport { createSnapOutcomeStore, type SnapOutcomeStore } from './outcomeStore';\nimport { buildProbes, subjectOf } from './probes2d';\nimport { sceneProbeReads, sceneRotations, sceneSnapFrames, withSubtrees } from './sceneReads';\nimport { createSession2d, DEFAULT_SNAP_PX } from './session2d';\nimport type { SnapGesture, SnapSource } from './types';\n\ntype AnyScene = Scene<unknown, string, unknown>;\n\n/** What a session over a scene runs on: its subject's probes and boxes come\n * from `scene`, measured through `boxes`. */\nexport interface SceneSessionInputs {\n req: SnapBegin;\n scene: AnyScene;\n boxes: DrawnBoxes;\n sources: readonly SnapSource[];\n view(): View | null;\n reachPx: number;\n store: SnapOutcomeStore;\n geometryAt?: (press: WorldPoint, ids: readonly string[]) => WorldPoint | null;\n /** How a pose's origin is read. Default `AUTO_ORIGIN_PROJECTION`. */\n originProjection?: OriginProjection<unknown>;\n /** How a node's rotation is read. Default `AUTO_POSE_DESCRIPTOR`. */\n poseDescriptor?: PoseDescriptor<unknown>;\n /** Where each frame's candidates are recorded. */\n debug?: DebugSink;\n}\n\n/** A 2D session whose probes are the subject's, read from the scene at press. */\nexport function sceneSession2d(i: SceneSessionInputs): SnapSession {\n const reads = sceneProbeReads({\n scene: i.scene, boxes: i.boxes,\n ...(i.geometryAt ? { geometryAt: i.geometryAt } : {}),\n ...(i.originProjection ? { originProjection: i.originProjection } : {}),\n });\n const subject = subjectOf(i.req, reads);\n return createSession2d({\n req: i.req,\n sources: i.sources,\n probes: buildProbes(i.req, reads, subject),\n box: subject.box,\n resize: subject.resize,\n drawnBox: (id) => {\n const pose = reads.pose(id);\n return pose === undefined ? undefined : reads.drawnBox(id, pose);\n },\n ...(i.req.ids ? { exclude: withSubtrees(i.scene, i.req.ids) } : {}),\n view: i.view,\n reachPx: i.reachPx,\n scene: i.scene,\n rotationOf: sceneRotations(i.scene, i.poseDescriptor),\n frameOf: sceneSnapFrames(i.scene),\n store: i.store,\n ...(i.debug ? { debug: i.debug } : {}),\n });\n}\n\n/** Options for {@link createSnapSession2d}. */\nexport interface SnapSession2dOptions {\n scene: AnyScene;\n /** The camera the reach is measured through. */\n view: View;\n sources: readonly SnapSource[];\n gesture: SnapGesture;\n /** World coords. */\n press: WorldPoint;\n /** The subject, whose geometry offers no targets. */\n ids?: readonly string[];\n /** The container a subject not yet in the scene lands in. */\n parent?: string;\n /** Point gestures: the previous anchor, a line's start. */\n origin?: WorldPoint;\n constrain?: SnapConstrain;\n /** Resize: the sides the drag pins. */\n handle?: ResizeAnchor;\n /** Rotate: the point the angle turns about. */\n pivot?: WorldPoint;\n /** Rotate: the subject's angle at press. */\n theta0?: number;\n /** Angle gestures: the reach as an angle, radians. */\n reachRad?: number;\n /** Resize: the box `handle` belongs to. Default: the subjects' drawn box. */\n box?: SnapResizeBox;\n also?: SnapGeometry;\n /** The reach of a source that sets none, in screen px. Default `DEFAULT_SNAP_PX`. */\n reachPx?: number;\n /** Where the session writes its marks. Default: a store of its own. */\n store?: SnapOutcomeStore;\n /** How poses are read. Default `AUTO_POSE_DESCRIPTOR`. */\n poseDescriptor?: PoseDescriptor<unknown>;\n /** Whether drawn boxes include the stroke. Default `true`. */\n boundsIncludeStroke?: boolean;\n /** How a pose's origin, the point a grid or a guide snaps, is read.\n * Default `AUTO_ORIGIN_PROJECTION`: a rect's `{x, y}`, a path's bounds. */\n originProjection?: OriginProjection<unknown>;\n /** How `view`'s world maps into the parallax plane the gesture's points\n * are in. Default: they are in `view`'s own world. */\n plane?: PlaneMap | null;\n}\n\n/**\n * One gesture's snapping over a scene, for a host without `<SceneCanvas>`:\n * the session a canvas's `snap` dep begins, built from the same probes and\n * drawn boxes. Call `at` with each world point the gesture reaches, and\n * `end` when it lets go.\n */\nexport function createSnapSession2d(opts: SnapSession2dOptions): SnapSession {\n const view = opts.view;\n const req: SnapBegin = {\n gesture: opts.gesture,\n press: opts.press,\n ...(opts.ids ? { ids: opts.ids } : {}),\n ...(opts.parent !== undefined ? { parent: opts.parent } : {}),\n ...(opts.origin ? { origin: opts.origin } : {}),\n ...(opts.constrain ? { constrain: opts.constrain } : {}),\n ...(opts.handle ? { handle: opts.handle } : {}),\n ...(opts.pivot ? { pivot: opts.pivot } : {}),\n ...(opts.theta0 !== undefined ? { theta0: opts.theta0 } : {}),\n ...(opts.reachRad !== undefined ? { reachRad: opts.reachRad } : {}),\n ...(opts.box ? { box: opts.box } : {}),\n ...(opts.also ? { also: opts.also } : {}),\n ...(opts.plane ? { plane: () => opts.plane ?? null } : {}),\n };\n return sceneSession2d({\n req,\n scene: opts.scene,\n boxes: drawnBoxes({\n scene: opts.scene,\n view: { get: () => view, set: () => {} },\n ...(opts.poseDescriptor ? { poseDescriptor: opts.poseDescriptor } : {}),\n ...(opts.boundsIncludeStroke !== undefined ? { boundsIncludeStroke: opts.boundsIncludeStroke } : {}),\n }),\n sources: opts.sources,\n view: () => view,\n reachPx: opts.reachPx ?? DEFAULT_SNAP_PX,\n store: opts.store ?? createSnapOutcomeStore(),\n ...(opts.originProjection ? { originProjection: opts.originProjection } : {}),\n ...(opts.poseDescriptor ? { poseDescriptor: opts.poseDescriptor } : {}),\n });\n}\n"],"mappings":";;;;;;;;AAqCA,SAAgB,eAAe,GAAoC;CACjE,MAAM,QAAQ,gBAAgB;EAC5B,OAAO,EAAE;EAAO,OAAO,EAAE;EACzB,GAAI,EAAE,aAAa,EAAE,YAAY,EAAE,WAAW,IAAI,CAAC;EACnD,GAAI,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,iBAAiB,IAAI,CAAC;CACvE,CAAC;CACD,MAAM,UAAU,UAAU,EAAE,KAAK,KAAK;CACtC,OAAO,gBAAgB;EACrB,KAAK,EAAE;EACP,SAAS,EAAE;EACX,QAAQ,YAAY,EAAE,KAAK,OAAO,OAAO;EACzC,KAAK,QAAQ;EACb,QAAQ,QAAQ;EAChB,WAAW,OAAO;GAChB,MAAM,OAAO,MAAM,KAAK,EAAE;GAC1B,OAAO,SAAS,SAAY,SAAY,MAAM,SAAS,IAAI,IAAI;EACjE;EACA,GAAI,EAAE,IAAI,MAAM,EAAE,SAAS,aAAa,EAAE,OAAO,EAAE,IAAI,GAAG,EAAE,IAAI,CAAC;EACjE,MAAM,EAAE;EACR,SAAS,EAAE;EACX,OAAO,EAAE;EACT,YAAY,eAAe,EAAE,OAAO,EAAE,cAAc;EACpD,SAAS,gBAAgB,EAAE,KAAK;EAChC,OAAO,EAAE;EACT,GAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;CACtC,CAAC;AACH;;;;;;;AAmDA,SAAgB,oBAAoB,MAAyC;CAC3E,MAAM,OAAO,KAAK;CAgBlB,OAAO,eAAe;EACpB;GAfA,SAAS,KAAK;GACd,OAAO,KAAK;GACZ,GAAI,KAAK,MAAM,EAAE,KAAK,KAAK,IAAI,IAAI,CAAC;GACpC,GAAI,KAAK,WAAW,SAAY,EAAE,QAAQ,KAAK,OAAO,IAAI,CAAC;GAC3D,GAAI,KAAK,SAAS,EAAE,QAAQ,KAAK,OAAO,IAAI,CAAC;GAC7C,GAAI,KAAK,YAAY,EAAE,WAAW,KAAK,UAAU,IAAI,CAAC;GACtD,GAAI,KAAK,SAAS,EAAE,QAAQ,KAAK,OAAO,IAAI,CAAC;GAC7C,GAAI,KAAK,QAAQ,EAAE,OAAO,KAAK,MAAM,IAAI,CAAC;GAC1C,GAAI,KAAK,WAAW,SAAY,EAAE,QAAQ,KAAK,OAAO,IAAI,CAAC;GAC3D,GAAI,KAAK,aAAa,SAAY,EAAE,UAAU,KAAK,SAAS,IAAI,CAAC;GACjE,GAAI,KAAK,MAAM,EAAE,KAAK,KAAK,IAAI,IAAI,CAAC;GACpC,GAAI,KAAK,OAAO,EAAE,MAAM,KAAK,KAAK,IAAI,CAAC;GACvC,GAAI,KAAK,QAAQ,EAAE,aAAa,KAAK,SAAS,KAAK,IAAI,CAAC;EAGxD;EACA,OAAO,KAAK;EACZ,OAAO,WAAW;GAChB,OAAO,KAAK;GACZ,MAAM;IAAE,WAAW;IAAM,WAAW,CAAC;GAAE;GACvC,GAAI,KAAK,iBAAiB,EAAE,gBAAgB,KAAK,eAAe,IAAI,CAAC;GACrE,GAAI,KAAK,wBAAwB,SAAY,EAAE,qBAAqB,KAAK,oBAAoB,IAAI,CAAC;EACpG,CAAC;EACD,SAAS,KAAK;EACd,YAAY;EACZ,SAAS,KAAK,WAAW;EACzB,OAAO,KAAK,SAAS,uBAAuB;EAC5C,GAAI,KAAK,mBAAmB,EAAE,kBAAkB,KAAK,iBAAiB,IAAI,CAAC;EAC3E,GAAI,KAAK,iBAAiB,EAAE,gBAAgB,KAAK,eAAe,IAAI,CAAC;CACvE,CAAC;AACH"}
|
|
@@ -2,7 +2,7 @@ import { viewToTransform } from "../../core/viewport/view.js";
|
|
|
2
2
|
import { fromPlane } from "../../core/viewport/parallax.js";
|
|
3
3
|
import { worldToScreen } from "../../core/viewport/viewTransform.js";
|
|
4
4
|
|
|
5
|
-
//#region src/
|
|
5
|
+
//#region src/domains/snap/screen.ts
|
|
6
6
|
/** A point in the gesture's plane to screen px. */
|
|
7
7
|
function screenOf(view, plane) {
|
|
8
8
|
const t = view ? viewToTransform(view) : null;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"screen.js","names":[],"sources":["../../../src/domains/snap/screen.ts"],"sourcesContent":["import type { View } from '@weasel-js/geom';\nimport { viewToTransform } from 'core/viewport/view';\nimport { worldToScreen } from 'core/viewport/viewTransform';\nimport { fromPlane, type PlaneMap } from 'core/viewport/parallax';\n\n/** A point in the gesture's plane to screen px. */\nexport function screenOf(view: View | null, plane: PlaneMap | null): (w: readonly number[]) => readonly number[] {\n const t = view ? viewToTransform(view) : null;\n return ([x, y]) => {\n const w = plane ? fromPlane(plane, { x, y }) : { x, y };\n return t ? worldToScreen(w.x, w.y, t) : [w.x, w.y];\n };\n}\n"],"mappings":";;;;;;AAMA,SAAgB,SAAS,MAAmB,OAAqE;CAC/G,MAAM,IAAI,OAAO,gBAAgB,IAAI,IAAI;CACzC,QAAQ,CAAC,GAAG,OAAO;EACjB,MAAM,IAAI,QAAQ,UAAU,OAAO;GAAE;GAAG;EAAE,CAAC,IAAI;GAAE;GAAG;EAAE;EACtD,OAAO,IAAI,cAAc,EAAE,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;CACnD;AACF"}
|
|
@@ -8,7 +8,7 @@ import { recordSnapCandidates } from "./debugCandidates.js";
|
|
|
8
8
|
import { createSnapOutcomeStore } from "./outcomeStore.js";
|
|
9
9
|
import { closestOnFlat, resolveSnap } from "@weasel-js/geom/nd";
|
|
10
10
|
|
|
11
|
-
//#region src/
|
|
11
|
+
//#region src/domains/snap/session2d.ts
|
|
12
12
|
/** The canvas's reach when neither a source nor the kit settings name one. */
|
|
13
13
|
var DEFAULT_SNAP_PX = 8;
|
|
14
14
|
/** A snap session over a 2D canvas: ctx points are world points. */
|
|
@@ -86,7 +86,8 @@ function collectAtPress(inputs) {
|
|
|
86
86
|
...inputs.drawnBox ? { drawnBox: inputs.drawnBox } : {},
|
|
87
87
|
...req.origin ? { origin: req.origin } : {},
|
|
88
88
|
...req.also ? { also: req.also } : {},
|
|
89
|
-
...inputs.scene ? { scene: inputs.scene } : {}
|
|
89
|
+
...inputs.scene ? { scene: inputs.scene } : {},
|
|
90
|
+
...inputs.frameOf ? { frameOf: inputs.frameOf } : {}
|
|
90
91
|
};
|
|
91
92
|
}
|
|
92
93
|
function collectAll(sources, probesAtPress, fixed, { delta0, view, plane }, reachPx) {
|