@weasel-js/core 1.0.3 → 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.
@@ -1,7 +1,7 @@
1
- import { ActionDisabledReason, useOptionalDepRegistry, DepRegistryProvider, useActionsRegistry, ActionsProvider, useDepRegistry, reportRouteConflicts, buildDepsFromRequires, useDepSource, actionBindings } from './chunk-TR3HZN34.js';
2
- import { scratchKey, createTransformOp, snap, getScratch, createReparentOp, setScratch } from './chunk-3KGMJMOS.js';
3
- import { fixedCornerOf, DEFAULT_RESIZE_BEHAVIORS, CORNER_ANCHORS, cornerPoint } from './chunk-3JYFAQIB.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-U45SODC2.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
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';
@@ -10,7 +10,7 @@ import { createContext, createElement, forwardRef, useMemo, useRef, useState, us
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.3" ;
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);
@@ -4092,7 +4216,7 @@ function drawImage(ctx, cmd) {
4092
4216
  );
4093
4217
  gl.uniform1i(prog.uniform("u_sampler"), 0);
4094
4218
  gl.uniform1f(prog.uniform("u_opacity"), cmd.opacity ?? 1);
4095
- gl.uniform1f(prog.uniform("u_alpha"), ctx.state.alpha);
4219
+ setAlphaUniform(ctx, prog, ctx.state.alpha);
4096
4220
  applyClipTest(ctx);
4097
4221
  gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_INT, 0);
4098
4222
  gl.bindVertexArray(null);
@@ -4321,6 +4445,8 @@ var WeaselRenderer = class {
4321
4445
  const program = new ShaderProgram(this.gl, vertSrc, fragSrc);
4322
4446
  program.lookupUniforms([...CUSTOM_KIT_UNIFORMS, ...extractUniformNames(fragSrc)]);
4323
4447
  program.lookupAttributes(CUSTOM_ATTRIBUTES);
4448
+ const previous = this.programRegistry.get(handle.id);
4449
+ if (previous) this.gl.deleteProgram(previous.handle);
4324
4450
  this.programRegistry.set(handle.id, program);
4325
4451
  }
4326
4452
  applyViewport() {
@@ -4419,7 +4545,7 @@ var WeaselRenderer = class {
4419
4545
  }
4420
4546
  this.meshCache.freeTransient();
4421
4547
  this.meshCache.drainPendingDeletes();
4422
- 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]) {
4423
4549
  gl.deleteProgram(prog.handle);
4424
4550
  }
4425
4551
  for (const prog of this.programRegistry.values()) {
@@ -4446,6 +4572,7 @@ var WeaselRenderer = class {
4446
4572
  const gl = this.gl;
4447
4573
  this.meshCache.drainPendingDeletes();
4448
4574
  resetBakeBudget(this.bakeBudget);
4575
+ this.groupState.reset();
4449
4576
  gl.stencilMask(255);
4450
4577
  gl.clear(gl.COLOR_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
4451
4578
  const ctx = {
@@ -5202,9 +5329,15 @@ function beginPointerDrag(payload, source, startX, startY, ghostFn) {
5202
5329
  function onUp(e) {
5203
5330
  if (!activeDrag) return;
5204
5331
  const zone = findZone(e.clientX, e.clientY, payload.kind);
5332
+ const dropped = activeDrag.payload;
5205
5333
  activeDrag.lastZone?.onOver?.(false);
5206
- if (zone) zone.onDrop(activeDrag.payload, e.clientX, e.clientY);
5207
- 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
+ }
5208
5341
  }
5209
5342
  function onCancel() {
5210
5343
  activeDrag?.lastZone?.onOver?.(false);
@@ -5225,6 +5358,10 @@ var DRAG_THRESHOLD_PX_SQ = 25;
5225
5358
  function useDragHandle(getPayload, options) {
5226
5359
  const optsRef = useRef(options);
5227
5360
  optsRef.current = options;
5361
+ const pendingTeardownRef = useRef(null);
5362
+ useEffect(() => () => {
5363
+ pendingTeardownRef.current?.();
5364
+ }, []);
5228
5365
  const onPointerDown = useCallback((e) => {
5229
5366
  if (e.pointerType === "mouse" && e.button !== 0) return;
5230
5367
  const target = e.currentTarget;
@@ -5260,10 +5397,12 @@ function useDragHandle(getPayload, options) {
5260
5397
  document.removeEventListener("pointermove", onMove);
5261
5398
  document.removeEventListener("pointerup", onEnd);
5262
5399
  document.removeEventListener("pointercancel", onEnd);
5400
+ pendingTeardownRef.current = null;
5263
5401
  }
5264
5402
  document.addEventListener("pointermove", onMove);
5265
5403
  document.addEventListener("pointerup", onEnd);
5266
5404
  document.addEventListener("pointercancel", onEnd);
5405
+ pendingTeardownRef.current = cleanup;
5267
5406
  }, [getPayload]);
5268
5407
  return { onPointerDown, style: { touchAction: "none" } };
5269
5408
  }
@@ -9102,7 +9241,7 @@ var reorderBackwardAction = {
9102
9241
  }
9103
9242
  ],
9104
9243
  eligible: { capability: "edits-page" },
9105
- requires: ["selection", "scene"],
9244
+ requires: ["selection", "scene", "applyOps"],
9106
9245
  invoker: {
9107
9246
  timing: "immediate",
9108
9247
  run: (deps, params) => {
@@ -9269,6 +9408,7 @@ function makeAlignAction(edge) {
9269
9408
  icon: ICON_FOR[edge],
9270
9409
  group: "align",
9271
9410
  eligible: { capability: "transforms-selection" },
9411
+ requires: ["selection", "scene"],
9272
9412
  // No default keybindings — six edges/centers don't fit a clean default
9273
9413
  // chord set. Wire bindings explicitly via the actions registry override map.
9274
9414
  invoker: {
@@ -9280,7 +9420,14 @@ function makeAlignAction(edge) {
9280
9420
  alignSelection(selection, scene, edge);
9281
9421
  }
9282
9422
  },
9283
- 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
+ }
9284
9431
  };
9285
9432
  }
9286
9433
  var alignLeftAction = makeAlignAction("left");
@@ -9361,6 +9508,7 @@ function makeDistributeAction(axis) {
9361
9508
  icon: ICON_FOR2[axis],
9362
9509
  group: "distribute",
9363
9510
  eligible: { capability: "transforms-selection" },
9511
+ requires: ["selection", "scene"],
9364
9512
  // No default keybindings. Wire bindings explicitly via the actions registry.
9365
9513
  invoker: {
9366
9514
  timing: "immediate",
@@ -9371,7 +9519,14 @@ function makeDistributeAction(axis) {
9371
9519
  distributeSelection(selection, scene, axis);
9372
9520
  }
9373
9521
  },
9374
- 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
+ }
9375
9530
  };
9376
9531
  }
9377
9532
  var distributeHorizontalAction = makeDistributeAction("x");
@@ -9455,7 +9610,91 @@ function pathToMultiPolygon(path, opts = {}) {
9455
9610
  }
9456
9611
  finalizeCurrent();
9457
9612
  if (rings.length === 0) return [];
9458
- 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;
9459
9698
  }
9460
9699
  function multiPolygonToPath(mp) {
9461
9700
  let nCmds = 0;
@@ -9772,6 +10011,7 @@ function makePathfinderAction(op) {
9772
10011
  icon: ICON_FOR3[op],
9773
10012
  group: "pathfinder",
9774
10013
  eligible: { capability: "creates-shapes" },
10014
+ requires: ["selection", "booleansAdapter"],
9775
10015
  // No default keybindings — there's no industry-standard chord set for
9776
10016
  // boolean ops. Wire bindings explicitly via the actions registry override map.
9777
10017
  invoker: {
@@ -12169,10 +12409,11 @@ function createDispatcher(opts) {
12169
12409
  uiOngoingByAction.set(actionId, gestureId);
12170
12410
  notify2();
12171
12411
  let ended = false;
12412
+ const live = () => !ended && inFlightHandles.get(gestureId) === handle;
12172
12413
  return {
12173
12414
  gestureId,
12174
12415
  update(nextParams) {
12175
- if (ended) return;
12416
+ if (!live()) return;
12176
12417
  if (!handle.onMove) return;
12177
12418
  try {
12178
12419
  handle.onMove(buildUiInvocationCtx(deps, nextParams));
@@ -12182,7 +12423,10 @@ function createDispatcher(opts) {
12182
12423
  notify2();
12183
12424
  },
12184
12425
  end(reason) {
12185
- if (ended) return;
12426
+ if (!live()) {
12427
+ ended = true;
12428
+ return;
12429
+ }
12186
12430
  ended = true;
12187
12431
  if (handle.onEnd) {
12188
12432
  try {
@@ -13509,6 +13753,7 @@ function useTools(opts) {
13509
13753
  );
13510
13754
  const active = contributions.focused;
13511
13755
  const getActiveOverlays = contributions.overlays;
13756
+ const registryKey = Object.keys(slotted.registry).sort().join("|") + "#" + slotted.ambient.map((t) => t.id).join("|");
13512
13757
  return useMemo(
13513
13758
  () => ({
13514
13759
  active,
@@ -13521,7 +13766,7 @@ function useTools(opts) {
13521
13766
  has,
13522
13767
  getActiveOverlays
13523
13768
  }),
13524
- [active, setActive, hotkeyEngaged, engageHotkey, disengageHotkey, has, getActiveOverlays]
13769
+ [active, setActive, hotkeyEngaged, engageHotkey, disengageHotkey, has, getActiveOverlays, registryKey]
13525
13770
  );
13526
13771
  }
13527
13772
 
@@ -15128,8 +15373,17 @@ function composeAffordanceLayer(id, label, affordances) {
15128
15373
  // `buildAffordanceAt` share one implementation rather than two that can
15129
15374
  // drift. This wrapper lifts the region's declared cursor and claim onto
15130
15375
  // the binding, the way `buildAffordanceAt` lifts them onto `AffordanceHit`.
15131
- hitTest: (wx, wy, state, view, _dims, isVisible) => {
15132
- 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
+ );
15133
15387
  if (!hit) return null;
15134
15388
  const { cursor, strength, claimedKinds } = hit.region;
15135
15389
  return {
@@ -15489,16 +15743,6 @@ function useRotateTool(adapter, options) {
15489
15743
  [overlay, handleHitRadius, rotationHandleDistance]
15490
15744
  );
15491
15745
  }
15492
-
15493
- // src/tools/builtin/hitExistingGate.ts
15494
- function applyHitExistingGate(ctx, hitExisting) {
15495
- if (!hitExisting) return false;
15496
- const hit = hitExisting({ x: ctx.worldX, y: ctx.worldY });
15497
- if (!hit) return false;
15498
- const ids = Array.isArray(hit) ? hit : [hit];
15499
- ctx.selection.set(ids);
15500
- return true;
15501
- }
15502
15746
  function useHandTool(opts = {}) {
15503
15747
  const inertia = opts.inertia === false ? false : opts.inertia;
15504
15748
  const axis = opts.axis ?? "both";
@@ -15750,6 +15994,10 @@ function usePenTool(options) {
15750
15994
  onEnd: (endCtx, reason) => {
15751
15995
  const se = s();
15752
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
+ }
15753
16001
  se.draggingHandleAt = null;
15754
16002
  forceRenderRef.current();
15755
16003
  return;
@@ -17541,7 +17789,6 @@ function CanvasInner(props, ref) {
17541
17789
  shaders,
17542
17790
  previewIdsExtra,
17543
17791
  previewPoseExtra,
17544
- previewBoundsExtra,
17545
17792
  gestureSource,
17546
17793
  viewport,
17547
17794
  backgroundFill,
@@ -17567,6 +17814,7 @@ function CanvasInner(props, ref) {
17567
17814
  debugSinkRefForCtx.current = debugSink;
17568
17815
  const adapter = adapterProp;
17569
17816
  const canvasRef = useRef(null);
17817
+ const helpersForLayersRef = useRef(null);
17570
17818
  const dimsRef = useRef({ width, height });
17571
17819
  dimsRef.current = { width, height };
17572
17820
  const getIsVisibleRef = useRef(getIsVisible);
@@ -17589,7 +17837,7 @@ function CanvasInner(props, ref) {
17589
17837
  const isVisible = getIsVisibleRef.current?.() ?? alwaysVisible;
17590
17838
  for (const layer of layers2) {
17591
17839
  if (!layer.hitTest) continue;
17592
- const hit = layer.hitTest(worldX, worldY, void 0, view, dims, isVisible);
17840
+ const hit = layer.hitTest(worldX, worldY, helpersForLayersRef.current, view, dims, isVisible);
17593
17841
  if (hit) return { layerId: layer.id, hit };
17594
17842
  }
17595
17843
  return null;
@@ -17744,8 +17992,8 @@ function CanvasInner(props, ref) {
17744
17992
  };
17745
17993
  const selectedIdsForWiring = effectiveSelection.current;
17746
17994
  const multiActive2 = selectedIdsForWiring.length > 1;
17747
- const previewExtraRef = useRef({ previewPoseExtra, previewBoundsExtra });
17748
- previewExtraRef.current = { previewPoseExtra, previewBoundsExtra };
17995
+ const previewExtraRef = useRef({ previewPoseExtra });
17996
+ previewExtraRef.current = { previewPoseExtra };
17749
17997
  const effectiveBoundsOf = useMemo(() => {
17750
17998
  return boundsOf2 ?? baseBoundsOf;
17751
17999
  }, [boundsOf2, baseBoundsOf]);
@@ -17764,10 +18012,6 @@ function CanvasInner(props, ref) {
17764
18012
  if (p != null) return geometry.getBounds(p);
17765
18013
  }
17766
18014
  const extras = previewExtraRef.current;
17767
- if (extras.previewBoundsExtra) {
17768
- const b = extras.previewBoundsExtra(id);
17769
- if (b) return b;
17770
- }
17771
18015
  if (extras.previewPoseExtra) {
17772
18016
  const p = extras.previewPoseExtra(id);
17773
18017
  if (p != null) return geometry.getBounds(p);
@@ -17808,10 +18052,6 @@ function CanvasInner(props, ref) {
17808
18052
  const p = firstPreviewPose(tools, id);
17809
18053
  if (p != null) return geometry.getBounds(p);
17810
18054
  }
17811
- if (previewBoundsExtra) {
17812
- const b = previewBoundsExtra(id);
17813
- if (b) return b;
17814
- }
17815
18055
  if (previewPoseExtra) {
17816
18056
  const p = previewPoseExtra(id);
17817
18057
  if (p != null) return geometry.getBounds(p);
@@ -17847,6 +18087,7 @@ function CanvasInner(props, ref) {
17847
18087
  getDebug: () => debugSink,
17848
18088
  getIsVisible: () => getIsVisibleRef.current?.() ?? alwaysVisible
17849
18089
  };
18090
+ helpersForLayersRef.current = helpersForLayers;
17850
18091
  if (helpersRef) helpersRef.current = helpersForLayers;
17851
18092
  const pointerDownRef = useRef(false);
17852
18093
  const handlePointerDown = (e) => {
@@ -18028,6 +18269,11 @@ function CanvasInner(props, ref) {
18028
18269
  );
18029
18270
  renderer.render(commands, viewToMat3(effectiveView));
18030
18271
  }, [layersWithDebug, width, height, effectiveView, debugSink, redrawNonce, dprProp]);
18272
+ useEffect(() => () => {
18273
+ glRendererRef.current?.dispose();
18274
+ glRendererRef.current = null;
18275
+ lastResizeRef.current = null;
18276
+ }, []);
18031
18277
  const shaderIdKey = shaders?.map((h) => h.id).join("|") ?? "";
18032
18278
  useEffect(() => {
18033
18279
  const renderer = glRendererRef.current;
@@ -19492,6 +19738,89 @@ function poseContainsRotated(pose, wx, wy, tolerance) {
19492
19738
  }
19493
19739
  return poseContains(pose, wx, wy, tolerance);
19494
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
+ }
19495
19824
 
19496
19825
  // src/canvas/SceneCanvas/useSceneSelectTool.ts
19497
19826
  var DEFAULT_PICK_TOLERANCE_PX = 4;
@@ -19591,7 +19920,9 @@ function useSceneSelectTool(args) {
19591
19920
  }
19592
19921
  const tolerance = pickTolerancePx / meanScale(getView?.()?.scale ?? { x: 1, y: 1 });
19593
19922
  const out = [];
19923
+ const hidden = hiddenLayerIds(scene.layers);
19594
19924
  for (const n of scene.renderOrderNodes()) {
19925
+ if (hidden.size > 0 && hidden.has(n.layer)) continue;
19595
19926
  if (!poseContainsRotated(n.pose, wx, wy, tolerance)) continue;
19596
19927
  if (shapePicking && !shapeCoversPoint(n, n.pose, wx, wy, { tolerance })) continue;
19597
19928
  out.push(n.id);
@@ -20494,8 +20825,10 @@ function createPathAnchorAffordances(getAnchorState, opts = {}) {
20494
20825
  const anchors = {
20495
20826
  id: PATH_ANCHOR_CHROME_ID,
20496
20827
  regions(state) {
20828
+ const editingId = getAnchorState()?.editingId ?? null;
20497
20829
  const out = [];
20498
20830
  for (const { id, path } of editablePaths(state)) {
20831
+ if (editingId !== null && id !== editingId) continue;
20499
20832
  for (const a of enumerateAnchors(path)) {
20500
20833
  out.push(point(
20501
20834
  `${id}:anchor:${a.anchorIndex}`,
@@ -20758,80 +21091,6 @@ function DepRegistryProviderIfRoot({ children }) {
20758
21091
  if (parent) return /* @__PURE__ */ jsx(Fragment, { children });
20759
21092
  return /* @__PURE__ */ jsx(DepRegistryProvider, { children });
20760
21093
  }
20761
- function hitTestArea(scene, bounds) {
20762
- const { x, y, width: w, height: h } = bounds;
20763
- const area = [x, y, x + w, y, x + w, y + h, x, y + h];
20764
- return hitTestAreaPolygon(scene, area, { x, y, width: w, height: h }, true);
20765
- }
20766
- function hitTestAreaPolygon(scene, area, areaBounds, areaIsRect = false) {
20767
- const ab = areaBounds ?? boundsOf(area);
20768
- if (!ab) return [];
20769
- const hits = [];
20770
- const order = scene.renderOrderNodes();
20771
- for (let i = 0; i < order.length; i++) {
20772
- const node = order[i];
20773
- if (node.kind === "container") continue;
20774
- const pose = node.pose;
20775
- const silhouette = pose !== null && typeof pose === "object" && pose.kind === "polygon";
20776
- const b = silhouette ? nodeMemo(node, "aabb", pose, () => aabbOfPose(pose)) : aabbOfPose(pose);
20777
- if (!Number.isFinite(b.x) || !Number.isFinite(b.y) || !Number.isFinite(b.width) || !Number.isFinite(b.height)) {
20778
- continue;
20779
- }
20780
- 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) {
20781
- continue;
20782
- }
20783
- 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) {
20784
- hits.push(node.id);
20785
- continue;
20786
- }
20787
- if (silhouette) {
20788
- if (silhouetteOverlapsArea(pose.coords, area)) {
20789
- hits.push(node.id);
20790
- }
20791
- continue;
20792
- }
20793
- const drawn = findShapeSilhouette(node, pose);
20794
- if (drawn?.kind === "polygon") {
20795
- if (silhouetteOverlapsArea(drawn.coords, area)) hits.push(node.id);
20796
- continue;
20797
- }
20798
- hits.push(node.id);
20799
- }
20800
- return hits;
20801
- }
20802
- function silhouetteOverlapsArea(sil, area) {
20803
- const ns = sil.length >> 1;
20804
- const na = area.length >> 1;
20805
- if (ns < 1 || na < 3) return false;
20806
- for (let i = 0; i < ns; i++) {
20807
- if (pointInPolygon(area, sil[i * 2], sil[i * 2 + 1])) return true;
20808
- }
20809
- for (let i = 0; i < na; i++) {
20810
- if (pointInPolygon(sil, area[i * 2], area[i * 2 + 1])) return true;
20811
- }
20812
- for (let i = 0, j = ns - 1; i < ns; j = i++) {
20813
- const ax = sil[j * 2], ay = sil[j * 2 + 1];
20814
- const bx = sil[i * 2], by = sil[i * 2 + 1];
20815
- for (let k = 0, l = na - 1; k < na; l = k++) {
20816
- const cx = area[l * 2], cy = area[l * 2 + 1];
20817
- const dx = area[k * 2], dy = area[k * 2 + 1];
20818
- if (segmentsCross(ax, ay, bx, by, cx, cy, dx, dy)) return true;
20819
- }
20820
- }
20821
- return false;
20822
- }
20823
- function boundsOf(coords) {
20824
- if (coords.length < 2) return null;
20825
- let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
20826
- for (let i = 0; i + 1 < coords.length; i += 2) {
20827
- const x = coords[i], y = coords[i + 1];
20828
- if (x < minX) minX = x;
20829
- if (y < minY) minY = y;
20830
- if (x > maxX) maxX = x;
20831
- if (y > maxY) maxY = y;
20832
- }
20833
- return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };
20834
- }
20835
21094
  function useViewDepSource(currentViewRef, onViewChange, recenter, hostSize) {
20836
21095
  const viewApiRef = useRef({
20837
21096
  get: () => currentViewRef.current,
@@ -21634,6 +21893,7 @@ function useActionsPropResolver(actions) {
21634
21893
  }
21635
21894
  if (!prop) return;
21636
21895
  const unregisters = [];
21896
+ const restores = [];
21637
21897
  const warnedIds = /* @__PURE__ */ new Set();
21638
21898
  for (const [slotId, entry] of Object.entries(prop)) {
21639
21899
  if (entry === null) {
@@ -21661,10 +21921,14 @@ function useActionsPropResolver(actions) {
21661
21921
  }
21662
21922
  const { id: _drop, ...rest } = entry;
21663
21923
  const merged = { ...existing, ...rest };
21924
+ restores.push(() => {
21925
+ reg.register(existing);
21926
+ });
21664
21927
  unregisters.push(reg.register(merged));
21665
21928
  }
21666
21929
  return () => {
21667
21930
  for (const u of unregisters) u();
21931
+ for (const r of restores) r();
21668
21932
  };
21669
21933
  }, [reg, actions]);
21670
21934
  }
@@ -24894,23 +25158,7 @@ function nestedHitTester(adapter, opts) {
24894
25158
  };
24895
25159
  return { pickOutermost, pickBest };
24896
25160
  }
24897
-
24898
- // src/features/paths/pathDistance.ts
24899
25161
  var BEZIER_SAMPLES = 16;
24900
- function pointSegDist2(px, py, ax, ay, bx, by) {
24901
- const dx = bx - ax, dy = by - ay;
24902
- const len2 = dx * dx + dy * dy;
24903
- if (len2 === 0) {
24904
- const ex2 = px - ax, ey2 = py - ay;
24905
- return ex2 * ex2 + ey2 * ey2;
24906
- }
24907
- let t = ((px - ax) * dx + (py - ay) * dy) / len2;
24908
- if (t < 0) t = 0;
24909
- else if (t > 1) t = 1;
24910
- const cx = ax + dx * t, cy = ay + dy * t;
24911
- const ex = px - cx, ey = py - cy;
24912
- return ex * ex + ey * ey;
24913
- }
24914
25162
  function pointCubicDist2(px, py, x0, y0, x1, y1, x2, y2, x3, y3) {
24915
25163
  let prevX = x0, prevY = y0;
24916
25164
  let best = Infinity;
@@ -24919,7 +25167,7 @@ function pointCubicDist2(px, py, x0, y0, x1, y1, x2, y2, x3, y3) {
24919
25167
  const u = 1 - t;
24920
25168
  const sx = u * u * u * x0 + 3 * u * u * t * x1 + 3 * u * t * t * x2 + t * t * t * x3;
24921
25169
  const sy = u * u * u * y0 + 3 * u * u * t * y1 + 3 * u * t * t * y2 + t * t * t * y3;
24922
- const d2 = pointSegDist2(px, py, prevX, prevY, sx, sy);
25170
+ const d2 = pointSegmentDist2(px, py, prevX, prevY, sx, sy);
24923
25171
  if (d2 < best) best = d2;
24924
25172
  prevX = sx;
24925
25173
  prevY = sy;
@@ -24956,7 +25204,7 @@ function polygonPathDistance(path, px, py) {
24956
25204
  ci += 2;
24957
25205
  } else if (cmd === PATH_L) {
24958
25206
  const x = coords[ci], y = coords[ci + 1];
24959
- const d2 = pointSegDist2(px, py, curX, curY, x, y);
25207
+ const d2 = pointSegmentDist2(px, py, curX, curY, x, y);
24960
25208
  if (d2 < best) best = d2;
24961
25209
  curX = x;
24962
25210
  curY = y;
@@ -24983,7 +25231,7 @@ function polygonPathDistance(path, px, py) {
24983
25231
  curY = y;
24984
25232
  ci += 4;
24985
25233
  } else if (cmd === PATH_Z) {
24986
- const d2 = pointSegDist2(px, py, curX, curY, startX, startY);
25234
+ const d2 = pointSegmentDist2(px, py, curX, curY, startX, startY);
24987
25235
  if (d2 < best) best = d2;
24988
25236
  curX = startX;
24989
25237
  curY = startY;
@@ -28338,6 +28586,6 @@ function mergeContributions(...bundles) {
28338
28586
  return out;
28339
28587
  }
28340
28588
 
28341
- 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 };
28342
- //# sourceMappingURL=chunk-SMCZRSYB.js.map
28343
- //# sourceMappingURL=chunk-SMCZRSYB.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