@weasel-js/core 1.11.1 → 1.13.0-rc.0
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 +275 -0
- package/dist/WeaselProvider.js +1 -1
- package/dist/affordances/pathAnchors.js +10 -6
- package/dist/affordances/pathAnchors.js.map +1 -1
- package/dist/animation/poseTarget.js +46 -15
- package/dist/animation/poseTarget.js.map +1 -1
- package/dist/animation/poseTransition.js +3 -3
- package/dist/animation/poseTransition.js.map +1 -1
- package/dist/animation/reflow.js +3 -6
- package/dist/animation/reflow.js.map +1 -1
- package/dist/animation/rig/bindRig.js +2 -2
- package/dist/animation/rig/bindRig.js.map +1 -1
- package/dist/animation/rig/skinBinding.js +2 -2
- package/dist/animation/rig/skinBinding.js.map +1 -1
- package/dist/barrel/canvas.js +5 -1
- package/dist/barrel/chrome.js +3 -1
- package/dist/barrel/paint.js +4 -4
- package/dist/barrel/paths.js +9 -4
- package/dist/barrel/renderer.js +3 -2
- package/dist/barrel/routing.js +4 -4
- package/dist/barrel/scene.js +7 -1
- package/dist/barrel/text.js +2 -2
- package/dist/barrel/viewport.js +6 -2
- package/dist/canvas/Canvas.js +2 -1
- package/dist/canvas/Canvas.js.map +1 -1
- package/dist/canvas/CanvasView.js +23 -34
- package/dist/canvas/CanvasView.js.map +1 -1
- package/dist/canvas/ModalityHud.js +1 -1
- package/dist/canvas/NodeShape.js +5 -1
- package/dist/canvas/NodeShape.js.map +1 -1
- package/dist/canvas/SceneCanvas/ActionsProviderIfRoot.js +1 -1
- package/dist/canvas/SceneCanvas/DepRegistryProviderIfRoot.js +1 -1
- package/dist/canvas/SceneCanvas/PointerProviderIfRoot.js +1 -1
- package/dist/canvas/SceneCanvas/SceneCanvasInput.js +2 -0
- package/dist/canvas/SceneCanvas/SceneCanvasInput.js.map +1 -1
- package/dist/canvas/SceneCanvas/SurfaceDeclarations.js +23 -0
- package/dist/canvas/SceneCanvas/SurfaceDeclarations.js.map +1 -0
- package/dist/canvas/SceneCanvas/canvasPassThrough.js +2 -1
- package/dist/canvas/SceneCanvas/canvasPassThrough.js.map +1 -1
- package/dist/canvas/SceneCanvas/defaultNodeRouting.js +2 -2
- package/dist/canvas/SceneCanvas/defaultNodeRouting.js.map +1 -1
- package/dist/canvas/SceneCanvas/props.js.map +1 -1
- package/dist/canvas/SceneCanvas/scenePointQuery.js +27 -5
- package/dist/canvas/SceneCanvas/scenePointQuery.js.map +1 -1
- package/dist/canvas/SceneCanvas/useActionTunings.js +6 -1
- package/dist/canvas/SceneCanvas/useActionTunings.js.map +1 -1
- package/dist/canvas/SceneCanvas/useCanvasDevtoolsRoot.js +1 -0
- package/dist/canvas/SceneCanvas/useCanvasDevtoolsRoot.js.map +1 -1
- package/dist/canvas/SceneCanvas/useCanvasTools.js +10 -2
- package/dist/canvas/SceneCanvas/useCanvasTools.js.map +1 -1
- package/dist/canvas/SceneCanvas/usePreviewGhostLayer.js +25 -19
- package/dist/canvas/SceneCanvas/usePreviewGhostLayer.js.map +1 -1
- package/dist/canvas/SceneCanvas/useSceneCanvasHandle.js +9 -3
- package/dist/canvas/SceneCanvas/useSceneCanvasHandle.js.map +1 -1
- package/dist/canvas/SceneCanvas/useSceneCanvasLayers.js +17 -2
- package/dist/canvas/SceneCanvas/useSceneCanvasLayers.js.map +1 -1
- package/dist/canvas/SceneCanvas/useSceneCanvasTools.js +2 -0
- package/dist/canvas/SceneCanvas/useSceneCanvasTools.js.map +1 -1
- package/dist/canvas/SceneCanvas/useSceneGestureDispatcher.js +19 -4
- package/dist/canvas/SceneCanvas/useSceneGestureDispatcher.js.map +1 -1
- package/dist/canvas/SceneCanvas/useScenePicking.js +31 -6
- package/dist/canvas/SceneCanvas/useScenePicking.js.map +1 -1
- package/dist/canvas/SceneCanvas/useSceneSelectTool.js +4 -5
- package/dist/canvas/SceneCanvas/useSceneSelectTool.js.map +1 -1
- package/dist/canvas/SceneCanvas/useSceneStandardActions.js +7 -4
- package/dist/canvas/SceneCanvas/useSceneStandardActions.js.map +1 -1
- package/dist/canvas/SceneCanvas.js +30 -12
- package/dist/canvas/SceneCanvas.js.map +1 -1
- package/dist/canvas/ViewMarker.js +35 -0
- package/dist/canvas/ViewMarker.js.map +1 -0
- package/dist/canvas/accentColor.js +26 -3
- package/dist/canvas/accentColor.js.map +1 -1
- package/dist/canvas/buildSceneTree.js +14 -20
- package/dist/canvas/buildSceneTree.js.map +1 -1
- package/dist/canvas/copiesAbove.js +1 -1
- package/dist/canvas/copiesAbove.js.map +1 -1
- package/dist/canvas/defaultDrawOne.js +11 -6
- package/dist/canvas/defaultDrawOne.js.map +1 -1
- package/dist/canvas/deps/areaSelect.js +5 -2
- package/dist/canvas/deps/areaSelect.js.map +1 -1
- package/dist/canvas/deps/booleans.js +3 -2
- package/dist/canvas/deps/booleans.js.map +1 -1
- package/dist/canvas/deps/enteredGroup.js +81 -0
- package/dist/canvas/deps/enteredGroup.js.map +1 -0
- package/dist/canvas/deps/hitTestArea.js +28 -16
- package/dist/canvas/deps/hitTestArea.js.map +1 -1
- package/dist/canvas/deps/insert.js +10 -38
- package/dist/canvas/deps/insert.js.map +1 -1
- package/dist/canvas/deps/insertSite.js +39 -0
- package/dist/canvas/deps/insertSite.js.map +1 -0
- package/dist/canvas/deps/lassoSelect.js +6 -3
- package/dist/canvas/deps/lassoSelect.js.map +1 -1
- package/dist/canvas/deps/pathEditCommits.js +3 -7
- package/dist/canvas/deps/pathEditCommits.js.map +1 -1
- package/dist/canvas/deps/pathLeaf.js +1 -1
- package/dist/canvas/deps/pathLeaf.js.map +1 -1
- package/dist/canvas/deps/slice.js +2 -1
- package/dist/canvas/deps/slice.js.map +1 -1
- package/dist/canvas/derivedPath.js +14 -6
- package/dist/canvas/derivedPath.js.map +1 -1
- package/dist/canvas/doubleClickTarget.js +9 -11
- package/dist/canvas/doubleClickTarget.js.map +1 -1
- package/dist/canvas/drawnBounds.js +26 -9
- package/dist/canvas/drawnBounds.js.map +1 -1
- package/dist/canvas/inheritedPaints.js +55 -0
- package/dist/canvas/inheritedPaints.js.map +1 -0
- package/dist/canvas/nodeShapes/derivedPainter.js +15 -16
- package/dist/canvas/nodeShapes/derivedPainter.js.map +1 -1
- package/dist/canvas/nodeShapes/nodePaint.js +7 -34
- package/dist/canvas/nodeShapes/nodePaint.js.map +1 -1
- package/dist/canvas/nodeShapes/pathPainter.js +7 -7
- package/dist/canvas/nodeShapes/pathPainter.js.map +1 -1
- package/dist/canvas/nodeShapes/rectFallbackPainter.js +4 -5
- package/dist/canvas/nodeShapes/rectFallbackPainter.js.map +1 -1
- package/dist/canvas/nodeShapes/shapePainter.js +9 -9
- package/dist/canvas/nodeShapes/shapePainter.js.map +1 -1
- package/dist/canvas/nodeShapes/textPainter.js +13 -12
- package/dist/canvas/nodeShapes/textPainter.js.map +1 -1
- package/dist/canvas/ownClip.js +24 -0
- package/dist/canvas/ownClip.js.map +1 -0
- package/dist/canvas/paintCull.js.map +1 -1
- package/dist/canvas/pickIndex/nodeBroadBox.js +86 -0
- package/dist/canvas/pickIndex/nodeBroadBox.js.map +1 -0
- package/dist/canvas/pickIndex/scenePickIndex.js +208 -0
- package/dist/canvas/pickIndex/scenePickIndex.js.map +1 -0
- package/dist/canvas/pickReach.js +3 -3
- package/dist/canvas/pickReach.js.map +1 -1
- package/dist/canvas/pickWalk.js +17 -91
- package/dist/canvas/pickWalk.js.map +1 -1
- package/dist/canvas/poseCascade.js +1 -1
- package/dist/canvas/poseCascade.js.map +1 -1
- package/dist/canvas/publishPreviews.js +97 -0
- package/dist/canvas/publishPreviews.js.map +1 -0
- package/dist/canvas/renderSceneToPixels.js +1 -1
- package/dist/canvas/renderSceneToPixels.js.map +1 -1
- package/dist/canvas/sceneAdapter.js +7 -5
- package/dist/canvas/sceneAdapter.js.map +1 -1
- package/dist/canvas/sceneClipboard.js +17 -10
- package/dist/canvas/sceneClipboard.js.map +1 -1
- package/dist/canvas/scenePickReads.js +37 -0
- package/dist/canvas/scenePickReads.js.map +1 -0
- package/dist/canvas/scenePickSource.js +74 -0
- package/dist/canvas/scenePickSource.js.map +1 -0
- package/dist/canvas/sceneSlotWiring.js +9 -3
- package/dist/canvas/sceneSlotWiring.js.map +1 -1
- package/dist/canvas/sceneViewRender.js +9 -4
- package/dist/canvas/sceneViewRender.js.map +1 -1
- package/dist/canvas/shownNodes.js +15 -0
- package/dist/canvas/shownNodes.js.map +1 -0
- package/dist/canvas/surfaceContribution.js +12 -8
- package/dist/canvas/surfaceContribution.js.map +1 -1
- package/dist/canvas/useCanvasView.js +4 -2
- package/dist/canvas/useCanvasView.js.map +1 -1
- package/dist/canvas/useLayerStack.js +6 -2
- package/dist/canvas/useLayerStack.js.map +1 -1
- package/dist/canvas/useSceneAdapter.js +5 -3
- package/dist/canvas/useSceneAdapter.js.map +1 -1
- package/dist/canvas/useViewAim.js +121 -0
- package/dist/canvas/useViewAim.js.map +1 -0
- package/dist/canvas/useViewNesting.js +3 -2
- package/dist/canvas/useViewNesting.js.map +1 -1
- package/dist/canvas/useViewRegistrySurface.js +4 -2
- package/dist/canvas/useViewRegistrySurface.js.map +1 -1
- package/dist/canvas/viewMarkers.js +63 -0
- package/dist/canvas/viewMarkers.js.map +1 -0
- package/dist/canvas/viewRegistry.js +27 -1
- package/dist/canvas/viewRegistry.js.map +1 -1
- package/dist/clipboard.d.ts +2 -2
- package/dist/{clone-C3e0OTuF.d.ts → clone-qb2e1F5p.d.ts} +2 -2
- package/dist/clone.d.ts +3 -3
- package/dist/core/isPlainObject.js +2 -2
- package/dist/core/layers/layerGroup.js.map +1 -1
- package/dist/core/pages/pageEdits.js +2 -3
- package/dist/core/pages/pageEdits.js.map +1 -1
- package/dist/core/paint/meshKindLazy.js +59 -2
- package/dist/core/paint/meshKindLazy.js.map +1 -1
- package/dist/core/scene/NodeRouting.js.map +1 -1
- package/dist/core/scene/arrivalWindow.js +1 -1
- package/dist/core/scene/arrivalWindow.js.map +1 -1
- package/dist/core/scene/clipNothing.js +10 -0
- package/dist/core/scene/clipNothing.js.map +1 -0
- package/dist/core/scene/declaredFieldSetters.js +44 -0
- package/dist/core/scene/declaredFieldSetters.js.map +1 -0
- package/dist/core/scene/depMemo.js +14 -3
- package/dist/core/scene/depMemo.js.map +1 -1
- package/dist/core/scene/dependents.js +9 -1
- package/dist/core/scene/dependents.js.map +1 -1
- package/dist/core/scene/derivedParts.js +10 -11
- package/dist/core/scene/derivedParts.js.map +1 -1
- package/dist/core/scene/documentOf.js +43 -0
- package/dist/core/scene/documentOf.js.map +1 -0
- package/dist/core/scene/effectivePose.js +44 -15
- package/dist/core/scene/effectivePose.js.map +1 -1
- package/dist/core/scene/fieldEdits.js +17 -14
- package/dist/core/scene/fieldEdits.js.map +1 -1
- package/dist/core/scene/fontReads.js +37 -0
- package/dist/core/scene/fontReads.js.map +1 -0
- package/dist/core/scene/historyForm.js +4 -4
- package/dist/core/scene/historyForm.js.map +1 -1
- package/dist/core/scene/inheritedPaint.js +97 -0
- package/dist/core/scene/inheritedPaint.js.map +1 -0
- package/dist/core/scene/kitOps.js +3 -23
- 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/layoutPass.js +1 -2
- package/dist/core/scene/layoutPass.js.map +1 -1
- package/dist/core/scene/nodeAsShown.js +72 -0
- package/dist/core/scene/nodeAsShown.js.map +1 -0
- package/dist/core/scene/nodeFnFields.js +2 -10
- package/dist/core/scene/nodeFnFields.js.map +1 -1
- package/dist/core/scene/nodeMemo.js +21 -8
- package/dist/core/scene/nodeMemo.js.map +1 -1
- package/dist/core/scene/nodeStore.js +2 -4
- package/dist/core/scene/nodeStore.js.map +1 -1
- package/dist/core/scene/pathEffects/blend.js.map +1 -1
- package/dist/core/scene/pathEffects/derive.js +10 -4
- package/dist/core/scene/pathEffects/derive.js.map +1 -1
- package/dist/core/scene/pathEffects/effects.js +3 -1
- package/dist/core/scene/pathEffects/effects.js.map +1 -1
- package/dist/core/scene/pathEffects/foundHidden.js +35 -0
- package/dist/core/scene/pathEffects/foundHidden.js.map +1 -0
- package/dist/core/scene/pathEffects/textAlong.js +95 -0
- package/dist/core/scene/pathEffects/textAlong.js.map +1 -0
- package/dist/core/scene/plyStacks.js +89 -0
- package/dist/core/scene/plyStacks.js.map +1 -0
- package/dist/core/scene/poseHold.js +42 -24
- package/dist/core/scene/poseHold.js.map +1 -1
- package/dist/core/scene/poseOverrides.js +35 -38
- package/dist/core/scene/poseOverrides.js.map +1 -1
- package/dist/core/scene/posePlies.js +59 -0
- package/dist/core/scene/posePlies.js.map +1 -0
- package/dist/core/scene/reconcileSpecs.js +6 -15
- package/dist/core/scene/reconcileSpecs.js.map +1 -1
- package/dist/core/scene/renderOrder.js +10 -4
- package/dist/core/scene/renderOrder.js.map +1 -1
- package/dist/core/scene/sameValue.js +17 -0
- package/dist/core/scene/sameValue.js.map +1 -0
- package/dist/core/scene/scene.js +3 -3
- package/dist/core/scene/scene.js.map +1 -1
- package/dist/core/scene/sceneEdits.js +8 -0
- package/dist/core/scene/sceneEdits.js.map +1 -1
- package/dist/core/scene/sceneState.js +1 -2
- package/dist/core/scene/sceneState.js.map +1 -1
- package/dist/core/scene/serialization.js +45 -9
- package/dist/core/scene/serialization.js.map +1 -1
- package/dist/core/scene/staleReplay.js +5 -2
- package/dist/core/scene/staleReplay.js.map +1 -1
- package/dist/core/scene/statedFields.js +4 -2
- package/dist/core/scene/statedFields.js.map +1 -1
- package/dist/core/scene/treeEdits.js +2 -4
- package/dist/core/scene/treeEdits.js.map +1 -1
- package/dist/core/scene/treeOrder.js +3 -1
- package/dist/core/scene/treeOrder.js.map +1 -1
- package/dist/core/scene/treeReads.js +1 -2
- package/dist/core/scene/treeReads.js.map +1 -1
- package/dist/core/scene/treeShape.js +13 -0
- package/dist/core/scene/treeShape.js.map +1 -0
- package/dist/core/scene/types.js.map +1 -1
- package/dist/core/scene/useScene.js +1 -1
- package/dist/core/scene/useScene.js.map +1 -1
- package/dist/{cornerHandles-BHuoMs1o.d.ts → cornerHandles-CNCb7aTY.d.ts} +3 -2
- package/dist/{depSchema-BpZNOv7q.d.ts → depSchema-B1RS-IJx.d.ts} +39 -18
- package/dist/devtools/handlers.js +1 -1
- package/dist/devtools/handlers.js.map +1 -1
- package/dist/devtools/protocol.js.map +1 -1
- package/dist/devtools/registry.js +4 -4
- package/dist/devtools/registry.js.map +1 -1
- package/dist/devtools-protocol.d.ts +4 -3
- package/dist/devtools.d.ts +3 -2
- package/dist/features/measure/measureContribution.js +4 -2
- package/dist/features/measure/measureContribution.js.map +1 -1
- package/dist/features/measure/measureHit.js +5 -3
- package/dist/features/measure/measureHit.js.map +1 -1
- package/dist/features/measure/measurement.js +1 -1
- package/dist/features/measure/measurement.js.map +1 -1
- package/dist/features/modes/modeLayers.js +14 -7
- package/dist/features/modes/modeLayers.js.map +1 -1
- package/dist/features/modes/modeTriggers.js +10 -6
- package/dist/features/modes/modeTriggers.js.map +1 -1
- package/dist/features/pathEffects/effectSources.js +69 -0
- package/dist/features/pathEffects/effectSources.js.map +1 -0
- package/dist/features/pathEffects/readSource.js +18 -2
- package/dist/features/pathEffects/readSource.js.map +1 -1
- package/dist/features/pathEffects/textItems.js +53 -0
- package/dist/features/pathEffects/textItems.js.map +1 -0
- package/dist/features/pathEffects/useEffectSourcesLayer.js +53 -0
- package/dist/features/pathEffects/useEffectSourcesLayer.js.map +1 -0
- package/dist/features/paths/editablePath.js +1 -1
- package/dist/features/paths/editablePath.js.map +1 -1
- package/dist/features/paths/pathEditState.js +5 -2
- package/dist/features/paths/pathEditState.js.map +1 -1
- package/dist/features/paths/pathSnap/sceneIndex.js +1 -1
- package/dist/features/paths/pathSnap/sceneIndex.js.map +1 -1
- package/dist/features/selection/enteredGroupFrame.js +65 -0
- package/dist/features/selection/enteredGroupFrame.js.map +1 -0
- package/dist/features/selection/enteredGroupScope.js +44 -0
- package/dist/features/selection/enteredGroupScope.js.map +1 -0
- package/dist/features/text/sceneTextDrafts.js +64 -0
- package/dist/features/text/sceneTextDrafts.js.map +1 -0
- package/dist/features/text/textHitAt.js +34 -3
- package/dist/features/text/textHitAt.js.map +1 -1
- package/dist/features/text/useSceneTextEdit.js +23 -19
- package/dist/features/text/useSceneTextEdit.js.map +1 -1
- package/dist/features/viewports/aim.js +105 -0
- package/dist/features/viewports/aim.js.map +1 -0
- package/dist/features/viewports/viewMarker.js +82 -0
- package/dist/features/viewports/viewMarker.js.map +1 -0
- package/dist/features/viewports/viewMarkerDrag.js +55 -0
- package/dist/features/viewports/viewMarkerDrag.js.map +1 -0
- package/dist/index.d.ts +709 -258
- package/dist/index.js +33 -12
- package/dist/interactions/actions/admitsChild.js +11 -0
- package/dist/interactions/actions/admitsChild.js.map +1 -0
- package/dist/interactions/actions/booleans/booleans.js +2 -1
- package/dist/interactions/actions/booleans/booleans.js.map +1 -1
- package/dist/interactions/actions/booleans/operands.js +6 -5
- package/dist/interactions/actions/booleans/operands.js.map +1 -1
- package/dist/interactions/actions/clipboard/action.js +27 -17
- package/dist/interactions/actions/clipboard/action.js.map +1 -1
- package/dist/interactions/actions/defaults/anchorEditing.js +44 -23
- package/dist/interactions/actions/defaults/anchorEditing.js.map +1 -1
- package/dist/interactions/actions/defaults/anchorJoin.js +12 -6
- package/dist/interactions/actions/defaults/anchorJoin.js.map +1 -1
- package/dist/interactions/actions/defaults/bendSegment.js +7 -4
- package/dist/interactions/actions/defaults/bendSegment.js.map +1 -1
- package/dist/interactions/actions/defaults/cancelGesture.js +11 -8
- package/dist/interactions/actions/defaults/cancelGesture.js.map +1 -1
- package/dist/interactions/actions/defaults/contextMenu.js +33 -11
- package/dist/interactions/actions/defaults/contextMenu.js.map +1 -1
- package/dist/interactions/actions/defaults/createPaintAction.js +5 -2
- package/dist/interactions/actions/defaults/createPaintAction.js.map +1 -1
- package/dist/interactions/actions/defaults/delete.js +28 -14
- package/dist/interactions/actions/defaults/delete.js.map +1 -1
- package/dist/interactions/actions/defaults/duplicate.js +11 -8
- package/dist/interactions/actions/defaults/duplicate.js.map +1 -1
- package/dist/interactions/actions/defaults/enterGroup.js +88 -0
- package/dist/interactions/actions/defaults/enterGroup.js.map +1 -0
- package/dist/interactions/actions/defaults/enterPathEdit.js +20 -10
- package/dist/interactions/actions/defaults/enterPathEdit.js.map +1 -1
- package/dist/interactions/actions/defaults/enterTextEdit.js +1 -1
- package/dist/interactions/actions/defaults/enterTextEdit.js.map +1 -1
- package/dist/interactions/actions/defaults/escape.js +11 -8
- package/dist/interactions/actions/defaults/escape.js.map +1 -1
- package/dist/interactions/actions/defaults/exitPathEdit.js +7 -4
- package/dist/interactions/actions/defaults/exitPathEdit.js.map +1 -1
- package/dist/interactions/actions/defaults/group.js +26 -20
- package/dist/interactions/actions/defaults/group.js.map +1 -1
- package/dist/interactions/actions/defaults/ingest.js +10 -4
- package/dist/interactions/actions/defaults/ingest.js.map +1 -1
- package/dist/interactions/actions/defaults/insertPathAnchor.js +7 -4
- package/dist/interactions/actions/defaults/insertPathAnchor.js.map +1 -1
- package/dist/interactions/actions/defaults/nudge.js +8 -2
- package/dist/interactions/actions/defaults/nudge.js.map +1 -1
- package/dist/interactions/actions/defaults/pathEditTools.js +11 -8
- package/dist/interactions/actions/defaults/pathEditTools.js.map +1 -1
- package/dist/interactions/actions/defaults/pinchZoom.js +7 -4
- package/dist/interactions/actions/defaults/pinchZoom.js.map +1 -1
- package/dist/interactions/actions/defaults/reorder.js +24 -6
- package/dist/interactions/actions/defaults/reorder.js.map +1 -1
- package/dist/interactions/actions/defaults/selectAll.js +15 -8
- package/dist/interactions/actions/defaults/selectAll.js.map +1 -1
- package/dist/interactions/actions/defaults/selectDeep.js +35 -0
- package/dist/interactions/actions/defaults/selectDeep.js.map +1 -0
- package/dist/interactions/actions/defaults/setFill.js +7 -3
- package/dist/interactions/actions/defaults/setFill.js.map +1 -1
- package/dist/interactions/actions/defaults/setFillOpacity.js +1 -1
- package/dist/interactions/actions/defaults/setStroke.js +12 -11
- package/dist/interactions/actions/defaults/setStroke.js.map +1 -1
- package/dist/interactions/actions/defaults/setStrokeOpacity.js +1 -1
- package/dist/interactions/actions/defaults/toolActivate.js +7 -1
- package/dist/interactions/actions/defaults/toolActivate.js.map +1 -1
- package/dist/interactions/actions/defaults/toolResetToDefault.js +7 -4
- package/dist/interactions/actions/defaults/toolResetToDefault.js.map +1 -1
- package/dist/interactions/actions/defaults/undoRedo.js +19 -13
- package/dist/interactions/actions/defaults/undoRedo.js.map +1 -1
- package/dist/interactions/actions/defaults/viewportWheelPan.js +16 -7
- package/dist/interactions/actions/defaults/viewportWheelPan.js.map +1 -1
- package/dist/interactions/actions/defaults/viewportZoom.js +24 -6
- package/dist/interactions/actions/defaults/viewportZoom.js.map +1 -1
- package/dist/interactions/actions/drawnBoxes.js +2 -1
- package/dist/interactions/actions/drawnBoxes.js.map +1 -1
- package/dist/interactions/actions/edit-anchors/action.js +7 -4
- package/dist/interactions/actions/edit-anchors/action.js.map +1 -1
- package/dist/interactions/actions/flip/action.js +8 -2
- package/dist/interactions/actions/flip/action.js.map +1 -1
- package/dist/interactions/actions/insert/action.js +1 -0
- package/dist/interactions/actions/insert/action.js.map +1 -1
- package/dist/interactions/actions/insert/parent.js +7 -5
- package/dist/interactions/actions/insert/parent.js.map +1 -1
- package/dist/interactions/actions/insert/placeAction.js +3 -2
- package/dist/interactions/actions/insert/placeAction.js.map +1 -1
- package/dist/interactions/actions/insert/repositionAction.js +2 -1
- package/dist/interactions/actions/insert/repositionAction.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 +7 -4
- package/dist/interactions/actions/move/action.js.map +1 -1
- package/dist/interactions/actions/move/commit/reparent.js +1 -1
- package/dist/interactions/actions/move/commit/reparent.js.map +1 -1
- package/dist/interactions/actions/move/gestureAdapter.js +6 -7
- package/dist/interactions/actions/move/gestureAdapter.js.map +1 -1
- package/dist/interactions/actions/move/layout/exits.js +1 -1
- package/dist/interactions/actions/move/layout/exits.js.map +1 -1
- package/dist/interactions/actions/move/session.js +4 -4
- package/dist/interactions/actions/move/session.js.map +1 -1
- package/dist/interactions/actions/outlines/createOutlinesAction.js +8 -5
- package/dist/interactions/actions/outlines/createOutlinesAction.js.map +1 -1
- package/dist/interactions/actions/outlines/outlineStroke.js +5 -3
- package/dist/interactions/actions/outlines/outlineStroke.js.map +1 -1
- package/dist/interactions/actions/pathCommands/cutJoin.js +8 -5
- package/dist/interactions/actions/pathCommands/cutJoin.js.map +1 -1
- package/dist/interactions/actions/pathCommands/pathNodes.js +14 -5
- package/dist/interactions/actions/pathCommands/pathNodes.js.map +1 -1
- package/dist/interactions/actions/resize/cornerHandles.js +2 -1
- package/dist/interactions/actions/resize/cornerHandles.js.map +1 -1
- package/dist/interactions/actions/selectionSubtree.js +12 -7
- package/dist/interactions/actions/selectionSubtree.js.map +1 -1
- package/dist/interactions/actions/transform-again/action.js +8 -5
- package/dist/interactions/actions/transform-again/action.js.map +1 -1
- package/dist/interactions/gestures/thresholdDrag/thresholdDrag.js +14 -2
- package/dist/interactions/gestures/thresholdDrag/thresholdDrag.js.map +1 -1
- package/dist/json.d.ts +4 -0
- package/dist/json.js +3 -0
- package/dist/kitSettingsSchema.js +8 -1
- package/dist/kitSettingsSchema.js.map +1 -1
- package/dist/{math-CrJULaZI.d.ts → math-C_elShP_.d.ts} +7 -1
- package/dist/math.d.ts +1 -1
- package/dist/math.js +2 -1
- package/dist/move.d.ts +4 -4
- package/dist/{options-DBxEryYq.d.ts → options-ClEm3SEl.d.ts} +1 -1
- package/dist/resize.d.ts +4 -4
- package/dist/test-seams.d.ts +6 -6
- package/dist/tools/builtin/ellipse/useEllipseTool.js +1 -0
- package/dist/tools/builtin/ellipse/useEllipseTool.js.map +1 -1
- package/dist/tools/builtin/eyedropper/useEyedropperTool.js +2 -1
- package/dist/tools/builtin/eyedropper/useEyedropperTool.js.map +1 -1
- package/dist/tools/builtin/hand/dragPanContribution.js +4 -1
- package/dist/tools/builtin/hand/dragPanContribution.js.map +1 -1
- package/dist/tools/builtin/hand/useHandTool.js +7 -4
- package/dist/tools/builtin/hand/useHandTool.js.map +1 -1
- package/dist/tools/builtin/image/useImageTool.js +1 -0
- package/dist/tools/builtin/image/useImageTool.js.map +1 -1
- package/dist/tools/builtin/lasso/useLassoTool.js +1 -0
- package/dist/tools/builtin/lasso/useLassoTool.js.map +1 -1
- package/dist/tools/builtin/line/useLineTool.js +1 -0
- package/dist/tools/builtin/line/useLineTool.js.map +1 -1
- package/dist/tools/builtin/measure/useMeasureTool.js +12 -5
- package/dist/tools/builtin/measure/useMeasureTool.js.map +1 -1
- package/dist/tools/builtin/pen/usePenTool.js +14 -6
- package/dist/tools/builtin/pen/usePenTool.js.map +1 -1
- package/dist/tools/builtin/pencil/usePencilTool.js +1 -0
- package/dist/tools/builtin/pencil/usePencilTool.js.map +1 -1
- package/dist/tools/builtin/polygon/usePolygonTool.js +13 -4
- package/dist/tools/builtin/polygon/usePolygonTool.js.map +1 -1
- package/dist/tools/builtin/pressTarget.js +22 -0
- package/dist/tools/builtin/pressTarget.js.map +1 -0
- package/dist/tools/builtin/rect/useRectTool.js +1 -0
- package/dist/tools/builtin/rect/useRectTool.js.map +1 -1
- package/dist/tools/builtin/select/adapterPointQuery.js +6 -5
- package/dist/tools/builtin/select/adapterPointQuery.js.map +1 -1
- package/dist/tools/builtin/select/collapseDeferred.js +40 -0
- package/dist/tools/builtin/select/collapseDeferred.js.map +1 -0
- package/dist/tools/builtin/select/groupEntry.js +82 -0
- package/dist/tools/builtin/select/groupEntry.js.map +1 -0
- package/dist/tools/builtin/select/pressDecision.js +32 -0
- package/dist/tools/builtin/select/pressDecision.js.map +1 -0
- package/dist/tools/builtin/select/selectionContributions.js +22 -13
- package/dist/tools/builtin/select/selectionContributions.js.map +1 -1
- package/dist/tools/builtin/select/useSelectTool.js +74 -55
- package/dist/tools/builtin/select/useSelectTool.js.map +1 -1
- package/dist/tools/builtin/slice/useSliceTool.js +22 -8
- package/dist/tools/builtin/slice/useSliceTool.js.map +1 -1
- package/dist/tools/builtin/star/useStarTool.js +13 -4
- package/dist/tools/builtin/star/useStarTool.js.map +1 -1
- package/dist/tools/builtin/sticky/stickyNode.js +4 -1
- package/dist/tools/builtin/sticky/stickyNode.js.map +1 -1
- package/dist/tools/builtin/sticky/useStickyTool.js +10 -5
- package/dist/tools/builtin/sticky/useStickyTool.js.map +1 -1
- package/dist/tools/builtin/text/useTextTool.js +3 -1
- package/dist/tools/builtin/text/useTextTool.js.map +1 -1
- package/dist/{types-7puAuVD2.d.ts → types-49uYJN3j.d.ts} +1 -1
- package/dist/{types-CniVctmk.d.ts → types-BEdRIhNc.d.ts} +272 -109
- package/dist/{types-oFeQ5VjV.d.ts → types-p2alu-R1.d.ts} +1 -1
- package/dist/util/paint.js +1 -3
- package/dist/util/paint.js.map +1 -1
- package/dist/version.js +1 -1
- package/package.json +29 -25
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { planeMap } from "../core/viewport/parallax.js";
|
|
2
|
+
import { resolveDerivedPath } from "../core/scene/derivedPath.js";
|
|
3
|
+
import { nodeAsShown, nodesAsShown } from "../core/scene/nodeAsShown.js";
|
|
4
|
+
import { asNodeId } from "../core/scene/types.js";
|
|
5
|
+
import { annotationLayerIds } from "../core/scene/annotation.js";
|
|
6
|
+
import { nodeGates } from "../core/scene/nodeGates.js";
|
|
7
|
+
import { scenePaintedPoseOf } from "./derivedPath.js";
|
|
8
|
+
import { sceneParentsOf, sceneShownPathOf } from "./scenePickReads.js";
|
|
9
|
+
import { indexedCandidates } from "./pickIndex/scenePickIndex.js";
|
|
10
|
+
|
|
11
|
+
//#region src/canvas/scenePickSource.ts
|
|
12
|
+
function scenePickSource(scene, opts = {}) {
|
|
13
|
+
const gates = nodeGates(scene);
|
|
14
|
+
const enumerable = typeof scene.overrides?.ids === "function";
|
|
15
|
+
const asShown = (node) => scene.overrides ? nodeAsShown(scene.overrides, node) : node;
|
|
16
|
+
const allAsShown = (nodes) => enumerable ? nodesAsShown(scene.overrides, nodes) : nodes.map(asShown);
|
|
17
|
+
const annotations = annotationLayerIds(scene.layers);
|
|
18
|
+
const { getPose, alphaOf, layerIsPainted } = opts;
|
|
19
|
+
let faded = null;
|
|
20
|
+
if (!alphaOf && enumerable) for (const id of scene.overrides.ids()) {
|
|
21
|
+
const a = scene.overrides.read(id)?.alpha;
|
|
22
|
+
if (a !== void 0 && a <= 0) (faded ??= /* @__PURE__ */ new Set()).add(id);
|
|
23
|
+
}
|
|
24
|
+
const readAlpha = alphaOf ?? (enumerable ? faded ? (id) => faded.has(id) ? 0 : 1 : void 0 : (id) => scene.overrides.read(asNodeId(id))?.alpha ?? 1);
|
|
25
|
+
const paintedPoseOf = scenePaintedPoseOf(scene);
|
|
26
|
+
const poseOf = getPose ? (node) => getPose(node.id) : (node) => paintedPoseOf(node);
|
|
27
|
+
const childrenOf = (id) => scene.childrenOf(id);
|
|
28
|
+
const depOf = (id) => {
|
|
29
|
+
const stored = scene.get(id);
|
|
30
|
+
if (stored === void 0) return void 0;
|
|
31
|
+
const dep = asShown(stored);
|
|
32
|
+
return {
|
|
33
|
+
node: dep,
|
|
34
|
+
pose: poseOf(dep),
|
|
35
|
+
get path() {
|
|
36
|
+
return resolveDerivedPath(dep, depOf, childrenOf);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
const derivedPathOf = getPose ? (node) => {
|
|
41
|
+
const n = node;
|
|
42
|
+
return n.dependsOn === void 0 ? null : resolveDerivedPath(n, depOf, childrenOf);
|
|
43
|
+
} : sceneShownPathOf(scene);
|
|
44
|
+
const planeOf = opts.camera ? scenePlaneOf(scene.layers, opts.camera) : null;
|
|
45
|
+
const index = getPose || typeof scene.getVersion !== "function" ? void 0 : opts.index;
|
|
46
|
+
return {
|
|
47
|
+
...planeOf ? { planeOf } : {},
|
|
48
|
+
...index ? { candidates: (broadFor) => {
|
|
49
|
+
const found = indexedCandidates(scene, index.descriptor, broadFor);
|
|
50
|
+
return found === null ? null : allAsShown(found);
|
|
51
|
+
} } : {},
|
|
52
|
+
order: () => allAsShown(scene.renderOrderNodes()),
|
|
53
|
+
derivedPathOf,
|
|
54
|
+
poseOf,
|
|
55
|
+
parentsOf: sceneParentsOf(scene),
|
|
56
|
+
...readAlpha ? { alphaOf: readAlpha } : {},
|
|
57
|
+
isLocked: (node) => gates.locked(node.id),
|
|
58
|
+
isHidden: (node) => gates.hidden(node.id),
|
|
59
|
+
...annotations.size > 0 || layerIsPainted ? { layerIsPainted: (layer) => !annotations.has(layer) && (layerIsPainted === void 0 || layerIsPainted(layer)) } : {}
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/** Each parallax layer's plane map under `camera`, or null when no layer is a
|
|
63
|
+
* plane — which keeps the per-layer lookup off the walk entirely. */
|
|
64
|
+
function scenePlaneOf(layers, camera) {
|
|
65
|
+
let maps = null;
|
|
66
|
+
for (const l of layers ?? []) if (l.parallax) (maps ??= /* @__PURE__ */ new Map()).set(l.id, planeMap(camera, l.parallax));
|
|
67
|
+
if (maps === null) return null;
|
|
68
|
+
const found = maps;
|
|
69
|
+
return (layer) => found.get(layer) ?? null;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
//#endregion
|
|
73
|
+
export { scenePickSource, scenePlaneOf };
|
|
74
|
+
//# sourceMappingURL=scenePickSource.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scenePickSource.js","names":[],"sources":["../../src/canvas/scenePickSource.ts"],"sourcesContent":["/** The pick source over a `Scene`: its render order, painted poses and gates,\n * and, given a descriptor, the pick index that narrows the walk. */\nimport type { Path } from '@weasel-js/geom';\nimport type { DerivedDep, Node, NodeId, Scene } from 'core/scene/types';\nimport { asNodeId } from 'core/scene/types';\nimport { annotationLayerIds } from 'core/scene/annotation';\nimport { nodeGates } from 'core/scene/nodeGates';\nimport { planeMap, type ParallaxOpts, type PlaneMap } from 'core/viewport/parallax';\nimport type { View } from 'core/viewport/view';\nimport type { PoseDescriptor } from 'interactions/actions/resize/geometry';\nimport { resolveDerivedPath, scenePaintedPoseOf } from './derivedPath';\nimport { indexedCandidates } from './pickIndex/scenePickIndex';\nimport type { PickBroad, PickCandidate, PickSource, ViewPickGates } from './pickWalk';\nimport { sceneParentsOf, sceneShownPathOf } from './scenePickReads';\nimport { nodeAsShown, nodesAsShown } from 'core/scene/nodeAsShown';\n\nexport interface ScenePickSourceOptions<TPose> extends ViewPickGates {\n /** Pose lookup, when the caller holds an adapter that already resolves\n * overrides. Defaults to `effectivePose` against the scene's own. */\n getPose?: (id: string) => TPose;\n /** The asking view's composed alpha — `alphaFor(id)` times override alpha.\n * Defaults to the override alpha alone, which is all a bare scene knows. */\n alphaOf?: (id: string) => number;\n /** The asking view's answer to \"does this scene layer reach the screen\",\n * which is `layerVisibility` and `layerOrder` on top of the scene's own\n * `visible` flag. Consulted after the scene's flag, never instead of it. */\n layerIsPainted?: (layer: string) => boolean;\n /** The asking view's camera. With it, a layer carrying `parallax` is picked\n * through its plane; without it, every layer is taken to move with the\n * camera. */\n camera?: View;\n /** Box every node once per scene change, so a query carrying a `broad` box\n * visits only the nodes it can hit. `descriptor` must be the one the\n * query reads poses through. */\n index?: { descriptor: PoseDescriptor<unknown> };\n}\n\nexport function scenePickSource<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n opts: ScenePickSourceOptions<TPose> = {},\n): PickSource<TPose> {\n // Partial scene stand-ins carry only `layers` and `get`, which is all the gates read.\n const gates = nodeGates(scene as never);\n const enumerable = typeof scene.overrides?.ids === 'function';\n // Pick candidates carry a plain string id; the scene answers them all the same.\n const asShown = <N extends { id: string; data?: unknown }>(node: N): N =>\n (scene.overrides ? nodeAsShown(scene.overrides, node as N & { id: NodeId }) : node);\n const allAsShown = <N extends { id: string; data?: unknown }>(nodes: readonly N[]): readonly N[] =>\n (enumerable ? nodesAsShown(scene.overrides, nodes as readonly (N & { id: NodeId })[]) : nodes.map(asShown));\n const annotations = annotationLayerIds(scene.layers);\n const { getPose, alphaOf, layerIsPainted } = opts;\n\n // Resolved once per walk rather than once per candidate. Needs enumeration — a\n // partial scene stand-in carrying only `read` falls back to reading per node.\n let faded: Set<string> | null = null;\n if (!alphaOf && enumerable) {\n for (const id of scene.overrides.ids()) {\n const a = scene.overrides.read(id)?.alpha;\n if (a !== undefined && a <= 0) (faded ??= new Set()).add(id);\n }\n }\n const readAlpha = alphaOf\n ?? (enumerable\n ? (faded ? (id: string) => (faded.has(id) ? 0 : 1) : undefined)\n : (id: string) => scene.overrides.read(asNodeId(id))?.alpha ?? 1);\n\n // A composing strategy makes a node's own pose local, so picking folds the\n // parent chain the same way the render walk does: one definition of both.\n const paintedPoseOf = scenePaintedPoseOf(scene);\n const poseOf = getPose\n ? (node: PickCandidate<TPose>) => getPose(node.id)\n : (node: PickCandidate<TPose>) => paintedPoseOf(node as never);\n\n // Through `poseOf`, not the document pose: a derived node has to be tested\n // where the renderer draws its dependencies, which is what an override says.\n const childrenOf = (id: NodeId): readonly NodeId[] => scene.childrenOf(id);\n const depOf = (id: NodeId): DerivedDep<TPose> | undefined => {\n const stored = scene.get(id);\n if (stored === undefined) return undefined;\n const dep = asShown(stored);\n return {\n node: dep as Node<unknown, string, TPose>,\n pose: poseOf(dep as never),\n get path(): Path | null {\n return resolveDerivedPath(dep as never, depOf, childrenOf);\n },\n };\n };\n\n const derivedPathOf = getPose\n ? (node: PickCandidate<TPose>): Path | null => {\n const n = node as unknown as Node<TData, TLayer, TPose>;\n return n.dependsOn === undefined ? null : resolveDerivedPath(n, depOf, childrenOf);\n }\n : sceneShownPathOf(scene);\n\n const planeOf = opts.camera ? scenePlaneOf(scene.layers, opts.camera) : null;\n\n // The index boxes nodes at the scene's painted poses; a custom `getPose` must be shown to agree first.\n // A partial stand-in has no versions for it to key on.\n const index = getPose || typeof scene.getVersion !== 'function' ? undefined : opts.index;\n return {\n ...(planeOf ? { planeOf } : {}),\n ...(index ? {\n candidates: (broadFor: (layer: string | undefined) => PickBroad | null | undefined) => {\n const found = indexedCandidates(scene as never, index.descriptor, broadFor) as readonly PickCandidate<TPose>[] | null;\n return found === null ? null : allAsShown(found);\n },\n } : {}),\n order: () => allAsShown(scene.renderOrderNodes() as unknown as readonly PickCandidate<TPose>[]),\n derivedPathOf,\n poseOf,\n parentsOf: sceneParentsOf(scene),\n // Absent entirely when nothing is faded, so the walk skips the gate.\n ...(readAlpha ? { alphaOf: readAlpha } : {}),\n isLocked: (node: PickCandidate<TPose>) => gates.locked(node.id),\n isHidden: (node: PickCandidate<TPose>) => gates.hidden(node.id),\n ...(annotations.size > 0 || layerIsPainted\n ? {\n layerIsPainted: (layer: string) =>\n !annotations.has(layer) && (layerIsPainted === undefined || layerIsPainted(layer)),\n }\n : {}),\n };\n}\n\n/** Each parallax layer's plane map under `camera`, or null when no layer is a\n * plane — which keeps the per-layer lookup off the walk entirely. */\nexport function scenePlaneOf(\n layers: readonly { id: string; parallax?: ParallaxOpts }[] | undefined,\n camera: View,\n): ((layer: string) => PlaneMap | null) | null {\n let maps: Map<string, PlaneMap> | null = null;\n for (const l of layers ?? []) {\n if (l.parallax) (maps ??= new Map()).set(l.id, planeMap(camera, l.parallax));\n }\n if (maps === null) return null;\n const found = maps;\n return (layer) => found.get(layer) ?? null;\n}\n"],"mappings":";;;;;;;;;;;AAqCA,SAAgB,gBACd,OACA,OAAsC,CAAC,GACpB;CAEnB,MAAM,QAAQ,UAAU,KAAc;CACtC,MAAM,aAAa,OAAO,MAAM,WAAW,QAAQ;CAEnD,MAAM,WAAqD,SACxD,MAAM,YAAY,YAAY,MAAM,WAAW,IAA0B,IAAI;CAChF,MAAM,cAAwD,UAC3D,aAAa,aAAa,MAAM,WAAW,KAAwC,IAAI,MAAM,IAAI,OAAO;CAC3G,MAAM,cAAc,mBAAmB,MAAM,MAAM;CACnD,MAAM,EAAE,SAAS,SAAS,mBAAmB;CAI7C,IAAI,QAA4B;CAChC,IAAI,CAAC,WAAW,YACd,KAAK,MAAM,MAAM,MAAM,UAAU,IAAI,GAAG;EACtC,MAAM,IAAI,MAAM,UAAU,KAAK,EAAE,CAAC,EAAE;EACpC,IAAI,MAAM,UAAa,KAAK,GAAG,CAAC,0BAAU,IAAI,IAAI,EAAA,CAAG,IAAI,EAAE;CAC7D;CAEF,MAAM,YAAY,YACZ,aACC,SAAS,OAAgB,MAAM,IAAI,EAAE,IAAI,IAAI,IAAK,UAClD,OAAe,MAAM,UAAU,KAAK,SAAS,EAAE,CAAC,CAAC,EAAE,SAAS;CAInE,MAAM,gBAAgB,mBAAmB,KAAK;CAC9C,MAAM,SAAS,WACV,SAA+B,QAAQ,KAAK,EAAE,KAC9C,SAA+B,cAAc,IAAa;CAI/D,MAAM,cAAc,OAAkC,MAAM,WAAW,EAAE;CACzE,MAAM,SAAS,OAA8C;EAC3D,MAAM,SAAS,MAAM,IAAI,EAAE;EAC3B,IAAI,WAAW,QAAW,OAAO;EACjC,MAAM,MAAM,QAAQ,MAAM;EAC1B,OAAO;GACL,MAAM;GACN,MAAM,OAAO,GAAY;GACzB,IAAI,OAAoB;IACtB,OAAO,mBAAmB,KAAc,OAAO,UAAU;GAC3D;EACF;CACF;CAEA,MAAM,gBAAgB,WACjB,SAA4C;EAC7C,MAAM,IAAI;EACV,OAAO,EAAE,cAAc,SAAY,OAAO,mBAAmB,GAAG,OAAO,UAAU;CACnF,IACE,iBAAiB,KAAK;CAE1B,MAAM,UAAU,KAAK,SAAS,aAAa,MAAM,QAAQ,KAAK,MAAM,IAAI;CAIxE,MAAM,QAAQ,WAAW,OAAO,MAAM,eAAe,aAAa,SAAY,KAAK;CACnF,OAAO;EACL,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;EAC7B,GAAI,QAAQ,EACV,aAAa,aAA0E;GACrF,MAAM,QAAQ,kBAAkB,OAAgB,MAAM,YAAY,QAAQ;GAC1E,OAAO,UAAU,OAAO,OAAO,WAAW,KAAK;EACjD,EACF,IAAI,CAAC;EACL,aAAa,WAAW,MAAM,iBAAiB,CAA+C;EAC9F;EACA;EACA,WAAW,eAAe,KAAK;EAE/B,GAAI,YAAY,EAAE,SAAS,UAAU,IAAI,CAAC;EAC1C,WAAW,SAA+B,MAAM,OAAO,KAAK,EAAE;EAC9D,WAAW,SAA+B,MAAM,OAAO,KAAK,EAAE;EAC9D,GAAI,YAAY,OAAO,KAAK,iBACxB,EACA,iBAAiB,UACf,CAAC,YAAY,IAAI,KAAK,MAAM,mBAAmB,UAAa,eAAe,KAAK,GACpF,IACE,CAAC;CACP;AACF;;;AAIA,SAAgB,aACd,QACA,QAC6C;CAC7C,IAAI,OAAqC;CACzC,KAAK,MAAM,KAAK,UAAU,CAAC,GACzB,IAAI,EAAE,UAAU,CAAC,yBAAS,IAAI,IAAI,EAAA,CAAG,IAAI,EAAE,IAAI,SAAS,QAAQ,EAAE,QAAQ,CAAC;CAE7E,IAAI,SAAS,MAAM,OAAO;CAC1B,MAAM,QAAQ;CACd,QAAQ,UAAU,MAAM,IAAI,KAAK,KAAK;AACxC"}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import { nodeAsShown, shownLookup } from "../core/scene/nodeAsShown.js";
|
|
2
|
+
import { withInheritedPaintBounds, withInheritedPaints } from "./inheritedPaints.js";
|
|
1
3
|
import { sceneDerivedPathOf, sceneShownToPose, withDerivedPaths } from "./derivedPath.js";
|
|
2
4
|
import { withColorOverrides } from "./colorOverrides.js";
|
|
5
|
+
import { withShownNode } from "./shownNodes.js";
|
|
3
6
|
|
|
4
7
|
//#region src/canvas/sceneSlotWiring.ts
|
|
5
8
|
/**
|
|
@@ -15,13 +18,16 @@ function composeAlphaFor(scene, alphaFor) {
|
|
|
15
18
|
return alphaFor ? (id) => alphaFor(id) * overrideAlphaFor(id) : overrideAlphaFor;
|
|
16
19
|
}
|
|
17
20
|
function wireSceneSlotToScene(slot, scene, alphaFor, colorOverrides) {
|
|
18
|
-
const
|
|
21
|
+
const shown = shownLookup(scene);
|
|
22
|
+
const derived = withDerivedPaths(scene, withInheritedPaints(shown, slot.drawOne), slot.toPose);
|
|
23
|
+
const painted = colorOverrides ? withColorOverrides(colorOverrides, derived) : derived;
|
|
19
24
|
const derivedPathOf = sceneDerivedPathOf(scene, slot.toPose);
|
|
20
25
|
return {
|
|
21
26
|
...slot,
|
|
22
27
|
...slot.toPose ? { toPose: sceneShownToPose(scene, slot.toPose) } : {},
|
|
23
|
-
|
|
24
|
-
|
|
28
|
+
...slot.paintBounds ? { paintBounds: withShownNode(scene.overrides, withInheritedPaintBounds(shown, slot.paintBounds)) } : {},
|
|
29
|
+
drawOne: withShownNode(scene.overrides, painted),
|
|
30
|
+
derivedPathOf: (node) => derivedPathOf(nodeAsShown(scene.overrides, node)),
|
|
25
31
|
alphaFor: composeAlphaFor(scene, alphaFor)
|
|
26
32
|
};
|
|
27
33
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sceneSlotWiring.js","names":[],"sources":["../../src/canvas/sceneSlotWiring.ts"],"sourcesContent":["/**\n * What the scene slot needs from the `Scene` that `<Canvas>` cannot see.\n *\n * `<Canvas>` is scene-agnostic: it walks an adapter.
|
|
1
|
+
{"version":3,"file":"sceneSlotWiring.js","names":[],"sources":["../../src/canvas/sceneSlotWiring.ts"],"sourcesContent":["/**\n * What the scene slot needs from the `Scene` that `<Canvas>` cannot see.\n *\n * `<Canvas>` is scene-agnostic: it walks an adapter. Five things a node is\n * painted with are therefore invisible to it — an ephemeral override's alpha\n * and data, a derived path, which needs other nodes' poses to resolve, the\n * paint an `'inherit'` field takes from its containers, and animated vertex\n * colors, which live in an animator. `<SceneCanvas>` folds them into the slot\n * here; `buildSceneViewCommands` does the same for the headless walk.\n */\nimport type { SceneSlotConfig } from './buildSceneLayer';\nimport type { Node, NodeId, Scene } from 'core/scene/types';\nimport { withInheritedPaintBounds, withInheritedPaints } from './inheritedPaints';\nimport { withDerivedPaths, sceneDerivedPathOf, sceneShownToPose } from './derivedPath';\nimport { withColorOverrides } from './colorOverrides';\nimport { nodeAsShown, shownLookup } from 'core/scene/nodeAsShown';\nimport { withShownNode } from './shownNodes';\nimport type { ColorOverrideRegistry } from '@weasel-js/animator';\n\n/**\n * The alpha a view paints a node at: the view's own `alphaFor` times any\n * ephemeral override alpha.\n *\n * The hit path asks this too — a node painted at alpha 0 is not on screen and\n * must not claim clicks — so it is one function rather than the painter's and\n * picking's separate readings of the same two inputs.\n */\nexport function composeAlphaFor<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n alphaFor?: (id: string) => number,\n): (id: string) => number {\n const overrideAlphaFor = (id: string) => scene.overrides.read(id as NodeId)?.alpha ?? 1;\n return alphaFor ? (id: string) => alphaFor(id) * overrideAlphaFor(id) : overrideAlphaFor;\n}\n\nexport function wireSceneSlotToScene<TData, TLayer extends string, TPose>(\n slot: SceneSlotConfig<Node<TData, TLayer, TPose>, TPose>,\n scene: Scene<TData, TLayer, TPose>,\n alphaFor?: (id: string) => number,\n colorOverrides?: ColorOverrideRegistry,\n): SceneSlotConfig<Node<TData, TLayer, TPose>, TPose> {\n const shown = shownLookup(scene);\n const derived = withDerivedPaths(scene, withInheritedPaints(shown, slot.drawOne), slot.toPose);\n const painted = colorOverrides ? withColorOverrides(colorOverrides, derived) : derived;\n const derivedPathOf = sceneDerivedPathOf(scene, slot.toPose);\n return {\n ...slot,\n ...(slot.toPose ? { toPose: sceneShownToPose(scene, slot.toPose) } : {}),\n ...(slot.paintBounds\n ? { paintBounds: withShownNode(scene.overrides, withInheritedPaintBounds(shown, slot.paintBounds)) }\n : {}),\n drawOne: withShownNode(scene.overrides, painted),\n derivedPathOf: (node) => derivedPathOf(nodeAsShown(scene.overrides, node)),\n alphaFor: composeAlphaFor(scene, alphaFor),\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;AA2BA,SAAgB,gBACd,OACA,UACwB;CACxB,MAAM,oBAAoB,OAAe,MAAM,UAAU,KAAK,EAAY,CAAC,EAAE,SAAS;CACtF,OAAO,YAAY,OAAe,SAAS,EAAE,IAAI,iBAAiB,EAAE,IAAI;AAC1E;AAEA,SAAgB,qBACd,MACA,OACA,UACA,gBACoD;CACpD,MAAM,QAAQ,YAAY,KAAK;CAC/B,MAAM,UAAU,iBAAiB,OAAO,oBAAoB,OAAO,KAAK,OAAO,GAAG,KAAK,MAAM;CAC7F,MAAM,UAAU,iBAAiB,mBAAmB,gBAAgB,OAAO,IAAI;CAC/E,MAAM,gBAAgB,mBAAmB,OAAO,KAAK,MAAM;CAC3D,OAAO;EACL,GAAG;EACH,GAAI,KAAK,SAAS,EAAE,QAAQ,iBAAiB,OAAO,KAAK,MAAM,EAAE,IAAI,CAAC;EACtE,GAAI,KAAK,cACL,EAAE,aAAa,cAAc,MAAM,WAAW,yBAAyB,OAAO,KAAK,WAAW,CAAC,EAAE,IACjG,CAAC;EACL,SAAS,cAAc,MAAM,WAAW,OAAO;EAC/C,gBAAgB,SAAS,cAAc,YAAY,MAAM,WAAW,IAAI,CAAC;EACzE,UAAU,gBAAgB,OAAO,QAAQ;CAC3C;AACF"}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { nodeAsShown, shownLookup } from "../core/scene/nodeAsShown.js";
|
|
2
|
+
import { withInheritedPaintBounds, withInheritedPaints } from "./inheritedPaints.js";
|
|
1
3
|
import { paintedSceneLayers } from "./sceneLayerPaint.js";
|
|
2
4
|
import { paintCanvas } from "./canvasRenderer.js";
|
|
3
5
|
import { wrapNodeOutput } from "./wrapNodeOutput.js";
|
|
@@ -7,6 +9,7 @@ import { sceneToAdapter } from "./sceneAdapter.js";
|
|
|
7
9
|
import { withColorOverrides } from "./colorOverrides.js";
|
|
8
10
|
import { paintMissesView } from "./paintCull.js";
|
|
9
11
|
import { paintBoundsFor } from "./defaultDrawOne.js";
|
|
12
|
+
import { withShownNode } from "./shownNodes.js";
|
|
10
13
|
import { cullDrawCommands } from "@weasel-js/renderer";
|
|
11
14
|
import { viewToMat3 as viewToMat3$1 } from "@weasel-js/geom";
|
|
12
15
|
|
|
@@ -43,12 +46,14 @@ function sceneAsHierarchy(scene, layers = {}) {
|
|
|
43
46
|
* `layers.layerOrder`), each holding one group per node on that layer.
|
|
44
47
|
*/
|
|
45
48
|
function buildSceneViewCommands(scene, view, drawOne, extraCommands, alphaFor, layers, colorOverrides, cull) {
|
|
46
|
-
const
|
|
49
|
+
const shown = shownLookup(scene);
|
|
50
|
+
const derivedOnly = withDerivedPaths(scene, withInheritedPaints(shown, drawOne));
|
|
47
51
|
const derived = colorOverrides ? withColorOverrides(colorOverrides, derivedOnly) : derivedOnly;
|
|
48
|
-
const
|
|
52
|
+
const derivedPathAt = sceneDerivedPathOf(scene);
|
|
53
|
+
const derivedPathOf = (node) => derivedPathAt(nodeAsShown(scene.overrides, node));
|
|
49
54
|
const wrappedDrawOne = (node, pose, v) => {
|
|
50
55
|
const overrideAlpha = scene.overrides.read(node.id)?.alpha ?? 1;
|
|
51
|
-
return wrapNodeOutput(derived(node, pose, v), pose, (alphaFor ? alphaFor(node.id) : 1) * overrideAlpha);
|
|
56
|
+
return wrapNodeOutput(derived(nodeAsShown(scene.overrides, node), pose, v), pose, (alphaFor ? alphaFor(node.id) : 1) * overrideAlpha);
|
|
52
57
|
};
|
|
53
58
|
const hierarchy = sceneAsHierarchy(scene, layers);
|
|
54
59
|
const cullRect = cull ? {
|
|
@@ -57,7 +62,7 @@ function buildSceneViewCommands(scene, view, drawOne, extraCommands, alphaFor, l
|
|
|
57
62
|
width: cull.width,
|
|
58
63
|
height: cull.height
|
|
59
64
|
} : void 0;
|
|
60
|
-
const culled = cullRect && cull?.paintBounds ? paintMissesView(cull.paintBounds, view, cullRect) : void 0;
|
|
65
|
+
const culled = cullRect && cull?.paintBounds ? paintMissesView(withShownNode(scene.overrides, withInheritedPaintBounds(shown, cull.paintBounds)), view, cullRect) : void 0;
|
|
61
66
|
const tree = buildSceneTree(hierarchy, wrappedDrawOne, view, void 0, derivedPathOf, culled);
|
|
62
67
|
const children = cullRect ? cullDrawCommands(tree, viewToMat3$1(view), cullRect) : tree;
|
|
63
68
|
if (extraCommands && extraCommands.length > 0) for (const cmd of extraCommands) children.push(cmd);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sceneViewRender.js","names":["viewToMat3"],"sources":["../../src/canvas/sceneViewRender.ts"],"sourcesContent":["/**\n * `renderSceneToCanvas` — substrate for detached, read-only scene views\n * (`<SceneViewCanvas>` / `<MinimapCanvas>`). Given a `<canvas>`, a `Scene`,\n * a `View`, and a per-node `drawOne`, render one frame.\n */\n\nimport type { WeaselRenderer } from '@weasel-js/renderer';\nimport { cachedCanvasRenderer, paintCanvas } from './canvasRenderer';\nimport { viewToMat3 } from '@weasel-js/geom';\nimport type { DrawCommand } from '@weasel-js/renderer';\nimport type { View } from '../core/viewport/view';\nimport type { Node, NodeId, Scene } from '../core/scene/types';\nimport { wrapNodeOutput } from './wrapNodeOutput';\nimport { buildSceneTree, type HierarchicalAdapter } from './buildSceneTree';\nimport { sceneToAdapter } from './sceneAdapter';\nimport { withDerivedPaths, sceneDerivedPathOf } from './derivedPath';\nimport { withColorOverrides } from './colorOverrides';\nimport type { ColorOverrideRegistry } from '@weasel-js/animator';\nimport type { SceneViewDrawOne } from './NodeShape';\nimport { paintedSceneLayers } from './sceneLayerPaint';\nimport { cullDrawCommands } from '@weasel-js/renderer';\nimport { paintMissesView, type PaintBoundsFn } from './paintCull';\nimport { paintBoundsFor } from './defaultDrawOne';\n\nexport type { SceneViewDrawOne } from './NodeShape';\n\n/**\n * Which scene layers a detached view paints, on top of each layer's own\n * `visible` flag. Keyed the way `<SceneCanvas>` keys its scene layers —\n * `scene:<layerId>` — so the map a main canvas takes serves its minimap too.\n */\nexport interface SceneViewLayers {\n /** `false` hides that layer in this view. It cannot show one the scene hides. */\n layerVisibility?: Record<string, boolean>;\n /** Paint order, bottom first. A listed order is the whole list: a scene\n * layer left out of it is not painted. */\n layerOrder?: readonly string[];\n}\n\n/** The view size `buildSceneViewCommands` culls to, and how it bounds a\n * node's paint before painting it. */\nexport interface SceneViewCull<TData, TLayer extends string, TPose> {\n width: number;\n height: number;\n paintBounds?: PaintBoundsFn<Node<TData, TLayer, TPose>, TPose>;\n}\n\n/** What to draw into an existing canvas: the scene, the view, and the same\n * painting hooks `<SceneCanvas>` takes. */\nexport interface RenderSceneToCanvasArgs<TData, TLayer extends string, TPose> {\n /** The DOM canvas to paint into. The first call on a given canvas creates\n * its renderer and later calls reuse it;\n * `releaseCanvasRenderer(canvas)` frees it. */\n canvas: HTMLCanvasElement;\n scene: Scene<TData, TLayer, TPose>;\n /** Camera view applied to scene and `extraCommands` alike. */\n view: View;\n /** CSS-pixel size. The drawing buffer is set to `width × dpr` and\n * `height × dpr`; the element's CSS size is the caller's to set. */\n width: number;\n height: number;\n drawOne: SceneViewDrawOne<TData, TLayer, TPose>;\n /** Commands appended after the scene-node output, wrapped in the same view\n * transform as scene commands. */\n extraCommands?: DrawCommand[];\n /** Per-id alpha multiplier, mirroring `<SceneCanvas>`'s scene-slot\n * `alphaFor`. Defaults to `() => 1`. */\n alphaFor?: (id: string) => number;\n /** Per-view layer visibility. See {@link SceneViewLayers}. */\n layerVisibility?: SceneViewLayers['layerVisibility'];\n /** Per-view layer order. See {@link SceneViewLayers}. */\n layerOrder?: SceneViewLayers['layerOrder'];\n /** Animated vertex colors to paint, typically an animator's\n * `colorOverrides` — see `NodePaintCtx.vertexColors`. */\n colorOverrides?: ColorOverrideRegistry;\n /** Skip what cannot reach the `width × height` view: nodes `paintBounds`\n * places outside it are not painted, and scene commands that cannot reach\n * it are dropped before the renderer — the scene slot's `cull`. Off by\n * default. `extraCommands` are never culled. */\n cull?: boolean;\n /** Where `drawOne`'s output for a node can reach, as on the scene slot.\n * Defaults to `defaultPaintBounds` when `drawOne` is `defaultDrawOne`. */\n paintBounds?: PaintBoundsFn<Node<TData, TLayer, TPose>, TPose>;\n /** Device-pixel ratio. Defaults to `window.devicePixelRatio || 1` when\n * available, otherwise 1. */\n dpr?: number;\n}\n\n/** Test seam: the renderer `renderSceneToCanvas` created for a canvas. Not\n * re-exported from the barrel. */\nexport function __getCachedRendererForTest(\n canvas: HTMLCanvasElement,\n): WeaselRenderer | undefined {\n return cachedCanvasRenderer(canvas);\n}\n\n/**\n * Present a `Scene` as the reading surface `buildSceneTree` walks: the scene\n * adapter's own reads, under this view's layer list.\n */\nfunction sceneAsHierarchy<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n layers: SceneViewLayers = {},\n): HierarchicalAdapter<Node<TData, TLayer, TPose>, TPose> {\n const { getNode, getChildren, getPose, composePose } = sceneToAdapter(scene);\n return {\n getLayers: () =>\n paintedSceneLayers(scene.layers, layers)\n .map((l) => ({ id: l.id, visible: l.visible, parallax: l.parallax })),\n getNode,\n getChildren,\n getPose,\n ...(composePose ? { composePose } : {}),\n };\n}\n\n/**\n * Build the DrawCommand list that `renderSceneToCanvas` would dispatch, in\n * screen space. Pure — no GL, no DOM. Walks the scene through `buildSceneTree`,\n * the same walk `<SceneCanvas>` uses, which is what keeps hidden layers\n * unpainted and container clips applied here.\n *\n * Each node's commands go through `wrapNodeOutput` — pose rotation, then the\n * `alphaFor` multiplier — so a `drawOne` that rotates its own output rotates\n * twice; emit unrotated geometry and let the pose drive it.\n *\n * Output is one group per **visible** layer, in scene-layer order (or\n * `layers.layerOrder`), each holding one group per node on that layer.\n */\nexport function buildSceneViewCommands<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n view: View,\n drawOne: SceneViewDrawOne<TData, TLayer, TPose>,\n extraCommands?: ReadonlyArray<DrawCommand>,\n alphaFor?: (id: string) => number,\n /** This view's own layer visibility and order. */\n layers?: SceneViewLayers,\n /** Animated vertex colors to paint, typically an animator's `colorOverrides`. */\n colorOverrides?: ColorOverrideRegistry,\n /** Cull the scene to this CSS-pixel view size — see\n * `RenderSceneToCanvasArgs.cull`. Omit to paint every node. */\n cull?: SceneViewCull<TData, TLayer, TPose>,\n): DrawCommand[] {\n const derivedOnly = withDerivedPaths(scene, drawOne);\n const derived = colorOverrides ? withColorOverrides(colorOverrides, derivedOnly) : derivedOnly;\n const derivedPathOf = sceneDerivedPathOf(scene);\n const wrappedDrawOne = (\n node: Node<TData, TLayer, TPose>,\n pose: TPose,\n v: View,\n ): DrawCommand[] => {\n const overrideAlpha = scene.overrides.read(node.id as NodeId)?.alpha ?? 1;\n return wrapNodeOutput(\n derived(node, pose, v),\n pose,\n (alphaFor ? alphaFor(node.id) : 1) * overrideAlpha,\n );\n };\n\n const hierarchy = sceneAsHierarchy(scene, layers);\n\n const cullRect = cull ? { x: 0, y: 0, width: cull.width, height: cull.height } : undefined;\n const culled = cullRect && cull?.paintBounds ? paintMissesView(cull.paintBounds, view, cullRect) : undefined;\n const tree: DrawCommand[] = buildSceneTree(\n hierarchy as Parameters<typeof buildSceneTree>[0],\n wrappedDrawOne as unknown as Parameters<typeof buildSceneTree>[1],\n view,\n undefined,\n derivedPathOf as unknown as Parameters<typeof buildSceneTree>[4],\n culled as Parameters<typeof buildSceneTree>[5],\n );\n const children = cullRect ? cullDrawCommands(tree, viewToMat3(view), cullRect) : tree;\n if (extraCommands && extraCommands.length > 0) {\n for (const cmd of extraCommands) children.push(cmd);\n }\n return [{\n kind: 'group',\n transform: viewToMat3(view),\n children,\n }];\n}\n\n/**\n * The commands `renderSceneToCanvas` paints for one frame — everything in\n * `args` but the canvas. `<SceneViewCanvas>` paints these through its own\n * renderer lease.\n */\nexport function sceneViewFrame<TData, TLayer extends string, TPose>(\n args: Omit<RenderSceneToCanvasArgs<TData, TLayer, TPose>, 'canvas'>,\n): DrawCommand[] {\n const {\n scene, view, width, height, drawOne, extraCommands, alphaFor, layerVisibility, layerOrder,\n colorOverrides, cull,\n } = args;\n return buildSceneViewCommands(\n scene, view, drawOne, extraCommands, alphaFor, { layerVisibility, layerOrder }, colorOverrides,\n cull ? { width, height, paintBounds: args.paintBounds ?? paintBoundsFor(drawOne) } : undefined,\n );\n}\n\n/**\n * Render one frame of `scene` at `view` into `canvas`. Where no WebGL2\n * context is available (jsdom) the call paints nothing. The canvas's renderer\n * lives until `releaseCanvasRenderer(canvas)`.\n */\nexport function renderSceneToCanvas<TData, TLayer extends string, TPose>(\n args: RenderSceneToCanvasArgs<TData, TLayer, TPose>,\n): void {\n const { canvas, view, width, height, dpr } = args;\n paintCanvas(canvas, sceneViewFrame(args), view, { width, height, dpr });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAoGA,SAAS,iBACP,OACA,SAA0B,CAAC,GAC6B;CACxD,MAAM,EAAE,SAAS,aAAa,SAAS,gBAAgB,eAAe,KAAK;CAC3E,OAAO;EACL,iBACE,mBAAmB,MAAM,QAAQ,MAAM,CAAC,CACrC,KAAK,OAAO;GAAE,IAAI,EAAE;GAAI,SAAS,EAAE;GAAS,UAAU,EAAE;EAAS,EAAE;EACxE;EACA;EACA;EACA,GAAI,cAAc,EAAE,YAAY,IAAI,CAAC;CACvC;AACF;;;;;;;;;;;;;;AAeA,SAAgB,uBACd,OACA,MACA,SACA,eACA,UAEA,QAEA,gBAGA,MACe;CACf,MAAM,cAAc,iBAAiB,OAAO,OAAO;CACnD,MAAM,UAAU,iBAAiB,mBAAmB,gBAAgB,WAAW,IAAI;CACnF,MAAM,gBAAgB,mBAAmB,KAAK;CAC9C,MAAM,kBACJ,MACA,MACA,MACkB;EAClB,MAAM,gBAAgB,MAAM,UAAU,KAAK,KAAK,EAAY,CAAC,EAAE,SAAS;EACxE,OAAO,eACL,QAAQ,MAAM,MAAM,CAAC,GACrB,OACC,WAAW,SAAS,KAAK,EAAE,IAAI,KAAK,aACvC;CACF;CAEA,MAAM,YAAY,iBAAiB,OAAO,MAAM;CAEhD,MAAM,WAAW,OAAO;EAAE,GAAG;EAAG,GAAG;EAAG,OAAO,KAAK;EAAO,QAAQ,KAAK;CAAO,IAAI;CACjF,MAAM,SAAS,YAAY,MAAM,cAAc,gBAAgB,KAAK,aAAa,MAAM,QAAQ,IAAI;CACnG,MAAM,OAAsB,eAC1B,WACA,gBACA,MACA,QACA,eACA,MACF;CACA,MAAM,WAAW,WAAW,iBAAiB,MAAMA,aAAW,IAAI,GAAG,QAAQ,IAAI;CACjF,IAAI,iBAAiB,cAAc,SAAS,GAC1C,KAAK,MAAM,OAAO,eAAe,SAAS,KAAK,GAAG;CAEpD,OAAO,CAAC;EACN,MAAM;EACN,WAAWA,aAAW,IAAI;EAC1B;CACF,CAAC;AACH;;;;;;AAOA,SAAgB,eACd,MACe;CACf,MAAM,EACJ,OAAO,MAAM,OAAO,QAAQ,SAAS,eAAe,UAAU,iBAAiB,YAC/E,gBAAgB,SACd;CACJ,OAAO,uBACL,OAAO,MAAM,SAAS,eAAe,UAAU;EAAE;EAAiB;CAAW,GAAG,gBAChF,OAAO;EAAE;EAAO;EAAQ,aAAa,KAAK,eAAe,eAAe,OAAO;CAAE,IAAI,MACvF;AACF;;;;;;AAOA,SAAgB,oBACd,MACM;CACN,MAAM,EAAE,QAAQ,MAAM,OAAO,QAAQ,QAAQ;CAC7C,YAAY,QAAQ,eAAe,IAAI,GAAG,MAAM;EAAE;EAAO;EAAQ;CAAI,CAAC;AACxE"}
|
|
1
|
+
{"version":3,"file":"sceneViewRender.js","names":["viewToMat3"],"sources":["../../src/canvas/sceneViewRender.ts"],"sourcesContent":["/**\n * `renderSceneToCanvas` — substrate for detached, read-only scene views\n * (`<SceneViewCanvas>` / `<MinimapCanvas>`). Given a `<canvas>`, a `Scene`,\n * a `View`, and a per-node `drawOne`, render one frame.\n */\n\nimport type { WeaselRenderer } from '@weasel-js/renderer';\nimport { cachedCanvasRenderer, paintCanvas } from './canvasRenderer';\nimport { viewToMat3 } from '@weasel-js/geom';\nimport type { DrawCommand } from '@weasel-js/renderer';\nimport type { View } from '../core/viewport/view';\nimport type { Node, NodeId, Scene } from '../core/scene/types';\nimport { wrapNodeOutput } from './wrapNodeOutput';\nimport { buildSceneTree, type HierarchicalAdapter } from './buildSceneTree';\nimport { sceneToAdapter } from './sceneAdapter';\nimport { withInheritedPaintBounds, withInheritedPaints } from './inheritedPaints';\nimport { withDerivedPaths, sceneDerivedPathOf } from './derivedPath';\nimport { withColorOverrides } from './colorOverrides';\nimport type { ColorOverrideRegistry } from '@weasel-js/animator';\nimport type { SceneViewDrawOne } from './NodeShape';\nimport { paintedSceneLayers } from './sceneLayerPaint';\nimport { cullDrawCommands } from '@weasel-js/renderer';\nimport { paintMissesView, type PaintBoundsFn } from './paintCull';\nimport { paintBoundsFor } from './defaultDrawOne';\nimport { nodeAsShown, shownLookup } from 'core/scene/nodeAsShown';\nimport { withShownNode } from './shownNodes';\n\nexport type { SceneViewDrawOne } from './NodeShape';\n\n/**\n * Which scene layers a detached view paints, on top of each layer's own\n * `visible` flag. Keyed the way `<SceneCanvas>` keys its scene layers —\n * `scene:<layerId>` — so the map a main canvas takes serves its minimap too.\n */\nexport interface SceneViewLayers {\n /** `false` hides that layer in this view. It cannot show one the scene hides. */\n layerVisibility?: Record<string, boolean>;\n /** Paint order, bottom first. A listed order is the whole list: a scene\n * layer left out of it is not painted. */\n layerOrder?: readonly string[];\n}\n\n/** The view size `buildSceneViewCommands` culls to, and how it bounds a\n * node's paint before painting it. */\nexport interface SceneViewCull<TData, TLayer extends string, TPose> {\n width: number;\n height: number;\n paintBounds?: PaintBoundsFn<Node<TData, TLayer, TPose>, TPose>;\n}\n\n/** What to draw into an existing canvas: the scene, the view, and the same\n * painting hooks `<SceneCanvas>` takes. */\nexport interface RenderSceneToCanvasArgs<TData, TLayer extends string, TPose> {\n /** The DOM canvas to paint into. The first call on a given canvas creates\n * its renderer and later calls reuse it;\n * `releaseCanvasRenderer(canvas)` frees it. */\n canvas: HTMLCanvasElement;\n scene: Scene<TData, TLayer, TPose>;\n /** Camera view applied to scene and `extraCommands` alike. */\n view: View;\n /** CSS-pixel size. The drawing buffer is set to `width × dpr` and\n * `height × dpr`; the element's CSS size is the caller's to set. */\n width: number;\n height: number;\n drawOne: SceneViewDrawOne<TData, TLayer, TPose>;\n /** Commands appended after the scene-node output, wrapped in the same view\n * transform as scene commands. */\n extraCommands?: DrawCommand[];\n /** Per-id alpha multiplier, mirroring `<SceneCanvas>`'s scene-slot\n * `alphaFor`. Defaults to `() => 1`. */\n alphaFor?: (id: string) => number;\n /** Per-view layer visibility. See {@link SceneViewLayers}. */\n layerVisibility?: SceneViewLayers['layerVisibility'];\n /** Per-view layer order. See {@link SceneViewLayers}. */\n layerOrder?: SceneViewLayers['layerOrder'];\n /** Animated vertex colors to paint, typically an animator's\n * `colorOverrides` — see `NodePaintCtx.vertexColors`. */\n colorOverrides?: ColorOverrideRegistry;\n /** Skip what cannot reach the `width × height` view: nodes `paintBounds`\n * places outside it are not painted, and scene commands that cannot reach\n * it are dropped before the renderer — the scene slot's `cull`. Off by\n * default. `extraCommands` are never culled. */\n cull?: boolean;\n /** Where `drawOne`'s output for a node can reach, as on the scene slot.\n * Defaults to `defaultPaintBounds` when `drawOne` is `defaultDrawOne`. */\n paintBounds?: PaintBoundsFn<Node<TData, TLayer, TPose>, TPose>;\n /** Device-pixel ratio. Defaults to `window.devicePixelRatio || 1` when\n * available, otherwise 1. */\n dpr?: number;\n}\n\n/** Test seam: the renderer `renderSceneToCanvas` created for a canvas. Not\n * re-exported from the barrel. */\nexport function __getCachedRendererForTest(\n canvas: HTMLCanvasElement,\n): WeaselRenderer | undefined {\n return cachedCanvasRenderer(canvas);\n}\n\n/**\n * Present a `Scene` as the reading surface `buildSceneTree` walks: the scene\n * adapter's own reads, under this view's layer list.\n */\nfunction sceneAsHierarchy<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n layers: SceneViewLayers = {},\n): HierarchicalAdapter<Node<TData, TLayer, TPose>, TPose> {\n const { getNode, getChildren, getPose, composePose } = sceneToAdapter(scene);\n return {\n getLayers: () =>\n paintedSceneLayers(scene.layers, layers)\n .map((l) => ({ id: l.id, visible: l.visible, parallax: l.parallax })),\n getNode,\n getChildren,\n getPose,\n ...(composePose ? { composePose } : {}),\n };\n}\n\n/**\n * Build the DrawCommand list that `renderSceneToCanvas` would dispatch, in\n * screen space. Pure — no GL, no DOM. Walks the scene through `buildSceneTree`,\n * the same walk `<SceneCanvas>` uses, which is what keeps hidden layers\n * unpainted and container clips applied here.\n *\n * Each node's commands go through `wrapNodeOutput` — pose rotation, then the\n * `alphaFor` multiplier — so a `drawOne` that rotates its own output rotates\n * twice; emit unrotated geometry and let the pose drive it.\n *\n * Output is one group per **visible** layer, in scene-layer order (or\n * `layers.layerOrder`), each holding one group per node on that layer.\n */\nexport function buildSceneViewCommands<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n view: View,\n drawOne: SceneViewDrawOne<TData, TLayer, TPose>,\n extraCommands?: ReadonlyArray<DrawCommand>,\n alphaFor?: (id: string) => number,\n /** This view's own layer visibility and order. */\n layers?: SceneViewLayers,\n /** Animated vertex colors to paint, typically an animator's `colorOverrides`. */\n colorOverrides?: ColorOverrideRegistry,\n /** Cull the scene to this CSS-pixel view size — see\n * `RenderSceneToCanvasArgs.cull`. Omit to paint every node. */\n cull?: SceneViewCull<TData, TLayer, TPose>,\n): DrawCommand[] {\n const shown = shownLookup(scene);\n const derivedOnly = withDerivedPaths(scene, withInheritedPaints(shown, drawOne));\n const derived = colorOverrides ? withColorOverrides(colorOverrides, derivedOnly) : derivedOnly;\n const derivedPathAt = sceneDerivedPathOf(scene);\n const derivedPathOf = (node: Node<TData, TLayer, TPose>) => derivedPathAt(nodeAsShown(scene.overrides, node));\n const wrappedDrawOne = (\n node: Node<TData, TLayer, TPose>,\n pose: TPose,\n v: View,\n ): DrawCommand[] => {\n const overrideAlpha = scene.overrides.read(node.id as NodeId)?.alpha ?? 1;\n return wrapNodeOutput(\n derived(nodeAsShown(scene.overrides, node), pose, v),\n pose,\n (alphaFor ? alphaFor(node.id) : 1) * overrideAlpha,\n );\n };\n\n const hierarchy = sceneAsHierarchy(scene, layers);\n\n const cullRect = cull ? { x: 0, y: 0, width: cull.width, height: cull.height } : undefined;\n const culled = cullRect && cull?.paintBounds\n ? paintMissesView(withShownNode(scene.overrides, withInheritedPaintBounds(shown, cull.paintBounds)), view, cullRect)\n : undefined;\n const tree: DrawCommand[] = buildSceneTree(\n hierarchy as Parameters<typeof buildSceneTree>[0],\n wrappedDrawOne as unknown as Parameters<typeof buildSceneTree>[1],\n view,\n undefined,\n derivedPathOf as unknown as Parameters<typeof buildSceneTree>[4],\n culled as Parameters<typeof buildSceneTree>[5],\n );\n const children = cullRect ? cullDrawCommands(tree, viewToMat3(view), cullRect) : tree;\n if (extraCommands && extraCommands.length > 0) {\n for (const cmd of extraCommands) children.push(cmd);\n }\n return [{\n kind: 'group',\n transform: viewToMat3(view),\n children,\n }];\n}\n\n/**\n * The commands `renderSceneToCanvas` paints for one frame — everything in\n * `args` but the canvas. `<SceneViewCanvas>` paints these through its own\n * renderer lease.\n */\nexport function sceneViewFrame<TData, TLayer extends string, TPose>(\n args: Omit<RenderSceneToCanvasArgs<TData, TLayer, TPose>, 'canvas'>,\n): DrawCommand[] {\n const {\n scene, view, width, height, drawOne, extraCommands, alphaFor, layerVisibility, layerOrder,\n colorOverrides, cull,\n } = args;\n return buildSceneViewCommands(\n scene, view, drawOne, extraCommands, alphaFor, { layerVisibility, layerOrder }, colorOverrides,\n cull ? { width, height, paintBounds: args.paintBounds ?? paintBoundsFor(drawOne) } : undefined,\n );\n}\n\n/**\n * Render one frame of `scene` at `view` into `canvas`. Where no WebGL2\n * context is available (jsdom) the call paints nothing. The canvas's renderer\n * lives until `releaseCanvasRenderer(canvas)`.\n */\nexport function renderSceneToCanvas<TData, TLayer extends string, TPose>(\n args: RenderSceneToCanvasArgs<TData, TLayer, TPose>,\n): void {\n const { canvas, view, width, height, dpr } = args;\n paintCanvas(canvas, sceneViewFrame(args), view, { width, height, dpr });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAuGA,SAAS,iBACP,OACA,SAA0B,CAAC,GAC6B;CACxD,MAAM,EAAE,SAAS,aAAa,SAAS,gBAAgB,eAAe,KAAK;CAC3E,OAAO;EACL,iBACE,mBAAmB,MAAM,QAAQ,MAAM,CAAC,CACrC,KAAK,OAAO;GAAE,IAAI,EAAE;GAAI,SAAS,EAAE;GAAS,UAAU,EAAE;EAAS,EAAE;EACxE;EACA;EACA;EACA,GAAI,cAAc,EAAE,YAAY,IAAI,CAAC;CACvC;AACF;;;;;;;;;;;;;;AAeA,SAAgB,uBACd,OACA,MACA,SACA,eACA,UAEA,QAEA,gBAGA,MACe;CACf,MAAM,QAAQ,YAAY,KAAK;CAC/B,MAAM,cAAc,iBAAiB,OAAO,oBAAoB,OAAO,OAAO,CAAC;CAC/E,MAAM,UAAU,iBAAiB,mBAAmB,gBAAgB,WAAW,IAAI;CACnF,MAAM,gBAAgB,mBAAmB,KAAK;CAC9C,MAAM,iBAAiB,SAAqC,cAAc,YAAY,MAAM,WAAW,IAAI,CAAC;CAC5G,MAAM,kBACJ,MACA,MACA,MACkB;EAClB,MAAM,gBAAgB,MAAM,UAAU,KAAK,KAAK,EAAY,CAAC,EAAE,SAAS;EACxE,OAAO,eACL,QAAQ,YAAY,MAAM,WAAW,IAAI,GAAG,MAAM,CAAC,GACnD,OACC,WAAW,SAAS,KAAK,EAAE,IAAI,KAAK,aACvC;CACF;CAEA,MAAM,YAAY,iBAAiB,OAAO,MAAM;CAEhD,MAAM,WAAW,OAAO;EAAE,GAAG;EAAG,GAAG;EAAG,OAAO,KAAK;EAAO,QAAQ,KAAK;CAAO,IAAI;CACjF,MAAM,SAAS,YAAY,MAAM,cAC7B,gBAAgB,cAAc,MAAM,WAAW,yBAAyB,OAAO,KAAK,WAAW,CAAC,GAAG,MAAM,QAAQ,IACjH;CACJ,MAAM,OAAsB,eAC1B,WACA,gBACA,MACA,QACA,eACA,MACF;CACA,MAAM,WAAW,WAAW,iBAAiB,MAAMA,aAAW,IAAI,GAAG,QAAQ,IAAI;CACjF,IAAI,iBAAiB,cAAc,SAAS,GAC1C,KAAK,MAAM,OAAO,eAAe,SAAS,KAAK,GAAG;CAEpD,OAAO,CAAC;EACN,MAAM;EACN,WAAWA,aAAW,IAAI;EAC1B;CACF,CAAC;AACH;;;;;;AAOA,SAAgB,eACd,MACe;CACf,MAAM,EACJ,OAAO,MAAM,OAAO,QAAQ,SAAS,eAAe,UAAU,iBAAiB,YAC/E,gBAAgB,SACd;CACJ,OAAO,uBACL,OAAO,MAAM,SAAS,eAAe,UAAU;EAAE;EAAiB;CAAW,GAAG,gBAChF,OAAO;EAAE;EAAO;EAAQ,aAAa,KAAK,eAAe,eAAe,OAAO;CAAE,IAAI,MACvF;AACF;;;;;;AAOA,SAAgB,oBACd,MACM;CACN,MAAM,EAAE,QAAQ,MAAM,OAAO,QAAQ,QAAQ;CAC7C,YAAY,QAAQ,eAAe,IAAI,GAAG,MAAM;EAAE;EAAO;EAAQ;CAAI,CAAC;AACxE"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { nodeAsShown } from "../core/scene/nodeAsShown.js";
|
|
2
|
+
|
|
3
|
+
//#region src/canvas/shownNodes.ts
|
|
4
|
+
/**
|
|
5
|
+
* The scene walks' half of `PoseOverride.data`: handing painters and cull
|
|
6
|
+
* bounds each node as the scene shows it, through `nodeAsShown`.
|
|
7
|
+
*/
|
|
8
|
+
/** `fn`, a painter or a cull's bounds, handed each node as it shows. */
|
|
9
|
+
function withShownNode(overrides, fn) {
|
|
10
|
+
return (node, a, b, c) => fn(nodeAsShown(overrides, node), a, b, c);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
//#endregion
|
|
14
|
+
export { withShownNode };
|
|
15
|
+
//# sourceMappingURL=shownNodes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shownNodes.js","names":[],"sources":["../../src/canvas/shownNodes.ts"],"sourcesContent":["/**\n * The scene walks' half of `PoseOverride.data`: handing painters and cull\n * bounds each node as the scene shows it, through `nodeAsShown`.\n */\nimport { nodeAsShown, type ShownDataSource } from 'core/scene/nodeAsShown';\nimport type { NodeId } from 'core/scene/types';\n\n/** `fn`, a painter or a cull's bounds, handed each node as it shows. */\nexport function withShownNode<TNode extends { id: NodeId; data?: unknown }, A, B, C, TOut>(\n overrides: ShownDataSource,\n fn: (node: TNode, a: A, b: B, c: C) => TOut,\n): (node: TNode, a: A, b: B, c: C) => TOut {\n return (node, a, b, c) => fn(nodeAsShown(overrides, node), a, b, c);\n}\n"],"mappings":";;;;;;;;AAQA,SAAgB,cACd,WACA,IACyC;CACzC,QAAQ,MAAM,GAAG,GAAG,MAAM,GAAG,YAAY,WAAW,IAAI,GAAG,GAAG,GAAG,CAAC;AACpE"}
|
|
@@ -8,19 +8,23 @@ import { mergeContributions } from "@weasel-js/routing";
|
|
|
8
8
|
*/
|
|
9
9
|
/**
|
|
10
10
|
* Concatenate contribution bundles into one registry, preserving order. Throws
|
|
11
|
-
* on a duplicate entry id, dep name or
|
|
12
|
-
* the same name is a bug in whichever was added second.
|
|
11
|
+
* on a duplicate entry id, dep name, view id or marker id — two features
|
|
12
|
+
* answering for the same name is a bug in whichever was added second.
|
|
13
13
|
*/
|
|
14
14
|
function mergeContributions$1(...bundles) {
|
|
15
15
|
const out = mergeContributions(...bundles);
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const owner = viewOwner.get(view.id);
|
|
19
|
-
if (owner !== void 0) throw new Error(`mergeContributions: view "${view.id}" is added by both "${owner}" and "${entry.id}". View ids are unique per surface; rename one.`);
|
|
20
|
-
viewOwner.set(view.id, entry.id);
|
|
21
|
-
}
|
|
16
|
+
claimIds(out, "view", (entry) => entry.views ?? []);
|
|
17
|
+
claimIds(out, "marker", (entry) => entry.markers ?? []);
|
|
22
18
|
return out;
|
|
23
19
|
}
|
|
20
|
+
function claimIds(entries, kind, of) {
|
|
21
|
+
const owners = /* @__PURE__ */ new Map();
|
|
22
|
+
for (const entry of entries) for (const { id } of of(entry)) {
|
|
23
|
+
const owner = owners.get(id);
|
|
24
|
+
if (owner !== void 0) throw new Error(`mergeContributions: ${kind} "${id}" is added by both "${owner}" and "${entry.id}". ${kind === "view" ? "View" : "Marker"} ids are unique per surface; rename one.`);
|
|
25
|
+
owners.set(id, entry.id);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
24
28
|
|
|
25
29
|
//#endregion
|
|
26
30
|
export { mergeContributions$1 as mergeContributions };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"surfaceContribution.js","names":["mergeContributions","mergeRoutingContributions"],"sources":["../../src/canvas/surfaceContribution.ts"],"sourcesContent":["/**\n * The canvas's unit of extension: a routing `Contribution` plus the roles only\n * a surface can install — views on it, and whatever else needs the mounted\n * canvas.\n */\nimport { mergeContributions as mergeRoutingContributions } from '@weasel-js/routing';\nimport type { DepName, DepSchema } from 'interactions/actions/depSchema';\nimport type { Contribution } from '../tools/overlayBinding';\nimport type { CanvasExtensionApi } from './canvasExtension';\nimport type { CanvasViewProps } from './CanvasView';\nimport type { View } from '../core/viewport/view';\nimport type { KitRequirements } from './kitRequirements';\n\n/** Reads the surface's deps from inside `SurfaceContribution.attach`. */\nexport interface ContributionDepReader {\n get<K extends DepName>(name: K): DepSchema[K] | undefined;\n}\n\n/** What {@link SurfaceContribution.beforePaint} and `afterPaint` are handed. */\nexport interface ContributionFrameCtx {\n /** The frame's timestamp, on `performance.now()`'s clock. Both phases of one\n * frame see the same value. */\n readonly time: number;\n /** The surface camera this frame paints with. */\n readonly view: View;\n /** Ask for another frame. A hook animating something calls this every frame\n * it still has work for, and stops calling it to let the loop go idle. */\n requestFrame(): void;\n /** The surface's deps, as `attach` reads them. */\n readonly deps: ContributionDepReader;\n}\n\n/**\n * A feature a surface installs in one step. Every role is optional: `bindings`,\n * `actions`, `deps`, `overlay` and `presentation` from `Contribution`, plus\n * the ones below. Installing it installs every role it declares, and removing\n * it removes them.\n */\nexport interface SurfaceContribution extends Contribution {\n /** Views this entry adds to the surface, as `<SceneCanvas views>` takes. */\n views?: readonly CanvasViewProps[];\n /**\n * Runs once the surface mounts; returns its teardown. For what the roles\n * above cannot say — a registered (hit-testable) layer, a subscription.\n *\n * Keyed by the function's identity, so a contribution built once (in a\n * `useMemo`, or at module scope) attaches once however often the host\n * re-renders.\n */\n attach?: (api: CanvasExtensionApi, deps: ContributionDepReader) => () => void;\n /**\n * Runs on every frame the surface paints, before the paint — for state the\n * entry's layers read, advanced once per frame. Hooks run in the order the\n * surface lists its entries (registered tools, then `ambient` in array\n * order), and one that throws is reported and skipped without stopping the\n * frame.\n */\n beforePaint?: (ctx: ContributionFrameCtx) => void;\n /** Runs after a frame's pixels have landed, in the same order as\n * {@link beforePaint}. A frame that painted nothing runs no `afterPaint`. */\n afterPaint?: (ctx: ContributionFrameCtx) => void;\n /**\n * The kit versions this entry was written against, as semver ranges:\n * `{ core: '^1.7' }`. A mismatch warns in development, or throws where the\n * surface is set to `versionCheck=\"strict\"`.\n */\n requires?: KitRequirements;\n}\n\n/**\n * Concatenate contribution bundles into one registry, preserving order. Throws\n * on a duplicate entry id, dep name or
|
|
1
|
+
{"version":3,"file":"surfaceContribution.js","names":["mergeContributions","mergeRoutingContributions"],"sources":["../../src/canvas/surfaceContribution.ts"],"sourcesContent":["/**\n * The canvas's unit of extension: a routing `Contribution` plus the roles only\n * a surface can install — views on it, and whatever else needs the mounted\n * canvas.\n */\nimport { mergeContributions as mergeRoutingContributions } from '@weasel-js/routing';\nimport type { DepName, DepSchema } from 'interactions/actions/depSchema';\nimport type { Contribution } from '../tools/overlayBinding';\nimport type { CanvasExtensionApi } from './canvasExtension';\nimport type { CanvasViewProps } from './CanvasView';\nimport type { ViewMarkerProps } from '../features/viewports/viewMarker';\nimport type { View } from '../core/viewport/view';\nimport type { KitRequirements } from './kitRequirements';\n\n/** Reads the surface's deps from inside `SurfaceContribution.attach`. */\nexport interface ContributionDepReader {\n get<K extends DepName>(name: K): DepSchema[K] | undefined;\n}\n\n/** What {@link SurfaceContribution.beforePaint} and `afterPaint` are handed. */\nexport interface ContributionFrameCtx {\n /** The frame's timestamp, on `performance.now()`'s clock. Both phases of one\n * frame see the same value. */\n readonly time: number;\n /** The surface camera this frame paints with. */\n readonly view: View;\n /** Ask for another frame. A hook animating something calls this every frame\n * it still has work for, and stops calling it to let the loop go idle. */\n requestFrame(): void;\n /** The surface's deps, as `attach` reads them. */\n readonly deps: ContributionDepReader;\n}\n\n/**\n * A feature a surface installs in one step. Every role is optional: `bindings`,\n * `actions`, `deps`, `overlay` and `presentation` from `Contribution`, plus\n * the ones below. Installing it installs every role it declares, and removing\n * it removes them.\n */\nexport interface SurfaceContribution extends Contribution {\n /** Views this entry adds to the surface, as `<SceneCanvas views>` takes. */\n views?: readonly CanvasViewProps[];\n /** Markers this entry draws, as `<ViewMarker>` elements would. */\n markers?: readonly ViewMarkerProps[];\n /**\n * Runs once the surface mounts; returns its teardown. For what the roles\n * above cannot say — a registered (hit-testable) layer, a subscription.\n *\n * Keyed by the function's identity, so a contribution built once (in a\n * `useMemo`, or at module scope) attaches once however often the host\n * re-renders.\n */\n attach?: (api: CanvasExtensionApi, deps: ContributionDepReader) => () => void;\n /**\n * Runs on every frame the surface paints, before the paint — for state the\n * entry's layers read, advanced once per frame. Hooks run in the order the\n * surface lists its entries (registered tools, then `ambient` in array\n * order), and one that throws is reported and skipped without stopping the\n * frame.\n */\n beforePaint?: (ctx: ContributionFrameCtx) => void;\n /** Runs after a frame's pixels have landed, in the same order as\n * {@link beforePaint}. A frame that painted nothing runs no `afterPaint`. */\n afterPaint?: (ctx: ContributionFrameCtx) => void;\n /**\n * The kit versions this entry was written against, as semver ranges:\n * `{ core: '^1.7' }`. A mismatch warns in development, or throws where the\n * surface is set to `versionCheck=\"strict\"`.\n */\n requires?: KitRequirements;\n}\n\n/**\n * Concatenate contribution bundles into one registry, preserving order. Throws\n * on a duplicate entry id, dep name, view id or marker id — two features\n * answering for the same name is a bug in whichever was added second.\n */\nexport function mergeContributions<T extends SurfaceContribution>(\n ...bundles: readonly (readonly T[])[]\n): T[] {\n const out = mergeRoutingContributions<T>(...bundles);\n claimIds(out, 'view', (entry) => entry.views ?? []);\n claimIds(out, 'marker', (entry) => entry.markers ?? []);\n return out;\n}\n\nfunction claimIds<T extends SurfaceContribution>(\n entries: readonly T[], kind: 'view' | 'marker', of: (entry: T) => readonly { id: string }[],\n): void {\n const owners = new Map<string, string>();\n for (const entry of entries) {\n for (const { id } of of(entry)) {\n const owner = owners.get(id);\n if (owner !== undefined) {\n throw new Error(\n `mergeContributions: ${kind} \"${id}\" is added by both \"${owner}\" and \"${entry.id}\". `\n + `${kind === 'view' ? 'View' : 'Marker'} ids are unique per surface; rename one.`,\n );\n }\n owners.set(id, entry.id);\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;AA6EA,SAAgBA,qBACd,GAAG,SACE;CACL,MAAM,MAAMC,mBAA6B,GAAG,OAAO;CACnD,SAAS,KAAK,SAAS,UAAU,MAAM,SAAS,CAAC,CAAC;CAClD,SAAS,KAAK,WAAW,UAAU,MAAM,WAAW,CAAC,CAAC;CACtD,OAAO;AACT;AAEA,SAAS,SACP,SAAuB,MAAyB,IAC1C;CACN,MAAM,yBAAS,IAAI,IAAoB;CACvC,KAAK,MAAM,SAAS,SAClB,KAAK,MAAM,EAAE,QAAQ,GAAG,KAAK,GAAG;EAC9B,MAAM,QAAQ,OAAO,IAAI,EAAE;EAC3B,IAAI,UAAU,QACZ,MAAM,IAAI,MACR,uBAAuB,KAAK,IAAI,GAAG,sBAAsB,MAAM,SAAS,MAAM,GAAG,KAC5E,SAAS,SAAS,SAAS,SAAS,yCAC3C;EAEF,OAAO,IAAI,IAAI,MAAM,EAAE;CACzB;AAEJ"}
|
|
@@ -30,7 +30,8 @@ function useCanvasView(opts) {
|
|
|
30
30
|
onViewChange,
|
|
31
31
|
viewBounds,
|
|
32
32
|
dims,
|
|
33
|
-
requestRedraw
|
|
33
|
+
requestRedraw,
|
|
34
|
+
by: opts.controlledBy ?? "view"
|
|
34
35
|
});
|
|
35
36
|
const controlledWarnedRef = useRef(false);
|
|
36
37
|
const getView = useCallback(() => {
|
|
@@ -44,7 +45,8 @@ function useCanvasView(opts) {
|
|
|
44
45
|
if (controlled) {
|
|
45
46
|
if (imperative && !controlledWarnedRef.current) {
|
|
46
47
|
controlledWarnedRef.current = true;
|
|
47
|
-
|
|
48
|
+
const [prop, cb] = live.current.by === "aim" ? ["aim", "onAimChange"] : ["view", "onViewChange"];
|
|
49
|
+
console.warn(forward ? `[weasel] setView not applied locally: this canvas is controlled by its \`${prop}\` prop. The value was forwarded to \`${cb}\` — update the prop from there, or drop it to take the imperative path.` : `[weasel] setView ignored: this canvas is controlled by its \`${prop}\` prop and has no \`${cb}\`, so the value has nowhere to go. Update the prop, or drop it to take the imperative path.`);
|
|
48
50
|
}
|
|
49
51
|
forward?.(clamped);
|
|
50
52
|
if (derived) redraw();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useCanvasView.js","names":[],"sources":["../../src/canvas/useCanvasView.ts"],"sourcesContent":["/**\n * A camera: held in a ref when uncontrolled, taken from the `view` option when\n * controlled, with one write path and one subscriber list over both.\n * `<SceneCanvas>` makes the one its `<Canvas>` looks through, and each\n * `<CanvasView>` makes its own.\n */\nimport { useCallback, useRef, type MutableRefObject } from 'react';\nimport { useLatest } from '@weasel-js/react';\nimport type { Dims } from 'core/layers/render';\nimport type { Bounds } from 'core/viewport/fitViewToBounds';\nimport { clampView } from 'core/viewport/clampView';\nimport { normalizeView, sameView, type View } from 'core/viewport/view';\n\n/** The view props a canvas takes for its camera. */\nexport interface CameraProps {\n /** Controlled viewport. When supplied, the canvas does not own the value —\n * the consumer must supply `onViewChange` and re-render with the new\n * view. See `View` JSDoc for the camera-position convention. */\n view?: View;\n /** Initial viewport for the uncontrolled path. Default `{x:0, y:0}`. */\n defaultView?: View;\n /** Fires whenever the viewport changes — in both controlled and\n * uncontrolled modes. */\n onViewChange?: (next: View) => void;\n /**\n * Optional world-space rect that constrains pan: every write to the view passes through\n * `clampView` first, keeping the visible rect inside `viewBounds`. An axis where the\n * visible rect is larger than the bounds is centered. Has no effect on `scale`.\n */\n viewBounds?: { x: number; y: number; width: number; height: number };\n}\n\n/** Inputs to {@link useCanvasView}: the camera's view props and what a write\n * needs from whatever the camera looks through. */\nexport interface CanvasViewOptions {\n /** Supplied, the camera is controlled. A thunk is a camera derived from\n * something else, read fresh at every {@link CanvasViewState.getView}. */\n view: View | (() => View) | undefined;\n defaultView: View | undefined;\n onViewChange: ((next: View) => void) | undefined;\n viewBounds: Bounds | undefined;\n /** The size the camera looks through, which `viewBounds` clamps against. */\n dims: () => Dims;\n requestRedraw: () => void;\n}\n\n/** What `useCanvasView` hands back. The owner decides when in a commit\n * the two controlled steps run, since they have to sit among its own effects. */\nexport interface CanvasViewState {\n /** The view in effect. Written by a write when uncontrolled and by\n * `adoptControlled` when controlled. A camera derived by a thunk is not\n * kept here: read `getView`. */\n viewRef: MutableRefObject<View>;\n /** This render's controlled view, absent when the camera is uncontrolled or\n * derived. A new object every render, so compare its numbers. */\n controlled: View | undefined;\n /** The imperative write. Controlled, it is forwarded to `onViewChange`\n * instead of applied, and says so once per mount. */\n setView: (next: View | ((current: View) => View)) => void;\n /** The write input makes. Controlled, forwarding it to `onViewChange` is how\n * the owner hears of a pan at all, so nothing is warned. */\n setViewFromInput: (next: View) => void;\n getView: () => View;\n subscribeView: (fn: (v: View) => void) => () => void;\n /** Take this render's controlled view into `viewRef`. Call from an insertion effect. */\n adoptControlled: () => void;\n /** Tell subscribers of a controlled view that moved since the last call.\n * A controlled view reaches the ref with no write, so this is where they\n * hear of it. Call from a layout effect. */\n announceControlled: () => void;\n /** Drop every subscriber, on unmount. */\n clearSubscribers: () => void;\n}\n\nconst IDENTITY: View = { x: 0, y: 0, scale: { x: 1, y: 1 } };\n\nexport function useCanvasView(opts: CanvasViewOptions): CanvasViewState {\n const { view: viewProp, defaultView, onViewChange, viewBounds, dims, requestRedraw } = opts;\n const derived = typeof viewProp === 'function' ? viewProp : undefined;\n const controlledView = viewProp === undefined || derived ? undefined : normalizeView(viewProp as View);\n // The uncontrolled view lives in a ref, not `useState`, so a camera moving\n // at 60 Hz costs no React render; DOM that mirrors it subscribes instead.\n const viewRef = useRef<View>(controlledView ?? normalizeView(defaultView ?? IDENTITY));\n const viewSubsRef = useRef<Set<(v: View) => void>>(new Set());\n const live = useLatest({\n controlled: viewProp !== undefined, derived, onViewChange, viewBounds, dims, requestRedraw,\n });\n const controlledWarnedRef = useRef(false);\n\n const getView = useCallback((): View => {\n const thunk = live.current.derived;\n return thunk ? normalizeView(thunk()) : viewRef.current;\n }, [live]);\n\n const write = useCallback((next: View, imperative: boolean): void => {\n const {\n controlled, derived, onViewChange: forward, viewBounds: bounds, dims: size, requestRedraw: redraw,\n } = live.current;\n const valid = normalizeView(next);\n const clamped = bounds ? clampView(valid, bounds, size()) : valid;\n if (controlled) {\n // The prop is the authority; writing the ref would put pixels and props\n // out of step with nothing to reconcile them.\n if (imperative && !controlledWarnedRef.current) {\n controlledWarnedRef.current = true;\n console.warn(forward\n ?
|
|
1
|
+
{"version":3,"file":"useCanvasView.js","names":[],"sources":["../../src/canvas/useCanvasView.ts"],"sourcesContent":["/**\n * A camera: held in a ref when uncontrolled, taken from the `view` option when\n * controlled, with one write path and one subscriber list over both.\n * `<SceneCanvas>` makes the one its `<Canvas>` looks through, and each\n * `<CanvasView>` makes its own.\n */\nimport { useCallback, useRef, type MutableRefObject } from 'react';\nimport { useLatest } from '@weasel-js/react';\nimport type { Dims } from 'core/layers/render';\nimport type { Bounds } from 'core/viewport/fitViewToBounds';\nimport { clampView } from 'core/viewport/clampView';\nimport { normalizeView, sameView, type View } from 'core/viewport/view';\n\n/** The view props a canvas takes for its camera. */\nexport interface CameraProps {\n /** Controlled viewport. When supplied, the canvas does not own the value —\n * the consumer must supply `onViewChange` and re-render with the new\n * view. See `View` JSDoc for the camera-position convention. */\n view?: View;\n /** Initial viewport for the uncontrolled path. Default `{x:0, y:0}`. */\n defaultView?: View;\n /** Fires whenever the viewport changes — in both controlled and\n * uncontrolled modes. */\n onViewChange?: (next: View) => void;\n /**\n * Optional world-space rect that constrains pan: every write to the view passes through\n * `clampView` first, keeping the visible rect inside `viewBounds`. An axis where the\n * visible rect is larger than the bounds is centered. Has no effect on `scale`.\n */\n viewBounds?: { x: number; y: number; width: number; height: number };\n}\n\n/** Inputs to {@link useCanvasView}: the camera's view props and what a write\n * needs from whatever the camera looks through. */\nexport interface CanvasViewOptions {\n /** Supplied, the camera is controlled. A thunk is a camera derived from\n * something else, read fresh at every {@link CanvasViewState.getView}. */\n view: View | (() => View) | undefined;\n defaultView: View | undefined;\n onViewChange: ((next: View) => void) | undefined;\n viewBounds: Bounds | undefined;\n /** The size the camera looks through, which `viewBounds` clamps against. */\n dims: () => Dims;\n requestRedraw: () => void;\n /** The prop a controlled camera answers to, which a warning names. Default `'view'`. */\n controlledBy?: 'view' | 'aim';\n}\n\n/** What `useCanvasView` hands back. The owner decides when in a commit\n * the two controlled steps run, since they have to sit among its own effects. */\nexport interface CanvasViewState {\n /** The view in effect. Written by a write when uncontrolled and by\n * `adoptControlled` when controlled. A camera derived by a thunk is not\n * kept here: read `getView`. */\n viewRef: MutableRefObject<View>;\n /** This render's controlled view, absent when the camera is uncontrolled or\n * derived. A new object every render, so compare its numbers. */\n controlled: View | undefined;\n /** The imperative write. Controlled, it is forwarded to `onViewChange`\n * instead of applied, and says so once per mount. */\n setView: (next: View | ((current: View) => View)) => void;\n /** The write input makes. Controlled, forwarding it to `onViewChange` is how\n * the owner hears of a pan at all, so nothing is warned. */\n setViewFromInput: (next: View) => void;\n getView: () => View;\n subscribeView: (fn: (v: View) => void) => () => void;\n /** Take this render's controlled view into `viewRef`. Call from an insertion effect. */\n adoptControlled: () => void;\n /** Tell subscribers of a controlled view that moved since the last call.\n * A controlled view reaches the ref with no write, so this is where they\n * hear of it. Call from a layout effect. */\n announceControlled: () => void;\n /** Drop every subscriber, on unmount. */\n clearSubscribers: () => void;\n}\n\nconst IDENTITY: View = { x: 0, y: 0, scale: { x: 1, y: 1 } };\n\nexport function useCanvasView(opts: CanvasViewOptions): CanvasViewState {\n const { view: viewProp, defaultView, onViewChange, viewBounds, dims, requestRedraw } = opts;\n const derived = typeof viewProp === 'function' ? viewProp : undefined;\n const controlledView = viewProp === undefined || derived ? undefined : normalizeView(viewProp as View);\n // The uncontrolled view lives in a ref, not `useState`, so a camera moving\n // at 60 Hz costs no React render; DOM that mirrors it subscribes instead.\n const viewRef = useRef<View>(controlledView ?? normalizeView(defaultView ?? IDENTITY));\n const viewSubsRef = useRef<Set<(v: View) => void>>(new Set());\n const live = useLatest({\n controlled: viewProp !== undefined, derived, onViewChange, viewBounds, dims, requestRedraw,\n by: opts.controlledBy ?? 'view',\n });\n const controlledWarnedRef = useRef(false);\n\n const getView = useCallback((): View => {\n const thunk = live.current.derived;\n return thunk ? normalizeView(thunk()) : viewRef.current;\n }, [live]);\n\n const write = useCallback((next: View, imperative: boolean): void => {\n const {\n controlled, derived, onViewChange: forward, viewBounds: bounds, dims: size, requestRedraw: redraw,\n } = live.current;\n const valid = normalizeView(next);\n const clamped = bounds ? clampView(valid, bounds, size()) : valid;\n if (controlled) {\n // The prop is the authority; writing the ref would put pixels and props\n // out of step with nothing to reconcile them.\n if (imperative && !controlledWarnedRef.current) {\n controlledWarnedRef.current = true;\n const [prop, cb] = live.current.by === 'aim' ? ['aim', 'onAimChange'] : ['view', 'onViewChange'];\n console.warn(forward\n ? `[weasel] setView not applied locally: this canvas is controlled by its \\`${prop}\\` prop. The value was forwarded to \\`${cb}\\` — update the prop from there, or drop it to take the imperative path.`\n : `[weasel] setView ignored: this canvas is controlled by its \\`${prop}\\` prop and has no \\`${cb}\\`, so the value has nowhere to go. Update the prop, or drop it to take the imperative path.`);\n }\n forward?.(clamped);\n // A derived camera has no prop to change, so nothing else repaints it.\n if (derived) redraw();\n return;\n }\n viewRef.current = clamped;\n for (const fn of viewSubsRef.current) fn(clamped);\n forward?.(clamped);\n redraw();\n }, [live]);\n\n const setView = useCallback((next: View | ((current: View) => View)) => {\n write(typeof next === 'function' ? next(getView()) : next, true);\n }, [write, getView]);\n const setViewFromInput = useCallback((next: View) => { write(next, false); }, [write]);\n\n const subscribeView = useCallback((fn: (v: View) => void) => {\n viewSubsRef.current.add(fn);\n return () => { viewSubsRef.current.delete(fn); };\n }, []);\n\n const controlledMovedRef = useRef(false);\n // A closure over this render's prop, not a ref read: the owner calls it\n // from the same render's insertion effect.\n const adoptControlled = (): void => {\n if (!controlledView) return;\n controlledMovedRef.current ||= !sameView(viewRef.current, controlledView);\n viewRef.current = controlledView;\n };\n const announceControlled = useCallback(() => {\n if (!controlledMovedRef.current) return;\n controlledMovedRef.current = false;\n for (const fn of viewSubsRef.current) fn(viewRef.current);\n }, []);\n const clearSubscribers = useCallback(() => { viewSubsRef.current.clear(); }, []);\n\n return {\n viewRef, controlled: controlledView, setView, setViewFromInput, getView, subscribeView,\n adoptControlled, announceControlled, clearSubscribers,\n };\n}\n"],"mappings":";;;;;;;;;;;;AA4EA,IAAM,WAAiB;CAAE,GAAG;CAAG,GAAG;CAAG,OAAO;EAAE,GAAG;EAAG,GAAG;CAAE;AAAE;AAE3D,SAAgB,cAAc,MAA0C;CACtE,MAAM,EAAE,MAAM,UAAU,aAAa,cAAc,YAAY,MAAM,kBAAkB;CACvF,MAAM,UAAU,OAAO,aAAa,aAAa,WAAW;CAC5D,MAAM,iBAAiB,aAAa,UAAa,UAAU,SAAY,cAAc,QAAgB;CAGrG,MAAM,UAAU,OAAa,kBAAkB,cAAc,eAAe,QAAQ,CAAC;CACrF,MAAM,cAAc,uBAA+B,IAAI,IAAI,CAAC;CAC5D,MAAM,OAAO,UAAU;EACrB,YAAY,aAAa;EAAW;EAAS;EAAc;EAAY;EAAM;EAC7E,IAAI,KAAK,gBAAgB;CAC3B,CAAC;CACD,MAAM,sBAAsB,OAAO,KAAK;CAExC,MAAM,UAAU,kBAAwB;EACtC,MAAM,QAAQ,KAAK,QAAQ;EAC3B,OAAO,QAAQ,cAAc,MAAM,CAAC,IAAI,QAAQ;CAClD,GAAG,CAAC,IAAI,CAAC;CAET,MAAM,QAAQ,aAAa,MAAY,eAA8B;EACnE,MAAM,EACJ,YAAY,SAAS,cAAc,SAAS,YAAY,QAAQ,MAAM,MAAM,eAAe,WACzF,KAAK;EACT,MAAM,QAAQ,cAAc,IAAI;EAChC,MAAM,UAAU,SAAS,UAAU,OAAO,QAAQ,KAAK,CAAC,IAAI;EAC5D,IAAI,YAAY;GAGd,IAAI,cAAc,CAAC,oBAAoB,SAAS;IAC9C,oBAAoB,UAAU;IAC9B,MAAM,CAAC,MAAM,MAAM,KAAK,QAAQ,OAAO,QAAQ,CAAC,OAAO,aAAa,IAAI,CAAC,QAAQ,cAAc;IAC/F,QAAQ,KAAK,UACT,4EAA4E,KAAK,wCAAwC,GAAG,4EAC5H,gEAAgE,KAAK,uBAAuB,GAAG,6FAA6F;GAClM;GACA,UAAU,OAAO;GAEjB,IAAI,SAAS,OAAO;GACpB;EACF;EACA,QAAQ,UAAU;EAClB,KAAK,MAAM,MAAM,YAAY,SAAS,GAAG,OAAO;EAChD,UAAU,OAAO;EACjB,OAAO;CACT,GAAG,CAAC,IAAI,CAAC;CAET,MAAM,UAAU,aAAa,SAA2C;EACtE,MAAM,OAAO,SAAS,aAAa,KAAK,QAAQ,CAAC,IAAI,MAAM,IAAI;CACjE,GAAG,CAAC,OAAO,OAAO,CAAC;CACnB,MAAM,mBAAmB,aAAa,SAAe;EAAE,MAAM,MAAM,KAAK;CAAG,GAAG,CAAC,KAAK,CAAC;CAErF,MAAM,gBAAgB,aAAa,OAA0B;EAC3D,YAAY,QAAQ,IAAI,EAAE;EAC1B,aAAa;GAAE,YAAY,QAAQ,OAAO,EAAE;EAAG;CACjD,GAAG,CAAC,CAAC;CAEL,MAAM,qBAAqB,OAAO,KAAK;CAGvC,MAAM,wBAA8B;EAClC,IAAI,CAAC,gBAAgB;EACrB,mBAAmB,YAAY,CAAC,SAAS,QAAQ,SAAS,cAAc;EACxE,QAAQ,UAAU;CACpB;CAQA,OAAO;EACL;EAAS,YAAY;EAAgB;EAAS;EAAkB;EAAS;EACzE;EAAiB,oBATQ,kBAAkB;GAC3C,IAAI,CAAC,mBAAmB,SAAS;GACjC,mBAAmB,UAAU;GAC7B,KAAK,MAAM,MAAM,YAAY,SAAS,GAAG,QAAQ,OAAO;EAC1D,GAAG,CAAC,CAKe;EAAoB,kBAJd,kBAAkB;GAAE,YAAY,QAAQ,MAAM;EAAG,GAAG,CAAC,CAIvC;CACvC;AACF"}
|
|
@@ -32,7 +32,7 @@ function useSlotLayers(layersMap, tools, backgroundFill, decorationLayer) {
|
|
|
32
32
|
]);
|
|
33
33
|
}
|
|
34
34
|
/**
|
|
35
|
-
* The full stack the canvas paints: its slot layers, then registered views, the debug overlay,
|
|
35
|
+
* The full stack the canvas paints: its slot layers, then root view markers, registered views, the debug overlay,
|
|
36
36
|
* externally registered layers, and the cursor. Every layer that can change on its own
|
|
37
37
|
* repaints the canvas through `requestRedraw`.
|
|
38
38
|
*/
|
|
@@ -40,7 +40,11 @@ function useComposedLayers(layers, above, requestRedraw) {
|
|
|
40
40
|
const { viewRegistry, debugOverlay, extrasRef, extrasVersion, cursorLayer } = above;
|
|
41
41
|
const viewRegistryVersion = useSyncExternalStore(useCallback((cb) => viewRegistry?.subscribe(cb) ?? (() => {}), [viewRegistry]), () => viewRegistry?.getVersion() ?? 0, () => 0);
|
|
42
42
|
const composed = useMemo(() => {
|
|
43
|
-
const withViews = viewRegistry ? [
|
|
43
|
+
const withViews = viewRegistry ? [
|
|
44
|
+
...layers,
|
|
45
|
+
...viewRegistry.markerLayers(null),
|
|
46
|
+
...viewRegistry.list().filter((r) => r.paint).map((r) => r.layer)
|
|
47
|
+
] : layers;
|
|
44
48
|
return [
|
|
45
49
|
...debugOverlay ? [...withViews, debugOverlay] : withViews,
|
|
46
50
|
...extrasRef.current,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useLayerStack.js","names":[],"sources":["../../src/canvas/useLayerStack.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useSyncExternalStore } from 'react';\nimport type { RenderLayer } from 'core/layers/render';\nimport type { Paint } from '@weasel-js/paint';\nimport { createBackgroundFillLayer } from 'core/layers/backgroundFill';\nimport { composeOrderedLayers, placeToolOverlays } from './layerOrder';\nimport { STANDARD_SLOTS, isCustomEntry } from './layerSlots';\nimport type { CanvasProps } from './canvasProps';\nimport type { ViewRegistry } from './viewRegistry';\n\n/** The `layers` prop's slots and custom entries in draw order, with the background fill beneath,\n * the decoration layer above, and the active tool's overlays placed among them. */\nexport function useSlotLayers(\n layersMap: CanvasProps<unknown>['layers'],\n tools: CanvasProps<unknown>['tools'],\n backgroundFill: Paint | undefined,\n decorationLayer: RenderLayer<unknown> | undefined,\n): RenderLayer<unknown>[] {\n const backgroundLayer = useMemo(\n () => (backgroundFill ? createBackgroundFillLayer(backgroundFill) : undefined),\n [backgroundFill],\n );\n\n return useMemo<RenderLayer<unknown>[]>(() => {\n const standardLayers: Partial<\n Record<(typeof STANDARD_SLOTS)[number], RenderLayer<unknown>>\n > = {};\n for (const slot of ['grid', 'cellHighlight', 'selectionOverlay'] as const) {\n const entry = layersMap[slot];\n if (isCustomEntry(entry)) standardLayers[slot] = entry.layer;\n }\n const out: RenderLayer<unknown>[] = composeOrderedLayers(\n decorationLayer ? { ...layersMap, decorationLayer: { layer: decorationLayer } } : layersMap,\n standardLayers, layersMap.scene?.layers, backgroundLayer,\n );\n if (tools) {\n placeToolOverlays(out, standardLayers.selectionOverlay, tools.getActiveOverlays);\n }\n return out;\n }, [layersMap, tools, backgroundLayer, decorationLayer]);\n}\n\n/** What the canvas paints on top of its slot layers. */\nexport interface StackAbove {\n viewRegistry: ViewRegistry | null;\n debugOverlay: RenderLayer<unknown> | null | undefined;\n /** Registered layers; re-read whenever `extrasVersion` changes. */\n extrasRef: { readonly current: ReadonlySet<RenderLayer<unknown>> };\n extrasVersion: number;\n cursorLayer: RenderLayer<unknown>;\n}\n\n/**\n * The full stack the canvas paints: its slot layers, then registered views, the debug overlay,\n * externally registered layers, and the cursor. Every layer that can change on its own\n * repaints the canvas through `requestRedraw`.\n */\nexport function useComposedLayers(\n layers: readonly RenderLayer<unknown>[],\n above: StackAbove,\n requestRedraw: () => void,\n): RenderLayer<unknown>[] {\n const { viewRegistry, debugOverlay, extrasRef, extrasVersion, cursorLayer } = above;\n const viewRegistryVersion = useSyncExternalStore(\n useCallback((cb: () => void) => viewRegistry?.subscribe(cb) ?? (() => {}), [viewRegistry]),\n () => viewRegistry?.getVersion() ?? 0,\n () => 0,\n );\n\n const composed = useMemo(() => {\n // Views paint through the surface's own stack, so they sit above it and\n // below both the debug overlay and externally-registered layers.\n const withViews = viewRegistry\n ? [...layers
|
|
1
|
+
{"version":3,"file":"useLayerStack.js","names":[],"sources":["../../src/canvas/useLayerStack.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useSyncExternalStore } from 'react';\nimport type { RenderLayer } from 'core/layers/render';\nimport type { Paint } from '@weasel-js/paint';\nimport { createBackgroundFillLayer } from 'core/layers/backgroundFill';\nimport { composeOrderedLayers, placeToolOverlays } from './layerOrder';\nimport { STANDARD_SLOTS, isCustomEntry } from './layerSlots';\nimport type { CanvasProps } from './canvasProps';\nimport type { ViewRegistry } from './viewRegistry';\n\n/** The `layers` prop's slots and custom entries in draw order, with the background fill beneath,\n * the decoration layer above, and the active tool's overlays placed among them. */\nexport function useSlotLayers(\n layersMap: CanvasProps<unknown>['layers'],\n tools: CanvasProps<unknown>['tools'],\n backgroundFill: Paint | undefined,\n decorationLayer: RenderLayer<unknown> | undefined,\n): RenderLayer<unknown>[] {\n const backgroundLayer = useMemo(\n () => (backgroundFill ? createBackgroundFillLayer(backgroundFill) : undefined),\n [backgroundFill],\n );\n\n return useMemo<RenderLayer<unknown>[]>(() => {\n const standardLayers: Partial<\n Record<(typeof STANDARD_SLOTS)[number], RenderLayer<unknown>>\n > = {};\n for (const slot of ['grid', 'cellHighlight', 'selectionOverlay'] as const) {\n const entry = layersMap[slot];\n if (isCustomEntry(entry)) standardLayers[slot] = entry.layer;\n }\n const out: RenderLayer<unknown>[] = composeOrderedLayers(\n decorationLayer ? { ...layersMap, decorationLayer: { layer: decorationLayer } } : layersMap,\n standardLayers, layersMap.scene?.layers, backgroundLayer,\n );\n if (tools) {\n placeToolOverlays(out, standardLayers.selectionOverlay, tools.getActiveOverlays);\n }\n return out;\n }, [layersMap, tools, backgroundLayer, decorationLayer]);\n}\n\n/** What the canvas paints on top of its slot layers. */\nexport interface StackAbove {\n viewRegistry: ViewRegistry | null;\n debugOverlay: RenderLayer<unknown> | null | undefined;\n /** Registered layers; re-read whenever `extrasVersion` changes. */\n extrasRef: { readonly current: ReadonlySet<RenderLayer<unknown>> };\n extrasVersion: number;\n cursorLayer: RenderLayer<unknown>;\n}\n\n/**\n * The full stack the canvas paints: its slot layers, then root view markers, registered views, the debug overlay,\n * externally registered layers, and the cursor. Every layer that can change on its own\n * repaints the canvas through `requestRedraw`.\n */\nexport function useComposedLayers(\n layers: readonly RenderLayer<unknown>[],\n above: StackAbove,\n requestRedraw: () => void,\n): RenderLayer<unknown>[] {\n const { viewRegistry, debugOverlay, extrasRef, extrasVersion, cursorLayer } = above;\n const viewRegistryVersion = useSyncExternalStore(\n useCallback((cb: () => void) => viewRegistry?.subscribe(cb) ?? (() => {}), [viewRegistry]),\n () => viewRegistry?.getVersion() ?? 0,\n () => 0,\n );\n\n const composed = useMemo(() => {\n // Views paint through the surface's own stack, so they sit above it and\n // below both the debug overlay and externally-registered layers. Root\n // markers sit under the views, as a view's own markers sit under its nested ones.\n const withViews = viewRegistry\n ? [\n ...layers,\n ...viewRegistry.markerLayers(null),\n ...viewRegistry.list().filter((r) => r.paint).map((r) => r.layer as RenderLayer<unknown>),\n ]\n : layers;\n const base = debugOverlay ? [...withViews, debugOverlay] : withViews;\n // The cursor goes last: it is the one thing that is always in front of\n // everything, including a consumer's own registered layers.\n return [...base, ...extrasRef.current, cursorLayer];\n // extrasVersion drives re-reads of extrasRef when layers are registered/detached;\n // viewRegistryVersion does the same for registered views.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [layers, debugOverlay, extrasVersion, viewRegistry, viewRegistryVersion,\n cursorLayer]);\n\n useEffect(() => {\n const redraw = (): void => { requestRedraw(); };\n const offs: (() => void)[] = [];\n for (const layer of composed) if (layer.subscribe) offs.push(layer.subscribe(redraw));\n return () => { for (const off of offs) off(); };\n }, [composed, requestRedraw]);\n\n return composed;\n}\n"],"mappings":";;;;;;;;AAWA,SAAgB,cACd,WACA,OACA,gBACA,iBACwB;CACxB,MAAM,kBAAkB,cACf,iBAAiB,0BAA0B,cAAc,IAAI,QACpE,CAAC,cAAc,CACjB;CAEA,OAAO,cAAsC;EAC3C,MAAM,iBAEF,CAAC;EACL,KAAK,MAAM,QAAQ;GAAC;GAAQ;GAAiB;EAAkB,GAAY;GACzE,MAAM,QAAQ,UAAU;GACxB,IAAI,cAAc,KAAK,GAAG,eAAe,QAAQ,MAAM;EACzD;EACA,MAAM,MAA8B,qBAClC,kBAAkB;GAAE,GAAG;GAAW,iBAAiB,EAAE,OAAO,gBAAgB;EAAE,IAAI,WAClF,gBAAgB,UAAU,OAAO,QAAQ,eAC3C;EACA,IAAI,OACF,kBAAkB,KAAK,eAAe,kBAAkB,MAAM,iBAAiB;EAEjF,OAAO;CACT,GAAG;EAAC;EAAW;EAAO;EAAiB;CAAe,CAAC;AACzD;;;;;;AAiBA,SAAgB,kBACd,QACA,OACA,eACwB;CACxB,MAAM,EAAE,cAAc,cAAc,WAAW,eAAe,gBAAgB;CAC9E,MAAM,sBAAsB,qBAC1B,aAAa,OAAmB,cAAc,UAAU,EAAE,YAAY,CAAC,IAAI,CAAC,YAAY,CAAC,SACnF,cAAc,WAAW,KAAK,SAC9B,CACR;CAEA,MAAM,WAAW,cAAc;EAI7B,MAAM,YAAY,eACd;GACE,GAAG;GACH,GAAG,aAAa,aAAa,IAAI;GACjC,GAAG,aAAa,KAAK,CAAC,CAAC,QAAQ,MAAM,EAAE,KAAK,CAAC,CAAC,KAAK,MAAM,EAAE,KAA6B;EAC1F,IACA;EAIJ,OAAO;GAAC,GAHK,eAAe,CAAC,GAAG,WAAW,YAAY,IAAI;GAG1C,GAAG,UAAU;GAAS;EAAW;CAIpD,GAAG;EAAC;EAAQ;EAAc;EAAe;EAAc;EACnD;CAAW,CAAC;CAEhB,gBAAgB;EACd,MAAM,eAAqB;GAAE,cAAc;EAAG;EAC9C,MAAM,OAAuB,CAAC;EAC9B,KAAK,MAAM,SAAS,UAAU,IAAI,MAAM,WAAW,KAAK,KAAK,MAAM,UAAU,MAAM,CAAC;EACpF,aAAa;GAAE,KAAK,MAAM,OAAO,MAAM,IAAI;EAAG;CAChD,GAAG,CAAC,UAAU,aAAa,CAAC;CAE5B,OAAO;AACT"}
|
|
@@ -7,18 +7,20 @@ import { useMemo } from "react";
|
|
|
7
7
|
* the adapter keeps its identity across renders unless one of them changes.
|
|
8
8
|
*/
|
|
9
9
|
function useSceneAdapter(scene, options = {}) {
|
|
10
|
-
const { selection, commitInsert, insertLayer, poseDescriptor } = options;
|
|
10
|
+
const { selection, commitInsert, insertLayer, poseDescriptor, pasteInto } = options;
|
|
11
11
|
return useMemo(() => sceneToAdapter(scene, {
|
|
12
12
|
selection,
|
|
13
13
|
commitInsert,
|
|
14
14
|
insertLayer,
|
|
15
|
-
poseDescriptor
|
|
15
|
+
poseDescriptor,
|
|
16
|
+
...pasteInto ? { pasteInto } : {}
|
|
16
17
|
}), [
|
|
17
18
|
scene,
|
|
18
19
|
selection,
|
|
19
20
|
commitInsert,
|
|
20
21
|
insertLayer,
|
|
21
|
-
poseDescriptor
|
|
22
|
+
poseDescriptor,
|
|
23
|
+
pasteInto
|
|
22
24
|
]);
|
|
23
25
|
}
|
|
24
26
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useSceneAdapter.js","names":[],"sources":["../../src/canvas/useSceneAdapter.ts"],"sourcesContent":["import { useMemo } from 'react';\nimport type { Scene } from 'core/scene/types';\nimport {\n sceneToAdapter,\n type SceneCanvasAdapter,\n type SceneToAdapterOptions,\n} from './sceneAdapter';\n\n/**\n * React-hook wrapper around `sceneToAdapter`. Memoizes on every option, so\n * the adapter keeps its identity across renders unless one of them changes.\n */\nexport function useSceneAdapter<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n options: SceneToAdapterOptions<TData, TLayer, TPose> = {},\n): SceneCanvasAdapter<TData, TLayer, TPose> {\n const {\n selection, commitInsert, insertLayer, poseDescriptor,\n } = options;\n return useMemo(\n () => sceneToAdapter(scene, {\n selection, commitInsert, insertLayer, poseDescriptor,\n }),\n [scene, selection, commitInsert, insertLayer, poseDescriptor],\n );\n}\n"],"mappings":";;;;;;;;AAYA,SAAgB,gBACd,OACA,UAAuD,CAAC,GACd;CAC1C,MAAM,EACJ,WAAW,cAAc,aAAa,
|
|
1
|
+
{"version":3,"file":"useSceneAdapter.js","names":[],"sources":["../../src/canvas/useSceneAdapter.ts"],"sourcesContent":["import { useMemo } from 'react';\nimport type { Scene } from 'core/scene/types';\nimport {\n sceneToAdapter,\n type SceneCanvasAdapter,\n type SceneToAdapterOptions,\n} from './sceneAdapter';\n\n/**\n * React-hook wrapper around `sceneToAdapter`. Memoizes on every option, so\n * the adapter keeps its identity across renders unless one of them changes.\n */\nexport function useSceneAdapter<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n options: SceneToAdapterOptions<TData, TLayer, TPose> = {},\n): SceneCanvasAdapter<TData, TLayer, TPose> {\n const {\n selection, commitInsert, insertLayer, poseDescriptor, pasteInto,\n } = options;\n return useMemo(\n () => sceneToAdapter(scene, {\n selection, commitInsert, insertLayer, poseDescriptor, ...(pasteInto ? { pasteInto } : {}),\n }),\n [scene, selection, commitInsert, insertLayer, poseDescriptor, pasteInto],\n );\n}\n"],"mappings":";;;;;;;;AAYA,SAAgB,gBACd,OACA,UAAuD,CAAC,GACd;CAC1C,MAAM,EACJ,WAAW,cAAc,aAAa,gBAAgB,cACpD;CACJ,OAAO,cACC,eAAe,OAAO;EAC1B;EAAW;EAAc;EAAa;EAAgB,GAAI,YAAY,EAAE,UAAU,IAAI,CAAC;CACzF,CAAC,GACD;EAAC;EAAO;EAAW;EAAc;EAAa;EAAgB;CAAS,CACzE;AACF"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { normalizeView } from "../core/viewport/view.js";
|
|
2
|
+
import { isRectAim, rectAim, viewForAim } from "../features/viewports/aim.js";
|
|
3
|
+
import { viewportWorldRect } from "../core/viewport/viewportWorldRect.js";
|
|
4
|
+
import { useCanvasView } from "./useCanvasView.js";
|
|
5
|
+
import { sizeOf } from "./useViewNesting.js";
|
|
6
|
+
import { IDENTITY_VIEW, UNMEASURED_DIMS } from "./viewRegistry.js";
|
|
7
|
+
import { useCallback } from "react";
|
|
8
|
+
import { useLatest } from "@weasel-js/react";
|
|
9
|
+
|
|
10
|
+
//#region src/canvas/useViewAim.ts
|
|
11
|
+
/**
|
|
12
|
+
* A `<CanvasView>`'s camera and its aim, whichever of the two the view holds.
|
|
13
|
+
* A camera-held view answers its aim from its camera; an aim-held one derives
|
|
14
|
+
* its camera from the aim, through the same thunk a derived `view` uses.
|
|
15
|
+
*/
|
|
16
|
+
/** `held` carried by the camera move that turns the world rect `from` into `to`: panned and scaled
|
|
17
|
+
* with it, so the aim keeps its own shape rather than taking the frame's. */
|
|
18
|
+
function carried(held, from, to) {
|
|
19
|
+
const kx = from.width > 0 ? to.width / from.width : 1;
|
|
20
|
+
const ky = from.height > 0 ? to.height / from.height : 1;
|
|
21
|
+
return {
|
|
22
|
+
x: to.x + (held.x - from.x) * kx,
|
|
23
|
+
y: to.y + (held.y - from.y) * ky,
|
|
24
|
+
width: held.width * kx,
|
|
25
|
+
height: held.height * ky
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function useViewAim(args) {
|
|
29
|
+
const { props, id, registry, derivedAt, rectAt, rectNow } = args;
|
|
30
|
+
const { view, defaultView, onViewChange, viewBounds, aim: aimProp, onAimChange } = props;
|
|
31
|
+
const held = aimProp !== void 0 ? "aim" : "camera";
|
|
32
|
+
const live = useLatest({
|
|
33
|
+
view,
|
|
34
|
+
onViewChange,
|
|
35
|
+
aimProp,
|
|
36
|
+
onAimChange
|
|
37
|
+
});
|
|
38
|
+
/** The rect an aim-held view holds, for a surface frame. */
|
|
39
|
+
const heldAt = useCallback((outer, dims) => {
|
|
40
|
+
const a = live.current.aimProp;
|
|
41
|
+
return typeof a === "function" ? derivedAt(a, outer, dims) : a;
|
|
42
|
+
}, [live, derivedAt]);
|
|
43
|
+
/** The camera derived for a surface frame, or `undefined` for a camera the view keeps. */
|
|
44
|
+
const derivedCamera = useCallback((outer, dims) => {
|
|
45
|
+
const rect = heldAt(outer, dims);
|
|
46
|
+
if (rect) return viewForAim(rect, sizeOf(rectAt(outer, dims)), "contain");
|
|
47
|
+
const v = live.current.view;
|
|
48
|
+
return typeof v === "function" ? normalizeView(derivedAt(v, outer, dims)) : void 0;
|
|
49
|
+
}, [
|
|
50
|
+
live,
|
|
51
|
+
heldAt,
|
|
52
|
+
rectAt,
|
|
53
|
+
derivedAt
|
|
54
|
+
]);
|
|
55
|
+
const surfaceFrame = useCallback(() => {
|
|
56
|
+
const surface = registry?.surface();
|
|
57
|
+
return [surface?.view() ?? IDENTITY_VIEW, surface?.dims() ?? UNMEASURED_DIMS];
|
|
58
|
+
}, [registry]);
|
|
59
|
+
/** A camera write on an aim-held view, reported as the held rect it carries. */
|
|
60
|
+
const reportWrite = useCallback((next) => {
|
|
61
|
+
const frame = surfaceFrame();
|
|
62
|
+
const held = heldAt(...frame);
|
|
63
|
+
const current = derivedCamera(...frame);
|
|
64
|
+
if (!held || !current) return;
|
|
65
|
+
const size = sizeOf(rectAt(...frame));
|
|
66
|
+
live.current.onAimChange?.(carried(held, viewportWorldRect(current, size), viewportWorldRect(next, size)));
|
|
67
|
+
}, [
|
|
68
|
+
live,
|
|
69
|
+
surfaceFrame,
|
|
70
|
+
heldAt,
|
|
71
|
+
derivedCamera,
|
|
72
|
+
rectAt
|
|
73
|
+
]);
|
|
74
|
+
const state = useCanvasView({
|
|
75
|
+
view: held === "aim" || typeof view === "function" ? () => derivedCamera(...surfaceFrame()) : view,
|
|
76
|
+
defaultView,
|
|
77
|
+
onViewChange: held === "aim" ? onAimChange && reportWrite : onViewChange,
|
|
78
|
+
viewBounds,
|
|
79
|
+
dims: () => sizeOf(rectNow()),
|
|
80
|
+
requestRedraw: () => registry?.surface()?.requestRedraw(),
|
|
81
|
+
controlledBy: held === "aim" ? "aim" : "view"
|
|
82
|
+
});
|
|
83
|
+
const { getView, setViewFromInput } = state;
|
|
84
|
+
const aim = useCallback(() => {
|
|
85
|
+
const rect = heldAt(...surfaceFrame());
|
|
86
|
+
return rectAim(id, rect ?? viewportWorldRect(getView(), sizeOf(rectNow())));
|
|
87
|
+
}, [
|
|
88
|
+
id,
|
|
89
|
+
heldAt,
|
|
90
|
+
surfaceFrame,
|
|
91
|
+
getView,
|
|
92
|
+
rectNow
|
|
93
|
+
]);
|
|
94
|
+
const setAim = useCallback((next) => {
|
|
95
|
+
if (!isRectAim(next)) return false;
|
|
96
|
+
const { view: v, onViewChange: onView, aimProp: a, onAimChange: report } = live.current;
|
|
97
|
+
if (a === void 0) {
|
|
98
|
+
if (v !== void 0 && !onView) return false;
|
|
99
|
+
setViewFromInput(viewForAim(next.extent, sizeOf(rectNow()), "exact"));
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
report?.(next.extent);
|
|
103
|
+
return report !== void 0;
|
|
104
|
+
}, [
|
|
105
|
+
live,
|
|
106
|
+
setViewFromInput,
|
|
107
|
+
rectNow
|
|
108
|
+
]);
|
|
109
|
+
const cameraAt = useCallback((outer, dims) => derivedCamera(outer, dims) ?? getView(), [derivedCamera, getView]);
|
|
110
|
+
return {
|
|
111
|
+
...state,
|
|
112
|
+
held,
|
|
113
|
+
aim,
|
|
114
|
+
setAim,
|
|
115
|
+
cameraAt
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
//#endregion
|
|
120
|
+
export { useViewAim };
|
|
121
|
+
//# sourceMappingURL=useViewAim.js.map
|