@pixerate/editor 0.41.0 → 0.42.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2; var _class3;
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2; var _class3; var _class4; var _class5;
2
2
 
3
3
  var _chunkQKLRAA4Tcjs = require('../chunk-QKLRAA4T.cjs');
4
4
 
@@ -36,6 +36,7 @@ var _chunkQKLRAA4Tcjs = require('../chunk-QKLRAA4T.cjs');
36
36
 
37
37
 
38
38
 
39
+
39
40
 
40
41
 
41
42
  var _chunkVNYRI265cjs = require('../chunk-VNYRI265.cjs');
@@ -73,6 +74,8 @@ var VECTOR_TOOLS = [
73
74
  ];
74
75
  var VECTOR_TRANSFORM_HANDLES = ["nw", "n", "ne", "e", "se", "s", "sw", "w", "rotate"];
75
76
  var VECTOR_PATHFINDER_OPERATIONS = ["divide", "trim", "merge", "crop", "outline", "minusBack"];
77
+ var VECTOR_EFFECT_TYPES = ["trim", "roundCorners", "puckerBloat", "twist", "zigzag", "wiggle", "offset", "merge", "repeater"];
78
+ var VECTOR_MERGE_MODES = ["merge", "add", "subtract", "intersect", "exclude"];
76
79
 
77
80
  // src/vector/corners.ts
78
81
  var EPS = 1e-9;
@@ -735,7 +738,7 @@ function variableStrokeOutline(path, options) {
735
738
  let polygons;
736
739
  try {
737
740
  polygons = _chunkVNYRI265cjs.polygonBoolean.call(void 0, "union", [{ rings: pieces, fillRule: "nonzero" }]);
738
- } catch (e2) {
741
+ } catch (e3) {
739
742
  return [];
740
743
  }
741
744
  const out = [];
@@ -1042,8 +1045,872 @@ function vectorStrokeReach(style) {
1042
1045
  return reach;
1043
1046
  }
1044
1047
 
1045
- // src/vector/geometry.ts
1048
+ // src/vector/pathEffects.ts
1046
1049
  var EPS2 = 1e-9;
1050
+ var degenerate = (s) => s.every((p) => Math.abs(p[0] - s[0][0]) < EPS2 && Math.abs(p[1] - s[0][1]) < EPS2);
1051
+ function raise(seg) {
1052
+ if (seg.length !== 3) return seg.map((p) => [p[0], p[1]]);
1053
+ const [p0, p1, p2] = seg;
1054
+ return [p0, [p0[0] + 2 / 3 * (p1[0] - p0[0]), p0[1] + 2 / 3 * (p1[1] - p0[1])], [p2[0] + 2 / 3 * (p1[0] - p2[0]), p2[1] + 2 / 3 * (p1[1] - p2[1])], p2];
1055
+ }
1056
+ function subsOf(path) {
1057
+ return _chunkVNYRI265cjs.pathToContours.call(void 0, path).map((c) => ({ segs: _chunkVNYRI265cjs.closeContour.call(void 0, c).filter((s) => !degenerate(s)).map(raise), closed: c.closed })).filter((s) => s.segs.length > 0);
1058
+ }
1059
+ var subsToPath = (subs) => _chunkVNYRI265cjs.contoursToPath.call(void 0, subs.map((s) => ({ segments: s.segs, closed: s.closed })));
1060
+ var unit2 = (x, y) => {
1061
+ const l = Math.hypot(x, y);
1062
+ return l > 1e-12 && Number.isFinite(l) ? [x / l, y / l] : null;
1063
+ };
1064
+ function startTangent(s) {
1065
+ for (let i = 1; i < s.length; i++) {
1066
+ const u = unit2(s[i][0] - s[0][0], s[i][1] - s[0][1]);
1067
+ if (u) return u;
1068
+ }
1069
+ return [1, 0];
1070
+ }
1071
+ function endTangent(s) {
1072
+ const end = s[s.length - 1];
1073
+ for (let i = s.length - 2; i >= 0; i--) {
1074
+ const u = unit2(end[0] - s[i][0], end[1] - s[i][1]);
1075
+ if (u) return u;
1076
+ }
1077
+ return [1, 0];
1078
+ }
1079
+ function tangentAt(s, t) {
1080
+ if (t <= 1e-9) return startTangent(s);
1081
+ if (t >= 1 - 1e-9) return endTangent(s);
1082
+ const d = _chunkVNYRI265cjs.segmentDerivative.call(void 0, s, t);
1083
+ return _nullishCoalesce(unit2(d[0], d[1]), () => ( startTangent(s)));
1084
+ }
1085
+ var perp = (v2) => [-v2[1], v2[0]];
1086
+ function effectPathLength(path) {
1087
+ let total = 0;
1088
+ for (const s of subsOf(path)) for (const seg of s.segs) total += _chunkVNYRI265cjs.segmentLength.call(void 0, seg);
1089
+ return total;
1090
+ }
1091
+ function effectPathVertexCount(path) {
1092
+ return subsOf(path).reduce((n, s) => n + s.segs.length + (s.closed ? 0 : 1), 0);
1093
+ }
1094
+ var Measured = class {
1095
+
1096
+
1097
+
1098
+ constructor(path) {
1099
+ this.segs = subsOf(path).flatMap((s) => s.segs);
1100
+ this.lens = this.segs.map((s) => _chunkVNYRI265cjs.segmentLength.call(void 0, s));
1101
+ this.total = this.lens.reduce((a, b) => a + b, 0);
1102
+ }
1103
+ /**
1104
+ * Appends the part between lengths `sa` and `sb`, continuing the last piece when this one
1105
+ * starts where it ends (across the start of a closed path).
1106
+ */
1107
+ append(sa, sb, out) {
1108
+ for (const piece of _chunkVNYRI265cjs.trimSegments.call(void 0, this.segs, sa, sb, this.lens)) {
1109
+ if (degenerate(piece)) continue;
1110
+ const last = _optionalChain([out, 'access', _28 => _28[out.length - 1], 'optionalAccess', _29 => _29.segs]);
1111
+ const end = _optionalChain([last, 'optionalAccess', _30 => _30[last.length - 1], 'optionalAccess', _31 => _31.at, 'call', _32 => _32(-1)]);
1112
+ if (!end || Math.hypot(end[0] - piece[0][0], end[1] - piece[0][1]) > 1e-6) out.push({ segs: [piece], closed: false });
1113
+ else last.push(piece);
1114
+ }
1115
+ }
1116
+ };
1117
+ function trimIntervals(start, end, offsetDegrees) {
1118
+ let s = start / 100;
1119
+ let e = end / 100;
1120
+ if (!Number.isFinite(s) || !Number.isFinite(e)) return null;
1121
+ if (s > e) [s, e] = [e, s];
1122
+ s = Math.min(1, Math.max(0, s));
1123
+ e = Math.min(1, Math.max(0, e));
1124
+ if (e - s >= 1 - 1e-9) return null;
1125
+ if (e - s <= 1e-9) return [];
1126
+ const off = Number.isFinite(offsetDegrees) ? (offsetDegrees / 360 % 1 + 1) % 1 : 0;
1127
+ s += off;
1128
+ e += off;
1129
+ if (e <= 1) return [[s, e]];
1130
+ if (s >= 1) return [[s - 1, e - 1]];
1131
+ return [
1132
+ [s, 1],
1133
+ [0, e - 1]
1134
+ ];
1135
+ }
1136
+ function trimPaths(paths, start, end, offsetDegrees = 0) {
1137
+ const iv = trimIntervals(start, end, offsetDegrees);
1138
+ if (!iv) return paths.slice();
1139
+ return paths.map((p) => {
1140
+ const m = new Measured(p);
1141
+ const out = [];
1142
+ if (m.total > 0) for (const [a, b] of iv) m.append(a * m.total, b * m.total, out);
1143
+ return subsToPath(out);
1144
+ });
1145
+ }
1146
+ function trimPathsIndividually(paths, start, end, offsetDegrees = 0) {
1147
+ const iv = trimIntervals(start, end, offsetDegrees);
1148
+ if (!iv) return paths.slice();
1149
+ const ms = paths.map((p) => new Measured(p));
1150
+ const total = ms.reduce((n, m) => n + m.total, 0);
1151
+ let base = 0;
1152
+ return ms.map((m) => {
1153
+ const out = [];
1154
+ for (const [a, b] of iv) {
1155
+ const la = Math.max(0, a * total - base);
1156
+ const lb = Math.min(m.total, b * total - base);
1157
+ if (lb > la) m.append(la, lb, out);
1158
+ }
1159
+ base += m.total;
1160
+ return subsToPath(out);
1161
+ });
1162
+ }
1163
+ function puckerBloatPaths(paths, amount) {
1164
+ const a = amount / 100;
1165
+ if (!a || !Number.isFinite(a)) return paths.slice();
1166
+ return paths.map((p) => {
1167
+ const verts = p.filter((c) => c.type !== "Z");
1168
+ if (!verts.length) return p;
1169
+ const cx = verts.reduce((s, c) => s + c.x, 0) / verts.length;
1170
+ const cy = verts.reduce((s, c) => s + c.y, 0) / verts.length;
1171
+ const mv = (x, y) => ({ x: x + (cx - x) * a, y: y + (cy - y) * a });
1172
+ const mvh = (x, y) => ({ x: x + (x - cx) * a, y: y + (y - cy) * a });
1173
+ const out = [];
1174
+ let prev = { x: 0, y: 0 };
1175
+ let start = { x: 0, y: 0 };
1176
+ const curve = (c1, c2, q) => {
1177
+ const h1 = mvh(c1.x, c1.y);
1178
+ const h2 = mvh(c2.x, c2.y);
1179
+ const e = mv(q.x, q.y);
1180
+ out.push({ type: "C", x1: h1.x, y1: h1.y, x2: h2.x, y2: h2.y, x: e.x, y: e.y });
1181
+ };
1182
+ for (const c of p) {
1183
+ switch (c.type) {
1184
+ case "M": {
1185
+ const e = mv(c.x, c.y);
1186
+ out.push({ type: "M", x: e.x, y: e.y });
1187
+ prev = start = { x: c.x, y: c.y };
1188
+ break;
1189
+ }
1190
+ case "L":
1191
+ curve(prev, c, c);
1192
+ prev = { x: c.x, y: c.y };
1193
+ break;
1194
+ case "Q": {
1195
+ const c1 = { x: prev.x + 2 / 3 * (c.x1 - prev.x), y: prev.y + 2 / 3 * (c.y1 - prev.y) };
1196
+ const c2 = { x: c.x + 2 / 3 * (c.x1 - c.x), y: c.y + 2 / 3 * (c.y1 - c.y) };
1197
+ curve(c1, c2, c);
1198
+ prev = { x: c.x, y: c.y };
1199
+ break;
1200
+ }
1201
+ case "C":
1202
+ curve({ x: c.x1, y: c.y1 }, { x: c.x2, y: c.y2 }, c);
1203
+ prev = { x: c.x, y: c.y };
1204
+ break;
1205
+ case "Z":
1206
+ if (Math.hypot(prev.x - start.x, prev.y - start.y) > EPS2) curve(prev, start, start);
1207
+ out.push({ type: "Z" });
1208
+ prev = start;
1209
+ break;
1210
+ }
1211
+ }
1212
+ return out;
1213
+ });
1214
+ }
1215
+ function roundCornerPaths(paths, radius) {
1216
+ if (!(radius > 0) || !Number.isFinite(radius)) return paths.slice();
1217
+ return paths.map((p) => subpathsToBezier(bezierToSubpaths(p).map((sp) => setSubpathCorners(sp, radius))));
1218
+ }
1219
+ function offsetPaths(paths, amount, join = "miter", miterLimit = 4, copies = 1, copyOffset = 0) {
1220
+ const n = Math.min(1e3, Math.max(1, Math.round(Number.isFinite(copies) ? copies : 1)));
1221
+ return paths.map((p) => {
1222
+ const out = [];
1223
+ for (let i = 0; i < n; i++) out.push(..._chunkVNYRI265cjs.offsetPath.call(void 0, p, amount * (i + 1 + copyOffset), { join, miterLimit }));
1224
+ return out;
1225
+ });
1226
+ }
1227
+ function twistPaths(paths, angle, center) {
1228
+ let rmax = 0;
1229
+ for (const p of paths) for (const c of p) if (c.type !== "Z") rmax = Math.max(rmax, Math.hypot(c.x - center.x, c.y - center.y));
1230
+ const a = angle * Math.PI / 180;
1231
+ if (!a || rmax <= 1e-9 || !Number.isFinite(a)) return paths.slice();
1232
+ const k = a / rmax;
1233
+ const rot = (v2, th) => {
1234
+ const s = Math.sin(th);
1235
+ const co = Math.cos(th);
1236
+ return [v2[0] * co - v2[1] * s, v2[0] * s + v2[1] * co];
1237
+ };
1238
+ const map = (p) => {
1239
+ const v2 = [p[0] - center.x, p[1] - center.y];
1240
+ const r = rot(v2, k * Math.hypot(v2[0], v2[1]));
1241
+ return [center.x + r[0], center.y + r[1]];
1242
+ };
1243
+ const jac = (p, dv) => {
1244
+ const v2 = [p[0] - center.x, p[1] - center.y];
1245
+ const r = Math.hypot(v2[0], v2[1]);
1246
+ let w = dv;
1247
+ if (r > 1e-12) {
1248
+ const f = k * (v2[0] * dv[0] + v2[1] * dv[1]) / r;
1249
+ w = [dv[0] - v2[1] * f, dv[1] + v2[0] * f];
1250
+ }
1251
+ return rot(w, k * r);
1252
+ };
1253
+ return paths.map((p) => {
1254
+ const out = [];
1255
+ for (const sub3 of subsOf(p)) {
1256
+ const segs = [];
1257
+ for (const seg of sub3.segs) {
1258
+ const cubic = seg.length === 2 ? [seg[0], seg[0], seg[1], seg[1]] : seg;
1259
+ const len2 = _chunkVNYRI265cjs.segmentLength.call(void 0, seg);
1260
+ const m = Math.min(64, Math.max(1, Math.ceil(Math.abs(a) * len2 / rmax / 0.15 + len2 / 50)));
1261
+ for (let i = 0; i < m; i++) {
1262
+ const q = _chunkVNYRI265cjs.subSegment.call(void 0, cubic, i / m, (i + 1) / m);
1263
+ const p0 = map(q[0]);
1264
+ const p3 = map(q[3]);
1265
+ const h1 = jac(q[0], [q[1][0] - q[0][0], q[1][1] - q[0][1]]);
1266
+ const h2 = jac(q[3], [q[2][0] - q[3][0], q[2][1] - q[3][1]]);
1267
+ segs.push([p0, [p0[0] + h1[0], p0[1] + h1[1]], [p3[0] + h2[0], p3[1] + h2[1]], p3]);
1268
+ }
1269
+ }
1270
+ out.push({ segs, closed: sub3.closed });
1271
+ }
1272
+ return subsToPath(out);
1273
+ });
1274
+ }
1275
+ function resample(sub3, m) {
1276
+ const segs = sub3.segs;
1277
+ const n = segs.length;
1278
+ const lens = segs.map((s) => _chunkVNYRI265cjs.segmentLength.call(void 0, s));
1279
+ const out = [];
1280
+ for (let j = 0; j < n; j++) {
1281
+ const piece = lens[j] / m;
1282
+ for (let k = 0; k < m; k++) {
1283
+ if (k === 0) {
1284
+ const tout = startTangent(segs[j]);
1285
+ const prev = sub3.closed || j > 0 ? (j + n - 1) % n : null;
1286
+ let tan = tout;
1287
+ if (prev !== null) {
1288
+ const tin = endTangent(segs[prev]);
1289
+ tan = _nullishCoalesce(unit2(tin[0] + tout[0], tin[1] + tout[1]), () => ( tout));
1290
+ }
1291
+ out.push({ p: segs[j][0], tan, lenPrev: prev === null ? 0 : lens[prev] / m, lenNext: piece });
1292
+ } else {
1293
+ const t = _chunkVNYRI265cjs.segmentParamAtLength.call(void 0, segs[j], piece * k, lens[j]);
1294
+ out.push({ p: _chunkVNYRI265cjs.segmentPoint.call(void 0, segs[j], t), tan: tangentAt(segs[j], t), lenPrev: piece, lenNext: piece });
1295
+ }
1296
+ }
1297
+ }
1298
+ if (!sub3.closed) {
1299
+ const last = segs[n - 1];
1300
+ out.push({ p: last[last.length - 1], tan: endTangent(last), lenPrev: lens[n - 1] / m, lenNext: 0 });
1301
+ }
1302
+ return out;
1303
+ }
1304
+ function emit(samples, disp, closed, smooth, handle) {
1305
+ const n = samples.length;
1306
+ if (!n) return null;
1307
+ const pt2 = (i) => [samples[i].p[0] + disp[i][0], samples[i].p[1] + disp[i][1]];
1308
+ const segs = [];
1309
+ const count = closed ? n : n - 1;
1310
+ for (let i = 0; i < count; i++) {
1311
+ const j = (i + 1) % n;
1312
+ const a = samples[i];
1313
+ const b = samples[j];
1314
+ const p = pt2(i);
1315
+ const q = pt2(j);
1316
+ if (smooth) segs.push([p, [p[0] + a.tan[0] * a.lenNext * handle, p[1] + a.tan[1] * a.lenNext * handle], [q[0] - b.tan[0] * b.lenPrev * handle, q[1] - b.tan[1] * b.lenPrev * handle], q]);
1317
+ else segs.push([p, q]);
1318
+ }
1319
+ if (!segs.length) return null;
1320
+ return { segs, closed };
1321
+ }
1322
+ function zigzagPaths(paths, size, ridges, smooth = false) {
1323
+ const m = Math.min(1e3, Math.max(0, Math.round(Number.isFinite(ridges) ? ridges : 0))) + 1;
1324
+ return paths.map((p) => {
1325
+ const out = [];
1326
+ for (const sub3 of subsOf(p)) {
1327
+ const s = resample(sub3, m);
1328
+ const disp = s.map((x, i) => {
1329
+ const n = perp(x.tan);
1330
+ const d = i % 2 === 0 ? size : -size;
1331
+ return [n[0] * d, n[1] * d];
1332
+ });
1333
+ const e = emit(s, disp, sub3.closed, smooth, 0.36);
1334
+ if (e) out.push(e);
1335
+ }
1336
+ return subsToPath(out);
1337
+ });
1338
+ }
1339
+ var MASK64 = (1n << 64n) - 1n;
1340
+ function splitmix(x) {
1341
+ x = x + 0x9e3779b97f4a7c15n & MASK64;
1342
+ let z = x;
1343
+ z = (z ^ z >> 30n) * 0xbf58476d1ce4e5b9n & MASK64;
1344
+ z = (z ^ z >> 27n) * 0x94d049bb133111ebn & MASK64;
1345
+ return z ^ z >> 31n;
1346
+ }
1347
+ function hash(seed, idx, t) {
1348
+ const h = splitmix(splitmix(splitmix(seed) ^ idx) ^ BigInt.asUintN(64, BigInt(t)));
1349
+ return Number(h >> 11n) / 2 ** 53 * 2 - 1;
1350
+ }
1351
+ function noise(seed, idx, t) {
1352
+ const i = Math.floor(t);
1353
+ const f = t - i;
1354
+ const p0 = hash(seed, idx, i - 1);
1355
+ const p1 = hash(seed, idx, i);
1356
+ const p2 = hash(seed, idx, i + 1);
1357
+ const p3 = hash(seed, idx, i + 2);
1358
+ const v2 = 0.5 * (2 * p1 + (-p0 + p2) * f + (2 * p0 - 5 * p1 + 4 * p2 - p3) * f * f + (-p0 + 3 * p1 - 3 * p2 + p3) * f * f * f);
1359
+ return Math.min(1, Math.max(-1, v2));
1360
+ }
1361
+ function wigglePaths(paths, w) {
1362
+ if (!w.size || !Number.isFinite(w.size)) return paths.slice();
1363
+ const m = Math.min(1e3, Math.max(0, Math.round(Number.isFinite(w.detail) ? w.detail : 0))) + 1;
1364
+ const seed = BigInt.asUintN(64, BigInt(Math.round(Number.isFinite(w.seed) ? w.seed : 0)));
1365
+ const t = (Number.isFinite(w.time) ? w.time : 0) * (Number.isFinite(w.speed) ? w.speed : 0) + (Number.isFinite(w.phase) ? w.phase : 0) / 360;
1366
+ const corr = Math.min(1, Math.max(0, (Number.isFinite(w.correlation) ? w.correlation : 0) / 100));
1367
+ const sx = noise(seed, MASK64, t);
1368
+ const sy = noise(seed, MASK64 - 1n, t);
1369
+ let idx = 0;
1370
+ return paths.map((p) => {
1371
+ const out = [];
1372
+ for (const sub3 of subsOf(p)) {
1373
+ const s = resample(sub3, m);
1374
+ const disp = s.map(() => {
1375
+ const i = BigInt(idx);
1376
+ const ox = noise(seed, i * 2n, t + idx * 0.37);
1377
+ const oy = noise(seed, i * 2n + 1n, t + idx * 0.61);
1378
+ idx++;
1379
+ return [(sx * corr + ox * (1 - corr)) * w.size, (sy * corr + oy * (1 - corr)) * w.size];
1380
+ });
1381
+ const e = emit(s, disp, sub3.closed, w.smooth, 1 / 3);
1382
+ if (e) out.push(e);
1383
+ }
1384
+ return subsToPath(out);
1385
+ });
1386
+ }
1387
+ var MERGE_OPS = { add: "union", subtract: "difference", intersect: "intersection", exclude: "xor" };
1388
+ function mergePaths(paths, mode = "merge") {
1389
+ if (mode === "merge" || !(mode in MERGE_OPS)) return paths.flat();
1390
+ const inputs = paths.filter((p) => p.length > 0).map((path) => ({ path, fillRule: "nonzero" }));
1391
+ if (!inputs.length) return [];
1392
+ return _chunkVNYRI265cjs.pathBoolean.call(void 0, MERGE_OPS[mode], inputs).path;
1393
+ }
1394
+ function vectorRepeaterCopies(r, pivot) {
1395
+ const copies = Math.max(0, Number.isFinite(r.copies) ? Math.min(r.copies, 1e3) : 0);
1396
+ const n = Math.ceil(copies);
1397
+ const offset = Number.isFinite(r.offset) ? r.offset : 0;
1398
+ const so = (_nullishCoalesce(r.startOpacity, () => ( 100))) / 100;
1399
+ const eo = (_nullishCoalesce(r.endOpacity, () => ( 100))) / 100;
1400
+ const fract = copies - Math.floor(copies);
1401
+ const out = [];
1402
+ for (let i = 0; i < n; i++) {
1403
+ const k = i + offset;
1404
+ let m = translateMatrix(-pivot.x, -pivot.y);
1405
+ m = multiplyMatrices(m, scaleMatrix(Math.pow((_nullishCoalesce(_optionalChain([r, 'access', _33 => _33.scale, 'optionalAccess', _34 => _34.x]), () => ( 100))) / 100, k), Math.pow((_nullishCoalesce(_optionalChain([r, 'access', _35 => _35.scale, 'optionalAccess', _36 => _36.y]), () => ( 100))) / 100, k)));
1406
+ m = multiplyMatrices(m, rotateMatrix((_nullishCoalesce(r.rotation, () => ( 0))) * k));
1407
+ m = multiplyMatrices(m, translateMatrix(pivot.x + (_nullishCoalesce(_optionalChain([r, 'access', _37 => _37.position, 'optionalAccess', _38 => _38.x]), () => ( 0))) * k, pivot.y + (_nullishCoalesce(_optionalChain([r, 'access', _39 => _39.position, 'optionalAccess', _40 => _40.y]), () => ( 0))) * k));
1408
+ const t = n > 1 ? i / (n - 1) : 0;
1409
+ const partial = i + 1 === n && fract > 0 ? fract : 1;
1410
+ out.push({ index: i, matrix: m, opacity: Math.min(1, Math.max(0, (so + (eo - so) * t) * partial)) });
1411
+ }
1412
+ return out;
1413
+ }
1414
+ function repeatPaths(paths, r, pivot) {
1415
+ return vectorRepeaterCopies(r, pivot).map((copy) => ({ copy, paths: paths.map((p) => _chunkVNYRI265cjs.transformBezierPath.call(void 0, p, copy.matrix)) }));
1416
+ }
1417
+ function pathsCenter(paths) {
1418
+ const b = _chunkVNYRI265cjs.bezierPathBounds.call(void 0, paths.flat());
1419
+ return b ? { x: (b.minX + b.maxX) / 2, y: (b.minY + b.maxY) / 2 } : { x: 0, y: 0 };
1420
+ }
1421
+
1422
+ // src/vector/appearance.ts
1423
+ var VECTOR_EFFECT_DEFAULTS = {
1424
+ trim: { start: 0, end: 50, offset: 0, mode: "simultaneous" },
1425
+ roundCorners: { radius: 10 },
1426
+ puckerBloat: { amount: 30 },
1427
+ twist: { angle: 45, center: { x: 0, y: 0 } },
1428
+ zigzag: { size: 5, ridges: 4, smooth: false },
1429
+ wiggle: { size: 5, detail: 6, smooth: true, speed: 2, correlation: 50, phase: 0, seed: 1, time: 0 },
1430
+ offset: { amount: 5, join: "miter", miterLimit: 4, copies: 1, copyOffset: 0 },
1431
+ merge: { mode: "add" },
1432
+ repeater: {
1433
+ copies: 3,
1434
+ offset: 0,
1435
+ position: { x: 100, y: 0 },
1436
+ anchor: { x: 0, y: 0 },
1437
+ rotation: 0,
1438
+ scale: { x: 100, y: 100 },
1439
+ startOpacity: 100,
1440
+ endOpacity: 100,
1441
+ composite: "below"
1442
+ }
1443
+ };
1444
+ var VECTOR_EFFECT_LABELS = {
1445
+ trim: "Trim Paths",
1446
+ roundCorners: "Round Corners",
1447
+ puckerBloat: "Pucker & Bloat",
1448
+ twist: "Twist",
1449
+ zigzag: "Zig Zag",
1450
+ wiggle: "Wiggle Paths",
1451
+ offset: "Offset Paths",
1452
+ merge: "Merge Paths",
1453
+ repeater: "Repeater"
1454
+ };
1455
+ var VECTOR_EFFECT_PARAM_SPECS = {
1456
+ trim: [
1457
+ { key: "start", label: "Start %", kind: "number", min: 0, max: 100, step: 1, slider: true },
1458
+ { key: "end", label: "End %", kind: "number", min: 0, max: 100, step: 1, slider: true },
1459
+ { key: "offset", label: "Offset \xB0", kind: "number", min: -360, max: 360, step: 1, slider: true },
1460
+ {
1461
+ key: "mode",
1462
+ label: "Paths",
1463
+ kind: "select",
1464
+ options: [
1465
+ { value: "simultaneous", label: "Simultaneously" },
1466
+ { value: "individual", label: "Individually" }
1467
+ ]
1468
+ }
1469
+ ],
1470
+ roundCorners: [{ key: "radius", label: "Radius", kind: "number", min: 0, max: 200, step: 1, slider: true }],
1471
+ puckerBloat: [{ key: "amount", label: "Amount %", kind: "number", min: -100, max: 100, step: 1, slider: true }],
1472
+ twist: [
1473
+ { key: "angle", label: "Angle \xB0", kind: "number", min: -720, max: 720, step: 1, slider: true },
1474
+ { key: "center", label: "Centre", kind: "vec2", step: 1 }
1475
+ ],
1476
+ zigzag: [
1477
+ { key: "size", label: "Size", kind: "number", min: 0, max: 100, step: 0.5, slider: true },
1478
+ { key: "ridges", label: "Ridges", kind: "number", min: 0, max: 50, step: 1, slider: true },
1479
+ { key: "smooth", label: "Smooth", kind: "boolean" }
1480
+ ],
1481
+ wiggle: [
1482
+ { key: "size", label: "Size", kind: "number", min: 0, max: 100, step: 0.5, slider: true },
1483
+ { key: "detail", label: "Detail", kind: "number", min: 0, max: 50, step: 1, slider: true },
1484
+ { key: "smooth", label: "Smooth", kind: "boolean" },
1485
+ { key: "correlation", label: "Correlation %", kind: "number", min: 0, max: 100, step: 1, slider: true },
1486
+ { key: "speed", label: "Speed", kind: "number", min: 0, step: 0.1 },
1487
+ { key: "phase", label: "Phase \xB0", kind: "number", step: 1 },
1488
+ { key: "time", label: "Time (s)", kind: "number", min: 0, max: 10, step: 0.05, slider: true },
1489
+ { key: "seed", label: "Seed", kind: "number", step: 1 }
1490
+ ],
1491
+ offset: [
1492
+ { key: "amount", label: "Amount", kind: "number", min: -100, max: 100, step: 0.5, slider: true },
1493
+ {
1494
+ key: "join",
1495
+ label: "Join",
1496
+ kind: "select",
1497
+ options: [
1498
+ { value: "miter", label: "Miter" },
1499
+ { value: "round", label: "Round" },
1500
+ { value: "bevel", label: "Bevel" }
1501
+ ]
1502
+ },
1503
+ { key: "miterLimit", label: "Miter limit", kind: "number", min: 1, step: 0.5 },
1504
+ { key: "copies", label: "Copies", kind: "number", min: 1, max: 20, step: 1 },
1505
+ { key: "copyOffset", label: "Copy offset", kind: "number", step: 0.5 }
1506
+ ],
1507
+ merge: [
1508
+ {
1509
+ key: "mode",
1510
+ label: "Mode",
1511
+ kind: "select",
1512
+ options: [
1513
+ { value: "merge", label: "Merge" },
1514
+ { value: "add", label: "Add" },
1515
+ { value: "subtract", label: "Subtract" },
1516
+ { value: "intersect", label: "Intersect" },
1517
+ { value: "exclude", label: "Exclude" }
1518
+ ]
1519
+ }
1520
+ ],
1521
+ repeater: [
1522
+ { key: "copies", label: "Copies", kind: "number", min: 0, max: 50, step: 0.1, slider: true },
1523
+ { key: "offset", label: "Offset", kind: "number", min: -10, max: 10, step: 0.1, slider: true },
1524
+ { key: "position", label: "Position", kind: "vec2", step: 1 },
1525
+ { key: "anchor", label: "Anchor", kind: "vec2", step: 1 },
1526
+ { key: "rotation", label: "Rotation \xB0", kind: "number", min: -360, max: 360, step: 1, slider: true },
1527
+ { key: "scale", label: "Scale %", kind: "vec2", step: 1 },
1528
+ { key: "startOpacity", label: "Start opacity %", kind: "number", min: 0, max: 100, step: 1, slider: true },
1529
+ { key: "endOpacity", label: "End opacity %", kind: "number", min: 0, max: 100, step: 1, slider: true },
1530
+ {
1531
+ key: "composite",
1532
+ label: "Copies",
1533
+ kind: "select",
1534
+ options: [
1535
+ { value: "below", label: "Below" },
1536
+ { value: "above", label: "Above" }
1537
+ ]
1538
+ }
1539
+ ]
1540
+ };
1541
+ var isVec2 = (v2) => !!v2 && typeof v2 === "object" && Number.isFinite(v2.x) && Number.isFinite(v2.y);
1542
+ function normalizeVectorEffectParams(type, params, base) {
1543
+ const defaults = VECTOR_EFFECT_DEFAULTS[type];
1544
+ if (!defaults) return null;
1545
+ const out = { ...defaults, ..._nullishCoalesce(base, () => ( {})) };
1546
+ for (const spec of VECTOR_EFFECT_PARAM_SPECS[type]) {
1547
+ const v2 = _optionalChain([params, 'optionalAccess', _41 => _41[spec.key]]);
1548
+ if (v2 === void 0) continue;
1549
+ if (spec.kind === "number" && typeof v2 === "number" && Number.isFinite(v2)) out[spec.key] = Math.min(_nullishCoalesce(spec.max, () => ( Infinity)), Math.max(_nullishCoalesce(spec.min, () => ( -Infinity)), v2));
1550
+ else if (spec.kind === "boolean" && typeof v2 === "boolean") out[spec.key] = v2;
1551
+ else if (spec.kind === "vec2" && isVec2(v2)) out[spec.key] = { x: v2.x, y: v2.y };
1552
+ else if (spec.kind === "select" && spec.options.some((o) => o.value === v2)) out[spec.key] = v2;
1553
+ }
1554
+ return out;
1555
+ }
1556
+ function createVectorEffect(type, id, params) {
1557
+ const p = normalizeVectorEffectParams(type, params);
1558
+ return p ? { id, type, params: p } : null;
1559
+ }
1560
+ var isEnabled = (e) => e.enabled !== false && !!VECTOR_EFFECT_DEFAULTS[e.type];
1561
+ function activeVectorEffects(node) {
1562
+ return _nullishCoalesce(_optionalChain([node, 'access', _42 => _42.effects, 'optionalAccess', _43 => _43.filter, 'call', _44 => _44(isEnabled)]), () => ( []));
1563
+ }
1564
+ function hasOwnVectorAppearance(node) {
1565
+ return node.type === "group" && !!node.liveBoolean || !!_optionalChain([node, 'access', _45 => _45.effects, 'optionalAccess', _46 => _46.some, 'call', _47 => _47(isEnabled)]);
1566
+ }
1567
+ var liveCache = /* @__PURE__ */ new WeakMap();
1568
+ function hasVectorAppearance(node) {
1569
+ let v2 = liveCache.get(node);
1570
+ if (v2 === void 0) {
1571
+ v2 = hasOwnVectorAppearance(node) || node.type === "group" && node.children.some(hasVectorAppearance);
1572
+ liveCache.set(node, v2);
1573
+ }
1574
+ return v2;
1575
+ }
1576
+ function isVectorLiveBoolean(node) {
1577
+ return _optionalChain([node, 'optionalAccess', _48 => _48.type]) === "group" && !!node.liveBoolean;
1578
+ }
1579
+ function vectorOperandOperation(group, child) {
1580
+ return _nullishCoalesce(_nullishCoalesce(child.booleanOperation, () => ( group.liveBoolean)), () => ( "union"));
1581
+ }
1582
+ var PATH_OPS = { union: "union", subtract: "difference", intersect: "intersection", exclude: "xor" };
1583
+ var FoldCache = (_class = class {
1584
+ constructor(cap) {;_class.prototype.__init.call(this);
1585
+ this.cap = cap;
1586
+ }
1587
+
1588
+ __init() {this.map = /* @__PURE__ */ new Map()}
1589
+ get(key) {
1590
+ const hit = this.map.get(key);
1591
+ if (hit) {
1592
+ this.map.delete(key);
1593
+ this.map.set(key, hit);
1594
+ }
1595
+ return hit;
1596
+ }
1597
+ set(key, path) {
1598
+ if (this.map.size >= this.cap) {
1599
+ let drop = Math.floor(this.map.size / 2);
1600
+ for (const k of this.map.keys()) {
1601
+ if (drop-- <= 0) break;
1602
+ this.map.delete(k);
1603
+ }
1604
+ }
1605
+ this.map.set(key, path);
1606
+ }
1607
+ clear() {
1608
+ this.map.clear();
1609
+ }
1610
+ }, _class);
1611
+ var foldCache = new FoldCache(4096);
1612
+ var foldSteps = 0;
1613
+ function vectorLiveBooleanSteps() {
1614
+ return foldSteps;
1615
+ }
1616
+ function clearVectorLiveBooleanCache() {
1617
+ foldCache.clear();
1618
+ }
1619
+ var RollingHash = (_class2 = class _RollingHash {constructor() { _class2.prototype.__init2.call(this);_class2.prototype.__init3.call(this); }
1620
+ __init2() {this.a = 2166136261}
1621
+ __init3() {this.b = 16777619 ^ 1540483477}
1622
+ static __initStatic() {this.view = new DataView(new ArrayBuffer(8))}
1623
+ byte(v2) {
1624
+ this.a = Math.imul(this.a ^ v2 & 255, 16777619);
1625
+ this.b = Math.imul(this.b ^ v2 & 255, 1540483477) ^ this.b >>> 15;
1626
+ }
1627
+ num(n) {
1628
+ _RollingHash.view.setFloat64(0, n);
1629
+ for (let i = 0; i < 8; i++) this.byte(_RollingHash.view.getUint8(i));
1630
+ }
1631
+ path(p) {
1632
+ for (const c of p) {
1633
+ this.byte(c.type.charCodeAt(0));
1634
+ if (c.type === "Z") continue;
1635
+ if (c.type === "C") {
1636
+ this.num(c.x1);
1637
+ this.num(c.y1);
1638
+ this.num(c.x2);
1639
+ this.num(c.y2);
1640
+ } else if (c.type === "Q") {
1641
+ this.num(c.x1);
1642
+ this.num(c.y1);
1643
+ }
1644
+ this.num(c.x);
1645
+ this.num(c.y);
1646
+ }
1647
+ }
1648
+ key() {
1649
+ return `${(this.a >>> 0).toString(36)}.${(this.b >>> 0).toString(36)}`;
1650
+ }
1651
+ }, _class2.__initStatic(), _class2);
1652
+ function foldVectorBooleanOperands(operands) {
1653
+ if (!operands.length) return [];
1654
+ if (operands.length === 1) return operands[0].path;
1655
+ const h = new RollingHash();
1656
+ const keys = operands.map((o, i) => {
1657
+ if (i > 0) h.byte(o.operation.charCodeAt(0) + o.operation.length);
1658
+ h.byte(o.fillRule === "evenodd" ? 1 : 0);
1659
+ h.path(o.path);
1660
+ h.byte(9);
1661
+ return h.key();
1662
+ });
1663
+ let start = 0;
1664
+ let acc = operands[0].path;
1665
+ for (let i = keys.length - 1; i >= 1; i--) {
1666
+ const hit = foldCache.get(keys[i]);
1667
+ if (hit) {
1668
+ if (i === keys.length - 1) return hit;
1669
+ start = i;
1670
+ acc = hit;
1671
+ break;
1672
+ }
1673
+ }
1674
+ let accRule = start === 0 ? operands[0].fillRule : "nonzero";
1675
+ for (let i = start + 1; i < operands.length; i++) {
1676
+ const o = operands[i];
1677
+ foldSteps++;
1678
+ const r = _chunkVNYRI265cjs.pathBoolean.call(void 0, _nullishCoalesce(PATH_OPS[o.operation], () => ( "union")), [
1679
+ { path: acc, fillRule: accRule },
1680
+ { path: o.path, fillRule: o.fillRule }
1681
+ ]);
1682
+ if (r.error) return [];
1683
+ acc = r.path;
1684
+ accRule = "nonzero";
1685
+ foldCache.set(keys[i], acc);
1686
+ }
1687
+ return acc;
1688
+ }
1689
+ var compareOrder = (a, b) => {
1690
+ const n = Math.min(a.length, b.length);
1691
+ for (let i = 0; i < n; i++) if (a[i] !== b[i]) return a[i] - b[i];
1692
+ return a.length - b.length;
1693
+ };
1694
+ var add2 = (a, b) => ({ x: a.x + (_nullishCoalesce(_optionalChain([b, 'optionalAccess', _49 => _49.x]), () => ( 0))), y: a.y + (_nullishCoalesce(_optionalChain([b, 'optionalAccess', _50 => _50.y]), () => ( 0))) });
1695
+ var mapPaths = (shapes, fn) => {
1696
+ const out = fn(shapes.map((s) => s.path));
1697
+ return shapes.map((s, i) => ({ ...s, path: _nullishCoalesce(out[i], () => ( [])) }));
1698
+ };
1699
+ function applyVectorEffects(shapes, effects) {
1700
+ let list = shapes.slice();
1701
+ for (const e of _nullishCoalesce(effects, () => ( []))) {
1702
+ if (!isEnabled(e) || !list.length) continue;
1703
+ switch (e.type) {
1704
+ case "trim": {
1705
+ const { start, end, offset, mode } = e.params;
1706
+ list = mapPaths(list, (p) => mode === "individual" ? trimPathsIndividually(p, start, end, offset) : trimPaths(p, start, end, offset));
1707
+ break;
1708
+ }
1709
+ case "roundCorners":
1710
+ list = mapPaths(list, (p) => roundCornerPaths(p, e.params.radius));
1711
+ break;
1712
+ case "puckerBloat":
1713
+ list = mapPaths(list, (p) => puckerBloatPaths(p, e.params.amount));
1714
+ break;
1715
+ case "twist":
1716
+ list = mapPaths(list, (p) => twistPaths(p, e.params.angle, add2(pathsCenter(p), e.params.center)));
1717
+ break;
1718
+ case "zigzag":
1719
+ list = mapPaths(list, (p) => zigzagPaths(p, e.params.size, e.params.ridges, e.params.smooth));
1720
+ break;
1721
+ case "wiggle":
1722
+ list = mapPaths(list, (p) => wigglePaths(p, e.params));
1723
+ break;
1724
+ case "offset": {
1725
+ const o = e.params;
1726
+ list = mapPaths(list, (p) => offsetPaths(p, o.amount, o.join, o.miterLimit, o.copies, o.copyOffset));
1727
+ break;
1728
+ }
1729
+ case "merge": {
1730
+ const first = list[0];
1731
+ list = [{ ...first, path: mergePaths(list.map((s) => s.path), e.params.mode) }];
1732
+ break;
1733
+ }
1734
+ case "repeater": {
1735
+ const r = e.params;
1736
+ const copies = repeatPaths(
1737
+ list.map((s) => s.path),
1738
+ r,
1739
+ add2(pathsCenter(list.map((s) => s.path)), r.anchor)
1740
+ );
1741
+ const n = copies.length;
1742
+ const next = [];
1743
+ for (const { copy, paths } of copies) {
1744
+ const rank = r.composite === "above" ? copy.index : n - 1 - copy.index;
1745
+ list.forEach((s, i) => next.push({ source: s.source, path: paths[i], opacity: s.opacity * copy.opacity, order: [rank, ...s.order] }));
1746
+ }
1747
+ list = next;
1748
+ break;
1749
+ }
1750
+ }
1751
+ }
1752
+ return list;
1753
+ }
1754
+ function childShapes(child, index) {
1755
+ if (child.visible === false) return [];
1756
+ const m = child.transform;
1757
+ const k = _nullishCoalesce(child.opacity, () => ( 1));
1758
+ return vectorAppearanceShapes(child).map((s) => ({
1759
+ source: s.source,
1760
+ path: m && !isIdentityMatrix(m) ? _chunkVNYRI265cjs.transformBezierPath.call(void 0, s.path, m) : s.path,
1761
+ opacity: s.opacity * k,
1762
+ order: [index, ...s.order]
1763
+ }));
1764
+ }
1765
+ function liveBooleanShapes(group) {
1766
+ const operands = [];
1767
+ let source = null;
1768
+ group.children.forEach((child, i) => {
1769
+ const shapes = childShapes(child, i);
1770
+ if (!shapes.length) return;
1771
+ source ??= shapes[0].source;
1772
+ const path = shapes.length === 1 ? shapes[0].path : _chunkVNYRI265cjs.pathBoolean.call(void 0, "union", shapes.map((s) => ({ path: s.path, fillRule: _nullishCoalesce(s.source.fillRule, () => ( "nonzero")) }))).path;
1773
+ const fillRule = shapes.length === 1 ? _nullishCoalesce(shapes[0].source.fillRule, () => ( "nonzero")) : "nonzero";
1774
+ operands.push({ path, fillRule, operation: vectorOperandOperation(group, child) });
1775
+ });
1776
+ if (!source) return [];
1777
+ return [{ source, path: foldVectorBooleanOperands(operands), opacity: 1, order: [0] }];
1778
+ }
1779
+ var shapeCache = /* @__PURE__ */ new WeakMap();
1780
+ function vectorAppearanceShapes(node) {
1781
+ const hit = shapeCache.get(node);
1782
+ if (hit) return hit;
1783
+ let base;
1784
+ if (node.type === "path") base = [{ source: node, path: subpathsToBezier(node.subpaths), opacity: 1, order: [] }];
1785
+ else if (node.liveBoolean) base = liveBooleanShapes(node);
1786
+ else base = node.children.flatMap((c, i) => childShapes(c, i));
1787
+ const out = applyVectorEffects(base, node.effects).sort((a, b) => compareOrder(a.order, b.order));
1788
+ shapeCache.set(node, out);
1789
+ return out;
1790
+ }
1791
+ var outlineCache = /* @__PURE__ */ new WeakMap();
1792
+ function vectorAppearanceOutline(node) {
1793
+ let hit = outlineCache.get(node);
1794
+ if (!hit) {
1795
+ hit = node.type === "path" && !hasOwnVectorAppearance(node) ? subpathsToBezier(node.subpaths) : vectorAppearanceShapes(node).flatMap((s) => s.path);
1796
+ outlineCache.set(node, hit);
1797
+ }
1798
+ return hit;
1799
+ }
1800
+ function shapeNode(shape, id) {
1801
+ const {
1802
+ id: _id,
1803
+ type: _type,
1804
+ subpaths: _s,
1805
+ transform: _t,
1806
+ effects: _e,
1807
+ booleanOperation: _b,
1808
+ blendStep: _bs,
1809
+ locked: _l,
1810
+ visible: _v,
1811
+ opacity: _o,
1812
+ ...style
1813
+ } = shape.source;
1814
+ return { ...style, id, type: "path", subpaths: bezierToSubpaths(shape.path), ...shape.opacity < 1 ? { opacity: shape.opacity } : {} };
1815
+ }
1816
+ function placement(node) {
1817
+ return {
1818
+ ...node.name !== void 0 ? { name: node.name } : {},
1819
+ ...node.transform ? { transform: node.transform } : {},
1820
+ ...node.visible === false ? { visible: false } : {},
1821
+ ...node.locked ? { locked: true } : {},
1822
+ ...node.blendStep ? { blendStep: true } : {},
1823
+ ...node.booleanOperation ? { booleanOperation: node.booleanOperation } : {}
1824
+ };
1825
+ }
1826
+ function vectorAppearanceNodes(node) {
1827
+ return vectorAppearanceShapes(node).map((s, k) => shapeNode(s, `${node.id}~fx${k}`));
1828
+ }
1829
+ var expandCache = /* @__PURE__ */ new WeakMap();
1830
+ function expandVectorAppearance(node) {
1831
+ if (!hasVectorAppearance(node)) return node;
1832
+ const hit = expandCache.get(node);
1833
+ if (hit) return hit;
1834
+ let out;
1835
+ if (!hasOwnVectorAppearance(node)) {
1836
+ const group = node;
1837
+ out = { ...group, children: group.children.map(expandVectorAppearance) };
1838
+ } else {
1839
+ const shapes = vectorAppearanceShapes(node);
1840
+ if (node.type === "path" && shapes.length === 1) {
1841
+ const one = shapes[0];
1842
+ const { effects: _e, opacity: _o, ...rest } = node;
1843
+ const opacity = (_nullishCoalesce(node.opacity, () => ( 1))) * one.opacity;
1844
+ out = { ...rest, subpaths: bezierToSubpaths(one.path), ...opacity < 1 ? { opacity } : {} };
1845
+ } else {
1846
+ out = {
1847
+ id: node.id,
1848
+ type: "group",
1849
+ ...placement(node),
1850
+ ...node.opacity !== void 0 ? { opacity: node.opacity } : {},
1851
+ children: vectorAppearanceNodes(node)
1852
+ };
1853
+ }
1854
+ }
1855
+ expandCache.set(node, out);
1856
+ return out;
1857
+ }
1858
+ function expandVectorAppearances(nodes) {
1859
+ let changed = false;
1860
+ const out = nodes.map((n) => {
1861
+ const e = expandVectorAppearance(n);
1862
+ if (e !== n) changed = true;
1863
+ return e;
1864
+ });
1865
+ return changed ? out : nodes;
1866
+ }
1867
+ function sanitizeVectorEffects(value) {
1868
+ if (!Array.isArray(value)) return [];
1869
+ const out = [];
1870
+ const used = /* @__PURE__ */ new Set();
1871
+ for (const raw of value) {
1872
+ if (!raw || typeof raw !== "object") continue;
1873
+ const r = raw;
1874
+ const type = r.type;
1875
+ if (typeof type !== "string" || !VECTOR_EFFECT_DEFAULTS[type]) continue;
1876
+ let id = typeof r.id === "string" && r.id && !used.has(r.id) ? r.id : "";
1877
+ for (let k = out.length + 1; !id; k++) if (!used.has(`fx${k}`)) id = `fx${k}`;
1878
+ used.add(id);
1879
+ const effect = createVectorEffect(type, id, _nullishCoalesce(r.params, () => ( {})));
1880
+ out.push(r.enabled === false ? { ...effect, enabled: false } : effect);
1881
+ }
1882
+ return out;
1883
+ }
1884
+ function transformVectorEffects(effects, m) {
1885
+ const lin = (v2) => ({ x: m[0] * v2.x + m[2] * v2.y, y: m[1] * v2.x + m[3] * v2.y });
1886
+ const mirror = m[0] * m[3] - m[1] * m[2] < 0 ? -1 : 1;
1887
+ return effects.map((e) => {
1888
+ if (e.type === "twist") return { ...e, params: { ...e.params, center: lin(e.params.center), angle: e.params.angle * mirror } };
1889
+ if (e.type === "repeater")
1890
+ return { ...e, params: { ...e.params, position: lin(e.params.position), anchor: lin(e.params.anchor), rotation: e.params.rotation * mirror } };
1891
+ return e;
1892
+ });
1893
+ }
1894
+ function vectorEnteredGroups(nodes, ids) {
1895
+ const out = /* @__PURE__ */ new Set();
1896
+ if (!ids.length) return out;
1897
+ const want = new Set(ids);
1898
+ const visit = (list, live) => {
1899
+ for (const n of list) {
1900
+ const own = n.type === "group" && hasOwnVectorAppearance(n);
1901
+ if (want.has(n.id)) {
1902
+ for (const id of live) out.add(id);
1903
+ if (own) out.add(n.id);
1904
+ }
1905
+ if (n.type === "group") visit(n.children, own ? [...live, n.id] : live);
1906
+ }
1907
+ };
1908
+ visit(nodes, []);
1909
+ return out;
1910
+ }
1911
+
1912
+ // src/vector/geometry.ts
1913
+ var EPS3 = 1e-9;
1047
1914
  var cloneAnchor = (a) => ({
1048
1915
  x: a.x,
1049
1916
  y: a.y,
@@ -1068,7 +1935,7 @@ function hasPaint(paint) {
1068
1935
  return true;
1069
1936
  }
1070
1937
  var handleOf = (a, side) => _nullishCoalesce(a[side], () => ( { x: a.x, y: a.y }));
1071
- var isOnAnchor = (a, h) => !h || Math.abs(h.x - a.x) < EPS2 && Math.abs(h.y - a.y) < EPS2;
1938
+ var isOnAnchor = (a, h) => !h || Math.abs(h.x - a.x) < EPS3 && Math.abs(h.y - a.y) < EPS3;
1072
1939
  function subpathSegmentCount(sp) {
1073
1940
  const n = sp.anchors.length;
1074
1941
  if (n < 2) return 0;
@@ -1100,7 +1967,7 @@ function subpathsToBezier(subpaths, options = {}) {
1100
1967
  return out;
1101
1968
  }
1102
1969
  function vectorNodeToBezier(node) {
1103
- return node.type === "path" ? subpathsToBezier(node.subpaths) : [];
1970
+ return node.type === "path" ? vectorAppearanceOutline(node) : [];
1104
1971
  }
1105
1972
  function vectorPathData(input, precision = 3) {
1106
1973
  const subpaths = Array.isArray(input) ? input : input.subpaths;
@@ -1214,12 +2081,13 @@ function collectPathNodes(node) {
1214
2081
  function nodeMatrix(node) {
1215
2082
  return _nullishCoalesce(node.transform, () => ( IDENTITY_MATRIX));
1216
2083
  }
1217
- function vectorPathWorldBezier(node, parent = IDENTITY_MATRIX) {
2084
+ function vectorPathWorldBezier(node, parent = IDENTITY_MATRIX, options = {}) {
1218
2085
  const m = multiplyMatrices(nodeMatrix(node), parent);
1219
- const path = subpathsToBezier(node.subpaths);
2086
+ const path = options.effects === false || !hasOwnVectorAppearance(node) ? subpathsToBezier(node.subpaths) : vectorAppearanceOutline(node);
1220
2087
  return isIdentityMatrix(m) ? path : _chunkVNYRI265cjs.transformBezierPath.call(void 0, path, m);
1221
2088
  }
1222
2089
  function vectorNodeBounds(node, parent = IDENTITY_MATRIX) {
2090
+ node = expandVectorAppearance(node);
1223
2091
  if (node.type === "group") {
1224
2092
  const m = multiplyMatrices(nodeMatrix(node), parent);
1225
2093
  return unionBounds(node.children.map((c) => vectorNodeBounds(c, m)));
@@ -1249,11 +2117,12 @@ function boundsIntersect(a, b) {
1249
2117
  function boundsFromPoints(a, b) {
1250
2118
  return { x: Math.min(a.x, b.x), y: Math.min(a.y, b.y), width: Math.abs(b.x - a.x), height: Math.abs(b.y - a.y) };
1251
2119
  }
1252
- function hitTestVectorNode(node, p, tolerance = 0, parent = IDENTITY_MATRIX) {
2120
+ function hitTestVectorNode(node, p, tolerance = 0, parent = IDENTITY_MATRIX, options = {}) {
1253
2121
  if (node.visible === false) return false;
2122
+ if (!(node.type === "group" && (!hasOwnVectorAppearance(node) || _optionalChain([options, 'access', _51 => _51.entered, 'optionalAccess', _52 => _52.has, 'call', _53 => _53(node.id)])))) node = expandVectorAppearance(node);
1254
2123
  if (node.type === "group") {
1255
2124
  const m = multiplyMatrices(nodeMatrix(node), parent);
1256
- return node.children.some((c) => hitTestVectorNode(c, p, tolerance, m));
2125
+ return node.children.some((c) => hitTestVectorNode(c, p, tolerance, m, options));
1257
2126
  }
1258
2127
  const path = vectorPathWorldBezier(node, parent);
1259
2128
  if (path.length === 0) return false;
@@ -1266,11 +2135,11 @@ function vectorStrokeOutline(node, parent = IDENTITY_MATRIX) {
1266
2135
  if (!hasPaint(node.stroke) || !((_nullishCoalesce(node.strokeWidth, () => ( 1))) > 0)) return [];
1267
2136
  return vectorStrokeOutlinePath(vectorPathWorldBezier(node, parent), node);
1268
2137
  }
1269
- function hitTestVectorNodes(nodes, p, tolerance = 0) {
2138
+ function hitTestVectorNodes(nodes, p, tolerance = 0, options = {}) {
1270
2139
  for (let i = nodes.length - 1; i >= 0; i--) {
1271
2140
  const node = nodes[i];
1272
2141
  if (node.visible === false || node.locked) continue;
1273
- if (hitTestVectorNode(node, p, tolerance)) return node;
2142
+ if (hitTestVectorNode(node, p, tolerance, IDENTITY_MATRIX, options)) return node;
1274
2143
  }
1275
2144
  return null;
1276
2145
  }
@@ -1349,16 +2218,17 @@ function mapAnchor(a, m) {
1349
2218
  }
1350
2219
  function bakeIntoGeometry(node, m) {
1351
2220
  if (isIdentityMatrix(m)) return node;
2221
+ if (_optionalChain([node, 'access', _54 => _54.effects, 'optionalAccess', _55 => _55.length])) node = { ...node, effects: transformVectorEffects(node.effects, m) };
1352
2222
  if (node.type === "group") {
1353
2223
  const group = node;
1354
2224
  const children = group.children.map((c) => transformVectorNode(c, m));
1355
- const spine = _optionalChain([group, 'access', _28 => _28.blend, 'optionalAccess', _29 => _29.spine]);
2225
+ const spine = _optionalChain([group, 'access', _56 => _56.blend, 'optionalAccess', _57 => _57.spine]);
1356
2226
  if (!spine) return { ...group, children };
1357
2227
  const moved = { closed: spine.closed, anchors: spine.anchors.map((a) => mapAnchor(a, m)) };
1358
2228
  return { ...group, children, blend: { ...group.blend, spine: moved } };
1359
2229
  }
1360
2230
  const path = node;
1361
- const mirrored = m[0] * m[3] - m[1] * m[2] < 0 && _optionalChain([path, 'access', _30 => _30.strokeWidthProfile, 'optionalAccess', _31 => _31.length]);
2231
+ const mirrored = m[0] * m[3] - m[1] * m[2] < 0 && _optionalChain([path, 'access', _58 => _58.strokeWidthProfile, 'optionalAccess', _59 => _59.length]);
1362
2232
  return {
1363
2233
  ...path,
1364
2234
  ...mirrored ? { strokeWidthProfile: mirrorWidthProfile(path.strokeWidthProfile) } : {},
@@ -1416,7 +2286,7 @@ function moveAnchorHandle(a, side, pos, breakHandles = false) {
1416
2286
  const dy = pos.y - a.y;
1417
2287
  const len2 = Math.hypot(dx, dy);
1418
2288
  if (type === "symmetric") next[other] = { x: a.x - dx, y: a.y - dy };
1419
- else if (type === "smooth" && len2 > EPS2) {
2289
+ else if (type === "smooth" && len2 > EPS3) {
1420
2290
  const o = a[other];
1421
2291
  const olen = o ? Math.hypot(o.x - a.x, o.y - a.y) : len2;
1422
2292
  next[other] = { x: a.x - dx / len2 * olen, y: a.y - dy / len2 * olen };
@@ -1446,15 +2316,15 @@ function convertAnchor(sp, index, type) {
1446
2316
  else if (prev && next) dir = { x: next.x - prev.x, y: next.y - prev.y };
1447
2317
  else if (next) dir = { x: next.x - a.x, y: next.y - a.y };
1448
2318
  else if (prev) dir = { x: a.x - prev.x, y: a.y - prev.y };
1449
- if (!dir || Math.hypot(dir.x, dir.y) < EPS2) return { anchors, closed: sp.closed };
2319
+ if (!dir || Math.hypot(dir.x, dir.y) < EPS3) return { anchors, closed: sp.closed };
1450
2320
  const dl = Math.hypot(dir.x, dir.y);
1451
2321
  const ux = dir.x / dl;
1452
2322
  const uy = dir.y / dl;
1453
2323
  lenIn = a.in && !isOnAnchor(a, a.in) ? Math.hypot(a.in.x - a.x, a.in.y - a.y) : prev ? Math.hypot(prev.x - a.x, prev.y - a.y) / 3 : 0;
1454
2324
  lenOut = a.out && !isOnAnchor(a, a.out) ? Math.hypot(a.out.x - a.x, a.out.y - a.y) : next ? Math.hypot(next.x - a.x, next.y - a.y) / 3 : 0;
1455
2325
  if (type === "symmetric") lenIn = lenOut = (lenIn + lenOut) / 2 || Math.max(lenIn, lenOut);
1456
- if (lenIn > EPS2) a.in = { x: a.x - ux * lenIn, y: a.y - uy * lenIn };
1457
- if (lenOut > EPS2) a.out = { x: a.x + ux * lenOut, y: a.y + uy * lenOut };
2326
+ if (lenIn > EPS3) a.in = { x: a.x - ux * lenIn, y: a.y - uy * lenIn };
2327
+ if (lenOut > EPS3) a.out = { x: a.x + ux * lenOut, y: a.y + uy * lenOut };
1458
2328
  a.type = type;
1459
2329
  return { anchors, closed: sp.closed };
1460
2330
  }
@@ -1569,7 +2439,7 @@ function applyVectorCornersAttribute(subpaths, value) {
1569
2439
  for (const item of value.trim().split(/\s+/)) {
1570
2440
  const m = /^(\d+)\.(\d+):([\d.eE+-]+)(?::([a-z]+))?$/.exec(item);
1571
2441
  if (!m) continue;
1572
- const a = _optionalChain([subpaths, 'access', _32 => _32[+m[1]], 'optionalAccess', _33 => _33.anchors, 'access', _34 => _34[+m[2]]]);
2442
+ const a = _optionalChain([subpaths, 'access', _60 => _60[+m[1]], 'optionalAccess', _61 => _61.anchors, 'access', _62 => _62[+m[2]]]);
1573
2443
  const radius = parseFloat(m[3]);
1574
2444
  if (!a || !(radius > 0)) continue;
1575
2445
  const kind = VECTOR_CORNER_KINDS.includes(m[4]) ? m[4] : void 0;
@@ -1637,7 +2507,7 @@ function blendFromAttribute(value, m) {
1637
2507
  let raw;
1638
2508
  try {
1639
2509
  raw = JSON.parse(value);
1640
- } catch (e3) {
2510
+ } catch (e4) {
1641
2511
  return null;
1642
2512
  }
1643
2513
  if (!raw || typeof raw !== "object") return null;
@@ -1674,13 +2544,33 @@ function vectorDocumentToSvg(doc, options = {}) {
1674
2544
  if (node.visible === false) out2 += ` display="none"`;
1675
2545
  if (node.blendStep) out2 += ` data-vector-blend-step=""`;
1676
2546
  if (node.type === "group" && node.blend) out2 += ` data-vector-blend="${escapeAttr(JSON.stringify(node.blend))}"`;
2547
+ if (node.booleanOperation) out2 += ` data-vector-boolean-operation="${node.booleanOperation}"`;
1677
2548
  return out2;
1678
2549
  };
1679
- const emit = (node, depth) => {
2550
+ const emit2 = (node, depth) => {
1680
2551
  if (node.visible === false && !options.includeHidden) return;
2552
+ if (hasOwnVectorAppearance(node)) {
2553
+ const live2 = {
2554
+ kind: node.type,
2555
+ ..._optionalChain([node, 'access', _63 => _63.effects, 'optionalAccess', _64 => _64.length]) ? { effects: node.effects } : {},
2556
+ ...node.type === "group" && node.liveBoolean ? { liveBoolean: node.liveBoolean } : {}
2557
+ };
2558
+ lines.push(`${indent(depth)}<g${common(node)} data-vector-live="${escapeAttr(JSON.stringify(live2))}">`);
2559
+ lines.push(`${indent(depth + 1)}<g data-vector-part="appearance">`);
2560
+ for (const shape of vectorAppearanceNodes(node)) emit2(shape, depth + 2);
2561
+ lines.push(`${indent(depth + 1)}</g>`);
2562
+ lines.push(`${indent(depth + 1)}<g data-vector-part="source" display="none">`);
2563
+ if (node.type === "path") {
2564
+ const { effects: _e, transform: _t, opacity: _o, visible: _v, booleanOperation: _b, blendStep: _s, ...source } = node;
2565
+ emit2({ ...source, id: `${node.id}~src` }, depth + 2);
2566
+ } else for (const child of node.children) emit2(child, depth + 2);
2567
+ lines.push(`${indent(depth + 1)}</g>`);
2568
+ lines.push(`${indent(depth)}</g>`);
2569
+ return;
2570
+ }
1681
2571
  if (node.type === "group") {
1682
2572
  lines.push(`${indent(depth)}<g${common(node)}>`);
1683
- for (const child of node.children) emit(child, depth + 1);
2573
+ for (const child of node.children) emit2(child, depth + 1);
1684
2574
  lines.push(`${indent(depth)}</g>`);
1685
2575
  return;
1686
2576
  }
@@ -1696,7 +2586,7 @@ function vectorDocumentToSvg(doc, options = {}) {
1696
2586
  let out2 = ` stroke="${escapeAttr(stroke.value)}" stroke-width="${num(width)}"`;
1697
2587
  if (node.strokeLinecap && node.strokeLinecap !== "butt") out2 += ` stroke-linecap="${node.strokeLinecap}"`;
1698
2588
  if (node.strokeLinejoin && node.strokeLinejoin !== "miter") out2 += ` stroke-linejoin="${node.strokeLinejoin}"`;
1699
- if (_optionalChain([node, 'access', _35 => _35.strokeDasharray, 'optionalAccess', _36 => _36.length])) out2 += ` stroke-dasharray="${node.strokeDasharray.map(num).join(" ")}"`;
2589
+ if (_optionalChain([node, 'access', _65 => _65.strokeDasharray, 'optionalAccess', _66 => _66.length])) out2 += ` stroke-dasharray="${node.strokeDasharray.map(num).join(" ")}"`;
1700
2590
  return out2;
1701
2591
  };
1702
2592
  const parts = stroke.value !== "none" ? vectorStrokeSvgParts(node, `${prefix}clip-${node.id}`, precision) : void 0;
@@ -1716,7 +2606,7 @@ function vectorDocumentToSvg(doc, options = {}) {
1716
2606
  data += ` data-vector-width-profile="${widthProfileToAttribute(profile)}"`;
1717
2607
  if (node.strokeLinecap && node.strokeLinecap !== "butt") data += ` data-vector-stroke-linecap="${node.strokeLinecap}"`;
1718
2608
  if (node.strokeLinejoin && node.strokeLinejoin !== "miter") data += ` data-vector-stroke-linejoin="${node.strokeLinejoin}"`;
1719
- if (_optionalChain([node, 'access', _37 => _37.strokeDasharray, 'optionalAccess', _38 => _38.length])) data += ` data-vector-stroke-dasharray="${node.strokeDasharray.map(num).join(" ")}"`;
2609
+ if (_optionalChain([node, 'access', _67 => _67.strokeDasharray, 'optionalAccess', _68 => _68.length])) data += ` data-vector-stroke-dasharray="${node.strokeDasharray.map(num).join(" ")}"`;
1720
2610
  }
1721
2611
  lines.push(`${indent(depth)}<g${common(node)}${data}>`);
1722
2612
  lines.push(`${indent(depth + 1)}<path data-vector-part="fill" d="${d}"${fillAttrs}${live}/>`);
@@ -1744,7 +2634,7 @@ function vectorDocumentToSvg(doc, options = {}) {
1744
2634
  }
1745
2635
  lines.push(`${indent(depth)}</g>`);
1746
2636
  };
1747
- for (const node of doc.nodes) emit(node, 1);
2637
+ for (const node of doc.nodes) emit2(node, 1);
1748
2638
  const w = num(doc.width);
1749
2639
  const h = num(doc.height);
1750
2640
  const nl = pretty ? "\n" : "";
@@ -1756,6 +2646,7 @@ function vectorDocumentToSvg(doc, options = {}) {
1756
2646
  out.push(...lines, "</svg>");
1757
2647
  return out.join(nl);
1758
2648
  }
2649
+ var BOOLEAN_OPERATIONS = ["union", "subtract", "intersect", "exclude"];
1759
2650
  function parseXml(source) {
1760
2651
  const text = source.replace(/<!--[\s\S]*?-->/g, "").replace(/<\?[\s\S]*?\?>/g, "").replace(/<!\[CDATA\[[\s\S]*?\]\]>/g, "").replace(/<!DOCTYPE[^>[]*(\[[\s\S]*?\])?\s*>/gi, "");
1761
2652
  const root = { name: "#root", attrs: {}, children: [] };
@@ -1885,7 +2776,7 @@ function resolveGradient(id, raw, seen = /* @__PURE__ */ new Set()) {
1885
2776
  seen.add(id);
1886
2777
  let stops = readStops(el);
1887
2778
  const href = _nullishCoalesce(el.attrs.href, () => ( el.attrs["xlink:href"]));
1888
- if (!stops.length && _optionalChain([href, 'optionalAccess', _39 => _39.startsWith, 'call', _40 => _40("#")])) stops = _nullishCoalesce(_optionalChain([resolveGradient, 'call', _41 => _41(href.slice(1), raw, seen), 'optionalAccess', _42 => _42.stops]), () => ( []));
2779
+ if (!stops.length && _optionalChain([href, 'optionalAccess', _69 => _69.startsWith, 'call', _70 => _70("#")])) stops = _nullishCoalesce(_optionalChain([resolveGradient, 'call', _71 => _71(href.slice(1), raw, seen), 'optionalAccess', _72 => _72.stops]), () => ( []));
1889
2780
  if (!stops.length) return null;
1890
2781
  if (el.name === "radialGradient") {
1891
2782
  return { type: "radial", cx: fraction(el.attrs.cx, 0.5), cy: fraction(el.attrs.cy, 0.5), r: fraction(el.attrs.r, 0.5), stops };
@@ -1989,7 +2880,7 @@ function parseVectorSvg(svg, options = {}) {
1989
2880
  const part = (name) => g.children.find((c) => c.name === "path" && c.attrs["data-vector-part"] === name);
1990
2881
  const fillEl = part("fill");
1991
2882
  const subpaths = fillEl ? shapeOf(fillEl) : null;
1992
- if (!fillEl || !_optionalChain([subpaths, 'optionalAccess', _43 => _43.length])) return null;
2883
+ if (!fillEl || !_optionalChain([subpaths, 'optionalAccess', _73 => _73.length])) return null;
1993
2884
  const a = g.attrs;
1994
2885
  const fs = readStyle(fillEl, style);
1995
2886
  const strokeEl = part("stroke");
@@ -2026,10 +2917,38 @@ function parseVectorSvg(svg, options = {}) {
2026
2917
  ...profile.length ? { strokeWidthProfile: profile } : {},
2027
2918
  ...keptCap ? { strokeLinecap: keptCap } : {},
2028
2919
  ...keptJoin ? { strokeLinejoin: keptJoin } : {},
2029
- ..._optionalChain([keptDash, 'optionalAccess', _44 => _44.length]) ? { strokeDasharray: keptDash } : {}
2920
+ ..._optionalChain([keptDash, 'optionalAccess', _74 => _74.length]) ? { strokeDasharray: keptDash } : {}
2030
2921
  };
2031
2922
  return placed(node, m);
2032
2923
  };
2924
+ const liveNode = (g, style, m, meta) => {
2925
+ let raw = {};
2926
+ try {
2927
+ raw = _nullishCoalesce(JSON.parse(g.attrs["data-vector-live"]), () => ( {}));
2928
+ } catch (e5) {
2929
+ raw = {};
2930
+ }
2931
+ const sourceEl = g.children.find((c) => c.name === "g" && c.attrs["data-vector-part"] === "source");
2932
+ if (!sourceEl) return null;
2933
+ const inner = visit(sourceEl, style, m);
2934
+ const effects = sanitizeVectorEffects(raw.effects);
2935
+ const liveBoolean = BOOLEAN_OPERATIONS.includes(raw.liveBoolean) ? raw.liveBoolean : null;
2936
+ const id = idFor(g);
2937
+ if (raw.kind === "path") {
2938
+ const path = inner.find((n) => n.type === "path");
2939
+ if (!path) return null;
2940
+ const { residual } = decomposeRigid(m);
2941
+ const { visible: _v, ...rest } = path;
2942
+ return { ...rest, id, ...meta, ...effects.length ? { effects: transformVectorEffects(effects, residual) } : {} };
2943
+ }
2944
+ if (!inner.length) return null;
2945
+ const group = { id, type: "group", ...meta, children: inner };
2946
+ if (effects.length) group.effects = transformVectorEffects(effects, m);
2947
+ if (liveBoolean) group.liveBoolean = liveBoolean;
2948
+ const blend = blendFromAttribute(g.attrs["data-vector-blend"], m);
2949
+ if (blend) group.blend = blend;
2950
+ return group;
2951
+ };
2033
2952
  const visit = (el, style, matrix) => {
2034
2953
  const out = [];
2035
2954
  for (const child of el.children) {
@@ -2044,6 +2963,13 @@ function parseVectorSvg(svg, options = {}) {
2044
2963
  ...hidden ? { visible: false } : {}
2045
2964
  };
2046
2965
  if (child.attrs["data-vector-blend-step"] !== void 0) continue;
2966
+ const operation = child.attrs["data-vector-boolean-operation"];
2967
+ if (BOOLEAN_OPERATIONS.includes(operation)) meta.booleanOperation = operation;
2968
+ if (child.name === "g" && child.attrs["data-vector-live"] !== void 0) {
2969
+ const node2 = liveNode(child, s, m, meta);
2970
+ if (node2) out.push(node2);
2971
+ continue;
2972
+ }
2047
2973
  if (child.name === "g" && child.attrs["data-vector-path"] !== void 0) {
2048
2974
  const node2 = mergedPath(child, s, m, meta);
2049
2975
  if (node2) out.push(node2);
@@ -2572,7 +3498,7 @@ function interpolateVectorPaint(a, b, t) {
2572
3498
  return t < 0.5 ? a : b;
2573
3499
  }
2574
3500
  function interpolateWidthProfiles(a, b, t) {
2575
- if (!_optionalChain([a, 'optionalAccess', _45 => _45.length]) && !_optionalChain([b, 'optionalAccess', _46 => _46.length])) return null;
3501
+ if (!_optionalChain([a, 'optionalAccess', _75 => _75.length]) && !_optionalChain([b, 'optionalAccess', _76 => _76.length])) return null;
2576
3502
  const at2 = [..._nullishCoalesce(a, () => ( [])), ..._nullishCoalesce(b, () => ( [])), { t: 0 }, { t: 1 }].map((p) => p.t).sort((x, y) => x - y);
2577
3503
  const ts = at2.filter((v2, i) => i === 0 || v2 - at2[i - 1] > 1e-6);
2578
3504
  return ts.map((pos) => {
@@ -2582,7 +3508,7 @@ function interpolateWidthProfiles(a, b, t) {
2582
3508
  });
2583
3509
  }
2584
3510
  function lerpDashes(a, b, t) {
2585
- const dashed = (d) => !!_optionalChain([d, 'optionalAccess', _47 => _47.length]) && d.some((v2) => v2 > 0);
3511
+ const dashed = (d) => !!_optionalChain([d, 'optionalAccess', _77 => _77.length]) && d.some((v2) => v2 > 0);
2586
3512
  if (!dashed(a) && !dashed(b)) return t < 0.5 ? a : b;
2587
3513
  const even = (p) => p.length % 2 ? [...p, ...p] : p;
2588
3514
  const solid = (p) => {
@@ -2609,7 +3535,7 @@ function interpolateVectorStyle(a, b, t) {
2609
3535
  for (const key of ["startArrowScale", "endArrowScale"])
2610
3536
  if (a[key] !== void 0 || b[key] !== void 0) out[key] = lerpN(_nullishCoalesce(a[key], () => ( 1)), _nullishCoalesce(b[key], () => ( 1)), t);
2611
3537
  const dash = lerpDashes(a.strokeDasharray, b.strokeDasharray, t);
2612
- if (_optionalChain([dash, 'optionalAccess', _48 => _48.length])) out.strokeDasharray = dash;
3538
+ if (_optionalChain([dash, 'optionalAccess', _78 => _78.length])) out.strokeDasharray = dash;
2613
3539
  const profile = interpolateWidthProfiles(a.strokeWidthProfile, b.strokeWidthProfile, t);
2614
3540
  if (profile) out.strokeWidthProfile = profile;
2615
3541
  return out;
@@ -2620,7 +3546,7 @@ function reversedStyle(s) {
2620
3546
  out.endArrow = s.startArrow;
2621
3547
  out.startArrowScale = s.endArrowScale;
2622
3548
  out.endArrowScale = s.startArrowScale;
2623
- if (_optionalChain([s, 'access', _49 => _49.strokeWidthProfile, 'optionalAccess', _50 => _50.length])) out.strokeWidthProfile = reverseWidthProfile(s.strokeWidthProfile);
3549
+ if (_optionalChain([s, 'access', _79 => _79.strokeWidthProfile, 'optionalAccess', _80 => _80.length])) out.strokeWidthProfile = reverseWidthProfile(s.strokeWidthProfile);
2624
3550
  for (const k of ["startArrow", "endArrow", "startArrowScale", "endArrowScale"]) if (out[k] === void 0) delete out[k];
2625
3551
  return out;
2626
3552
  }
@@ -2766,11 +3692,11 @@ function vectorBlendKeys(group) {
2766
3692
  }
2767
3693
  function resolveVectorBlendOptions(options) {
2768
3694
  return {
2769
- spacing: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _51 => _51.spacing]), () => ( "steps")),
2770
- steps: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _52 => _52.steps]), () => ( DEFAULT_VECTOR_BLEND_STEPS)),
2771
- distance: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _53 => _53.distance]), () => ( DEFAULT_VECTOR_BLEND_DISTANCE)),
2772
- orientToSpine: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _54 => _54.orientToSpine]), () => ( false)),
2773
- linear: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _55 => _55.linear]), () => ( false))
3695
+ spacing: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _81 => _81.spacing]), () => ( "steps")),
3696
+ steps: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _82 => _82.steps]), () => ( DEFAULT_VECTOR_BLEND_STEPS)),
3697
+ distance: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _83 => _83.distance]), () => ( DEFAULT_VECTOR_BLEND_DISTANCE)),
3698
+ orientToSpine: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _84 => _84.orientToSpine]), () => ( false)),
3699
+ linear: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _85 => _85.linear]), () => ( false))
2774
3700
  };
2775
3701
  }
2776
3702
  function paintColors(p) {
@@ -2858,7 +3784,7 @@ function vectorBlendRailAt(rail, s) {
2858
3784
  function vectorBlendSpine(group) {
2859
3785
  const keys = vectorBlendKeys(group);
2860
3786
  if (keys.length < 2) return null;
2861
- const stored = _optionalChain([group, 'access', _56 => _56.blend, 'optionalAccess', _57 => _57.spine]);
3787
+ const stored = _optionalChain([group, 'access', _86 => _86.blend, 'optionalAccess', _87 => _87.spine]);
2862
3788
  if (stored && stored.anchors.length >= 2) {
2863
3789
  const rail2 = vectorBlendRail(stored);
2864
3790
  if (rail2) {
@@ -2879,7 +3805,7 @@ function vectorBlendKeyTargets(group) {
2879
3805
  }
2880
3806
  var morphCache = /* @__PURE__ */ new WeakMap();
2881
3807
  function morphFor(a, b, blend) {
2882
- const starts = [_nullishCoalesce(_optionalChain([blend, 'access', _58 => _58.starts, 'optionalAccess', _59 => _59[a.id]]), () => ( null)), _nullishCoalesce(_optionalChain([blend, 'access', _60 => _60.starts, 'optionalAccess', _61 => _61[b.id]]), () => ( null))];
3808
+ const starts = [_nullishCoalesce(_optionalChain([blend, 'access', _88 => _88.starts, 'optionalAccess', _89 => _89[a.id]]), () => ( null)), _nullishCoalesce(_optionalChain([blend, 'access', _90 => _90.starts, 'optionalAccess', _91 => _91[b.id]]), () => ( null))];
2883
3809
  const key = JSON.stringify([!!blend.linear, starts]);
2884
3810
  let inner = morphCache.get(a);
2885
3811
  if (!inner) morphCache.set(a, inner = /* @__PURE__ */ new WeakMap());
@@ -2978,7 +3904,7 @@ function releaseVectorBlend(group, newId) {
2978
3904
  const m = nodeMatrix(group);
2979
3905
  const opacity = group.opacity;
2980
3906
  const keys = vectorBlendKeys(group).map((c) => group.transform ? transformVectorNode(c, m) : c).map((c) => opacity !== void 0 && opacity < 1 ? { ...c, opacity: (_nullishCoalesce(c.opacity, () => ( 1))) * opacity } : c);
2981
- const spine = _optionalChain([group, 'access', _62 => _62.blend, 'optionalAccess', _63 => _63.spine]);
3907
+ const spine = _optionalChain([group, 'access', _92 => _92.blend, 'optionalAccess', _93 => _93.spine]);
2982
3908
  if (!spine || spine.anchors.length < 2) return keys;
2983
3909
  const path = { id: newId(), type: "path", name: "Spine", fill: null, stroke: null, subpaths: [{ closed: spine.closed, anchors: spine.anchors.map((a) => ({ ...a })) }] };
2984
3910
  return [...keys, group.transform ? transformVectorNode(path, m) : path];
@@ -2987,7 +3913,7 @@ function releaseVectorBlend(group, newId) {
2987
3913
  // src/vector/snap.ts
2988
3914
  var VECTOR_CONSTRUCTION_ANGLES = [0, 45, 90, 135];
2989
3915
  function constrainToLeave(leave, p) {
2990
- if (!_optionalChain([leave, 'optionalAccess', _64 => _64.constrain])) return p;
3916
+ if (!_optionalChain([leave, 'optionalAccess', _94 => _94.constrain])) return p;
2991
3917
  const dx = p.x - leave.at.x;
2992
3918
  const dy = p.y - leave.at.y;
2993
3919
  switch (leave.constrain) {
@@ -3051,16 +3977,16 @@ function contains(node, ids) {
3051
3977
  if (ids.has(node.id)) return true;
3052
3978
  return node.type === "group" && node.children.some((c) => contains(c, ids));
3053
3979
  }
3054
- var VectorSnapTargets = (_class = class _VectorSnapTargets {
3055
- __init() {this.points = []}
3056
- __init2() {this.xs = []}
3057
- __init3() {this.ys = []}
3058
- __init4() {this.segments = []}
3980
+ var VectorSnapTargets = (_class3 = class _VectorSnapTargets {
3981
+ __init4() {this.points = []}
3982
+ __init5() {this.xs = []}
3983
+ __init6() {this.ys = []}
3984
+ __init7() {this.segments = []}
3059
3985
  /** Bounds of the objects a moved box spaces itself evenly with. */
3060
- __init5() {this.boxes = []}
3986
+ __init8() {this.boxes = []}
3061
3987
  /** Side lengths of the other objects (in their own frames), which a resize may match. */
3062
- __init6() {this.sizes = []}
3063
- constructor() {;_class.prototype.__init.call(this);_class.prototype.__init2.call(this);_class.prototype.__init3.call(this);_class.prototype.__init4.call(this);_class.prototype.__init5.call(this);_class.prototype.__init6.call(this);
3988
+ __init9() {this.sizes = []}
3989
+ constructor() {;_class3.prototype.__init4.call(this);_class3.prototype.__init5.call(this);_class3.prototype.__init6.call(this);_class3.prototype.__init7.call(this);_class3.prototype.__init8.call(this);_class3.prototype.__init9.call(this);
3064
3990
  }
3065
3991
  /** How many targets of each sort were gathered. */
3066
3992
  get counts() {
@@ -3098,7 +4024,7 @@ var VectorSnapTargets = (_class = class _VectorSnapTargets {
3098
4024
  moving.set(r.nodeId, set);
3099
4025
  }
3100
4026
  const t = _VectorSnapTargets.collect(doc, new Set(moving.keys()), "segments", false);
3101
- t.pushPaths(doc, new Set(moving.keys()), (id, s, i) => !!_optionalChain([moving, 'access', _65 => _65.get, 'call', _66 => _66(id), 'optionalAccess', _67 => _67.has, 'call', _68 => _68(`${s}:${i}`)]), true);
4027
+ t.pushPaths(doc, new Set(moving.keys()), (id, s, i) => !!_optionalChain([moving, 'access', _95 => _95.get, 'call', _96 => _96(id), 'optionalAccess', _97 => _97.has, 'call', _98 => _98(`${s}:${i}`)]), true);
3102
4028
  return t.index();
3103
4029
  }
3104
4030
  /**
@@ -3197,8 +4123,9 @@ var VectorSnapTargets = (_class = class _VectorSnapTargets {
3197
4123
  let anchors = BUDGET;
3198
4124
  let segments = BUDGET;
3199
4125
  const visit = (list, parent) => {
3200
- for (const n of list) {
3201
- if (exclude.has(n.id) || n.visible === false) continue;
4126
+ for (const stored of list) {
4127
+ if (exclude.has(stored.id) || stored.visible === false) continue;
4128
+ const n = contains(stored, exclude) ? stored : expandVectorAppearance(stored);
3202
4129
  const m = multiplyMatrices(nodeMatrix(n), parent);
3203
4130
  if (n.type === "group") {
3204
4131
  visit(n.children, m);
@@ -3216,7 +4143,7 @@ var VectorSnapTargets = (_class = class _VectorSnapTargets {
3216
4143
  }
3217
4144
  const b = vectorNodeBounds(n, parent);
3218
4145
  const f = nodeFrame(n, parent, b);
3219
- if (b) self.pushRect(b, "edge", _nullishCoalesce(_optionalChain([f, 'optionalAccess', _69 => _69.centre]), () => ( null)));
4146
+ if (b) self.pushRect(b, "edge", _nullishCoalesce(_optionalChain([f, 'optionalAccess', _99 => _99.centre]), () => ( null)));
3220
4147
  }
3221
4148
  };
3222
4149
  visit(doc.nodes, IDENTITY_MATRIX);
@@ -3261,7 +4188,7 @@ var VectorSnapTargets = (_class = class _VectorSnapTargets {
3261
4188
  lines: lines2,
3262
4189
  labels: [this.label(q, kind)]
3263
4190
  });
3264
- if (_optionalChain([leave, 'optionalAccess', _70 => _70.constrain])) {
4191
+ if (_optionalChain([leave, 'optionalAccess', _100 => _100.constrain])) {
3265
4192
  const q = constrainToLeave(leave, p);
3266
4193
  const hit = this.slide(leave.at, { x: q.x - leave.at.x, y: q.y - leave.at.y }, q, tol, true);
3267
4194
  return hit ? { point: hit.point, x: true, y: true, ...this.linedUp(hit.point, hit.from) } : none(q);
@@ -3277,7 +4204,7 @@ var VectorSnapTargets = (_class = class _VectorSnapTargets {
3277
4204
  }
3278
4205
  const on = this.onSegment(near2);
3279
4206
  if (on) return at2(on, "path");
3280
- if (_optionalChain([leave, 'optionalAccess', _71 => _71.angles, 'optionalAccess', _72 => _72.length])) {
4207
+ if (_optionalChain([leave, 'optionalAccess', _101 => _101.angles, 'optionalAccess', _102 => _102.length])) {
3281
4208
  const c = construction(leave, p, tol);
3282
4209
  if (c) {
3283
4210
  const hit = this.slide(leave.at, c.dir, c.point, tol, false);
@@ -3407,7 +4334,7 @@ var VectorSnapTargets = (_class = class _VectorSnapTargets {
3407
4334
  * with nothing spaces the box evenly in its row or column. Returns the correction and guides.
3408
4335
  */
3409
4336
  snapRect(r, tol, options = {}) {
3410
- const axes = { x: _optionalChain([options, 'access', _73 => _73.axes, 'optionalAccess', _74 => _74.x]) !== false, y: _optionalChain([options, 'access', _75 => _75.axes, 'optionalAccess', _76 => _76.y]) !== false };
4337
+ const axes = { x: _optionalChain([options, 'access', _103 => _103.axes, 'optionalAccess', _104 => _104.x]) !== false, y: _optionalChain([options, 'access', _105 => _105.axes, 'optionalAccess', _106 => _106.y]) !== false };
3411
4338
  const nearest = (lines, values) => {
3412
4339
  let best = null;
3413
4340
  for (const v2 of values) for (const l of linesNear(lines, v2, tol)) if (!best || Math.abs(l.v - v2) < Math.abs(best.d)) best = { d: l.v - v2, from: l.from };
@@ -3415,7 +4342,7 @@ var VectorSnapTargets = (_class = class _VectorSnapTargets {
3415
4342
  };
3416
4343
  const bx = axes.x ? nearest(this.xs, [r.x, r.x + r.width / 2, r.x + r.width]) : null;
3417
4344
  const by = axes.y ? nearest(this.ys, [r.y, r.y + r.height / 2, r.y + r.height]) : null;
3418
- const out = { dx: _nullishCoalesce(_optionalChain([bx, 'optionalAccess', _77 => _77.d]), () => ( 0)), dy: _nullishCoalesce(_optionalChain([by, 'optionalAccess', _78 => _78.d]), () => ( 0)), x: !!bx, y: !!by, lines: [], labels: [] };
4345
+ const out = { dx: _nullishCoalesce(_optionalChain([bx, 'optionalAccess', _107 => _107.d]), () => ( 0)), dy: _nullishCoalesce(_optionalChain([by, 'optionalAccess', _108 => _108.d]), () => ( 0)), x: !!bx, y: !!by, lines: [], labels: [] };
3419
4346
  const done = { ...r, x: r.x + out.dx, y: r.y + out.dy };
3420
4347
  if (bx) {
3421
4348
  const x = bx.from.x;
@@ -3538,9 +4465,9 @@ var VectorSnapTargets = (_class = class _VectorSnapTargets {
3538
4465
  const on = this.nearestPoint(p, tol);
3539
4466
  const tries = [];
3540
4467
  if (on) tries.push({ tx: on.p.x, ty: on.p.y, s: { hx: null, hy: null, on } });
3541
- tries.push({ tx: _nullishCoalesce(_optionalChain([hx, 'optionalAccess', _79 => _79.v]), () => ( null)), ty: _nullishCoalesce(_optionalChain([hy, 'optionalAccess', _80 => _80.v]), () => ( null)), s: { hx, hy, on: null } });
3542
- tries.push({ tx: _nullishCoalesce(_optionalChain([hx, 'optionalAccess', _81 => _81.v]), () => ( null)), ty: null, s: { hx, hy: null, on: null } });
3543
- tries.push({ tx: null, ty: _nullishCoalesce(_optionalChain([hy, 'optionalAccess', _82 => _82.v]), () => ( null)), s: { hx: null, hy, on: null } });
4468
+ tries.push({ tx: _nullishCoalesce(_optionalChain([hx, 'optionalAccess', _109 => _109.v]), () => ( null)), ty: _nullishCoalesce(_optionalChain([hy, 'optionalAccess', _110 => _110.v]), () => ( null)), s: { hx, hy, on: null } });
4469
+ tries.push({ tx: _nullishCoalesce(_optionalChain([hx, 'optionalAccess', _111 => _111.v]), () => ( null)), ty: null, s: { hx, hy: null, on: null } });
4470
+ tries.push({ tx: null, ty: _nullishCoalesce(_optionalChain([hy, 'optionalAccess', _112 => _112.v]), () => ( null)), s: { hx: null, hy, on: null } });
3544
4471
  for (const { tx, ty, s } of tries) {
3545
4472
  if (tx === null && ty === null) continue;
3546
4473
  const q = applyMatrix(toLocal, { x: _nullishCoalesce(tx, () => ( p.x)), y: _nullishCoalesce(ty, () => ( p.y)) });
@@ -3657,7 +4584,7 @@ var VectorSnapTargets = (_class = class _VectorSnapTargets {
3657
4584
  }
3658
4585
  return out;
3659
4586
  }
3660
- }, _class);
4587
+ }, _class3);
3661
4588
  var RING = ["nw", "n", "ne", "e", "se", "s", "sw", "w"];
3662
4589
  function opposite(h) {
3663
4590
  return RING[(RING.indexOf(h) + 4) % 8];
@@ -3736,8 +4663,8 @@ function solveOnSegment(seg, base, cond) {
3736
4663
  }
3737
4664
 
3738
4665
  // src/vector/pathEdit.ts
3739
- var EPS3 = 1e-9;
3740
- var unit2 = (x, y) => {
4666
+ var EPS4 = 1e-9;
4667
+ var unit3 = (x, y) => {
3741
4668
  const l = Math.hypot(x, y);
3742
4669
  return l > 1e-12 && Number.isFinite(l) ? [x / l, y / l] : null;
3743
4670
  };
@@ -3748,16 +4675,16 @@ function cubicOf(sp, i) {
3748
4675
  return [a, [a[0] + (b[0] - a[0]) / 3, a[1] + (b[1] - a[1]) / 3], [a[0] + 2 * (b[0] - a[0]) / 3, a[1] + 2 * (b[1] - a[1]) / 3], b];
3749
4676
  }
3750
4677
  var isLine = (sp, i) => subpathSegment(sp, i).length === 2;
3751
- function startTangent(c) {
4678
+ function startTangent2(c) {
3752
4679
  for (let k = 1; k < 4; k++) {
3753
- const u = unit2(c[k][0] - c[0][0], c[k][1] - c[0][1]);
4680
+ const u = unit3(c[k][0] - c[0][0], c[k][1] - c[0][1]);
3754
4681
  if (u) return u;
3755
4682
  }
3756
4683
  return [1, 0];
3757
4684
  }
3758
- function endTangent(c) {
4685
+ function endTangent2(c) {
3759
4686
  for (let k = 2; k >= 0; k--) {
3760
- const u = unit2(c[3][0] - c[k][0], c[3][1] - c[k][1]);
4687
+ const u = unit3(c[3][0] - c[k][0], c[3][1] - c[k][1]);
3761
4688
  if (u) return u;
3762
4689
  }
3763
4690
  return [1, 0];
@@ -3765,7 +4692,7 @@ function endTangent(c) {
3765
4692
  function sample(c, n, out, withStart) {
3766
4693
  for (let i = withStart ? 0 : 1; i <= n; i++) out.push(_chunkVNYRI265cjs.segmentPoint.call(void 0, c, i / n));
3767
4694
  }
3768
- var onAnchor2 = (a, h) => !h || Math.abs(h.x - a.x) < EPS3 && Math.abs(h.y - a.y) < EPS3;
4695
+ var onAnchor2 = (a, h) => !h || Math.abs(h.x - a.x) < EPS4 && Math.abs(h.y - a.y) < EPS4;
3769
4696
  function tidy(a, keepType = true) {
3770
4697
  const next = cloneAnchor(a);
3771
4698
  if (onAnchor2(next, next.in)) delete next.in;
@@ -3827,8 +4754,8 @@ function removeAnchorKeepingShape(sp, index) {
3827
4754
  const pts = [];
3828
4755
  sample(left, N, pts, true);
3829
4756
  sample(right, N, pts, false);
3830
- const t0 = startTangent(left);
3831
- const t1 = endTangent(right);
4757
+ const t0 = startTangent2(left);
4758
+ const t1 = endTangent2(right);
3832
4759
  const { curve } = fitAcross(pts, N, t0, t1);
3833
4760
  if ([curve.p1, curve.p2].every((p) => Number.isFinite(p[0]) && Number.isFinite(p[1]))) {
3834
4761
  anchors[pi] = tidy({ ...anchors[pi], out: { x: curve.p1[0], y: curve.p1[1] } });
@@ -4029,7 +4956,7 @@ function smoothSubpath(sp, amount = 1, only) {
4029
4956
  const prev = orig[(i + n - 1) % n];
4030
4957
  const next = orig[(i + 1) % n];
4031
4958
  const p = orig[i];
4032
- const dir = unit2(next.x - prev.x, next.y - prev.y);
4959
+ const dir = unit3(next.x - prev.x, next.y - prev.y);
4033
4960
  if (!dir) continue;
4034
4961
  const li = dist2(p, prev) / 3;
4035
4962
  const lo = dist2(p, next) / 3;
@@ -4095,13 +5022,13 @@ function mergePair(a, b, tol) {
4095
5022
  }
4096
5023
  const ca = a.line ? [a0, a0, a3, a3] : a.c;
4097
5024
  const cb = b.line ? [a3, a3, b3, b3] : b.c;
4098
- const ta = endTangent(ca);
4099
- const tb = startTangent(cb);
5025
+ const ta = endTangent2(ca);
5026
+ const tb = startTangent2(cb);
4100
5027
  if (ta[0] * tb[0] + ta[1] * tb[1] < 0.99) return null;
4101
5028
  const pts = [];
4102
5029
  sample(ca, 16, pts, true);
4103
5030
  sample(cb, 16, pts, false);
4104
- const { curve, error } = fitAcross(pts, 16, startTangent(ca), endTangent(cb));
5031
+ const { curve, error } = fitAcross(pts, 16, startTangent2(ca), endTangent2(cb));
4105
5032
  return error <= tol ? { c: [curve.p0, curve.p1, curve.p2, curve.p3], line: false } : null;
4106
5033
  }
4107
5034
  function removeRedundantPoints(sp, tolerance) {
@@ -4233,14 +5160,14 @@ function lineHits(p, q, seg) {
4233
5160
  return out;
4234
5161
  }
4235
5162
  var near = (a, b, eps) => Math.abs(a[0] - b[0]) <= eps && Math.abs(a[1] - b[1]) <= eps;
4236
- var degenerate = (seg, eps) => seg.every((p) => near(p, seg[0], eps));
5163
+ var degenerate2 = (seg, eps) => seg.every((p) => near(p, seg[0], eps));
4237
5164
  function arc(l, a, b, eps) {
4238
5165
  const n = l.segs.length;
4239
5166
  const segs = [];
4240
5167
  const chord = [];
4241
5168
  const push = (k, t0, t1) => {
4242
5169
  const piece = t0 <= 0 && t1 >= 1 ? l.segs[k].slice() : _chunkVNYRI265cjs.subSegment.call(void 0, l.segs[k], t0, t1);
4243
- if (!degenerate(piece, eps)) {
5170
+ if (!degenerate2(piece, eps)) {
4244
5171
  segs.push(piece);
4245
5172
  chord.push(l.chord[k]);
4246
5173
  }
@@ -4470,14 +5397,14 @@ function simplifyPolyline(points, tolerance) {
4470
5397
  }
4471
5398
 
4472
5399
  // src/vector/ink.ts
4473
- var LazyMouse = (_class2 = class {
5400
+ var LazyMouse = (_class4 = class {
4474
5401
  /** `length` is the string length in the units of the points (0 turns smoothing off). */
4475
- constructor(length2) {;_class2.prototype.__init7.call(this);_class2.prototype.__init8.call(this);
5402
+ constructor(length2) {;_class4.prototype.__init10.call(this);_class4.prototype.__init11.call(this);
4476
5403
  this.length = length2;
4477
5404
  }
4478
5405
 
4479
- __init7() {this.pos = null}
4480
- __init8() {this.last = null}
5406
+ __init10() {this.pos = null}
5407
+ __init11() {this.last = null}
4481
5408
  push(p) {
4482
5409
  this.last = p;
4483
5410
  if (!(this.length > 0)) return [p];
@@ -4508,7 +5435,7 @@ var LazyMouse = (_class2 = class {
4508
5435
  this.pos = last;
4509
5436
  return [last];
4510
5437
  }
4511
- }, _class2);
5438
+ }, _class4);
4512
5439
  var VECTOR_INK_MAX_CORNERS = 8;
4513
5440
  var MAX_POINTS = 1e5;
4514
5441
  function vectorInkShapeName(shape) {
@@ -4698,8 +5625,9 @@ function recognizeInkShape(points, options = {}) {
4698
5625
  // src/vector/builder.ts
4699
5626
  function vectorPathEntries(doc, roots, options = {}) {
4700
5627
  const out = [];
4701
- const visit = (node, parent, inside) => {
4702
- if (node.visible === false || node.locked && !options.locked) return;
5628
+ const visit = (stored, parent, inside) => {
5629
+ if (stored.visible === false || stored.locked && !options.locked) return;
5630
+ const node = options.expand === false ? stored : expandVectorAppearance(stored);
4703
5631
  const picked = inside || roots === null || roots.includes(node.id);
4704
5632
  if (node.type === "group") {
4705
5633
  const m = multiplyMatrices(nodeMatrix(node), parent);
@@ -4753,7 +5681,7 @@ var STROKE_KEYS = [
4753
5681
  "strokeWidthProfile"
4754
5682
  ];
4755
5683
  function vectorResultStyle(node, paint, edge = false) {
4756
- const { id: _id, subpaths: _s, transform: _t, ...rest } = node;
5684
+ const { id: _id, subpaths: _s, transform: _t, effects: _e, booleanOperation: _b, ...rest } = node;
4757
5685
  const base = { ...rest, fillRule: "nonzero" };
4758
5686
  if (edge) {
4759
5687
  for (const k of STROKE_KEYS) delete base[k];
@@ -4969,7 +5897,7 @@ function getEditablePathIds(state) {
4969
5897
  }
4970
5898
  }
4971
5899
  }
4972
- return [...ids].filter((id) => _optionalChain([findVectorNode, 'call', _83 => _83(state.document.nodes, id), 'optionalAccess', _84 => _84.type]) === "path");
5900
+ return [...ids].filter((id) => _optionalChain([findVectorNode, 'call', _113 => _113(state.document.nodes, id), 'optionalAccess', _114 => _114.type]) === "path");
4973
5901
  }
4974
5902
  function getVisibleAnchors(state) {
4975
5903
  const out = [];
@@ -4984,7 +5912,7 @@ function getVisibleHandles(state) {
4984
5912
  const seen = /* @__PURE__ */ new Set();
4985
5913
  const push = (node, s, i, handle) => {
4986
5914
  const sp = node.subpaths[s];
4987
- const a = _optionalChain([sp, 'optionalAccess', _85 => _85.anchors, 'access', _86 => _86[i]]);
5915
+ const a = _optionalChain([sp, 'optionalAccess', _115 => _115.anchors, 'access', _116 => _116[i]]);
4988
5916
  if (!a || !a[handle]) return;
4989
5917
  const key = `${node.id}:${s}:${i}:${handle}`;
4990
5918
  if (seen.has(key)) return;
@@ -4993,8 +5921,8 @@ function getVisibleHandles(state) {
4993
5921
  };
4994
5922
  if (state.tool === "pen" && state.pen) {
4995
5923
  const node = findVectorNode(state.document.nodes, state.pen.nodeId);
4996
- const sp = _optionalChain([node, 'optionalAccess', _87 => _87.type]) === "path" ? node.subpaths[state.pen.subpath] : void 0;
4997
- if (_optionalChain([node, 'optionalAccess', _88 => _88.type]) === "path" && sp) {
5924
+ const sp = _optionalChain([node, 'optionalAccess', _117 => _117.type]) === "path" ? node.subpaths[state.pen.subpath] : void 0;
5925
+ if (_optionalChain([node, 'optionalAccess', _118 => _118.type]) === "path" && sp) {
4998
5926
  const last = sp.anchors.length - 1;
4999
5927
  push(node, state.pen.subpath, last, "in");
5000
5928
  push(node, state.pen.subpath, last, "out");
@@ -5032,11 +5960,11 @@ function getVectorCornerWidgets(state) {
5032
5960
  const side = Math.min(c.lu, c.lv);
5033
5961
  if (side * zoom < 3 * VECTOR_CORNER_WIDGET_INSET) continue;
5034
5962
  const a = node.subpaths[c.subpath].anchors[c.index];
5035
- const radius = _nullishCoalesce(_optionalChain([a, 'access', _89 => _89.corner, 'optionalAccess', _90 => _90.radius]), () => ( 0));
5963
+ const radius = _nullishCoalesce(_optionalChain([a, 'access', _119 => _119.corner, 'optionalAccess', _120 => _120.radius]), () => ( 0));
5036
5964
  const drawn = fitCornerRadius(c, radius);
5037
5965
  const k = Math.min(Math.max(drawn / c.sin, VECTOR_CORNER_WIDGET_INSET / (zoom * Math.sqrt(1 + c.cos))), side / 2);
5038
5966
  const p = applyMatrix(m, cornerBisectorPoint(c, k));
5039
- out.push({ ref: { nodeId: id, subpath: c.subpath, index: c.index }, x: p.x, y: p.y, radius, drawnRadius: drawn, kind: _nullishCoalesce(_optionalChain([a, 'access', _91 => _91.corner, 'optionalAccess', _92 => _92.kind]), () => ( "round")), corner: c });
5967
+ out.push({ ref: { nodeId: id, subpath: c.subpath, index: c.index }, x: p.x, y: p.y, radius, drawnRadius: drawn, kind: _nullishCoalesce(_optionalChain([a, 'access', _121 => _121.corner, 'optionalAccess', _122 => _122.kind]), () => ( "round")), corner: c });
5040
5968
  }
5041
5969
  }
5042
5970
  return out;
@@ -5059,13 +5987,13 @@ function getVectorWidthHandles(state) {
5059
5987
  const n = findVectorNode(state.document.nodes, id);
5060
5988
  if (n) for (const p of collectPathNodes(n)) ids.add(p.id);
5061
5989
  }
5062
- if (_optionalChain([state, 'access', _93 => _93.hover, 'optionalAccess', _94 => _94.nodeId])) ids.add(state.hover.nodeId);
5063
- if (_optionalChain([state, 'access', _95 => _95.interaction, 'optionalAccess', _96 => _96.type]) === "width") ids.add(state.interaction.ref.nodeId);
5990
+ if (_optionalChain([state, 'access', _123 => _123.hover, 'optionalAccess', _124 => _124.nodeId])) ids.add(state.hover.nodeId);
5991
+ if (_optionalChain([state, 'access', _125 => _125.interaction, 'optionalAccess', _126 => _126.type]) === "width") ids.add(state.interaction.ref.nodeId);
5064
5992
  for (const r of state.selectedWidthPoints) ids.add(r.nodeId);
5065
5993
  const out = [];
5066
5994
  for (const id of ids) {
5067
5995
  const node = findVectorNode(state.document.nodes, id);
5068
- if (_optionalChain([node, 'optionalAccess', _97 => _97.type]) !== "path" || node.visible === false || !_optionalChain([node, 'access', _98 => _98.strokeWidthProfile, 'optionalAccess', _99 => _99.length])) continue;
5996
+ if (_optionalChain([node, 'optionalAccess', _127 => _127.type]) !== "path" || node.visible === false || !_optionalChain([node, 'access', _128 => _128.strokeWidthProfile, 'optionalAccess', _129 => _129.length])) continue;
5069
5997
  const g = vectorStrokeWidthGeometry(node);
5070
5998
  if (!g) continue;
5071
5999
  const profile = sanitizeWidthProfile(node.strokeWidthProfile);
@@ -5098,7 +6026,7 @@ function getVectorWidthHandles(state) {
5098
6026
  }
5099
6027
  function getAnchor(doc, ref) {
5100
6028
  const node = findVectorNode(doc.nodes, ref.nodeId);
5101
- return _optionalChain([node, 'optionalAccess', _100 => _100.type]) === "path" ? _optionalChain([node, 'access', _101 => _101.subpaths, 'access', _102 => _102[ref.subpath], 'optionalAccess', _103 => _103.anchors, 'access', _104 => _104[ref.index]]) : void 0;
6029
+ return _optionalChain([node, 'optionalAccess', _130 => _130.type]) === "path" ? _optionalChain([node, 'access', _131 => _131.subpaths, 'access', _132 => _132[ref.subpath], 'optionalAccess', _133 => _133.anchors, 'access', _134 => _134[ref.index]]) : void 0;
5102
6030
  }
5103
6031
  function getAnchorWorld(doc, ref) {
5104
6032
  const a = getAnchor(doc, ref);
@@ -5281,55 +6209,61 @@ function spliceTree(nodes, id, replacements) {
5281
6209
  return changed ? out : nodes;
5282
6210
  }
5283
6211
  var toPoint2 = (p) => [p.x, p.y];
6212
+ var placementOf = (n) => ({
6213
+ ...n.transform ? { transform: n.transform } : {},
6214
+ ...n.visible === false ? { visible: false } : {},
6215
+ ...n.locked ? { locked: true } : {},
6216
+ ...n.booleanOperation ? { booleanOperation: n.booleanOperation } : {}
6217
+ });
5284
6218
  var isRoot = (m) => m === IDENTITY_MATRIX || m[0] === 1 && m[1] === 0 && m[2] === 0 && m[3] === 1 && m[4] === 0 && m[5] === 0;
5285
6219
  var idCounter = 0;
5286
6220
  var defaultCreateId = () => `vn-${Date.now().toString(36)}${(++idCounter).toString(36)}`;
5287
- var VectorEditorController = (_class3 = class {
6221
+ var VectorEditorController = (_class5 = class {
5288
6222
 
5289
6223
 
5290
- __init9() {this.selection = []}
5291
- __init10() {this.anchors = []}
5292
- __init11() {this.widthPoints = []}
5293
- __init12() {this.widthEdit = null}
5294
- __init13() {this.editingId = null}
5295
- __init14() {this.pen = null}
6224
+ __init12() {this.selection = []}
6225
+ __init13() {this.anchors = []}
6226
+ __init14() {this.widthPoints = []}
6227
+ __init15() {this.widthEdit = null}
6228
+ __init16() {this.editingId = null}
6229
+ __init17() {this.pen = null}
5296
6230
 
5297
6231
 
5298
6232
 
5299
6233
 
5300
6234
 
5301
6235
 
5302
- __init15() {this.hover = null}
5303
- __init16() {this.pointer = null}
5304
- __init17() {this.drag = null}
5305
- __init18() {this.interaction = null}
5306
- __init19() {this.guides = null}
6236
+ __init18() {this.hover = null}
6237
+ __init19() {this.pointer = null}
6238
+ __init20() {this.drag = null}
6239
+ __init21() {this.interaction = null}
6240
+ __init22() {this.guides = null}
5307
6241
  /** Whether the last `snapDrawn` landed on an object (guides may be hidden). */
5308
- __init20() {this.snappedToObject = false}
6242
+ __init23() {this.snappedToObject = false}
5309
6243
  /** Drawing targets for hovering the pen and shape tools, kept while the document and the excluded path stay the same. */
5310
- __init21() {this.hoverTargets = null}
5311
- __init22() {this.spaceHeld = false}
5312
- __init23() {this.clipboard = null}
6244
+ __init24() {this.hoverTargets = null}
6245
+ __init25() {this.spaceHeld = false}
6246
+ __init26() {this.clipboard = null}
5313
6247
  /** Shape Builder map of the selection, kept while the document and the selection stay the same. */
5314
- __init24() {this.builderCache = null}
6248
+ __init27() {this.builderCache = null}
5315
6249
  /** Paint bucket map of the visible outlines. */
5316
- __init25() {this.fillCache = null}
5317
- __init26() {this.builderPreview = null}
5318
- __init27() {this.blendStart = null}
6250
+ __init28() {this.fillCache = null}
6251
+ __init29() {this.builderPreview = null}
6252
+ __init30() {this.blendStart = null}
5319
6253
  /** Options new blends get (the toolbars edit them along with the selected blend's). */
5320
- __init28() {this.blendDefaults = {}}
6254
+ __init31() {this.blendDefaults = {}}
5321
6255
  /** What the highlight shows, to skip notifying when the pointer stays over the same face. */
5322
- __init29() {this.builderHoverKey = null}
6256
+ __init32() {this.builderHoverKey = null}
5323
6257
 
5324
6258
 
5325
- __init30() {this.listeners = /* @__PURE__ */ new Set()}
5326
- __init31() {this.cleanups = []}
5327
- __init32() {this.applying = false}
6259
+ __init33() {this.listeners = /* @__PURE__ */ new Set()}
6260
+ __init34() {this.cleanups = []}
6261
+ __init35() {this.applying = false}
5328
6262
  /** Set while a commit records a change that was already applied, so `restore` still reports it. */
5329
- __init33() {this.committing = false}
5330
- __init34() {this.revision = 0}
6263
+ __init36() {this.committing = false}
6264
+ __init37() {this.revision = 0}
5331
6265
 
5332
- constructor(options = {}) {;_class3.prototype.__init9.call(this);_class3.prototype.__init10.call(this);_class3.prototype.__init11.call(this);_class3.prototype.__init12.call(this);_class3.prototype.__init13.call(this);_class3.prototype.__init14.call(this);_class3.prototype.__init15.call(this);_class3.prototype.__init16.call(this);_class3.prototype.__init17.call(this);_class3.prototype.__init18.call(this);_class3.prototype.__init19.call(this);_class3.prototype.__init20.call(this);_class3.prototype.__init21.call(this);_class3.prototype.__init22.call(this);_class3.prototype.__init23.call(this);_class3.prototype.__init24.call(this);_class3.prototype.__init25.call(this);_class3.prototype.__init26.call(this);_class3.prototype.__init27.call(this);_class3.prototype.__init28.call(this);_class3.prototype.__init29.call(this);_class3.prototype.__init30.call(this);_class3.prototype.__init31.call(this);_class3.prototype.__init32.call(this);_class3.prototype.__init33.call(this);_class3.prototype.__init34.call(this);_class3.prototype.__init35.call(this);_class3.prototype.__init36.call(this);
6266
+ constructor(options = {}) {;_class5.prototype.__init12.call(this);_class5.prototype.__init13.call(this);_class5.prototype.__init14.call(this);_class5.prototype.__init15.call(this);_class5.prototype.__init16.call(this);_class5.prototype.__init17.call(this);_class5.prototype.__init18.call(this);_class5.prototype.__init19.call(this);_class5.prototype.__init20.call(this);_class5.prototype.__init21.call(this);_class5.prototype.__init22.call(this);_class5.prototype.__init23.call(this);_class5.prototype.__init24.call(this);_class5.prototype.__init25.call(this);_class5.prototype.__init26.call(this);_class5.prototype.__init27.call(this);_class5.prototype.__init28.call(this);_class5.prototype.__init29.call(this);_class5.prototype.__init30.call(this);_class5.prototype.__init31.call(this);_class5.prototype.__init32.call(this);_class5.prototype.__init33.call(this);_class5.prototype.__init34.call(this);_class5.prototype.__init35.call(this);_class5.prototype.__init36.call(this);_class5.prototype.__init37.call(this);_class5.prototype.__init38.call(this);_class5.prototype.__init39.call(this);
5333
6267
  this.history = _nullishCoalesce(options.history, () => ( new (0, _chunkQKLRAA4Tcjs.HistoryManager)()));
5334
6268
  this.doc = options.document ? cloneVectorDocument(options.document) : { width: 800, height: 600, nodes: [] };
5335
6269
  this.doc = this.refreshed(this.doc);
@@ -5359,9 +6293,9 @@ var VectorEditorController = (_class3 = class {
5359
6293
  // State
5360
6294
  // -------------------------------------------------------------------------
5361
6295
  /** The current snapshot (stable until the next change). */
5362
- __init35() {this.getState = () => this.state}
6296
+ __init38() {this.getState = () => this.state}
5363
6297
  /** Calls `listener` after every change. Returns an unsubscribe function. */
5364
- __init36() {this.subscribe = (listener) => {
6298
+ __init39() {this.subscribe = (listener) => {
5365
6299
  this.listeners.add(listener);
5366
6300
  return () => {
5367
6301
  this.listeners.delete(listener);
@@ -5417,7 +6351,7 @@ var VectorEditorController = (_class3 = class {
5417
6351
  if (this.blendStart && !this.getNode(this.blendStart.nodeId)) this.blendStart = null;
5418
6352
  this.revision++;
5419
6353
  this.state = this.computeState();
5420
- if (docChanged) _optionalChain([this, 'access', _105 => _105.onChange, 'optionalCall', _106 => _106(this.doc)]);
6354
+ if (docChanged) _optionalChain([this, 'access', _135 => _135.onChange, 'optionalCall', _136 => _136(this.doc)]);
5421
6355
  const state = this.state;
5422
6356
  this.listeners.forEach((listener) => {
5423
6357
  try {
@@ -5447,31 +6381,31 @@ var VectorEditorController = (_class3 = class {
5447
6381
  return applyMatrix(invertMatrix(this.worldOf(id, doc)), p);
5448
6382
  }
5449
6383
  cursorFor() {
5450
- if (_optionalChain([this, 'access', _107 => _107.drag, 'optionalAccess', _108 => _108.kind]) === "pan" || this.spaceHeld) return this.drag ? "grabbing" : "grab";
5451
- if (_optionalChain([this, 'access', _109 => _109.drag, 'optionalAccess', _110 => _110.kind]) === "rotate") return "grabbing";
5452
- if (_optionalChain([this, 'access', _111 => _111.drag, 'optionalAccess', _112 => _112.kind]) === "move") return "move";
6384
+ if (_optionalChain([this, 'access', _137 => _137.drag, 'optionalAccess', _138 => _138.kind]) === "pan" || this.spaceHeld) return this.drag ? "grabbing" : "grab";
6385
+ if (_optionalChain([this, 'access', _139 => _139.drag, 'optionalAccess', _140 => _140.kind]) === "rotate") return "grabbing";
6386
+ if (_optionalChain([this, 'access', _141 => _141.drag, 'optionalAccess', _142 => _142.kind]) === "move") return "move";
5453
6387
  const h = this.hover;
5454
6388
  switch (this.tool) {
5455
6389
  case "select":
5456
- if (_optionalChain([h, 'optionalAccess', _113 => _113.transformHandle])) return vectorResizeCursor(h.transformHandle, _nullishCoalesce(_optionalChain([this, 'access', _114 => _114.frameOf, 'call', _115 => _115(this.selectedRoots()), 'optionalAccess', _116 => _116.angle]), () => ( 0)));
5457
- return _optionalChain([h, 'optionalAccess', _117 => _117.nodeId]) ? "move" : "default";
6390
+ if (_optionalChain([h, 'optionalAccess', _143 => _143.transformHandle])) return vectorResizeCursor(h.transformHandle, _nullishCoalesce(_optionalChain([this, 'access', _144 => _144.frameOf, 'call', _145 => _145(this.selectedRoots()), 'optionalAccess', _146 => _146.angle]), () => ( 0)));
6391
+ return _optionalChain([h, 'optionalAccess', _147 => _147.nodeId]) ? "move" : "default";
5458
6392
  case "direct":
5459
- if (_optionalChain([h, 'optionalAccess', _118 => _118.anchor]) || _optionalChain([h, 'optionalAccess', _119 => _119.handle]) || _optionalChain([h, 'optionalAccess', _120 => _120.corner])) return "pointer";
5460
- if (_optionalChain([h, 'optionalAccess', _121 => _121.segment])) return "copy";
5461
- return _optionalChain([h, 'optionalAccess', _122 => _122.nodeId]) ? "move" : "default";
6393
+ if (_optionalChain([h, 'optionalAccess', _148 => _148.anchor]) || _optionalChain([h, 'optionalAccess', _149 => _149.handle]) || _optionalChain([h, 'optionalAccess', _150 => _150.corner])) return "pointer";
6394
+ if (_optionalChain([h, 'optionalAccess', _151 => _151.segment])) return "copy";
6395
+ return _optionalChain([h, 'optionalAccess', _152 => _152.nodeId]) ? "move" : "default";
5462
6396
  case "pen":
5463
- return _optionalChain([h, 'optionalAccess', _123 => _123.anchor]) ? "pointer" : "crosshair";
6397
+ return _optionalChain([h, 'optionalAccess', _153 => _153.anchor]) ? "pointer" : "crosshair";
5464
6398
  case "width":
5465
- if (_optionalChain([this, 'access', _124 => _124.drag, 'optionalAccess', _125 => _125.kind]) === "width") return this.drag.mode === "width" ? "ew-resize" : "grabbing";
5466
- if (_optionalChain([h, 'optionalAccess', _126 => _126.widthPoint])) return h.widthPoint.part === "center" ? "grab" : "ew-resize";
5467
- return _optionalChain([h, 'optionalAccess', _127 => _127.strokeSpot]) ? "copy" : "default";
6399
+ if (_optionalChain([this, 'access', _154 => _154.drag, 'optionalAccess', _155 => _155.kind]) === "width") return this.drag.mode === "width" ? "ew-resize" : "grabbing";
6400
+ if (_optionalChain([h, 'optionalAccess', _156 => _156.widthPoint])) return h.widthPoint.part === "center" ? "grab" : "ew-resize";
6401
+ return _optionalChain([h, 'optionalAccess', _157 => _157.strokeSpot]) ? "copy" : "default";
5468
6402
  case "shapeBuilder":
5469
- if (!_optionalChain([this, 'access', _128 => _128.builderPreview, 'optionalAccess', _129 => _129.faces, 'access', _130 => _130.length]) && !_optionalChain([this, 'access', _131 => _131.builderPreview, 'optionalAccess', _132 => _132.lines, 'access', _133 => _133.length])) return "crosshair";
6403
+ if (!_optionalChain([this, 'access', _158 => _158.builderPreview, 'optionalAccess', _159 => _159.faces, 'access', _160 => _160.length]) && !_optionalChain([this, 'access', _161 => _161.builderPreview, 'optionalAccess', _162 => _162.lines, 'access', _163 => _163.length])) return "crosshair";
5470
6404
  return this.builderPreview.mode === "erase" ? "not-allowed" : "cell";
5471
6405
  case "paintBucket":
5472
6406
  return this.builderPreview ? "cell" : "crosshair";
5473
6407
  case "blend":
5474
- return _optionalChain([h, 'optionalAccess', _134 => _134.nodeId]) ? this.blendStart && this.blendStart.nodeId !== h.nodeId ? "copy" : "pointer" : "crosshair";
6408
+ return _optionalChain([h, 'optionalAccess', _164 => _164.nodeId]) ? this.blendStart && this.blendStart.nodeId !== h.nodeId ? "copy" : "pointer" : "crosshair";
5475
6409
  default:
5476
6410
  return "crosshair";
5477
6411
  }
@@ -5492,11 +6426,11 @@ var VectorEditorController = (_class3 = class {
5492
6426
  this.selection = s.selection.filter((id) => this.getNode(id));
5493
6427
  this.anchors = s.anchors.filter((r) => getAnchor(this.doc, r));
5494
6428
  this.editingId = s.editingId && this.getNode(s.editingId) ? s.editingId : null;
5495
- this.pen = s.pen && _optionalChain([this, 'access', _135 => _135.getNode, 'call', _136 => _136(s.pen.nodeId), 'optionalAccess', _137 => _137.subpaths, 'optionalAccess', _138 => _138[s.pen.subpath]]) ? s.pen : null;
6429
+ this.pen = s.pen && _optionalChain([this, 'access', _165 => _165.getNode, 'call', _166 => _166(s.pen.nodeId), 'optionalAccess', _167 => _167.subpaths, 'optionalAccess', _168 => _168[s.pen.subpath]]) ? s.pen : null;
5496
6430
  if (this.widthPoints.length) {
5497
6431
  const kept = this.widthPoints.filter((r) => {
5498
6432
  const n = this.getNode(r.nodeId);
5499
- return _optionalChain([n, 'optionalAccess', _139 => _139.type]) === "path" && !!_optionalChain([n, 'access', _140 => _140.strokeWidthProfile, 'optionalAccess', _141 => _141[r.index]]);
6433
+ return _optionalChain([n, 'optionalAccess', _169 => _169.type]) === "path" && !!_optionalChain([n, 'access', _170 => _170.strokeWidthProfile, 'optionalAccess', _171 => _171[r.index]]);
5500
6434
  });
5501
6435
  if (kept.length !== this.widthPoints.length) this.widthPoints = kept;
5502
6436
  }
@@ -5505,8 +6439,11 @@ var VectorEditorController = (_class3 = class {
5505
6439
  }
5506
6440
  this.notify(docChanged);
5507
6441
  }
5508
- /** Records the change from `before` to the current state as one undo step. */
5509
- commit(name, before) {
6442
+ /**
6443
+ * Records the change from `before` to the current state as one undo step. Consecutive
6444
+ * changes with the same `merge` key (a slider drag) fold into one step.
6445
+ */
6446
+ commit(name, before, merge) {
5510
6447
  this.doc = this.refreshed(this.doc);
5511
6448
  const after = this.snapshot();
5512
6449
  if (before.doc === after.doc) {
@@ -5517,17 +6454,23 @@ var VectorEditorController = (_class3 = class {
5517
6454
  name,
5518
6455
  execute: () => this.restore(after),
5519
6456
  undo: () => this.restore(before),
5520
- redo: () => this.restore(after)
6457
+ redo: () => this.restore(after),
6458
+ ...merge ? { tag: merge } : {}
5521
6459
  };
5522
6460
  this.committing = true;
5523
- this.history.execute(command);
6461
+ if (merge) this.history.executeMerged(command, { key: merge });
6462
+ else this.history.execute(command);
5524
6463
  this.committing = false;
5525
6464
  }
5526
- /** Runs `fn` (which updates fields) and records it as one undo step. */
5527
- change(name, fn) {
6465
+ /** Runs `fn` (which updates fields) and records it as one undo step (merged by `merge` key). */
6466
+ change(name, fn, merge) {
5528
6467
  const before = this.snapshot();
5529
6468
  fn();
5530
- this.commit(name, before);
6469
+ this.commit(name, before, merge);
6470
+ }
6471
+ /** Ends a merged edit (a slider released): the next change starts a new undo step. */
6472
+ endMergedEdit() {
6473
+ this.history.endGesture();
5531
6474
  }
5532
6475
  setDoc(nodes) {
5533
6476
  if (nodes !== this.doc.nodes) this.doc = { ...this.doc, nodes };
@@ -5669,7 +6612,7 @@ var VectorEditorController = (_class3 = class {
5669
6612
  if (res.kind) {
5670
6613
  this.snappedToObject = true;
5671
6614
  this.setGuides(res);
5672
- return _optionalChain([leave, 'optionalAccess', _142 => _142.constrain]) ? res.point : { x: res.x ? res.point.x : this.gridValue(res.point.x), y: res.y ? res.point.y : this.gridValue(res.point.y) };
6615
+ return _optionalChain([leave, 'optionalAccess', _172 => _172.constrain]) ? res.point : { x: res.x ? res.point.x : this.gridValue(res.point.x), y: res.y ? res.point.y : this.gridValue(res.point.y) };
5673
6616
  }
5674
6617
  }
5675
6618
  this.setGuides(null);
@@ -5687,14 +6630,14 @@ var VectorEditorController = (_class3 = class {
5687
6630
  /** Where the pointer at `p` would place a point with the pen or a shape tool (and the guides showing why). */
5688
6631
  hoverSnap(p, input) {
5689
6632
  if (this.tool === "pen") {
5690
- const sp = this.pen ? _optionalChain([this, 'access', _143 => _143.getNode, 'call', _144 => _144(this.pen.nodeId), 'optionalAccess', _145 => _145.subpaths, 'access', _146 => _146[this.pen.subpath]]) : void 0;
5691
- if (this.pen && sp && _optionalChain([this, 'access', _147 => _147.hover, 'optionalAccess', _148 => _148.anchor])) {
6633
+ const sp = this.pen ? _optionalChain([this, 'access', _173 => _173.getNode, 'call', _174 => _174(this.pen.nodeId), 'optionalAccess', _175 => _175.subpaths, 'access', _176 => _176[this.pen.subpath]]) : void 0;
6634
+ if (this.pen && sp && _optionalChain([this, 'access', _177 => _177.hover, 'optionalAccess', _178 => _178.anchor])) {
5692
6635
  this.setGuides(null);
5693
6636
  return p;
5694
6637
  }
5695
6638
  const last = this.pen && sp ? getAnchorWorld(this.doc, { nodeId: this.pen.nodeId, subpath: this.pen.subpath, index: sp.anchors.length - 1 }) : void 0;
5696
6639
  const leave = last ? { at: { x: last.x, y: last.y }, constrain: input.shift ? "angle" : null } : null;
5697
- return this.snapDrawn(p, leave, input, () => this.drawingTargets(_nullishCoalesce(_optionalChain([this, 'access', _149 => _149.pen, 'optionalAccess', _150 => _150.nodeId]), () => ( null))));
6640
+ return this.snapDrawn(p, leave, input, () => this.drawingTargets(_nullishCoalesce(_optionalChain([this, 'access', _179 => _179.pen, 'optionalAccess', _180 => _180.nodeId]), () => ( null))));
5698
6641
  }
5699
6642
  if (SHAPE_TOOLS.has(this.tool)) return this.snapDrawn(p, null, input, () => this.drawingTargets(null));
5700
6643
  this.setGuides(null);
@@ -5842,7 +6785,7 @@ var VectorEditorController = (_class3 = class {
5842
6785
  if (d.fillRule) out.fillRule = d.fillRule;
5843
6786
  if (d.strokeAlign && d.strokeAlign !== "center") out.strokeAlign = d.strokeAlign;
5844
6787
  for (const key of ["startArrow", "endArrow", "arrowAlign", "startArrowScale", "endArrowScale"]) if (d[key]) out[key] = d[key];
5845
- if (_optionalChain([d, 'access', _151 => _151.strokeWidthProfile, 'optionalAccess', _152 => _152.length])) out.strokeWidthProfile = d.strokeWidthProfile.map((p) => ({ ...p }));
6788
+ if (_optionalChain([d, 'access', _181 => _181.strokeWidthProfile, 'optionalAccess', _182 => _182.length])) out.strokeWidthProfile = d.strokeWidthProfile.map((p) => ({ ...p }));
5846
6789
  return out;
5847
6790
  }
5848
6791
  /** Merges `patch` into a node (paths take style and geometry; groups name / visibility / opacity). */
@@ -5897,7 +6840,7 @@ var VectorEditorController = (_class3 = class {
5897
6840
  const byNode = /* @__PURE__ */ new Map();
5898
6841
  for (const r of refs) {
5899
6842
  const node = this.getNode(r.nodeId);
5900
- if (_optionalChain([node, 'optionalAccess', _153 => _153.type]) !== "path" || !_optionalChain([node, 'access', _154 => _154.strokeWidthProfile, 'optionalAccess', _155 => _155[r.index]])) continue;
6843
+ if (_optionalChain([node, 'optionalAccess', _183 => _183.type]) !== "path" || !_optionalChain([node, 'access', _184 => _184.strokeWidthProfile, 'optionalAccess', _185 => _185[r.index]])) continue;
5901
6844
  byNode.set(r.nodeId, [..._nullishCoalesce(byNode.get(r.nodeId), () => ( [])), r.index]);
5902
6845
  }
5903
6846
  if (!byNode.size) return { ok: false, message: "There is no such width point." };
@@ -5915,12 +6858,12 @@ var VectorEditorController = (_class3 = class {
5915
6858
  }
5916
6859
  /** Selects width points (width tool); points on other paths than the first are dropped. */
5917
6860
  selectWidthPoints(refs) {
5918
- const first = _optionalChain([refs, 'access', _156 => _156[0], 'optionalAccess', _157 => _157.nodeId]);
6861
+ const first = _optionalChain([refs, 'access', _186 => _186[0], 'optionalAccess', _187 => _187.nodeId]);
5919
6862
  const next = [];
5920
6863
  for (const r of refs) {
5921
6864
  if (r.nodeId !== first || next.some((q) => q.index === r.index)) continue;
5922
6865
  const n = this.getNode(r.nodeId);
5923
- if (_optionalChain([n, 'optionalAccess', _158 => _158.type]) === "path" && _optionalChain([n, 'access', _159 => _159.strokeWidthProfile, 'optionalAccess', _160 => _160[r.index]])) next.push({ nodeId: r.nodeId, index: r.index, subpath: _nullishCoalesce(r.subpath, () => ( 0)) });
6866
+ if (_optionalChain([n, 'optionalAccess', _188 => _188.type]) === "path" && _optionalChain([n, 'access', _189 => _189.strokeWidthProfile, 'optionalAccess', _190 => _190[r.index]])) next.push({ nodeId: r.nodeId, index: r.index, subpath: _nullishCoalesce(r.subpath, () => ( 0)) });
5924
6867
  }
5925
6868
  this.widthPoints = next;
5926
6869
  this.notify();
@@ -5935,7 +6878,7 @@ var VectorEditorController = (_class3 = class {
5935
6878
  */
5936
6879
  setWidthPoint(target, values) {
5937
6880
  const node = this.getNode(target.nodeId);
5938
- if (_optionalChain([node, 'optionalAccess', _161 => _161.type]) !== "path") return { ok: false, message: "There is no such path." };
6881
+ if (_optionalChain([node, 'optionalAccess', _191 => _191.type]) !== "path") return { ok: false, message: "There is no such path." };
5939
6882
  const g = vectorStrokeWidthGeometry(node);
5940
6883
  if (!g || !(g.unit > 0)) return { ok: false, message: "The path has no visible stroke." };
5941
6884
  const num = (v2) => typeof v2 === "number" && Number.isFinite(v2) ? v2 : void 0;
@@ -5968,11 +6911,11 @@ var VectorEditorController = (_class3 = class {
5968
6911
  }
5969
6912
  }
5970
6913
  }
5971
- const subpath = _optionalChain([this, 'access', _162 => _162.widthEdit, 'optionalAccess', _163 => _163.nodeId]) === node.id ? this.widthEdit.subpath : _nullishCoalesce(_optionalChain([this, 'access', _164 => _164.widthPoints, 'access', _165 => _165.find, 'call', _166 => _166((r) => r.nodeId === node.id), 'optionalAccess', _167 => _167.subpath]), () => ( 0));
6914
+ const subpath = _optionalChain([this, 'access', _192 => _192.widthEdit, 'optionalAccess', _193 => _193.nodeId]) === node.id ? this.widthEdit.subpath : _nullishCoalesce(_optionalChain([this, 'access', _194 => _194.widthPoints, 'access', _195 => _195.find, 'call', _196 => _196((r) => r.nodeId === node.id), 'optionalAccess', _197 => _197.subpath]), () => ( 0));
5972
6915
  const edit = this.widthEdit;
5973
6916
  this.change("Width Point", () => this.replaceNode(node.id, withStyle(node, { strokeWidthProfile: points })));
5974
6917
  this.widthPoints = [{ nodeId: node.id, index, subpath }];
5975
- if (_optionalChain([edit, 'optionalAccess', _168 => _168.nodeId]) === node.id && (edit.index === existing || existing === null)) this.widthEdit = this.widthEditFor(node.id, subpath, index, null);
6918
+ if (_optionalChain([edit, 'optionalAccess', _198 => _198.nodeId]) === node.id && (edit.index === existing || existing === null)) this.widthEdit = this.widthEditFor(node.id, subpath, index, null);
5976
6919
  this.notify();
5977
6920
  return { ok: true };
5978
6921
  }
@@ -6006,7 +6949,7 @@ var VectorEditorController = (_class3 = class {
6006
6949
  /** The editor's view of point `index` (or of the stroke at `t` when index is null) of `nodeId`. */
6007
6950
  widthEditFor(nodeId, subpath, index, t) {
6008
6951
  const node = this.getNode(nodeId);
6009
- if (_optionalChain([node, 'optionalAccess', _169 => _169.type]) !== "path") return null;
6952
+ if (_optionalChain([node, 'optionalAccess', _199 => _199.type]) !== "path") return null;
6010
6953
  const g = vectorStrokeWidthGeometry(node);
6011
6954
  if (!g) return null;
6012
6955
  const profile = sanitizeWidthProfile(node.strokeWidthProfile);
@@ -6040,7 +6983,7 @@ var VectorEditorController = (_class3 = class {
6040
6983
  const refs = this.cornerTargets(options);
6041
6984
  if (!refs.length) return { ok: false, message: "Nothing is selected." };
6042
6985
  this.change("Corner Kind", () => {
6043
- this.doc = this.updateAnchors(this.doc, refs, (a) => setAnchorCorner(a, _nullishCoalesce(_optionalChain([a, 'access', _170 => _170.corner, 'optionalAccess', _171 => _171.radius]), () => ( 0)), kind));
6986
+ this.doc = this.updateAnchors(this.doc, refs, (a) => setAnchorCorner(a, _nullishCoalesce(_optionalChain([a, 'access', _200 => _200.corner, 'optionalAccess', _201 => _201.radius]), () => ( 0)), kind));
6044
6987
  });
6045
6988
  return { ok: true };
6046
6989
  }
@@ -6077,7 +7020,7 @@ var VectorEditorController = (_class3 = class {
6077
7020
  const created = [];
6078
7021
  const replace = /* @__PURE__ */ new Map();
6079
7022
  for (const p of paths) {
6080
- const outline = bezierToSubpaths(vectorStrokeOutlinePath(subpathsToBezier(p.subpaths), p));
7023
+ const outline = bezierToSubpaths(vectorStrokeOutlinePath(vectorAppearanceOutline(p), p));
6081
7024
  if (!outline.length) continue;
6082
7025
  const {
6083
7026
  stroke,
@@ -6092,11 +7035,12 @@ var VectorEditorController = (_class3 = class {
6092
7035
  startArrowScale: _ss,
6093
7036
  endArrowScale: _es,
6094
7037
  strokeWidthProfile: _wp,
7038
+ effects,
6095
7039
  ...rest
6096
7040
  } = cloneVectorNode(p);
6097
7041
  const id = this.newId();
6098
7042
  const strokeNode = { ...rest, id, name: `${_nullishCoalesce(p.name, () => ( "Path"))} Stroke`, subpaths: outline, fill: _nullishCoalesce(stroke, () => ( null)), stroke: null, fillRule: "nonzero" };
6099
- const list = hasPaint(p.fill) ? [{ ...rest, stroke: null }, strokeNode] : [strokeNode];
7043
+ const list = hasPaint(p.fill) ? [{ ...rest, ...effects ? { effects } : {}, stroke: null }, strokeNode] : [strokeNode];
6100
7044
  created.push(id);
6101
7045
  replace.set(p.id, list);
6102
7046
  }
@@ -6111,6 +7055,121 @@ var VectorEditorController = (_class3 = class {
6111
7055
  });
6112
7056
  return created;
6113
7057
  }
7058
+ // -------------------------------------------------------------------------
7059
+ // Path effects
7060
+ // -------------------------------------------------------------------------
7061
+ /** Selected (or given) nodes that can carry effects: the roots of the selection. */
7062
+ effectTargets(ids) {
7063
+ return (_nullishCoalesce(ids, () => ( this.selectedRoots()))).map((id) => this.getNode(id)).filter((n) => !!n && !n.blendStep);
7064
+ }
7065
+ /**
7066
+ * Adds an effect of `type` to the selected (or given) nodes, at the bottom of each stack (or
7067
+ * at `index`), with default parameters merged with `params`. A repeater's copies start one
7068
+ * shape width apart. One undo step; returns the new effect ids (one per node, in order).
7069
+ */
7070
+ addEffect(type, options = {}) {
7071
+ const targets = this.effectTargets(options.ids);
7072
+ if (!targets.length || !createVectorEffect(type, "")) return [];
7073
+ const created = [];
7074
+ const next = /* @__PURE__ */ new Map();
7075
+ for (const node of targets) {
7076
+ const list = _nullishCoalesce(node.effects, () => ( []));
7077
+ let k = list.length + 1;
7078
+ while (list.some((e) => e.id === `fx${k}`)) k++;
7079
+ const params = { ..._nullishCoalesce(options.params, () => ( {})) };
7080
+ if (type === "repeater" && params.position === void 0) {
7081
+ const b = _chunkVNYRI265cjs.bezierPathBounds.call(void 0, vectorAppearanceOutline(node));
7082
+ if (b && b.maxX - b.minX > 0) params.position = { x: Math.round((b.maxX - b.minX) * 1.25 * 100) / 100, y: 0 };
7083
+ }
7084
+ const effect = createVectorEffect(type, `fx${k}`, params);
7085
+ const at2 = options.index === void 0 ? list.length : Math.min(list.length, Math.max(0, Math.round(options.index)));
7086
+ next.set(node.id, { ...node, effects: [...list.slice(0, at2), effect, ...list.slice(at2)] });
7087
+ created.push(effect.id);
7088
+ }
7089
+ this.change(`Add ${VECTOR_EFFECT_LABELS[type]}`, () => this.setDoc(mapTree(this.doc.nodes, (n) => _nullishCoalesce(next.get(n.id), () => ( n)))));
7090
+ return created;
7091
+ }
7092
+ editEffects(nodeId, label, fn, merge) {
7093
+ const node = this.getNode(nodeId);
7094
+ if (!node) return { ok: false, message: `There is no node "${nodeId}".` };
7095
+ const result = fn(_nullishCoalesce(node.effects, () => ( [])));
7096
+ if (typeof result === "string") return { ok: false, message: result };
7097
+ this.change(label, () => this.replaceNode(nodeId, result.length ? { ...node, effects: result } : (({ effects: _e, ...rest }) => rest)(node)), merge);
7098
+ return { ok: true };
7099
+ }
7100
+ /**
7101
+ * Turns an effect on or off and changes its parameters (unknown or invalid values are
7102
+ * ignored). With `merge` (true, or a key of your own), consecutive updates of the same effect
7103
+ * fold into one undo step, as a slider drag should; call `endMergedEdit` when it ends.
7104
+ */
7105
+ updateEffect(nodeId, effectId, patch, options = {}) {
7106
+ const merge = options.merge === true ? `effect:${nodeId}:${effectId}` : options.merge || void 0;
7107
+ const node = this.getNode(nodeId);
7108
+ const current = _optionalChain([node, 'optionalAccess', _202 => _202.effects, 'optionalAccess', _203 => _203.find, 'call', _204 => _204((e) => e.id === effectId)]);
7109
+ const label = current ? _nullishCoalesce(VECTOR_EFFECT_LABELS[current.type], () => ( "Effect")) : "Effect";
7110
+ return this.editEffects(
7111
+ nodeId,
7112
+ `Edit ${label}`,
7113
+ (list) => {
7114
+ const i = list.findIndex((e2) => e2.id === effectId);
7115
+ if (i < 0) return `Node "${nodeId}" has no effect "${effectId}".`;
7116
+ const e = list[i];
7117
+ const params = patch.params ? normalizeVectorEffectParams(e.type, patch.params, e.params) : e.params;
7118
+ const next = { ...e, params, ...patch.enabled !== void 0 ? { enabled: patch.enabled } : {} };
7119
+ if (next.enabled !== false) delete next.enabled;
7120
+ return list.map((x, j) => j === i ? next : x);
7121
+ },
7122
+ merge
7123
+ );
7124
+ }
7125
+ /** Removes an effect from a node's stack. */
7126
+ removeEffect(nodeId, effectId) {
7127
+ return this.editEffects(nodeId, "Remove Effect", (list) => list.some((e) => e.id === effectId) ? list.filter((e) => e.id !== effectId) : `Node "${nodeId}" has no effect "${effectId}".`);
7128
+ }
7129
+ /** Moves an effect to position `index` of its stack (0 is applied first). */
7130
+ moveEffect(nodeId, effectId, index) {
7131
+ return this.editEffects(nodeId, "Reorder Effects", (list) => {
7132
+ const i = list.findIndex((e2) => e2.id === effectId);
7133
+ if (i < 0) return `Node "${nodeId}" has no effect "${effectId}".`;
7134
+ const to = Math.min(list.length - 1, Math.max(0, Math.round(index)));
7135
+ const out = list.slice();
7136
+ const [e] = out.splice(i, 1);
7137
+ out.splice(to, 0, e);
7138
+ return out;
7139
+ });
7140
+ }
7141
+ /**
7142
+ * Expand Appearance: bakes the path effects and live booleans of the selected (or given)
7143
+ * nodes, and of everything inside them, into plain paths. A node keeps its id (a group when
7144
+ * it draws as several shapes); the shapes it made get new ids. Returns the ids of the expanded
7145
+ * nodes (empty when none was live).
7146
+ */
7147
+ expandAppearance(options = {}) {
7148
+ const roots = (_nullishCoalesce(options.ids, () => ( this.selectedRoots()))).map((id) => this.getNode(id)).filter((n) => !!n && hasVectorAppearance(n));
7149
+ if (!roots.length) return [];
7150
+ const fresh = (n) => {
7151
+ const id = n.id.includes("~fx") ? this.newId() : n.id;
7152
+ return n.type === "group" ? { ...n, id, children: n.children.map(fresh) } : { ...n, id };
7153
+ };
7154
+ const bake = (n) => {
7155
+ if (!hasVectorAppearance(n)) return n;
7156
+ if (!hasOwnVectorAppearance(n)) return { ...n, children: n.children.map(bake) };
7157
+ let e = expandVectorAppearance(n);
7158
+ if (e.type === "group" && e.children.length === 1 && e.children[0].type === "path") {
7159
+ const { id: _id, opacity, name, ...child } = e.children[0];
7160
+ const k = (_nullishCoalesce(e.opacity, () => ( 1))) * (_nullishCoalesce(opacity, () => ( 1)));
7161
+ e = { ...child, id: e.id, name: _nullishCoalesce(e.name, () => ( name)), ...placementOf(e), ...k < 1 ? { opacity: k } : {} };
7162
+ }
7163
+ return fresh(e);
7164
+ };
7165
+ const next = new Map(roots.map((n) => [n.id, bake(n)]));
7166
+ this.change("Expand Appearance", () => {
7167
+ this.setDoc(mapTree(this.doc.nodes, (n) => _nullishCoalesce(next.get(n.id), () => ( n))));
7168
+ this.anchors = [];
7169
+ this.editingId = null;
7170
+ });
7171
+ return roots.map((n) => n.id);
7172
+ }
6114
7173
  rename(id, name) {
6115
7174
  return this.updateNode(id, { name }, { label: "Rename" });
6116
7175
  }
@@ -6179,10 +7238,10 @@ var VectorEditorController = (_class3 = class {
6179
7238
  return this.selection.filter((id) => {
6180
7239
  let covered = false;
6181
7240
  const loc = locateVectorNode(this.doc.nodes, id);
6182
- let parent = _nullishCoalesce(_optionalChain([loc, 'optionalAccess', _172 => _172.parent]), () => ( null));
7241
+ let parent = _nullishCoalesce(_optionalChain([loc, 'optionalAccess', _205 => _205.parent]), () => ( null));
6183
7242
  while (parent) {
6184
7243
  if (this.selection.includes(parent.id)) covered = true;
6185
- parent = _nullishCoalesce(_optionalChain([locateVectorNode, 'call', _173 => _173(this.doc.nodes, parent.id), 'optionalAccess', _174 => _174.parent]), () => ( null));
7244
+ parent = _nullishCoalesce(_optionalChain([locateVectorNode, 'call', _206 => _206(this.doc.nodes, parent.id), 'optionalAccess', _207 => _207.parent]), () => ( null));
6186
7245
  }
6187
7246
  return !covered;
6188
7247
  });
@@ -6365,8 +7424,8 @@ var VectorEditorController = (_class3 = class {
6365
7424
  if (!ids.length) return null;
6366
7425
  const locs = ids.map((id2) => locateVectorNode(this.doc.nodes, id2));
6367
7426
  if (locs.some((l) => !l)) return null;
6368
- const parent = _nullishCoalesce(_optionalChain([locs, 'access', _175 => _175[0], 'access', _176 => _176.parent, 'optionalAccess', _177 => _177.id]), () => ( null));
6369
- if (locs.some((l) => (_nullishCoalesce(_optionalChain([l, 'access', _178 => _178.parent, 'optionalAccess', _179 => _179.id]), () => ( null))) !== parent)) return null;
7427
+ const parent = _nullishCoalesce(_optionalChain([locs, 'access', _208 => _208[0], 'access', _209 => _209.parent, 'optionalAccess', _210 => _210.id]), () => ( null));
7428
+ if (locs.some((l) => (_nullishCoalesce(_optionalChain([l, 'access', _211 => _211.parent, 'optionalAccess', _212 => _212.id]), () => ( null))) !== parent)) return null;
6370
7429
  const id = this.newId();
6371
7430
  this.change("Group", () => {
6372
7431
  const set = new Set(ids);
@@ -6389,7 +7448,7 @@ var VectorEditorController = (_class3 = class {
6389
7448
  }
6390
7449
  /** Replaces selected groups with their children. */
6391
7450
  ungroup(options = {}) {
6392
- const groups = (_nullishCoalesce(options.ids, () => ( this.selection))).map((id) => this.getNode(id)).filter((n) => _optionalChain([n, 'optionalAccess', _180 => _180.type]) === "group");
7451
+ const groups = (_nullishCoalesce(options.ids, () => ( this.selection))).map((id) => this.getNode(id)).filter((n) => _optionalChain([n, 'optionalAccess', _213 => _213.type]) === "group");
6393
7452
  if (!groups.length) return { ok: false, message: "Select a group to ungroup." };
6394
7453
  const set = new Set(groups.map((g) => g.id));
6395
7454
  this.change("Ungroup", () => {
@@ -6402,7 +7461,7 @@ var VectorEditorController = (_class3 = class {
6402
7461
  const opacity = n.opacity;
6403
7462
  const m = nodeMatrix(n);
6404
7463
  out.push(
6405
- ...n.children.map((c) => c.blendStep ? (({ blendStep: _s, locked: _l, ...rest }) => rest)(c) : c).map((c) => n.transform ? transformVectorNode(c, m) : c).map((c) => opacity !== void 0 && opacity < 1 ? { ...c, opacity: (_nullishCoalesce(c.opacity, () => ( 1))) * opacity } : c)
7464
+ ...n.children.map((c) => c.blendStep ? (({ blendStep: _s, locked: _l, ...rest }) => rest)(c) : c).map((c) => c.booleanOperation ? (({ booleanOperation: _b, ...rest }) => rest)(c) : c).map((c) => n.transform ? transformVectorNode(c, m) : c).map((c) => opacity !== void 0 && opacity < 1 ? { ...c, opacity: (_nullishCoalesce(c.opacity, () => ( 1))) * opacity } : c)
6406
7465
  );
6407
7466
  } else if (n.type === "group") {
6408
7467
  const children = flatten2(n.children);
@@ -6439,34 +7498,33 @@ var VectorEditorController = (_class3 = class {
6439
7498
  /**
6440
7499
  * Combines the selected paths (two or more) into one with a boolean operation. `subtract`
6441
7500
  * removes the upper shapes from the lowest one. The result takes the lowest shape's style
6442
- * and place.
7501
+ * and place. Shapes take part as drawn (path effects and live booleans applied).
7502
+ *
7503
+ * With `live`, the operands stay editable instead: a lone live boolean group gets the
7504
+ * operation (its operands follow it again), operands of live boolean groups get it as their
7505
+ * own, and anything else (two or more nodes with one parent) is wrapped in a new live boolean
7506
+ * group. Returns the result's (or the live group's) id, or null.
6443
7507
  */
6444
7508
  booleanOp(op, options = {}) {
6445
7509
  const roots = _nullishCoalesce(options.ids, () => ( this.selectedRoots()));
6446
- const order = [];
6447
- walkVectorNodes(this.doc.nodes, (n) => {
6448
- if (roots.includes(n.id)) for (const p of collectPathNodes(n)) order.push(p.id);
6449
- });
6450
- const paths = [...new Set(order)].map((id2) => this.getNode(id2));
6451
- if (paths.length < 2) return null;
7510
+ if (options.live) return this.liveBooleanOp(op, roots);
7511
+ const entries = vectorPathEntries(this.doc, roots, { locked: true });
7512
+ if (entries.length < 2) return null;
6452
7513
  const result = _chunkVNYRI265cjs.pathBoolean.call(void 0,
6453
7514
  BOOLEAN_OPS[op],
6454
- paths.map((p) => ({
6455
- path: vectorPathWorldBezier(
6456
- { ...p, subpaths: p.subpaths.filter((s) => s.anchors.length > 1).map((s) => ({ ...s, closed: true })) },
6457
- _nullishCoalesce(vectorParentMatrix(this.doc.nodes, p.id), () => ( IDENTITY_MATRIX))
6458
- ),
6459
- fillRule: _nullishCoalesce(p.fillRule, () => ( "nonzero"))
7515
+ entries.map((e) => ({
7516
+ path: vectorPathWorldBezier({ ...e.node, subpaths: e.node.subpaths.filter((s) => s.anchors.length > 1).map((s) => ({ ...s, closed: true })) }, e.parent),
7517
+ fillRule: _nullishCoalesce(e.node.fillRule, () => ( "nonzero"))
6460
7518
  }))
6461
7519
  );
6462
- const base = paths[0];
6463
- const anchorRoot = _nullishCoalesce(roots.find((r) => findVectorNode([this.getNode(r)], base.id)), () => ( base.id));
7520
+ const base = entries[0].node;
7521
+ const anchorRoot = _nullishCoalesce(roots.find((r) => this.holds(r, base.id)), () => ( base.id));
6464
7522
  const subpaths = bezierToSubpaths(this.intoParentSpace(anchorRoot, result.path));
6465
7523
  if (result.error || !subpaths.length) return null;
6466
7524
  const id = this.newId();
6467
- const { transform: _t, ...baseRest } = cloneVectorNode(base);
7525
+ const { transform: _t, effects: _e, booleanOperation: _b, ...baseRest } = cloneVectorNode(base);
6468
7526
  const node = { ...baseRest, id, name: BOOLEAN_LABELS[op], subpaths };
6469
- const drop = /* @__PURE__ */ new Set([...paths.map((p) => p.id), ...roots]);
7527
+ const drop = /* @__PURE__ */ new Set([...entries.map((e) => e.node.id), ...roots]);
6470
7528
  this.change(BOOLEAN_LABELS[op], () => {
6471
7529
  this.setDoc(mapTree(this.doc.nodes, (n) => n.id === anchorRoot ? node : drop.has(n.id) ? null : n));
6472
7530
  this.selection = [id];
@@ -6475,18 +7533,75 @@ var VectorEditorController = (_class3 = class {
6475
7533
  });
6476
7534
  return id;
6477
7535
  }
7536
+ /** Whether stored node `rootId` holds `id` as drawn (`id` may be an expanded path inside it). */
7537
+ holds(rootId, id) {
7538
+ const n = this.getNode(rootId);
7539
+ return !!n && (!!findVectorNode([n], id) || !!findVectorNode([expandVectorAppearance(n)], id));
7540
+ }
7541
+ liveBooleanOp(op, roots) {
7542
+ const nodes = roots.map((id2) => this.getNode(id2));
7543
+ if (!nodes.length || nodes.some((n) => !n)) return null;
7544
+ const label = `Live ${BOOLEAN_LABELS[op]}`;
7545
+ const lone = nodes.length === 1 ? nodes[0] : null;
7546
+ if (isVectorLiveBoolean(lone)) {
7547
+ const children = lone.children.map((c) => c.booleanOperation ? (({ booleanOperation: _b, ...rest }) => rest)(c) : c);
7548
+ this.change(label, () => this.replaceNode(lone.id, { ...lone, liveBoolean: op, children }));
7549
+ return lone.id;
7550
+ }
7551
+ const parents = roots.map((id2) => _nullishCoalesce(_optionalChain([locateVectorNode, 'call', _214 => _214(this.doc.nodes, id2), 'optionalAccess', _215 => _215.parent]), () => ( null)));
7552
+ if (parents.every((g) => isVectorLiveBoolean(g))) {
7553
+ const set = new Set(roots);
7554
+ this.change(
7555
+ label,
7556
+ () => this.setDoc(
7557
+ mapTree(this.doc.nodes, (n) => {
7558
+ if (n.type !== "group" || !n.liveBoolean || !n.children.some((c) => set.has(c.id))) return n;
7559
+ const group = n;
7560
+ const children = group.children.map((c) => {
7561
+ if (!set.has(c.id)) return c;
7562
+ const { booleanOperation: _b, ...rest } = c;
7563
+ return op === group.liveBoolean ? rest : { ...rest, booleanOperation: op };
7564
+ });
7565
+ return { ...group, children };
7566
+ })
7567
+ )
7568
+ );
7569
+ return parents[0].id;
7570
+ }
7571
+ if (nodes.length < 2) return null;
7572
+ const parent = _nullishCoalesce(_optionalChain([parents, 'access', _216 => _216[0], 'optionalAccess', _217 => _217.id]), () => ( null));
7573
+ if (parents.some((g) => (_nullishCoalesce(_optionalChain([g, 'optionalAccess', _218 => _218.id]), () => ( null))) !== parent)) return null;
7574
+ const id = this.newId();
7575
+ this.change(label, () => {
7576
+ const set = new Set(roots);
7577
+ const wrap = (list) => {
7578
+ const members = list.filter((n) => set.has(n.id)).map((c) => c.booleanOperation ? (({ booleanOperation: _b, ...rest }) => rest)(c) : c);
7579
+ const top = Math.max(...list.map((n, i) => set.has(n.id) ? i : -1));
7580
+ const out = [];
7581
+ list.forEach((n, i) => {
7582
+ if (i === top) out.push({ id, type: "group", name: BOOLEAN_LABELS[op], liveBoolean: op, children: members });
7583
+ if (!set.has(n.id)) out.push(n);
7584
+ });
7585
+ return out;
7586
+ };
7587
+ if (parent === null) this.setDoc(wrap(this.doc.nodes));
7588
+ else this.setDoc(mapTree(this.doc.nodes, (n) => n.id === parent && n.type === "group" ? { ...n, children: wrap(n.children) } : n));
7589
+ this.selection = [id];
7590
+ this.anchors = [];
7591
+ this.editingId = null;
7592
+ });
7593
+ return id;
7594
+ }
6478
7595
  /** Joins the selected paths into one compound path (subpaths kept, lowest style). */
6479
7596
  combine(options = {}) {
6480
7597
  const roots = _nullishCoalesce(options.ids, () => ( this.selectedRoots()));
6481
- const paths = [];
6482
- walkVectorNodes(this.doc.nodes, (n) => {
6483
- if (roots.includes(n.id)) paths.push(...collectPathNodes(n));
6484
- });
6485
- if (paths.length < 2) return null;
7598
+ const entries = vectorPathEntries(this.doc, roots, { locked: true });
7599
+ if (entries.length < 2) return null;
7600
+ const paths = entries.map((e) => e.node);
6486
7601
  const id = this.newId();
6487
- const first = _nullishCoalesce(roots.find((r) => findVectorNode([this.getNode(r)], paths[0].id)), () => ( paths[0].id));
6488
- const subpaths = paths.flatMap((p) => bezierToSubpaths(this.intoParentSpace(first, vectorPathWorldBezier(p, _nullishCoalesce(vectorParentMatrix(this.doc.nodes, p.id), () => ( IDENTITY_MATRIX))))));
6489
- const { transform: _t, ...baseRest } = cloneVectorNode(paths[0]);
7602
+ const first = _nullishCoalesce(roots.find((r) => this.holds(r, paths[0].id)), () => ( paths[0].id));
7603
+ const subpaths = entries.flatMap((e) => bezierToSubpaths(this.intoParentSpace(first, vectorPathWorldBezier(e.node, e.parent))));
7604
+ const { transform: _t, effects: _e, booleanOperation: _b, ...baseRest } = cloneVectorNode(paths[0]);
6490
7605
  const node = { ...baseRest, id, name: "Compound Path", subpaths };
6491
7606
  const drop = /* @__PURE__ */ new Set([...paths.map((p) => p.id), ...roots]);
6492
7607
  this.change("Combine", () => {
@@ -6503,7 +7618,7 @@ var VectorEditorController = (_class3 = class {
6503
7618
  }
6504
7619
  /** Splits selected compound paths into one path per subpath. */
6505
7620
  breakApart(options = {}) {
6506
- const paths = (_nullishCoalesce(options.ids, () => ( this.selection))).map((id) => this.getNode(id)).filter((n) => _optionalChain([n, 'optionalAccess', _181 => _181.type]) === "path" && n.subpaths.length > 1);
7621
+ const paths = (_nullishCoalesce(options.ids, () => ( this.selection))).map((id) => this.getNode(id)).filter((n) => _optionalChain([n, 'optionalAccess', _219 => _219.type]) === "path" && n.subpaths.length > 1);
6507
7622
  if (!paths.length) return { ok: false, message: "Select a compound path to break apart." };
6508
7623
  const created = [];
6509
7624
  const set = new Set(paths.map((p) => p.id));
@@ -6541,10 +7656,7 @@ var VectorEditorController = (_class3 = class {
6541
7656
  const result = _chunkVNYRI265cjs.pathfinder.call(void 0, op, shapes);
6542
7657
  if (result.error || !result.pieces.length) return [];
6543
7658
  const last = entries[entries.length - 1].node.id;
6544
- const topRoot = _nullishCoalesce([...roots].reverse().find((r) => {
6545
- const n = this.getNode(r);
6546
- return !!n && !!findVectorNode([n], last);
6547
- }), () => ( last));
7659
+ const topRoot = _nullishCoalesce([...roots].reverse().find((r) => this.holds(r, last)), () => ( last));
6548
7660
  const nodes = [];
6549
7661
  for (const piece of result.pieces) {
6550
7662
  const subpaths = bezierToSubpaths(this.intoParentSpace(topRoot, piece.path)).map((sp) => piece.open ? { ...sp, closed: false } : sp);
@@ -6574,7 +7686,7 @@ var VectorEditorController = (_class3 = class {
6574
7686
  const out = /* @__PURE__ */ new Map();
6575
7687
  for (const id of _nullishCoalesce(ids, () => ( this.selection))) {
6576
7688
  const node = this.getNode(id);
6577
- const group = isVectorBlendGroup(node) ? node : _optionalChain([locateVectorNode, 'call', _182 => _182(this.doc.nodes, id), 'optionalAccess', _183 => _183.parent]);
7689
+ const group = isVectorBlendGroup(node) ? node : _optionalChain([locateVectorNode, 'call', _220 => _220(this.doc.nodes, id), 'optionalAccess', _221 => _221.parent]);
6578
7690
  if (isVectorBlendGroup(group)) out.set(group.id, group);
6579
7691
  }
6580
7692
  return [...out.values()];
@@ -6592,8 +7704,8 @@ var VectorEditorController = (_class3 = class {
6592
7704
  });
6593
7705
  if (ids.length < 2) return null;
6594
7706
  const locs = ids.map((id2) => locateVectorNode(this.doc.nodes, id2));
6595
- const parent = _nullishCoalesce(_optionalChain([locs, 'access', _184 => _184[0], 'access', _185 => _185.parent, 'optionalAccess', _186 => _186.id]), () => ( null));
6596
- if (locs.some((l) => (_nullishCoalesce(_optionalChain([l, 'access', _187 => _187.parent, 'optionalAccess', _188 => _188.id]), () => ( null))) !== parent)) return null;
7707
+ const parent = _nullishCoalesce(_optionalChain([locs, 'access', _222 => _222[0], 'access', _223 => _223.parent, 'optionalAccess', _224 => _224.id]), () => ( null));
7708
+ if (locs.some((l) => (_nullishCoalesce(_optionalChain([l, 'access', _225 => _225.parent, 'optionalAccess', _226 => _226.id]), () => ( null))) !== parent)) return null;
6597
7709
  const order = input.keepOrder ? ids : ids.slice().sort((a, b) => locs[ids.indexOf(a)].index - locs[ids.indexOf(b)].index);
6598
7710
  const blend = blendOptionsOf({ ...this.blendDefaults, ...input });
6599
7711
  if (input.starts) {
@@ -6635,7 +7747,7 @@ var VectorEditorController = (_class3 = class {
6635
7747
  const node = this.getNode(nodeId);
6636
7748
  if (!isVectorBlendGroup(group)) return { ok: false, message: `"${blendId}" is not a blend.` };
6637
7749
  if (!node || node.blendStep || node.locked || node.id === blendId) return { ok: false, message: `"${nodeId}" cannot be a key.` };
6638
- const parentOf = (id) => _nullishCoalesce(_optionalChain([locateVectorNode, 'call', _189 => _189(this.doc.nodes, id), 'optionalAccess', _190 => _190.parent, 'optionalAccess', _191 => _191.id]), () => ( null));
7750
+ const parentOf = (id) => _nullishCoalesce(_optionalChain([locateVectorNode, 'call', _227 => _227(this.doc.nodes, id), 'optionalAccess', _228 => _228.parent, 'optionalAccess', _229 => _229.id]), () => ( null));
6639
7751
  if (parentOf(blendId) !== parentOf(nodeId)) return { ok: false, message: "The new key must sit beside the blend (same parent)." };
6640
7752
  const start = options.start;
6641
7753
  this.change("Blend", () => {
@@ -6705,7 +7817,7 @@ var VectorEditorController = (_class3 = class {
6705
7817
  replaceBlendSpine(options = {}) {
6706
7818
  const roots = _nullishCoalesce(options.ids, () => ( this.selectedRoots()));
6707
7819
  const groups = this.blendTargets(roots);
6708
- const paths = roots.map((id) => this.getNode(id)).filter((n) => _optionalChain([n, 'optionalAccess', _192 => _192.type]) === "path" && !n.blendStep && !isVectorBlendGroup(_optionalChain([locateVectorNode, 'call', _193 => _193(this.doc.nodes, n.id), 'optionalAccess', _194 => _194.parent])));
7820
+ const paths = roots.map((id) => this.getNode(id)).filter((n) => _optionalChain([n, 'optionalAccess', _230 => _230.type]) === "path" && !n.blendStep && !isVectorBlendGroup(_optionalChain([locateVectorNode, 'call', _231 => _231(this.doc.nodes, n.id), 'optionalAccess', _232 => _232.parent])));
6709
7821
  if (groups.length !== 1 || paths.length !== 1) return { ok: false, message: "Select one blend and one path to be its spine." };
6710
7822
  const group = groups[0];
6711
7823
  const path = paths[0];
@@ -6736,8 +7848,8 @@ var VectorEditorController = (_class3 = class {
6736
7848
  shapeBuilderMap(ids) {
6737
7849
  const roots = _nullishCoalesce(ids, () => ( this.selectedRoots()));
6738
7850
  const key = roots.join("\0");
6739
- if (_optionalChain([this, 'access', _195 => _195.builderCache, 'optionalAccess', _196 => _196.doc]) === this.doc && this.builderCache.key === key) return this.builderCache.map;
6740
- const entries = roots.length ? vectorPathEntries(this.doc, roots) : [];
7851
+ if (_optionalChain([this, 'access', _233 => _233.builderCache, 'optionalAccess', _234 => _234.doc]) === this.doc && this.builderCache.key === key) return this.builderCache.map;
7852
+ const entries = roots.length ? vectorPathEntries(this.doc, roots, { expand: false }) : [];
6741
7853
  const map = entries.length ? vectorShapeBuilderMap(entries) : null;
6742
7854
  this.builderCache = { doc: this.doc, key, map };
6743
7855
  return map;
@@ -6796,9 +7908,9 @@ var VectorEditorController = (_class3 = class {
6796
7908
  const list = [];
6797
7909
  const r = plan.replace.get(i);
6798
7910
  if (r === void 0) list.push(node);
6799
- else if (_optionalChain([r, 'optionalAccess', _197 => _197.kind]) === "fill") list.push({ ...node, fillRule: "nonzero", subpaths: bezierToSubpaths(toLocal(r.path)) });
6800
- else if (_optionalChain([r, 'optionalAccess', _198 => _198.kind]) === "outline") list.push({ ...node, subpaths: bezierToSubpaths(toLocal(r.path)) });
6801
- else if (_optionalChain([r, 'optionalAccess', _199 => _199.kind]) === "pieces") {
7911
+ else if (_optionalChain([r, 'optionalAccess', _235 => _235.kind]) === "fill") list.push({ ...node, fillRule: "nonzero", subpaths: bezierToSubpaths(toLocal(r.path)) });
7912
+ else if (_optionalChain([r, 'optionalAccess', _236 => _236.kind]) === "outline") list.push({ ...node, subpaths: bezierToSubpaths(toLocal(r.path)) });
7913
+ else if (_optionalChain([r, 'optionalAccess', _237 => _237.kind]) === "pieces") {
6802
7914
  r.paths.forEach(
6803
7915
  (path, k) => list.push({ ...node, id: k === 0 ? node.id : this.newId(), subpaths: bezierToSubpaths(toLocal(path)).map((sp) => ({ ...sp, closed: false })) })
6804
7916
  );
@@ -6832,7 +7944,7 @@ var VectorEditorController = (_class3 = class {
6832
7944
  }
6833
7945
  /** The paint bucket's map of the visible outlines, cached per document and gap. */
6834
7946
  fillMap(gap) {
6835
- if (_optionalChain([this, 'access', _200 => _200.fillCache, 'optionalAccess', _201 => _201.doc]) === this.doc && this.fillCache.gap === gap) return this.fillCache.map;
7947
+ if (_optionalChain([this, 'access', _238 => _238.fillCache, 'optionalAccess', _239 => _239.doc]) === this.doc && this.fillCache.gap === gap) return this.fillCache.map;
6836
7948
  const map = vectorFillMap(this.doc, gap);
6837
7949
  this.fillCache = { doc: this.doc, gap, map };
6838
7950
  return map;
@@ -6846,8 +7958,8 @@ var VectorEditorController = (_class3 = class {
6846
7958
  */
6847
7959
  fillRegion(point, options = {}) {
6848
7960
  if (!Number.isFinite(point.x) || !Number.isFinite(point.y)) return null;
6849
- const region = _optionalChain([this, 'access', _202 => _202.fillMap, 'call', _203 => _203(_nullishCoalesce(options.gap, () => ( this.editing.fillGap))), 'optionalAccess', _204 => _204.regionAt, 'call', _205 => _205([point.x, point.y])]);
6850
- if (!_optionalChain([region, 'optionalAccess', _206 => _206.length])) return null;
7961
+ const region = _optionalChain([this, 'access', _240 => _240.fillMap, 'call', _241 => _241(_nullishCoalesce(options.gap, () => ( this.editing.fillGap))), 'optionalAccess', _242 => _242.regionAt, 'call', _243 => _243([point.x, point.y])]);
7962
+ if (!_optionalChain([region, 'optionalAccess', _244 => _244.length])) return null;
6851
7963
  let below = null;
6852
7964
  const roots = new Set(this.selectedRoots());
6853
7965
  walkVectorNodes(this.doc.nodes, (n) => {
@@ -6873,7 +7985,7 @@ var VectorEditorController = (_class3 = class {
6873
7985
  /** Updates the Shape Builder / paint bucket highlight for the pointer at `p`; true when it changed. */
6874
7986
  hoverBuilder(p, alt) {
6875
7987
  if (this.tool === "paintBucket") {
6876
- const region = _nullishCoalesce(_optionalChain([this, 'access', _207 => _207.fillMap, 'call', _208 => _208(this.editing.fillGap), 'optionalAccess', _209 => _209.regionAt, 'call', _210 => _210([p.x, p.y])]), () => ( null));
7988
+ const region = _nullishCoalesce(_optionalChain([this, 'access', _245 => _245.fillMap, 'call', _246 => _246(this.editing.fillGap), 'optionalAccess', _247 => _247.regionAt, 'call', _248 => _248([p.x, p.y])]), () => ( null));
6877
7989
  const key2 = region ? _chunkVNYRI265cjs.bezierPathToSvg.call(void 0, region, { precision: 2 }) : null;
6878
7990
  if (key2 === this.builderHoverKey) return false;
6879
7991
  this.builderHoverKey = key2;
@@ -6981,7 +8093,7 @@ var VectorEditorController = (_class3 = class {
6981
8093
  /** `doc` with anchor `ref` moved to document point `to` by a Curvature-tool move. */
6982
8094
  curvatureMoved(doc, ref, to) {
6983
8095
  const node = findVectorNode(doc.nodes, ref.nodeId);
6984
- if (_optionalChain([node, 'optionalAccess', _211 => _211.type]) !== "path" || node.locked || !node.subpaths[ref.subpath]) return doc;
8096
+ if (_optionalChain([node, 'optionalAccess', _249 => _249.type]) !== "path" || node.locked || !node.subpaths[ref.subpath]) return doc;
6985
8097
  const q = this.toLocal(ref.nodeId, to, doc);
6986
8098
  const subpaths = node.subpaths.map((sp, i) => i === ref.subpath ? curvatureMoveAnchor(sp, ref.index, q) : sp);
6987
8099
  const nodes = mapTree(doc.nodes, (n) => n.id === ref.nodeId ? { ...node, subpaths } : n);
@@ -6990,7 +8102,7 @@ var VectorEditorController = (_class3 = class {
6990
8102
  /** `doc` with segment `ref` bent through document point `p` at parameter `t`. */
6991
8103
  bent(doc, ref, t, p) {
6992
8104
  const node = findVectorNode(doc.nodes, ref.nodeId);
6993
- if (_optionalChain([node, 'optionalAccess', _212 => _212.type]) !== "path" || node.locked || !node.subpaths[ref.subpath]) return doc;
8105
+ if (_optionalChain([node, 'optionalAccess', _250 => _250.type]) !== "path" || node.locked || !node.subpaths[ref.subpath]) return doc;
6994
8106
  const q = this.toLocal(ref.nodeId, p, doc);
6995
8107
  const subpaths = node.subpaths.map((sp, i) => i === ref.subpath ? bendSegment(sp, ref.segment, t, q) : sp);
6996
8108
  return { ...doc, nodes: mapTree(doc.nodes, (n) => n.id === ref.nodeId ? { ...node, subpaths } : n) };
@@ -7001,7 +8113,7 @@ var VectorEditorController = (_class3 = class {
7001
8113
  */
7002
8114
  bendSegment(ref, to, t = 0.5) {
7003
8115
  const node = this.getNode(ref.nodeId);
7004
- const sp = _optionalChain([node, 'optionalAccess', _213 => _213.type]) === "path" ? node.subpaths[ref.subpath] : void 0;
8116
+ const sp = _optionalChain([node, 'optionalAccess', _251 => _251.type]) === "path" ? node.subpaths[ref.subpath] : void 0;
7005
8117
  if (!sp || ref.segment < 0 || ref.segment >= (sp.closed ? sp.anchors.length : sp.anchors.length - 1) || sp.anchors.length < 2) return { ok: false, message: "There is no such segment." };
7006
8118
  if (node.locked) return { ok: false, message: "The path is locked." };
7007
8119
  this.change("Bend Segment", () => {
@@ -7036,7 +8148,7 @@ var VectorEditorController = (_class3 = class {
7036
8148
  /** Adds an anchor on the nearest segment of `nodeId` to document point `point` (shape unchanged). */
7037
8149
  insertAnchorAt(nodeId, point) {
7038
8150
  const node = this.getNode(nodeId);
7039
- if (_optionalChain([node, 'optionalAccess', _214 => _214.type]) !== "path") return null;
8151
+ if (_optionalChain([node, 'optionalAccess', _252 => _252.type]) !== "path") return null;
7040
8152
  const hit = nearestSegment(node, this.toLocal(nodeId, point));
7041
8153
  if (!hit) return null;
7042
8154
  const { subpath, index } = insertAnchor(node.subpaths[hit.subpath], hit.segment, hit.t);
@@ -7080,7 +8192,7 @@ var VectorEditorController = (_class3 = class {
7080
8192
  setClosed(closed, nodeId) {
7081
8193
  const targets = nodeId ? (() => {
7082
8194
  const n = this.getNode(nodeId);
7083
- return _optionalChain([n, 'optionalAccess', _215 => _215.type]) === "path" ? n.subpaths.map((_, s) => ({ nodeId, subpath: s })) : [];
8195
+ return _optionalChain([n, 'optionalAccess', _253 => _253.type]) === "path" ? n.subpaths.map((_, s) => ({ nodeId, subpath: s })) : [];
7084
8196
  })() : this.anchors.map((r) => ({ nodeId: r.nodeId, subpath: r.subpath }));
7085
8197
  if (!targets.length) return { ok: false, message: "Select a path or points." };
7086
8198
  this.change(closed ? "Close Path" : "Open Path", () => {
@@ -7101,7 +8213,7 @@ var VectorEditorController = (_class3 = class {
7101
8213
  this.setDoc(
7102
8214
  mapTree(
7103
8215
  this.doc.nodes,
7104
- (n) => n.type === "path" && set.has(n.id) ? { ...n, subpaths: n.subpaths.map(reverseSubpath), ..._optionalChain([n, 'access', _216 => _216.strokeWidthProfile, 'optionalAccess', _217 => _217.length]) ? { strokeWidthProfile: reverseWidthProfile(n.strokeWidthProfile) } : {} } : n
8216
+ (n) => n.type === "path" && set.has(n.id) ? { ...n, subpaths: n.subpaths.map(reverseSubpath), ..._optionalChain([n, 'access', _254 => _254.strokeWidthProfile, 'optionalAccess', _255 => _255.length]) ? { strokeWidthProfile: reverseWidthProfile(n.strokeWidthProfile) } : {} } : n
7105
8217
  )
7106
8218
  );
7107
8219
  this.anchors = [];
@@ -7239,7 +8351,7 @@ var VectorEditorController = (_class3 = class {
7239
8351
  */
7240
8352
  cutPathAt(nodeId, point) {
7241
8353
  const node = this.getNode(nodeId);
7242
- if (_optionalChain([node, 'optionalAccess', _218 => _218.type]) !== "path" || node.locked) return null;
8354
+ if (_optionalChain([node, 'optionalAccess', _256 => _256.type]) !== "path" || node.locked) return null;
7243
8355
  const local = this.toLocal(nodeId, point);
7244
8356
  const hit = nearestSegment(node, local);
7245
8357
  if (!hit) return null;
@@ -7289,7 +8401,7 @@ var VectorEditorController = (_class3 = class {
7289
8401
  if (n.visible === false || n.locked || parent && blocked.has(parent.id)) blocked.add(n.id);
7290
8402
  });
7291
8403
  const visible = (p) => !blocked.has(p.id);
7292
- if (_optionalChain([ids, 'optionalAccess', _219 => _219.length]) || this.selection.length) return this.pathTargets(_nullishCoalesce(ids, () => ( this.selection))).filter(visible);
8404
+ if (_optionalChain([ids, 'optionalAccess', _257 => _257.length]) || this.selection.length) return this.pathTargets(_nullishCoalesce(ids, () => ( this.selection))).filter(visible);
7293
8405
  const box = polylineBounds(points.map(toPoint2), pad);
7294
8406
  if (!box) return [];
7295
8407
  const out = [];
@@ -7375,7 +8487,7 @@ var VectorEditorController = (_class3 = class {
7375
8487
  finishPath() {
7376
8488
  if (!this.pen) return;
7377
8489
  const node = this.getNode(this.pen.nodeId);
7378
- const sp = _optionalChain([node, 'optionalAccess', _220 => _220.subpaths, 'access', _221 => _221[this.pen.subpath]]);
8490
+ const sp = _optionalChain([node, 'optionalAccess', _258 => _258.subpaths, 'access', _259 => _259[this.pen.subpath]]);
7379
8491
  const pen = this.pen;
7380
8492
  this.pen = null;
7381
8493
  this.pointer = null;
@@ -7419,19 +8531,19 @@ var VectorEditorController = (_class3 = class {
7419
8531
  if (trimmed.startsWith("{")) {
7420
8532
  try {
7421
8533
  const data = JSON.parse(trimmed);
7422
- if (_optionalChain([data, 'optionalAccess', _222 => _222.type]) === VECTOR_CLIPBOARD_TYPE && Array.isArray(data.nodes)) nodes = data.nodes;
7423
- } catch (e4) {
8534
+ if (_optionalChain([data, 'optionalAccess', _260 => _260.type]) === VECTOR_CLIPBOARD_TYPE && Array.isArray(data.nodes)) nodes = data.nodes;
8535
+ } catch (e6) {
7424
8536
  nodes = null;
7425
8537
  }
7426
8538
  } else if (/<svg[\s>]/i.test(trimmed)) {
7427
8539
  try {
7428
8540
  nodes = parseVectorSvg(trimmed).nodes;
7429
- } catch (e5) {
8541
+ } catch (e7) {
7430
8542
  nodes = null;
7431
8543
  }
7432
8544
  }
7433
8545
  } else nodes = this.clipboard;
7434
- if (!_optionalChain([nodes, 'optionalAccess', _223 => _223.length])) return [];
8546
+ if (!_optionalChain([nodes, 'optionalAccess', _261 => _261.length])) return [];
7435
8547
  const offset = _nullishCoalesce(options.offset, () => ( (text && !text.trim().startsWith("{") ? { x: 0, y: 0 } : { x: 10, y: 10 })));
7436
8548
  const copies = nodes.map((n) => transformVectorNode(this.freshIds(n), translateMatrix(offset.x, offset.y)));
7437
8549
  this.change("Paste", () => {
@@ -7482,7 +8594,7 @@ var VectorEditorController = (_class3 = class {
7482
8594
  hitHandle(screen) {
7483
8595
  for (const ref of getVisibleHandles(this.view()).reverse()) {
7484
8596
  const a = getAnchorWorld(this.doc, ref);
7485
- const h = _optionalChain([a, 'optionalAccess', _224 => _224[ref.handle]]);
8597
+ const h = _optionalChain([a, 'optionalAccess', _262 => _262[ref.handle]]);
7486
8598
  if (!h) continue;
7487
8599
  const s = this.documentToScreen(h);
7488
8600
  if (Math.hypot(s.x - screen.x, s.y - screen.y) <= this.hitRadius) return ref;
@@ -7521,16 +8633,22 @@ var VectorEditorController = (_class3 = class {
7521
8633
  return best;
7522
8634
  }
7523
8635
  /** Deepest unlocked visible path under `p`. */
8636
+ /** Live groups being edited (selected, or holding the selection or the edited path): their children are hit as stored. */
8637
+ enteredGroups() {
8638
+ return vectorEnteredGroups(this.doc.nodes, this.editingId ? [...this.selection, this.editingId] : this.selection);
8639
+ }
7524
8640
  hitPath(p) {
7525
8641
  const tol = this.tolerance();
8642
+ const entered = this.enteredGroups();
7526
8643
  const search = (list, parent) => {
7527
8644
  for (let i = list.length - 1; i >= 0; i--) {
7528
8645
  const n = list[i];
7529
8646
  if (n.visible === false || n.locked) continue;
7530
8647
  if (n.type === "group") {
8648
+ if (hasOwnVectorAppearance(n) && !entered.has(n.id) && !hitTestVectorNode(n, p, tol, parent, { entered })) continue;
7531
8649
  const found = search(n.children, multiplyMatrices(nodeMatrix(n), parent));
7532
8650
  if (found) return found;
7533
- } else if (hitTestVectorNode(n, p, tol, parent)) return n;
8651
+ } else if (hitTestVectorNode(n, p, tol, parent, { entered })) return n;
7534
8652
  }
7535
8653
  return null;
7536
8654
  };
@@ -7555,7 +8673,7 @@ var VectorEditorController = (_class3 = class {
7555
8673
  case "select": {
7556
8674
  const handle = this.hitTransformHandle(screen);
7557
8675
  if (handle) return { nodeId: null, transformHandle: handle };
7558
- const node = hitTestVectorNodes(this.doc.nodes, p, this.tolerance());
8676
+ const node = hitTestVectorNodes(this.doc.nodes, p, this.tolerance(), { entered: this.enteredGroups() });
7559
8677
  return node ? { nodeId: node.id } : null;
7560
8678
  }
7561
8679
  case "direct": {
@@ -7608,7 +8726,7 @@ var VectorEditorController = (_class3 = class {
7608
8726
  const shown = this.hitWidthHandleIn(screen, this.widthView());
7609
8727
  if (shown) return shown;
7610
8728
  const spot = this.strokeSpotAt(this.screenToDocument(screen));
7611
- return spot && spot.nodeId !== _optionalChain([this, 'access', _225 => _225.hover, 'optionalAccess', _226 => _226.nodeId]) ? this.hitWidthHandleIn(screen, { ...this.widthView(), hover: { nodeId: spot.nodeId } }) : null;
8729
+ return spot && spot.nodeId !== _optionalChain([this, 'access', _263 => _263.hover, 'optionalAccess', _264 => _264.nodeId]) ? this.hitWidthHandleIn(screen, { ...this.widthView(), hover: { nodeId: spot.nodeId } }) : null;
7612
8730
  }
7613
8731
  hitWidthHandleIn(screen, view) {
7614
8732
  let best = null;
@@ -7663,9 +8781,9 @@ var VectorEditorController = (_class3 = class {
7663
8781
  downWidth(screen, p, input) {
7664
8782
  const hit = this.hitWidthHandle(screen);
7665
8783
  const spot = hit ? null : this.strokeSpotAt(p);
7666
- const nodeId = _nullishCoalesce(_optionalChain([hit, 'optionalAccess', _227 => _227.ref, 'access', _228 => _228.nodeId]), () => ( _optionalChain([spot, 'optionalAccess', _229 => _229.nodeId])));
8784
+ const nodeId = _nullishCoalesce(_optionalChain([hit, 'optionalAccess', _265 => _265.ref, 'access', _266 => _266.nodeId]), () => ( _optionalChain([spot, 'optionalAccess', _267 => _267.nodeId])));
7667
8785
  const node = nodeId ? this.getNode(nodeId) : void 0;
7668
- const g = _optionalChain([node, 'optionalAccess', _230 => _230.type]) === "path" ? vectorStrokeWidthGeometry(node) : null;
8786
+ const g = _optionalChain([node, 'optionalAccess', _268 => _268.type]) === "path" ? vectorStrokeWidthGeometry(node) : null;
7669
8787
  if (this.widthEdit) this.widthEdit = null;
7670
8788
  if (!node || node.type !== "path" || !g) {
7671
8789
  if (!input.shift) this.widthPoints = [];
@@ -7685,7 +8803,7 @@ var VectorEditorController = (_class3 = class {
7685
8803
  if (hit) {
7686
8804
  profile = sanitizeWidthProfile(node.strokeWidthProfile);
7687
8805
  ref = { nodeId: node.id, index: hit.ref.index, subpath: hit.ref.subpath };
7688
- t = _nullishCoalesce(_optionalChain([profile, 'access', _231 => _231[ref.index], 'optionalAccess', _232 => _232.t]), () => ( 0));
8806
+ t = _nullishCoalesce(_optionalChain([profile, 'access', _269 => _269[ref.index], 'optionalAccess', _270 => _270.t]), () => ( 0));
7689
8807
  subpath = hit.ref.subpath;
7690
8808
  if (hit.ref.part === "center") mode = input.alt && profile.length < VECTOR_WIDTH_PROFILE_MAX_POINTS ? "copy" : "move";
7691
8809
  else if (input.alt) side = hit.ref.part;
@@ -7840,7 +8958,7 @@ var VectorEditorController = (_class3 = class {
7840
8958
  let anchor = null;
7841
8959
  if (node.type === "path" && node.subpaths[0]) {
7842
8960
  const refs = node.subpaths[0].anchors.map((_, index) => ({ nodeId: node.id, subpath: 0, index }));
7843
- anchor = _nullishCoalesce(_optionalChain([this, 'access', _233 => _233.hitAnchor, 'call', _234 => _234(screen, refs), 'optionalAccess', _235 => _235.index]), () => ( null));
8961
+ anchor = _nullishCoalesce(_optionalChain([this, 'access', _271 => _271.hitAnchor, 'call', _272 => _272(screen, refs), 'optionalAccess', _273 => _273.index]), () => ( null));
7844
8962
  }
7845
8963
  return { nodeId: node.id, anchor };
7846
8964
  }
@@ -7884,7 +9002,7 @@ var VectorEditorController = (_class3 = class {
7884
9002
  this.notify();
7885
9003
  return;
7886
9004
  }
7887
- const node = hitTestVectorNodes(this.doc.nodes, p, this.tolerance());
9005
+ const node = hitTestVectorNodes(this.doc.nodes, p, this.tolerance(), { entered: this.enteredGroups() });
7888
9006
  if (node) {
7889
9007
  const selected = this.selection.includes(node.id);
7890
9008
  if (input.shift) {
@@ -7993,7 +9111,7 @@ var VectorEditorController = (_class3 = class {
7993
9111
  }
7994
9112
  downPen(screen, p, input) {
7995
9113
  const before = this.snapshot();
7996
- const sp = this.pen ? _optionalChain([this, 'access', _236 => _236.getNode, 'call', _237 => _237(this.pen.nodeId), 'optionalAccess', _238 => _238.subpaths, 'access', _239 => _239[this.pen.subpath]]) : void 0;
9114
+ const sp = this.pen ? _optionalChain([this, 'access', _274 => _274.getNode, 'call', _275 => _275(this.pen.nodeId), 'optionalAccess', _276 => _276.subpaths, 'access', _277 => _277[this.pen.subpath]]) : void 0;
7997
9115
  if (this.pen && sp) {
7998
9116
  const pen = this.pen;
7999
9117
  const first = { nodeId: pen.nodeId, subpath: pen.subpath, index: 0 };
@@ -8255,7 +9373,7 @@ var VectorEditorController = (_class3 = class {
8255
9373
  }
8256
9374
  case "shape": {
8257
9375
  const node = this.getNode(drag.nodeId);
8258
- if (_optionalChain([node, 'optionalAccess', _240 => _240.type]) !== "path") return;
9376
+ if (_optionalChain([node, 'optionalAccess', _278 => _278.type]) !== "path") return;
8259
9377
  const leave = { at: drag.start, constrain: input.shift ? drag.tool === "line" ? "angle" : "square" : null, curves: false };
8260
9378
  let end = this.snapDrawn(p, leave, input, () => drag.targets ??= this.drawingTargets(null));
8261
9379
  if (!this.snappedToObject && drag.tool !== "line" && !input.shift && !input.mod && this.snap.objects && drag.targets) end = this.matchShapeSize(drag.targets, drag.start, end, input.alt);
@@ -8329,14 +9447,14 @@ var VectorEditorController = (_class3 = class {
8329
9447
  for (const q of drag.lazy.push([p.x, p.y])) {
8330
9448
  if (Math.hypot(q[0] - last[0], q[1] - last[1]) * this.viewport.zoom < 1.5) continue;
8331
9449
  drag.points.push(q);
8332
- _optionalChain([drag, 'access', _241 => _241.pressures, 'optionalAccess', _242 => _242.push, 'call', _243 => _243(drag.pressure)]);
9450
+ _optionalChain([drag, 'access', _279 => _279.pressures, 'optionalAccess', _280 => _280.push, 'call', _281 => _281(drag.pressure)]);
8333
9451
  moved = true;
8334
9452
  }
8335
9453
  const string = drag.lazy.string();
8336
9454
  const node = this.getNode(drag.nodeId);
8337
- if (_optionalChain([node, 'optionalAccess', _244 => _244.type]) !== "path") return;
9455
+ if (_optionalChain([node, 'optionalAccess', _282 => _282.type]) !== "path") return;
8338
9456
  if (!moved) {
8339
- if (string && _optionalChain([this, 'access', _245 => _245.interaction, 'optionalAccess', _246 => _246.type]) === "draw") {
9457
+ if (string && _optionalChain([this, 'access', _283 => _283.interaction, 'optionalAccess', _284 => _284.type]) === "draw") {
8340
9458
  this.interaction = { ...this.interaction, string: [{ x: string[0][0], y: string[0][1] }, { x: string[1][0], y: string[1][1] }] };
8341
9459
  this.notify();
8342
9460
  }
@@ -8372,8 +9490,8 @@ var VectorEditorController = (_class3 = class {
8372
9490
  }
8373
9491
  this.setGuides(res);
8374
9492
  return {
8375
- dx: _optionalChain([res, 'optionalAccess', _247 => _247.x]) ? dx + res.dx : axes.x ? this.gridValue(origin.x + dx) - origin.x : dx,
8376
- dy: _optionalChain([res, 'optionalAccess', _248 => _248.y]) ? dy + res.dy : axes.y ? this.gridValue(origin.y + dy) - origin.y : dy
9493
+ dx: _optionalChain([res, 'optionalAccess', _285 => _285.x]) ? dx + res.dx : axes.x ? this.gridValue(origin.x + dx) - origin.x : dx,
9494
+ dy: _optionalChain([res, 'optionalAccess', _286 => _286.y]) ? dy + res.dy : axes.y ? this.gridValue(origin.y + dy) - origin.y : dy
8377
9495
  };
8378
9496
  }
8379
9497
  /** The anchor a point drag snaps by, where it started: the grabbed one, else the moving one nearest the press. */
@@ -8452,7 +9570,7 @@ var VectorEditorController = (_class3 = class {
8452
9570
  if (drag.moved) return this.commit("Corner Radius", drag.before);
8453
9571
  if (drag.alt) {
8454
9572
  const kind = nextVectorCornerKind(drag.widget.kind);
8455
- this.doc = this.updateAnchors(drag.base, drag.refs, (a) => setAnchorCorner(a, _nullishCoalesce(_optionalChain([a, 'access', _249 => _249.corner, 'optionalAccess', _250 => _250.radius]), () => ( 0)), kind));
9573
+ this.doc = this.updateAnchors(drag.base, drag.refs, (a) => setAnchorCorner(a, _nullishCoalesce(_optionalChain([a, 'access', _287 => _287.corner, 'optionalAccess', _288 => _288.radius]), () => ( 0)), kind));
8456
9574
  return this.commit("Corner Kind", drag.before);
8457
9575
  }
8458
9576
  const ref = drag.widget.ref;
@@ -8467,7 +9585,7 @@ var VectorEditorController = (_class3 = class {
8467
9585
  const several = drag.group.length > 0;
8468
9586
  if (drag.mode === "copy") this.widthPoints = [drag.ref];
8469
9587
  else if (drag.mode === "move" && several) {
8470
- this.widthPoints = [drag.source, ...drag.group].map((i) => ({ ...drag.ref, index: _nullishCoalesce(_optionalChain([drag, 'access', _251 => _251.renumber, 'optionalAccess', _252 => _252.get, 'call', _253 => _253(i)]), () => ( i)) }));
9588
+ this.widthPoints = [drag.source, ...drag.group].map((i) => ({ ...drag.ref, index: _nullishCoalesce(_optionalChain([drag, 'access', _289 => _289.renumber, 'optionalAccess', _290 => _290.get, 'call', _291 => _291(i)]), () => ( i)) }));
8471
9589
  } else if (!several) this.widthPoints = [drag.ref];
8472
9590
  const label = drag.mode === "copy" ? "Copy Width Point" : drag.mode === "move" ? several ? "Move Width Points" : "Move Width Point" : several ? "Width Points" : "Width Point";
8473
9591
  return this.commit(label, drag.before);
@@ -8509,14 +9627,14 @@ var VectorEditorController = (_class3 = class {
8509
9627
  }
8510
9628
  case "pencil": {
8511
9629
  const node = this.getNode(drag.nodeId);
8512
- if (_optionalChain([node, 'optionalAccess', _254 => _254.type]) !== "path" || drag.points.length < 2) {
9630
+ if (_optionalChain([node, 'optionalAccess', _292 => _292.type]) !== "path" || drag.points.length < 2) {
8513
9631
  this.doc = drag.before.doc;
8514
9632
  this.notify(true);
8515
9633
  return;
8516
9634
  }
8517
9635
  for (const q of drag.lazy.finish()) {
8518
9636
  drag.points.push(q);
8519
- _optionalChain([drag, 'access', _255 => _255.pressures, 'optionalAccess', _256 => _256.push, 'call', _257 => _257(drag.pressure)]);
9637
+ _optionalChain([drag, 'access', _293 => _293.pressures, 'optionalAccess', _294 => _294.push, 'call', _295 => _295(drag.pressure)]);
8520
9638
  }
8521
9639
  const shape = this.editing.recognizeShapes ? recognizeInkShape(drag.points, { minSize: 6 / this.viewport.zoom }) : null;
8522
9640
  if (shape) {
@@ -8591,7 +9709,7 @@ var VectorEditorController = (_class3 = class {
8591
9709
  this.convertAnchors(a.in || a.out ? "corner" : "smooth", [anchor]);
8592
9710
  return;
8593
9711
  }
8594
- const id = _nullishCoalesce(_optionalChain([this, 'access', _258 => _258.hover, 'optionalAccess', _259 => _259.segment, 'optionalAccess', _260 => _260.nodeId]), () => ( this.editingId));
9712
+ const id = _nullishCoalesce(_optionalChain([this, 'access', _296 => _296.hover, 'optionalAccess', _297 => _297.segment, 'optionalAccess', _298 => _298.nodeId]), () => ( this.editingId));
8595
9713
  if (id) {
8596
9714
  const node = this.getNode(id);
8597
9715
  const seg = node ? nearestSegment(node, this.toLocal(id, p)) : null;
@@ -8688,7 +9806,7 @@ var VectorEditorController = (_class3 = class {
8688
9806
  this.finishPath();
8689
9807
  return true;
8690
9808
  }
8691
- if (this.tool === "select" && this.selection.length === 1 && _optionalChain([this, 'access', _261 => _261.getNode, 'call', _262 => _262(this.selection[0]), 'optionalAccess', _263 => _263.type]) === "path") {
9809
+ if (this.tool === "select" && this.selection.length === 1 && _optionalChain([this, 'access', _299 => _299.getNode, 'call', _300 => _300(this.selection[0]), 'optionalAccess', _301 => _301.type]) === "path") {
8692
9810
  this.tool = "direct";
8693
9811
  this.editingId = this.selection[0];
8694
9812
  this.notify();
@@ -8734,7 +9852,7 @@ var VectorEditorController = (_class3 = class {
8734
9852
  this.notify();
8735
9853
  }
8736
9854
  }
8737
- }, _class3);
9855
+ }, _class5);
8738
9856
  function inkShapeLabel(shape) {
8739
9857
  const name = vectorInkShapeName(shape);
8740
9858
  return name[0].toUpperCase() + name.slice(1);
@@ -8809,8 +9927,9 @@ function pencilPressureProfile(points, pressures) {
8809
9927
  var fmt = (n) => Math.round(n * 100) / 100;
8810
9928
  var fmtMatrix = (m) => `matrix(${m.map((n) => Math.round(n * 1e6) / 1e6).join(" ")})`;
8811
9929
  var VECTOR_BUILDER_HATCH_GAP = 6;
8812
- function renderNode(node, defs, idPrefix) {
8813
- if (node.visible === false) return null;
9930
+ function renderNode(stored, defs, idPrefix) {
9931
+ if (stored.visible === false) return null;
9932
+ const node = expandVectorAppearance(stored);
8814
9933
  if (node.type === "group") {
8815
9934
  const children = node.children.map((c) => renderNode(c, defs, idPrefix)).filter((c) => !!c);
8816
9935
  return { kind: "group", id: node.id, ...node.transform ? { transform: fmtMatrix(node.transform) } : {}, opacity: _nullishCoalesce(node.opacity, () => ( 1)), children };
@@ -8831,7 +9950,7 @@ function renderNode(node, defs, idPrefix) {
8831
9950
  strokeWidth: _nullishCoalesce(node.strokeWidth, () => ( 1)),
8832
9951
  ...node.strokeLinecap ? { strokeLinecap: node.strokeLinecap } : {},
8833
9952
  ...node.strokeLinejoin ? { strokeLinejoin: node.strokeLinejoin } : {},
8834
- ..._optionalChain([node, 'access', _264 => _264.strokeDasharray, 'optionalAccess', _265 => _265.length]) ? { strokeDasharray: node.strokeDasharray.join(" ") } : {},
9953
+ ..._optionalChain([node, 'access', _302 => _302.strokeDasharray, 'optionalAccess', _303 => _303.length]) ? { strokeDasharray: node.strokeDasharray.join(" ") } : {},
8835
9954
  fillRule: _nullishCoalesce(node.fillRule, () => ( "nonzero")),
8836
9955
  opacity: _nullishCoalesce(node.opacity, () => ( 1))
8837
9956
  };
@@ -8851,16 +9970,20 @@ function getVectorSceneRenderData(state, options = {}) {
8851
9970
  };
8852
9971
  }
8853
9972
  var toScreen = (state, p) => ({ x: p.x * state.viewport.zoom + state.viewport.x, y: p.y * state.viewport.zoom + state.viewport.y });
8854
- function screenOutline(state, node) {
9973
+ function screenOutline(state, node, entered) {
8855
9974
  const v2 = state.viewport;
8856
9975
  const view = [v2.zoom, 0, 0, v2.zoom, v2.x, v2.y];
8857
9976
  const parent = _nullishCoalesce(vectorParentMatrix(state.document.nodes, node.id), () => ( IDENTITY_MATRIX));
8858
- return collectWithMatrix(node, parent).map(({ path, parent: m }) => _chunkVNYRI265cjs.bezierPathToSvg.call(void 0, _chunkVNYRI265cjs.transformBezierPath.call(void 0, vectorPathWorldBezier(path, m), view), { precision: 2 })).join(" ");
9977
+ return outlinePaths(node, parent, entered).map((path) => _chunkVNYRI265cjs.bezierPathToSvg.call(void 0, _chunkVNYRI265cjs.transformBezierPath.call(void 0, path, view), { precision: 2 })).join(" ");
8859
9978
  }
8860
- function collectWithMatrix(node, parent) {
8861
- if (node.type === "path") return [{ path: node, parent }];
9979
+ function outlinePaths(node, parent, entered) {
9980
+ if (node.type === "path") return [vectorPathWorldBezier(node, parent, { effects: false })];
8862
9981
  const m = multiplyMatrices(nodeMatrix(node), parent);
8863
- return node.children.flatMap((c) => collectWithMatrix(c, m));
9982
+ if (hasOwnVectorAppearance(node) && !entered.has(node.id)) return [_chunkVNYRI265cjs.transformBezierPath.call(void 0, vectorAppearanceOutline(node), m)];
9983
+ return node.children.filter((c) => c.visible !== false).flatMap((c) => outlinePaths(c, m, entered));
9984
+ }
9985
+ function getVectorEnteredGroups(state) {
9986
+ return vectorEnteredGroups(state.document.nodes, state.editingId ? [...state.selection, state.editingId] : state.selection);
8864
9987
  }
8865
9988
  function collect(node) {
8866
9989
  if (node.type === "path") return [node];
@@ -8870,19 +9993,20 @@ function getVectorOverlayRenderData(state) {
8870
9993
  const doc = state.document;
8871
9994
  const z = state.viewport.zoom;
8872
9995
  const outlines = [];
9996
+ const entered = getVectorEnteredGroups(state);
8873
9997
  const seen = /* @__PURE__ */ new Set();
8874
9998
  const outline = (id, selected2) => {
8875
9999
  if (seen.has(id)) return;
8876
10000
  const node = findVectorNode(doc.nodes, id);
8877
10001
  if (!node || node.visible === false) return;
8878
10002
  seen.add(id);
8879
- outlines.push({ id, d: screenOutline(state, node), selected: selected2 });
10003
+ outlines.push({ id, d: screenOutline(state, node, entered), selected: selected2 });
8880
10004
  };
8881
10005
  for (const id of state.selection) outline(id, true);
8882
10006
  if (state.editingId) outline(state.editingId, true);
8883
- if (_optionalChain([state, 'access', _266 => _266.hover, 'optionalAccess', _267 => _267.nodeId]) && !state.interaction) outline(state.hover.nodeId, false);
10007
+ if (_optionalChain([state, 'access', _304 => _304.hover, 'optionalAccess', _305 => _305.nodeId]) && !state.interaction) outline(state.hover.nodeId, false);
8884
10008
  let selectionBox = null;
8885
- if (state.tool === "select" && state.selectionFrame && _optionalChain([state, 'access', _268 => _268.interaction, 'optionalAccess', _269 => _269.type]) !== "marquee") {
10009
+ if (state.tool === "select" && state.selectionFrame && _optionalChain([state, 'access', _306 => _306.interaction, 'optionalAccess', _307 => _307.type]) !== "marquee") {
8886
10010
  const g = getVectorSelectionBoxGeometry(state.selectionFrame, state.viewport);
8887
10011
  selectionBox = { ...g.box, angle: g.angle, transform: g.transform, corners: g.corners, handles: g.handles };
8888
10012
  }
@@ -8892,9 +10016,9 @@ function getVectorOverlayRenderData(state) {
8892
10016
  const a = getAnchorWorld(doc, ref);
8893
10017
  const s = toScreen(state, a);
8894
10018
  const closes = !!state.pen && state.pen.nodeId === ref.nodeId && state.pen.subpath === ref.subpath && ref.index === 0;
8895
- return { ref, x: s.x, y: s.y, type: _nullishCoalesce(a.type, () => ( inferAnchorType(a))), selected: selected(ref), hovered: sameAnchor(_optionalChain([state, 'access', _270 => _270.hover, 'optionalAccess', _271 => _271.anchor]), ref), closes };
10019
+ return { ref, x: s.x, y: s.y, type: _nullishCoalesce(a.type, () => ( inferAnchorType(a))), selected: selected(ref), hovered: sameAnchor(_optionalChain([state, 'access', _308 => _308.hover, 'optionalAccess', _309 => _309.anchor]), ref), closes };
8896
10020
  });
8897
- if (state.tool === "pen" && !state.pen && _optionalChain([state, 'access', _272 => _272.hover, 'optionalAccess', _273 => _273.anchor])) {
10021
+ if (state.tool === "pen" && !state.pen && _optionalChain([state, 'access', _310 => _310.hover, 'optionalAccess', _311 => _311.anchor])) {
8898
10022
  const a = getAnchorWorld(doc, state.hover.anchor);
8899
10023
  if (a) {
8900
10024
  const s = toScreen(state, a);
@@ -8903,15 +10027,15 @@ function getVectorOverlayRenderData(state) {
8903
10027
  }
8904
10028
  const handles = getVisibleHandles(state).flatMap((ref) => {
8905
10029
  const a = getAnchorWorld(doc, ref);
8906
- const h = _optionalChain([a, 'optionalAccess', _274 => _274[ref.handle]]);
10030
+ const h = _optionalChain([a, 'optionalAccess', _312 => _312[ref.handle]]);
8907
10031
  if (!a || !h) return [];
8908
10032
  const s = toScreen(state, h);
8909
10033
  const sa = toScreen(state, a);
8910
- const hovered = !!_optionalChain([state, 'access', _275 => _275.hover, 'optionalAccess', _276 => _276.handle]) && sameAnchor(state.hover.handle, ref) && state.hover.handle.handle === ref.handle;
10034
+ const hovered = !!_optionalChain([state, 'access', _313 => _313.hover, 'optionalAccess', _314 => _314.handle]) && sameAnchor(state.hover.handle, ref) && state.hover.handle.handle === ref.handle;
8911
10035
  return [{ ref, x: s.x, y: s.y, anchorX: sa.x, anchorY: sa.y, hovered }];
8912
10036
  });
8913
10037
  let marquee = null;
8914
- if (_optionalChain([state, 'access', _277 => _277.interaction, 'optionalAccess', _278 => _278.type]) === "marquee") {
10038
+ if (_optionalChain([state, 'access', _315 => _315.interaction, 'optionalAccess', _316 => _316.type]) === "marquee") {
8915
10039
  const b = state.interaction.bounds;
8916
10040
  const tl = toScreen(state, b);
8917
10041
  marquee = { x: tl.x, y: tl.y, width: b.width * z, height: b.height * z };
@@ -8919,7 +10043,7 @@ function getVectorOverlayRenderData(state) {
8919
10043
  let penPreview = null;
8920
10044
  if (state.tool === "pen" && state.pen && state.pointer && !state.interaction) {
8921
10045
  const node = findVectorNode(doc.nodes, state.pen.nodeId);
8922
- const sp = _optionalChain([node, 'optionalAccess', _279 => _279.type]) === "path" ? node.subpaths[state.pen.subpath] : void 0;
10046
+ const sp = _optionalChain([node, 'optionalAccess', _317 => _317.type]) === "path" ? node.subpaths[state.pen.subpath] : void 0;
8923
10047
  const last = sp ? getAnchorWorld(doc, { nodeId: state.pen.nodeId, subpath: state.pen.subpath, index: sp.anchors.length - 1 }) : void 0;
8924
10048
  if (last) {
8925
10049
  const a = toScreen(state, last);
@@ -8932,9 +10056,9 @@ function getVectorOverlayRenderData(state) {
8932
10056
  const artboard = { x: origin.x, y: origin.y, width: doc.width * z, height: doc.height * z };
8933
10057
  let status = null;
8934
10058
  const it = state.interaction;
8935
- if (_optionalChain([it, 'optionalAccess', _280 => _280.type]) === "rotate") status = `${Math.round(it.angle)}\xB0`;
8936
- else if (_optionalChain([it, 'optionalAccess', _281 => _281.type]) === "move" || _optionalChain([it, 'optionalAccess', _282 => _282.type]) === "anchors") status = `\u0394 ${fmt(it.dx)}, ${fmt(it.dy)}`;
8937
- else if (_optionalChain([it, 'optionalAccess', _283 => _283.type]) === "scale" || _optionalChain([it, 'optionalAccess', _284 => _284.type]) === "draw") {
10059
+ if (_optionalChain([it, 'optionalAccess', _318 => _318.type]) === "rotate") status = `${Math.round(it.angle)}\xB0`;
10060
+ else if (_optionalChain([it, 'optionalAccess', _319 => _319.type]) === "move" || _optionalChain([it, 'optionalAccess', _320 => _320.type]) === "anchors") status = `\u0394 ${fmt(it.dx)}, ${fmt(it.dy)}`;
10061
+ else if (_optionalChain([it, 'optionalAccess', _321 => _321.type]) === "scale" || _optionalChain([it, 'optionalAccess', _322 => _322.type]) === "draw") {
8938
10062
  const b = it.type === "draw" ? findVectorNode(doc.nodes, it.nodeId) ? vectorNodeBounds(findVectorNode(doc.nodes, it.nodeId)) : null : state.selectionFrame;
8939
10063
  if (b) status = `W ${fmt(b.width)} \xD7 H ${fmt(b.height)}`;
8940
10064
  }
@@ -8951,24 +10075,24 @@ function getVectorOverlayRenderData(state) {
8951
10075
  }
8952
10076
  }
8953
10077
  let toolStroke = null;
8954
- if (_optionalChain([it, 'optionalAccess', _285 => _285.type]) === "stroke") {
10078
+ if (_optionalChain([it, 'optionalAccess', _323 => _323.type]) === "stroke") {
8955
10079
  const pts = it.points.map((q) => toScreen(state, q));
8956
10080
  const d = pts.map((q, i) => `${i ? "L" : "M"}${fmt(q.x)} ${fmt(q.y)}`).join("") + (pts.length === 1 ? `L${fmt(pts[0].x)} ${fmt(pts[0].y)}` : "");
8957
10081
  toolStroke = { tool: it.tool, d, width: fmt(it.width * z) };
8958
10082
  }
8959
10083
  let pencilString = null;
8960
- if (_optionalChain([it, 'optionalAccess', _286 => _286.type]) === "draw" && it.string) {
10084
+ if (_optionalChain([it, 'optionalAccess', _324 => _324.type]) === "draw" && it.string) {
8961
10085
  const a = toScreen(state, it.string[0]);
8962
10086
  const b = toScreen(state, it.string[1]);
8963
10087
  pencilString = { x1: fmt(a.x), y1: fmt(a.y), x2: fmt(b.x), y2: fmt(b.y) };
8964
10088
  }
8965
- const dragged = _optionalChain([it, 'optionalAccess', _287 => _287.type]) === "corner" ? it.ref : null;
10089
+ const dragged = _optionalChain([it, 'optionalAccess', _325 => _325.type]) === "corner" ? it.ref : null;
8966
10090
  const cornerWidgets = getVectorCornerWidgets(state).map((w) => {
8967
10091
  const s = toScreen(state, w);
8968
- return { ref: w.ref, x: fmt(s.x), y: fmt(s.y), radius: w.radius, kind: w.kind, hovered: sameAnchor(_optionalChain([state, 'access', _288 => _288.hover, 'optionalAccess', _289 => _289.corner]), w.ref), active: !!dragged };
10092
+ return { ref: w.ref, x: fmt(s.x), y: fmt(s.y), radius: w.radius, kind: w.kind, hovered: sameAnchor(_optionalChain([state, 'access', _326 => _326.hover, 'optionalAccess', _327 => _327.corner]), w.ref), active: !!dragged };
8969
10093
  });
8970
- if (_optionalChain([it, 'optionalAccess', _290 => _290.type]) === "corner") status = `R ${fmt(it.radius)}`;
8971
- const cutPoint = state.tool === "scissors" && _optionalChain([state, 'access', _291 => _291.hover, 'optionalAccess', _292 => _292.segment]) && !it ? (({ x, y }) => ({ x: fmt(x), y: fmt(y) }))(toScreen(state, state.hover.segment.point)) : null;
10094
+ if (_optionalChain([it, 'optionalAccess', _328 => _328.type]) === "corner") status = `R ${fmt(it.radius)}`;
10095
+ const cutPoint = state.tool === "scissors" && _optionalChain([state, 'access', _329 => _329.hover, 'optionalAccess', _330 => _330.segment]) && !it ? (({ x, y }) => ({ x: fmt(x), y: fmt(y) }))(toScreen(state, state.hover.segment.point)) : null;
8972
10096
  const sc = (p) => {
8973
10097
  const q = toScreen(state, p);
8974
10098
  return { x: fmt(q.x), y: fmt(q.y) };
@@ -8976,13 +10100,13 @@ function getVectorOverlayRenderData(state) {
8976
10100
  const sameWidth = (a, b) => !!a && a.nodeId === b.nodeId && a.index === b.index;
8977
10101
  const widthPoints = getVectorWidthHandles(state).map((h) => {
8978
10102
  const c = sc(h);
8979
- const hw = _optionalChain([state, 'access', _293 => _293.hover, 'optionalAccess', _294 => _294.widthPoint]);
10103
+ const hw = _optionalChain([state, 'access', _331 => _331.hover, 'optionalAccess', _332 => _332.widthPoint]);
8980
10104
  const hovered = hw && sameWidth(hw, h.ref) && hw.subpath === h.ref.subpath ? hw.part : null;
8981
- return { ref: h.ref, x: c.x, y: c.y, left: sc(h.left), right: sc(h.right), selected: h.selected, hovered, active: _optionalChain([it, 'optionalAccess', _295 => _295.type]) === "width" && sameWidth(it.ref, h.ref) };
10105
+ return { ref: h.ref, x: c.x, y: c.y, left: sc(h.left), right: sc(h.right), selected: h.selected, hovered, active: _optionalChain([it, 'optionalAccess', _333 => _333.type]) === "width" && sameWidth(it.ref, h.ref) };
8982
10106
  });
8983
- const spot = state.tool === "width" && !it ? _optionalChain([state, 'access', _296 => _296.hover, 'optionalAccess', _297 => _297.strokeSpot]) : null;
10107
+ const spot = state.tool === "width" && !it ? _optionalChain([state, 'access', _334 => _334.hover, 'optionalAccess', _335 => _335.strokeSpot]) : null;
8984
10108
  const widthSpot = spot ? { ...sc(spot.point), left: sc(spot.left), right: sc(spot.right) } : null;
8985
- if (_optionalChain([it, 'optionalAccess', _298 => _298.type]) === "width") status = it.mode === "move" ? "Move width point" : it.mode === "copy" ? "Copy width point" : `W ${fmt(it.width)}`;
10109
+ if (_optionalChain([it, 'optionalAccess', _336 => _336.type]) === "width") status = it.mode === "move" ? "Move width point" : it.mode === "copy" ? "Copy width point" : `W ${fmt(it.width)}`;
8986
10110
  let builder = null;
8987
10111
  if (state.builder) {
8988
10112
  const v2 = state.viewport;
@@ -8998,7 +10122,7 @@ function getVectorOverlayRenderData(state) {
8998
10122
  lines: state.builder.lines.map((l) => svg(_chunkVNYRI265cjs.transformBezierPath.call(void 0, l, view))),
8999
10123
  trail
9000
10124
  };
9001
- if (state.builder.mode !== "fill" && _optionalChain([it, 'optionalAccess', _299 => _299.type]) === "builder") {
10125
+ if (state.builder.mode !== "fill" && _optionalChain([it, 'optionalAccess', _337 => _337.type]) === "builder") {
9002
10126
  const n = state.builder.faces.length;
9003
10127
  status = state.builder.mode === "erase" ? `Delete ${n} ${n === 1 ? "face" : "faces"}` : `Merge ${n} ${n === 1 ? "face" : "faces"}`;
9004
10128
  }
@@ -9011,7 +10135,7 @@ function selectedBlends(state) {
9011
10135
  const out = /* @__PURE__ */ new Map();
9012
10136
  for (const id of state.selection) {
9013
10137
  const node = findVectorNode(state.document.nodes, id);
9014
- const group = isVectorBlendGroup(node) ? node : _optionalChain([locateVectorNode, 'call', _300 => _300(state.document.nodes, id), 'optionalAccess', _301 => _301.parent]);
10138
+ const group = isVectorBlendGroup(node) ? node : _optionalChain([locateVectorNode, 'call', _338 => _338(state.document.nodes, id), 'optionalAccess', _339 => _339.parent]);
9015
10139
  if (isVectorBlendGroup(group)) out.set(group.id, group);
9016
10140
  }
9017
10141
  return [...out.values()];
@@ -9041,13 +10165,13 @@ function blendOverlay(state) {
9041
10165
  const from = state.blendStart ? findVectorNode(doc.nodes, state.blendStart.nodeId) : void 0;
9042
10166
  if (from && state.blendStart) {
9043
10167
  const a = state.blendStart.anchor === null ? void 0 : getAnchorWorld(doc, { nodeId: from.id, subpath: 0, index: state.blendStart.anchor });
9044
- start = { d: screenOutline(state, from), anchor: a ? sc(a, view) : null };
10168
+ start = { d: screenOutline(state, from, /* @__PURE__ */ new Set()), anchor: a ? sc(a, view) : null };
9045
10169
  }
9046
- const hovered = _optionalChain([state, 'access', _302 => _302.hover, 'optionalAccess', _303 => _303.nodeId]) ? findVectorNode(doc.nodes, state.hover.nodeId) : void 0;
9047
- if (_optionalChain([hovered, 'optionalAccess', _304 => _304.type]) === "path" && hovered.subpaths[0]) {
10170
+ const hovered = _optionalChain([state, 'access', _340 => _340.hover, 'optionalAccess', _341 => _341.nodeId]) ? findVectorNode(doc.nodes, state.hover.nodeId) : void 0;
10171
+ if (_optionalChain([hovered, 'optionalAccess', _342 => _342.type]) === "path" && hovered.subpaths[0]) {
9048
10172
  hovered.subpaths[0].anchors.forEach((_, index) => {
9049
10173
  const a = getAnchorWorld(doc, { nodeId: hovered.id, subpath: 0, index });
9050
- if (a) anchors.push({ ...sc(a, view), hovered: _optionalChain([state, 'access', _305 => _305.hover, 'optionalAccess', _306 => _306.anchor, 'optionalAccess', _307 => _307.index]) === index });
10174
+ if (a) anchors.push({ ...sc(a, view), hovered: _optionalChain([state, 'access', _343 => _343.hover, 'optionalAccess', _344 => _344.anchor, 'optionalAccess', _345 => _345.index]) === index });
9051
10175
  });
9052
10176
  }
9053
10177
  }
@@ -9058,17 +10182,17 @@ function getVectorBlendControls(state) {
9058
10182
  const doc = state.document;
9059
10183
  const roots = state.selection.filter((id) => {
9060
10184
  const node = findVectorNode(doc.nodes, id);
9061
- return !!node && !node.blendStep && !node.locked && !state.selection.includes(_nullishCoalesce(_optionalChain([locateVectorNode, 'call', _308 => _308(doc.nodes, id), 'optionalAccess', _309 => _309.parent, 'optionalAccess', _310 => _310.id]), () => ( "")));
10185
+ return !!node && !node.blendStep && !node.locked && !state.selection.includes(_nullishCoalesce(_optionalChain([locateVectorNode, 'call', _346 => _346(doc.nodes, id), 'optionalAccess', _347 => _347.parent, 'optionalAccess', _348 => _348.id]), () => ( "")));
9062
10186
  });
9063
- const parents = new Set(roots.map((id) => _nullishCoalesce(_optionalChain([locateVectorNode, 'call', _311 => _311(doc.nodes, id), 'optionalAccess', _312 => _312.parent, 'optionalAccess', _313 => _313.id]), () => ( null))));
9064
- const paths = roots.filter((id) => _optionalChain([findVectorNode, 'call', _314 => _314(doc.nodes, id), 'optionalAccess', _315 => _315.type]) === "path" && !isVectorBlendGroup(_optionalChain([locateVectorNode, 'call', _316 => _316(doc.nodes, id), 'optionalAccess', _317 => _317.parent])));
10187
+ const parents = new Set(roots.map((id) => _nullishCoalesce(_optionalChain([locateVectorNode, 'call', _349 => _349(doc.nodes, id), 'optionalAccess', _350 => _350.parent, 'optionalAccess', _351 => _351.id]), () => ( null))));
10188
+ const paths = roots.filter((id) => _optionalChain([findVectorNode, 'call', _352 => _352(doc.nodes, id), 'optionalAccess', _353 => _353.type]) === "path" && !isVectorBlendGroup(_optionalChain([locateVectorNode, 'call', _354 => _354(doc.nodes, id), 'optionalAccess', _355 => _355.parent])));
9065
10189
  const first = blends[0];
9066
10190
  return {
9067
10191
  ids: blends.map((g) => g.id),
9068
10192
  options: resolveVectorBlendOptions(first ? first.blend : state.blendDefaults),
9069
10193
  canBlend: roots.length >= 2 && parents.size === 1,
9070
10194
  canReplaceSpine: blends.length === 1 && paths.length === 1,
9071
- hasSpine: !!_optionalChain([first, 'optionalAccess', _318 => _318.blend, 'optionalAccess', _319 => _319.spine])
10195
+ hasSpine: !!_optionalChain([first, 'optionalAccess', _356 => _356.blend, 'optionalAccess', _357 => _357.spine])
9072
10196
  };
9073
10197
  }
9074
10198
  function applyVectorBlendOptions(controller, patch) {
@@ -9121,7 +10245,7 @@ function isVectorTextTarget(target) {
9121
10245
  if (!el || typeof el !== "object") return false;
9122
10246
  const tag = (_nullishCoalesce(el.tagName, () => ( ""))).toUpperCase();
9123
10247
  if (tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT") return true;
9124
- return !!el.isContentEditable || _optionalChain([el, 'access', _320 => _320.getAttribute, 'optionalCall', _321 => _321("contenteditable")]) === "true";
10248
+ return !!el.isContentEditable || _optionalChain([el, 'access', _358 => _358.getAttribute, 'optionalCall', _359 => _359("contenteditable")]) === "true";
9125
10249
  }
9126
10250
  function getVectorSelectionStyle(state) {
9127
10251
  const paths = [];
@@ -9129,12 +10253,12 @@ function getVectorSelectionStyle(state) {
9129
10253
  const node = findVectorNode(state.document.nodes, id);
9130
10254
  if (node) paths.push(...collect(node));
9131
10255
  }
9132
- const anchorMode = state.tool === "direct" && !!_optionalChain([state, 'access', _322 => _322.selectedAnchors, 'optionalAccess', _323 => _323.length]);
10256
+ const anchorMode = state.tool === "direct" && !!_optionalChain([state, 'access', _360 => _360.selectedAnchors, 'optionalAccess', _361 => _361.length]);
9133
10257
  if (anchorMode) {
9134
10258
  for (const r of state.selectedAnchors) {
9135
10259
  if (paths.some((p) => p.id === r.nodeId)) continue;
9136
10260
  const node = findVectorNode(state.document.nodes, r.nodeId);
9137
- if (_optionalChain([node, 'optionalAccess', _324 => _324.type]) === "path") paths.push(node);
10261
+ if (_optionalChain([node, 'optionalAccess', _362 => _362.type]) === "path") paths.push(node);
9138
10262
  }
9139
10263
  }
9140
10264
  if (!paths.length) return null;
@@ -9145,7 +10269,7 @@ function getVectorSelectionStyle(state) {
9145
10269
  for (const c of vectorCorners(p.subpaths)) {
9146
10270
  if (anchorMode && !state.selectedAnchors.some((r) => r.nodeId === p.id && r.subpath === c.subpath && r.index === c.index)) continue;
9147
10271
  const corner = p.subpaths[c.subpath].anchors[c.index].corner;
9148
- corners2.push({ radius: _nullishCoalesce(_optionalChain([corner, 'optionalAccess', _325 => _325.radius]), () => ( 0)), kind: _nullishCoalesce(_optionalChain([corner, 'optionalAccess', _326 => _326.kind]), () => ( "round")) });
10272
+ corners2.push({ radius: _nullishCoalesce(_optionalChain([corner, 'optionalAccess', _363 => _363.radius]), () => ( 0)), kind: _nullishCoalesce(_optionalChain([corner, 'optionalAccess', _364 => _364.kind]), () => ( "round")) });
9149
10273
  }
9150
10274
  }
9151
10275
  const c0 = _nullishCoalesce(corners2[0], () => ( { radius: 0, kind: "round" }));
@@ -9226,8 +10350,28 @@ var VECTOR_EDIT_TOGGLES = [
9226
10350
  { key: "curvatureMoves", label: "Curv", title: "Curvature point moves (Alt flips while dragging)" },
9227
10351
  { key: "recognizeShapes", label: "Shapes", title: "Turn pencil scribbles into shapes" }
9228
10352
  ];
10353
+ var VECTOR_EFFECT_MENU = VECTOR_EFFECT_TYPES.map((type) => ({ type, label: VECTOR_EFFECT_LABELS[type] }));
10354
+ function getVectorEffectsPanel(state) {
10355
+ const nodes = state.selection.map((id) => findVectorNode(state.document.nodes, id)).filter((n) => !!n && !n.blendStep);
10356
+ if (!nodes.length) return null;
10357
+ const one = nodes.length === 1 ? nodes[0] : null;
10358
+ return {
10359
+ nodeId: _nullishCoalesce(_optionalChain([one, 'optionalAccess', _365 => _365.id]), () => ( null)),
10360
+ count: nodes.length,
10361
+ effects: (_nullishCoalesce(_optionalChain([one, 'optionalAccess', _366 => _366.effects]), () => ( []))).map((e) => ({
10362
+ id: e.id,
10363
+ type: e.type,
10364
+ label: _nullishCoalesce(VECTOR_EFFECT_LABELS[e.type], () => ( e.type)),
10365
+ enabled: e.enabled !== false,
10366
+ params: e.params,
10367
+ specs: _nullishCoalesce(VECTOR_EFFECT_PARAM_SPECS[e.type], () => ( []))
10368
+ })),
10369
+ expandable: nodes.some(hasVectorAppearance)
10370
+ };
10371
+ }
9229
10372
 
9230
10373
  // src/vector/commands.ts
10374
+ var EFFECT_PARAMS_DESCRIPTION = "Effect parameters (missing ones keep their value or default). trim: start, end (percent), offset (degrees), mode simultaneous|individual. roundCorners: radius. puckerBloat: amount (\u2212100\u2026100). twist: angle, center {x, y} (offset from the middle). zigzag: size, ridges, smooth. wiggle: size, detail, smooth, speed, correlation, phase, seed, time (seconds). offset: amount, join miter|round|bevel, miterLimit, copies, copyOffset. merge: mode merge|add|subtract|intersect|exclude. repeater: copies (fractions fade the last), offset, position {x, y}, anchor {x, y} (offset from the middle), rotation, scale {x, y} (percent), startOpacity, endOpacity (percent), composite below|above.";
9231
10375
  var fail = (message) => {
9232
10376
  throw new Error(message);
9233
10377
  };
@@ -9268,9 +10412,9 @@ var BLEND_PROPS = {
9268
10412
  linear: { type: "boolean", description: "Move anchors in straight lines instead of the rotation-aware morph." }
9269
10413
  };
9270
10414
  var checkBlendOptions = (params) => {
9271
- if (_optionalChain([params, 'optionalAccess', _327 => _327.spacing]) !== void 0 && !VECTOR_BLEND_SPACINGS.includes(params.spacing)) fail(`Unknown blend spacing "${params.spacing}".`);
9272
- if (_optionalChain([params, 'optionalAccess', _328 => _328.steps]) !== void 0 && !(Number.isFinite(params.steps) && params.steps >= 1)) fail("steps must be at least 1.");
9273
- if (_optionalChain([params, 'optionalAccess', _329 => _329.distance]) !== void 0 && !(Number.isFinite(params.distance) && params.distance > 0)) fail("distance must be positive.");
10415
+ if (_optionalChain([params, 'optionalAccess', _367 => _367.spacing]) !== void 0 && !VECTOR_BLEND_SPACINGS.includes(params.spacing)) fail(`Unknown blend spacing "${params.spacing}".`);
10416
+ if (_optionalChain([params, 'optionalAccess', _368 => _368.steps]) !== void 0 && !(Number.isFinite(params.steps) && params.steps >= 1)) fail("steps must be at least 1.");
10417
+ if (_optionalChain([params, 'optionalAccess', _369 => _369.distance]) !== void 0 && !(Number.isFinite(params.distance) && params.distance > 0)) fail("distance must be positive.");
9274
10418
  };
9275
10419
  var PAINT = {
9276
10420
  description: 'A CSS colour, `null` for none, or a gradient `{ type: "linear", angle, stops: [{ offset, color }] }`.'
@@ -9305,17 +10449,17 @@ function createVectorCommands(controller, options = {}) {
9305
10449
  const base = { group, ...options.scope ? { scope: options.scope } : {} };
9306
10450
  const hasSelection = () => controller.getState().selection.length ? true : "Nothing is selected.";
9307
10451
  const ids = (params) => {
9308
- const list2 = _nullishCoalesce(_optionalChain([params, 'optionalAccess', _330 => _330.ids]), () => ( controller.getState().selection));
10452
+ const list2 = _nullishCoalesce(_optionalChain([params, 'optionalAccess', _370 => _370.ids]), () => ( controller.getState().selection));
9309
10453
  for (const id of list2) if (!controller.getNode(id)) fail(`There is no node "${id}".`);
9310
10454
  if (!list2.length) fail("Nothing is selected; pass ids.");
9311
10455
  return list2;
9312
10456
  };
9313
- const enabledFor = (_, params) => _optionalChain([params, 'optionalAccess', _331 => _331.ids, 'optionalAccess', _332 => _332.length]) ? true : hasSelection();
10457
+ const enabledFor = (_, params) => _optionalChain([params, 'optionalAccess', _371 => _371.ids, 'optionalAccess', _372 => _372.length]) ? true : hasSelection();
9314
10458
  const anchorsOf = (refs) => {
9315
10459
  if (!refs) return [...controller.getState().selectedAnchors];
9316
10460
  for (const r of refs) {
9317
10461
  const node = controller.getNode(r.nodeId);
9318
- if (_optionalChain([node, 'optionalAccess', _333 => _333.type]) !== "path" || !_optionalChain([node, 'access', _334 => _334.subpaths, 'access', _335 => _335[r.subpath], 'optionalAccess', _336 => _336.anchors, 'access', _337 => _337[r.index]])) fail(`There is no anchor ${r.index} on subpath ${r.subpath} of "${r.nodeId}".`);
10462
+ if (_optionalChain([node, 'optionalAccess', _373 => _373.type]) !== "path" || !_optionalChain([node, 'access', _374 => _374.subpaths, 'access', _375 => _375[r.subpath], 'optionalAccess', _376 => _376.anchors, 'access', _377 => _377[r.index]])) fail(`There is no anchor ${r.index} on subpath ${r.subpath} of "${r.nodeId}".`);
9319
10463
  }
9320
10464
  return refs;
9321
10465
  };
@@ -9338,7 +10482,10 @@ function createVectorCommands(controller, options = {}) {
9338
10482
  selected: state.selection.includes(n.id),
9339
10483
  ...n.type === "path" ? { fill: _nullishCoalesce(n.fill, () => ( null)), stroke: _nullishCoalesce(n.stroke, () => ( null)), strokeWidth: _nullishCoalesce(n.strokeWidth, () => ( 1)), d: vectorPathData(n, 2) } : { children: n.children.length },
9340
10484
  ...n.type === "group" && n.blend ? { blend: { ...resolveVectorBlendOptions(n.blend), spine: !!n.blend.spine, keys: vectorBlendKeys(n).map((k) => k.id) } } : {},
9341
- ...n.blendStep ? { blendStep: true } : {}
10485
+ ...n.blendStep ? { blendStep: true } : {},
10486
+ ..._optionalChain([n, 'access', _378 => _378.effects, 'optionalAccess', _379 => _379.length]) ? { effects: n.effects } : {},
10487
+ ...n.type === "group" && n.liveBoolean ? { liveBoolean: n.liveBoolean } : {},
10488
+ ...n.booleanOperation ? { booleanOperation: n.booleanOperation } : {}
9342
10489
  });
9343
10490
  if (n.type === "group") visit(n.children, depth + 1);
9344
10491
  }
@@ -9408,7 +10555,7 @@ function createVectorCommands(controller, options = {}) {
9408
10555
  run: (_ctx, params) => {
9409
10556
  const id = controller.addPath(params.d, { ...pickStyle(params), ...params.name ? { name: params.name } : {} });
9410
10557
  const node = controller.getNode(id);
9411
- if (_optionalChain([node, 'optionalAccess', _338 => _338.type]) === "path" && !node.subpaths.length) {
10558
+ if (_optionalChain([node, 'optionalAccess', _380 => _380.type]) === "path" && !node.subpaths.length) {
9412
10559
  controller.undo();
9413
10560
  fail("The path data has no points.");
9414
10561
  }
@@ -9440,10 +10587,10 @@ function createVectorCommands(controller, options = {}) {
9440
10587
  params: { type: "object", properties: { radius: { type: "number", minimum: 0 }, kind: { type: "string", enum: VECTOR_CORNER_KINDS }, ids: IDS, anchors: ANCHORS } },
9441
10588
  undoable: true,
9442
10589
  run: (_ctx, params) => {
9443
- const refs = _optionalChain([params, 'optionalAccess', _339 => _339.anchors]) ? anchorsOf(params.anchors) : void 0;
9444
- const target = { refs, ids: _optionalChain([params, 'optionalAccess', _340 => _340.ids]) ? ids(params) : void 0 };
9445
- if (_optionalChain([params, 'optionalAccess', _341 => _341.radius]) !== void 0) check(controller.setCornerRadius(params.radius, { ...target, kind: params.kind }));
9446
- else if (_optionalChain([params, 'optionalAccess', _342 => _342.kind])) check(controller.setCornerKind(params.kind, target));
10590
+ const refs = _optionalChain([params, 'optionalAccess', _381 => _381.anchors]) ? anchorsOf(params.anchors) : void 0;
10591
+ const target = { refs, ids: _optionalChain([params, 'optionalAccess', _382 => _382.ids]) ? ids(params) : void 0 };
10592
+ if (_optionalChain([params, 'optionalAccess', _383 => _383.radius]) !== void 0) check(controller.setCornerRadius(params.radius, { ...target, kind: params.kind }));
10593
+ else if (_optionalChain([params, 'optionalAccess', _384 => _384.kind])) check(controller.setCornerKind(params.kind, target));
9447
10594
  else fail("Pass `radius` and / or `kind`.");
9448
10595
  return { ok: true };
9449
10596
  }
@@ -9478,12 +10625,12 @@ function createVectorCommands(controller, options = {}) {
9478
10625
  undoable: true,
9479
10626
  run: (_ctx, params) => {
9480
10627
  const target = { ids: ids(params) };
9481
- if (_optionalChain([params, 'optionalAccess', _343 => _343.preset])) check(controller.setWidthProfile(params.preset, target));
9482
- else if (_optionalChain([params, 'optionalAccess', _344 => _344.points]) !== void 0) check(controller.setWidthProfile(_nullishCoalesce(params.points, () => ( null)), target));
9483
- else if (_optionalChain([params, 'optionalAccess', _345 => _345.taper]) || _optionalChain([params, 'optionalAccess', _346 => _346.wave])) check(controller.setWidthProfile({ taper: params.taper, wave: params.wave }, target));
10628
+ if (_optionalChain([params, 'optionalAccess', _385 => _385.preset])) check(controller.setWidthProfile(params.preset, target));
10629
+ else if (_optionalChain([params, 'optionalAccess', _386 => _386.points]) !== void 0) check(controller.setWidthProfile(_nullishCoalesce(params.points, () => ( null)), target));
10630
+ else if (_optionalChain([params, 'optionalAccess', _387 => _387.taper]) || _optionalChain([params, 'optionalAccess', _388 => _388.wave])) check(controller.setWidthProfile({ taper: params.taper, wave: params.wave }, target));
9484
10631
  else fail("Pass `preset`, `points`, `taper` or `wave`.");
9485
10632
  const node = controller.getNode(target.ids[0]);
9486
- return { ok: true, points: _optionalChain([node, 'optionalAccess', _347 => _347.type]) === "path" ? _nullishCoalesce(node.strokeWidthProfile, () => ( [])) : [] };
10633
+ return { ok: true, points: _optionalChain([node, 'optionalAccess', _389 => _389.type]) === "path" ? _nullishCoalesce(node.strokeWidthProfile, () => ( [])) : [] };
9487
10634
  }
9488
10635
  },
9489
10636
  {
@@ -9505,10 +10652,10 @@ function createVectorCommands(controller, options = {}) {
9505
10652
  },
9506
10653
  undoable: true,
9507
10654
  run: (_ctx, params) => {
9508
- if (!_optionalChain([params, 'optionalAccess', _348 => _348.id])) fail("Pass the path `id`.");
10655
+ if (!_optionalChain([params, 'optionalAccess', _390 => _390.id])) fail("Pass the path `id`.");
9509
10656
  check(controller.setWidthPoint({ nodeId: params.id, index: _nullishCoalesce(params.index, () => ( null)) }, { t: params.t, left: params.left, right: params.right }));
9510
10657
  const node = controller.getNode(params.id);
9511
- return { ok: true, points: _optionalChain([node, 'optionalAccess', _349 => _349.type]) === "path" ? _nullishCoalesce(node.strokeWidthProfile, () => ( [])) : [] };
10658
+ return { ok: true, points: _optionalChain([node, 'optionalAccess', _391 => _391.type]) === "path" ? _nullishCoalesce(node.strokeWidthProfile, () => ( [])) : [] };
9512
10659
  }
9513
10660
  },
9514
10661
  {
@@ -9521,7 +10668,7 @@ function createVectorCommands(controller, options = {}) {
9521
10668
  enabled: enabledFor,
9522
10669
  undoable: true,
9523
10670
  run: (_ctx, params) => {
9524
- const created = controller.outlineStroke({ ids: _optionalChain([params, 'optionalAccess', _350 => _350.ids]) ? ids(params) : void 0 });
10671
+ const created = controller.outlineStroke({ ids: _optionalChain([params, 'optionalAccess', _392 => _392.ids]) ? ids(params) : void 0 });
9525
10672
  if (!created.length) fail("No selected path has a stroke.");
9526
10673
  return { ids: created };
9527
10674
  }
@@ -9574,15 +10721,101 @@ function createVectorCommands(controller, options = {}) {
9574
10721
  id: `${prefix}boolean`,
9575
10722
  label: "Boolean Operation\u2026",
9576
10723
  keywords: ["union", "unite", "subtract", "intersect", "exclude", "combine", "pathfinder"],
9577
- description: "Combines two or more paths with union, subtract (upper shapes from the lowest), intersect or exclude.",
9578
- params: { type: "object", properties: { operation: { type: "string", enum: ["union", "subtract", "intersect", "exclude"] }, ids: IDS }, required: ["operation"] },
10724
+ description: "Combines two or more paths with union, subtract (upper shapes from the lowest), intersect or exclude. With `live`, the shapes stay editable operands of a live boolean group instead (a lone live group gets the operation; its operands get their own).",
10725
+ params: {
10726
+ type: "object",
10727
+ properties: {
10728
+ operation: { type: "string", enum: ["union", "subtract", "intersect", "exclude"] },
10729
+ ids: IDS,
10730
+ live: { type: "boolean", description: "Keep the operands editable in a live boolean group (default false: one new path)." }
10731
+ },
10732
+ required: ["operation"]
10733
+ },
9579
10734
  undoable: true,
9580
10735
  run: (_ctx, params) => {
9581
- const id = controller.booleanOp(params.operation, { ids: ids(params) });
9582
- if (!id) fail("Select at least two overlapping paths (the result was empty).");
10736
+ const id = controller.booleanOp(params.operation, { ids: ids(params), live: params.live });
10737
+ if (!id) fail(params.live ? "Select two or more nodes with one parent, a live boolean group or its operands." : "Select at least two overlapping paths (the result was empty).");
9583
10738
  return { id };
9584
10739
  }
9585
10740
  },
10741
+ {
10742
+ ...base,
10743
+ id: `${prefix}addEffect`,
10744
+ label: "Add Path Effect\u2026",
10745
+ keywords: ["effect", "trim", "round corners", "pucker", "bloat", "twist", "zig zag", "wiggle", "offset", "merge", "repeater", "appearance", "live"],
10746
+ description: "Adds a live path effect to the bottom of the effect stack of nodes (paths or groups). Effects apply top to bottom; effects after a repeater act on its copies. Returns the new effect ids.",
10747
+ params: {
10748
+ type: "object",
10749
+ properties: {
10750
+ type: { type: "string", enum: VECTOR_EFFECT_TYPES },
10751
+ params: { type: "object", description: EFFECT_PARAMS_DESCRIPTION },
10752
+ index: { type: "integer", minimum: 0, description: "Position in the stack (default: last)." },
10753
+ ids: IDS
10754
+ },
10755
+ required: ["type"]
10756
+ },
10757
+ undoable: true,
10758
+ enabled: enabledFor,
10759
+ run: (_ctx, params) => {
10760
+ if (!VECTOR_EFFECT_TYPES.includes(params.type)) fail(`Unknown effect type "${params.type}".`);
10761
+ const targets = ids(params);
10762
+ const created = controller.addEffect(params.type, { ids: targets, params: params.params, index: params.index });
10763
+ if (!created.length) fail("Nothing to add the effect to.");
10764
+ return { effects: targets.map((id, i) => ({ nodeId: id, effectId: created[i] })) };
10765
+ }
10766
+ },
10767
+ {
10768
+ ...base,
10769
+ id: `${prefix}updateEffect`,
10770
+ label: "Edit Path Effect\u2026",
10771
+ keywords: ["effect", "parameters", "enable", "disable", "reorder"],
10772
+ description: "Changes a path effect: its parameters, whether it is enabled, and its position in the stack.",
10773
+ params: {
10774
+ type: "object",
10775
+ properties: {
10776
+ nodeId: { type: "string" },
10777
+ effectId: { type: "string" },
10778
+ params: { type: "object", description: EFFECT_PARAMS_DESCRIPTION },
10779
+ enabled: { type: "boolean" },
10780
+ index: { type: "integer", minimum: 0, description: "Move it to this position in the stack (0 applies first)." }
10781
+ },
10782
+ required: ["nodeId", "effectId"]
10783
+ },
10784
+ undoable: true,
10785
+ run: (_ctx, params) => {
10786
+ if (params.params !== void 0 || params.enabled !== void 0) check(controller.updateEffect(params.nodeId, params.effectId, { params: params.params, enabled: params.enabled }));
10787
+ if (params.index !== void 0) check(controller.moveEffect(params.nodeId, params.effectId, params.index));
10788
+ return { effects: _nullishCoalesce(_optionalChain([controller, 'access', _393 => _393.getNode, 'call', _394 => _394(params.nodeId), 'optionalAccess', _395 => _395.effects]), () => ( [])) };
10789
+ }
10790
+ },
10791
+ {
10792
+ ...base,
10793
+ id: `${prefix}removeEffect`,
10794
+ label: "Remove Path Effect",
10795
+ keywords: ["effect", "delete"],
10796
+ description: "Removes a path effect from a node.",
10797
+ params: { type: "object", properties: { nodeId: { type: "string" }, effectId: { type: "string" } }, required: ["nodeId", "effectId"] },
10798
+ undoable: true,
10799
+ run: (_ctx, params) => {
10800
+ check(controller.removeEffect(params.nodeId, params.effectId));
10801
+ return { ok: true };
10802
+ }
10803
+ },
10804
+ {
10805
+ ...base,
10806
+ id: `${prefix}expandAppearance`,
10807
+ label: "Expand Appearance",
10808
+ keywords: ["effects", "bake", "flatten", "live boolean", "expand"],
10809
+ description: "Bakes the path effects and live booleans of nodes (and everything inside them) into plain paths.",
10810
+ params: { type: "object", properties: { ids: IDS } },
10811
+ undoable: true,
10812
+ enabled: enabledFor,
10813
+ run: (_ctx, params) => {
10814
+ const expanded = controller.expandAppearance({ ids: ids(params) });
10815
+ if (!expanded.length) fail("Nothing selected has path effects or a live boolean.");
10816
+ return { ids: expanded };
10817
+ }
10818
+ },
9586
10819
  {
9587
10820
  ...base,
9588
10821
  id: `${prefix}blend`,
@@ -9616,7 +10849,7 @@ function createVectorCommands(controller, options = {}) {
9616
10849
  undoable: true,
9617
10850
  run: (_ctx, params) => {
9618
10851
  checkBlendOptions(params);
9619
- const r = controller.setBlendOptions(_nullishCoalesce(params, () => ( {})), { ids: _optionalChain([params, 'optionalAccess', _351 => _351.ids]) });
10852
+ const r = controller.setBlendOptions(_nullishCoalesce(params, () => ( {})), { ids: _optionalChain([params, 'optionalAccess', _396 => _396.ids]) });
9620
10853
  if (!r.ok) fail(r.message);
9621
10854
  return { ok: true };
9622
10855
  }
@@ -9630,7 +10863,7 @@ function createVectorCommands(controller, options = {}) {
9630
10863
  params: { type: "object", properties: { ids: IDS } },
9631
10864
  undoable: true,
9632
10865
  run: (_ctx, params) => {
9633
- const groups = controller.expandBlend({ ids: _optionalChain([params, 'optionalAccess', _352 => _352.ids]) });
10866
+ const groups = controller.expandBlend({ ids: _optionalChain([params, 'optionalAccess', _397 => _397.ids]) });
9634
10867
  if (!groups.length) fail("Select a blend to expand.");
9635
10868
  return { ids: groups };
9636
10869
  }
@@ -9644,7 +10877,7 @@ function createVectorCommands(controller, options = {}) {
9644
10877
  params: { type: "object", properties: { ids: IDS } },
9645
10878
  undoable: true,
9646
10879
  run: (_ctx, params) => {
9647
- const released = controller.releaseBlend({ ids: _optionalChain([params, 'optionalAccess', _353 => _353.ids]) });
10880
+ const released = controller.releaseBlend({ ids: _optionalChain([params, 'optionalAccess', _398 => _398.ids]) });
9648
10881
  if (!released.length) fail("Select a blend to release.");
9649
10882
  return { ids: released };
9650
10883
  }
@@ -9658,7 +10891,7 @@ function createVectorCommands(controller, options = {}) {
9658
10891
  params: { type: "object", properties: { ids: IDS } },
9659
10892
  undoable: true,
9660
10893
  run: (_ctx, params) => {
9661
- const r = controller.replaceBlendSpine({ ids: _optionalChain([params, 'optionalAccess', _354 => _354.ids]) });
10894
+ const r = controller.replaceBlendSpine({ ids: _optionalChain([params, 'optionalAccess', _399 => _399.ids]) });
9662
10895
  if (!r.ok) fail(r.message);
9663
10896
  return { ok: true };
9664
10897
  }
@@ -9772,7 +11005,7 @@ function createVectorCommands(controller, options = {}) {
9772
11005
  enabled: enabledFor,
9773
11006
  undoable: true,
9774
11007
  run: (_ctx, params) => {
9775
- const id = controller.group({ ids: ids(params), name: _optionalChain([params, 'optionalAccess', _355 => _355.name]) });
11008
+ const id = controller.group({ ids: ids(params), name: _optionalChain([params, 'optionalAccess', _400 => _400.name]) });
9776
11009
  if (!id) fail("Only nodes that share a parent can be grouped.");
9777
11010
  return { id };
9778
11011
  }
@@ -9800,7 +11033,7 @@ function createVectorCommands(controller, options = {}) {
9800
11033
  params: { type: "object", properties: { anchors: ANCHORS, keepShape: { type: "boolean" } } },
9801
11034
  undoable: true,
9802
11035
  run: (_ctx, params) => {
9803
- check(controller.deleteAnchors(anchorsOf(_optionalChain([params, 'optionalAccess', _356 => _356.anchors])), { keepShape: _optionalChain([params, 'optionalAccess', _357 => _357.keepShape]) }));
11036
+ check(controller.deleteAnchors(anchorsOf(_optionalChain([params, 'optionalAccess', _401 => _401.anchors])), { keepShape: _optionalChain([params, 'optionalAccess', _402 => _402.keepShape]) }));
9804
11037
  return { ok: true };
9805
11038
  }
9806
11039
  },
@@ -9855,7 +11088,7 @@ function createVectorCommands(controller, options = {}) {
9855
11088
  params: { type: "object", properties: { ids: IDS, tolerance: { type: "number", minimum: 0 } } },
9856
11089
  undoable: true,
9857
11090
  run: (_ctx, params) => {
9858
- check(controller.joinPaths({ ids: _optionalChain([params, 'optionalAccess', _358 => _358.ids]) ? ids(params) : void 0, tolerance: _optionalChain([params, 'optionalAccess', _359 => _359.tolerance]) }));
11091
+ check(controller.joinPaths({ ids: _optionalChain([params, 'optionalAccess', _403 => _403.ids]) ? ids(params) : void 0, tolerance: _optionalChain([params, 'optionalAccess', _404 => _404.tolerance]) }));
9859
11092
  return { selection: controller.getState().selection };
9860
11093
  }
9861
11094
  },
@@ -9869,7 +11102,7 @@ function createVectorCommands(controller, options = {}) {
9869
11102
  params: { type: "object", properties: { axis: { type: "string", enum: ["horizontal", "vertical", "both"] }, anchors: ANCHORS } },
9870
11103
  undoable: true,
9871
11104
  run: (_ctx, params) => {
9872
- check(controller.averageAnchors(_nullishCoalesce(_optionalChain([params, 'optionalAccess', _360 => _360.axis]), () => ( "both")), anchorsOf(_optionalChain([params, 'optionalAccess', _361 => _361.anchors]))));
11105
+ check(controller.averageAnchors(_nullishCoalesce(_optionalChain([params, 'optionalAccess', _405 => _405.axis]), () => ( "both")), anchorsOf(_optionalChain([params, 'optionalAccess', _406 => _406.anchors]))));
9873
11106
  return { ok: true };
9874
11107
  }
9875
11108
  },
@@ -9883,7 +11116,7 @@ function createVectorCommands(controller, options = {}) {
9883
11116
  enabled: enabledFor,
9884
11117
  undoable: true,
9885
11118
  run: (_ctx, params) => {
9886
- check(controller.removeRedundantPoints({ ids: _optionalChain([params, 'optionalAccess', _362 => _362.ids]) ? ids(params) : void 0, tolerance: _optionalChain([params, 'optionalAccess', _363 => _363.tolerance]) }));
11119
+ check(controller.removeRedundantPoints({ ids: _optionalChain([params, 'optionalAccess', _407 => _407.ids]) ? ids(params) : void 0, tolerance: _optionalChain([params, 'optionalAccess', _408 => _408.tolerance]) }));
9887
11120
  return { ok: true };
9888
11121
  }
9889
11122
  },
@@ -9896,7 +11129,7 @@ function createVectorCommands(controller, options = {}) {
9896
11129
  params: { type: "object", properties: { ids: IDS, amount: { type: "number", minimum: 0, maximum: 1 }, anchors: ANCHORS } },
9897
11130
  undoable: true,
9898
11131
  run: (_ctx, params) => {
9899
- check(controller.smoothPaths({ ids: _optionalChain([params, 'optionalAccess', _364 => _364.ids]) ? ids(params) : void 0, amount: _optionalChain([params, 'optionalAccess', _365 => _365.amount]), refs: _optionalChain([params, 'optionalAccess', _366 => _366.anchors]) }));
11132
+ check(controller.smoothPaths({ ids: _optionalChain([params, 'optionalAccess', _409 => _409.ids]) ? ids(params) : void 0, amount: _optionalChain([params, 'optionalAccess', _410 => _410.amount]), refs: _optionalChain([params, 'optionalAccess', _411 => _411.anchors]) }));
9900
11133
  return { ok: true };
9901
11134
  }
9902
11135
  },
@@ -9909,14 +11142,14 @@ function createVectorCommands(controller, options = {}) {
9909
11142
  params: { type: "object", properties: { nodeId: { type: "string" }, x: { type: "number" }, y: { type: "number" }, anchors: ANCHORS } },
9910
11143
  undoable: true,
9911
11144
  run: (_ctx, params) => {
9912
- if (_optionalChain([params, 'optionalAccess', _367 => _367.nodeId]) !== void 0) {
11145
+ if (_optionalChain([params, 'optionalAccess', _412 => _412.nodeId]) !== void 0) {
9913
11146
  if (!controller.getNode(params.nodeId)) fail(`There is no node "${params.nodeId}".`);
9914
11147
  if (params.x === void 0 || params.y === void 0) fail("Pass x and y with nodeId.");
9915
11148
  const created = controller.cutPathAt(params.nodeId, { x: params.x, y: params.y });
9916
11149
  if (!created) fail("Nothing to cut there (the end of an open path, or a locked path).");
9917
11150
  return { ids: created };
9918
11151
  }
9919
- check(controller.cutAtAnchors(anchorsOf(_optionalChain([params, 'optionalAccess', _368 => _368.anchors]))));
11152
+ check(controller.cutAtAnchors(anchorsOf(_optionalChain([params, 'optionalAccess', _413 => _413.anchors]))));
9920
11153
  return { ids: controller.getState().selection };
9921
11154
  }
9922
11155
  },
@@ -9967,7 +11200,7 @@ function createVectorCommands(controller, options = {}) {
9967
11200
  },
9968
11201
  run: (_ctx, params) => {
9969
11202
  const patch = {};
9970
- for (const key of ["keepShapeOnDelete", "curvatureMoves", "pencilSmoothing", "recognizeShapes", "eraserSize", "pencilPressure"]) if (_optionalChain([params, 'optionalAccess', _369 => _369[key]]) !== void 0) patch[key] = params[key];
11203
+ for (const key of ["keepShapeOnDelete", "curvatureMoves", "pencilSmoothing", "recognizeShapes", "eraserSize", "pencilPressure"]) if (_optionalChain([params, 'optionalAccess', _414 => _414[key]]) !== void 0) patch[key] = params[key];
9971
11204
  controller.setEditing(patch);
9972
11205
  return { editing: controller.getState().editing };
9973
11206
  }
@@ -9992,7 +11225,7 @@ function createVectorCommands(controller, options = {}) {
9992
11225
  keywords: ["download", "save", "markup"],
9993
11226
  description: "Returns the document as SVG markup.",
9994
11227
  params: { type: "object", properties: { precision: { type: "integer", minimum: 0, maximum: 8 } } },
9995
- run: (_ctx, params) => ({ svg: controller.toSvg({ precision: _optionalChain([params, 'optionalAccess', _370 => _370.precision]) }) })
11228
+ run: (_ctx, params) => ({ svg: controller.toSvg({ precision: _optionalChain([params, 'optionalAccess', _415 => _415.precision]) }) })
9996
11229
  },
9997
11230
  {
9998
11231
  ...base,
@@ -10244,5 +11477,47 @@ function createVectorCommands(controller, options = {}) {
10244
11477
 
10245
11478
 
10246
11479
 
10247
- exports.DEFAULT_VECTOR_BLEND_DISTANCE = DEFAULT_VECTOR_BLEND_DISTANCE; exports.DEFAULT_VECTOR_BLEND_STEPS = DEFAULT_VECTOR_BLEND_STEPS; exports.DEFAULT_VECTOR_PATH_EDIT = DEFAULT_VECTOR_PATH_EDIT; exports.DEFAULT_VECTOR_SNAP = DEFAULT_VECTOR_SNAP; exports.IDENTITY_MATRIX = IDENTITY_MATRIX; exports.KAPPA = KAPPA2; exports.LazyMouse = LazyMouse; exports.VECTOR_ARROWHEADS = VECTOR_ARROWHEADS; exports.VECTOR_ARROWHEAD_LABELS = VECTOR_ARROWHEAD_LABELS; exports.VECTOR_BLEND_MAX_SMOOTH_STEPS = VECTOR_BLEND_MAX_SMOOTH_STEPS; exports.VECTOR_BLEND_MAX_STEPS = VECTOR_BLEND_MAX_STEPS; exports.VECTOR_BLEND_SPACINGS = VECTOR_BLEND_SPACINGS; exports.VECTOR_BLEND_SPACING_LABELS = VECTOR_BLEND_SPACING_LABELS; exports.VECTOR_BUILDER_HATCH_GAP = VECTOR_BUILDER_HATCH_GAP; exports.VECTOR_CLIPBOARD_TYPE = VECTOR_CLIPBOARD_TYPE; exports.VECTOR_CONSTRUCTION_ANGLES = VECTOR_CONSTRUCTION_ANGLES; exports.VECTOR_CORNER_KINDS = VECTOR_CORNER_KINDS; exports.VECTOR_CORNER_KIND_LABELS = VECTOR_CORNER_KIND_LABELS; exports.VECTOR_CORNER_WIDGET_INSET = VECTOR_CORNER_WIDGET_INSET; exports.VECTOR_EDIT_TOGGLES = VECTOR_EDIT_TOGGLES; exports.VECTOR_FILL_GAP = VECTOR_FILL_GAP; exports.VECTOR_INK_MAX_CORNERS = VECTOR_INK_MAX_CORNERS; exports.VECTOR_OVERLAY_THEME = VECTOR_OVERLAY_THEME; exports.VECTOR_PATHFINDER_ACTIONS = VECTOR_PATHFINDER_ACTIONS; exports.VECTOR_PATHFINDER_LABELS = VECTOR_PATHFINDER_LABELS; exports.VECTOR_PATHFINDER_OPERATIONS = VECTOR_PATHFINDER_OPERATIONS; exports.VECTOR_PATH_ACTIONS = VECTOR_PATH_ACTIONS; exports.VECTOR_PENCIL_STRING_PX = VECTOR_PENCIL_STRING_PX; exports.VECTOR_PRESSURE_NOMINAL = VECTOR_PRESSURE_NOMINAL; exports.VECTOR_ROTATE_HANDLE_OFFSET = VECTOR_ROTATE_HANDLE_OFFSET; exports.VECTOR_STROKE_ALIGN_LABELS = VECTOR_STROKE_ALIGN_LABELS; exports.VECTOR_STYLE_KEYS = VECTOR_STYLE_KEYS; exports.VECTOR_TOOLS = VECTOR_TOOLS; exports.VECTOR_TOOL_GLYPHS = VECTOR_TOOL_GLYPHS; exports.VECTOR_TOOL_SHORTCUTS = VECTOR_TOOL_SHORTCUTS; exports.VECTOR_TRANSFORM_HANDLES = VECTOR_TRANSFORM_HANDLES; exports.VECTOR_WIDTH_PRESETS = VECTOR_WIDTH_PRESETS; exports.VECTOR_WIDTH_PRESET_IDS = VECTOR_WIDTH_PRESET_IDS; exports.VECTOR_WIDTH_PROFILE_MAX_POINTS = VECTOR_WIDTH_PROFILE_MAX_POINTS; exports.VECTOR_WIDTH_PROFILE_MAX_SCALE = VECTOR_WIDTH_PROFILE_MAX_SCALE; exports.VECTOR_WIDTH_SAME_T = VECTOR_WIDTH_SAME_T; exports.VectorEditorController = VectorEditorController; exports.VectorSnapTargets = VectorSnapTargets; exports.addBuilderHit = addBuilderHit; exports.applyMatrix = applyMatrix; exports.applyMatrixLinear = applyMatrixLinear; exports.applyVectorBlendOptions = applyVectorBlendOptions; exports.applyVectorCornersAttribute = applyVectorCornersAttribute; exports.arrowheadInset = arrowheadInset; exports.arrowheadPath = arrowheadPath; exports.arrowheadWeight = arrowheadWeight; exports.bendSegment = bendSegment; exports.bezierToSubpaths = bezierToSubpaths; exports.boundsFromPoints = boundsFromPoints; exports.boundsIntersect = boundsIntersect; exports.cloneAnchor = cloneAnchor; exports.cloneSubpath = cloneSubpath; exports.cloneVectorDocument = cloneVectorDocument; exports.cloneVectorNode = cloneVectorNode; exports.collectPathNodes = collectPathNodes; exports.constrainToLeave = constrainToLeave; exports.convertAnchor = convertAnchor; exports.cornerBisectorPoint = cornerBisectorPoint; exports.cornerRadiusChange = cornerRadiusChange; exports.cornerSetback = cornerSetback; exports.correspondMorphContours = correspondMorphContours; exports.createVectorCommands = createVectorCommands; exports.createVectorMorph = createVectorMorph; exports.curvatureMoveAnchor = curvatureMoveAnchor; exports.cutSubpathAt = cutSubpathAt; exports.dashIntervals = dashIntervals; exports.decomposeRigid = decomposeRigid; exports.effectiveStrokeAlign = effectiveStrokeAlign; exports.ellipseSubpath = ellipseSubpath; exports.eraseFromFill = eraseFromFill; exports.eraseFromOutline = eraseFromOutline; exports.eraserRegion = eraserRegion; exports.evaluateVectorPathKeyframes = evaluateVectorPathKeyframes; exports.expandVectorBlend = expandVectorBlend; exports.expandVectorCorners = expandVectorCorners; exports.expandVectorCornersOf = expandVectorCornersOf; exports.findVectorNode = findVectorNode; exports.fitCornerRadius = fitCornerRadius; exports.generateVectorBlendChildren = generateVectorBlendChildren; exports.generateWidthProfile = generateWidthProfile; exports.getAnchor = getAnchor; exports.getAnchorWorld = getAnchorWorld; exports.getEditablePathIds = getEditablePathIds; exports.getTransformHandlePositions = getTransformHandlePositions; exports.getVectorBlendControls = getVectorBlendControls; exports.getVectorCornerWidgets = getVectorCornerWidgets; exports.getVectorOverlayRenderData = getVectorOverlayRenderData; exports.getVectorSceneRenderData = getVectorSceneRenderData; exports.getVectorSelectionBoxGeometry = getVectorSelectionBoxGeometry; exports.getVectorSelectionFrame = getVectorSelectionFrame; exports.getVectorSelectionStyle = getVectorSelectionStyle; exports.getVectorWidthHandles = getVectorWidthHandles; exports.getVisibleAnchors = getVisibleAnchors; exports.getVisibleHandles = getVisibleHandles; exports.hasPaint = hasPaint; exports.hasStrokeExtras = hasStrokeExtras; exports.hasVectorCorners = hasVectorCorners; exports.hitTestVectorNode = hitTestVectorNode; exports.hitTestVectorNodes = hitTestVectorNodes; exports.hitTestVectorStroke = hitTestVectorStroke; exports.inferAnchorType = inferAnchorType; exports.insertAnchor = insertAnchor; exports.insertWidthPoint = insertWidthPoint; exports.interpolateMorphContours = interpolateMorphContours; exports.interpolateRigidMatrix = interpolateRigidMatrix; exports.interpolateVectorColor = interpolateVectorColor; exports.interpolateVectorPaint = interpolateVectorPaint; exports.interpolateVectorPaths = interpolateVectorPaths; exports.interpolateVectorStyle = interpolateVectorStyle; exports.interpolateWidthProfiles = interpolateWidthProfiles; exports.invertMatrix = invertMatrix; exports.isClosedBezierShape = isClosedBezierShape; exports.isIdentityMatrix = isIdentityMatrix; exports.isUniformWidthProfile = isUniformWidthProfile; exports.isVectorBlendGroup = isVectorBlendGroup; exports.isVectorTextTarget = isVectorTextTarget; exports.joinSubpaths = joinSubpaths; exports.knifePath = knifePath; exports.lineSubpath = lineSubpath; exports.locateVectorNode = locateVectorNode; exports.matrixRotation = matrixRotation; exports.mirrorWidthProfile = mirrorWidthProfile; exports.morphContourToSubpath = morphContourToSubpath; exports.morphPathsCross = morphPathsCross; exports.moveAnchorHandle = moveAnchorHandle; exports.multiplyMatrices = multiplyMatrices; exports.nearestSegment = nearestSegment; exports.nearestStrokePosition = nearestStrokePosition; exports.nextVectorCornerKind = nextVectorCornerKind; exports.nodeMatrix = nodeMatrix; exports.parseSvgTransform = parseSvgTransform; exports.parseVectorSvg = parseVectorSvg; exports.planShapeBuilder = planShapeBuilder; exports.polygonSubpath = polygonSubpath; exports.polylineBounds = polylineBounds; exports.pressureWidthProfile = pressureWidthProfile; exports.recognizeInkShape = recognizeInkShape; exports.rectSubpath = rectSubpath; exports.refineMorphContour = refineMorphContour; exports.refreshVectorBlends = refreshVectorBlends; exports.releaseVectorBlend = releaseVectorBlend; exports.removeAnchorKeepingShape = removeAnchorKeepingShape; exports.removeAnchors = removeAnchors; exports.removeAnchorsKeepingShape = removeAnchorsKeepingShape; exports.removeRedundantPoints = removeRedundantPoints; exports.removeWidthPoints = removeWidthPoints; exports.resampleGradientStops = resampleGradientStops; exports.resolveVectorBlendOptions = resolveVectorBlendOptions; exports.reverseMorphContour = reverseMorphContour; exports.reverseSubpath = reverseSubpath; exports.reverseWidthProfile = reverseWidthProfile; exports.rotateMatrix = rotateMatrix; exports.roundSubpaths = roundSubpaths; exports.samplePolyline = samplePolyline; exports.sanitizeWidthProfile = sanitizeWidthProfile; exports.scaleFor = scaleFor; exports.scaleMatrix = scaleMatrix; exports.setAnchorCorner = setAnchorCorner; exports.setSubpathCorners = setSubpathCorners; exports.setWidthPoint = setWidthPoint; exports.simplifyPolyline = simplifyPolyline; exports.smoothSubpath = smoothSubpath; exports.splitIntoFaces = splitIntoFaces; exports.splitSubpathAt = splitSubpathAt; exports.starSubpath = starSubpath; exports.strokePositionPoint = strokePositionPoint; exports.strokeWidthProfileOf = strokeWidthProfileOf; exports.subpathEnclosesArea = subpathEnclosesArea; exports.subpathPointAt = subpathPointAt; exports.subpathSegment = subpathSegment; exports.subpathSegmentCount = subpathSegmentCount; exports.subpathToMorphContour = subpathToMorphContour; exports.subpathsToBezier = subpathsToBezier; exports.taperWaveFactor = taperWaveFactor; exports.toVectorKeyInput = toVectorKeyInput; exports.toVectorModifiers = toVectorModifiers; exports.toVectorPointerInput = toVectorPointerInput; exports.transformVectorNode = transformVectorNode; exports.translateAnchor = translateAnchor; exports.translateMatrix = translateMatrix; exports.turnMorphContour = turnMorphContour; exports.unionBounds = unionBounds; exports.variableStrokeOutline = variableStrokeOutline; exports.variableStrokeRings = variableStrokeRings; exports.vectorBlendColorDistance = vectorBlendColorDistance; exports.vectorBlendKeyTargets = vectorBlendKeyTargets; exports.vectorBlendKeys = vectorBlendKeys; exports.vectorBlendRail = vectorBlendRail; exports.vectorBlendRailAt = vectorBlendRailAt; exports.vectorBlendSpine = vectorBlendSpine; exports.vectorBlendStepCount = vectorBlendStepCount; exports.vectorBuilderErasedEdges = vectorBuilderErasedEdges; exports.vectorCornerAt = vectorCornerAt; exports.vectorCorners = vectorCorners; exports.vectorCornersAttribute = vectorCornersAttribute; exports.vectorDiamondPath = vectorDiamondPath; exports.vectorDocumentToSvg = vectorDocumentToSvg; exports.vectorFillMap = vectorFillMap; exports.vectorInkShapeName = vectorInkShapeName; exports.vectorNodeBounds = vectorNodeBounds; exports.vectorNodeRotation = vectorNodeRotation; exports.vectorNodeToBezier = vectorNodeToBezier; exports.vectorPaintToHex = vectorPaintToHex; exports.vectorPaintToSvg = vectorPaintToSvg; exports.vectorParentMatrix = vectorParentMatrix; exports.vectorPathData = vectorPathData; exports.vectorPathEntries = vectorPathEntries; exports.vectorPathWorldBezier = vectorPathWorldBezier; exports.vectorPathfinderShape = vectorPathfinderShape; exports.vectorResizeCursor = vectorResizeCursor; exports.vectorResultStyle = vectorResultStyle; exports.vectorShapeBuilderHit = vectorShapeBuilderHit; exports.vectorShapeBuilderMap = vectorShapeBuilderMap; exports.vectorStrokeLineArea = vectorStrokeLineArea; exports.vectorStrokeOutline = vectorStrokeOutline; exports.vectorStrokeOutlinePath = vectorStrokeOutlinePath; exports.vectorStrokeParts = vectorStrokeParts; exports.vectorStrokeReach = vectorStrokeReach; exports.vectorStrokeSvgParts = vectorStrokeSvgParts; exports.vectorStrokeWidthGeometry = vectorStrokeWidthGeometry; exports.vectorToolLabel = vectorToolLabel; exports.vectorWorldMatrix = vectorWorldMatrix; exports.walkVectorNodes = walkVectorNodes; exports.widthProfileAt = widthProfileAt; exports.widthProfileFromAttribute = widthProfileFromAttribute; exports.widthProfileMaxScale = widthProfileMaxScale; exports.widthProfilePreset = widthProfilePreset; exports.widthProfilePresetId = widthProfilePresetId; exports.widthProfileToAttribute = widthProfileToAttribute;
11480
+
11481
+
11482
+
11483
+
11484
+
11485
+
11486
+
11487
+
11488
+
11489
+
11490
+
11491
+
11492
+
11493
+
11494
+
11495
+
11496
+
11497
+
11498
+
11499
+
11500
+
11501
+
11502
+
11503
+
11504
+
11505
+
11506
+
11507
+
11508
+
11509
+
11510
+
11511
+
11512
+
11513
+
11514
+
11515
+
11516
+
11517
+
11518
+
11519
+
11520
+
11521
+
11522
+ exports.DEFAULT_VECTOR_BLEND_DISTANCE = DEFAULT_VECTOR_BLEND_DISTANCE; exports.DEFAULT_VECTOR_BLEND_STEPS = DEFAULT_VECTOR_BLEND_STEPS; exports.DEFAULT_VECTOR_PATH_EDIT = DEFAULT_VECTOR_PATH_EDIT; exports.DEFAULT_VECTOR_SNAP = DEFAULT_VECTOR_SNAP; exports.IDENTITY_MATRIX = IDENTITY_MATRIX; exports.KAPPA = KAPPA2; exports.LazyMouse = LazyMouse; exports.VECTOR_ARROWHEADS = VECTOR_ARROWHEADS; exports.VECTOR_ARROWHEAD_LABELS = VECTOR_ARROWHEAD_LABELS; exports.VECTOR_BLEND_MAX_SMOOTH_STEPS = VECTOR_BLEND_MAX_SMOOTH_STEPS; exports.VECTOR_BLEND_MAX_STEPS = VECTOR_BLEND_MAX_STEPS; exports.VECTOR_BLEND_SPACINGS = VECTOR_BLEND_SPACINGS; exports.VECTOR_BLEND_SPACING_LABELS = VECTOR_BLEND_SPACING_LABELS; exports.VECTOR_BUILDER_HATCH_GAP = VECTOR_BUILDER_HATCH_GAP; exports.VECTOR_CLIPBOARD_TYPE = VECTOR_CLIPBOARD_TYPE; exports.VECTOR_CONSTRUCTION_ANGLES = VECTOR_CONSTRUCTION_ANGLES; exports.VECTOR_CORNER_KINDS = VECTOR_CORNER_KINDS; exports.VECTOR_CORNER_KIND_LABELS = VECTOR_CORNER_KIND_LABELS; exports.VECTOR_CORNER_WIDGET_INSET = VECTOR_CORNER_WIDGET_INSET; exports.VECTOR_EDIT_TOGGLES = VECTOR_EDIT_TOGGLES; exports.VECTOR_EFFECT_DEFAULTS = VECTOR_EFFECT_DEFAULTS; exports.VECTOR_EFFECT_LABELS = VECTOR_EFFECT_LABELS; exports.VECTOR_EFFECT_MENU = VECTOR_EFFECT_MENU; exports.VECTOR_EFFECT_PARAM_SPECS = VECTOR_EFFECT_PARAM_SPECS; exports.VECTOR_EFFECT_TYPES = VECTOR_EFFECT_TYPES; exports.VECTOR_FILL_GAP = VECTOR_FILL_GAP; exports.VECTOR_INK_MAX_CORNERS = VECTOR_INK_MAX_CORNERS; exports.VECTOR_MERGE_MODES = VECTOR_MERGE_MODES; exports.VECTOR_OVERLAY_THEME = VECTOR_OVERLAY_THEME; exports.VECTOR_PATHFINDER_ACTIONS = VECTOR_PATHFINDER_ACTIONS; exports.VECTOR_PATHFINDER_LABELS = VECTOR_PATHFINDER_LABELS; exports.VECTOR_PATHFINDER_OPERATIONS = VECTOR_PATHFINDER_OPERATIONS; exports.VECTOR_PATH_ACTIONS = VECTOR_PATH_ACTIONS; exports.VECTOR_PENCIL_STRING_PX = VECTOR_PENCIL_STRING_PX; exports.VECTOR_PRESSURE_NOMINAL = VECTOR_PRESSURE_NOMINAL; exports.VECTOR_ROTATE_HANDLE_OFFSET = VECTOR_ROTATE_HANDLE_OFFSET; exports.VECTOR_STROKE_ALIGN_LABELS = VECTOR_STROKE_ALIGN_LABELS; exports.VECTOR_STYLE_KEYS = VECTOR_STYLE_KEYS; exports.VECTOR_TOOLS = VECTOR_TOOLS; exports.VECTOR_TOOL_GLYPHS = VECTOR_TOOL_GLYPHS; exports.VECTOR_TOOL_SHORTCUTS = VECTOR_TOOL_SHORTCUTS; exports.VECTOR_TRANSFORM_HANDLES = VECTOR_TRANSFORM_HANDLES; exports.VECTOR_WIDTH_PRESETS = VECTOR_WIDTH_PRESETS; exports.VECTOR_WIDTH_PRESET_IDS = VECTOR_WIDTH_PRESET_IDS; exports.VECTOR_WIDTH_PROFILE_MAX_POINTS = VECTOR_WIDTH_PROFILE_MAX_POINTS; exports.VECTOR_WIDTH_PROFILE_MAX_SCALE = VECTOR_WIDTH_PROFILE_MAX_SCALE; exports.VECTOR_WIDTH_SAME_T = VECTOR_WIDTH_SAME_T; exports.VectorEditorController = VectorEditorController; exports.VectorSnapTargets = VectorSnapTargets; exports.activeVectorEffects = activeVectorEffects; exports.addBuilderHit = addBuilderHit; exports.applyMatrix = applyMatrix; exports.applyMatrixLinear = applyMatrixLinear; exports.applyVectorBlendOptions = applyVectorBlendOptions; exports.applyVectorCornersAttribute = applyVectorCornersAttribute; exports.applyVectorEffects = applyVectorEffects; exports.arrowheadInset = arrowheadInset; exports.arrowheadPath = arrowheadPath; exports.arrowheadWeight = arrowheadWeight; exports.bendSegment = bendSegment; exports.bezierToSubpaths = bezierToSubpaths; exports.boundsFromPoints = boundsFromPoints; exports.boundsIntersect = boundsIntersect; exports.clearVectorLiveBooleanCache = clearVectorLiveBooleanCache; exports.cloneAnchor = cloneAnchor; exports.cloneSubpath = cloneSubpath; exports.cloneVectorDocument = cloneVectorDocument; exports.cloneVectorNode = cloneVectorNode; exports.collectPathNodes = collectPathNodes; exports.constrainToLeave = constrainToLeave; exports.convertAnchor = convertAnchor; exports.cornerBisectorPoint = cornerBisectorPoint; exports.cornerRadiusChange = cornerRadiusChange; exports.cornerSetback = cornerSetback; exports.correspondMorphContours = correspondMorphContours; exports.createVectorCommands = createVectorCommands; exports.createVectorEffect = createVectorEffect; exports.createVectorMorph = createVectorMorph; exports.curvatureMoveAnchor = curvatureMoveAnchor; exports.cutSubpathAt = cutSubpathAt; exports.dashIntervals = dashIntervals; exports.decomposeRigid = decomposeRigid; exports.effectPathLength = effectPathLength; exports.effectPathVertexCount = effectPathVertexCount; exports.effectiveStrokeAlign = effectiveStrokeAlign; exports.ellipseSubpath = ellipseSubpath; exports.eraseFromFill = eraseFromFill; exports.eraseFromOutline = eraseFromOutline; exports.eraserRegion = eraserRegion; exports.evaluateVectorPathKeyframes = evaluateVectorPathKeyframes; exports.expandVectorAppearance = expandVectorAppearance; exports.expandVectorAppearances = expandVectorAppearances; exports.expandVectorBlend = expandVectorBlend; exports.expandVectorCorners = expandVectorCorners; exports.expandVectorCornersOf = expandVectorCornersOf; exports.findVectorNode = findVectorNode; exports.fitCornerRadius = fitCornerRadius; exports.foldVectorBooleanOperands = foldVectorBooleanOperands; exports.generateVectorBlendChildren = generateVectorBlendChildren; exports.generateWidthProfile = generateWidthProfile; exports.getAnchor = getAnchor; exports.getAnchorWorld = getAnchorWorld; exports.getEditablePathIds = getEditablePathIds; exports.getTransformHandlePositions = getTransformHandlePositions; exports.getVectorBlendControls = getVectorBlendControls; exports.getVectorCornerWidgets = getVectorCornerWidgets; exports.getVectorEffectsPanel = getVectorEffectsPanel; exports.getVectorEnteredGroups = getVectorEnteredGroups; exports.getVectorOverlayRenderData = getVectorOverlayRenderData; exports.getVectorSceneRenderData = getVectorSceneRenderData; exports.getVectorSelectionBoxGeometry = getVectorSelectionBoxGeometry; exports.getVectorSelectionFrame = getVectorSelectionFrame; exports.getVectorSelectionStyle = getVectorSelectionStyle; exports.getVectorWidthHandles = getVectorWidthHandles; exports.getVisibleAnchors = getVisibleAnchors; exports.getVisibleHandles = getVisibleHandles; exports.hasOwnVectorAppearance = hasOwnVectorAppearance; exports.hasPaint = hasPaint; exports.hasStrokeExtras = hasStrokeExtras; exports.hasVectorAppearance = hasVectorAppearance; exports.hasVectorCorners = hasVectorCorners; exports.hitTestVectorNode = hitTestVectorNode; exports.hitTestVectorNodes = hitTestVectorNodes; exports.hitTestVectorStroke = hitTestVectorStroke; exports.inferAnchorType = inferAnchorType; exports.insertAnchor = insertAnchor; exports.insertWidthPoint = insertWidthPoint; exports.interpolateMorphContours = interpolateMorphContours; exports.interpolateRigidMatrix = interpolateRigidMatrix; exports.interpolateVectorColor = interpolateVectorColor; exports.interpolateVectorPaint = interpolateVectorPaint; exports.interpolateVectorPaths = interpolateVectorPaths; exports.interpolateVectorStyle = interpolateVectorStyle; exports.interpolateWidthProfiles = interpolateWidthProfiles; exports.invertMatrix = invertMatrix; exports.isClosedBezierShape = isClosedBezierShape; exports.isIdentityMatrix = isIdentityMatrix; exports.isUniformWidthProfile = isUniformWidthProfile; exports.isVectorBlendGroup = isVectorBlendGroup; exports.isVectorLiveBoolean = isVectorLiveBoolean; exports.isVectorTextTarget = isVectorTextTarget; exports.joinSubpaths = joinSubpaths; exports.knifePath = knifePath; exports.lineSubpath = lineSubpath; exports.locateVectorNode = locateVectorNode; exports.matrixRotation = matrixRotation; exports.mergePaths = mergePaths; exports.mirrorWidthProfile = mirrorWidthProfile; exports.morphContourToSubpath = morphContourToSubpath; exports.morphPathsCross = morphPathsCross; exports.moveAnchorHandle = moveAnchorHandle; exports.multiplyMatrices = multiplyMatrices; exports.nearestSegment = nearestSegment; exports.nearestStrokePosition = nearestStrokePosition; exports.nextVectorCornerKind = nextVectorCornerKind; exports.nodeMatrix = nodeMatrix; exports.normalizeVectorEffectParams = normalizeVectorEffectParams; exports.offsetPaths = offsetPaths; exports.parseSvgTransform = parseSvgTransform; exports.parseVectorSvg = parseVectorSvg; exports.pathsCenter = pathsCenter; exports.planShapeBuilder = planShapeBuilder; exports.polygonSubpath = polygonSubpath; exports.polylineBounds = polylineBounds; exports.pressureWidthProfile = pressureWidthProfile; exports.puckerBloatPaths = puckerBloatPaths; exports.recognizeInkShape = recognizeInkShape; exports.rectSubpath = rectSubpath; exports.refineMorphContour = refineMorphContour; exports.refreshVectorBlends = refreshVectorBlends; exports.releaseVectorBlend = releaseVectorBlend; exports.removeAnchorKeepingShape = removeAnchorKeepingShape; exports.removeAnchors = removeAnchors; exports.removeAnchorsKeepingShape = removeAnchorsKeepingShape; exports.removeRedundantPoints = removeRedundantPoints; exports.removeWidthPoints = removeWidthPoints; exports.repeatPaths = repeatPaths; exports.resampleGradientStops = resampleGradientStops; exports.resolveVectorBlendOptions = resolveVectorBlendOptions; exports.reverseMorphContour = reverseMorphContour; exports.reverseSubpath = reverseSubpath; exports.reverseWidthProfile = reverseWidthProfile; exports.rotateMatrix = rotateMatrix; exports.roundCornerPaths = roundCornerPaths; exports.roundSubpaths = roundSubpaths; exports.samplePolyline = samplePolyline; exports.sanitizeVectorEffects = sanitizeVectorEffects; exports.sanitizeWidthProfile = sanitizeWidthProfile; exports.scaleFor = scaleFor; exports.scaleMatrix = scaleMatrix; exports.setAnchorCorner = setAnchorCorner; exports.setSubpathCorners = setSubpathCorners; exports.setWidthPoint = setWidthPoint; exports.simplifyPolyline = simplifyPolyline; exports.smoothSubpath = smoothSubpath; exports.splitIntoFaces = splitIntoFaces; exports.splitSubpathAt = splitSubpathAt; exports.starSubpath = starSubpath; exports.strokePositionPoint = strokePositionPoint; exports.strokeWidthProfileOf = strokeWidthProfileOf; exports.subpathEnclosesArea = subpathEnclosesArea; exports.subpathPointAt = subpathPointAt; exports.subpathSegment = subpathSegment; exports.subpathSegmentCount = subpathSegmentCount; exports.subpathToMorphContour = subpathToMorphContour; exports.subpathsToBezier = subpathsToBezier; exports.taperWaveFactor = taperWaveFactor; exports.toVectorKeyInput = toVectorKeyInput; exports.toVectorModifiers = toVectorModifiers; exports.toVectorPointerInput = toVectorPointerInput; exports.transformVectorEffects = transformVectorEffects; exports.transformVectorNode = transformVectorNode; exports.translateAnchor = translateAnchor; exports.translateMatrix = translateMatrix; exports.trimIntervals = trimIntervals; exports.trimPaths = trimPaths; exports.trimPathsIndividually = trimPathsIndividually; exports.turnMorphContour = turnMorphContour; exports.twistPaths = twistPaths; exports.unionBounds = unionBounds; exports.variableStrokeOutline = variableStrokeOutline; exports.variableStrokeRings = variableStrokeRings; exports.vectorAppearanceNodes = vectorAppearanceNodes; exports.vectorAppearanceOutline = vectorAppearanceOutline; exports.vectorAppearanceShapes = vectorAppearanceShapes; exports.vectorBlendColorDistance = vectorBlendColorDistance; exports.vectorBlendKeyTargets = vectorBlendKeyTargets; exports.vectorBlendKeys = vectorBlendKeys; exports.vectorBlendRail = vectorBlendRail; exports.vectorBlendRailAt = vectorBlendRailAt; exports.vectorBlendSpine = vectorBlendSpine; exports.vectorBlendStepCount = vectorBlendStepCount; exports.vectorBuilderErasedEdges = vectorBuilderErasedEdges; exports.vectorCornerAt = vectorCornerAt; exports.vectorCorners = vectorCorners; exports.vectorCornersAttribute = vectorCornersAttribute; exports.vectorDiamondPath = vectorDiamondPath; exports.vectorDocumentToSvg = vectorDocumentToSvg; exports.vectorEnteredGroups = vectorEnteredGroups; exports.vectorFillMap = vectorFillMap; exports.vectorInkShapeName = vectorInkShapeName; exports.vectorLiveBooleanSteps = vectorLiveBooleanSteps; exports.vectorNodeBounds = vectorNodeBounds; exports.vectorNodeRotation = vectorNodeRotation; exports.vectorNodeToBezier = vectorNodeToBezier; exports.vectorOperandOperation = vectorOperandOperation; exports.vectorPaintToHex = vectorPaintToHex; exports.vectorPaintToSvg = vectorPaintToSvg; exports.vectorParentMatrix = vectorParentMatrix; exports.vectorPathData = vectorPathData; exports.vectorPathEntries = vectorPathEntries; exports.vectorPathWorldBezier = vectorPathWorldBezier; exports.vectorPathfinderShape = vectorPathfinderShape; exports.vectorRepeaterCopies = vectorRepeaterCopies; exports.vectorResizeCursor = vectorResizeCursor; exports.vectorResultStyle = vectorResultStyle; exports.vectorShapeBuilderHit = vectorShapeBuilderHit; exports.vectorShapeBuilderMap = vectorShapeBuilderMap; exports.vectorStrokeLineArea = vectorStrokeLineArea; exports.vectorStrokeOutline = vectorStrokeOutline; exports.vectorStrokeOutlinePath = vectorStrokeOutlinePath; exports.vectorStrokeParts = vectorStrokeParts; exports.vectorStrokeReach = vectorStrokeReach; exports.vectorStrokeSvgParts = vectorStrokeSvgParts; exports.vectorStrokeWidthGeometry = vectorStrokeWidthGeometry; exports.vectorToolLabel = vectorToolLabel; exports.vectorWorldMatrix = vectorWorldMatrix; exports.walkVectorNodes = walkVectorNodes; exports.widthProfileAt = widthProfileAt; exports.widthProfileFromAttribute = widthProfileFromAttribute; exports.widthProfileMaxScale = widthProfileMaxScale; exports.widthProfilePreset = widthProfilePreset; exports.widthProfilePresetId = widthProfilePresetId; exports.widthProfileToAttribute = widthProfileToAttribute; exports.wigglePaths = wigglePaths; exports.zigzagPaths = zigzagPaths;
10248
11523
  //# sourceMappingURL=index.cjs.map