@weasel-js/core 1.5.2 → 1.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,164 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.6.1
4
+
5
+ ### Patch Changes
6
+
7
+ - b209a8e: A feature installs from one entry. `SurfaceContribution` extends `Contribution` with `views` and `attach(api, deps)`, and `Contribution` gains `deps`; `<SceneCanvas ambient>` installs every role an entry declares and removes them with it. `mergeContributions` throws on a duplicate dep name or view id as well as a duplicate entry id.
8
+
9
+ Bindings can be scoped to views with `opts.views`; a binding that names the view an input landed in outranks bindings that do not. `InvocationCtx.viewId` and `RuleCtx.viewId` carry that view, layer `data.viewId` names the view a draw is for, and the `rootView` dep answers the surface camera from inside a view.
10
+
11
+ `createMinimapContribution` puts a minimap inside a canvas, with a linked crosshair, and `createLinkedCursorContribution` draws the crosshair alone. `<MinimapCanvas>` now runs on a dispatcher, publishes its pointer, and takes an `id`.
12
+
13
+ Breaking: `PointerContextValue` is a store — `get`, `set`, `subscribe`, `getVersion` — in place of `pointerRef`, and `PointerWorldPos` carries `viewId`. `usePointerPosition()` follows it. `useHud`'s ref is optional; `useHudContribution(hud, options)` attaches the HUD as well as routing its input.
14
+ - 7683659: A labkit camera now routes through weasel's gesture dispatcher. `<CanvasStack>` and `<Stage>` pan on a drag, zoom on the wheel and report a tap through `CameraInput`, which drives core's `viewport.dragPan` and `viewport.zoom` over the camera as a weasel `View` (`toCameraView` / `fromCameraView`). The loupe joins the same dispatcher, taking the wheel while its lens is up. A trial publishes its pointer, and `RenderContext.trial.pointer` is that store; `<LinkedCursor>` draws the crosshair on the stage while the pointer is over another view.
15
+
16
+ Breaking: `usePanZoom` is removed. `PointerContextProvider` takes an optional `store`, and core exports `crosshairRects`.
17
+ - Updated dependencies [b209a8e]
18
+ - @weasel-js/routing@1.6.1
19
+ - @weasel-js/cursor@1.6.1
20
+ - @weasel-js/font@1.6.1
21
+ - @weasel-js/geom@1.6.1
22
+ - @weasel-js/gestures@1.6.1
23
+ - @weasel-js/history@1.6.1
24
+ - @weasel-js/paint@1.6.1
25
+ - @weasel-js/text@1.6.1
26
+
27
+ ## 1.6.0
28
+
29
+ ### Patch Changes
30
+
31
+ - 16c0da2: Kit actions can now fill a whole editor toolbar from the registry.
32
+
33
+ - `Action.variants` lists the separate things a parametric action does, each with its own label and params. `flip` declares Flip Horizontal and Flip Vertical; `reorder.forward` and `reorder.backward` declare their one-step and all-the-way forms. `actionItems(action)` expands an action into the entries a bar, menu or palette shows: one per variant, or the action itself. An action without an immediate invoker gets none, because `trigger` cannot start a drag.
34
+ - `actionShortcuts(action, params)` returns only the shortcuts whose binding passes those params, so each variant shows its own key.
35
+ - `ActionBar` renders one button per entry and triggers it with that entry's params. `icons` and `labels` are now keyed by entry key (`flip:y`, `reorder.forward:extreme`), which is still the action id for an action without variants. `enabled` is evaluated with the deps the action declares in `requires`, not a fixed set of six, and a tooltip without a `shortcut` override now shows the binding's key.
36
+ - New groups: `history` (undo, redo), `clipboard` (cut, copy, paste), `edit` (duplicate, delete), `structure` (group, ungroup) and `flip`.
37
+ - New `clipboard.paste` action, which calls the `clipboard` dep's `paste()`. It has no key binding, because Cmd/Ctrl+V already arrives as a paste event.
38
+ - `enabled` now follows the current state: undo and redo follow the history stacks, `delete` and `group` need a selection, `ungroup` needs a selected container, and `clipboard.paste` needs a non-empty clipboard. `delete`, `group` and `ungroup` used to report enabled unconditionally.
39
+ - Align actions now register left, center, right, top, middle, bottom.
40
+ - `buildDepsFromRequires` is re-exported from `@weasel-js/core`.
41
+ - b8ebef6: The eight glyphs the align and distribute actions ship are now exported from `@weasel-js/core` and re-exported from `@weasel-js/ui`, beside the Pathfinder and edit-action icons: `AlignLeftIcon`, `AlignCenterXIcon`, `AlignRightIcon`, `AlignTopIcon`, `AlignCenterYIcon`, `AlignBottomIcon`, `DistributeHorizontalIcon` and `DistributeVerticalIcon`. They are the same components the actions draw, so a consumer can render one outside an `<ActionBar>` without authoring its own.
42
+ - c373af4: Color ramps can interpolate in OKLab, HSL, sRGB and linear sRGB as well as OKLCH. `@weasel-js/ui` adds `colorRamp(from, to, steps, options)` and `rampColor(from, to, t, options)`, whose `space` option picks the space (default `'oklch'`), `hue` picks the shorter or longer arc in the polar spaces, and `chroma` applies a `ChromaCurve` after interpolation in any space. Underneath, `@weasel-js/paint` (re-exported from core) adds `interpolateSrgb` with the `ColorInterpolationSpace` and `HueInterpolation` types, plus float-precision `srgbToLinear`, `linearToSrgb`, `linearSrgbToOklab`, `oklabToLinearSrgb`, `srgbToHsl` and `hslToSrgb`. The forge story `ui/Color/ColorRamp` shows the same endpoints ramped in each space.
43
+ - bfe6a4f: `contrastLineColor(background, strength)` derives a line color that reads against an arbitrary background — a grid or a rule drawn over a page whose color the document picks, where theme tokens follow the chrome instead. It moves the background `strength` in OKLab lightness away from its nearer end, darker over light and lighter over dark, keeping its hue, so dark and tinted pages get lines that show. Re-exported from `@weasel-js/core`.
44
+ - 6857b4d: `DEFAULT_PALETTE` is now a `Palette` of five named sRGB entries rather than a `string[]`, which breaks any code indexing it as an array. `cycleFill(seq, palette?, fallback?)` gives the `seq`th entry as hex, wrapping, and is what the built-in shape tools and the `insert` dep now call. `@weasel-js/paint` gains `hexToColorLiteral` for `#rrggbb` and `#rrggbbaa`.
45
+ - bbaefca: Under a composing `poseComposition`, a container whose pose derives from its children (`dependsOn: 'children'` with a `derivePose`, as `groupAction` mints under the default strategy) is now an envelope rather than a frame: its children are stored in the same frame it is, and the render walk, `getWorldPose`, picking and the actions' world/local conversions pass over it. Before, its derived pose was folded in as the children's frame, which moved every child by its own offset. `unionOfChildren` needs no change and is right under any strategy. `definesFrame(node)` is exported, and `PoseAdapter` takes an optional `definesFrame(id)` so a hand-built adapter can say the same to `composeWorldPose` and `rebaseLocalPose`. Nothing changes without a composing strategy.
46
+
47
+ `moveAction`'s translate-only drag and commit are now right under a composing strategy. Dragging a frame container no longer also translates its descendants, which moved them twice; they ride the frame. A node stored under a turned frame now moves the way the pointer went, instead of by the world drag applied in its frame's rotated axes.
48
+
49
+ Copy and paste now keep a container's `dependsOn: 'children'` and `derivePose`, so a pasted group still tracks its members, under any strategy. Under a composing strategy, `snapshotSelection` also captures in world coordinates any node whose frame is not part of the copy, and `commitPaste` no longer offsets nodes inside a pasted frame a second time.
50
+ - 0cf6a0d: The clipboard, duplicate, group, ungroup, reorder and flip actions now ship their own icons, so `<ActionBar group="clipboard" />` and its siblings draw glyphs with no `icons` map. Each reorder and flip variant carries its own glyph (Bring Forward / Bring to Front, Send Backward / Send to Back, Flip Horizontal / Flip Vertical). The twelve glyphs are exported from `@weasel-js/core` and `@weasel-js/ui` as `CutIcon`, `CopyIcon`, `PasteIcon`, `DuplicateIcon`, `GroupIcon`, `UngroupIcon`, `BringForwardIcon`, `BringToFrontIcon`, `SendBackwardIcon`, `SendToBackIcon`, `FlipXIcon` and `FlipYIcon`, in the same 20×20 `currentColor` register as the Pathfinder icons. An `icons` entry still overrides them.
51
+ - 811abcd: A registered program's struct uniforms now get locations. `uniform Light
52
+ u_lights[2];` is looked up as `u_lights[0].pos`, `u_lights[0].r` and so on,
53
+ nested structs and array members included; before, only the bare name was
54
+ looked up, so every write to a struct member was dropped, with a warning only
55
+ in development.
56
+
57
+ Array sizes written as a `#define`, a top-level `const int`, a small integer
58
+ expression over those, or on the type (`uniform float[2] u_t;`) now resolve;
59
+ before, such a uniform got no locations at all. Uniforms inside comments are no
60
+ longer looked up.
61
+
62
+ A program recompiled after a restored WebGL context now looks up the uniforms
63
+ its own vertex shader declares, as `registerProgram` already did.
64
+ - 7c53d1a: The undo, redo and delete actions now ship their own icons, so `<ActionBar group="history" />` and `<ActionBar group="edit" />` draw glyphs with no `icons` map. `UndoIcon`, `RedoIcon` and `DeleteIcon` move into `@weasel-js/core`, which the actions need them in; `@weasel-js/ui` re-exports them under the same names with the same props, and `<Icon name="undo" />` draws the same glyph. Core also exports `ACTION_GLYPHS`, the three glyphs' SVG markup, which `ICON_PATHS` now points at.
65
+ - 5345efb: A `kit:image` node can crop and mirror its bitmap. `data.image` takes an
66
+ optional `source` — the part of the bitmap to draw into the pose rect, as
67
+ fractions of the bitmap's width and height — and optional `flipX` / `flipY`,
68
+ which mirror the drawn region within the rect without moving it. The painter
69
+ hands both to the renderer's existing `ImageDrawCommand` fields, so hit-testing
70
+ and the silhouette are unchanged. Existing image data draws as before.
71
+
72
+ `svgNodesToKitDrafts` now carries an `SvgImageNode`'s source rect and flips onto
73
+ `data.image` instead of dropping them, and the new `svgImageFromKit(image, pose)`
74
+ writes a `kit:image` leaf back as an `SvgImageNode`, so a cropped or flipped
75
+ image survives SVG → scene → SVG.
76
+ - 87fd8a8: Choose which layout container a drag lands in when several contain the drop point. `<SceneCanvas layoutDropTarget>` takes `'innermost'` (the default, and the behavior until now: the deepest container, ties to the one painted later), `'topmost'` (the container painted last, in the scene's render order across the whole tree) or `'region'` (only containers that declare a drop region). A layout strategy declares one with the new optional `dropRegion(container)`, returning a `Path` or a predicate in the container's local frame; a declared region replaces the container body as its hit area in every mode, and may reach past it. The drag-time reflow preview and the commit follow the same choice. New types: `LayoutDropTargetMode`, `DropRegion`.
77
+ - 6f14f6f: The pen joins paths. Finishing a path by clicking (or dragging on) another open path's endpoint now makes one node: the drawn path's anchors followed by the other path's, turned around when you land on its last anchor, with the other node deleted in the same undo step. The path being drawn keeps its identity — a continued node keeps its id and style, and a new path is minted like any other pen path.
78
+
79
+ Two optional additions make that one op batch: `EditAnchorsDep.editOps(id, worldPath, label)` returns the ops `applyEdit` would commit without applying them, and the pen adapter's `makeNode(pose)` builds the node `addNode` would insert. `<SceneCanvas>` supplies both. Without them the click places an anchor, as before.
80
+ - c1f82e2: The pen's curves now follow the handles you drag. Dragging while placing an anchor gives it an out-handle at the drag point and an in-handle mirrored through it, and each segment runs from its start anchor's out-handle to its end anchor's in-handle — as in Illustrator and Figma. Before, a segment's second control point was the mirror of the *previous* anchor's handle, which sat behind the start of the segment, and a dragged anchor never shaped the segment coming into it. The preview and the committed path both changed.
81
+
82
+ Alt held from the start of the drag leaves the anchor with no in-handle; Alt pressed part-way freezes the in-handle and moves only the out-handle. Dragging the endpoint of a path the pen picked up moves its out-handle only, leaving the existing segment into it alone. `PenAnchor.altBroken` now describes the anchor it is set on, not the one after it.
83
+ - 97561f1: Zoom the canvas on Safari's trackpad pinch
84
+
85
+ Safari reports a trackpad pinch as WebKit `gesturestart` / `gesturechange` /
86
+ `gestureend` events, and nothing listened for them, so the page zoomed instead
87
+ of the canvas. `useGestureDispatcher` now dispatches each `gesturechange` as a
88
+ new `pinch` gesture: `PinchSpec` (`{ kind: 'pinch', direction?: 'in' | 'out' }`),
89
+ `PinchEvent`, route-grammar name `pinch`, and `InvocationCtx.pinch`. Safari's
90
+ cumulative `scale` is turned into a per-sample step, and the focal point is
91
+ canvas-local like a wheel's. A new `pinch` entry in `DispatcherChannels` turns
92
+ the listeners off.
93
+
94
+ `viewport.zoom` binds it. Its wheel and pinch samples now share one path: each
95
+ becomes a scale factor about a focal point, so a pinch sample of 1.1 lands on
96
+ exactly the view a ctrl+wheel `deltaY` of -100 does.
97
+
98
+ Safari can send the same pinch as ctrl+wheel too. While a pinch some binding
99
+ has claimed is live, the dispatcher swallows ctrl+wheel (preventing its
100
+ default, dispatching nothing), so one pinch zooms once. When no binding claims
101
+ the pinch, the gesture events are left to the browser and ctrl+wheel reaches
102
+ its bindings as before.
103
+ - 89926b5: `<SceneCanvas>` now builds its adapter with `useSceneAdapter` and keeps the same adapter across renders unless one of its inputs changes; it used to build a new one on every render. Moving a container still moves its children, now through `sceneToAdapter`'s `cascadeContainerPose` rather than a second copy of that logic.
104
+
105
+ `useSceneAdapter` now passes `poseComposition` through to `sceneToAdapter`. It used to drop it, so the adapter it returned ignored the frame model. The undo entry `cascadeContainerPose` records for a container move is now labeled `move container` rather than `setPose`, the label `<SceneCanvas>` already used.
106
+ - 9f86dec: `<SceneCanvas selectionMode="none">` now blocks every selection write the canvas makes. Before, the adapter it hands its tools could still set the selection, and so could any op batch that selects its result, such as a paste or an ingest. `setSelection` on that adapter, and on the `selection` dep's `adapterMethods`, now does nothing in that mode. The consumer's own `SelectionApi`, passed as the `selection` prop or made with `useSelection({ scene })`, still writes, and the canvas draws what it holds.
107
+
108
+ `defaultCommitAdapter` takes an optional second argument, a `SelectionApi`'s `adapterMethods`. When it is passed, selection reads and writes go through it rather than the scene. Every built-in action now passes its `selection` dep.
109
+
110
+ The `CanvasSelectionMode` docs now say what each mode does. `'single'` is a click rule, not a cap: a marquee, lasso, select-all or paste can still select several nodes.
111
+ - 4074270: `ShapeKindIcon` draws the glyph for a shape kind — the one its insertion tool shows — and falls back to `UnknownIcon` for a kind the kit does not ship. The icon set gains `page` (`PageIcon`), a document page with a folded corner. Core now exports the `ShapeKind` type.
112
+ - debfd5d: An SVG image node (`data:image/svg+xml` source, or a URL ending in `.svg`) now stays sharp under zoom. The image cache re-rasterizes it at the size it is drawn, in power-of-two steps so a zoom gesture does not redraw it every frame, capped at the renderer's maximum texture size and 4096×4096 pixels. The previous raster keeps painting until the new one is ready, and its GL texture is freed when it is replaced. PNG, JPEG and other raster sources are unchanged.
113
+
114
+ New: `getImageBitmap(src, drawnAt?)` takes the size in device pixels an image is about to cover, `NodePaintCtx.pixelScale` carries device pixels per world unit to painters (`defaultDrawOne` fills it from the view and `devicePixelRatio`), and `isVectorImageSrc(src)` reports whether a source is treated as SVG.
115
+ - d975afa: `text-transform` for styled runs and text nodes
116
+
117
+ `StyledRun` and `TextStyle` gain `textTransform: 'none' | 'uppercase' |
118
+ 'lowercase' | 'capitalize'`, with CSS semantics. A run's value overrides the
119
+ node's, and `'none'` on a run turns an inherited transform off. Only what is
120
+ drawn changes: a run's `text` stays as authored, so carets, selections and
121
+ edits still address the source.
122
+
123
+ - Case mapping uses JavaScript's locale-independent full mappings, so `ß`
124
+ uppercases to `SS` and a word-final `Σ` lowercases to `ς`. `capitalize`
125
+ titlecases the first letter of each word (`dž` → `Dž`, `ß` → `Ss`) and leaves
126
+ the rest alone; word starts come from `Intl.Segmenter`, the same boundaries
127
+ browsers use, and are found across run boundaries.
128
+ - `resolveRuns` applies the transform, so `ResolvedRun.text` is the drawn
129
+ text. When a transform changes a length, the run carries `srcMap`: where
130
+ each drawn UTF-16 unit came from in the source. Layout reads each cell's
131
+ `srcIndex` / `srcEnd` off it, so both cells of an uppercased `ß` map to the
132
+ one source character, and `caretIndexAt` treats them as one stop.
133
+ - `transformRunTexts` is exported for callers laying text out themselves;
134
+ `layoutMarkdown` uses it.
135
+ - The range helpers (`applyStyleToRange`, `styleAtRange`,
136
+ `effectiveRangeStyle`) carry the new key, the text tool and the node's
137
+ Character properties offer it as "Case", and the edit overlay shows it with
138
+ CSS `text-transform` on the overlay and on each run span.
139
+ - `@weasel-js/svg` writes it as `style="text-transform:…"` on `<text>` and
140
+ `<tspan>` — it is a CSS property, not an SVG 1.1 presentation attribute — and
141
+ reads it back from either spelling or an ancestor.
142
+ - 62d8d7c: `useOngoingAction(actionId)` lets a UI control — a color picker, a slider, a swatch — drive an ongoing action the way a drag does: `input(params)` opens the action on the first call and moves it on the rest (the live preview), `commit(params?)` ends it as one undo entry, and `cancel()` drops it. A commit with nothing open is a whole edit on its own, which is what a click on a swatch is. An edit still open when the control unmounts or its action id changes is committed. It wraps `ActionsRegistry.begin`, whose begin-or-update-then-end bookkeeping every such control used to hand-roll around a ref; `SceneGradientHandles` now uses it.
143
+ - Updated dependencies [16c0da2]
144
+ - Updated dependencies [c373af4]
145
+ - Updated dependencies [bfe6a4f]
146
+ - Updated dependencies [6857b4d]
147
+ - Updated dependencies [b1c30bc]
148
+ - Updated dependencies [f792755]
149
+ - Updated dependencies [9aa63a1]
150
+ - Updated dependencies [97561f1]
151
+ - Updated dependencies [d975afa]
152
+ - Updated dependencies [62d8d7c]
153
+ - @weasel-js/routing@1.6.0
154
+ - @weasel-js/paint@1.6.0
155
+ - @weasel-js/text@1.6.0
156
+ - @weasel-js/gestures@1.6.0
157
+ - @weasel-js/cursor@1.6.0
158
+ - @weasel-js/font@1.6.0
159
+ - @weasel-js/geom@1.6.0
160
+ - @weasel-js/history@1.6.0
161
+
3
162
  ## 1.5.2
4
163
 
5
164
  ### Patch Changes
@@ -1,4 +1,5 @@
1
- import { P as PoseDescriptor, a as Path } from './poseDescriptor-PgfVKfa0.js';
1
+ import { P as Path } from './path-JEV2c5If.js';
2
+ import { P as PoseDescriptor } from './poseDescriptor-rZa9W5hJ.js';
2
3
 
3
4
  /** True for Path-shaped poses (`{kind: 'polygon' | 'rect'}`). Useful for
4
5
  * callers that need to fork between `pathPoseDescriptor` and
@@ -1,13 +1,15 @@
1
1
  import { GradStop, ColorSpace, TextureHandle, FillStyle, Stroke, ScreenLength } from '@weasel-js/paint';
2
2
  import { NodeId, Bounds, View, SelectionApi, ActionDeps, IngestItem, DragSample, Point2 } from '@weasel-js/routing';
3
- import { a as Path, P as PoseDescriptor } from './poseDescriptor-PgfVKfa0.js';
3
+ import { P as Path } from './path-JEV2c5If.js';
4
4
  import { ResolvedRun, TextStyle, TextVerticalAlign } from '@weasel-js/text';
5
5
  import { Mat3 } from '@weasel-js/geom';
6
+ import { ReactNode } from 'react';
6
7
  import * as _weasel_js_history from '@weasel-js/history';
7
8
  import { Op, History, SerializedHistory } from '@weasel-js/history';
8
- import { a as SceneAdapter, L as LayoutStrategy, I as InsertAdapter } from './types-BdaK9PcP.js';
9
+ import { a as SceneAdapter, L as LayoutStrategy, b as LayoutDropTargetMode, I as InsertAdapter } from './types-CxC8P6W0.js';
10
+ import { P as PoseDescriptor } from './poseDescriptor-rZa9W5hJ.js';
9
11
  import { ActiveToolContextValue } from '@weasel-js/routing/react';
10
- import { B as BoundsConstraint, P as PointSnapBehavior } from './types-BHGdrOcu.js';
12
+ import { B as BoundsConstraint, P as PointSnapBehavior } from './types-D_74YlWs.js';
11
13
 
12
14
  /**
13
15
  * Axis-aligned rectangle pose with optional rotation. The canonical pose
@@ -827,7 +829,8 @@ declare class GLTextureCache {
827
829
  *
828
830
  * Key: ImageBitmap (or pattern source object) identity (WeakMap) — lets GC
829
831
  * reclaim unreferenced bitmaps. The GL textures are NOT freed when the source
830
- * is gc'd; deferred to v2.
832
+ * is gc'd; a source's owner that knows it will never be drawn again frees them
833
+ * with {@link releaseImageSource}.
831
834
  *
832
835
  * Wrapping is set once at upload time per the `repetition` parameter:
833
836
  * - undefined / 'no-repeat' → CLAMP_TO_EDGE
@@ -844,6 +847,8 @@ type TexSource = ImageBitmap | ImageData | HTMLCanvasElement | HTMLImageElement;
844
847
  declare class GLImageCache {
845
848
  private readonly gl;
846
849
  private readonly minification;
850
+ /** This context's `MAX_TEXTURE_SIZE`. */
851
+ readonly maxTextureSide: number;
847
852
  private readonly map;
848
853
  /**
849
854
  * MAG_FILTER each texture currently carries, so a redundant write can be
@@ -869,6 +874,11 @@ declare class GLImageCache {
869
874
  * headless print/export path); bilinear-only minification undersamples
870
875
  * and produces moiré. */
871
876
  constructor(gl: WebGL2RenderingContext, minification?: ImageMinification);
877
+ /** Delete `key`'s texture, if it has one. */
878
+ release(key: object): void;
879
+ /** Stop answering {@link releaseImageSource} and {@link maxImageTextureSide}.
880
+ * Call when the context is disposed or lost. */
881
+ dispose(): void;
872
882
  upload(key: object, source: TexSource, repetition?: PatternRepetition): WebGLTexture;
873
883
  bind(key: object, unit: number): void;
874
884
  /** Set `key`'s MAG_FILTER, skipping the call when it already holds that
@@ -1764,65 +1774,6 @@ interface CullRect {
1764
1774
  */
1765
1775
  declare function cullDrawCommands(cmds: DrawCommand[], transform: GlMat3, rect: CullRect): DrawCommand[];
1766
1776
 
1767
- /** Options for stroke tessellation. */
1768
- interface StrokeOptions {
1769
- flattenTolerance?: number;
1770
- /**
1771
- * Shorten each open subpath by this much at its start / end, in the same
1772
- * world units as the path. Stroke markers use this so a filled head is not
1773
- * speared by its own line; the caller resolves the distance, because this
1774
- * layer knows nothing about the marker registry.
1775
- */
1776
- startInset?: number;
1777
- endInset?: number;
1778
- }
1779
- /** Resolve a stroke width to world units. A number is already world units;
1780
- * `{ px }` is screen pixels divided by the accumulated scale, so it holds its
1781
- * on-screen thickness as the view zooms. */
1782
- declare function resolveStrokeWidth(width: ScreenLength, scale: number): number;
1783
- /**
1784
- * Build a triangle-mesh ribbon from a stroked Path.
1785
- *
1786
- * Supports:
1787
- * - cap: 'butt' | 'round' | 'square'
1788
- * - join: 'miter' | 'round' | 'bevel'
1789
- * - center alignment directly; RectPath inner/outer alignment via a
1790
- * pre-shifted rect; PolygonPath inner/outer alignment via stencil at the
1791
- * renderer level
1792
- * - dash splitting
1793
- */
1794
- declare function tessellateStroke(path: Path, stroke: Stroke, opts?: StrokeOptions): Mesh;
1795
-
1796
- /**
1797
- * Effects that ship with the kit.
1798
- *
1799
- * Each is a function returning `Effect[]`, not a single `Effect`, because a
1800
- * separable kernel is genuinely two passes and hiding that behind one entry
1801
- * would make the cost invisible at the callsite:
1802
- *
1803
- * effects={[...blur({ radius: 4 }), ...vignette({ amount: 0.6 })]}
1804
- */
1805
-
1806
- /**
1807
- * Gaussian blur, as a horizontal pass followed by a vertical one.
1808
- *
1809
- * `radius` is in device pixels and is the distance of the outermost tap, not a
1810
- * standard deviation — 0 is a copy, and the falloff is the same nine-tap
1811
- * kernel at every radius, so a large one is a wide blur rather than a better
1812
- * one. Two passes at O(9) beat one at O(81) and look the same.
1813
- */
1814
- declare function blur({ radius }: {
1815
- radius: number;
1816
- }): Effect[];
1817
- /**
1818
- * Darken toward the corners. `amount` is how dark the corner gets (0..1) and
1819
- * `feather` how much of the radius the falloff occupies.
1820
- */
1821
- declare function vignette({ amount, feather }: {
1822
- amount: number;
1823
- feather?: number;
1824
- }): Effect[];
1825
-
1826
1777
  /** Per-axis limits on a view's position. Any side may be left open. */
1827
1778
  interface PanBounds {
1828
1779
  minX?: number;
@@ -2564,6 +2515,66 @@ declare function useViewAnimation(view: ViewChannel, animator?: Animator): ViewA
2564
2515
  * animator of its own, so the camera runs on exactly the one passed. */
2565
2516
  declare function useViewAnimationOn(view: ViewChannel, animator: Animator): ViewAnimationApi;
2566
2517
 
2518
+ /**
2519
+ * @experimental
2520
+ * PointerContext — the world-space position of the canvas pointer, and the
2521
+ * view it is over, refreshed on every `pointermove` and cleared on
2522
+ * `pointerleave`.
2523
+ *
2524
+ * It is an external store rather than React state: cursor moves fire dozens of
2525
+ * times per second, and a consumer that only reads on demand (paste at the
2526
+ * pointer) must not re-render for each one. Readers that do need to follow it
2527
+ * — a linked cursor — subscribe, or use `usePointerPosition()`.
2528
+ *
2529
+ * `<SceneCanvas>` publishes automatically, and defers to a provider already in
2530
+ * scope, so several surfaces under one provider share one pointer: a detached
2531
+ * minimap and its main canvas each see where the other's pointer is.
2532
+ */
2533
+
2534
+ /** @experimental World-space pointer position and the view it is over — a
2535
+ * view id, or `null` for a surface's own camera. `null` as a whole when the
2536
+ * pointer is over no publishing surface. */
2537
+ type PointerWorldPos = {
2538
+ worldX: number;
2539
+ worldY: number;
2540
+ viewId: string | null;
2541
+ } | null;
2542
+ /** @experimental */
2543
+ interface PointerContextValue {
2544
+ /** The latest position. */
2545
+ get(): PointerWorldPos;
2546
+ /** Publish a position. Subscribers hear only a changed value. */
2547
+ set(next: PointerWorldPos): void;
2548
+ /** Called after every change; returns the unsubscribe. */
2549
+ subscribe(fn: () => void): () => void;
2550
+ /** Bumps on every change. */
2551
+ getVersion(): number;
2552
+ /** `get()` as a stable thunk, for hooks taking a drop-point option. */
2553
+ readonly getDropPoint: () => PointerWorldPos;
2554
+ }
2555
+ /** @experimental A pointer store with no provider around it. */
2556
+ declare function createPointerStore(): PointerContextValue;
2557
+ /**
2558
+ * @experimental
2559
+ * Wrap the part of the React tree that should share one pointer. Usually at
2560
+ * the app root, alongside `<ActionsProvider>` and `<SelectionContextProvider>`.
2561
+ *
2562
+ * Most consumers don't need to mount this directly — `<SceneCanvas>` mounts
2563
+ * one when none is in scope. Mount it yourself when two surfaces should share
2564
+ * a pointer. Pass `store` to publish into one you hold elsewhere
2565
+ * (`createPointerStore()`).
2566
+ */
2567
+ declare function PointerContextProvider({ children, store }: {
2568
+ children: ReactNode;
2569
+ store?: PointerContextValue;
2570
+ }): ReactNode;
2571
+ /** @experimental The surrounding pointer store, or `null` when no provider is
2572
+ * in scope. */
2573
+ declare function usePointerContext(): PointerContextValue | null;
2574
+ /** @experimental The pointer, re-rendering the caller whenever it changes.
2575
+ * `null` outside a provider. */
2576
+ declare function usePointerPosition(): PointerWorldPos;
2577
+
2567
2578
  /**
2568
2579
  * Pose composition for hierarchical scene graphs.
2569
2580
  *
@@ -2589,6 +2600,10 @@ declare function useViewAnimationOn(view: ViewChannel, animator: Animator): View
2589
2600
  interface PoseAdapter<TPose> {
2590
2601
  getPose(id: string): TPose;
2591
2602
  getParent(id: string): string | null;
2603
+ /** Whether `id`'s pose is a frame its children are expressed in. Absent
2604
+ * means every node is one. A container whose pose derives from its children
2605
+ * is not: its children share its frame, so the fold passes over it. */
2606
+ definesFrame?(id: string): boolean;
2592
2607
  }
2593
2608
  /**
2594
2609
  * The transforms a `compose` represents **exactly**. A parent transform wider
@@ -2965,6 +2980,12 @@ interface EditAnchorsDep {
2965
2980
  * (when the polygon lives on data.path). Records one history entry
2966
2981
  * labelled `label`. */
2967
2982
  applyEdit(id: string, worldPath: unknown, label: string): void;
2983
+ /** The ops `applyEdit` would commit for the same arguments, unapplied, so
2984
+ * a caller can make the edit part of a larger batch — the pen joining
2985
+ * two paths edits one node and deletes the other in one undo step.
2986
+ * Optional; a caller that needs it declines the composite edit without
2987
+ * it. Returns `[]` when `id` has no editable polygon. */
2988
+ editOps?(id: string, worldPath: unknown, label: string): Op[];
2968
2989
  /**
2969
2990
  * Anchors currently selected within the edited path, as **flat anchor
2970
2991
  * indices** — the same numbering `enumerateAnchors` produces and the
@@ -3237,6 +3258,9 @@ interface ResizePolicy<TPose> {
3237
3258
  */
3238
3259
  interface LayoutDep {
3239
3260
  getLayout(containerId: string): LayoutStrategy<unknown> | null;
3261
+ /** Which container wins when several contain the drop point. Default
3262
+ * `'innermost'`. */
3263
+ dropTarget?: LayoutDropTargetMode;
3240
3264
  }
3241
3265
  /**
3242
3266
  * Dep for `enterTextEditAction`.
@@ -3475,7 +3499,77 @@ declare module '@weasel-js/routing' {
3475
3499
  * consults this seam (rotation lives on the pose, baked at render).
3476
3500
  */
3477
3501
  geometryProjection?: GeometryProjection;
3502
+ /**
3503
+ * The surface's own camera. Inside a `<CanvasView>`, `view` answers that
3504
+ * view's camera and this one does not change: an action bound in a view
3505
+ * that must move the main camera — a minimap's pan — reads this.
3506
+ */
3507
+ rootView: ViewApi;
3508
+ /**
3509
+ * The pointer store in scope: where the pointer is, in which view. Shared
3510
+ * by every surface under one `<PointerContextProvider>`.
3511
+ */
3512
+ pointer?: PointerContextValue;
3478
3513
  }
3479
3514
  }
3480
3515
 
3481
- export { type DerivedDep as $, type SliceDep as A, type VertexColorChannel as B, type CullRect as C, type DrawCommand as D, type Effect as E, type InsertExtras as F, type GlMat3 as G, type SerializedScene as H, IDENTITY_COLOR_MATRIX as I, type GeometryProjection as J, type ContentHandlerEntry as K, type SvgIngestOptions as L, type Mesh as M, type Node as N, type PanBounds as O, type PathDrawCommand as P, type Animator as Q, type RenderTarget as R, SPRITE_STRIDE as S, type TextDrawCommand as T, ColorOverrideRegistry as U, type ViewAnimationOptions as V, WeaselRenderer as W, type UseSceneOptions as X, type SceneRegistry as Y, type RegisteredOp as Z, type PoseOverrides as _, type GroupDrawCommand as a, type StaggerSpringPoseOptions as a$, type ViewportDims as a0, ShaderProgram as a1, type BooleansAdapter as a2, type UseAnimatorOptions as a3, type SpringPresetName as a4, type EasingSpec as a5, type AnimationHandle as a6, type SampledTrack as a7, type AddLayerSpec as a8, type AddNodeSpec as a9, type Keyframe as aA, type LassoSelectDep as aB, type LayerRecord as aC, type LayoutDep as aD, type LeafNode as aE, type LoopFactory as aF, type LoopOptions as aG, type NestedTimeline as aH, type NodeAtPointDep as aI, type PhysicsHandle as aJ, type PhysicsOptions as aK, type PoseAdapter as aL, type PoseClosure as aM, type PoseOverride as aN, RECT_POSE_COMPOSITION as aO, RIGID_POSE_COMPOSITION as aP, type ResizePolicy as aQ, SPRING_PRESETS as aR, type SerializedNode as aS, type SnapDep as aT, type SpringOptions as aU, type SpringPreset as aV, type StaggerBuilder as aW, type StaggerDelay as aX, type StaggerFactory as aY, type StaggerOptions as aZ, type StaggerPerItem as a_, type AnimateToBoundsOptions as aa, type AreaSelectDep as ab, type BezierEasing as ac, type BooleanOp as ad, type BooleanOpResult as ae, type ClipboardDep as af, type ClipboardIngestCtx as ag, type ColorOverride as ah, type ColorOverrideFn as ai, type ContainerNode as aj, type DecayLoopConfig as ak, type DecayOptions as al, EASINGS as am, type EasingFn as an, type EasingName as ao, type EditAnchorsDep as ap, type EventBooking as aq, type EventBookingHandle as ar, type EventTrack as as, type FitViewToBoundsOptions as at, IDENTITY_POSE_COMPOSITION as au, type IngestCtx as av, type IngestionDep as aw, type InsertDep as ax, type Interpolate as ay, type InterpolatorFactory as az, type ImageDrawCommand as b, resolveEasing as b$, type StaggerTweenOptions as b0, type SvgUnpacker as b1, type SystemLayerRecord as b2, type SystemLayerSpec as b3, type TextEditDep as b4, type TimelineClock as b5, type TimelineEvent as b6, type TimelineHandle as b7, type TimelineOptions as b8, type TimelineTrack as b9, easeInOutCirc as bA, easeInOutCubic as bB, easeInOutElastic as bC, easeInOutExpo as bD, easeInOutQuad as bE, easeInOutQuart as bF, easeInOutQuint as bG, easeInOutSine as bH, easeInQuad as bI, easeInQuart as bJ, easeInQuint as bK, easeInSine as bL, easeOut as bM, easeOutBack as bN, easeOutBounce as bO, easeOutCirc as bP, easeOutCubic as bQ, easeOutElastic as bR, easeOutExpo as bS, easeOutQuad as bT, easeOutQuart as bU, easeOutQuint as bV, easeOutSine as bW, fitViewToBounds as bX, linear as bY, rebaseLocalPose as bZ, registerContentHandler as b_, type Track as ba, type TweenLoopOptions as bb, type TweenOptions as bc, type UserLayerRecord as bd, VIEW_ANIMATION_KEY as be, type ViewAnimationApi as bf, type ViewApi as bg, type ViewChannel as bh, applyBooleanOp as bi, asNodeId as bj, composeRectPose as bk, composeRigidPose as bl, composeWorldPose as bm, cubicBezierEasing as bn, decomposeRectPose as bo, decomposeRigidPose as bp, easeIn as bq, easeInBack as br, easeInBounce as bs, easeInCirc as bt, easeInCubic as bu, easeInElastic as bv, easeInExpo as bw, easeInOut as bx, easeInOutBack as by, easeInOutBounce as bz, type ImageMinification as c, resolveStrokeWidth as c0, translateRectPose as c1, useDecayLoop as c2, useViewAnimation as c3, useViewAnimationOn as c4, worldPoseLookup as c5, ShaderCompileError as d, type ShaderDrawCommand as e, type ShaderProgramHandle as f, type ShaderUniform as g, type SolidPaint as h, type SpriteSheet as i, type SpritesDrawCommand as j, type StrokeOptions as k, type WeaselRendererOptions as l, blur as m, buildGradientRamp as n, cullDrawCommands as o, frameRect as p, mat3 as q, registerEffect as r, registerProgram as s, tessellateStroke as t, vignette as u, viewToMat3 as v, type Scene as w, type RectPose as x, type InertiaConfig as y, type PoseComposition as z };
3516
+ /** Options for stroke tessellation. */
3517
+ interface StrokeOptions {
3518
+ flattenTolerance?: number;
3519
+ /**
3520
+ * Shorten each open subpath by this much at its start / end, in the same
3521
+ * world units as the path. Stroke markers use this so a filled head is not
3522
+ * speared by its own line; the caller resolves the distance, because this
3523
+ * layer knows nothing about the marker registry.
3524
+ */
3525
+ startInset?: number;
3526
+ endInset?: number;
3527
+ }
3528
+ /** Resolve a stroke width to world units. A number is already world units;
3529
+ * `{ px }` is screen pixels divided by the accumulated scale, so it holds its
3530
+ * on-screen thickness as the view zooms. */
3531
+ declare function resolveStrokeWidth(width: ScreenLength, scale: number): number;
3532
+ /**
3533
+ * Build a triangle-mesh ribbon from a stroked Path.
3534
+ *
3535
+ * Supports:
3536
+ * - cap: 'butt' | 'round' | 'square'
3537
+ * - join: 'miter' | 'round' | 'bevel'
3538
+ * - center alignment directly; RectPath inner/outer alignment via a
3539
+ * pre-shifted rect; PolygonPath inner/outer alignment via stencil at the
3540
+ * renderer level
3541
+ * - dash splitting
3542
+ */
3543
+ declare function tessellateStroke(path: Path, stroke: Stroke, opts?: StrokeOptions): Mesh;
3544
+
3545
+ /**
3546
+ * Effects that ship with the kit.
3547
+ *
3548
+ * Each is a function returning `Effect[]`, not a single `Effect`, because a
3549
+ * separable kernel is genuinely two passes and hiding that behind one entry
3550
+ * would make the cost invisible at the callsite:
3551
+ *
3552
+ * effects={[...blur({ radius: 4 }), ...vignette({ amount: 0.6 })]}
3553
+ */
3554
+
3555
+ /**
3556
+ * Gaussian blur, as a horizontal pass followed by a vertical one.
3557
+ *
3558
+ * `radius` is in device pixels and is the distance of the outermost tap, not a
3559
+ * standard deviation — 0 is a copy, and the falloff is the same nine-tap
3560
+ * kernel at every radius, so a large one is a wide blur rather than a better
3561
+ * one. Two passes at O(9) beat one at O(81) and look the same.
3562
+ */
3563
+ declare function blur({ radius }: {
3564
+ radius: number;
3565
+ }): Effect[];
3566
+ /**
3567
+ * Darken toward the corners. `amount` is how dark the corner gets (0..1) and
3568
+ * `feather` how much of the radius the falloff occupies.
3569
+ */
3570
+ declare function vignette({ amount, feather }: {
3571
+ amount: number;
3572
+ feather?: number;
3573
+ }): Effect[];
3574
+
3575
+ export { type DerivedDep as $, type SliceDep as A, type VertexColorChannel as B, type CullRect as C, type DrawCommand as D, type Effect as E, type InsertExtras as F, type GlMat3 as G, type SerializedScene as H, IDENTITY_COLOR_MATRIX as I, type GeometryProjection as J, type ContentHandlerEntry as K, type SvgIngestOptions as L, type Mesh as M, type Node as N, type PanBounds as O, type PathDrawCommand as P, type Animator as Q, type RenderTarget as R, SPRITE_STRIDE as S, type TextDrawCommand as T, ColorOverrideRegistry as U, type ViewAnimationOptions as V, WeaselRenderer as W, type UseSceneOptions as X, type SceneRegistry as Y, type RegisteredOp as Z, type PoseOverrides as _, type GroupDrawCommand as a, type StaggerDelay as a$, type ViewportDims as a0, type ViewApi as a1, ShaderProgram as a2, type BooleansAdapter as a3, type UseAnimatorOptions as a4, type SpringPresetName as a5, type EasingSpec as a6, type AnimationHandle as a7, type SampledTrack as a8, type AddLayerSpec as a9, type InterpolatorFactory as aA, type Keyframe as aB, type LassoSelectDep as aC, type LayerRecord as aD, type LayoutDep as aE, type LeafNode as aF, type LoopFactory as aG, type LoopOptions as aH, type NestedTimeline as aI, type NodeAtPointDep as aJ, type PhysicsHandle as aK, type PhysicsOptions as aL, PointerContextProvider as aM, type PointerContextValue as aN, type PointerWorldPos as aO, type PoseAdapter as aP, type PoseClosure as aQ, type PoseOverride as aR, RECT_POSE_COMPOSITION as aS, RIGID_POSE_COMPOSITION as aT, type ResizePolicy as aU, SPRING_PRESETS as aV, type SerializedNode as aW, type SnapDep as aX, type SpringOptions as aY, type SpringPreset as aZ, type StaggerBuilder as a_, type AddNodeSpec as aa, type AnimateToBoundsOptions as ab, type AreaSelectDep as ac, type BezierEasing as ad, type BooleanOp as ae, type BooleanOpResult as af, type ClipboardDep as ag, type ClipboardIngestCtx as ah, type ColorOverride as ai, type ColorOverrideFn as aj, type ContainerNode as ak, type DecayLoopConfig as al, type DecayOptions as am, EASINGS as an, type EasingFn as ao, type EasingName as ap, type EditAnchorsDep as aq, type EventBooking as ar, type EventBookingHandle as as, type EventTrack as at, type FitViewToBoundsOptions as au, IDENTITY_POSE_COMPOSITION as av, type IngestCtx as aw, type IngestionDep as ax, type InsertDep as ay, type Interpolate as az, type ImageDrawCommand as b, fitViewToBounds as b$, type StaggerFactory as b0, type StaggerOptions as b1, type StaggerPerItem as b2, type StaggerSpringPoseOptions as b3, type StaggerTweenOptions as b4, type SvgUnpacker as b5, type SystemLayerRecord as b6, type SystemLayerSpec as b7, type TextEditDep as b8, type TimelineClock as b9, easeInExpo as bA, easeInOut as bB, easeInOutBack as bC, easeInOutBounce as bD, easeInOutCirc as bE, easeInOutCubic as bF, easeInOutElastic as bG, easeInOutExpo as bH, easeInOutQuad as bI, easeInOutQuart as bJ, easeInOutQuint as bK, easeInOutSine as bL, easeInQuad as bM, easeInQuart as bN, easeInQuint as bO, easeInSine as bP, easeOut as bQ, easeOutBack as bR, easeOutBounce as bS, easeOutCirc as bT, easeOutCubic as bU, easeOutElastic as bV, easeOutExpo as bW, easeOutQuad as bX, easeOutQuart as bY, easeOutQuint as bZ, easeOutSine as b_, type TimelineEvent as ba, type TimelineHandle as bb, type TimelineOptions as bc, type TimelineTrack as bd, type Track as be, type TweenLoopOptions as bf, type TweenOptions as bg, type UserLayerRecord as bh, VIEW_ANIMATION_KEY as bi, type ViewAnimationApi as bj, type ViewChannel as bk, applyBooleanOp as bl, asNodeId as bm, composeRectPose as bn, composeRigidPose as bo, composeWorldPose as bp, createPointerStore as bq, cubicBezierEasing as br, decomposeRectPose as bs, decomposeRigidPose as bt, easeIn as bu, easeInBack as bv, easeInBounce as bw, easeInCirc as bx, easeInCubic as by, easeInElastic as bz, type ImageMinification as c, linear as c0, rebaseLocalPose as c1, registerContentHandler as c2, resolveEasing as c3, resolveStrokeWidth as c4, translateRectPose as c5, useDecayLoop as c6, usePointerContext as c7, usePointerPosition as c8, useViewAnimation as c9, useViewAnimationOn as ca, worldPoseLookup as cb, ShaderCompileError as d, type ShaderDrawCommand as e, type ShaderProgramHandle as f, type ShaderUniform as g, type SolidPaint as h, type SpriteSheet as i, type SpritesDrawCommand as j, type StrokeOptions as k, type WeaselRendererOptions as l, blur as m, buildGradientRamp as n, cullDrawCommands as o, frameRect as p, mat3 as q, registerEffect as r, registerProgram as s, tessellateStroke as t, vignette as u, viewToMat3 as v, type Scene as w, type RectPose as x, type InertiaConfig as y, type PoseComposition as z };