@weasel-js/minimap 1.9.4 → 1.10.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/dist/index.d.ts CHANGED
@@ -1,22 +1,25 @@
1
- import { View, Bounds, Scene, ViewportDims, PoseDescriptor, PathDrawCommand, ViewRect, Dims, RenderLayer, SurfaceContribution, ViewApi, SceneViewDrawOne, SceneViewLayers, Animator } from '@weasel-js/core';
1
+ import { View, Bounds, Scene, ViewportDims, PoseDescriptor, PathDrawCommand, ViewRect, Dims, RenderLayer, SurfaceContribution, ViewApi, SceneViewDrawOne, SceneViewLayers } from '@weasel-js/core';
2
2
  import { Action } from '@weasel-js/routing';
3
3
  import { PointerWorldPos } from '@weasel-js/routing/react';
4
4
  import * as react from 'react';
5
5
  import { Ref } from 'react';
6
+ import { Animator } from '@weasel-js/animator';
6
7
 
7
- /**
8
- * Fallback view returned when there is nothing to fit (empty scene, etc.).
9
- * Identity view at the origin — produces a 1:1 mapping centered on (0, 0).
10
- */
8
+ /** Fallback view returned when there is nothing to fit (empty scene, etc.). */
11
9
  declare const FALLBACK_FIT_VIEW: View;
12
10
  /**
13
11
  * Fit policy for `<MinimapCanvas>` / `computeFitView`.
14
12
  *
15
- * - `"scene"` — union of leaf-node pose AABBs (via the pose descriptor).
13
+ * - `"scene"` — union of leaf-node pose AABBs (via the pose descriptor), read
14
+ * from the document: a pose override moves what is painted and not the frame.
15
+ * - `"live"` — the same union over the poses being shown, overrides included,
16
+ * so the frame follows a drag, a settle, or a simulation writing overrides.
17
+ * Refit on every override publish, which is a sweep of every leaf and
18
+ * rescales the whole minimap while one moves past the edge.
16
19
  * - `{ kind: "world", rect }` — caller-supplied world rect.
17
20
  * - `(scene, dims) => View` — caller derives the view directly.
18
21
  */
19
- type MinimapFit<TData, TLayer extends string, TPose> = 'scene' | {
22
+ type MinimapFit<TData, TLayer extends string, TPose> = 'scene' | 'live' | {
20
23
  kind: 'world';
21
24
  rect: Bounds;
22
25
  } | ((scene: Scene<TData, TLayer, TPose>, dims: ViewportDims) => View);
@@ -38,34 +41,19 @@ interface ComputeFitViewOptions {
38
41
  * Derive a `View` that fits the chosen world rect into a minimap of
39
42
  * `dims.width × dims.height` CSS px. Uniform scale on both axes; the rect
40
43
  * is centered with `padding` (default 8) on each side. The smaller-axis
41
- * fit ratio wins, so the whole rect is visible.
42
- *
43
- * - `fit === "scene"`: union AABB of leaf-node poses via `descriptor`.
44
- * Empty scene → {@link FALLBACK_FIT_VIEW}.
45
- * - `fit` is `{ kind: "world", rect }`: fit `rect`.
46
- * - `fit` is a function: called with `(scene, dims)`; its return is
47
- * passed through unchanged.
44
+ * fit ratio wins, so the whole rect is visible. An empty scene gives
45
+ * {@link FALLBACK_FIT_VIEW}; a function `fit` is passed through unchanged.
48
46
  *
49
47
  * A rect with one zero axis (a line) is fitted along the other. One with no
50
48
  * positive axis falls back to identity scale centered on its top-left.
51
49
  */
52
50
  declare function computeFitView<TData, TLayer extends string, TPose>(scene: Scene<TData, TLayer, TPose>, dims: ViewportDims, fit: MinimapFit<TData, TLayer, TPose>, descriptor: PoseDescriptor<TPose>, opts?: ComputeFitViewOptions): View;
53
51
  /**
54
- * Build the visible-window indicator `DrawCommand` for the minimap.
55
- *
56
- * The main canvas's visible world rect is:
57
- * ```
58
- * worldX = mainView.x
59
- * worldY = mainView.y
60
- * worldW = mainViewDims.width / mainView.scale.x
61
- * worldH = mainViewDims.height / mainView.scale.y
62
- * ```
63
- * That world rect is then transformed into the minimap's screen
64
- * coordinates through `minimapView`.
65
- *
66
- * The returned command is a dashed-stroke `path` rect with no fill. Pass the
67
- * `minimapView` it will be drawn through, so the stroke width and dash come
68
- * out in CSS px at any fit scale; without it they are in world units.
52
+ * Build the visible-window indicator `DrawCommand` for the minimap: the main
53
+ * canvas's visible world rect as a dashed-stroke `path` rect with no fill, in
54
+ * world coordinates. Pass the `minimapView` it will be drawn through, so the
55
+ * stroke width and dash come out in CSS px at any fit scale; without it they
56
+ * are in world units.
69
57
  */
70
58
  declare function computeIndicatorCommand(mainView: View, mainViewDims: ViewportDims, style?: IndicatorStyle, minimapView?: View): PathDrawCommand;
71
59
 
@@ -218,10 +206,10 @@ interface MinimapCanvasProps<TData, TLayer extends string, TPose> {
218
206
  /** Fit policy. Defaults to `"scene"` (AABB union of leaf poses). See
219
207
  * `MinimapFit` for the full shape.
220
208
  *
221
- * Framing is derived from **document** poses, not `scene.overrides` — a
222
- * node moved by an override paints where the override puts it, outside the
209
+ * `"scene"` frames **document** poses, not `scene.overrides` — a node
210
+ * moved by an override paints where the override puts it, outside the
223
211
  * frame if it goes there, rather than making the whole minimap rescale on
224
- * every frame of a drag or a settle. */
212
+ * every frame of a drag or a settle. `"live"` frames the overrides too. */
225
213
  fit?: MinimapFit<TData, TLayer, TPose>;
226
214
  /** How to read poses. Default `AUTO_POSE_DESCRIPTOR`. */
227
215
  poseDescriptor?: PoseDescriptor<TPose>;
@@ -240,7 +228,8 @@ interface MinimapCanvasProps<TData, TLayer extends string, TPose> {
240
228
  animator?: Animator;
241
229
  /** Visual tuning of the indicator stroke. */
242
230
  indicatorStyle?: IndicatorStyle;
243
- /** CSS class for positioning the canvas. Its size is `width` × `height`. */
231
+ /** CSS class for the canvas. Its size is `width` × `height` unless a rule
232
+ * on this class sizes it. */
244
233
  className?: string;
245
234
  /** Forwarded ref to the underlying `<canvas>`. */
246
235
  canvasRef?: Ref<HTMLCanvasElement>;
@@ -249,11 +238,14 @@ interface MinimapCanvasProps<TData, TLayer extends string, TPose> {
249
238
  id?: string;
250
239
  }
251
240
  /**
252
- * Opinionated minimap. See `MinimapCanvasProps` for the full surface and
253
- * the module docstring for the rendering / input model.
241
+ * Opinionated minimap on a canvas of its own. Renders the same `scene` the
242
+ * main canvas is showing through a derived "fit" view, and overlays a dashed
243
+ * indicator of where the main canvas is looking. Press anywhere in it to
244
+ * recenter the main view on that world point; drag to pan continuously.
254
245
  *
255
246
  * Its dispatcher, actions and deps are its own, so it never competes with
256
- * the main canvas for input. The pointer store is shared when one is in scope.
247
+ * the main canvas for input. Put one `<PointerContextProvider>` around it and
248
+ * the main canvas for linked cursors both ways.
257
249
  *
258
250
  * `forwardRef` is not used because the component is generic over
259
251
  * `<TData, TLayer, TPose>` and React's `forwardRef` erases generics. The
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { PointerProviderIfRoot, AUTO_POSE_DESCRIPTOR, poseDescriptorForNode, documentPose, FALLBACK_ACCENT, normalizeView, accentColorOf, SceneViewCanvas } from '@weasel-js/core';
2
- import { useSyncExternalStore, useMemo, useRef, useEffect, useCallback } from 'react';
1
+ import { PointerProviderIfRoot, AUTO_POSE_DESCRIPTOR, poseDescriptorForNode, effectivePose, documentPose, FALLBACK_ACCENT, normalizeView, accentColorOf, SceneViewCanvas } from '@weasel-js/core';
2
+ import { useMemo, useRef, useEffect, useCallback, useSyncExternalStore } from 'react';
3
3
  import { DepRegistryProvider, ActionsProvider, ActiveToolContextProvider, useDepSource, useActionsRegistry, useGestureDispatcher, usePointerContext, usePointerPosition } from '@weasel-js/routing/react';
4
4
  import { useLatest, assignRef } from '@weasel-js/react';
5
5
  import { jsx } from 'react/jsx-runtime';
@@ -34,7 +34,7 @@ function fitRectInto(rect, dims, padding) {
34
34
  scale: { x: s, y: s }
35
35
  };
36
36
  }
37
- function sceneLeafBounds(scene, descriptor) {
37
+ function sceneLeafBounds(scene, descriptor, poseOf) {
38
38
  let minX = Infinity;
39
39
  let minY = Infinity;
40
40
  let maxX = -Infinity;
@@ -42,7 +42,7 @@ function sceneLeafBounds(scene, descriptor) {
42
42
  let any = false;
43
43
  for (const node of scene.nodes.values()) {
44
44
  if (node.kind !== "leaf") continue;
45
- const b = poseDescriptorForNode(descriptor, node).getBounds(documentPose(scene, node));
45
+ const b = poseDescriptorForNode(descriptor, node).getBounds(poseOf(scene, node));
46
46
  if (!Number.isFinite(b.x + b.y + b.width + b.height)) continue;
47
47
  if (b.x < minX) minX = b.x;
48
48
  if (b.y < minY) minY = b.y;
@@ -60,8 +60,8 @@ function computeFitView(scene, dims, fit, descriptor, opts = {}) {
60
60
  if (typeof fit === "function") {
61
61
  return fit(scene, dims);
62
62
  }
63
- if (fit === "scene") {
64
- const rect = sceneLeafBounds(scene, descriptor);
63
+ if (fit === "scene" || fit === "live") {
64
+ const rect = sceneLeafBounds(scene, descriptor, fit === "live" ? effectivePose : documentPose);
65
65
  if (rect === null) return FALLBACK_FIT_VIEW;
66
66
  return fitRectInto(rect, dims, padding);
67
67
  }
@@ -77,7 +77,7 @@ function computeIndicatorCommand(mainView, mainViewDims, style = {}, minimapView
77
77
  kind: "path",
78
78
  path: { kind: "rect", x, y, width, height },
79
79
  stroke: {
80
- paint: { fill: "solid", color: style.stroke ?? DEFAULT_INDICATOR_STROKE },
80
+ paint: { kind: "solid", color: style.stroke ?? DEFAULT_INDICATOR_STROKE },
81
81
  width: (style.width ?? DEFAULT_INDICATOR_WIDTH) * px,
82
82
  dash: (style.dash ?? DEFAULT_INDICATOR_DASH).map((d) => d * px)
83
83
  }
@@ -187,7 +187,7 @@ function createLinkedCursorLayer(opts) {
187
187
  const rect = (r, c) => ({
188
188
  kind: "path",
189
189
  path: { kind: "rect", x: r.x, y: r.y, width: r.w, height: r.h },
190
- fill: { fill: "solid", color: c }
190
+ fill: { paint: { kind: "solid", color: c } }
191
191
  });
192
192
  const accent = color();
193
193
  return [
@@ -237,12 +237,13 @@ function createMinimapContribution(opts) {
237
237
  if (!scene) return FALLBACK_FIT_VIEW;
238
238
  const r = typeof opts.rect === "function" ? opts.rect(outer, dims) : opts.rect;
239
239
  const version = scene.getVersion();
240
- if (cached && cached.scene === scene && cached.version === version && cached.w === r.w && cached.h === r.h) {
240
+ const shown = fit === "live" ? scene.overrides.getGeneration() : 0;
241
+ if (cached && cached.scene === scene && cached.version === version && cached.shown === shown && cached.w === r.w && cached.h === r.h) {
241
242
  return cached.view;
242
243
  }
243
244
  const descriptor = deps?.get("poseDescriptor") ?? AUTO_POSE_DESCRIPTOR;
244
245
  const view = computeFitView(scene, { width: r.w, height: r.h }, fit, descriptor);
245
- cached = { scene, version, w: r.w, h: r.h, view };
246
+ cached = { scene, version, shown, w: r.w, h: r.h, view };
246
247
  return view;
247
248
  };
248
249
  const cursor = linkedCursor(`${id}.cursor`, [null, id]);
@@ -280,6 +281,19 @@ function createMinimapContribution(opts) {
280
281
  }
281
282
  };
282
283
  }
284
+ var NEVER = () => () => {
285
+ };
286
+ function useFitView(scene, width, height, fit, descriptor) {
287
+ const sceneVersion = useSyncExternalStore(scene.subscribe, scene.getVersion, scene.getVersion);
288
+ const overrideGeneration = useSyncExternalStore(
289
+ fit === "live" ? scene.overrides.subscribe : NEVER,
290
+ scene.overrides.getGeneration,
291
+ scene.overrides.getGeneration
292
+ );
293
+ return useMemo(() => {
294
+ return normalizeView(computeFitView(scene, { width, height }, fit, descriptor));
295
+ }, [scene, sceneVersion, overrideGeneration, width, height, fit, descriptor]);
296
+ }
283
297
  var MINIMAP_INPUT = {
284
298
  id: "minimap",
285
299
  eligibility: { always: true },
@@ -311,15 +325,8 @@ function MinimapCanvasInner(props) {
311
325
  id = "minimap"
312
326
  } = props;
313
327
  const mainView = normalizeView(mainViewProp);
314
- const sceneVersion = useSyncExternalStore(
315
- scene.subscribe,
316
- scene.getVersion,
317
- scene.getVersion
318
- );
319
328
  const descriptor = poseDescriptor ?? AUTO_POSE_DESCRIPTOR;
320
- const fitView = useMemo(() => {
321
- return normalizeView(computeFitView(scene, { width, height }, fit, descriptor));
322
- }, [scene, sceneVersion, width, height, fit, descriptor]);
329
+ const fitView = useFitView(scene, width, height, fit, descriptor);
323
330
  const indicatorCmd = useMemo(() => {
324
331
  return computeIndicatorCommand(mainView, mainViewDims, indicatorStyle, fitView);
325
332
  }, [mainView, mainViewDims, indicatorStyle, fitView]);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/minimapMath.ts","../src/actions.ts","../src/layers.ts","../src/createMinimapContribution.ts","../src/MinimapCanvas.tsx"],"names":["AUTO_POSE_DESCRIPTOR","accentColorOf"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Pure math helpers for `<MinimapCanvas>`.\n *\n * `computeFitView` derives a `View` that fits a chosen world rect into a\n * minimap canvas of given pixel dims. `computeIndicatorCommand` builds the\n * dashed \"visible window\" rect — the main canvas's screen window projected\n * into the minimap's own screen coordinates.\n *\n * Neither helper touches GL, the DOM, or the renderer; they're pure\n * functions, unit-testable with `expect`.\n */\nimport { documentPose } from '@weasel-js/core';\nimport type { Scene } from '@weasel-js/core';\nimport type { View } from '@weasel-js/core';\nimport type { Bounds, ViewportDims } from '@weasel-js/core';\nimport { poseDescriptorForNode, type PoseDescriptor } from '@weasel-js/core';\nimport type { PathDrawCommand } from '@weasel-js/core';\n\n/** Inset (CSS px) around the fit rect on each side. Matches the spec note. */\nconst DEFAULT_FIT_PADDING = 8;\n\n/**\n * Fallback view returned when there is nothing to fit (empty scene, etc.).\n * Identity view at the origin — produces a 1:1 mapping centered on (0, 0).\n */\nexport const FALLBACK_FIT_VIEW: View = { x: 0, y: 0, scale: { x: 1, y: 1 } };\n\n/**\n * Fit policy for `<MinimapCanvas>` / `computeFitView`.\n *\n * - `\"scene\"` — union of leaf-node pose AABBs (via the pose descriptor).\n * - `{ kind: \"world\", rect }` — caller-supplied world rect.\n * - `(scene, dims) => View` — caller derives the view directly.\n */\nexport type MinimapFit<TData, TLayer extends string, TPose> =\n | 'scene'\n | { kind: 'world'; rect: Bounds }\n | ((scene: Scene<TData, TLayer, TPose>, dims: ViewportDims) => View);\n\n/** Style for the visible-window indicator rect drawn over the minimap. */\nexport interface IndicatorStyle {\n /** Stroke color (any CSS color). Defaults to `'#ffffff'`. */\n stroke?: string;\n /** Stroke width in CSS px. Defaults to `1`. */\n width?: number;\n /** Dash pattern in CSS px. Defaults to `[2, 3]`. */\n dash?: number[];\n}\n\nconst DEFAULT_INDICATOR_STROKE = '#ffffff';\nconst DEFAULT_INDICATOR_WIDTH = 1;\nconst DEFAULT_INDICATOR_DASH: readonly number[] = [2, 3];\n\n/** Internal: fit a world rect uniformly into dims with padding. */\nfunction fitRectInto(rect: Bounds, dims: ViewportDims, padding: number): View {\n const availW = Math.max(1, dims.width - padding * 2);\n const availH = Math.max(1, dims.height - padding * 2);\n const hasW = rect.width > 0;\n const hasH = rect.height > 0;\n if (!hasW && !hasH) {\n return {\n x: rect.x - dims.width / 2,\n y: rect.y - dims.height / 2,\n scale: { x: 1, y: 1 },\n };\n }\n const s = Math.min(\n hasW ? availW / rect.width : Infinity,\n hasH ? availH / rect.height : Infinity,\n );\n const worldCx = rect.x + Math.max(0, rect.width) / 2;\n const worldCy = rect.y + Math.max(0, rect.height) / 2;\n return {\n x: worldCx - dims.width / (2 * s),\n y: worldCy - dims.height / (2 * s),\n scale: { x: s, y: s },\n };\n}\n\n/**\n * Compute the AABB union of all leaf-node poses in the scene, via\n * `descriptor`. Container nodes are skipped — their effective bounds come\n * from their descendant leaves, and so is a leaf whose bounds are not finite,\n * which would otherwise make the whole union non-finite. Returns `null` when\n * the scene has no leaf with bounds.\n */\nfunction sceneLeafBounds<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n descriptor: PoseDescriptor<TPose>,\n): Bounds | null {\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n let any = false;\n for (const node of scene.nodes.values()) {\n if (node.kind !== 'leaf') continue;\n const b = poseDescriptorForNode(descriptor, node).getBounds(documentPose(scene, node));\n if (!Number.isFinite(b.x + b.y + b.width + b.height)) continue;\n if (b.x < minX) minX = b.x;\n if (b.y < minY) minY = b.y;\n const right = b.x + b.width;\n const bottom = b.y + b.height;\n if (right > maxX) maxX = right;\n if (bottom > maxY) maxY = bottom;\n any = true;\n }\n if (!any) return null;\n return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };\n}\n\n/** Options for {@link computeFitView}. */\nexport interface ComputeFitViewOptions {\n /** Inset (CSS px) around the fit rect on each side. Defaults to `8`. */\n padding?: number;\n}\n\n/**\n * Derive a `View` that fits the chosen world rect into a minimap of\n * `dims.width × dims.height` CSS px. Uniform scale on both axes; the rect\n * is centered with `padding` (default 8) on each side. The smaller-axis\n * fit ratio wins, so the whole rect is visible.\n *\n * - `fit === \"scene\"`: union AABB of leaf-node poses via `descriptor`.\n * Empty scene → {@link FALLBACK_FIT_VIEW}.\n * - `fit` is `{ kind: \"world\", rect }`: fit `rect`.\n * - `fit` is a function: called with `(scene, dims)`; its return is\n * passed through unchanged.\n *\n * A rect with one zero axis (a line) is fitted along the other. One with no\n * positive axis falls back to identity scale centered on its top-left.\n */\nexport function computeFitView<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n dims: ViewportDims,\n fit: MinimapFit<TData, TLayer, TPose>,\n descriptor: PoseDescriptor<TPose>,\n opts: ComputeFitViewOptions = {},\n): View {\n const padding = opts.padding ?? DEFAULT_FIT_PADDING;\n\n if (typeof fit === 'function') {\n return fit(scene, dims);\n }\n if (fit === 'scene') {\n const rect = sceneLeafBounds(scene, descriptor);\n if (rect === null) return FALLBACK_FIT_VIEW;\n return fitRectInto(rect, dims, padding);\n }\n // { kind: 'world', rect }\n return fitRectInto(fit.rect, dims, padding);\n}\n\n/**\n * Build the visible-window indicator `DrawCommand` for the minimap.\n *\n * The main canvas's visible world rect is:\n * ```\n * worldX = mainView.x\n * worldY = mainView.y\n * worldW = mainViewDims.width / mainView.scale.x\n * worldH = mainViewDims.height / mainView.scale.y\n * ```\n * That world rect is then transformed into the minimap's screen\n * coordinates through `minimapView`.\n *\n * The returned command is a dashed-stroke `path` rect with no fill. Pass the\n * `minimapView` it will be drawn through, so the stroke width and dash come\n * out in CSS px at any fit scale; without it they are in world units.\n */\nexport function computeIndicatorCommand(\n mainView: View,\n mainViewDims: ViewportDims,\n style: IndicatorStyle = {},\n minimapView?: View,\n): PathDrawCommand {\n // World-space rect: returned as-is. The caller wraps the command list\n // (scene + extras) in a group transformed by the minimap's view, so the\n // indicator lands in screen coords automatically. Returning screen coords\n // here would get the view transform applied a second time — a bug that\n // manifested as the indicator drifting at non-identity minimap scale.\n const x = mainView.x;\n const y = mainView.y;\n const width = mainViewDims.width / mainView.scale.x;\n const height = mainViewDims.height / mainView.scale.y;\n const px = minimapView ? 1 / Math.abs(minimapView.scale.x) : 1;\n return {\n kind: 'path',\n path: { kind: 'rect', x, y, width, height },\n stroke: {\n paint: { fill: 'solid', color: style.stroke ?? DEFAULT_INDICATOR_STROKE },\n width: (style.width ?? DEFAULT_INDICATOR_WIDTH) * px,\n dash: (style.dash ?? DEFAULT_INDICATOR_DASH).map((d) => d * px),\n },\n };\n}\n","/**\n * The minimap's input: press to recenter the main camera on a world point,\n * drag to keep it there. Both read `rootView` — never `view`, which inside the\n * minimap's own view answers the minimap's camera.\n */\nimport type { Action, InvocationCtx, OngoingHandle } from '@weasel-js/routing';\nimport type { ViewApi } from '@weasel-js/core';\n\n/** Action id for `minimapCenterAction`. */\nexport const MINIMAP_CENTER = 'minimap.center';\n/** Action id for `minimapPanAction`. */\nexport const MINIMAP_PAN = 'minimap.pan';\n\n/** Move `root` so world point (`x`, `y`) sits at the center of its host,\n * keeping its scale. A no-op while the host is unmeasured. */\nexport function centerRootOn(root: ViewApi, x: number, y: number): void {\n const size = root.hostSize?.();\n if (!size) return;\n const v = root.get();\n root.set({\n x: x - size.width / (2 * v.scale.x),\n y: y - size.height / (2 * v.scale.y),\n scale: v.scale,\n });\n}\n\nfunction rootOf(deps: InvocationCtx['deps']): ViewApi | undefined {\n return deps.rootView;\n}\n\n/** Recenter the main camera on the pressed world point. */\nexport function minimapCenterAction(): Action {\n return {\n id: MINIMAP_CENTER,\n label: 'Minimap — center the view here',\n requires: ['rootView'],\n invoker: {\n timing: 'immediate',\n run: (deps, params) => {\n const p = params as { worldX?: number; worldY?: number } | undefined;\n const root = rootOf(deps);\n if (!root || p?.worldX === undefined || p.worldY === undefined) return;\n centerRootOn(root, p.worldX, p.worldY);\n },\n },\n };\n}\n\n/** Keep the main camera centered on the pointer's world point while dragging.\n * Pair it with `minimap.center` on `pointerDown`, which handles the press.\n * A recenter lands the moment it is computed, so there is nothing to commit\n * and a cancel ends where a release does. */\nexport function minimapPanAction(): Action {\n return {\n id: MINIMAP_PAN,\n label: 'Minimap — pan the view',\n requires: ['rootView'],\n invoker: {\n timing: 'ongoing',\n start(ctx: InvocationCtx): OngoingHandle {\n const root = rootOf(ctx.deps);\n if (!root) return {};\n // The press already centered (`minimap.center`); the move that crossed\n // the drag threshold is pumped to `onMove` like every later one.\n return {\n onMove: (m) => {\n const p = m.drag?.current ?? m.world;\n centerRootOn(root, p.x, p.y);\n },\n onEnd: () => {},\n };\n },\n },\n };\n}\n","/**\n * The minimap's chrome: the main camera's visible rect, drawn in the minimap,\n * and the linked crosshair, drawn in every view the pointer is not over.\n */\nimport type { RenderLayer } from '@weasel-js/core';\nimport type { View } from '@weasel-js/core';\nimport type { DrawCommand } from '@weasel-js/core';\nimport type { ViewApi } from '@weasel-js/core';\nimport type { PointerWorldPos } from '@weasel-js/routing/react';\nimport { computeIndicatorCommand, type IndicatorStyle } from './minimapMath';\n\n/** What a layer's `data` carries for this feature: the view it draws for. */\nfunction viewIdOf(data: unknown): string | null {\n return (data as { viewId?: string | null } | null)?.viewId ?? null;\n}\n\n/**\n * The main camera's visible world rect, painted only in view `viewId`. Its\n * stroke and dash are screen pixels whatever the minimap's scale.\n */\nexport function createIndicatorLayer(opts: {\n viewId: string;\n root: () => ViewApi | undefined;\n style?: IndicatorStyle;\n}): RenderLayer<unknown> {\n const { viewId, root, style = {} } = opts;\n return {\n id: `${viewId}.indicator`,\n label: 'Minimap indicator',\n draw: (data, view: View): DrawCommand[] => {\n if (viewIdOf(data) !== viewId) return [];\n const r = root();\n const size = r?.hostSize?.();\n if (!r || !size) return [];\n return [computeIndicatorCommand(r.get(), size, style, view)];\n },\n };\n}\n\n/** Screen-pixel geometry of the crosshair: arm length, the gap at its center,\n * line thickness, and the dark halo that keeps it legible over any content. */\nconst ARM = 9;\nconst GAP = 3;\nconst THICK = 2;\nconst HALO = 1;\n/** The halo's color: dark enough to separate the accent from any content. */\nexport const CROSSHAIR_HALO = 'rgba(0, 0, 0, 0.6)';\n\n/** An axis-aligned rect, `{ x, y, w, h }`. */\nexport interface CrosshairRect { x: number; y: number; w: number; h: number }\n\n/**\n * The linked crosshair at (`x`, `y`) as rects in the caller's units, where one\n * screen pixel is `unitsPerPx` of them: four halo rects to paint first, then\n * four bars. A painter with no weasel renderer — a 2D canvas — draws the same\n * crosshair from these.\n */\nexport function crosshairRects(\n x: number, y: number, unitsPerPx: number,\n): { halo: CrosshairRect[]; bars: CrosshairRect[] } {\n const k = unitsPerPx;\n const arm = ARM * k, gap = GAP * k, t = THICK * k, h = HALO * k;\n const bars: CrosshairRect[] = [\n { x: x - gap - arm, y: y - t / 2, w: arm, h: t },\n { x: x + gap, y: y - t / 2, w: arm, h: t },\n { x: x - t / 2, y: y - gap - arm, w: t, h: arm },\n { x: x - t / 2, y: y + gap, w: t, h: arm },\n ];\n const halo = bars.map((b) => ({ x: b.x - h, y: b.y - h, w: b.w + 2 * h, h: b.h + 2 * h }));\n return { halo, bars };\n}\n\n/**\n * A crosshair at the pointer's world point, in each of `views` the pointer is\n * not over — the other side of a linked cursor. A fixed screen size in every\n * view. `views` omitted paints in every view.\n */\nexport function createLinkedCursorLayer(opts: {\n id: string;\n pointer: () => PointerWorldPos;\n color: () => string;\n views?: readonly (string | null)[];\n}): RenderLayer<unknown> {\n const { id, pointer, color, views } = opts;\n return {\n id,\n label: 'Linked cursor',\n draw: (data, view: View): DrawCommand[] => {\n const p = pointer();\n const here = viewIdOf(data);\n if (!p || p.viewId === here || (views && !views.includes(here))) return [];\n const { halo, bars } = crosshairRects(p.worldX, p.worldY, 1 / view.scale.x);\n const rect = (r: CrosshairRect, c: string): DrawCommand => ({\n kind: 'path',\n path: { kind: 'rect', x: r.x, y: r.y, width: r.w, height: r.h },\n fill: { fill: 'solid', color: c },\n });\n const accent = color();\n return [\n ...halo.map((r) => rect(r, CROSSHAIR_HALO)),\n ...bars.map((r) => rect(r, accent)),\n ];\n },\n };\n}\n","/**\n * A minimap over a `<SceneCanvas>`, written as one `SurfaceContribution`: a\n * view through a fit camera, the pan that moves the main camera from inside\n * it, the visible-rect indicator, and a linked crosshair.\n */\nimport type { Dims, RenderLayer } from '@weasel-js/core';\nimport type { View } from '@weasel-js/core';\nimport type { Scene } from '@weasel-js/core';\nimport type { PoseDescriptor } from '@weasel-js/core';\nimport { AUTO_POSE_DESCRIPTOR } from '@weasel-js/core';\nimport type { PointerWorldPos } from '@weasel-js/routing/react';\nimport type { CanvasExtensionApi } from '@weasel-js/core';\nimport type { ViewRect } from '@weasel-js/core';\nimport type { ContributionDepReader, SurfaceContribution } from '@weasel-js/core';\nimport {\n computeFitView, FALLBACK_FIT_VIEW, type IndicatorStyle, type MinimapFit,\n} from './minimapMath';\nimport {\n MINIMAP_CENTER, MINIMAP_PAN, minimapCenterAction, minimapPanAction,\n} from './actions';\nimport { createIndicatorLayer, createLinkedCursorLayer } from './layers';\nimport { accentColorOf, FALLBACK_ACCENT } from '@weasel-js/core';\n\n\n/**\n * The linked crosshair's live half: follows the pointer store, and asks the\n * surface to repaint whenever the crosshair shows, moves, or has just hidden.\n * `ownViews` are the view ids this surface paints; the crosshair shows in any\n * of them the pointer is not over.\n */\nfunction linkedCursor(id: string, ownViews: readonly (string | null)[]) {\n let pointer: PointerWorldPos = null;\n let color = FALLBACK_ACCENT;\n const visible = (p: PointerWorldPos): boolean =>\n p !== null && ownViews.some((v) => v !== p.viewId);\n const layer = createLinkedCursorLayer({ id, pointer: () => pointer, color: () => color, views: ownViews });\n const attach = (api: CanvasExtensionApi, deps: ContributionDepReader): (() => void) => {\n const store = deps.get('pointer');\n if (!store) return () => {};\n color = accentColorOf(api.element);\n pointer = store.get();\n const off = store.subscribe(() => {\n const prev = pointer;\n pointer = store.get();\n if (visible(prev) || visible(pointer)) api.requestRedraw();\n });\n return () => {\n off();\n pointer = null;\n api.requestRedraw();\n };\n };\n return { layer, attach };\n}\n\n/** Options for {@link createLinkedCursorContribution}. */\nexport interface LinkedCursorOptions {\n /** Entry id. Default `'linked-cursor'`. */\n id?: string;\n /** Views on this surface the crosshair may paint in. Default `[null]`, the\n * surface's own camera — the main canvas beside a detached minimap. */\n views?: readonly (string | null)[];\n}\n\n/**\n * The linked crosshair alone: this surface paints the pointer's position\n * whenever the pointer is over some other view — another surface under the\n * same `<PointerContextProvider>`, such as a detached `<MinimapCanvas>`.\n *\n * A surface carrying `createMinimapContribution` already has one, in both its\n * views; this is for a surface without.\n */\nexport function createLinkedCursorContribution(opts: LinkedCursorOptions = {}): SurfaceContribution {\n const id = opts.id ?? 'linked-cursor';\n const cursor = linkedCursor(id, opts.views ?? [null]);\n return { id, eligibility: { always: true }, overlay: cursor.layer, attach: cursor.attach };\n}\n\n/** Options for {@link createMinimapContribution}. */\nexport interface MinimapContributionOptions<TData = unknown, TLayer extends string = string, TPose = unknown> {\n /** View and entry id. Default `'minimap'`. */\n id?: string;\n /** Where the minimap paints, in CSS pixels from the canvas top-left. A\n * function is re-read every frame, so it can follow the canvas's size. */\n rect: ViewRect | ((outer: View, dims: Dims) => ViewRect);\n /** What the minimap frames. Default `'scene'`, the union of leaf poses. */\n fit?: MinimapFit<TData, TLayer, TPose>;\n /** The surface layers the minimap paints. Default: all of them. */\n layers?: (surface: readonly RenderLayer<unknown>[]) => readonly RenderLayer<unknown>[];\n /** Ground painted before the minimap's layers, so the main canvas does not\n * show through. */\n background?: string;\n /** The visible-rect indicator's stroke. */\n indicatorStyle?: IndicatorStyle;\n}\n\nconst DEFAULT_BACKGROUND = '#18181c';\n\n/**\n * A minimap inside a `<SceneCanvas>`, installed with one entry:\n *\n * ```tsx\n * const minimap = useMemo(() => createMinimapContribution({ rect: { x: 8, y: 8, w: 160, h: 110 } }), []);\n * <SceneCanvas ambient={[minimap]} … />\n * ```\n *\n * Press in it to center the main camera on that point, drag to keep it there.\n * It shows the main camera's visible rect, and a crosshair where the pointer is\n * over the other view. Build it once — each instance keeps the live state its\n * layers read.\n */\nexport function createMinimapContribution<TData = unknown, TLayer extends string = string, TPose = unknown>(\n opts: MinimapContributionOptions<TData, TLayer, TPose>,\n): SurfaceContribution {\n const id = opts.id ?? 'minimap';\n const fit = (opts.fit ?? 'scene') as MinimapFit<unknown, string, unknown>;\n let deps: ContributionDepReader | null = null;\n\n // The fit follows the scene, so it is recomputed only when the scene's\n // version or the minimap's size changes — it is read on every frame and\n // every event.\n let cached: { scene: unknown; version: number; w: number; h: number; view: View } | null = null;\n const fitCamera = (outer: View, dims: Dims): View => {\n const scene = deps?.get('scene') as Scene<unknown, string, unknown> | undefined;\n if (!scene) return FALLBACK_FIT_VIEW;\n const r = typeof opts.rect === 'function' ? opts.rect(outer, dims) : opts.rect;\n const version = scene.getVersion();\n if (cached && cached.scene === scene && cached.version === version && cached.w === r.w && cached.h === r.h) {\n return cached.view;\n }\n const descriptor = (deps?.get('poseDescriptor') ?? AUTO_POSE_DESCRIPTOR) as PoseDescriptor<unknown>;\n const view = computeFitView(scene, { width: r.w, height: r.h }, fit, descriptor);\n cached = { scene, version, w: r.w, h: r.h, view };\n return view;\n };\n\n const cursor = linkedCursor(`${id}.cursor`, [null, id]);\n const indicator = createIndicatorLayer({\n viewId: id,\n root: () => deps?.get('rootView'),\n ...(opts.indicatorStyle ? { style: opts.indicatorStyle } : {}),\n });\n\n return {\n id,\n eligibility: { always: true },\n views: [{\n id,\n bounds: opts.rect,\n view: fitCamera,\n interactive: true,\n background: opts.background ?? DEFAULT_BACKGROUND,\n ...(opts.layers ? { layers: opts.layers } : {}),\n }],\n actions: [minimapCenterAction(), minimapPanAction()],\n bindings: [\n { spec: { kind: 'pointerDown' }, actionId: MINIMAP_CENTER, opts: { views: [id] } },\n { spec: { kind: 'drag' }, actionId: MINIMAP_PAN, opts: { views: [id] } },\n ],\n overlay: [indicator, cursor.layer],\n attach: (api, reader) => {\n deps = reader;\n const detachCursor = cursor.attach(api, reader);\n // The fit camera had no scene until now.\n api.requestRedraw();\n return () => {\n detachCursor();\n deps = null;\n cached = null;\n };\n },\n };\n}\n","/**\n * `<MinimapCanvas>` — opinionated minimap on a canvas of its own, built on\n * `<SceneViewCanvas>`.\n *\n * Renders the same `scene` the main canvas is showing, through a derived\n * \"fit\" view, and overlays a dashed visible-window indicator showing where\n * the main canvas is currently looking. Press anywhere in the minimap to\n * recenter the main view on that world point; drag to pan continuously.\n *\n * Input runs on a dispatcher of its own, through the same `minimap.center` /\n * `minimap.pan` actions the in-surface minimap (`createMinimapContribution`)\n * binds. It publishes its pointer into the pointer store in scope, and draws a\n * crosshair wherever that store says the pointer is on another surface — put\n * one `<PointerContextProvider>` around it and the main canvas for linked\n * cursors both ways.\n */\nimport {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useSyncExternalStore,\n} from 'react';\nimport type { Ref } from 'react';\nimport {\n ActionsProvider,\n ActiveToolContextProvider,\n DepRegistryProvider,\n useActionsRegistry,\n useDepSource,\n useGestureDispatcher,\n} from '@weasel-js/routing/react';\nimport { assignRef, useLatest } from '@weasel-js/react';\nimport type { Tool } from '@weasel-js/routing';\nimport { PointerProviderIfRoot } from '@weasel-js/core';\nimport { usePointerContext, usePointerPosition } from '@weasel-js/routing/react';\nimport {\n MINIMAP_CENTER, MINIMAP_PAN, minimapCenterAction, minimapPanAction,\n} from './actions';\nimport { createLinkedCursorLayer } from './layers';\nimport type { ViewApi } from '@weasel-js/core';\nimport { SceneViewCanvas } from '@weasel-js/core';\nimport {\n computeFitView,\n computeIndicatorCommand,\n} from './minimapMath';\nimport type { IndicatorStyle, MinimapFit } from './minimapMath';\nimport type { SceneViewDrawOne, SceneViewLayers } from '@weasel-js/core';\nimport type { DrawCommand } from '@weasel-js/core';\nimport { normalizeView, type View } from '@weasel-js/core';\nimport type { Scene } from '@weasel-js/core';\nimport type { PoseDescriptor } from '@weasel-js/core';\nimport type { Animator } from '@weasel-js/core';\nimport { AUTO_POSE_DESCRIPTOR } from '@weasel-js/core';\nimport { accentColorOf } from '@weasel-js/core';\n\n/** Props for `<MinimapCanvas>`. */\nexport interface MinimapCanvasProps<TData, TLayer extends string, TPose> {\n /** Same scene the main canvas is rendering. */\n scene: Scene<TData, TLayer, TPose>;\n /** Main canvas's view — used to position the visible-window indicator and\n * to preserve `scale` when the minimap recenters. */\n mainView: View;\n /** Main canvas's CSS-pixel dims. Used to compute the visible-window rect\n * and the recenter offset. */\n mainViewDims: { width: number; height: number };\n /** Setter called on click (single recenter) and during drag (continuous\n * recenter). Receives a `View` with the same `scale` as `mainView` and\n * `(x, y)` shifted so the pointer's world point lands at the main\n * canvas's center. */\n onMainViewChange: (next: View) => void;\n /** Minimap's own CSS-pixel dims. */\n width: number;\n height: number;\n /** Consumer's draw callback. Applied through the derived fit view; same\n * signature as `<SceneCanvas>`'s scene-slot `drawOne` so the consumer\n * can reuse it (typically simplified — just colored AABBs). */\n drawOne: SceneViewDrawOne<TData, TLayer, TPose>;\n /** Fit policy. Defaults to `\"scene\"` (AABB union of leaf poses). See\n * `MinimapFit` for the full shape.\n *\n * Framing is derived from **document** poses, not `scene.overrides` — a\n * node moved by an override paints where the override puts it, outside the\n * frame if it goes there, rather than making the whole minimap rescale on\n * every frame of a drag or a settle. */\n fit?: MinimapFit<TData, TLayer, TPose>;\n /** How to read poses. Default `AUTO_POSE_DESCRIPTOR`. */\n poseDescriptor?: PoseDescriptor<TPose>;\n /** Optional per-id alpha multiplier, mirroring `<SceneCanvas>`'s scene-slot\n * `alphaFor`. Pass the same function the main canvas uses so a\n * scoping-dim treatment shows up in the minimap too. */\n alphaFor?: (id: string) => number;\n /** Hide scene layers in the minimap, keyed `scene:<layerId>` as on\n * `<SceneCanvas>` — pass the main canvas's map so both show the same set. */\n layerVisibility?: SceneViewLayers['layerVisibility'];\n /** Paint order for the minimap, keyed as `layerVisibility`. */\n layerOrder?: SceneViewLayers['layerOrder'];\n /** Optional animator: the minimap repaints on its ticks and paints its\n * `colorOverrides`. Pass the main canvas's animator so both show the same\n * colors. */\n animator?: Animator;\n /** Visual tuning of the indicator stroke. */\n indicatorStyle?: IndicatorStyle;\n /** CSS class for positioning the canvas. Its size is `width` × `height`. */\n className?: string;\n /** Forwarded ref to the underlying `<canvas>`. */\n canvasRef?: Ref<HTMLCanvasElement>;\n /** The view id this minimap publishes its pointer under. Default\n * `'minimap'`. */\n id?: string;\n}\n\n/** The minimap's own bindings. Unscoped: this dispatcher routes no views, so\n * every input on it is the minimap's. */\nconst MINIMAP_INPUT: Tool = {\n id: 'minimap',\n eligibility: { always: true },\n bindings: [\n { spec: { kind: 'pointerDown' }, actionId: MINIMAP_CENTER },\n { spec: { kind: 'drag' }, actionId: MINIMAP_PAN },\n ],\n};\nconst TOOLS_BY_ID: ReadonlyMap<string, Tool> = new Map([[MINIMAP_INPUT.id, MINIMAP_INPUT]]);\nconst CHANNELS = { wheel: false, pinch: false, contextMenu: false, ingest: false } as const;\n\nfunction MinimapCanvasInner<TData, TLayer extends string, TPose>(\n props: MinimapCanvasProps<TData, TLayer, TPose>,\n) {\n const {\n scene,\n mainView: mainViewProp,\n mainViewDims,\n onMainViewChange,\n width,\n height,\n drawOne,\n alphaFor,\n layerVisibility,\n layerOrder,\n animator,\n fit = 'scene',\n poseDescriptor,\n indicatorStyle,\n className,\n canvasRef,\n id = 'minimap',\n } = props;\n const mainView = normalizeView(mainViewProp);\n\n // Subscribe to scene version so the fit view recomputes when the scene\n // mutates. `<SceneViewCanvas>` also subscribes, but it owns its own\n // rendering; we need the version *here* to invalidate the memoized fit.\n const sceneVersion = useSyncExternalStore(\n scene.subscribe,\n scene.getVersion,\n scene.getVersion,\n );\n\n const descriptor = (poseDescriptor ?? AUTO_POSE_DESCRIPTOR) as PoseDescriptor<TPose>;\n\n const fitView = useMemo<View>(() => {\n // A `fit` function's result is the caller's; pointer math divides by its scale.\n return normalizeView(computeFitView(scene, { width, height }, fit, descriptor));\n // `sceneVersion` participates so the memo re-evaluates after scene mutations.\n // `descriptor` is stable when the prop is omitted.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [scene, sceneVersion, width, height, fit, descriptor]);\n\n const indicatorCmd = useMemo<DrawCommand>(() => {\n return computeIndicatorCommand(mainView, mainViewDims, indicatorStyle, fitView);\n }, [mainView, mainViewDims, indicatorStyle, fitView]);\n\n // -------------------------------------------------------------------------\n // Input\n // -------------------------------------------------------------------------\n //\n // The \"latest\" pattern (refs holding the current mainView / dims / setter\n // / fitView) lets the dep and the listeners read up-to-date values without\n // re-binding every frame.\n\n const localCanvasRef = useRef<HTMLCanvasElement | null>(null);\n const mainViewRef = useLatest(mainView);\n const mainViewDimsRef = useLatest(mainViewDims);\n const onMainViewChangeRef = useLatest(onMainViewChange);\n const fitViewRef = useLatest(fitView);\n\n // The main canvas's camera, which is what the minimap's actions move.\n const rootView = useMemo<ViewApi>(() => ({\n get: () => mainViewRef.current,\n set: (v) => onMainViewChangeRef.current(v),\n hostSize: () => mainViewDimsRef.current,\n }), [mainViewRef, onMainViewChangeRef, mainViewDimsRef]);\n useDepSource('rootView', () => rootView);\n\n const actions = useActionsRegistry();\n useEffect(() => {\n if (!actions) return;\n const off = [actions.register(minimapCenterAction()), actions.register(minimapPanAction())];\n return () => { for (const u of off) u(); };\n }, [actions]);\n\n /** Client point → world, through the fit camera. */\n const clientToWorld = useCallback((cx: number, cy: number) => {\n const rect = localCanvasRef.current?.getBoundingClientRect();\n const fv = fitViewRef.current;\n return {\n x: fv.x + (cx - (rect?.left ?? 0)) / fv.scale.x,\n y: fv.y + (cy - (rect?.top ?? 0)) / fv.scale.y,\n };\n }, [fitViewRef]);\n\n useGestureDispatcher({\n canvasRef: localCanvasRef,\n actions: actions!,\n entriesById: TOOLS_BY_ID,\n clientToWorld,\n keyboard: false,\n channels: CHANNELS,\n });\n\n // -------------------------------------------------------------------------\n // Linked cursor\n // -------------------------------------------------------------------------\n\n const pointerStore = usePointerContext();\n useEffect(() => {\n const el = localCanvasRef.current;\n if (!el || !pointerStore) return;\n const onMove = (e: PointerEvent): void => {\n const w = clientToWorld(e.clientX, e.clientY);\n pointerStore.set({ worldX: w.x, worldY: w.y, viewId: id });\n };\n const onLeave = (e: PointerEvent): void => {\n if (e.buttons !== 0) return;\n if (pointerStore.get()?.viewId === id) pointerStore.set(null);\n };\n el.addEventListener('pointermove', onMove);\n el.addEventListener('pointerleave', onLeave);\n return () => {\n el.removeEventListener('pointermove', onMove);\n el.removeEventListener('pointerleave', onLeave);\n };\n }, [pointerStore, clientToWorld, id]);\n\n const pointer = usePointerPosition();\n const cursorLayer = useMemo(() => createLinkedCursorLayer({\n id: `${id}.cursor`,\n pointer: () => pointer,\n color: () => accentColorOf(localCanvasRef.current),\n }), [id, pointer]);\n\n const extraCommands = useMemo<DrawCommand[]>(() => [\n indicatorCmd,\n ...cursorLayer.draw({ viewId: id }, fitView, { width, height }),\n ], [indicatorCmd, cursorLayer, id, fitView, width, height]);\n\n // `<SceneViewCanvas>` doesn't expose its element except via `canvasRef`, so\n // we route both our internal ref and the consumer's ref through one setter.\n const setCanvasRef = useCallback((el: HTMLCanvasElement | null) => {\n localCanvasRef.current = el;\n assignRef(canvasRef, el);\n }, [canvasRef]);\n\n return (\n <SceneViewCanvas\n scene={scene}\n view={fitView}\n width={width}\n height={height}\n drawOne={drawOne}\n extraCommands={extraCommands}\n alphaFor={alphaFor}\n layerVisibility={layerVisibility}\n layerOrder={layerOrder}\n animator={animator}\n className={className}\n canvasRef={setCanvasRef}\n />\n );\n}\n\n/**\n * Opinionated minimap. See `MinimapCanvasProps` for the full surface and\n * the module docstring for the rendering / input model.\n *\n * Its dispatcher, actions and deps are its own, so it never competes with\n * the main canvas for input. The pointer store is shared when one is in scope.\n *\n * `forwardRef` is not used because the component is generic over\n * `<TData, TLayer, TPose>` and React's `forwardRef` erases generics. The\n * `canvasRef` prop is the plain-prop equivalent.\n */\nexport function MinimapCanvas<TData, TLayer extends string, TPose>(\n props: MinimapCanvasProps<TData, TLayer, TPose>,\n) {\n return (\n <DepRegistryProvider>\n <ActionsProvider>\n <ActiveToolContextProvider>\n <PointerProviderIfRoot>\n <MinimapCanvasInner {...props} />\n </PointerProviderIfRoot>\n </ActiveToolContextProvider>\n </ActionsProvider>\n </DepRegistryProvider>\n );\n}\n"]}
1
+ {"version":3,"sources":["../src/minimapMath.ts","../src/actions.ts","../src/layers.ts","../src/createMinimapContribution.ts","../src/useFitView.ts","../src/MinimapCanvas.tsx"],"names":["normalizeView","AUTO_POSE_DESCRIPTOR","useMemo","accentColorOf"],"mappings":"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","file":"index.js","sourcesContent":["/** Pure math helpers for `<MinimapCanvas>`: no GL, DOM, or renderer. */\nimport { documentPose, effectivePose } from '@weasel-js/core';\nimport type { Scene } from '@weasel-js/core';\nimport type { View } from '@weasel-js/core';\nimport type { Bounds, ViewportDims } from '@weasel-js/core';\nimport { poseDescriptorForNode, type PoseDescriptor } from '@weasel-js/core';\nimport type { PathDrawCommand } from '@weasel-js/core';\n\n/** Inset (CSS px) around the fit rect on each side. Matches the spec note. */\nconst DEFAULT_FIT_PADDING = 8;\n\n/** Fallback view returned when there is nothing to fit (empty scene, etc.). */\nexport const FALLBACK_FIT_VIEW: View = { x: 0, y: 0, scale: { x: 1, y: 1 } };\n\n/**\n * Fit policy for `<MinimapCanvas>` / `computeFitView`.\n *\n * - `\"scene\"` — union of leaf-node pose AABBs (via the pose descriptor), read\n * from the document: a pose override moves what is painted and not the frame.\n * - `\"live\"` — the same union over the poses being shown, overrides included,\n * so the frame follows a drag, a settle, or a simulation writing overrides.\n * Refit on every override publish, which is a sweep of every leaf and\n * rescales the whole minimap while one moves past the edge.\n * - `{ kind: \"world\", rect }` — caller-supplied world rect.\n * - `(scene, dims) => View` — caller derives the view directly.\n */\nexport type MinimapFit<TData, TLayer extends string, TPose> =\n | 'scene'\n | 'live'\n | { kind: 'world'; rect: Bounds }\n | ((scene: Scene<TData, TLayer, TPose>, dims: ViewportDims) => View);\n\n/** Style for the visible-window indicator rect drawn over the minimap. */\nexport interface IndicatorStyle {\n /** Stroke color (any CSS color). Defaults to `'#ffffff'`. */\n stroke?: string;\n /** Stroke width in CSS px. Defaults to `1`. */\n width?: number;\n /** Dash pattern in CSS px. Defaults to `[2, 3]`. */\n dash?: number[];\n}\n\nconst DEFAULT_INDICATOR_STROKE = '#ffffff';\nconst DEFAULT_INDICATOR_WIDTH = 1;\nconst DEFAULT_INDICATOR_DASH: readonly number[] = [2, 3];\n\n/** Internal: fit a world rect uniformly into dims with padding. */\nfunction fitRectInto(rect: Bounds, dims: ViewportDims, padding: number): View {\n const availW = Math.max(1, dims.width - padding * 2);\n const availH = Math.max(1, dims.height - padding * 2);\n const hasW = rect.width > 0;\n const hasH = rect.height > 0;\n if (!hasW && !hasH) {\n return {\n x: rect.x - dims.width / 2,\n y: rect.y - dims.height / 2,\n scale: { x: 1, y: 1 },\n };\n }\n const s = Math.min(\n hasW ? availW / rect.width : Infinity,\n hasH ? availH / rect.height : Infinity,\n );\n const worldCx = rect.x + Math.max(0, rect.width) / 2;\n const worldCy = rect.y + Math.max(0, rect.height) / 2;\n return {\n x: worldCx - dims.width / (2 * s),\n y: worldCy - dims.height / (2 * s),\n scale: { x: s, y: s },\n };\n}\n\n/**\n * Compute the AABB union of all leaf-node poses in the scene, via\n * `descriptor`. Container nodes are skipped — their effective bounds come\n * from their descendant leaves, and so is a leaf whose bounds are not finite,\n * which would otherwise make the whole union non-finite. Returns `null` when\n * the scene has no leaf with bounds.\n */\nfunction sceneLeafBounds<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n descriptor: PoseDescriptor<TPose>,\n poseOf: typeof documentPose,\n): Bounds | null {\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n let any = false;\n for (const node of scene.nodes.values()) {\n if (node.kind !== 'leaf') continue;\n const b = poseDescriptorForNode(descriptor, node).getBounds(poseOf(scene, node));\n if (!Number.isFinite(b.x + b.y + b.width + b.height)) continue;\n if (b.x < minX) minX = b.x;\n if (b.y < minY) minY = b.y;\n const right = b.x + b.width;\n const bottom = b.y + b.height;\n if (right > maxX) maxX = right;\n if (bottom > maxY) maxY = bottom;\n any = true;\n }\n if (!any) return null;\n return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };\n}\n\n/** Options for {@link computeFitView}. */\nexport interface ComputeFitViewOptions {\n /** Inset (CSS px) around the fit rect on each side. Defaults to `8`. */\n padding?: number;\n}\n\n/**\n * Derive a `View` that fits the chosen world rect into a minimap of\n * `dims.width × dims.height` CSS px. Uniform scale on both axes; the rect\n * is centered with `padding` (default 8) on each side. The smaller-axis\n * fit ratio wins, so the whole rect is visible. An empty scene gives\n * {@link FALLBACK_FIT_VIEW}; a function `fit` is passed through unchanged.\n *\n * A rect with one zero axis (a line) is fitted along the other. One with no\n * positive axis falls back to identity scale centered on its top-left.\n */\nexport function computeFitView<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n dims: ViewportDims,\n fit: MinimapFit<TData, TLayer, TPose>,\n descriptor: PoseDescriptor<TPose>,\n opts: ComputeFitViewOptions = {},\n): View {\n const padding = opts.padding ?? DEFAULT_FIT_PADDING;\n\n if (typeof fit === 'function') {\n return fit(scene, dims);\n }\n if (fit === 'scene' || fit === 'live') {\n const rect = sceneLeafBounds(scene, descriptor, fit === 'live' ? effectivePose : documentPose);\n if (rect === null) return FALLBACK_FIT_VIEW;\n return fitRectInto(rect, dims, padding);\n }\n // { kind: 'world', rect }\n return fitRectInto(fit.rect, dims, padding);\n}\n\n/**\n * Build the visible-window indicator `DrawCommand` for the minimap: the main\n * canvas's visible world rect as a dashed-stroke `path` rect with no fill, in\n * world coordinates. Pass the `minimapView` it will be drawn through, so the\n * stroke width and dash come out in CSS px at any fit scale; without it they\n * are in world units.\n */\nexport function computeIndicatorCommand(\n mainView: View,\n mainViewDims: ViewportDims,\n style: IndicatorStyle = {},\n minimapView?: View,\n): PathDrawCommand {\n // World-space rect, returned as-is: the caller wraps the command list in a\n // group transformed by the minimap's view, and screen coords here would get\n // that transform applied a second time.\n const x = mainView.x;\n const y = mainView.y;\n const width = mainViewDims.width / mainView.scale.x;\n const height = mainViewDims.height / mainView.scale.y;\n const px = minimapView ? 1 / Math.abs(minimapView.scale.x) : 1;\n return {\n kind: 'path',\n path: { kind: 'rect', x, y, width, height },\n stroke: {\n paint: { kind: 'solid', color: style.stroke ?? DEFAULT_INDICATOR_STROKE },\n width: (style.width ?? DEFAULT_INDICATOR_WIDTH) * px,\n dash: (style.dash ?? DEFAULT_INDICATOR_DASH).map((d) => d * px),\n },\n };\n}\n","/**\n * The minimap's input: press to recenter the main camera on a world point,\n * drag to keep it there. Both read `rootView` — never `view`, which inside the\n * minimap's own view answers the minimap's camera.\n */\nimport type { Action, InvocationCtx, OngoingHandle } from '@weasel-js/routing';\nimport type { ViewApi } from '@weasel-js/core';\n\n/** Action id for `minimapCenterAction`. */\nexport const MINIMAP_CENTER = 'minimap.center';\n/** Action id for `minimapPanAction`. */\nexport const MINIMAP_PAN = 'minimap.pan';\n\n/** Move `root` so world point (`x`, `y`) sits at the center of its host,\n * keeping its scale. A no-op while the host is unmeasured. */\nexport function centerRootOn(root: ViewApi, x: number, y: number): void {\n const size = root.hostSize?.();\n if (!size) return;\n const v = root.get();\n root.set({\n x: x - size.width / (2 * v.scale.x),\n y: y - size.height / (2 * v.scale.y),\n scale: v.scale,\n });\n}\n\nfunction rootOf(deps: InvocationCtx['deps']): ViewApi | undefined {\n return deps.rootView;\n}\n\n/** Recenter the main camera on the pressed world point. */\nexport function minimapCenterAction(): Action {\n return {\n id: MINIMAP_CENTER,\n label: 'Minimap — center the view here',\n requires: ['rootView'],\n invoker: {\n timing: 'immediate',\n run: (deps, params) => {\n const p = params as { worldX?: number; worldY?: number } | undefined;\n const root = rootOf(deps);\n if (!root || p?.worldX === undefined || p.worldY === undefined) return;\n centerRootOn(root, p.worldX, p.worldY);\n },\n },\n };\n}\n\n/** Keep the main camera centered on the pointer's world point while dragging.\n * Pair it with `minimap.center` on `pointerDown`, which handles the press.\n * A recenter lands the moment it is computed, so there is nothing to commit\n * and a cancel ends where a release does. */\nexport function minimapPanAction(): Action {\n return {\n id: MINIMAP_PAN,\n label: 'Minimap — pan the view',\n requires: ['rootView'],\n invoker: {\n timing: 'ongoing',\n start(ctx: InvocationCtx): OngoingHandle {\n const root = rootOf(ctx.deps);\n if (!root) return {};\n // The press already centered (`minimap.center`); the move that crossed\n // the drag threshold is pumped to `onMove` like every later one.\n return {\n onMove: (m) => {\n const p = m.drag?.current ?? m.world;\n centerRootOn(root, p.x, p.y);\n },\n onEnd: () => {},\n };\n },\n },\n };\n}\n","/**\n * The minimap's chrome: the main camera's visible rect, drawn in the minimap,\n * and the linked crosshair, drawn in every view the pointer is not over.\n */\nimport type { RenderLayer } from '@weasel-js/core';\nimport type { View } from '@weasel-js/core';\nimport type { DrawCommand } from '@weasel-js/core';\nimport type { ViewApi } from '@weasel-js/core';\nimport type { PointerWorldPos } from '@weasel-js/routing/react';\nimport { computeIndicatorCommand, type IndicatorStyle } from './minimapMath';\n\n/** What a layer's `data` carries for this feature: the view it draws for. */\nfunction viewIdOf(data: unknown): string | null {\n return (data as { viewId?: string | null } | null)?.viewId ?? null;\n}\n\n/**\n * The main camera's visible world rect, painted only in view `viewId`. Its\n * stroke and dash are screen pixels whatever the minimap's scale.\n */\nexport function createIndicatorLayer(opts: {\n viewId: string;\n root: () => ViewApi | undefined;\n style?: IndicatorStyle;\n}): RenderLayer<unknown> {\n const { viewId, root, style = {} } = opts;\n return {\n id: `${viewId}.indicator`,\n label: 'Minimap indicator',\n draw: (data, view: View): DrawCommand[] => {\n if (viewIdOf(data) !== viewId) return [];\n const r = root();\n const size = r?.hostSize?.();\n if (!r || !size) return [];\n return [computeIndicatorCommand(r.get(), size, style, view)];\n },\n };\n}\n\n/** Screen-pixel geometry of the crosshair: arm length, the gap at its center,\n * line thickness, and the dark halo that keeps it legible over any content. */\nconst ARM = 9;\nconst GAP = 3;\nconst THICK = 2;\nconst HALO = 1;\n/** The halo's color: dark enough to separate the accent from any content. */\nexport const CROSSHAIR_HALO = 'rgba(0, 0, 0, 0.6)';\n\n/** An axis-aligned rect, `{ x, y, w, h }`. */\nexport interface CrosshairRect { x: number; y: number; w: number; h: number }\n\n/**\n * The linked crosshair at (`x`, `y`) as rects in the caller's units, where one\n * screen pixel is `unitsPerPx` of them: four halo rects to paint first, then\n * four bars. A painter with no weasel renderer — a 2D canvas — draws the same\n * crosshair from these.\n */\nexport function crosshairRects(\n x: number, y: number, unitsPerPx: number,\n): { halo: CrosshairRect[]; bars: CrosshairRect[] } {\n const k = unitsPerPx;\n const arm = ARM * k, gap = GAP * k, t = THICK * k, h = HALO * k;\n const bars: CrosshairRect[] = [\n { x: x - gap - arm, y: y - t / 2, w: arm, h: t },\n { x: x + gap, y: y - t / 2, w: arm, h: t },\n { x: x - t / 2, y: y - gap - arm, w: t, h: arm },\n { x: x - t / 2, y: y + gap, w: t, h: arm },\n ];\n const halo = bars.map((b) => ({ x: b.x - h, y: b.y - h, w: b.w + 2 * h, h: b.h + 2 * h }));\n return { halo, bars };\n}\n\n/**\n * A crosshair at the pointer's world point, in each of `views` the pointer is\n * not over — the other side of a linked cursor. A fixed screen size in every\n * view. `views` omitted paints in every view.\n */\nexport function createLinkedCursorLayer(opts: {\n id: string;\n pointer: () => PointerWorldPos;\n color: () => string;\n views?: readonly (string | null)[];\n}): RenderLayer<unknown> {\n const { id, pointer, color, views } = opts;\n return {\n id,\n label: 'Linked cursor',\n draw: (data, view: View): DrawCommand[] => {\n const p = pointer();\n const here = viewIdOf(data);\n if (!p || p.viewId === here || (views && !views.includes(here))) return [];\n const { halo, bars } = crosshairRects(p.worldX, p.worldY, 1 / view.scale.x);\n const rect = (r: CrosshairRect, c: string): DrawCommand => ({\n kind: 'path',\n path: { kind: 'rect', x: r.x, y: r.y, width: r.w, height: r.h },\n fill: { paint: { kind: 'solid', color: c } },\n });\n const accent = color();\n return [\n ...halo.map((r) => rect(r, CROSSHAIR_HALO)),\n ...bars.map((r) => rect(r, accent)),\n ];\n },\n };\n}\n","/**\n * A minimap over a `<SceneCanvas>`, written as one `SurfaceContribution`: a\n * view through a fit camera, the pan that moves the main camera from inside\n * it, the visible-rect indicator, and a linked crosshair.\n */\nimport type { Dims, RenderLayer } from '@weasel-js/core';\nimport type { View } from '@weasel-js/core';\nimport type { Scene } from '@weasel-js/core';\nimport type { PoseDescriptor } from '@weasel-js/core';\nimport { AUTO_POSE_DESCRIPTOR } from '@weasel-js/core';\nimport type { PointerWorldPos } from '@weasel-js/routing/react';\nimport type { CanvasExtensionApi } from '@weasel-js/core';\nimport type { ViewRect } from '@weasel-js/core';\nimport type { ContributionDepReader, SurfaceContribution } from '@weasel-js/core';\nimport {\n computeFitView, FALLBACK_FIT_VIEW, type IndicatorStyle, type MinimapFit,\n} from './minimapMath';\nimport {\n MINIMAP_CENTER, MINIMAP_PAN, minimapCenterAction, minimapPanAction,\n} from './actions';\nimport { createIndicatorLayer, createLinkedCursorLayer } from './layers';\nimport { accentColorOf, FALLBACK_ACCENT } from '@weasel-js/core';\n\n\n/**\n * The linked crosshair's live half: follows the pointer store, and asks the\n * surface to repaint whenever the crosshair shows, moves, or has just hidden.\n * `ownViews` are the view ids this surface paints; the crosshair shows in any\n * of them the pointer is not over.\n */\nfunction linkedCursor(id: string, ownViews: readonly (string | null)[]) {\n let pointer: PointerWorldPos = null;\n let color = FALLBACK_ACCENT;\n const visible = (p: PointerWorldPos): boolean =>\n p !== null && ownViews.some((v) => v !== p.viewId);\n const layer = createLinkedCursorLayer({ id, pointer: () => pointer, color: () => color, views: ownViews });\n const attach = (api: CanvasExtensionApi, deps: ContributionDepReader): (() => void) => {\n const store = deps.get('pointer');\n if (!store) return () => {};\n color = accentColorOf(api.element);\n pointer = store.get();\n const off = store.subscribe(() => {\n const prev = pointer;\n pointer = store.get();\n if (visible(prev) || visible(pointer)) api.requestRedraw();\n });\n return () => {\n off();\n pointer = null;\n api.requestRedraw();\n };\n };\n return { layer, attach };\n}\n\n/** Options for {@link createLinkedCursorContribution}. */\nexport interface LinkedCursorOptions {\n /** Entry id. Default `'linked-cursor'`. */\n id?: string;\n /** Views on this surface the crosshair may paint in. Default `[null]`, the\n * surface's own camera — the main canvas beside a detached minimap. */\n views?: readonly (string | null)[];\n}\n\n/**\n * The linked crosshair alone: this surface paints the pointer's position\n * whenever the pointer is over some other view — another surface under the\n * same `<PointerContextProvider>`, such as a detached `<MinimapCanvas>`.\n *\n * A surface carrying `createMinimapContribution` already has one, in both its\n * views; this is for a surface without.\n */\nexport function createLinkedCursorContribution(opts: LinkedCursorOptions = {}): SurfaceContribution {\n const id = opts.id ?? 'linked-cursor';\n const cursor = linkedCursor(id, opts.views ?? [null]);\n return { id, eligibility: { always: true }, overlay: cursor.layer, attach: cursor.attach };\n}\n\n/** Options for {@link createMinimapContribution}. */\nexport interface MinimapContributionOptions<TData = unknown, TLayer extends string = string, TPose = unknown> {\n /** View and entry id. Default `'minimap'`. */\n id?: string;\n /** Where the minimap paints, in CSS pixels from the canvas top-left. A\n * function is re-read every frame, so it can follow the canvas's size. */\n rect: ViewRect | ((outer: View, dims: Dims) => ViewRect);\n /** What the minimap frames. Default `'scene'`, the union of leaf poses. */\n fit?: MinimapFit<TData, TLayer, TPose>;\n /** The surface layers the minimap paints. Default: all of them. */\n layers?: (surface: readonly RenderLayer<unknown>[]) => readonly RenderLayer<unknown>[];\n /** Ground painted before the minimap's layers, so the main canvas does not\n * show through. */\n background?: string;\n /** The visible-rect indicator's stroke. */\n indicatorStyle?: IndicatorStyle;\n}\n\nconst DEFAULT_BACKGROUND = '#18181c';\n\n/**\n * A minimap inside a `<SceneCanvas>`, installed with one entry:\n *\n * ```tsx\n * const minimap = useMemo(() => createMinimapContribution({ rect: { x: 8, y: 8, w: 160, h: 110 } }), []);\n * <SceneCanvas ambient={[minimap]} … />\n * ```\n *\n * Press in it to center the main camera on that point, drag to keep it there.\n * It shows the main camera's visible rect, and a crosshair where the pointer is\n * over the other view. Build it once — each instance keeps the live state its\n * layers read.\n */\nexport function createMinimapContribution<TData = unknown, TLayer extends string = string, TPose = unknown>(\n opts: MinimapContributionOptions<TData, TLayer, TPose>,\n): SurfaceContribution {\n const id = opts.id ?? 'minimap';\n const fit = (opts.fit ?? 'scene') as MinimapFit<unknown, string, unknown>;\n let deps: ContributionDepReader | null = null;\n\n // The fit follows the scene, so it is recomputed only when the scene's\n // version or the minimap's size changes — it is read on every frame and\n // every event.\n let cached: { scene: unknown; version: number; shown: number; w: number; h: number; view: View } | null = null;\n const fitCamera = (outer: View, dims: Dims): View => {\n const scene = deps?.get('scene') as Scene<unknown, string, unknown> | undefined;\n if (!scene) return FALLBACK_FIT_VIEW;\n const r = typeof opts.rect === 'function' ? opts.rect(outer, dims) : opts.rect;\n const version = scene.getVersion();\n // Only a live fit reads overrides, so only it refits when they publish.\n const shown = fit === 'live' ? scene.overrides.getGeneration() : 0;\n if (cached && cached.scene === scene && cached.version === version && cached.shown === shown\n && cached.w === r.w && cached.h === r.h) {\n return cached.view;\n }\n const descriptor = (deps?.get('poseDescriptor') ?? AUTO_POSE_DESCRIPTOR) as PoseDescriptor<unknown>;\n const view = computeFitView(scene, { width: r.w, height: r.h }, fit, descriptor);\n cached = { scene, version, shown, w: r.w, h: r.h, view };\n return view;\n };\n\n const cursor = linkedCursor(`${id}.cursor`, [null, id]);\n const indicator = createIndicatorLayer({\n viewId: id,\n root: () => deps?.get('rootView'),\n ...(opts.indicatorStyle ? { style: opts.indicatorStyle } : {}),\n });\n\n return {\n id,\n eligibility: { always: true },\n views: [{\n id,\n bounds: opts.rect,\n view: fitCamera,\n interactive: true,\n background: opts.background ?? DEFAULT_BACKGROUND,\n ...(opts.layers ? { layers: opts.layers } : {}),\n }],\n actions: [minimapCenterAction(), minimapPanAction()],\n bindings: [\n { spec: { kind: 'pointerDown' }, actionId: MINIMAP_CENTER, opts: { views: [id] } },\n { spec: { kind: 'drag' }, actionId: MINIMAP_PAN, opts: { views: [id] } },\n ],\n overlay: [indicator, cursor.layer],\n attach: (api, reader) => {\n deps = reader;\n const detachCursor = cursor.attach(api, reader);\n // The fit camera had no scene until now.\n api.requestRedraw();\n return () => {\n detachCursor();\n deps = null;\n cached = null;\n };\n },\n };\n}\n","import { useMemo, useSyncExternalStore } from 'react';\nimport { normalizeView, type PoseDescriptor, type Scene, type View } from '@weasel-js/core';\nimport { computeFitView, type MinimapFit } from './minimapMath';\n\nconst NEVER = (): (() => void) => () => {};\n\n/**\n * The minimap's fit view, recomputed when what it frames changes: the scene's\n * version always, and the overrides only under a `\"live\"` fit, the one policy\n * that reads them.\n */\nexport function useFitView<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n width: number,\n height: number,\n fit: MinimapFit<TData, TLayer, TPose>,\n descriptor: PoseDescriptor<TPose>,\n): View {\n const sceneVersion = useSyncExternalStore(scene.subscribe, scene.getVersion, scene.getVersion);\n const overrideGeneration = useSyncExternalStore(\n fit === 'live' ? scene.overrides.subscribe : NEVER,\n scene.overrides.getGeneration,\n scene.overrides.getGeneration,\n );\n return useMemo<View>(() => {\n // A `fit` function's result is the caller's; pointer math divides by its scale.\n return normalizeView(computeFitView(scene, { width, height }, fit, descriptor));\n // The two counters are what say the scene's contents moved.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [scene, sceneVersion, overrideGeneration, width, height, fit, descriptor]);\n}\n","import {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n} from 'react';\nimport type { Ref } from 'react';\nimport {\n ActionsProvider,\n ActiveToolContextProvider,\n DepRegistryProvider,\n useActionsRegistry,\n useDepSource,\n useGestureDispatcher,\n} from '@weasel-js/routing/react';\nimport { assignRef, useLatest } from '@weasel-js/react';\nimport type { Tool } from '@weasel-js/routing';\nimport { PointerProviderIfRoot } from '@weasel-js/core';\nimport { usePointerContext, usePointerPosition } from '@weasel-js/routing/react';\nimport {\n MINIMAP_CENTER, MINIMAP_PAN, minimapCenterAction, minimapPanAction,\n} from './actions';\nimport { createLinkedCursorLayer } from './layers';\nimport type { ViewApi } from '@weasel-js/core';\nimport { SceneViewCanvas } from '@weasel-js/core';\nimport { computeIndicatorCommand } from './minimapMath';\nimport { useFitView } from './useFitView';\nimport type { IndicatorStyle, MinimapFit } from './minimapMath';\nimport type { SceneViewDrawOne, SceneViewLayers } from '@weasel-js/core';\nimport type { DrawCommand } from '@weasel-js/core';\nimport { normalizeView, type View } from '@weasel-js/core';\nimport type { Scene } from '@weasel-js/core';\nimport type { PoseDescriptor } from '@weasel-js/core';\nimport type { Animator } from '@weasel-js/animator';\nimport { AUTO_POSE_DESCRIPTOR } from '@weasel-js/core';\nimport { accentColorOf } from '@weasel-js/core';\n\n/** Props for `<MinimapCanvas>`. */\nexport interface MinimapCanvasProps<TData, TLayer extends string, TPose> {\n /** Same scene the main canvas is rendering. */\n scene: Scene<TData, TLayer, TPose>;\n /** Main canvas's view — used to position the visible-window indicator and\n * to preserve `scale` when the minimap recenters. */\n mainView: View;\n /** Main canvas's CSS-pixel dims. Used to compute the visible-window rect\n * and the recenter offset. */\n mainViewDims: { width: number; height: number };\n /** Setter called on click (single recenter) and during drag (continuous\n * recenter). Receives a `View` with the same `scale` as `mainView` and\n * `(x, y)` shifted so the pointer's world point lands at the main\n * canvas's center. */\n onMainViewChange: (next: View) => void;\n /** Minimap's own CSS-pixel dims. */\n width: number;\n height: number;\n /** Consumer's draw callback. Applied through the derived fit view; same\n * signature as `<SceneCanvas>`'s scene-slot `drawOne` so the consumer\n * can reuse it (typically simplified — just colored AABBs). */\n drawOne: SceneViewDrawOne<TData, TLayer, TPose>;\n /** Fit policy. Defaults to `\"scene\"` (AABB union of leaf poses). See\n * `MinimapFit` for the full shape.\n *\n * `\"scene\"` frames **document** poses, not `scene.overrides` — a node\n * moved by an override paints where the override puts it, outside the\n * frame if it goes there, rather than making the whole minimap rescale on\n * every frame of a drag or a settle. `\"live\"` frames the overrides too. */\n fit?: MinimapFit<TData, TLayer, TPose>;\n /** How to read poses. Default `AUTO_POSE_DESCRIPTOR`. */\n poseDescriptor?: PoseDescriptor<TPose>;\n /** Optional per-id alpha multiplier, mirroring `<SceneCanvas>`'s scene-slot\n * `alphaFor`. Pass the same function the main canvas uses so a\n * scoping-dim treatment shows up in the minimap too. */\n alphaFor?: (id: string) => number;\n /** Hide scene layers in the minimap, keyed `scene:<layerId>` as on\n * `<SceneCanvas>` — pass the main canvas's map so both show the same set. */\n layerVisibility?: SceneViewLayers['layerVisibility'];\n /** Paint order for the minimap, keyed as `layerVisibility`. */\n layerOrder?: SceneViewLayers['layerOrder'];\n /** Optional animator: the minimap repaints on its ticks and paints its\n * `colorOverrides`. Pass the main canvas's animator so both show the same\n * colors. */\n animator?: Animator;\n /** Visual tuning of the indicator stroke. */\n indicatorStyle?: IndicatorStyle;\n /** CSS class for the canvas. Its size is `width` × `height` unless a rule\n * on this class sizes it. */\n className?: string;\n /** Forwarded ref to the underlying `<canvas>`. */\n canvasRef?: Ref<HTMLCanvasElement>;\n /** The view id this minimap publishes its pointer under. Default\n * `'minimap'`. */\n id?: string;\n}\n\n/** The minimap's own bindings. Unscoped: this dispatcher routes no views, so\n * every input on it is the minimap's. */\nconst MINIMAP_INPUT: Tool = {\n id: 'minimap',\n eligibility: { always: true },\n bindings: [\n { spec: { kind: 'pointerDown' }, actionId: MINIMAP_CENTER },\n { spec: { kind: 'drag' }, actionId: MINIMAP_PAN },\n ],\n};\nconst TOOLS_BY_ID: ReadonlyMap<string, Tool> = new Map([[MINIMAP_INPUT.id, MINIMAP_INPUT]]);\nconst CHANNELS = { wheel: false, pinch: false, contextMenu: false, ingest: false } as const;\n\nfunction MinimapCanvasInner<TData, TLayer extends string, TPose>(\n props: MinimapCanvasProps<TData, TLayer, TPose>,\n) {\n const {\n scene,\n mainView: mainViewProp,\n mainViewDims,\n onMainViewChange,\n width,\n height,\n drawOne,\n alphaFor,\n layerVisibility,\n layerOrder,\n animator,\n fit = 'scene',\n poseDescriptor,\n indicatorStyle,\n className,\n canvasRef,\n id = 'minimap',\n } = props;\n const mainView = normalizeView(mainViewProp);\n\n const descriptor = (poseDescriptor ?? AUTO_POSE_DESCRIPTOR) as PoseDescriptor<TPose>;\n const fitView = useFitView(scene, width, height, fit, descriptor);\n\n const indicatorCmd = useMemo<DrawCommand>(() => {\n return computeIndicatorCommand(mainView, mainViewDims, indicatorStyle, fitView);\n }, [mainView, mainViewDims, indicatorStyle, fitView]);\n\n const localCanvasRef = useRef<HTMLCanvasElement | null>(null);\n const mainViewRef = useLatest(mainView);\n const mainViewDimsRef = useLatest(mainViewDims);\n const onMainViewChangeRef = useLatest(onMainViewChange);\n const fitViewRef = useLatest(fitView);\n\n // The main canvas's camera, which is what the minimap's actions move.\n const rootView = useMemo<ViewApi>(() => ({\n get: () => mainViewRef.current,\n set: (v) => onMainViewChangeRef.current(v),\n hostSize: () => mainViewDimsRef.current,\n }), [mainViewRef, onMainViewChangeRef, mainViewDimsRef]);\n useDepSource('rootView', () => rootView);\n\n const actions = useActionsRegistry();\n useEffect(() => {\n if (!actions) return;\n const off = [actions.register(minimapCenterAction()), actions.register(minimapPanAction())];\n return () => { for (const u of off) u(); };\n }, [actions]);\n\n /** Client point → world, through the fit camera. */\n const clientToWorld = useCallback((cx: number, cy: number) => {\n const rect = localCanvasRef.current?.getBoundingClientRect();\n const fv = fitViewRef.current;\n return {\n x: fv.x + (cx - (rect?.left ?? 0)) / fv.scale.x,\n y: fv.y + (cy - (rect?.top ?? 0)) / fv.scale.y,\n };\n }, [fitViewRef]);\n\n useGestureDispatcher({\n canvasRef: localCanvasRef,\n actions: actions!,\n entriesById: TOOLS_BY_ID,\n clientToWorld,\n keyboard: false,\n channels: CHANNELS,\n });\n\n const pointerStore = usePointerContext();\n useEffect(() => {\n const el = localCanvasRef.current;\n if (!el || !pointerStore) return;\n const onMove = (e: PointerEvent): void => {\n const w = clientToWorld(e.clientX, e.clientY);\n pointerStore.set({ worldX: w.x, worldY: w.y, viewId: id });\n };\n const onLeave = (e: PointerEvent): void => {\n if (e.buttons !== 0) return;\n if (pointerStore.get()?.viewId === id) pointerStore.set(null);\n };\n el.addEventListener('pointermove', onMove);\n el.addEventListener('pointerleave', onLeave);\n return () => {\n el.removeEventListener('pointermove', onMove);\n el.removeEventListener('pointerleave', onLeave);\n };\n }, [pointerStore, clientToWorld, id]);\n\n const pointer = usePointerPosition();\n const cursorLayer = useMemo(() => createLinkedCursorLayer({\n id: `${id}.cursor`,\n pointer: () => pointer,\n color: () => accentColorOf(localCanvasRef.current),\n }), [id, pointer]);\n\n const extraCommands = useMemo<DrawCommand[]>(() => [\n indicatorCmd,\n ...cursorLayer.draw({ viewId: id }, fitView, { width, height }),\n ], [indicatorCmd, cursorLayer, id, fitView, width, height]);\n\n // `<SceneViewCanvas>` doesn't expose its element except via `canvasRef`, so\n // we route both our internal ref and the consumer's ref through one setter.\n const setCanvasRef = useCallback((el: HTMLCanvasElement | null) => {\n localCanvasRef.current = el;\n assignRef(canvasRef, el);\n }, [canvasRef]);\n\n return (\n <SceneViewCanvas\n scene={scene}\n view={fitView}\n width={width}\n height={height}\n drawOne={drawOne}\n extraCommands={extraCommands}\n alphaFor={alphaFor}\n layerVisibility={layerVisibility}\n layerOrder={layerOrder}\n animator={animator}\n className={className}\n canvasRef={setCanvasRef}\n />\n );\n}\n\n/**\n * Opinionated minimap on a canvas of its own. Renders the same `scene` the\n * main canvas is showing through a derived \"fit\" view, and overlays a dashed\n * indicator of where the main canvas is looking. Press anywhere in it to\n * recenter the main view on that world point; drag to pan continuously.\n *\n * Its dispatcher, actions and deps are its own, so it never competes with\n * the main canvas for input. Put one `<PointerContextProvider>` around it and\n * the main canvas for linked cursors both ways.\n *\n * `forwardRef` is not used because the component is generic over\n * `<TData, TLayer, TPose>` and React's `forwardRef` erases generics. The\n * `canvasRef` prop is the plain-prop equivalent.\n */\nexport function MinimapCanvas<TData, TLayer extends string, TPose>(\n props: MinimapCanvasProps<TData, TLayer, TPose>,\n) {\n return (\n <DepRegistryProvider>\n <ActionsProvider>\n <ActiveToolContextProvider>\n <PointerProviderIfRoot>\n <MinimapCanvasInner {...props} />\n </PointerProviderIfRoot>\n </ActiveToolContextProvider>\n </ActionsProvider>\n </DepRegistryProvider>\n );\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@weasel-js/minimap",
3
- "version": "1.9.4",
3
+ "version": "1.10.0",
4
4
  "description": "A minimap for a weasel canvas: a read-only overview with a viewport indicator you drag to pan, fit math, and a linked crosshair between surfaces.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -37,11 +37,12 @@
37
37
  "build": "tsup"
38
38
  },
39
39
  "dependencies": {
40
- "@weasel-js/react": "1.9.4",
41
- "@weasel-js/routing": "1.9.4"
40
+ "@weasel-js/react": "1.10.0",
41
+ "@weasel-js/routing": "1.10.0"
42
42
  },
43
43
  "peerDependencies": {
44
- "@weasel-js/core": "1.9.4",
44
+ "@weasel-js/animator": "1.10.0",
45
+ "@weasel-js/core": "1.10.0",
45
46
  "react": ">=18"
46
47
  },
47
48
  "publishConfig": {