@weasel-js/labkit 1.4.0-pre.0 → 1.4.0-pre.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.
Files changed (54) hide show
  1. package/README.md +226 -55
  2. package/dist/_dts/{CanvasStackContext-DtAn_3O-.d.ts → CanvasStackContext-LnCfqNBA.d.ts} +1 -1
  3. package/dist/_dts/{frac-Cp3NivlC.d.ts → frac-C-2c72Ij.d.ts} +9 -2
  4. package/dist/canvas/index.d.ts +73 -7
  5. package/dist/canvas/index.js +2 -2
  6. package/dist/chrome/index.d.ts +2 -2
  7. package/dist/chrome/index.js +5 -5
  8. package/dist/{chunk-LITE5YFB.js → chunk-6OEYTYML.js} +6 -6
  9. package/dist/{chunk-LITE5YFB.js.map → chunk-6OEYTYML.js.map} +1 -1
  10. package/dist/{chunk-JDDIZSLL.js → chunk-AE5CNVRU.js} +3 -3
  11. package/dist/{chunk-JDDIZSLL.js.map → chunk-AE5CNVRU.js.map} +1 -1
  12. package/dist/{chunk-EQIB2PGC.js → chunk-E2UQVZ44.js} +3 -3
  13. package/dist/{chunk-EQIB2PGC.js.map → chunk-E2UQVZ44.js.map} +1 -1
  14. package/dist/{chunk-4EY67BKJ.js → chunk-ESIQNQ6K.js} +3 -3
  15. package/dist/{chunk-4EY67BKJ.js.map → chunk-ESIQNQ6K.js.map} +1 -1
  16. package/dist/{chunk-6JMU56CU.js → chunk-HHGVISVZ.js} +4 -4
  17. package/dist/{chunk-6JMU56CU.js.map → chunk-HHGVISVZ.js.map} +1 -1
  18. package/dist/{chunk-3ZELRRBV.js → chunk-HMFODCOX.js} +86 -6
  19. package/dist/chunk-HMFODCOX.js.map +1 -0
  20. package/dist/{chunk-ROQDRXKW.js → chunk-L5QJOOLV.js} +126 -12
  21. package/dist/chunk-L5QJOOLV.js.map +1 -0
  22. package/dist/{chunk-5TCEVMPI.js → chunk-M75ZU6ZZ.js} +3 -3
  23. package/dist/{chunk-5TCEVMPI.js.map → chunk-M75ZU6ZZ.js.map} +1 -1
  24. package/dist/{chunk-3P5TTTA7.js → chunk-QB5SM4BM.js} +3 -3
  25. package/dist/{chunk-3P5TTTA7.js.map → chunk-QB5SM4BM.js.map} +1 -1
  26. package/dist/{chunk-HEORBLVT.js → chunk-RBGKL7NF.js} +3 -3
  27. package/dist/{chunk-HEORBLVT.js.map → chunk-RBGKL7NF.js.map} +1 -1
  28. package/dist/{chunk-YQJNT4XQ.js → chunk-TO2FUOKF.js} +4 -4
  29. package/dist/{chunk-YQJNT4XQ.js.map → chunk-TO2FUOKF.js.map} +1 -1
  30. package/dist/controls/index.js +3 -3
  31. package/dist/dragdrop/index.d.ts +1 -1
  32. package/dist/dragdrop/index.js +2 -2
  33. package/dist/index.d.ts +7 -52
  34. package/dist/index.js +49 -101
  35. package/dist/index.js.map +1 -1
  36. package/dist/layers/index.d.ts +2 -2
  37. package/dist/layers/index.js +3 -3
  38. package/dist/loupe/index.d.ts +3 -3
  39. package/dist/loupe/index.js +2 -2
  40. package/dist/passthrough/weasel-canvas.js +1 -1
  41. package/dist/passthrough/weasel-ui.js +2 -2
  42. package/dist/primitives/index.js +4 -4
  43. package/dist/surface/index.js +2 -2
  44. package/dist/ui/layers/index.js +2 -2
  45. package/dist/undo/index.d.ts +1 -1
  46. package/package.json +7 -7
  47. package/src/annotations/store.test.ts +72 -0
  48. package/src/annotations/store.ts +30 -0
  49. package/src/annotations/types.ts +9 -2
  50. package/src/canvas/index.ts +11 -0
  51. package/src/index.test.ts +1 -0
  52. package/src/index.ts +13 -9
  53. package/dist/chunk-3ZELRRBV.js.map +0 -1
  54. package/dist/chunk-ROQDRXKW.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/canvas/useLayerScheduler.ts","../src/canvas/usePanZoom.ts","../src/canvas/CanvasStack.tsx","../src/canvas/useOrbit.ts"],"names":["useRef","useEffect","DRAG_THRESHOLD","useCallback"],"mappings":"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","file":"chunk-HMFODCOX.js","sourcesContent":["import { useVisibleRaf } from '@weasel-js/core';\nimport { type RefObject, useEffect, useRef } from 'react';\nimport type { ViewTransform } from '../instrument/types';\nimport { DEFAULT_FRAME, type WorldFrame } from './worldSpec';\n\n/** One layer of a canvas stack: its id, whether it is currently shown, and how\n * it paints itself. */\nexport interface CanvasLayerDescriptor {\n id: string;\n visible: boolean;\n render: (ctx: CanvasRenderingContext2D, view: ViewTransform, frame: WorldFrame) => void;\n}\n\ninterface SchedulerOptions {\n layers: CanvasLayerDescriptor[];\n view: ViewTransform;\n /** The instrument's coordinate system, resolved against `size`. */\n frame?: WorldFrame;\n canvasRefs: RefObject<Map<string, HTMLCanvasElement>>;\n size: { width: number; height: number; dpr: number };\n /** The element the stack occupies. Given one, the scheduler also stops while\n * the stack sits outside the viewport. */\n host?: RefObject<Element | null>;\n}\n\nexport function useLayerScheduler({\n layers,\n view,\n frame = DEFAULT_FRAME,\n canvasRefs,\n size,\n host,\n}: SchedulerOptions): void {\n const dirty = useRef<Set<string>>(new Set());\n const lastRenderRef = useRef<Map<string, CanvasLayerDescriptor['render']>>(new Map());\n\n useEffect(() => {\n for (const layer of layers) {\n const prev = lastRenderRef.current.get(layer.id);\n if (prev !== layer.render) dirty.current.add(layer.id);\n lastRenderRef.current.set(layer.id, layer.render);\n }\n for (const id of [...lastRenderRef.current.keys()]) {\n if (!layers.find((l) => l.id === id)) lastRenderRef.current.delete(id);\n }\n }, [layers]);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: re-mark dirty when view or size changes\n useEffect(() => {\n for (const layer of layers) dirty.current.add(layer.id);\n }, [view, frame, size, layers]);\n\n // Painting only what is dirty is not the same as doing nothing: a hidden tab\n // still commits React updates, and the effect above marks every layer dirty\n // on any view or size change. The gate is what actually stops the work.\n const frameLoop = useVisibleRaf(\n () => {\n if (dirty.current.size === 0) return;\n const map = canvasRefs.current;\n if (!map) {\n dirty.current.clear();\n return;\n }\n for (const layer of layers) {\n if (!dirty.current.has(layer.id)) continue;\n if (!layer.visible) continue;\n const canvas = map.get(layer.id);\n if (!canvas) continue;\n const ctx = canvas.getContext('2d');\n if (!ctx) continue;\n ctx.save();\n ctx.setTransform(size.dpr, 0, 0, size.dpr, 0, 0);\n ctx.clearRect(0, 0, size.width, size.height);\n layer.render(ctx, view, frame);\n ctx.restore();\n }\n dirty.current.clear();\n },\n { target: host },\n );\n\n useEffect(() => {\n if (dirty.current.size > 0) frameLoop.request();\n });\n}\n","import { type PointerEvent, useCallback, useRef, type WheelEvent } from 'react';\nimport type { ViewTransform } from '../instrument/types';\nimport { zoomAt } from './camera';\nimport { DEFAULT_FRAME, type WorldFrame } from './worldSpec';\n\nexport interface UsePanZoomOptions {\n view: ViewTransform;\n onViewChange: (v: ViewTransform) => void;\n /** The opening `view.zoom` always stays reachable, widening these past\n * whatever is passed here if it would otherwise exclude it. */\n minZoom?: number;\n maxZoom?: number;\n /** The instrument's coordinate system, resolved against the viewport. The\n * wheel anchors in this frame; omitting it anchors at the element's\n * top-left, which is what labkit did before a frame could be declared. */\n frame?: WorldFrame;\n}\n\nexport interface PanZoomHandlers {\n onWheel: (e: WheelEvent<HTMLElement>) => void;\n onPointerDown: (e: PointerEvent<HTMLElement>) => void;\n onPointerMove: (e: PointerEvent<HTMLElement>) => void;\n onPointerUp: (e: PointerEvent<HTMLElement>) => void;\n isDragging: () => boolean;\n}\n\ninterface DragState {\n pointerId: number;\n startScreenX: number;\n startScreenY: number;\n startPan: { x: number; y: number };\n moved: boolean;\n}\n\nconst DRAG_THRESHOLD = 3;\n\nfunction isPositiveFinite(n: number): boolean {\n return Number.isFinite(n) && n > 0;\n}\n\nexport function usePanZoom({\n view,\n onViewChange,\n minZoom = 0.1,\n maxZoom = 32,\n frame = DEFAULT_FRAME,\n}: UsePanZoomOptions): PanZoomHandlers {\n const dragRef = useRef<DragState | null>(null);\n const viewRef = useRef(view);\n viewRef.current = view;\n // Captured once, from the view the canvas opened at — not the current view,\n // which would let a prior zoom-out shrink the range and trap the opening\n // view unreachable behind it.\n const initialZoomRef = useRef(isPositiveFinite(view.zoom) ? view.zoom : null);\n\n const onWheel = useCallback(\n (e: WheelEvent<HTMLElement>) => {\n e.preventDefault();\n const rect = e.currentTarget.getBoundingClientRect();\n const initialZoom = initialZoomRef.current;\n onViewChange(\n zoomAt(\n viewRef.current,\n Math.exp(-e.deltaY * 0.001),\n { x: e.clientX - rect.left, y: e.clientY - rect.top },\n {\n frame,\n min: initialZoom == null ? minZoom : Math.min(minZoom, initialZoom),\n max: initialZoom == null ? maxZoom : Math.max(maxZoom, initialZoom),\n },\n ),\n );\n },\n [onViewChange, minZoom, maxZoom, frame],\n );\n\n const onPointerDown = useCallback((e: PointerEvent<HTMLElement>) => {\n if (e.button !== 0) return;\n e.currentTarget.setPointerCapture(e.pointerId);\n dragRef.current = {\n pointerId: e.pointerId,\n startScreenX: e.clientX,\n startScreenY: e.clientY,\n startPan: { ...viewRef.current.pan },\n moved: false,\n };\n }, []);\n\n const onPointerMove = useCallback(\n (e: PointerEvent<HTMLElement>) => {\n const drag = dragRef.current;\n if (!drag || drag.pointerId !== e.pointerId) return;\n const dx = e.clientX - drag.startScreenX;\n const dy = e.clientY - drag.startScreenY;\n if (!drag.moved && Math.hypot(dx, dy) < DRAG_THRESHOLD) return;\n drag.moved = true;\n onViewChange({\n zoom: viewRef.current.zoom,\n pan: { x: drag.startPan.x + dx, y: drag.startPan.y + dy },\n });\n },\n [onViewChange],\n );\n\n const onPointerUp = useCallback((e: PointerEvent<HTMLElement>) => {\n const drag = dragRef.current;\n if (!drag || drag.pointerId !== e.pointerId) return;\n if (e.currentTarget.hasPointerCapture(e.pointerId)) {\n e.currentTarget.releasePointerCapture(e.pointerId);\n }\n dragRef.current = null;\n }, []);\n\n const isDragging = useCallback(() => dragRef.current?.moved === true, []);\n\n return { onWheel, onPointerDown, onPointerMove, onPointerUp, isDragging };\n}\n","import { type CSSProperties, type ReactNode, useEffect, useMemo, useRef, useState } from 'react';\nimport type { Point, ViewTransform } from '../instrument/types';\nimport { CanvasStackContext } from './CanvasStackContext';\nimport { screenToWorld } from './canvasCoords';\nimport { type CanvasLayerDescriptor, useLayerScheduler } from './useLayerScheduler';\nimport { usePanZoom } from './usePanZoom';\nimport { resolveFrame, type ViewportSize, type WorldSpec } from './worldSpec';\n\n/** Props for `<CanvasStack>`. */\nexport interface CanvasStackProps {\n layers: CanvasLayerDescriptor[];\n view: ViewTransform;\n onViewChange: (v: ViewTransform) => void;\n /** The instrument's coordinate system. Omitted, world (0,0) sits at the\n * element's top-left with y running down. */\n worldSpec?: WorldSpec;\n minZoom?: number;\n maxZoom?: number;\n width?: number | string;\n height?: number | string;\n className?: string;\n /** Fired whenever the stack is measured, so a consumer can place a view that\n * only makes sense in terms of the viewport. */\n onResize?: (size: ViewportSize) => void;\n onHitTest?: (worldPos: Point) => void;\n children?: ReactNode;\n}\n\n/** Stacks one `<canvas>` per layer and drives them from a shared view, so a\n * layer that changes rarely is not redrawn with one that changes every frame.\n * Handles sizing, device pixel ratio, and pan/zoom. */\nexport function CanvasStack({\n layers,\n view,\n onViewChange,\n worldSpec,\n minZoom,\n maxZoom,\n width = '100%',\n height = '100%',\n className,\n onResize,\n onHitTest,\n children,\n}: CanvasStackProps) {\n const containerRef = useRef<HTMLDivElement | null>(null);\n const canvasMap = useRef<Map<string, HTMLCanvasElement>>(new Map());\n const [size, setSize] = useState({ width: 0, height: 0, dpr: 1 });\n\n const setCanvasRef = (id: string, el: HTMLCanvasElement | null): void => {\n if (el) canvasMap.current.set(id, el);\n else canvasMap.current.delete(id);\n };\n\n useEffect(() => {\n const el = containerRef.current;\n if (!el) return;\n const update = () => {\n const rect = el.getBoundingClientRect();\n const dpr = window.devicePixelRatio ?? 1;\n setSize((prev) => {\n if (prev.width === rect.width && prev.height === rect.height && prev.dpr === dpr) {\n return prev;\n }\n return { width: rect.width, height: rect.height, dpr };\n });\n };\n update();\n if (typeof ResizeObserver === 'undefined') return;\n const ro = new ResizeObserver(update);\n ro.observe(el);\n return () => ro.disconnect();\n }, []);\n\n const onResizeRef = useRef(onResize);\n onResizeRef.current = onResize;\n useEffect(() => {\n if (size.width === 0 && size.height === 0) return;\n onResizeRef.current?.({ width: size.width, height: size.height });\n }, [size.width, size.height]);\n\n const frame = useMemo(() => resolveFrame(worldSpec, size), [worldSpec, size]);\n\n const handlers = usePanZoom({ view, onViewChange, minZoom, maxZoom, frame });\n useLayerScheduler({ layers, view, frame, canvasRefs: canvasMap, size, host: containerRef });\n\n const ctxValue = useMemo(\n () => ({\n view,\n frame,\n surface: { element: containerRef, size, canvases: canvasMap, layers },\n }),\n [view, frame, size, layers],\n );\n\n const containerStyle: CSSProperties = { width, height };\n const canvasPx = {\n width: Math.max(0, Math.round(size.width * size.dpr)),\n height: Math.max(0, Math.round(size.height * size.dpr)),\n };\n const canvasCss: CSSProperties = {\n width: size.width,\n height: size.height,\n };\n\n const handlePointerUp = (e: React.PointerEvent<HTMLDivElement>) => {\n const wasDragging = handlers.isDragging();\n handlers.onPointerUp(e);\n if (!wasDragging && onHitTest && containerRef.current) {\n const rect = containerRef.current.getBoundingClientRect();\n const screen = { x: e.clientX - rect.left, y: e.clientY - rect.top };\n onHitTest(screenToWorld(screen, view, frame));\n }\n };\n\n return (\n <CanvasStackContext.Provider value={ctxValue}>\n <div\n ref={containerRef}\n className={className ? `lk-canvas-stack ${className}` : 'lk-canvas-stack'}\n style={containerStyle}\n onWheel={handlers.onWheel}\n onPointerDown={handlers.onPointerDown}\n onPointerMove={handlers.onPointerMove}\n onPointerUp={handlePointerUp}\n >\n {layers.map((layer) => (\n <canvas\n key={layer.id}\n ref={(el) => setCanvasRef(layer.id, el)}\n className=\"lk-canvas-stack__canvas\"\n width={canvasPx.width}\n height={canvasPx.height}\n style={{ ...canvasCss, display: layer.visible ? 'block' : 'none' }}\n />\n ))}\n <div className=\"lk-canvas-stack__overlay\">{children}</div>\n </div>\n </CanvasStackContext.Provider>\n );\n}\n","import { type PointerEvent, useCallback, useRef, type WheelEvent } from 'react';\n\n/** A point in the space the instrument works in. */\nexport interface Vec3 {\n x: number;\n y: number;\n z: number;\n}\n\n/** An orbit camera as a trial view: where it looks from, and what it looks at.\n * labkit does not turn this into a matrix — the host's renderer does. */\nexport interface OrbitView {\n yaw: number;\n pitch: number;\n distance: number;\n target: Vec3;\n}\n\n/** Just short of the pole. At exactly ±PI/2 the azimuth is undefined and the\n * camera rolls, which reads as the model jumping rather than as a limit. */\nexport const PITCH_LIMIT = Math.PI / 2 - 0.01;\n\nconst YAW_PER_PX = 0.008;\nconst PITCH_PER_PX = 0.008;\nconst DISTANCE_PER_NOTCH = 0.0015;\nconst DRAG_THRESHOLD = 3;\n\nexport function clampPitch(pitch: number): number {\n return Math.min(PITCH_LIMIT, Math.max(-PITCH_LIMIT, pitch));\n}\n\nexport function wrapYaw(yaw: number): number {\n const wrapped = ((((yaw + Math.PI) % (2 * Math.PI)) + 2 * Math.PI) % (2 * Math.PI)) - Math.PI;\n return wrapped === -Math.PI ? Math.PI : wrapped;\n}\n\n/** The view a drag of (dx, dy) from `start` produces. Absolute against the drag\n * start, so it can be re-applied any number of times without compounding. */\nexport function orbitAfterDrag(start: OrbitView, dx: number, dy: number): OrbitView {\n return {\n ...start,\n yaw: wrapYaw(start.yaw + dx * YAW_PER_PX),\n pitch: clampPitch(start.pitch + dy * PITCH_PER_PX),\n };\n}\n\n/** Multiplicative, so one notch covers the same proportion of the distance\n * whether the camera is near or far. */\nexport function orbitAfterWheel(\n view: OrbitView,\n deltaY: number,\n minDistance: number,\n maxDistance: number,\n): OrbitView {\n const factor = Math.exp(deltaY * DISTANCE_PER_NOTCH);\n return {\n ...view,\n distance: Math.min(maxDistance, Math.max(minDistance, view.distance * factor)),\n };\n}\n\nexport interface UseOrbitOptions {\n view: OrbitView;\n onViewChange: (v: OrbitView) => void;\n /** Restored on double-click. Defaults to the view the hook first saw. */\n home?: OrbitView;\n minDistance?: number;\n maxDistance?: number;\n}\n\nexport interface OrbitHandlers {\n onWheel: (e: WheelEvent<HTMLElement>) => void;\n onPointerDown: (e: PointerEvent<HTMLElement>) => void;\n onPointerMove: (e: PointerEvent<HTMLElement>) => void;\n onPointerUp: (e: PointerEvent<HTMLElement>) => void;\n onDoubleClick: () => void;\n isDragging: () => boolean;\n}\n\ninterface DragState {\n pointerId: number;\n startX: number;\n startY: number;\n startView: OrbitView;\n moved: boolean;\n}\n\n/** Pointer gestures over an orbit view: drag to turn, wheel or pinch to dolly,\n * double-click to go home. The 3D peer of `usePanZoom`. */\nexport function useOrbit({\n view,\n onViewChange,\n home,\n minDistance = 0.1,\n maxDistance = 1000,\n}: UseOrbitOptions): OrbitHandlers {\n const dragRef = useRef<DragState | null>(null);\n const viewRef = useRef(view);\n viewRef.current = view;\n const homeRef = useRef(home ?? view);\n if (home) homeRef.current = home;\n\n const onWheel = useCallback(\n (e: WheelEvent<HTMLElement>) => {\n e.preventDefault();\n onViewChange(orbitAfterWheel(viewRef.current, e.deltaY, minDistance, maxDistance));\n },\n [onViewChange, minDistance, maxDistance],\n );\n\n const onPointerDown = useCallback((e: PointerEvent<HTMLElement>) => {\n if (e.button !== 0) return;\n e.currentTarget.setPointerCapture(e.pointerId);\n dragRef.current = {\n pointerId: e.pointerId,\n startX: e.clientX,\n startY: e.clientY,\n startView: viewRef.current,\n moved: false,\n };\n }, []);\n\n const onPointerMove = useCallback(\n (e: PointerEvent<HTMLElement>) => {\n const drag = dragRef.current;\n if (!drag || drag.pointerId !== e.pointerId) return;\n const dx = e.clientX - drag.startX;\n const dy = e.clientY - drag.startY;\n if (!drag.moved && Math.hypot(dx, dy) < DRAG_THRESHOLD) return;\n drag.moved = true;\n onViewChange(orbitAfterDrag(drag.startView, dx, dy));\n },\n [onViewChange],\n );\n\n const onPointerUp = useCallback((e: PointerEvent<HTMLElement>) => {\n const drag = dragRef.current;\n if (!drag || drag.pointerId !== e.pointerId) return;\n if (e.currentTarget.hasPointerCapture(e.pointerId)) {\n e.currentTarget.releasePointerCapture(e.pointerId);\n }\n dragRef.current = null;\n }, []);\n\n const onDoubleClick = useCallback(() => onViewChange(homeRef.current), [onViewChange]);\n const isDragging = useCallback(() => dragRef.current?.moved === true, []);\n\n return { onWheel, onPointerDown, onPointerMove, onPointerUp, onDoubleClick, isDragging };\n}\n"]}
@@ -3841,6 +3841,120 @@ function eligibleContribution(reg, entry) {
3841
3841
  return eligibleForMode(reg.current(), entry.eligibility?.capabilities ?? []);
3842
3842
  }
3843
3843
 
3844
+ // ../cursor/dist/index.js
3845
+ var CURSOR_INK = "#141418";
3846
+ var CURSOR_HALO = "#ffffff";
3847
+ var CURSOR_HALO_WIDTH = 2.6;
3848
+ var CURSOR_MAX_CSS_PX = 128;
3849
+ function renderHalo(p) {
3850
+ switch (p.role) {
3851
+ case "ink":
3852
+ case "accent":
3853
+ return `<path d="${p.d}" fill="${CURSOR_HALO}" stroke="${CURSOR_HALO}" stroke-width="${CURSOR_HALO_WIDTH}" stroke-linejoin="round"/>`;
3854
+ case "stroke":
3855
+ return `<path d="${p.d}" fill="none" stroke="${CURSOR_HALO}" stroke-width="${p.width + CURSOR_HALO_WIDTH}" stroke-linecap="round" stroke-linejoin="round"/>`;
3856
+ // A detail IS halo-coloured and sits on top of the ink; it has no halo.
3857
+ case "detail":
3858
+ return "";
3859
+ }
3860
+ }
3861
+ function renderInk(p) {
3862
+ switch (p.role) {
3863
+ case "ink":
3864
+ return `<path d="${p.d}" fill="${CURSOR_INK}"/>`;
3865
+ case "stroke":
3866
+ return `<path d="${p.d}" fill="none" stroke="${CURSOR_INK}" stroke-width="${p.width}" stroke-linecap="round" stroke-linejoin="round"/>`;
3867
+ case "detail":
3868
+ return `<path d="${p.d}" fill="none" stroke="${CURSOR_HALO}" stroke-width="${p.width}" stroke-linecap="round"/>`;
3869
+ case "accent":
3870
+ return `<path d="${p.d}" fill="${p.fill}"/>`;
3871
+ }
3872
+ }
3873
+ function bakeCursor(glyph, opts = {}) {
3874
+ const size = opts.size ?? 24;
3875
+ if (size > CURSOR_MAX_CSS_PX) {
3876
+ throw new RangeError(
3877
+ `cursor size ${size} exceeds the ${CURSOR_MAX_CSS_PX}px cap: the browser would drop the image and silently fall back. Use the painted tier.`
3878
+ );
3879
+ }
3880
+ const body = glyph.paths.map(renderHalo).join("") + glyph.paths.map(renderInk).join("");
3881
+ const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" viewBox="0 0 ${glyph.box} ${glyph.box}">${body}</svg>`;
3882
+ const hx = Math.round(glyph.hotspot[0] / glyph.box * size);
3883
+ const hy = Math.round(glyph.hotspot[1] / glyph.box * size);
3884
+ const uri = `data:image/svg+xml,${encodeURIComponent(svg)}`;
3885
+ return `url("${uri}") ${hx} ${hy}, ${opts.fallback ?? "default"}`;
3886
+ }
3887
+ var GLYPHS = {
3888
+ "pencil": {
3889
+ "box": 24,
3890
+ "hotspot": [
3891
+ 5,
3892
+ 19
3893
+ ],
3894
+ "paths": [
3895
+ {
3896
+ "role": "ink",
3897
+ "d": "M 5 19 L 7.5 16.5 L 16 8 L 19 11 L 10.5 19.5 L 8 19 Z"
3898
+ },
3899
+ {
3900
+ "role": "detail",
3901
+ "d": "M 14 6 L 19 11",
3902
+ "width": 1.2
3903
+ }
3904
+ ]
3905
+ },
3906
+ "pen": {
3907
+ "box": 24,
3908
+ "hotspot": [
3909
+ 5,
3910
+ 19
3911
+ ],
3912
+ "paths": [
3913
+ {
3914
+ "role": "ink",
3915
+ "d": "M 5 19 L 8.5 9.5 L 13 5 L 18 10 L 13.5 14.5 Z"
3916
+ },
3917
+ {
3918
+ "role": "detail",
3919
+ "d": "M 8.4 13.9 L 12.2 10.1",
3920
+ "width": 0.9
3921
+ }
3922
+ ]
3923
+ },
3924
+ "eyedropper": {
3925
+ "box": 24,
3926
+ "hotspot": [
3927
+ 5,
3928
+ 19
3929
+ ],
3930
+ "paths": [
3931
+ {
3932
+ "role": "ink",
3933
+ "d": "M 5 19 L 6.8 14.8 L 14.4 7.2 L 16.8 9.6 L 9.2 17.2 Z"
3934
+ },
3935
+ {
3936
+ "role": "ink",
3937
+ "d": "M 18.2 2.6 A 3.2 3.2 0 1 0 18.2 9 A 3.2 3.2 0 1 0 18.2 2.6 Z"
3938
+ }
3939
+ ]
3940
+ }
3941
+ };
3942
+ var cache2 = /* @__PURE__ */ new Map();
3943
+ function cursorFor(name, opts = {}) {
3944
+ const size = opts.size ?? 24;
3945
+ const fallback = opts.fallback ?? "default";
3946
+ const key = `${name}|${size}|${fallback}`;
3947
+ const hit = cache2.get(key);
3948
+ if (hit !== void 0) return hit;
3949
+ const glyph = GLYPHS[name];
3950
+ if (glyph === void 0) {
3951
+ throw new Error(`unknown cursor glyph: ${String(name)}`);
3952
+ }
3953
+ const css = bakeCursor(glyph, { size, fallback });
3954
+ cache2.set(key, css);
3955
+ return css;
3956
+ }
3957
+
3844
3958
  // ../history/dist/index.js
3845
3959
  var RESUMERS = /* @__PURE__ */ new WeakMap();
3846
3960
  function _resumeJournalInternal(j) {
@@ -4263,7 +4377,7 @@ function serialToEntry(se, custom, logger) {
4263
4377
  };
4264
4378
  }
4265
4379
 
4266
- // ../core/dist/chunk-IMFXEINV.js
4380
+ // ../core/dist/chunk-FUQWXDG3.js
4267
4381
  function worldToScreen(worldX, worldY, view) {
4268
4382
  return [view.panX + worldX * view.zoom.x, view.panY + worldY * view.zoom.y];
4269
4383
  }
@@ -5821,12 +5935,12 @@ function pointInContour(coords, start, end, x, y) {
5821
5935
  }
5822
5936
  return inside;
5823
5937
  }
5824
- var cache2 = /* @__PURE__ */ new WeakMap();
5938
+ var cache3 = /* @__PURE__ */ new WeakMap();
5825
5939
  function getMesh(path) {
5826
- const cached2 = cache2.get(path);
5940
+ const cached2 = cache3.get(path);
5827
5941
  if (cached2 !== void 0) return cached2;
5828
5942
  const mesh = tessellate(path);
5829
- cache2.set(path, mesh);
5943
+ cache3.set(path, mesh);
5830
5944
  return mesh;
5831
5945
  }
5832
5946
  function extractPolylines(path, opts = {}) {
@@ -6846,7 +6960,7 @@ function outlineMesh(key, d) {
6846
6960
  }
6847
6961
  var OUTLINE_STROKE_MESH_CACHE_LIMIT = 2048;
6848
6962
  var WIDTH_QUANTUM = 1 / 1024;
6849
- var cache3 = /* @__PURE__ */ new Map();
6963
+ var cache32 = /* @__PURE__ */ new Map();
6850
6964
  function quantizeEmWidth(emWidth) {
6851
6965
  return Math.round(emWidth / WIDTH_QUANTUM) * WIDTH_QUANTUM;
6852
6966
  }
@@ -6861,15 +6975,15 @@ function outlineStrokeMesh(glyphKey, d, emWidth, stroke) {
6861
6975
  stroke.align ?? "center",
6862
6976
  (stroke.dash ?? []).join(",")
6863
6977
  ].join("|");
6864
- const cached2 = cache3.get(key);
6978
+ const cached2 = cache32.get(key);
6865
6979
  if (cached2 !== void 0) return cached2.indices.length === 0 ? null : cached2;
6866
- if (cache3.size >= OUTLINE_STROKE_MESH_CACHE_LIMIT) cache3 = /* @__PURE__ */ new Map();
6980
+ if (cache32.size >= OUTLINE_STROKE_MESH_CACHE_LIMIT) cache32 = /* @__PURE__ */ new Map();
6867
6981
  const mesh = tessellateStroke(
6868
6982
  pathFromD(d),
6869
6983
  { ...stroke, width: emWidth },
6870
6984
  { flattenTolerance: OUTLINE_FLATTEN_TOLERANCE }
6871
6985
  );
6872
- cache3.set(key, mesh);
6986
+ cache32.set(key, mesh);
6873
6987
  return mesh.indices.length === 0 ? null : mesh;
6874
6988
  }
6875
6989
  function poly(pts, size, close = true) {
@@ -20368,7 +20482,7 @@ function usePenTool(options) {
20368
20482
  hookName: "usePenTool",
20369
20483
  // Reads the tool's own ref rather than a scratch handed in by a
20370
20484
  // dispatcher — the pen owns this state and nothing else needs it.
20371
- cursor: () => scratchRef.current?.closeHintActive ? "pointer" : "crosshair",
20485
+ cursor: () => scratchRef.current?.closeHintActive ? "pointer" : cursorFor("pen", { fallback: "crosshair" }),
20372
20486
  presentation: {
20373
20487
  label: "Pen",
20374
20488
  icon: createElement(PenIcon),
@@ -20753,7 +20867,7 @@ function usePencilTool() {
20753
20867
  id: "pencil",
20754
20868
  capabilities: ["creates-paths"],
20755
20869
  hookName: "usePencilTool",
20756
- cursor: "crosshair",
20870
+ cursor: cursorFor("pencil", { fallback: "crosshair" }),
20757
20871
  presentation: {
20758
20872
  label: "Pencil",
20759
20873
  group: "draw",
@@ -28816,5 +28930,5 @@ function oklchToOklab(L, C, h) {
28816
28930
  }
28817
28931
 
28818
28932
  export { ArrowIcon, EllipseIcon, FALLBACK_FIT_VIEW, LineIcon, MinimapCanvas, PATH_C, PATH_L, PATH_M, PATH_Q, PATH_Z, PathBuilder, PencilIcon, RectIcon, SCRIPT_METRICS, SceneCanvas, SceneViewCanvas, SelectIcon, TextIcon, UnknownIcon, WeaselProvider, asNodeId, boundsOfPath, buildSceneViewCommands, computeFitView, computeIndicatorCommand, createScene, eligibleContribution, ellipsePath, evaluateEnabled, getMarker, getPaintKind, isBuiltinToolPref, linePath, markerDrawCommands, oklabToSrgbU8, oklchToOklab, rectPath, renderSceneToCanvas, renderSceneToPixels, resolveStrokeWidth, rgbaToHex, sceneFromJSON, textCommand, tileGeometry, useActionsRegistry, useActiveToolContext, useOptionalDepRegistry, useVisibleRaf };
28819
- //# sourceMappingURL=chunk-ROQDRXKW.js.map
28820
- //# sourceMappingURL=chunk-ROQDRXKW.js.map
28933
+ //# sourceMappingURL=chunk-L5QJOOLV.js.map
28934
+ //# sourceMappingURL=chunk-L5QJOOLV.js.map