@weasel-js/core 1.0.2 → 1.0.4

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 (51) hide show
  1. package/CHANGELOG.md +208 -0
  2. package/dist/{DrawCommand-DCmiNkBj.d.ts → DrawCommand-BbPrSTra.d.ts} +24 -0
  3. package/dist/{chunk-6SHZHXXR.js → chunk-4Z6J4IVH.js} +43 -27
  4. package/dist/chunk-4Z6J4IVH.js.map +1 -0
  5. package/dist/{chunk-PI56ORHE.js → chunk-AYGSXNY3.js} +540 -263
  6. package/dist/chunk-AYGSXNY3.js.map +1 -0
  7. package/dist/{chunk-UB6A6L77.js → chunk-CSMF654J.js} +3 -3
  8. package/dist/{chunk-UB6A6L77.js.map → chunk-CSMF654J.js.map} +1 -1
  9. package/dist/{chunk-IO5Z75X4.js → chunk-HGF5X6MZ.js} +2 -2
  10. package/dist/chunk-HGF5X6MZ.js.map +1 -0
  11. package/dist/{chunk-W2WB4352.js → chunk-J3YC3GVF.js} +5 -4
  12. package/dist/chunk-J3YC3GVF.js.map +1 -0
  13. package/dist/{chunk-Z3KNFTTS.js → chunk-J7LUY47N.js} +3 -3
  14. package/dist/chunk-J7LUY47N.js.map +1 -0
  15. package/dist/{chunk-775XXAHR.js → chunk-JOSUVS6C.js} +2 -2
  16. package/dist/{chunk-775XXAHR.js.map → chunk-JOSUVS6C.js.map} +1 -1
  17. package/dist/clipboard.d.ts +5 -2
  18. package/dist/clipboard.js +1 -1
  19. package/dist/clone.d.ts +2 -2
  20. package/dist/{geometry-CnISZ11w.d.ts → geometry-5X6TrAkX.d.ts} +1 -1
  21. package/dist/{grid-CBiLBnyc.d.ts → grid-sfilv5HP.d.ts} +7 -2
  22. package/dist/index.d.ts +552 -56
  23. package/dist/index.js +7 -7
  24. package/dist/insert.d.ts +6 -3
  25. package/dist/insert.js +1 -1
  26. package/dist/insert.js.map +1 -1
  27. package/dist/move.d.ts +26 -5
  28. package/dist/move.js +3 -3
  29. package/dist/move.js.map +1 -1
  30. package/dist/{options-DoOvx50U.d.ts → options-CbsIgQci.d.ts} +3 -1
  31. package/dist/patterns-builtin.d.ts +8 -0
  32. package/dist/patterns-builtin.js +1 -1
  33. package/dist/{pointSnapToGrid-Bj4r_lEQ.d.ts → pointSnapToGrid-C3wowsQy.d.ts} +9 -3
  34. package/dist/{registry-BQL4oyTg.d.ts → registry-QRg8KiNM.d.ts} +91 -7
  35. package/dist/renderer.d.ts +54 -17
  36. package/dist/renderer.js +7 -7
  37. package/dist/resize.d.ts +12 -5
  38. package/dist/resize.js +2 -2
  39. package/dist/routing.d.ts +7 -7
  40. package/dist/routing.js +1 -1
  41. package/dist/{types-Dtxe7jTS.d.ts → types-BHK2dkMu.d.ts} +23 -0
  42. package/dist/{types-Ct4n0Z38.d.ts → types-ByZxoD6P.d.ts} +1 -1
  43. package/dist/{types-Ch0Goo-j.d.ts → types-DpQ0cWYC.d.ts} +20 -0
  44. package/dist/{types-Kh_osAq9.d.ts → types-vqxpCFVp.d.ts} +31 -0
  45. package/dist/{viewToMat3-BvaWCN99.d.ts → viewToMat3-CQW_YqDw.d.ts} +1 -1
  46. package/package.json +6 -6
  47. package/dist/chunk-6SHZHXXR.js.map +0 -1
  48. package/dist/chunk-IO5Z75X4.js.map +0 -1
  49. package/dist/chunk-PI56ORHE.js.map +0 -1
  50. package/dist/chunk-W2WB4352.js.map +0 -1
  51. package/dist/chunk-Z3KNFTTS.js.map +0 -1
@@ -1,16 +1,16 @@
1
- import { ActionDisabledReason, useOptionalDepRegistry, DepRegistryProvider, useActionsRegistry, ActionsProvider, useDepRegistry, reportRouteConflicts, buildDepsFromRequires, useDepSource, actionBindings } from './chunk-W2WB4352.js';
2
- import { scratchKey, createTransformOp, snap, getScratch, createReparentOp, setScratch } from './chunk-UB6A6L77.js';
3
- import { fixedCornerOf, DEFAULT_RESIZE_BEHAVIORS, CORNER_ANCHORS, cornerPoint } from './chunk-Z3KNFTTS.js';
4
- import { AUTO_POSE_DESCRIPTOR, RECT_POSE_DESCRIPTOR, resolveUnit, pathPoseDescriptor, polygonFromPoints, starPath, regularPolygonPath, linePath, ellipsePath, rectPath, strokeHitTest, withinPxRadius, boundsOfPath, PATH_M, PATH_L, PATH_Z, PATH_Q, PATH_C, DEFAULT_FLATTEN_TOLERANCE, flattenQuadratic, flattenCubic, PathBuilder, pointInPath, transformPath, translatePath, pxExtent, remapRotatedLeaf, withinPxBox, flattenCubicWithArcLen, flattenQuadraticWithArcLen, PATH_CMD_LENGTHS, pointToGridCell } from './chunk-6SHZHXXR.js';
5
- import { dispatchApplyBatch, dlog, dwarn, usePointerContext, PointerContextProvider, applyOpsTo, extractWeaselClipboardFromSvg, parseWeaselClipboardText, materializePaste, WEASEL_CLIPBOARD_MIME, WEASEL_CLIPBOARD_MIME_WEB, sniffWeaselClipboardText } from './chunk-775XXAHR.js';
1
+ import { ActionDisabledReason, useOptionalDepRegistry, DepRegistryProvider, useActionsRegistry, ActionsProvider, useDepRegistry, reportRouteConflicts, buildDepsFromRequires, useDepSource, actionBindings } from './chunk-J3YC3GVF.js';
2
+ import { scratchKey, createTransformOp, snap, getScratch, createReparentOp, setScratch } from './chunk-CSMF654J.js';
3
+ import { fixedCornerOf, DEFAULT_RESIZE_BEHAVIORS, CORNER_ANCHORS, cornerPoint } from './chunk-J7LUY47N.js';
4
+ import { AUTO_POSE_DESCRIPTOR, RECT_POSE_DESCRIPTOR, resolveUnit, pathPoseDescriptor, polygonFromPoints, starPath, regularPolygonPath, linePath, ellipsePath, rectPath, strokeHitTest, withinPxRadius, boundsOfPath, PATH_M, PATH_L, PATH_Z, PATH_Q, PATH_C, DEFAULT_FLATTEN_TOLERANCE, flattenQuadratic, flattenCubic, PathBuilder, pointInPath, transformPath, translatePath, pxExtent, remapRotatedLeaf, withinPxBox, flattenCubicWithArcLen, flattenQuadraticWithArcLen, PATH_CMD_LENGTHS, pointToGridCell } from './chunk-4Z6J4IVH.js';
5
+ import { dispatchApplyBatch, dlog, dwarn, usePointerContext, PointerContextProvider, applyOpsTo, extractWeaselClipboardFromSvg, parseWeaselClipboardText, materializePaste, WEASEL_CLIPBOARD_MIME, WEASEL_CLIPBOARD_MIME_WEB, sniffWeaselClipboardText } from './chunk-JOSUVS6C.js';
6
6
  import { createSetSelectionOp } from './chunk-BHVYVFGV.js';
7
7
  import { registerOpFactory, createDeleteOp, createInsertOp, rebuildOp } from './chunk-GVCNT7UH.js';
8
- import { getTexture, chunks, dots, crosshatch, hatch } from './chunk-IO5Z75X4.js';
8
+ import { getTexture, chunks, dots, crosshatch, hatch } from './chunk-HGF5X6MZ.js';
9
9
  import { createContext, createElement, forwardRef, useMemo, useRef, useState, useCallback, useImperativeHandle, useEffect, useSyncExternalStore, useContext, useReducer, useLayoutEffect } from 'react';
10
10
  import { subscribeGlyphReady, DEFAULT_BAKE_BUDGET, TEXT_VERT_SRC, TEXT_FRAG_SRC, TEXT_SDF_UNIFORMS, TEXT_SDF_ATTRIBUTES, TEXT_FRAG_R8_SRC, markAllFontsNotUploaded, resetBakeBudget, glyphGeneration, syncDynamicPageTexture, ensureFontTexture, dynamicPageTextureId, textureCacheKey, resolveFontVariant, resolveGlyphFallback, glyphOutline } from '@weasel-js/font';
11
11
  export { canQueryLocalFonts, canQueryLocalFonts as canQueryLocalFonts2, enableLocalFontOutlines, enableLocalFontOutlines as enableLocalFontOutlines2, hasFontOutlines, hasFontOutlines as hasFontOutlines2, isCanvasFont, isCanvasFont as isCanvasFont2, listFontOutlines, listFontOutlines as listFontOutlines2, outlineStatus, outlineStatus as outlineStatus2, registerCanvasFont, registerCanvasFont as registerCanvasFont2, registerFont, registerFont as registerFont2, registerFontOutlines, registerFontOutlines as registerFontOutlines2, subscribeGlyphReady, subscribeGlyphReady as subscribeGlyphReady2, unregisterCanvasFont, unregisterCanvasFont as unregisterCanvasFont2, unregisterFontOutlines, unregisterFontOutlines as unregisterFontOutlines2 } from '@weasel-js/font';
12
12
  import earcut from 'earcut';
13
- import { applyToPoint, rotateAboutPoint, boxToBox, pointInPolygon, segmentsCross } from '@weasel-js/geom';
13
+ import { applyToPoint, rotateAboutPoint, boxToBox, pointInPolygon, segmentsCross, pointSegmentDist2 } from '@weasel-js/geom';
14
14
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
15
15
  import polygonClipping from 'polygon-clipping';
16
16
  import { matchSpec, RESERVED_ID_PREFIXES, RESERVED_ID_NAMES, parseTargetSpec, mimeMatchesGlob } from '@weasel-js/gestures';
@@ -19,7 +19,7 @@ import { createHistory } from '@weasel-js/history';
19
19
  export * from '@weasel-js/history';
20
20
 
21
21
  // src/version.ts
22
- var VERSION = "1.0.2" ;
22
+ var VERSION = "1.0.4" ;
23
23
 
24
24
  // src/features/grid/roundToCell.ts
25
25
  function roundToCell(value, cellSize) {
@@ -524,13 +524,20 @@ var GLTextureCache = class {
524
524
  }
525
525
  gl;
526
526
  map = /* @__PURE__ */ new Map();
527
+ wraps = /* @__PURE__ */ new Map();
527
528
  has(id) {
528
529
  return this.map.has(id);
529
530
  }
530
- /** Uploads once per id; `wrap` therefore applies on first upload only.
531
- * An id is either a pattern tile or a shader texture, never both. */
531
+ /** Uploads the pixels once per id. `wrap` is re-applied whenever it differs
532
+ * from what the id was last uploaded under: the same registered image can
533
+ * be a clamped shader texture in one draw and a repeating pattern tile in
534
+ * the next, and first-upload-wins gave the second one the first one's mode. */
532
535
  upload(id, source, wrap = "clamp") {
533
- if (this.map.has(id)) return id;
536
+ const cached = this.map.get(id);
537
+ if (cached) {
538
+ if (this.wraps.get(id) !== wrap) this.applyWrap(id, cached, wrap);
539
+ return id;
540
+ }
534
541
  const gl = this.gl;
535
542
  const tex = gl.createTexture();
536
543
  if (!tex) throw new Error(`GLTextureCache: createTexture failed for id="${id}"`);
@@ -543,8 +550,18 @@ var GLTextureCache = class {
543
550
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, wrapMode);
544
551
  gl.bindTexture(gl.TEXTURE_2D, null);
545
552
  this.map.set(id, tex);
553
+ this.wraps.set(id, wrap);
546
554
  return id;
547
555
  }
556
+ applyWrap(id, tex, wrap) {
557
+ const gl = this.gl;
558
+ const mode = wrap === "repeat" ? gl.REPEAT : gl.CLAMP_TO_EDGE;
559
+ gl.bindTexture(gl.TEXTURE_2D, tex);
560
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, mode);
561
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, mode);
562
+ gl.bindTexture(gl.TEXTURE_2D, null);
563
+ this.wraps.set(id, wrap);
564
+ }
548
565
  /** Create a single-channel R8 texture from raw bytes (full upload).
549
566
  * No-op if `id` already exists. Same LINEAR/CLAMP params as `upload`;
550
567
  * UNPACK_ALIGNMENT dropped to 1 for non-4-aligned row widths. */
@@ -563,6 +580,7 @@ var GLTextureCache = class {
563
580
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
564
581
  gl.bindTexture(gl.TEXTURE_2D, null);
565
582
  this.map.set(id, tex);
583
+ this.wraps.set(id, "clamp");
566
584
  }
567
585
  /** Patch a rect of an existing R8 texture with tightly-packed w×h bytes. */
568
586
  subImageR8(id, x, y, w, h, data) {
@@ -594,6 +612,7 @@ var GLTextureCache = class {
594
612
  gl.deleteTexture(tex);
595
613
  }
596
614
  this.map.clear();
615
+ this.wraps.clear();
597
616
  }
598
617
  };
599
618
 
@@ -1282,6 +1301,13 @@ var GroupState = class {
1282
1301
  this.alphaStack.push(nextAlpha);
1283
1302
  this.colorMatrixStack.push(nextCM);
1284
1303
  }
1304
+ /** Drop every pushed frame, leaving the root. A frame that throws part-way
1305
+ * down the tree never pops, and the next frame would draw under leftovers. */
1306
+ reset() {
1307
+ this.transformStack.length = 1;
1308
+ this.alphaStack.length = 1;
1309
+ this.colorMatrixStack.length = 1;
1310
+ }
1285
1311
  pop() {
1286
1312
  if (this.transformStack.length <= 1) {
1287
1313
  throw new Error("GroupState.pop: cannot pop root frame");
@@ -1935,16 +1961,28 @@ function verticalAlignOffset(align, boxHeight, textHeight) {
1935
1961
 
1936
1962
  // src/features/paths/pathFromD.ts
1937
1963
  var NUM_RE = /[+-]?(?:\d*\.\d+|\d+\.?)(?:[eE][+-]?\d+)?/g;
1964
+ var NUM_RE_AT = /[+-]?(?:\d*\.\d+|\d+\.?)(?:[eE][+-]?\d+)?/y;
1965
+ function isCommandLetter(d, j) {
1966
+ const c = d[j];
1967
+ if (!/[A-Za-z]/.test(c)) return false;
1968
+ if (c !== "e" && c !== "E") return true;
1969
+ if (!/[\d.]/.test(d[j - 1] ?? "")) return true;
1970
+ const k = d[j + 1] === "+" || d[j + 1] === "-" ? j + 2 : j + 1;
1971
+ return !/\d/.test(d[k] ?? "");
1972
+ }
1938
1973
  function tokenize(d) {
1939
1974
  const out = [];
1940
1975
  let i = 0;
1941
1976
  while (i < d.length) {
1942
- const ch = d[i];
1943
- if (/[A-Za-z]/.test(ch)) {
1977
+ if (isCommandLetter(d, i)) {
1944
1978
  let j = i + 1;
1945
- while (j < d.length && !/[A-Za-z]/.test(d[j])) j++;
1979
+ while (j < d.length && !isCommandLetter(d, j)) j++;
1946
1980
  const argSlice = d.slice(i + 1, j);
1947
- out.push({ cmd: ch, args: readNumbers(argSlice) });
1981
+ const cmd = d[i];
1982
+ out.push({
1983
+ cmd,
1984
+ args: cmd === "A" || cmd === "a" ? readArcArgs(argSlice) : readNumbers(argSlice)
1985
+ });
1948
1986
  i = j;
1949
1987
  } else {
1950
1988
  i++;
@@ -1962,6 +2000,30 @@ function readNumbers(s) {
1962
2000
  }
1963
2001
  return out;
1964
2002
  }
2003
+ function readArcArgs(s) {
2004
+ const out = [];
2005
+ let i = 0;
2006
+ while (i < s.length) {
2007
+ const c = s[i];
2008
+ if (c === "," || c === " " || c === " " || c === "\n" || c === "\r") {
2009
+ i++;
2010
+ continue;
2011
+ }
2012
+ const slot = out.length % 7;
2013
+ if (slot === 3 || slot === 4) {
2014
+ if (c !== "0" && c !== "1") return out;
2015
+ out.push(c === "1" ? 1 : 0);
2016
+ i++;
2017
+ continue;
2018
+ }
2019
+ NUM_RE_AT.lastIndex = i;
2020
+ const m = NUM_RE_AT.exec(s);
2021
+ if (!m) return out;
2022
+ out.push(Number(m[0]));
2023
+ i = NUM_RE_AT.lastIndex;
2024
+ }
2025
+ return out;
2026
+ }
1965
2027
  var ARG_COUNTS = {
1966
2028
  M: 2,
1967
2029
  L: 2,
@@ -2879,42 +2941,42 @@ var MAX_VERTICES_PER_BATCH = 32768;
2879
2941
  var FLOATS_PER_VERTEX = 6;
2880
2942
  var INITIAL_VERTICES = 256;
2881
2943
  var INITIAL_INDICES = 384;
2944
+ var SOLID_RING_SIZE = 64;
2945
+ var SOLID_RING_SLOT_VERTICES = 1024;
2946
+ var SOLID_RING_SLOT_INDICES = 3072;
2947
+ var SOLID_LARGE_RING_SIZE = 4;
2948
+ function doubledTo(from, need) {
2949
+ let capacity = from;
2950
+ while (capacity < need) capacity *= 2;
2951
+ return capacity;
2952
+ }
2882
2953
  var SolidBatch = class {
2883
2954
  gl;
2884
- vao;
2885
- vbo;
2886
- ibo;
2955
+ aPos;
2956
+ aColor;
2957
+ /** Cycled per flush, and created on first use so a renderer that flushes
2958
+ * rarely allocates as few slots as it flushes. */
2959
+ ring = new Array(SOLID_RING_SIZE).fill(void 0);
2960
+ next = 0;
2961
+ /** The same, for flushes past a slot's capacity; these sets grow to fit. */
2962
+ largeRing = new Array(SOLID_LARGE_RING_SIZE).fill(void 0);
2963
+ nextLarge = 0;
2887
2964
  verts = new Float32Array(INITIAL_VERTICES * FLOATS_PER_VERTEX);
2888
2965
  idx = new Uint32Array(INITIAL_INDICES);
2889
2966
  nVerts = 0;
2890
2967
  nIdx = 0;
2891
- /** What the GPU buffers are currently sized for. */
2892
- vboVerts = 0;
2893
- iboIdx = 0;
2968
+ /** Whether the staged run is rects alone, so its indices are the canonical
2969
+ * quad pattern and a slot already holding that pattern needs no upload. */
2970
+ pureRects = true;
2894
2971
  constructor(gl, prog) {
2895
2972
  const aPos = prog.attribute("a_position");
2896
2973
  const aColor = prog.attribute("a_vertexColor");
2897
2974
  if (aPos === void 0 || aColor === void 0) {
2898
2975
  throw new Error("SolidBatch: vertex-color program is missing a_position / a_vertexColor");
2899
2976
  }
2900
- const vao = gl.createVertexArray();
2901
- const vbo = gl.createBuffer();
2902
- const ibo = gl.createBuffer();
2903
- if (!vao || !vbo || !ibo) throw new Error("SolidBatch: failed to create GL objects");
2904
2977
  this.gl = gl;
2905
- this.vao = vao;
2906
- this.vbo = vbo;
2907
- this.ibo = ibo;
2908
- const stride = FLOATS_PER_VERTEX * 4;
2909
- gl.bindVertexArray(vao);
2910
- gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
2911
- gl.enableVertexAttribArray(aPos);
2912
- gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, stride, 0);
2913
- gl.enableVertexAttribArray(aColor);
2914
- gl.vertexAttribPointer(aColor, 4, gl.FLOAT, false, stride, 8);
2915
- gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo);
2916
- gl.bindVertexArray(null);
2917
- this.growGpu(INITIAL_VERTICES, INITIAL_INDICES);
2978
+ this.aPos = aPos;
2979
+ this.aColor = aColor;
2918
2980
  }
2919
2981
  get length() {
2920
2982
  return this.nIdx;
@@ -2984,6 +3046,7 @@ var SolidBatch = class {
2984
3046
  const srcIdx = mesh.indices;
2985
3047
  const n = src.length >> 1;
2986
3048
  this.reserve(n, srcIdx.length);
3049
+ this.pureRects = false;
2987
3050
  const v = this.verts;
2988
3051
  let i = this.nVerts * FLOATS_PER_VERTEX;
2989
3052
  const ma = m[0], mb = m[1], mc = m[3], md = m[4], mtx = m[6], mty = m[7];
@@ -3004,67 +3067,109 @@ var SolidBatch = class {
3004
3067
  this.nVerts += n;
3005
3068
  this.nIdx += srcIdx.length;
3006
3069
  }
3007
- /** Upload the staged geometry and bind the batch VAO. Returns the index
3008
- * count for the caller's `drawElements`. */
3070
+ /** Upload the staged geometry into the next set of buffers and bind its VAO.
3071
+ * Returns the index count for the caller's `drawElements`. */
3009
3072
  uploadAndBind() {
3010
3073
  const gl = this.gl;
3011
- if (this.nVerts > this.vboVerts || this.nIdx > this.iboIdx) {
3012
- this.growGpu(this.nVerts, this.nIdx);
3013
- }
3014
- gl.bindVertexArray(this.vao);
3015
- gl.bindBuffer(gl.ARRAY_BUFFER, this.vbo);
3074
+ const set = this.nVerts <= SOLID_RING_SLOT_VERTICES && this.nIdx <= SOLID_RING_SLOT_INDICES ? this.nextRingSlot() : this.nextLargeSlot();
3075
+ gl.bindVertexArray(set.vao);
3076
+ gl.bindBuffer(gl.ARRAY_BUFFER, set.vbo);
3016
3077
  gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.verts, 0, this.nVerts * FLOATS_PER_VERTEX);
3017
- gl.bufferSubData(gl.ELEMENT_ARRAY_BUFFER, 0, this.idx, 0, this.nIdx);
3078
+ const rects = this.pureRects ? this.nVerts >> 2 : -1;
3079
+ if (rects < 0 || rects !== set.indexRects) {
3080
+ gl.bufferSubData(gl.ELEMENT_ARRAY_BUFFER, 0, this.idx, 0, this.nIdx);
3081
+ set.indexRects = rects;
3082
+ }
3018
3083
  return this.nIdx;
3019
3084
  }
3020
3085
  reset() {
3021
3086
  this.nVerts = 0;
3022
3087
  this.nIdx = 0;
3088
+ this.pureRects = true;
3023
3089
  }
3024
3090
  dispose() {
3025
- const gl = this.gl;
3026
- gl.deleteBuffer(this.vbo);
3027
- gl.deleteBuffer(this.ibo);
3028
- gl.deleteVertexArray(this.vao);
3091
+ for (const set of [...this.ring, ...this.largeRing]) {
3092
+ if (set) this.deleteSet(set);
3093
+ }
3094
+ this.ring.fill(void 0);
3095
+ this.largeRing.fill(void 0);
3029
3096
  }
3030
3097
  /** Grow the CPU arrays so `vertices` / `indices` more fit. */
3031
3098
  reserve(vertices, indices) {
3032
3099
  const needVerts = (this.nVerts + vertices) * FLOATS_PER_VERTEX;
3033
3100
  if (needVerts > this.verts.length) {
3034
- let len = this.verts.length;
3035
- while (len < needVerts) len *= 2;
3036
- const grown = new Float32Array(len);
3101
+ const grown = new Float32Array(doubledTo(this.verts.length, needVerts));
3037
3102
  grown.set(this.verts);
3038
3103
  this.verts = grown;
3039
3104
  }
3040
3105
  const needIdx = this.nIdx + indices;
3041
3106
  if (needIdx > this.idx.length) {
3042
- let len = this.idx.length;
3043
- while (len < needIdx) len *= 2;
3044
- const grown = new Uint32Array(len);
3107
+ const grown = new Uint32Array(doubledTo(this.idx.length, needIdx));
3045
3108
  grown.set(this.idx);
3046
3109
  this.idx = grown;
3047
3110
  }
3048
3111
  }
3049
- /** Size both GPU buffers for at least what is staged, doubling to amortize. */
3050
- growGpu(vertices, indices) {
3112
+ nextRingSlot() {
3113
+ const slot = this.next;
3114
+ this.next = (slot + 1) % SOLID_RING_SIZE;
3115
+ const existing = this.ring[slot];
3116
+ if (existing) return existing;
3117
+ const set = this.createSet(SOLID_RING_SLOT_VERTICES, SOLID_RING_SLOT_INDICES);
3118
+ this.ring[slot] = set;
3119
+ return set;
3120
+ }
3121
+ nextLargeSlot() {
3051
3122
  const gl = this.gl;
3052
- if (vertices > this.vboVerts) {
3053
- let capacity = Math.max(this.vboVerts, INITIAL_VERTICES);
3054
- while (capacity < vertices) capacity *= 2;
3055
- gl.bindBuffer(gl.ARRAY_BUFFER, this.vbo);
3056
- gl.bufferData(gl.ARRAY_BUFFER, capacity * FLOATS_PER_VERTEX * 4, gl.DYNAMIC_DRAW);
3057
- this.vboVerts = capacity;
3058
- }
3059
- if (indices > this.iboIdx) {
3060
- let capacity = Math.max(this.iboIdx, INITIAL_INDICES);
3061
- while (capacity < indices) capacity *= 2;
3062
- gl.bindVertexArray(this.vao);
3063
- gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.ibo);
3064
- gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, capacity * 4, gl.DYNAMIC_DRAW);
3123
+ const slot = this.nextLarge;
3124
+ this.nextLarge = (slot + 1) % SOLID_LARGE_RING_SIZE;
3125
+ let set = this.largeRing[slot];
3126
+ if (!set) {
3127
+ set = this.createSet(
3128
+ doubledTo(SOLID_RING_SLOT_VERTICES, this.nVerts),
3129
+ doubledTo(SOLID_RING_SLOT_INDICES, this.nIdx)
3130
+ );
3131
+ this.largeRing[slot] = set;
3132
+ return set;
3133
+ }
3134
+ if (this.nVerts > set.vertexCapacity) {
3135
+ set.vertexCapacity = doubledTo(set.vertexCapacity, this.nVerts);
3136
+ gl.bindBuffer(gl.ARRAY_BUFFER, set.vbo);
3137
+ gl.bufferData(gl.ARRAY_BUFFER, set.vertexCapacity * FLOATS_PER_VERTEX * 4, gl.DYNAMIC_DRAW);
3138
+ }
3139
+ if (this.nIdx > set.indexCapacity) {
3140
+ set.indexCapacity = doubledTo(set.indexCapacity, this.nIdx);
3141
+ gl.bindVertexArray(set.vao);
3142
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, set.ibo);
3143
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, set.indexCapacity * 4, gl.DYNAMIC_DRAW);
3065
3144
  gl.bindVertexArray(null);
3066
- this.iboIdx = capacity;
3145
+ set.indexRects = -1;
3067
3146
  }
3147
+ return set;
3148
+ }
3149
+ createSet(vertices, indices) {
3150
+ const gl = this.gl;
3151
+ const vao = gl.createVertexArray();
3152
+ const vbo = gl.createBuffer();
3153
+ const ibo = gl.createBuffer();
3154
+ if (!vao || !vbo || !ibo) throw new Error("SolidBatch: failed to create GL objects");
3155
+ const stride = FLOATS_PER_VERTEX * 4;
3156
+ gl.bindVertexArray(vao);
3157
+ gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
3158
+ gl.bufferData(gl.ARRAY_BUFFER, vertices * stride, gl.DYNAMIC_DRAW);
3159
+ gl.enableVertexAttribArray(this.aPos);
3160
+ gl.vertexAttribPointer(this.aPos, 2, gl.FLOAT, false, stride, 0);
3161
+ gl.enableVertexAttribArray(this.aColor);
3162
+ gl.vertexAttribPointer(this.aColor, 4, gl.FLOAT, false, stride, 8);
3163
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo);
3164
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices * 4, gl.DYNAMIC_DRAW);
3165
+ gl.bindVertexArray(null);
3166
+ return { vao, vbo, ibo, vertexCapacity: vertices, indexCapacity: indices, indexRects: -1 };
3167
+ }
3168
+ deleteSet(set) {
3169
+ const gl = this.gl;
3170
+ gl.deleteBuffer(set.vbo);
3171
+ gl.deleteBuffer(set.ibo);
3172
+ gl.deleteVertexArray(set.vao);
3068
3173
  }
3069
3174
  };
3070
3175
 
@@ -3089,6 +3194,25 @@ function sameValues(prev, next) {
3089
3194
  for (let i = 0; i < prev.length; i++) if (prev[i] !== next[i]) return false;
3090
3195
  return true;
3091
3196
  }
3197
+ function setColorUniform(ctx, prog, r, g, b, a) {
3198
+ const loc = prog.uniform("u_color");
3199
+ if (loc === void 0) return;
3200
+ const uploaded = uploadedFor(ctx, prog);
3201
+ const prev = uploaded.color;
3202
+ if (prev !== void 0 && prev[0] === r && prev[1] === g && prev[2] === b && prev[3] === a) {
3203
+ return;
3204
+ }
3205
+ ctx.gl.uniform4f(loc, r, g, b, a);
3206
+ uploaded.color = [r, g, b, a];
3207
+ }
3208
+ function setAlphaUniform(ctx, prog, alpha) {
3209
+ const loc = prog.uniform("u_alpha");
3210
+ if (loc === void 0) return;
3211
+ const uploaded = uploadedFor(ctx, prog);
3212
+ if (uploaded.alpha === alpha) return;
3213
+ ctx.gl.uniform1f(loc, alpha);
3214
+ uploaded.alpha = alpha;
3215
+ }
3092
3216
  var BATCH_MODEL = mat3.identity();
3093
3217
  function projFor(ctx) {
3094
3218
  let proj = FRAME_PROJ.get(ctx);
@@ -3381,8 +3505,8 @@ function flushSolids(ctx) {
3381
3505
  gl.useProgram(prog.handle);
3382
3506
  const indexCount = batch.uploadAndBind();
3383
3507
  setProjAndModel(ctx, prog, BATCH_MODEL);
3384
- gl.uniform4f(prog.uniform("u_color"), 1, 1, 1, 1);
3385
- gl.uniform1f(prog.uniform("u_alpha"), staged.alpha);
3508
+ setColorUniform(ctx, prog, 1, 1, 1, 1);
3509
+ setAlphaUniform(ctx, prog, staged.alpha);
3386
3510
  setColorMatrixUniforms(ctx, prog, staged.colorMatrix);
3387
3511
  applyClipTest(ctx, staged.clipDepth);
3388
3512
  gl.drawElements(gl.TRIANGLES, indexCount, gl.UNSIGNED_INT, 0);
@@ -3447,10 +3571,9 @@ function setProjAndModel(ctx, prog, model = ctx.state.transform) {
3447
3571
  }
3448
3572
  }
3449
3573
  function setSolidPaintUniforms(ctx, prog, color, opacity) {
3450
- const gl = ctx.gl;
3451
3574
  const [r, g, b, a] = resolveColor(color);
3452
- gl.uniform4f(prog.uniform("u_color"), r, g, b, a * (opacity ?? 1));
3453
- gl.uniform1f(prog.uniform("u_alpha"), ctx.state.alpha);
3575
+ setColorUniform(ctx, prog, r, g, b, a * (opacity ?? 1));
3576
+ setAlphaUniform(ctx, prog, ctx.state.alpha);
3454
3577
  }
3455
3578
  function drawPathFillByKind(ctx, fill, handle) {
3456
3579
  const kind = fill.fill ?? "solid";
@@ -3496,7 +3619,7 @@ function drawPathFillPattern(ctx, fill, handle) {
3496
3619
  ctx.textureCache.bind(tex.id, 0);
3497
3620
  gl.uniform1i(ctx.patternFill.uniform("u_sampler"), 0);
3498
3621
  gl.uniform1f(ctx.patternFill.uniform("u_opacity"), fill.opacity ?? 1);
3499
- gl.uniform1f(ctx.patternFill.uniform("u_alpha"), ctx.state.alpha);
3622
+ setAlphaUniform(ctx, ctx.patternFill, ctx.state.alpha);
3500
3623
  applyClipTest(ctx);
3501
3624
  gl.drawElements(gl.TRIANGLES, handle.indexCount, gl.UNSIGNED_INT, 0);
3502
3625
  gl.bindVertexArray(null);
@@ -3520,7 +3643,7 @@ function drawPathFillGradient(ctx, fill, handle) {
3520
3643
  gl.uniformMatrix3fv(ctx.gradFill.uniform("u_worldInv"), false, gradientSpaceInverse(ctx, fill.units));
3521
3644
  ctx.gradRampCache.bind(key, 0);
3522
3645
  gl.uniform1i(ctx.gradFill.uniform("u_ramp"), 0);
3523
- gl.uniform1f(ctx.gradFill.uniform("u_alpha"), ctx.state.alpha);
3646
+ setAlphaUniform(ctx, ctx.gradFill, ctx.state.alpha);
3524
3647
  gl.uniform1f(ctx.gradFill.uniform("u_opacity"), fill.opacity ?? 1);
3525
3648
  if (fill.fill === "linear-gradient") {
3526
3649
  gl.uniform1i(ctx.gradFill.uniform("u_gradKind"), 0);
@@ -3670,6 +3793,7 @@ function drawPathStrokeUnclipped(ctx, cmd) {
3670
3793
  gl.enableVertexAttribArray(aVColorLoc);
3671
3794
  gl.vertexAttribPointer(aVColorLoc, 4, gl.FLOAT, false, 0, 0);
3672
3795
  }
3796
+ applyClipTest(ctx);
3673
3797
  gl.drawElements(gl.TRIANGLES, handle.indexCount, gl.UNSIGNED_INT, 0);
3674
3798
  gl.bindVertexArray(null);
3675
3799
  gl.deleteBuffer(colorVbo);
@@ -3785,7 +3909,7 @@ function drawText(ctx, cmd) {
3785
3909
  preparedPrograms.add(prog);
3786
3910
  setProjAndModel(ctx, prog);
3787
3911
  setColorMatrixUniforms(ctx, prog);
3788
- gl.uniform1f(prog.uniform("u_alpha"), ctx.state.alpha);
3912
+ setAlphaUniform(ctx, prog, ctx.state.alpha);
3789
3913
  }
3790
3914
  drawTextGroup(ctx, group, prog, dx, dy);
3791
3915
  }
@@ -3903,8 +4027,8 @@ function drawTextDecorations(ctx, decorations, dx, dy) {
3903
4027
  if (!ibo) throw new Error("drawTextDecorations: createBuffer (IBO) returned null");
3904
4028
  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo);
3905
4029
  gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.DYNAMIC_DRAW);
3906
- gl.uniform4f(prog.uniform("u_color"), rgba[0], rgba[1], rgba[2], rgba[3]);
3907
- gl.uniform1f(prog.uniform("u_alpha"), ctx.state.alpha);
4030
+ setColorUniform(ctx, prog, rgba[0], rgba[1], rgba[2], rgba[3]);
4031
+ setAlphaUniform(ctx, prog, ctx.state.alpha);
3908
4032
  gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_INT, 0);
3909
4033
  gl.bindVertexArray(null);
3910
4034
  gl.deleteVertexArray(vao);
@@ -3988,7 +4112,7 @@ function drawTextGroup(ctx, group, prog, dx, dy) {
3988
4112
  if ("color" in group.fill) {
3989
4113
  [r, g, b, a] = resolveColor(group.fill.color);
3990
4114
  }
3991
- gl.uniform4f(prog.uniform("u_color"), r, g, b, a);
4115
+ setColorUniform(ctx, prog, r, g, b, a);
3992
4116
  const synthBoldAmount = group.synthetic.bold ? 0.08 : 0;
3993
4117
  const uSynthBold = prog.uniform("u_synthBold");
3994
4118
  if (uSynthBold !== void 0) gl.uniform1f(uSynthBold, synthBoldAmount);
@@ -4004,70 +4128,98 @@ function drawTextGroup(ctx, group, prog, dx, dy) {
4004
4128
  gl.deleteBuffer(vbo);
4005
4129
  gl.deleteBuffer(ibo);
4006
4130
  }
4131
+ var IMAGE_QUAD_RING_SIZE = 64;
4132
+ var IMAGE_QUAD_RINGS = /* @__PURE__ */ new WeakMap();
4133
+ var IMAGE_QUAD_INDICES = new Uint32Array([0, 1, 2, 1, 3, 2]);
4134
+ var IMAGE_QUAD_STRIDE = 16;
4135
+ function imageQuadRing(gl, prog) {
4136
+ const existing = IMAGE_QUAD_RINGS.get(prog);
4137
+ if (existing) return existing;
4138
+ const aPosLoc = prog.attribute("a_position");
4139
+ const aUvLoc = prog.attribute("a_uv");
4140
+ const ibo = gl.createBuffer();
4141
+ if (!ibo) throw new Error("drawImage: createBuffer (IBO) returned null");
4142
+ const vaos = [];
4143
+ const vbos = [];
4144
+ for (let slot = 0; slot < IMAGE_QUAD_RING_SIZE; slot++) {
4145
+ const vao = gl.createVertexArray();
4146
+ const vbo = gl.createBuffer();
4147
+ if (!vao) throw new Error("drawImage: createVertexArray returned null");
4148
+ if (!vbo) throw new Error("drawImage: createBuffer returned null");
4149
+ gl.bindVertexArray(vao);
4150
+ gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
4151
+ gl.bufferData(gl.ARRAY_BUFFER, 4 * IMAGE_QUAD_STRIDE, gl.DYNAMIC_DRAW);
4152
+ if (aPosLoc !== void 0) {
4153
+ gl.enableVertexAttribArray(aPosLoc);
4154
+ gl.vertexAttribPointer(aPosLoc, 2, gl.FLOAT, false, IMAGE_QUAD_STRIDE, 0);
4155
+ }
4156
+ if (aUvLoc !== void 0) {
4157
+ gl.enableVertexAttribArray(aUvLoc);
4158
+ gl.vertexAttribPointer(aUvLoc, 2, gl.FLOAT, false, IMAGE_QUAD_STRIDE, 8);
4159
+ }
4160
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo);
4161
+ if (slot === 0) gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, IMAGE_QUAD_INDICES, gl.STATIC_DRAW);
4162
+ gl.bindVertexArray(null);
4163
+ vaos.push(vao);
4164
+ vbos.push(vbo);
4165
+ }
4166
+ const ring = { vaos, vbos, ibo, next: 0 };
4167
+ IMAGE_QUAD_RINGS.set(prog, ring);
4168
+ return ring;
4169
+ }
4170
+ function disposeImageQuads(gl, prog) {
4171
+ const ring = IMAGE_QUAD_RINGS.get(prog);
4172
+ if (!ring) return;
4173
+ for (const vao of ring.vaos) gl.deleteVertexArray(vao);
4174
+ for (const vbo of ring.vbos) gl.deleteBuffer(vbo);
4175
+ gl.deleteBuffer(ring.ibo);
4176
+ IMAGE_QUAD_RINGS.delete(prog);
4177
+ }
4178
+ var IMAGE_QUAD_VERTICES = new Float32Array(16);
4007
4179
  function drawImage(ctx, cmd) {
4008
4180
  ctx.imageCache.upload(cmd.image, cmd.image);
4009
4181
  const gl = ctx.gl;
4010
- gl.useProgram(ctx.imageFill.handle);
4182
+ const prog = ctx.imageFill;
4183
+ gl.useProgram(prog.handle);
4011
4184
  const x0 = cmd.x, y0 = cmd.y;
4012
4185
  const x1 = cmd.x + cmd.w, y1 = cmd.y + cmd.h;
4013
- const vertices = new Float32Array([
4014
- x0,
4015
- y0,
4016
- 0,
4017
- 0,
4018
- x1,
4019
- y0,
4020
- 1,
4021
- 0,
4022
- x0,
4023
- y1,
4024
- 0,
4025
- 1,
4026
- x1,
4027
- y1,
4028
- 1,
4029
- 1
4030
- ]);
4031
- const indices = new Uint32Array([0, 1, 2, 1, 3, 2]);
4032
- const vao = gl.createVertexArray();
4033
- if (!vao) throw new Error("drawImage: createVertexArray returned null");
4034
- gl.bindVertexArray(vao);
4035
- const vbo = gl.createBuffer();
4036
- if (!vbo) throw new Error("drawImage: createBuffer returned null");
4037
- gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
4038
- gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.DYNAMIC_DRAW);
4039
- const stride = 16;
4040
- const aPosLoc = ctx.imageFill.attribute("a_position");
4041
- const aUvLoc = ctx.imageFill.attribute("a_uv");
4042
- if (aPosLoc !== void 0) {
4043
- gl.enableVertexAttribArray(aPosLoc);
4044
- gl.vertexAttribPointer(aPosLoc, 2, gl.FLOAT, false, stride, 0);
4045
- }
4046
- if (aUvLoc !== void 0) {
4047
- gl.enableVertexAttribArray(aUvLoc);
4048
- gl.vertexAttribPointer(aUvLoc, 2, gl.FLOAT, false, stride, 8);
4049
- }
4050
- const ibo = gl.createBuffer();
4051
- if (!ibo) throw new Error("drawImage: createBuffer (IBO) returned null");
4052
- gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo);
4053
- gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.DYNAMIC_DRAW);
4054
- setProjAndModel(ctx, ctx.imageFill);
4055
- setColorMatrixUniforms(ctx, ctx.imageFill);
4186
+ const v = IMAGE_QUAD_VERTICES;
4187
+ v[0] = x0;
4188
+ v[1] = y0;
4189
+ v[2] = 0;
4190
+ v[3] = 0;
4191
+ v[4] = x1;
4192
+ v[5] = y0;
4193
+ v[6] = 1;
4194
+ v[7] = 0;
4195
+ v[8] = x0;
4196
+ v[9] = y1;
4197
+ v[10] = 0;
4198
+ v[11] = 1;
4199
+ v[12] = x1;
4200
+ v[13] = y1;
4201
+ v[14] = 1;
4202
+ v[15] = 1;
4203
+ const ring = imageQuadRing(gl, prog);
4204
+ const slot = ring.next;
4205
+ ring.next = (slot + 1) % IMAGE_QUAD_RING_SIZE;
4206
+ gl.bindVertexArray(ring.vaos[slot]);
4207
+ gl.bindBuffer(gl.ARRAY_BUFFER, ring.vbos[slot]);
4208
+ gl.bufferSubData(gl.ARRAY_BUFFER, 0, v);
4209
+ setProjAndModel(ctx, prog);
4210
+ setColorMatrixUniforms(ctx, prog);
4056
4211
  ctx.imageCache.bind(cmd.image, 0);
4057
4212
  gl.texParameteri(
4058
4213
  gl.TEXTURE_2D,
4059
4214
  gl.TEXTURE_MAG_FILTER,
4060
4215
  cmd.sampling === "nearest" ? gl.NEAREST : gl.LINEAR
4061
4216
  );
4062
- gl.uniform1i(ctx.imageFill.uniform("u_sampler"), 0);
4063
- gl.uniform1f(ctx.imageFill.uniform("u_opacity"), cmd.opacity ?? 1);
4064
- gl.uniform1f(ctx.imageFill.uniform("u_alpha"), ctx.state.alpha);
4217
+ gl.uniform1i(prog.uniform("u_sampler"), 0);
4218
+ gl.uniform1f(prog.uniform("u_opacity"), cmd.opacity ?? 1);
4219
+ setAlphaUniform(ctx, prog, ctx.state.alpha);
4065
4220
  applyClipTest(ctx);
4066
4221
  gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_INT, 0);
4067
4222
  gl.bindVertexArray(null);
4068
- gl.deleteVertexArray(vao);
4069
- gl.deleteBuffer(vbo);
4070
- gl.deleteBuffer(ibo);
4071
4223
  }
4072
4224
 
4073
4225
  // src/renderer/shaders/customPrelude.ts
@@ -4293,6 +4445,8 @@ var WeaselRenderer = class {
4293
4445
  const program = new ShaderProgram(this.gl, vertSrc, fragSrc);
4294
4446
  program.lookupUniforms([...CUSTOM_KIT_UNIFORMS, ...extractUniformNames(fragSrc)]);
4295
4447
  program.lookupAttributes(CUSTOM_ATTRIBUTES);
4448
+ const previous = this.programRegistry.get(handle.id);
4449
+ if (previous) this.gl.deleteProgram(previous.handle);
4296
4450
  this.programRegistry.set(handle.id, program);
4297
4451
  }
4298
4452
  applyViewport() {
@@ -4391,7 +4545,7 @@ var WeaselRenderer = class {
4391
4545
  }
4392
4546
  this.meshCache.freeTransient();
4393
4547
  this.meshCache.drainPendingDeletes();
4394
- for (const prog of [this.pathFill, this.pathFillVColor, this.textSdf, this.textSdfR8, this.imageFill, this.gradFill]) {
4548
+ for (const prog of [this.pathFill, this.pathFillVColor, this.textSdf, this.textSdfR8, this.imageFill, this.gradFill, this.patternFill]) {
4395
4549
  gl.deleteProgram(prog.handle);
4396
4550
  }
4397
4551
  for (const prog of this.programRegistry.values()) {
@@ -4402,6 +4556,7 @@ var WeaselRenderer = class {
4402
4556
  this.gradRampCache.free();
4403
4557
  if (this.quadVbo) gl.deleteBuffer(this.quadVbo);
4404
4558
  if (this.quadIbo) gl.deleteBuffer(this.quadIbo);
4559
+ disposeImageQuads(gl, this.imageFill);
4405
4560
  this.solidBatch.dispose();
4406
4561
  }
4407
4562
  /**
@@ -4417,6 +4572,7 @@ var WeaselRenderer = class {
4417
4572
  const gl = this.gl;
4418
4573
  this.meshCache.drainPendingDeletes();
4419
4574
  resetBakeBudget(this.bakeBudget);
4575
+ this.groupState.reset();
4420
4576
  gl.stencilMask(255);
4421
4577
  gl.clear(gl.COLOR_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
4422
4578
  const ctx = {
@@ -5173,9 +5329,15 @@ function beginPointerDrag(payload, source, startX, startY, ghostFn) {
5173
5329
  function onUp(e) {
5174
5330
  if (!activeDrag) return;
5175
5331
  const zone = findZone(e.clientX, e.clientY, payload.kind);
5332
+ const dropped = activeDrag.payload;
5176
5333
  activeDrag.lastZone?.onOver?.(false);
5177
- if (zone) zone.onDrop(activeDrag.payload, e.clientX, e.clientY);
5178
- cleanup();
5334
+ try {
5335
+ if (zone) zone.onDrop(dropped, e.clientX, e.clientY);
5336
+ } catch (err) {
5337
+ console.error("weasel pointerDrag: drop zone onDrop threw", err);
5338
+ } finally {
5339
+ cleanup();
5340
+ }
5179
5341
  }
5180
5342
  function onCancel() {
5181
5343
  activeDrag?.lastZone?.onOver?.(false);
@@ -5196,6 +5358,10 @@ var DRAG_THRESHOLD_PX_SQ = 25;
5196
5358
  function useDragHandle(getPayload, options) {
5197
5359
  const optsRef = useRef(options);
5198
5360
  optsRef.current = options;
5361
+ const pendingTeardownRef = useRef(null);
5362
+ useEffect(() => () => {
5363
+ pendingTeardownRef.current?.();
5364
+ }, []);
5199
5365
  const onPointerDown = useCallback((e) => {
5200
5366
  if (e.pointerType === "mouse" && e.button !== 0) return;
5201
5367
  const target = e.currentTarget;
@@ -5231,10 +5397,12 @@ function useDragHandle(getPayload, options) {
5231
5397
  document.removeEventListener("pointermove", onMove);
5232
5398
  document.removeEventListener("pointerup", onEnd);
5233
5399
  document.removeEventListener("pointercancel", onEnd);
5400
+ pendingTeardownRef.current = null;
5234
5401
  }
5235
5402
  document.addEventListener("pointermove", onMove);
5236
5403
  document.addEventListener("pointerup", onEnd);
5237
5404
  document.addEventListener("pointercancel", onEnd);
5405
+ pendingTeardownRef.current = cleanup;
5238
5406
  }, [getPayload]);
5239
5407
  return { onPointerDown, style: { touchAction: "none" } };
5240
5408
  }
@@ -9073,7 +9241,7 @@ var reorderBackwardAction = {
9073
9241
  }
9074
9242
  ],
9075
9243
  eligible: { capability: "edits-page" },
9076
- requires: ["selection", "scene"],
9244
+ requires: ["selection", "scene", "applyOps"],
9077
9245
  invoker: {
9078
9246
  timing: "immediate",
9079
9247
  run: (deps, params) => {
@@ -9240,6 +9408,7 @@ function makeAlignAction(edge) {
9240
9408
  icon: ICON_FOR[edge],
9241
9409
  group: "align",
9242
9410
  eligible: { capability: "transforms-selection" },
9411
+ requires: ["selection", "scene"],
9243
9412
  // No default keybindings — six edges/centers don't fit a clean default
9244
9413
  // chord set. Wire bindings explicitly via the actions registry override map.
9245
9414
  invoker: {
@@ -9251,7 +9420,14 @@ function makeAlignAction(edge) {
9251
9420
  alignSelection(selection, scene, edge);
9252
9421
  }
9253
9422
  },
9254
- enabled: () => ActionDisabledReason.SelectionRequired
9423
+ // Deps-aware, matching `alignSelection`'s own `ids.length < 2` guard: a
9424
+ // constant disabled reason greys the entry out forever (see
9425
+ // `requiresSelection`).
9426
+ enabled: (deps) => {
9427
+ const selection = deps?.selection;
9428
+ const count = selection?.get().length ?? 0;
9429
+ return count >= 2 ? true : ActionDisabledReason.SelectionRequired;
9430
+ }
9255
9431
  };
9256
9432
  }
9257
9433
  var alignLeftAction = makeAlignAction("left");
@@ -9332,6 +9508,7 @@ function makeDistributeAction(axis) {
9332
9508
  icon: ICON_FOR2[axis],
9333
9509
  group: "distribute",
9334
9510
  eligible: { capability: "transforms-selection" },
9511
+ requires: ["selection", "scene"],
9335
9512
  // No default keybindings. Wire bindings explicitly via the actions registry.
9336
9513
  invoker: {
9337
9514
  timing: "immediate",
@@ -9342,7 +9519,14 @@ function makeDistributeAction(axis) {
9342
9519
  distributeSelection(selection, scene, axis);
9343
9520
  }
9344
9521
  },
9345
- enabled: () => ActionDisabledReason.SelectionRequired
9522
+ // Deps-aware, matching `distributeSelection`'s own `ids.length < 3` guard:
9523
+ // a constant disabled reason greys the entry out forever (see
9524
+ // `requiresSelection`).
9525
+ enabled: (deps) => {
9526
+ const selection = deps?.selection;
9527
+ const count = selection?.get().length ?? 0;
9528
+ return count >= 3 ? true : ActionDisabledReason.SelectionRequired;
9529
+ }
9346
9530
  };
9347
9531
  }
9348
9532
  var distributeHorizontalAction = makeDistributeAction("x");
@@ -9426,7 +9610,91 @@ function pathToMultiPolygon(path, opts = {}) {
9426
9610
  }
9427
9611
  finalizeCurrent();
9428
9612
  if (rings.length === 0) return [];
9429
- return rings.map((r) => [r]);
9613
+ return groupRings(rings, path.fillRule);
9614
+ }
9615
+ function ringSignedArea(ring) {
9616
+ let a = 0;
9617
+ for (let i = 0, n = ring.length - 1; i < n; i++) {
9618
+ a += ring[i][0] * ring[i + 1][1] - ring[i + 1][0] * ring[i][1];
9619
+ }
9620
+ return a * 0.5;
9621
+ }
9622
+ function ringBox(ring) {
9623
+ let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
9624
+ for (const [x, y] of ring) {
9625
+ if (x < minX) minX = x;
9626
+ if (x > maxX) maxX = x;
9627
+ if (y < minY) minY = y;
9628
+ if (y > maxY) maxY = y;
9629
+ }
9630
+ return [minX, minY, maxX, maxY];
9631
+ }
9632
+ function pointInRing(ring, px, py) {
9633
+ let inside = false;
9634
+ for (let i = 0, n = ring.length - 1; i < n; i++) {
9635
+ const [ax, ay] = ring[i];
9636
+ const [bx, by] = ring[i + 1];
9637
+ if (ay > py !== by > py && px < (bx - ax) * (py - ay) / (by - ay) + ax) {
9638
+ inside = !inside;
9639
+ }
9640
+ }
9641
+ return inside;
9642
+ }
9643
+ function ringContains(outer, outerBox, inner, innerBox) {
9644
+ if (innerBox[0] < outerBox[0] || innerBox[1] < outerBox[1] || innerBox[2] > outerBox[2] || innerBox[3] > outerBox[3]) return false;
9645
+ const n = inner.length - 1;
9646
+ let votes = 0;
9647
+ for (const k of [0, Math.floor(n / 3), Math.floor(2 * n / 3)]) {
9648
+ if (pointInRing(outer, inner[k][0], inner[k][1])) votes++;
9649
+ }
9650
+ return votes >= 2;
9651
+ }
9652
+ function groupRings(rings, fillRule) {
9653
+ const n = rings.length;
9654
+ if (n === 1) return [[rings[0]]];
9655
+ const boxes = rings.map(ringBox);
9656
+ const orient = rings.map((r) => ringSignedArea(r) >= 0 ? 1 : -1);
9657
+ const parent = new Array(n).fill(-1);
9658
+ const children = rings.map(() => []);
9659
+ for (let i = 0; i < n; i++) {
9660
+ let best = -1;
9661
+ let bestArea = Infinity;
9662
+ for (let j = 0; j < n; j++) {
9663
+ if (i === j) continue;
9664
+ if (!ringContains(rings[j], boxes[j], rings[i], boxes[i])) continue;
9665
+ const area = (boxes[j][2] - boxes[j][0]) * (boxes[j][3] - boxes[j][1]);
9666
+ if (area < bestArea) {
9667
+ bestArea = area;
9668
+ best = j;
9669
+ }
9670
+ }
9671
+ parent[i] = best;
9672
+ }
9673
+ for (let i = 0; i < n; i++) if (parent[i] >= 0) children[parent[i]].push(i);
9674
+ const filled = new Array(n);
9675
+ for (let i = 0; i < n; i++) {
9676
+ let depth = 0;
9677
+ let winding = 0;
9678
+ for (let a = i; a >= 0; a = parent[a]) {
9679
+ winding += orient[a];
9680
+ if (a !== i) depth++;
9681
+ }
9682
+ filled[i] = fillRule === "evenodd" ? depth % 2 === 0 : winding !== 0;
9683
+ }
9684
+ const out = [];
9685
+ for (let i = 0; i < n; i++) {
9686
+ if (!filled[i]) continue;
9687
+ if (parent[i] >= 0 && filled[parent[i]]) continue;
9688
+ const polygon = [rings[i]];
9689
+ const queue = [...children[i]];
9690
+ while (queue.length > 0) {
9691
+ const c = queue.pop();
9692
+ if (filled[c]) queue.push(...children[c]);
9693
+ else polygon.push(rings[c]);
9694
+ }
9695
+ out.push(polygon);
9696
+ }
9697
+ return out;
9430
9698
  }
9431
9699
  function multiPolygonToPath(mp) {
9432
9700
  let nCmds = 0;
@@ -9743,6 +10011,7 @@ function makePathfinderAction(op) {
9743
10011
  icon: ICON_FOR3[op],
9744
10012
  group: "pathfinder",
9745
10013
  eligible: { capability: "creates-shapes" },
10014
+ requires: ["selection", "booleansAdapter"],
9746
10015
  // No default keybindings — there's no industry-standard chord set for
9747
10016
  // boolean ops. Wire bindings explicitly via the actions registry override map.
9748
10017
  invoker: {
@@ -12140,10 +12409,11 @@ function createDispatcher(opts) {
12140
12409
  uiOngoingByAction.set(actionId, gestureId);
12141
12410
  notify2();
12142
12411
  let ended = false;
12412
+ const live = () => !ended && inFlightHandles.get(gestureId) === handle;
12143
12413
  return {
12144
12414
  gestureId,
12145
12415
  update(nextParams) {
12146
- if (ended) return;
12416
+ if (!live()) return;
12147
12417
  if (!handle.onMove) return;
12148
12418
  try {
12149
12419
  handle.onMove(buildUiInvocationCtx(deps, nextParams));
@@ -12153,7 +12423,10 @@ function createDispatcher(opts) {
12153
12423
  notify2();
12154
12424
  },
12155
12425
  end(reason) {
12156
- if (ended) return;
12426
+ if (!live()) {
12427
+ ended = true;
12428
+ return;
12429
+ }
12157
12430
  ended = true;
12158
12431
  if (handle.onEnd) {
12159
12432
  try {
@@ -13480,6 +13753,7 @@ function useTools(opts) {
13480
13753
  );
13481
13754
  const active = contributions.focused;
13482
13755
  const getActiveOverlays = contributions.overlays;
13756
+ const registryKey = Object.keys(slotted.registry).sort().join("|") + "#" + slotted.ambient.map((t) => t.id).join("|");
13483
13757
  return useMemo(
13484
13758
  () => ({
13485
13759
  active,
@@ -13492,7 +13766,7 @@ function useTools(opts) {
13492
13766
  has,
13493
13767
  getActiveOverlays
13494
13768
  }),
13495
- [active, setActive, hotkeyEngaged, engageHotkey, disengageHotkey, has, getActiveOverlays]
13769
+ [active, setActive, hotkeyEngaged, engageHotkey, disengageHotkey, has, getActiveOverlays, registryKey]
13496
13770
  );
13497
13771
  }
13498
13772
 
@@ -15099,8 +15373,17 @@ function composeAffordanceLayer(id, label, affordances) {
15099
15373
  // `buildAffordanceAt` share one implementation rather than two that can
15100
15374
  // drift. This wrapper lifts the region's declared cursor and claim onto
15101
15375
  // the binding, the way `buildAffordanceAt` lifts them onto `AffordanceHit`.
15102
- hitTest: (wx, wy, state, view, _dims, isVisible) => {
15103
- const hit = hitAffordanceRegions(affordances, wx, wy, state, view, isVisible);
15376
+ hitTest: (wx, wy, data, view, _dims, isVisible) => {
15377
+ const state = asChromeState(data);
15378
+ if (!state) return null;
15379
+ const hit = hitAffordanceRegions(
15380
+ affordances,
15381
+ wx,
15382
+ wy,
15383
+ state,
15384
+ view,
15385
+ isVisible ?? asIsVisible(data) ?? void 0
15386
+ );
15104
15387
  if (!hit) return null;
15105
15388
  const { cursor, strength, claimedKinds } = hit.region;
15106
15389
  return {
@@ -15460,16 +15743,6 @@ function useRotateTool(adapter, options) {
15460
15743
  [overlay, handleHitRadius, rotationHandleDistance]
15461
15744
  );
15462
15745
  }
15463
-
15464
- // src/tools/builtin/hitExistingGate.ts
15465
- function applyHitExistingGate(ctx, hitExisting) {
15466
- if (!hitExisting) return false;
15467
- const hit = hitExisting({ x: ctx.worldX, y: ctx.worldY });
15468
- if (!hit) return false;
15469
- const ids = Array.isArray(hit) ? hit : [hit];
15470
- ctx.selection.set(ids);
15471
- return true;
15472
- }
15473
15746
  function useHandTool(opts = {}) {
15474
15747
  const inertia = opts.inertia === false ? false : opts.inertia;
15475
15748
  const axis = opts.axis ?? "both";
@@ -15721,6 +15994,10 @@ function usePenTool(options) {
15721
15994
  onEnd: (endCtx, reason) => {
15722
15995
  const se = s();
15723
15996
  if (reason === "cancel") {
15997
+ if (se.current && se.draggingHandleAt === se.current.anchors.length - 1) {
15998
+ se.current.anchors.pop();
15999
+ if (se.current.anchors.length === 0) se.current = null;
16000
+ }
15724
16001
  se.draggingHandleAt = null;
15725
16002
  forceRenderRef.current();
15726
16003
  return;
@@ -17512,7 +17789,6 @@ function CanvasInner(props, ref) {
17512
17789
  shaders,
17513
17790
  previewIdsExtra,
17514
17791
  previewPoseExtra,
17515
- previewBoundsExtra,
17516
17792
  gestureSource,
17517
17793
  viewport,
17518
17794
  backgroundFill,
@@ -17538,6 +17814,7 @@ function CanvasInner(props, ref) {
17538
17814
  debugSinkRefForCtx.current = debugSink;
17539
17815
  const adapter = adapterProp;
17540
17816
  const canvasRef = useRef(null);
17817
+ const helpersForLayersRef = useRef(null);
17541
17818
  const dimsRef = useRef({ width, height });
17542
17819
  dimsRef.current = { width, height };
17543
17820
  const getIsVisibleRef = useRef(getIsVisible);
@@ -17560,7 +17837,7 @@ function CanvasInner(props, ref) {
17560
17837
  const isVisible = getIsVisibleRef.current?.() ?? alwaysVisible;
17561
17838
  for (const layer of layers2) {
17562
17839
  if (!layer.hitTest) continue;
17563
- const hit = layer.hitTest(worldX, worldY, void 0, view, dims, isVisible);
17840
+ const hit = layer.hitTest(worldX, worldY, helpersForLayersRef.current, view, dims, isVisible);
17564
17841
  if (hit) return { layerId: layer.id, hit };
17565
17842
  }
17566
17843
  return null;
@@ -17715,8 +17992,8 @@ function CanvasInner(props, ref) {
17715
17992
  };
17716
17993
  const selectedIdsForWiring = effectiveSelection.current;
17717
17994
  const multiActive2 = selectedIdsForWiring.length > 1;
17718
- const previewExtraRef = useRef({ previewPoseExtra, previewBoundsExtra });
17719
- previewExtraRef.current = { previewPoseExtra, previewBoundsExtra };
17995
+ const previewExtraRef = useRef({ previewPoseExtra });
17996
+ previewExtraRef.current = { previewPoseExtra };
17720
17997
  const effectiveBoundsOf = useMemo(() => {
17721
17998
  return boundsOf2 ?? baseBoundsOf;
17722
17999
  }, [boundsOf2, baseBoundsOf]);
@@ -17735,10 +18012,6 @@ function CanvasInner(props, ref) {
17735
18012
  if (p != null) return geometry.getBounds(p);
17736
18013
  }
17737
18014
  const extras = previewExtraRef.current;
17738
- if (extras.previewBoundsExtra) {
17739
- const b = extras.previewBoundsExtra(id);
17740
- if (b) return b;
17741
- }
17742
18015
  if (extras.previewPoseExtra) {
17743
18016
  const p = extras.previewPoseExtra(id);
17744
18017
  if (p != null) return geometry.getBounds(p);
@@ -17779,10 +18052,6 @@ function CanvasInner(props, ref) {
17779
18052
  const p = firstPreviewPose(tools, id);
17780
18053
  if (p != null) return geometry.getBounds(p);
17781
18054
  }
17782
- if (previewBoundsExtra) {
17783
- const b = previewBoundsExtra(id);
17784
- if (b) return b;
17785
- }
17786
18055
  if (previewPoseExtra) {
17787
18056
  const p = previewPoseExtra(id);
17788
18057
  if (p != null) return geometry.getBounds(p);
@@ -17818,6 +18087,7 @@ function CanvasInner(props, ref) {
17818
18087
  getDebug: () => debugSink,
17819
18088
  getIsVisible: () => getIsVisibleRef.current?.() ?? alwaysVisible
17820
18089
  };
18090
+ helpersForLayersRef.current = helpersForLayers;
17821
18091
  if (helpersRef) helpersRef.current = helpersForLayers;
17822
18092
  const pointerDownRef = useRef(false);
17823
18093
  const handlePointerDown = (e) => {
@@ -17999,6 +18269,11 @@ function CanvasInner(props, ref) {
17999
18269
  );
18000
18270
  renderer.render(commands, viewToMat3(effectiveView));
18001
18271
  }, [layersWithDebug, width, height, effectiveView, debugSink, redrawNonce, dprProp]);
18272
+ useEffect(() => () => {
18273
+ glRendererRef.current?.dispose();
18274
+ glRendererRef.current = null;
18275
+ lastResizeRef.current = null;
18276
+ }, []);
18002
18277
  const shaderIdKey = shaders?.map((h) => h.id).join("|") ?? "";
18003
18278
  useEffect(() => {
18004
18279
  const renderer = glRendererRef.current;
@@ -19463,6 +19738,89 @@ function poseContainsRotated(pose, wx, wy, tolerance) {
19463
19738
  }
19464
19739
  return poseContains(pose, wx, wy, tolerance);
19465
19740
  }
19741
+ function hiddenLayerIds(layers) {
19742
+ const out = /* @__PURE__ */ new Set();
19743
+ for (const layer of layers ?? []) {
19744
+ if (layer.visible === false) out.add(layer.id);
19745
+ }
19746
+ return out;
19747
+ }
19748
+ function hitTestArea(scene, bounds) {
19749
+ const { x, y, width: w, height: h } = bounds;
19750
+ const area = [x, y, x + w, y, x + w, y + h, x, y + h];
19751
+ return hitTestAreaPolygon(scene, area, { x, y, width: w, height: h }, true);
19752
+ }
19753
+ function hitTestAreaPolygon(scene, area, areaBounds, areaIsRect = false) {
19754
+ const ab = areaBounds ?? boundsOf(area);
19755
+ if (!ab) return [];
19756
+ const hits = [];
19757
+ const hidden = hiddenLayerIds(scene.layers);
19758
+ const order = scene.renderOrderNodes();
19759
+ for (let i = 0; i < order.length; i++) {
19760
+ const node = order[i];
19761
+ if (node.kind === "container") continue;
19762
+ if (hidden.size > 0 && hidden.has(node.layer)) continue;
19763
+ const pose = node.pose;
19764
+ const silhouette = pose !== null && typeof pose === "object" && pose.kind === "polygon";
19765
+ const b = silhouette ? nodeMemo(node, "aabb", pose, () => aabbOfPose(pose)) : aabbOfPose(pose);
19766
+ if (!Number.isFinite(b.x) || !Number.isFinite(b.y) || !Number.isFinite(b.width) || !Number.isFinite(b.height)) {
19767
+ continue;
19768
+ }
19769
+ if (b.x >= ab.x + ab.width || b.x + b.width <= ab.x || b.y >= ab.y + ab.height || b.y + b.height <= ab.y) {
19770
+ continue;
19771
+ }
19772
+ if (areaIsRect && b.x >= ab.x && b.y >= ab.y && b.x + b.width <= ab.x + ab.width && b.y + b.height <= ab.y + ab.height) {
19773
+ hits.push(node.id);
19774
+ continue;
19775
+ }
19776
+ if (silhouette) {
19777
+ if (silhouetteOverlapsArea(pose.coords, area)) {
19778
+ hits.push(node.id);
19779
+ }
19780
+ continue;
19781
+ }
19782
+ const drawn = findShapeSilhouette(node, pose);
19783
+ if (drawn?.kind === "polygon") {
19784
+ if (silhouetteOverlapsArea(drawn.coords, area)) hits.push(node.id);
19785
+ continue;
19786
+ }
19787
+ hits.push(node.id);
19788
+ }
19789
+ return hits;
19790
+ }
19791
+ function silhouetteOverlapsArea(sil, area) {
19792
+ const ns = sil.length >> 1;
19793
+ const na = area.length >> 1;
19794
+ if (ns < 1 || na < 3) return false;
19795
+ for (let i = 0; i < ns; i++) {
19796
+ if (pointInPolygon(area, sil[i * 2], sil[i * 2 + 1])) return true;
19797
+ }
19798
+ for (let i = 0; i < na; i++) {
19799
+ if (pointInPolygon(sil, area[i * 2], area[i * 2 + 1])) return true;
19800
+ }
19801
+ for (let i = 0, j = ns - 1; i < ns; j = i++) {
19802
+ const ax = sil[j * 2], ay = sil[j * 2 + 1];
19803
+ const bx = sil[i * 2], by = sil[i * 2 + 1];
19804
+ for (let k = 0, l = na - 1; k < na; l = k++) {
19805
+ const cx = area[l * 2], cy = area[l * 2 + 1];
19806
+ const dx = area[k * 2], dy = area[k * 2 + 1];
19807
+ if (segmentsCross(ax, ay, bx, by, cx, cy, dx, dy)) return true;
19808
+ }
19809
+ }
19810
+ return false;
19811
+ }
19812
+ function boundsOf(coords) {
19813
+ if (coords.length < 2) return null;
19814
+ let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
19815
+ for (let i = 0; i + 1 < coords.length; i += 2) {
19816
+ const x = coords[i], y = coords[i + 1];
19817
+ if (x < minX) minX = x;
19818
+ if (y < minY) minY = y;
19819
+ if (x > maxX) maxX = x;
19820
+ if (y > maxY) maxY = y;
19821
+ }
19822
+ return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };
19823
+ }
19466
19824
 
19467
19825
  // src/canvas/SceneCanvas/useSceneSelectTool.ts
19468
19826
  var DEFAULT_PICK_TOLERANCE_PX = 4;
@@ -19562,7 +19920,9 @@ function useSceneSelectTool(args) {
19562
19920
  }
19563
19921
  const tolerance = pickTolerancePx / meanScale(getView?.()?.scale ?? { x: 1, y: 1 });
19564
19922
  const out = [];
19923
+ const hidden = hiddenLayerIds(scene.layers);
19565
19924
  for (const n of scene.renderOrderNodes()) {
19925
+ if (hidden.size > 0 && hidden.has(n.layer)) continue;
19566
19926
  if (!poseContainsRotated(n.pose, wx, wy, tolerance)) continue;
19567
19927
  if (shapePicking && !shapeCoversPoint(n, n.pose, wx, wy, { tolerance })) continue;
19568
19928
  out.push(n.id);
@@ -20465,8 +20825,10 @@ function createPathAnchorAffordances(getAnchorState, opts = {}) {
20465
20825
  const anchors = {
20466
20826
  id: PATH_ANCHOR_CHROME_ID,
20467
20827
  regions(state) {
20828
+ const editingId = getAnchorState()?.editingId ?? null;
20468
20829
  const out = [];
20469
20830
  for (const { id, path } of editablePaths(state)) {
20831
+ if (editingId !== null && id !== editingId) continue;
20470
20832
  for (const a of enumerateAnchors(path)) {
20471
20833
  out.push(point(
20472
20834
  `${id}:anchor:${a.anchorIndex}`,
@@ -20729,80 +21091,6 @@ function DepRegistryProviderIfRoot({ children }) {
20729
21091
  if (parent) return /* @__PURE__ */ jsx(Fragment, { children });
20730
21092
  return /* @__PURE__ */ jsx(DepRegistryProvider, { children });
20731
21093
  }
20732
- function hitTestArea(scene, bounds) {
20733
- const { x, y, width: w, height: h } = bounds;
20734
- const area = [x, y, x + w, y, x + w, y + h, x, y + h];
20735
- return hitTestAreaPolygon(scene, area, { x, y, width: w, height: h }, true);
20736
- }
20737
- function hitTestAreaPolygon(scene, area, areaBounds, areaIsRect = false) {
20738
- const ab = areaBounds ?? boundsOf(area);
20739
- if (!ab) return [];
20740
- const hits = [];
20741
- const order = scene.renderOrderNodes();
20742
- for (let i = 0; i < order.length; i++) {
20743
- const node = order[i];
20744
- if (node.kind === "container") continue;
20745
- const pose = node.pose;
20746
- const silhouette = pose !== null && typeof pose === "object" && pose.kind === "polygon";
20747
- const b = silhouette ? nodeMemo(node, "aabb", pose, () => aabbOfPose(pose)) : aabbOfPose(pose);
20748
- if (!Number.isFinite(b.x) || !Number.isFinite(b.y) || !Number.isFinite(b.width) || !Number.isFinite(b.height)) {
20749
- continue;
20750
- }
20751
- if (b.x >= ab.x + ab.width || b.x + b.width <= ab.x || b.y >= ab.y + ab.height || b.y + b.height <= ab.y) {
20752
- continue;
20753
- }
20754
- if (areaIsRect && b.x >= ab.x && b.y >= ab.y && b.x + b.width <= ab.x + ab.width && b.y + b.height <= ab.y + ab.height) {
20755
- hits.push(node.id);
20756
- continue;
20757
- }
20758
- if (silhouette) {
20759
- if (silhouetteOverlapsArea(pose.coords, area)) {
20760
- hits.push(node.id);
20761
- }
20762
- continue;
20763
- }
20764
- const drawn = findShapeSilhouette(node, pose);
20765
- if (drawn?.kind === "polygon") {
20766
- if (silhouetteOverlapsArea(drawn.coords, area)) hits.push(node.id);
20767
- continue;
20768
- }
20769
- hits.push(node.id);
20770
- }
20771
- return hits;
20772
- }
20773
- function silhouetteOverlapsArea(sil, area) {
20774
- const ns = sil.length >> 1;
20775
- const na = area.length >> 1;
20776
- if (ns < 1 || na < 3) return false;
20777
- for (let i = 0; i < ns; i++) {
20778
- if (pointInPolygon(area, sil[i * 2], sil[i * 2 + 1])) return true;
20779
- }
20780
- for (let i = 0; i < na; i++) {
20781
- if (pointInPolygon(sil, area[i * 2], area[i * 2 + 1])) return true;
20782
- }
20783
- for (let i = 0, j = ns - 1; i < ns; j = i++) {
20784
- const ax = sil[j * 2], ay = sil[j * 2 + 1];
20785
- const bx = sil[i * 2], by = sil[i * 2 + 1];
20786
- for (let k = 0, l = na - 1; k < na; l = k++) {
20787
- const cx = area[l * 2], cy = area[l * 2 + 1];
20788
- const dx = area[k * 2], dy = area[k * 2 + 1];
20789
- if (segmentsCross(ax, ay, bx, by, cx, cy, dx, dy)) return true;
20790
- }
20791
- }
20792
- return false;
20793
- }
20794
- function boundsOf(coords) {
20795
- if (coords.length < 2) return null;
20796
- let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
20797
- for (let i = 0; i + 1 < coords.length; i += 2) {
20798
- const x = coords[i], y = coords[i + 1];
20799
- if (x < minX) minX = x;
20800
- if (y < minY) minY = y;
20801
- if (x > maxX) maxX = x;
20802
- if (y > maxY) maxY = y;
20803
- }
20804
- return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };
20805
- }
20806
21094
  function useViewDepSource(currentViewRef, onViewChange, recenter, hostSize) {
20807
21095
  const viewApiRef = useRef({
20808
21096
  get: () => currentViewRef.current,
@@ -21605,6 +21893,7 @@ function useActionsPropResolver(actions) {
21605
21893
  }
21606
21894
  if (!prop) return;
21607
21895
  const unregisters = [];
21896
+ const restores = [];
21608
21897
  const warnedIds = /* @__PURE__ */ new Set();
21609
21898
  for (const [slotId, entry] of Object.entries(prop)) {
21610
21899
  if (entry === null) {
@@ -21632,10 +21921,14 @@ function useActionsPropResolver(actions) {
21632
21921
  }
21633
21922
  const { id: _drop, ...rest } = entry;
21634
21923
  const merged = { ...existing, ...rest };
21924
+ restores.push(() => {
21925
+ reg.register(existing);
21926
+ });
21635
21927
  unregisters.push(reg.register(merged));
21636
21928
  }
21637
21929
  return () => {
21638
21930
  for (const u of unregisters) u();
21931
+ for (const r of restores) r();
21639
21932
  };
21640
21933
  }, [reg, actions]);
21641
21934
  }
@@ -24865,23 +25158,7 @@ function nestedHitTester(adapter, opts) {
24865
25158
  };
24866
25159
  return { pickOutermost, pickBest };
24867
25160
  }
24868
-
24869
- // src/features/paths/pathDistance.ts
24870
25161
  var BEZIER_SAMPLES = 16;
24871
- function pointSegDist2(px, py, ax, ay, bx, by) {
24872
- const dx = bx - ax, dy = by - ay;
24873
- const len2 = dx * dx + dy * dy;
24874
- if (len2 === 0) {
24875
- const ex2 = px - ax, ey2 = py - ay;
24876
- return ex2 * ex2 + ey2 * ey2;
24877
- }
24878
- let t = ((px - ax) * dx + (py - ay) * dy) / len2;
24879
- if (t < 0) t = 0;
24880
- else if (t > 1) t = 1;
24881
- const cx = ax + dx * t, cy = ay + dy * t;
24882
- const ex = px - cx, ey = py - cy;
24883
- return ex * ex + ey * ey;
24884
- }
24885
25162
  function pointCubicDist2(px, py, x0, y0, x1, y1, x2, y2, x3, y3) {
24886
25163
  let prevX = x0, prevY = y0;
24887
25164
  let best = Infinity;
@@ -24890,7 +25167,7 @@ function pointCubicDist2(px, py, x0, y0, x1, y1, x2, y2, x3, y3) {
24890
25167
  const u = 1 - t;
24891
25168
  const sx = u * u * u * x0 + 3 * u * u * t * x1 + 3 * u * t * t * x2 + t * t * t * x3;
24892
25169
  const sy = u * u * u * y0 + 3 * u * u * t * y1 + 3 * u * t * t * y2 + t * t * t * y3;
24893
- const d2 = pointSegDist2(px, py, prevX, prevY, sx, sy);
25170
+ const d2 = pointSegmentDist2(px, py, prevX, prevY, sx, sy);
24894
25171
  if (d2 < best) best = d2;
24895
25172
  prevX = sx;
24896
25173
  prevY = sy;
@@ -24927,7 +25204,7 @@ function polygonPathDistance(path, px, py) {
24927
25204
  ci += 2;
24928
25205
  } else if (cmd === PATH_L) {
24929
25206
  const x = coords[ci], y = coords[ci + 1];
24930
- const d2 = pointSegDist2(px, py, curX, curY, x, y);
25207
+ const d2 = pointSegmentDist2(px, py, curX, curY, x, y);
24931
25208
  if (d2 < best) best = d2;
24932
25209
  curX = x;
24933
25210
  curY = y;
@@ -24954,7 +25231,7 @@ function polygonPathDistance(path, px, py) {
24954
25231
  curY = y;
24955
25232
  ci += 4;
24956
25233
  } else if (cmd === PATH_Z) {
24957
- const d2 = pointSegDist2(px, py, curX, curY, startX, startY);
25234
+ const d2 = pointSegmentDist2(px, py, curX, curY, startX, startY);
24958
25235
  if (d2 < best) best = d2;
24959
25236
  curX = startX;
24960
25237
  curY = startY;
@@ -28309,6 +28586,6 @@ function mergeContributions(...bundles) {
28309
28586
  return out;
28310
28587
  }
28311
28588
 
28312
- export { ALWAYS, ANCHOR_HIT_BASE_PX, ActionsProviderIfRoot, ActiveToolContextProvider, ActiveToolContextProviderIfRoot, BUNDLE_TOOLS, COARSE_TARGET_SCALE, CURVE_REPS, ColorOverrideRegistry, CropIcon, CursorCoordsHud, DEFAULT_ALPHA_DECAY, DEFAULT_ALPHA_MIN, DEFAULT_DEBUG_STROKES, DEFAULT_DEBUG_THEME, DEFAULT_DEVICE_PROFILE, DEFAULT_FILL_COLOR, DEFAULT_HANDLE_SIZE2 as DEFAULT_HANDLE_SIZE, DEFAULT_PALETTE, DEFAULT_ROTATION_HANDLE_DISTANCE, DEFAULT_STROKE_COLOR, DEFAULT_TEXT_STYLE, DEFAULT_VELOCITY_DECAY, DepRegistryProviderIfRoot, DeviceProfileProvider, DivideIcon, EASINGS, EllipseIcon, ExcludeIcon, EyedropperIcon, FALLBACK_FIT_VIEW, GHOST_STROKE, HANDLE_BASE_PX, HandIcon, IDENTITY_COLOR_MATRIX, IDENTITY_POSE_COMPOSITION, IntersectIcon, KIT_SHAPE_KINDS, LassoIcon, LineIcon, MIXED, MOVE_ANCHORS, MinimapCanvas, NEVER, OUTLINE_MIN_SCREEN_PX, PATH_ANCHOR_CHROME_ID, PenIcon, PencilIcon, PickHud, PointerProviderIfRoot, PolygonIcon, RECT_ALIGN_PROJECTION, ROTATION_HANDLE_BASE_PX, RectIcon, SPRING_PRESETS, SceneCanvas, SceneViewCanvas, SelectIcon, SelectionContextProvider, SelectionContextProviderIfRoot, ShaderCompileError, StarIcon, SubtractIcon, TextIcon, UnionIcon, UnknownIcon, VERSION, WeaselProvider, WeaselRenderer, aabbCenter, actionIs, alignDeltaFor, alignInsertBehavior, alignMoveBehavior, alignResizeBehavior, alignedStrokeRect, always, and, animateLifecycle, animateOnSetPose, annulusSemiAxes, applyBooleanOp, applyHitExistingGate, applyStyleToRange, areaSelectAction, arrayAdapter, asNodeId, bezierCubic, bezierQuadratic, buildChromeCtx, buildGradientRamp, buildRuleCtx, buildSceneViewCommands, canBringForward, canHover, canSendBackward, capabilityAll, capabilityIn, capabilityIs, capabilityNot, caretIndexAt, cellAt, charOffsetToDomPosition, clampView, clearSelectionAction, clientToCanvas, clipboardCopyAction, clipboardCutAction, cloneAction, coarsePointer, composeAffordanceLayer, composePath, composeRectPose, composeSelectionPose, composeWorldPose, computeFitView2 as computeFitView, computeIndicatorCommand, computeWheelAction, cond, constrainTo45, containedThenNearest, countPathAnchors, createCellHighlightLayer, createChildrenLayer, createCornerResizeAffordance, createDebugOverlayLayer, createDebugSink, createDispatcher, createGridLayer, createGuidesLayer, createHistory2 as createHistory, createMarkdownRenderer, createMoveToIndexOp, createNodeProperties, createNodeRouting, createParallaxLayer, createPathAnchorAffordances, createPathEditingOverlayLayer, createPathLayer, createPenPreviewLayer, createReorderOp, createRotationAffordance, createScene, createSelectionHandlesLayer, createSelectionOutlineLayer, createSelectionOverlayLayer, createSetDataOp, createSetLayerOp, createSetPathOp, createSetTextOp, createTextLayer, createViewportLayer, cycleVertexColors, decomposePath, decomposeRectPose, defaultCommitAdapter, defaultDrawOne, defaultLabelTextRenderer, defaultNodeProperties, defaultNodeRouting, defaultVisibilityRules, defineTool, defineViewportTool, deriveAlignmentGuides, deriveParallaxView, describeRule, domPositionToCharOffset, domToRuns, drawLayers, easeIn, easeInBack, easeInBounce, easeInCirc, easeInCubic, easeInElastic, easeInExpo, easeInOut, easeInOutBack, easeInOutBounce, easeInOutCirc, easeInOutCubic, easeInOutElastic, easeInOutExpo, easeInOutQuad, easeInOutQuart, easeInOutQuint, easeInOutSine, easeInQuad, easeInQuart, easeInQuint, easeInSine, easeOut, easeOutBack, easeOutBounce, easeOutCirc, easeOutCubic2 as easeOutCubic, easeOutElastic, easeOutExpo, easeOutQuad, easeOutQuart, easeOutQuint, easeOutSine, editAnchorsAction, enterTextEditAction, enumerateAnchors, evaluate, fillInPoseFrame, fillToBoundsFrame, findNodeShape, findShapeInk, findShapeSilhouette, fitTextPose, fitToBounds, fitViewToBounds, fitZoom, focused, fontString, forEachCoalesced, freeform, gateLayer, gesturing, getAlpha01, getImageBitmap, getNodeShapes, getStylusData, gradientForBounds, gradientGeometry, hexToRgba, hitAffordanceRegions, hitAnchor, hitRotationHandle, hovering, hoveringSelected, imageStatus, inferredNodeProperties, inferredNodeRouting, insertAction, isEditableTarget2 as isEditableTarget, isPatternSpec, lassoSelectAction, layoutMarkdown, lerpColorArray, lerpOklab, lerpOklch, linear, liveScope, makeViewportZoomAction, markdownToRuns, mat3, matchAlignment, matchesKeyBinding, meanScale, measureText, measureTextBounds, measuredWidth, mergeAlphaFromPrev, mergeContributions, modeIn, modeIs, modeNot, modifierHeld, momentum, moveAction, multiActive, nearest, nearestWithin, nestedHitTester, never, nodeHasFlag, none, normalizeHex, not, nurbs, oklabToOklch, oklabToSrgbU8, oklchToOklab, openFilePicker, or, parseColor, parseColorToRgba255, parseDebugFlags, pathContainsPoint, pathContainsPolygon, pathContainsRect, pathDistanceToPoint, pathDivide, pathExclude, pathFromD, pathInPoseFrame, pathInWorld, pathIntersect, pathIntersectsPolygon, pathIntersectsRect, pathOriginProjection, pathSubtract, pathToAnchors, pathUnion, pickTopMostHit, pinchZoomAction, planPixelRender, pointInRotatedRect, pointInTextPose, poseRotationOf, pressureToWidth, rainbowVertexColors, rebaseLocalPose, rectCorners, registerContentHandler, registerNodeShape, registerProgram, renderLabel, renderSceneToCanvas, renderSceneToPixels, resizeAction, resolveColor, resolveDeviceProfile, resolveFillPattern, resolvePatternSpec, resolveRuns, resolveTextStyle, resolveVisibility, rgbaToHex, rotateAction, rotateAroundAABBCenter, rotatePathAround, rotatePoint, rotatedRectCorners, rotationDegreesUnit, rotationHandle, roundToCell, runsToDom, runsToMarkdown, runsToPlainText, sampleGradientStops, sceneFromJSON, sceneNodeClientRect, sceneToAdapter, scopeBindings, screenToWorld, selectFromLasso, selectionAtLeast, selectionEmpty, selectionIs, setFlagOverRange, shapeCoversPoint, sliceAction, snapPoint, solidVertexColors, specificity, spiro, splitPathByLine, splitSubpaths, springPose, springVertexColors, srgbU8ToOklab, staggerVertexColors, startThresholdDrag, styleAtRange, subscribeImageReady, tessellate, tessellateStroke, textCommand, textLineBoxes, tileGrid, toHex8, toRuns, translatePoseViaDescriptor, translateRectPose, tweenPose, tweenVertexColors, unionBounds, unionBoundsPath, useActiveToolContext, useAlign, useAnimator, useArrayAdapter, useAutoCenter, useBooleans, useBooleansAdapter, useCanvasFocus, useCanvasSize, useDecayLoop, useDeviceProfile, useDistribute, useDragGesture, useDragHandle, useDragRadial, useDragRect, useDropZone, useEllipseTool, useEyedropperTool, useGestureDispatcher, useGridCellHover, useGuides, useHandTool, useHandleDrag, useHoverTracking, useImageTool, useKeybindings, useLassoTool, useLineTool, useOptionalActiveToolContext, usePenTool, usePencilTool, usePinchGesture, usePinchZoomTool, usePointerStylus, usePolygonTool, usePublishSelection, useRectTool, useResizePolicy, useRotateTool, useScene, useSceneAdapter, useSceneTextEdit, useSelectTool, useSelection, useSelectionContext, useSimulation, useSliceDep, useStandardActions, useStarTool, useTextEdit, useTextTool, useTools, useVelocityTracker, useViewAnimation, useViewTween, useZoom, verticalAlignOffset, viewToMat3, viewToTransform, viewportDragPanAction, viewportZoomAction, viewportsAt, when, withAlpha01, withCoord, withGradientKind, worldEditToStorage, worldPoseLookup, worldToScreen, zoomAt, zoomAtLeast };
28313
- //# sourceMappingURL=chunk-PI56ORHE.js.map
28314
- //# sourceMappingURL=chunk-PI56ORHE.js.map
28589
+ export { ALWAYS, ANCHOR_HIT_BASE_PX, ActionsProviderIfRoot, ActiveToolContextProvider, ActiveToolContextProviderIfRoot, BUNDLE_TOOLS, COARSE_TARGET_SCALE, CURVE_REPS, ColorOverrideRegistry, CropIcon, CursorCoordsHud, DEFAULT_ALPHA_DECAY, DEFAULT_ALPHA_MIN, DEFAULT_DEBUG_STROKES, DEFAULT_DEBUG_THEME, DEFAULT_DEVICE_PROFILE, DEFAULT_FILL_COLOR, DEFAULT_HANDLE_SIZE2 as DEFAULT_HANDLE_SIZE, DEFAULT_PALETTE, DEFAULT_ROTATION_HANDLE_DISTANCE, DEFAULT_STROKE_COLOR, DEFAULT_TEXT_STYLE, DEFAULT_VELOCITY_DECAY, DepRegistryProviderIfRoot, DeviceProfileProvider, DivideIcon, EASINGS, EllipseIcon, ExcludeIcon, EyedropperIcon, FALLBACK_FIT_VIEW, GHOST_STROKE, HANDLE_BASE_PX, HandIcon, IDENTITY_COLOR_MATRIX, IDENTITY_POSE_COMPOSITION, IntersectIcon, KIT_SHAPE_KINDS, LassoIcon, LineIcon, MIXED, MOVE_ANCHORS, MinimapCanvas, NEVER, OUTLINE_MIN_SCREEN_PX, PATH_ANCHOR_CHROME_ID, PenIcon, PencilIcon, PickHud, PointerProviderIfRoot, PolygonIcon, RECT_ALIGN_PROJECTION, ROTATION_HANDLE_BASE_PX, RectIcon, SPRING_PRESETS, SceneCanvas, SceneViewCanvas, SelectIcon, SelectionContextProvider, SelectionContextProviderIfRoot, ShaderCompileError, StarIcon, SubtractIcon, TextIcon, UnionIcon, UnknownIcon, VERSION, WeaselProvider, WeaselRenderer, aabbCenter, actionIs, alignDeltaFor, alignInsertBehavior, alignMoveBehavior, alignResizeBehavior, alignedStrokeRect, always, and, animateLifecycle, animateOnSetPose, annulusSemiAxes, applyBooleanOp, applyStyleToRange, areaSelectAction, arrayAdapter, asNodeId, bezierCubic, bezierQuadratic, buildChromeCtx, buildGradientRamp, buildRuleCtx, buildSceneViewCommands, canBringForward, canHover, canSendBackward, capabilityAll, capabilityIn, capabilityIs, capabilityNot, caretIndexAt, cellAt, charOffsetToDomPosition, clampView, clearSelectionAction, clientToCanvas, clipboardCopyAction, clipboardCutAction, cloneAction, coarsePointer, composeAffordanceLayer, composePath, composeRectPose, composeSelectionPose, composeWorldPose, computeFitView2 as computeFitView, computeIndicatorCommand, computeWheelAction, cond, constrainTo45, containedThenNearest, countPathAnchors, createCellHighlightLayer, createChildrenLayer, createCornerResizeAffordance, createDebugOverlayLayer, createDebugSink, createDispatcher, createGridLayer, createGuidesLayer, createHistory2 as createHistory, createMarkdownRenderer, createMoveToIndexOp, createNodeProperties, createNodeRouting, createParallaxLayer, createPathAnchorAffordances, createPathEditingOverlayLayer, createPathLayer, createPenPreviewLayer, createReorderOp, createRotationAffordance, createScene, createSelectionHandlesLayer, createSelectionOutlineLayer, createSelectionOverlayLayer, createSetDataOp, createSetLayerOp, createSetPathOp, createSetTextOp, createTextLayer, createViewportLayer, cycleVertexColors, decomposePath, decomposeRectPose, defaultCommitAdapter, defaultDrawOne, defaultLabelTextRenderer, defaultNodeProperties, defaultNodeRouting, defaultVisibilityRules, defineTool, defineViewportTool, deriveAlignmentGuides, deriveParallaxView, describeRule, domPositionToCharOffset, domToRuns, drawLayers, easeIn, easeInBack, easeInBounce, easeInCirc, easeInCubic, easeInElastic, easeInExpo, easeInOut, easeInOutBack, easeInOutBounce, easeInOutCirc, easeInOutCubic, easeInOutElastic, easeInOutExpo, easeInOutQuad, easeInOutQuart, easeInOutQuint, easeInOutSine, easeInQuad, easeInQuart, easeInQuint, easeInSine, easeOut, easeOutBack, easeOutBounce, easeOutCirc, easeOutCubic2 as easeOutCubic, easeOutElastic, easeOutExpo, easeOutQuad, easeOutQuart, easeOutQuint, easeOutSine, editAnchorsAction, enterTextEditAction, enumerateAnchors, evaluate, fillInPoseFrame, fillToBoundsFrame, findNodeShape, findShapeInk, findShapeSilhouette, fitTextPose, fitToBounds, fitViewToBounds, fitZoom, focused, fontString, forEachCoalesced, freeform, gateLayer, gesturing, getAlpha01, getImageBitmap, getNodeShapes, getStylusData, gradientForBounds, gradientGeometry, hexToRgba, hitAffordanceRegions, hitAnchor, hitRotationHandle, hovering, hoveringSelected, imageStatus, inferredNodeProperties, inferredNodeRouting, insertAction, isEditableTarget2 as isEditableTarget, isPatternSpec, lassoSelectAction, layoutMarkdown, lerpColorArray, lerpOklab, lerpOklch, linear, liveScope, makeViewportZoomAction, markdownToRuns, mat3, matchAlignment, matchesKeyBinding, meanScale, measureText, measureTextBounds, measuredWidth, mergeAlphaFromPrev, mergeContributions, modeIn, modeIs, modeNot, modifierHeld, momentum, moveAction, multiActive, nearest, nearestWithin, nestedHitTester, never, nodeHasFlag, none, normalizeHex, not, nurbs, oklabToOklch, oklabToSrgbU8, oklchToOklab, openFilePicker, or, parseColor, parseColorToRgba255, parseDebugFlags, pathContainsPoint, pathContainsPolygon, pathContainsRect, pathDistanceToPoint, pathDivide, pathExclude, pathFromD, pathInPoseFrame, pathInWorld, pathIntersect, pathIntersectsPolygon, pathIntersectsRect, pathOriginProjection, pathSubtract, pathToAnchors, pathUnion, pickTopMostHit, pinchZoomAction, planPixelRender, pointInRotatedRect, pointInTextPose, poseRotationOf, pressureToWidth, rainbowVertexColors, rebaseLocalPose, rectCorners, registerContentHandler, registerNodeShape, registerProgram, renderLabel, renderSceneToCanvas, renderSceneToPixels, resizeAction, resolveColor, resolveDeviceProfile, resolveFillPattern, resolvePatternSpec, resolveRuns, resolveTextStyle, resolveVisibility, rgbaToHex, rotateAction, rotateAroundAABBCenter, rotatePathAround, rotatePoint, rotatedRectCorners, rotationDegreesUnit, rotationHandle, roundToCell, runsToDom, runsToMarkdown, runsToPlainText, sampleGradientStops, sceneFromJSON, sceneNodeClientRect, sceneToAdapter, scopeBindings, screenToWorld, selectFromLasso, selectionAtLeast, selectionEmpty, selectionIs, setFlagOverRange, shapeCoversPoint, sliceAction, snapPoint, solidVertexColors, specificity, spiro, splitPathByLine, splitSubpaths, springPose, springVertexColors, srgbU8ToOklab, staggerVertexColors, startThresholdDrag, styleAtRange, subscribeImageReady, tessellate, tessellateStroke, textCommand, textLineBoxes, tileGrid, toHex8, toRuns, translatePoseViaDescriptor, translateRectPose, tweenPose, tweenVertexColors, unionBounds, unionBoundsPath, useActiveToolContext, useAlign, useAnimator, useArrayAdapter, useAutoCenter, useBooleans, useBooleansAdapter, useCanvasFocus, useCanvasSize, useDecayLoop, useDeviceProfile, useDistribute, useDragGesture, useDragHandle, useDragRadial, useDragRect, useDropZone, useEllipseTool, useEyedropperTool, useGestureDispatcher, useGridCellHover, useGuides, useHandTool, useHandleDrag, useHoverTracking, useImageTool, useKeybindings, useLassoTool, useLineTool, useOptionalActiveToolContext, usePenTool, usePencilTool, usePinchGesture, usePinchZoomTool, usePointerStylus, usePolygonTool, usePublishSelection, useRectTool, useResizePolicy, useRotateTool, useScene, useSceneAdapter, useSceneTextEdit, useSelectTool, useSelection, useSelectionContext, useSimulation, useSliceDep, useStandardActions, useStarTool, useTextEdit, useTextTool, useTools, useVelocityTracker, useViewAnimation, useViewTween, useZoom, verticalAlignOffset, viewToMat3, viewToTransform, viewportDragPanAction, viewportZoomAction, viewportsAt, when, withAlpha01, withCoord, withGradientKind, worldEditToStorage, worldPoseLookup, worldToScreen, zoomAt, zoomAtLeast };
28590
+ //# sourceMappingURL=chunk-AYGSXNY3.js.map
28591
+ //# sourceMappingURL=chunk-AYGSXNY3.js.map