@pixerate/editor 0.118.0 → 0.120.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/THIRD_PARTY_NOTICES.md +1 -0
- package/dist/animation-editor/index.cjs +54 -54
- package/dist/animation-editor/index.d.cts +3 -3
- package/dist/animation-editor/index.d.ts +3 -3
- package/dist/animation-editor/index.js +2 -2
- package/dist/{chunk-R2JE6SA7.js → chunk-BOWUU4LJ.js} +42 -7
- package/dist/chunk-BOWUU4LJ.js.map +1 -0
- package/dist/{chunk-M7O4BJRH.cjs → chunk-DFLJHLKA.cjs} +36 -36
- package/dist/{chunk-M7O4BJRH.cjs.map → chunk-DFLJHLKA.cjs.map} +1 -1
- package/dist/{chunk-2J3LS7JZ.cjs → chunk-HTAFDTNR.cjs} +221 -186
- package/dist/chunk-HTAFDTNR.cjs.map +1 -0
- package/dist/{chunk-L2T6EJ5S.cjs → chunk-L3PXFMOF.cjs} +38 -25
- package/dist/chunk-L3PXFMOF.cjs.map +1 -0
- package/dist/{chunk-IVSNUXW7.js → chunk-T7IZDNSL.js} +37 -24
- package/dist/chunk-T7IZDNSL.js.map +1 -0
- package/dist/{chunk-BYAWOAST.cjs → chunk-TS5IEUW6.cjs} +26 -25
- package/dist/chunk-TS5IEUW6.cjs.map +1 -0
- package/dist/{chunk-VD2UDVF7.js → chunk-UMVW2Q66.js} +21 -5
- package/dist/chunk-UMVW2Q66.js.map +1 -0
- package/dist/{chunk-FODKPD44.cjs → chunk-VYW7JBTM.cjs} +790 -549
- package/dist/chunk-VYW7JBTM.cjs.map +1 -0
- package/dist/{chunk-T2P5TIZ6.js → chunk-WAI6ATHC.js} +2 -2
- package/dist/{chunk-EBSYZRSW.cjs → chunk-WMRIG4XQ.cjs} +21 -5
- package/dist/chunk-WMRIG4XQ.cjs.map +1 -0
- package/dist/{chunk-7LNZAWSJ.js → chunk-WORWH5K5.js} +699 -458
- package/dist/chunk-WORWH5K5.js.map +1 -0
- package/dist/{chunk-JHXMNOMF.js → chunk-YHW26LS2.js} +14 -13
- package/dist/chunk-YHW26LS2.js.map +1 -0
- package/dist/{export-Dul1SbPv.d.ts → export-D2D8hb_u.d.ts} +18 -4
- package/dist/{export-DMOuzgZZ.d.cts → export-fP2hZYjm.d.cts} +18 -4
- package/dist/{flow-4-OC-UkQ.d.cts → flow-A2Dj-69w.d.cts} +21 -9
- package/dist/{flow-Cb7lkPm8.d.ts → flow-C95atNoQ.d.ts} +21 -9
- package/dist/image-editor/index.cjs +1104 -979
- package/dist/image-editor/index.cjs.map +1 -1
- package/dist/image-editor/index.d.cts +5 -5
- package/dist/image-editor/index.d.ts +5 -5
- package/dist/image-editor/index.js +157 -32
- package/dist/image-editor/index.js.map +1 -1
- package/dist/paint/index.cjs +5 -3
- package/dist/paint/index.cjs.map +1 -1
- package/dist/paint/index.d.cts +2 -2
- package/dist/paint/index.d.ts +2 -2
- package/dist/paint/index.js +4 -2
- package/dist/paint-editor/index.cjs +147 -147
- package/dist/paint-editor/index.d.cts +4 -4
- package/dist/paint-editor/index.d.ts +4 -4
- package/dist/paint-editor/index.js +4 -4
- package/dist/raster/index.cjs +2 -2
- package/dist/raster/index.js +1 -1
- package/dist/{svg-CVdFc80-.d.cts → svg-S9zzvqaZ.d.cts} +5 -1
- package/dist/{svg-DlEuhwoX.d.ts → svg-leZpRsJB.d.ts} +5 -1
- package/dist/{types-CDLGhAZp.d.ts → types-BgwxFWvn.d.ts} +59 -3
- package/dist/{types-Tfly4Aya.d.cts → types-DdRTDnza.d.cts} +59 -3
- package/dist/vector/index.cjs +1314 -1009
- package/dist/vector/index.cjs.map +1 -1
- package/dist/vector/index.d.cts +110 -5
- package/dist/vector/index.d.ts +110 -5
- package/dist/vector/index.js +319 -14
- package/dist/vector/index.js.map +1 -1
- package/package.json +1 -1
- package/skills/pixerate-image-editor/references/photoshop-files.md +5 -2
- package/skills/pixerate-vector/SKILL.md +13 -1
- package/skills/pixerate-vector/references/commands.md +2 -0
- package/dist/chunk-2J3LS7JZ.cjs.map +0 -1
- package/dist/chunk-7LNZAWSJ.js.map +0 -1
- package/dist/chunk-BYAWOAST.cjs.map +0 -1
- package/dist/chunk-EBSYZRSW.cjs.map +0 -1
- package/dist/chunk-FODKPD44.cjs.map +0 -1
- package/dist/chunk-IVSNUXW7.js.map +0 -1
- package/dist/chunk-JHXMNOMF.js.map +0 -1
- package/dist/chunk-L2T6EJ5S.cjs.map +0 -1
- package/dist/chunk-R2JE6SA7.js.map +0 -1
- package/dist/chunk-VD2UDVF7.js.map +0 -1
- /package/dist/{chunk-T2P5TIZ6.js.map → chunk-WAI6ATHC.js.map} +0 -0
package/dist/vector/index.js
CHANGED
|
@@ -40,7 +40,7 @@ import {
|
|
|
40
40
|
reverseMorphContour,
|
|
41
41
|
subpathToMorphContour,
|
|
42
42
|
turnMorphContour
|
|
43
|
-
} from "../chunk-
|
|
43
|
+
} from "../chunk-WAI6ATHC.js";
|
|
44
44
|
import {
|
|
45
45
|
DEFAULT_VECTOR_FONT,
|
|
46
46
|
IDENTITY_MATRIX,
|
|
@@ -83,6 +83,8 @@ import {
|
|
|
83
83
|
VECTOR_STROKE_GRADIENT_MODES,
|
|
84
84
|
VECTOR_STROKE_SETTING_KEYS,
|
|
85
85
|
VECTOR_SYMBOL_MAX_DEPTH,
|
|
86
|
+
VECTOR_SYMMETRY_MODES,
|
|
87
|
+
VECTOR_SYMMETRY_MODE_LABELS,
|
|
86
88
|
VECTOR_TEXT_ALIGNS,
|
|
87
89
|
VECTOR_TOOLS,
|
|
88
90
|
VECTOR_TRANSFORM_HANDLES,
|
|
@@ -200,6 +202,7 @@ import {
|
|
|
200
202
|
isVectorMaskType,
|
|
201
203
|
isVectorMeshGradient,
|
|
202
204
|
isVectorShadedPaint,
|
|
205
|
+
isVectorSymmetryGroup,
|
|
203
206
|
knifePath,
|
|
204
207
|
layoutVectorText,
|
|
205
208
|
lineSubpath,
|
|
@@ -284,6 +287,7 @@ import {
|
|
|
284
287
|
sanitizeVectorShadedPaint,
|
|
285
288
|
sanitizeVectorStrokeSettings,
|
|
286
289
|
sanitizeVectorStrokes,
|
|
290
|
+
sanitizeVectorSymmetry,
|
|
287
291
|
sanitizeVectorTextFields,
|
|
288
292
|
sanitizeVectorTextFrame,
|
|
289
293
|
sanitizeWidthProfile,
|
|
@@ -309,6 +313,7 @@ import {
|
|
|
309
313
|
subpathSegment,
|
|
310
314
|
subpathSegmentCount,
|
|
311
315
|
subpathsToBezier,
|
|
316
|
+
sweepPath,
|
|
312
317
|
taperWaveFactor,
|
|
313
318
|
tintVectorNode,
|
|
314
319
|
transformVectorEffects,
|
|
@@ -316,6 +321,7 @@ import {
|
|
|
316
321
|
transformVectorNode,
|
|
317
322
|
transformVectorPaint,
|
|
318
323
|
transformVectorShadedPaint,
|
|
324
|
+
transformVectorSymmetry,
|
|
319
325
|
translateAnchor,
|
|
320
326
|
translateMatrix,
|
|
321
327
|
trimIntervals,
|
|
@@ -429,6 +435,9 @@ import {
|
|
|
429
435
|
vectorStrokes,
|
|
430
436
|
vectorSymbolUses,
|
|
431
437
|
vectorSymbolsUsedIn,
|
|
438
|
+
vectorSymmetryAxes,
|
|
439
|
+
vectorSymmetryDrawn,
|
|
440
|
+
vectorSymmetryMatrices,
|
|
432
441
|
vectorTargetPaint,
|
|
433
442
|
vectorTextBoxOutline,
|
|
434
443
|
vectorTextCaret,
|
|
@@ -467,7 +476,7 @@ import {
|
|
|
467
476
|
withVectorStrokes,
|
|
468
477
|
withVectorTargetPaint,
|
|
469
478
|
zigzagPaths
|
|
470
|
-
} from "../chunk-
|
|
479
|
+
} from "../chunk-WORWH5K5.js";
|
|
471
480
|
import {
|
|
472
481
|
bezierPathBounds,
|
|
473
482
|
bezierPathToSvg,
|
|
@@ -2371,6 +2380,46 @@ function shadingOverlay(state) {
|
|
|
2371
2380
|
}
|
|
2372
2381
|
return out;
|
|
2373
2382
|
}
|
|
2383
|
+
function symmetryOverlay(state) {
|
|
2384
|
+
const ids = /* @__PURE__ */ new Set([...state.selection, ...state.symmetryTarget ? [state.symmetryTarget] : []]);
|
|
2385
|
+
const out = [];
|
|
2386
|
+
for (const id of ids) {
|
|
2387
|
+
const n2 = findVectorNode(state.document.nodes, id);
|
|
2388
|
+
if (!isVectorSymmetryGroup(n2)) continue;
|
|
2389
|
+
const world = vectorWorldMatrix(state.document.nodes, id);
|
|
2390
|
+
if (!world) continue;
|
|
2391
|
+
const inv = invertMatrix(world);
|
|
2392
|
+
const corners2 = [
|
|
2393
|
+
{ x: 0, y: 0 },
|
|
2394
|
+
{ x: state.document.width, y: 0 },
|
|
2395
|
+
{ x: 0, y: state.document.height },
|
|
2396
|
+
{ x: state.document.width, y: state.document.height }
|
|
2397
|
+
].map((p) => applyMatrix(inv, p));
|
|
2398
|
+
const { transform: _t, ...own } = n2;
|
|
2399
|
+
const b = unionBoxes([vectorNodeBounds(own), boundsFromCorners(corners2)]);
|
|
2400
|
+
if (!b) continue;
|
|
2401
|
+
const pad = Math.max(b.width, b.height) * 0.05;
|
|
2402
|
+
const lines = vectorSymmetryAxes(n2.symmetry, { x: b.x - pad, y: b.y - pad, width: b.width + 2 * pad, height: b.height + 2 * pad }).map(([a, c]) => {
|
|
2403
|
+
const p = toScreen(state, applyMatrix(world, a));
|
|
2404
|
+
const q = toScreen(state, applyMatrix(world, c));
|
|
2405
|
+
return { x1: p.x, y1: p.y, x2: q.x, y2: q.y };
|
|
2406
|
+
});
|
|
2407
|
+
out.push({ nodeId: id, drawing: state.symmetryTarget === id, lines });
|
|
2408
|
+
}
|
|
2409
|
+
return out;
|
|
2410
|
+
}
|
|
2411
|
+
function unionBoxes(list) {
|
|
2412
|
+
const ok = list.filter((b) => !!b);
|
|
2413
|
+
if (!ok.length) return null;
|
|
2414
|
+
const x = Math.min(...ok.map((b) => b.x));
|
|
2415
|
+
const y = Math.min(...ok.map((b) => b.y));
|
|
2416
|
+
return { x, y, width: Math.max(...ok.map((b) => b.x + b.width)) - x, height: Math.max(...ok.map((b) => b.y + b.height)) - y };
|
|
2417
|
+
}
|
|
2418
|
+
function boundsFromCorners(pts) {
|
|
2419
|
+
const xs = pts.map((p) => p.x);
|
|
2420
|
+
const ys = pts.map((p) => p.y);
|
|
2421
|
+
return { x: Math.min(...xs), y: Math.min(...ys), width: Math.max(...xs) - Math.min(...xs), height: Math.max(...ys) - Math.min(...ys) };
|
|
2422
|
+
}
|
|
2374
2423
|
function connectorSiteOverlay(state) {
|
|
2375
2424
|
if (state.tool !== "connector" || !state.pointer) return [];
|
|
2376
2425
|
const drawing = state.interaction?.type === "draw" && state.interaction.tool === "connector" ? state.interaction.nodeId : void 0;
|
|
@@ -2643,6 +2692,7 @@ function getVectorOverlayRenderData(state) {
|
|
|
2643
2692
|
frames: frameLabels(state),
|
|
2644
2693
|
connectorSites: connectorSiteOverlay(state),
|
|
2645
2694
|
shading: shadingOverlay(state),
|
|
2695
|
+
symmetry: symmetryOverlay(state),
|
|
2646
2696
|
trackingPoints: (state.trackingPoints ?? []).map((p) => toScreen(state, p)),
|
|
2647
2697
|
typedEntry: state.typedEntry ? { text: state.typedEntry, ...state.pointer ? toScreen(state, state.pointer) : { x: 0, y: 0 } } : null
|
|
2648
2698
|
};
|
|
@@ -3663,9 +3713,9 @@ function nodeGroup(node, notes) {
|
|
|
3663
3713
|
if (node.filters?.length) notes.push(`${label(node)}: filters (shadows, glows, blurs) are not part of Lottie (left out).`);
|
|
3664
3714
|
const m = nodeMatrix(node);
|
|
3665
3715
|
let items = [];
|
|
3666
|
-
const live = (node.effects ?? []).some((e) => e.enabled !== false && (e.type === "wiggle" || e.type === "envelope"));
|
|
3667
|
-
if (node.type === "text" || node.type === "instance" || live || isVectorMaskGroup(node) || isVectorFrame(node)) {
|
|
3668
|
-
if (live) notes.push(`${label(node)}: wiggle and
|
|
3716
|
+
const live = (node.effects ?? []).some((e) => e.enabled !== false && (e.type === "wiggle" || e.type === "envelope" || e.type === "contour" || e.type === "blockShadow"));
|
|
3717
|
+
if (node.type === "text" || node.type === "instance" || live || isVectorMaskGroup(node) || isVectorFrame(node) || isVectorSymmetryGroup(node)) {
|
|
3718
|
+
if (live) notes.push(`${label(node)}: wiggle, envelope, contour and block shadow effects have no Lottie equivalent (exported as drawn).`);
|
|
3669
3719
|
if (isVectorMaskGroup(node) && node.mask?.type !== "clip") notes.push(`${label(node)}: opacity masks are not exported (the contents are drawn whole).`);
|
|
3670
3720
|
const drawn = isVectorFrame(node) ? vectorFrameDrawn(node) : node;
|
|
3671
3721
|
const shapes = isVectorMaskGroup(drawn) && drawn.mask?.type === "clip" ? vectorAppearanceShapes({ ...drawn, transform: void 0 }) : null;
|
|
@@ -6899,6 +6949,7 @@ var VectorEditorController = class _VectorEditorController {
|
|
|
6899
6949
|
trackingPoints: this.trackingPoints,
|
|
6900
6950
|
typedEntry: this.typed,
|
|
6901
6951
|
shadingPoint: this.getShadingSelection(),
|
|
6952
|
+
symmetryTarget: this.symmetryTarget && this.doc.nodes.some((n2) => n2.id === this.symmetryTarget) ? this.symmetryTarget : null,
|
|
6902
6953
|
canUndo: h.canUndo,
|
|
6903
6954
|
canRedo: h.canRedo,
|
|
6904
6955
|
undoLabel: h.undoName,
|
|
@@ -9202,6 +9253,155 @@ var VectorEditorController = class _VectorEditorController {
|
|
|
9202
9253
|
return { ok: true, id };
|
|
9203
9254
|
}
|
|
9204
9255
|
// -----------------------------------------------------------------------------------------
|
|
9256
|
+
// Live symmetry groups
|
|
9257
|
+
/** The symmetry group new pen, pencil, shape and text art goes into (see `enterSymmetry`), or null. */
|
|
9258
|
+
symmetryTarget = null;
|
|
9259
|
+
/** The symmetry group drawn art goes into, while it is entered and still a top-level, unturned symmetry group. */
|
|
9260
|
+
drawingTarget() {
|
|
9261
|
+
const id = this.symmetryTarget;
|
|
9262
|
+
if (!id) return null;
|
|
9263
|
+
const n2 = this.doc.nodes.find((x) => x.id === id);
|
|
9264
|
+
if (!isVectorSymmetryGroup(n2) || n2.transform || n2.locked) {
|
|
9265
|
+
this.symmetryTarget = null;
|
|
9266
|
+
return null;
|
|
9267
|
+
}
|
|
9268
|
+
return n2;
|
|
9269
|
+
}
|
|
9270
|
+
/** Adds a node a drawing tool makes: into the entered symmetry group, else on top. */
|
|
9271
|
+
addDrawn(node) {
|
|
9272
|
+
const target = this.tool === "frame" || this.tool === "connector" ? null : this.drawingTarget();
|
|
9273
|
+
if (!target) return this.setDoc([...this.doc.nodes, node]);
|
|
9274
|
+
this.setDoc(this.doc.nodes.map((n2) => n2.id === target.id && n2.type === "group" ? { ...n2, children: [...n2.children, node] } : n2));
|
|
9275
|
+
}
|
|
9276
|
+
/**
|
|
9277
|
+
* Make Symmetry: puts objects that share a parent (default: the selection) into a live symmetry
|
|
9278
|
+
* group that draws them with their mirrored or rotated copies, the axes through `center`
|
|
9279
|
+
* (default: the objects' centre, or the artboard's when there are none, making an empty group to
|
|
9280
|
+
* draw into). One undo step; selects the group (and enters it when empty). Returns its id.
|
|
9281
|
+
*/
|
|
9282
|
+
makeSymmetry(input, options = {}) {
|
|
9283
|
+
const symmetry = sanitizeVectorSymmetry({ ...input, center: input.center ?? { x: 0, y: 0 } });
|
|
9284
|
+
if (!symmetry) return { ok: false, message: `Unknown symmetry "${input.mode}": use ${VECTOR_SYMMETRY_MODES.join(", ")}.` };
|
|
9285
|
+
if (input.copies !== void 0 && !(input.copies >= 2 && input.copies <= 64)) return { ok: false, message: "copies must be from 2 to 64." };
|
|
9286
|
+
const ids = [...new Set(options.ids ?? this.selectedRoots())];
|
|
9287
|
+
for (const id2 of ids) {
|
|
9288
|
+
const n2 = this.getNode(id2);
|
|
9289
|
+
if (!n2) return { ok: false, message: `There is no node "${id2}".` };
|
|
9290
|
+
if (n2.locked) return { ok: false, message: `"${id2}" is locked; unlock it first.` };
|
|
9291
|
+
}
|
|
9292
|
+
const locs = ids.map((id2) => locateVectorNode(this.doc.nodes, id2));
|
|
9293
|
+
const parent = locs[0]?.parent ?? null;
|
|
9294
|
+
if (locs.some((l) => (l.parent?.id ?? null) !== (parent?.id ?? null))) return { ok: false, message: "The objects must share a parent (pick objects at one level)." };
|
|
9295
|
+
const b = unionBounds(ids.map((id2) => vectorNodeBounds(this.getNode(id2))));
|
|
9296
|
+
const center = input.center ?? (b ? { x: b.x + b.width / 2, y: b.y + b.height / 2 } : { x: this.doc.width / 2, y: this.doc.height / 2 });
|
|
9297
|
+
const id = this.newId();
|
|
9298
|
+
const group = { id, type: "group", name: input.name ?? "Symmetry", symmetry: { ...symmetry, center }, children: [] };
|
|
9299
|
+
const order = ids.slice().sort((a, c) => locs[ids.indexOf(a)].index - locs[ids.indexOf(c)].index);
|
|
9300
|
+
const set = new Set(order);
|
|
9301
|
+
this.change("Make Symmetry", () => {
|
|
9302
|
+
if (!order.length) this.setDoc([...this.doc.nodes, group]);
|
|
9303
|
+
else {
|
|
9304
|
+
const regroup = (list) => {
|
|
9305
|
+
const members = order.map((m) => list.find((n2) => n2.id === m));
|
|
9306
|
+
const top = Math.max(...members.map((m) => list.indexOf(m)));
|
|
9307
|
+
const out = [];
|
|
9308
|
+
list.forEach((n2, i) => {
|
|
9309
|
+
if (i === top) out.push({ ...group, children: members });
|
|
9310
|
+
if (!set.has(n2.id)) out.push(n2);
|
|
9311
|
+
});
|
|
9312
|
+
return out;
|
|
9313
|
+
};
|
|
9314
|
+
if (!parent) this.setDoc(regroup(this.doc.nodes));
|
|
9315
|
+
else this.setDoc(mapTree(this.doc.nodes, (n2) => n2.id === parent.id && n2.type === "group" ? { ...n2, children: regroup(n2.children) } : n2));
|
|
9316
|
+
}
|
|
9317
|
+
this.selection = [id];
|
|
9318
|
+
this.anchors = [];
|
|
9319
|
+
this.editingId = null;
|
|
9320
|
+
if (!order.length && !parent) this.symmetryTarget = id;
|
|
9321
|
+
});
|
|
9322
|
+
return { ok: true, id };
|
|
9323
|
+
}
|
|
9324
|
+
/** Symmetry groups among `ids` (default: the selection, or the group holding it). */
|
|
9325
|
+
symmetryTargets(ids) {
|
|
9326
|
+
const out = /* @__PURE__ */ new Map();
|
|
9327
|
+
for (const id of ids ?? this.selection) {
|
|
9328
|
+
const n2 = this.getNode(id);
|
|
9329
|
+
if (isVectorSymmetryGroup(n2)) out.set(n2.id, n2);
|
|
9330
|
+
else if (!ids) {
|
|
9331
|
+
const p = locateVectorNode(this.doc.nodes, id)?.parent;
|
|
9332
|
+
if (isVectorSymmetryGroup(p)) out.set(p.id, p);
|
|
9333
|
+
}
|
|
9334
|
+
}
|
|
9335
|
+
return [...out.values()];
|
|
9336
|
+
}
|
|
9337
|
+
/** Changes symmetry groups (default: the selected one, or the one holding the selection): mode, centre (the group's space), rotation, radial copies and mirroring. One undo step (merged while `merge` is the same key). */
|
|
9338
|
+
setSymmetry(patch, options = {}) {
|
|
9339
|
+
if (options.ids) {
|
|
9340
|
+
for (const id of options.ids) if (!isVectorSymmetryGroup(this.getNode(id))) return { ok: false, message: `"${id}" is not a symmetry group (make one with vector.makeSymmetry).` };
|
|
9341
|
+
}
|
|
9342
|
+
const groups = this.symmetryTargets(options.ids);
|
|
9343
|
+
if (!groups.length) return { ok: false, message: "Select a symmetry group (or something in one)." };
|
|
9344
|
+
if (patch.mode !== void 0 && !VECTOR_SYMMETRY_MODES.includes(patch.mode)) return { ok: false, message: `Unknown symmetry "${patch.mode}": use ${VECTOR_SYMMETRY_MODES.join(", ")}.` };
|
|
9345
|
+
if (patch.copies !== void 0 && !(patch.copies >= 2 && patch.copies <= 64)) return { ok: false, message: "copies must be from 2 to 64." };
|
|
9346
|
+
const next = new Map(groups.map((g) => [g.id, sanitizeVectorSymmetry({ ...g.symmetry, ...patch })]));
|
|
9347
|
+
if ([...next.values()].some((v) => !v)) return { ok: false, message: "center must be { x, y } numbers." };
|
|
9348
|
+
this.change(
|
|
9349
|
+
"Symmetry",
|
|
9350
|
+
() => {
|
|
9351
|
+
this.setDoc(mapTree(this.doc.nodes, (n2) => next.has(n2.id) && n2.type === "group" ? { ...n2, symmetry: next.get(n2.id) } : n2));
|
|
9352
|
+
},
|
|
9353
|
+
options.merge
|
|
9354
|
+
);
|
|
9355
|
+
return { ok: true };
|
|
9356
|
+
}
|
|
9357
|
+
/**
|
|
9358
|
+
* Release Symmetry: the groups stop repeating their children. With `expand`, the copies become
|
|
9359
|
+
* real objects in the group (new ids); otherwise they go. One undo step. Returns the ids of the
|
|
9360
|
+
* objects added by expanding.
|
|
9361
|
+
*/
|
|
9362
|
+
releaseSymmetry(options = {}) {
|
|
9363
|
+
const groups = this.symmetryTargets(options.ids);
|
|
9364
|
+
if (!groups.length) return { ok: false, message: "Select a symmetry group (or something in one)." };
|
|
9365
|
+
const added = [];
|
|
9366
|
+
const next = /* @__PURE__ */ new Map();
|
|
9367
|
+
for (const g of groups) {
|
|
9368
|
+
const { symmetry: _s, ...rest } = g;
|
|
9369
|
+
if (!options.expand) {
|
|
9370
|
+
next.set(g.id, rest);
|
|
9371
|
+
continue;
|
|
9372
|
+
}
|
|
9373
|
+
const drawn = vectorSymmetryDrawn(g);
|
|
9374
|
+
const fresh = (n2) => {
|
|
9375
|
+
const id = this.newId();
|
|
9376
|
+
added.push(id);
|
|
9377
|
+
const { locked: _l, ...plain2 } = n2;
|
|
9378
|
+
return plain2.type === "group" ? { ...plain2, id, children: plain2.children.map(fresh) } : { ...plain2, id };
|
|
9379
|
+
};
|
|
9380
|
+
next.set(g.id, { ...rest, children: [...g.children, ...drawn.children.slice(g.children.length).map(fresh)] });
|
|
9381
|
+
}
|
|
9382
|
+
this.change(options.expand ? "Expand Symmetry" : "Release Symmetry", () => {
|
|
9383
|
+
this.setDoc(mapTree(this.doc.nodes, (n2) => next.get(n2.id) ?? n2));
|
|
9384
|
+
if (this.symmetryTarget && next.has(this.symmetryTarget)) this.symmetryTarget = null;
|
|
9385
|
+
});
|
|
9386
|
+
return { ok: true, ids: added.filter((id) => !!this.getNode(id)) };
|
|
9387
|
+
}
|
|
9388
|
+
/** Enters a top-level symmetry group: new pen, pencil, shape and text art goes into it (mirrored as it is drawn) until `exitSymmetry` or Escape. */
|
|
9389
|
+
enterSymmetry(id) {
|
|
9390
|
+
const n2 = this.doc.nodes.find((x) => x.id === id);
|
|
9391
|
+
if (!isVectorSymmetryGroup(n2)) return { ok: false, message: `"${id}" is not a top-level symmetry group.` };
|
|
9392
|
+
if (n2.transform) return { ok: false, message: "Drawing into a turned symmetry group is not supported; draw beside it and move the art in." };
|
|
9393
|
+
this.symmetryTarget = id;
|
|
9394
|
+
this.selection = [id];
|
|
9395
|
+
this.notify();
|
|
9396
|
+
return { ok: true };
|
|
9397
|
+
}
|
|
9398
|
+
/** Stops drawing into the entered symmetry group. */
|
|
9399
|
+
exitSymmetry() {
|
|
9400
|
+
if (!this.symmetryTarget) return;
|
|
9401
|
+
this.symmetryTarget = null;
|
|
9402
|
+
this.notify();
|
|
9403
|
+
}
|
|
9404
|
+
// -----------------------------------------------------------------------------------------
|
|
9205
9405
|
// PDF
|
|
9206
9406
|
/**
|
|
9207
9407
|
* The document as a vector PDF (see `vectorDocumentToPdf`): one page of the artboard, or a page
|
|
@@ -11673,7 +11873,7 @@ var VectorEditorController = class _VectorEditorController {
|
|
|
11673
11873
|
}
|
|
11674
11874
|
const pt2 = this.snapDrawn(p, null, input, () => this.drawingTargets(null));
|
|
11675
11875
|
const node = { id: this.newId(), type: "path", name: "Path", ...this.styleFor(true), subpaths: [{ anchors: [{ x: pt2.x, y: pt2.y }], closed: false }] };
|
|
11676
|
-
this.
|
|
11876
|
+
this.addDrawn(node);
|
|
11677
11877
|
this.pen = { nodeId: node.id, subpath: 0 };
|
|
11678
11878
|
this.selection = [node.id];
|
|
11679
11879
|
this.editingId = node.id;
|
|
@@ -11694,7 +11894,7 @@ var VectorEditorController = class _VectorEditorController {
|
|
|
11694
11894
|
strokeLinejoin: this.defaults.strokeLinejoin ?? "round",
|
|
11695
11895
|
subpaths: [{ anchors: [{ x: p.x, y: p.y }], closed: false }]
|
|
11696
11896
|
};
|
|
11697
|
-
this.
|
|
11897
|
+
this.addDrawn(node);
|
|
11698
11898
|
const lazy = new LazyMouse(this.editing.pencilSmoothing * VECTOR_PENCIL_STRING_PX / this.viewport.zoom);
|
|
11699
11899
|
lazy.push([p.x, p.y]);
|
|
11700
11900
|
const mode = this.editing.pencilPressure;
|
|
@@ -11712,7 +11912,7 @@ var VectorEditorController = class _VectorEditorController {
|
|
|
11712
11912
|
const kind = this.tool === "frame" ? "rect" : this.tool;
|
|
11713
11913
|
const node = this.createShapeNode({ kind, x: start.x, y: start.y, width: 0, height: 0 });
|
|
11714
11914
|
if (this.tool === "frame") Object.assign(node, { fill: "#ffffff", stroke: "#a3a3a3", strokeWidth: 1 / this.viewport.zoom });
|
|
11715
|
-
this.
|
|
11915
|
+
this.addDrawn(node);
|
|
11716
11916
|
this.drag = { kind: "shape", tool: this.tool, start, nodeId: node.id, before, targets };
|
|
11717
11917
|
this.interaction = { type: "draw", tool: this.tool, nodeId: node.id, bounds: { x: start.x, y: start.y, width: 0, height: 0 } };
|
|
11718
11918
|
this.notify(true);
|
|
@@ -12855,7 +13055,7 @@ var VectorEditorController = class _VectorEditorController {
|
|
|
12855
13055
|
this.endTextEdit();
|
|
12856
13056
|
const before = this.snapshot();
|
|
12857
13057
|
if (replace) this.setDoc(mapTree(this.doc.nodes, (n2) => n2.id === replace ? node : n2));
|
|
12858
|
-
else this.
|
|
13058
|
+
else this.addDrawn(node);
|
|
12859
13059
|
this.selection = [node.id];
|
|
12860
13060
|
this.anchors = [];
|
|
12861
13061
|
this.textEdit = { nodeId: node.id, anchor: 0, focus: 0, before, key: `text-edit:${node.id}:${++this.textEditCount}`, created: true };
|
|
@@ -13409,6 +13609,7 @@ var VectorEditorController = class _VectorEditorController {
|
|
|
13409
13609
|
case "Escape":
|
|
13410
13610
|
if (this.drag) this.cancelDrag();
|
|
13411
13611
|
else if (this.trackingPoints.length) this.clearTracking();
|
|
13612
|
+
else if (this.symmetryTarget && !this.pen) this.exitSymmetry();
|
|
13412
13613
|
else if (this.widthEdit) this.closeWidthPointEdit();
|
|
13413
13614
|
else if (this.tool === "width" && this.widthPoints.length) {
|
|
13414
13615
|
this.widthPoints = [];
|
|
@@ -13602,11 +13803,12 @@ function pencilPressureProfile(points, pressures) {
|
|
|
13602
13803
|
}
|
|
13603
13804
|
|
|
13604
13805
|
// src/vector/commands.ts
|
|
13605
|
-
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. envelope: style (a warp preset: arc|arcLower|arcUpper|arch|bulge|shellLower|shellUpper|flag|wave|fish|rise|fisheye|inflate|squeeze|twist, or mesh), bend, horizontal, vertical (percent, \u2212100\u2026100), orientation horizontal|vertical, rows, columns, mesh { us, vs, points } (node space; prefer vector.envelope).";
|
|
13806
|
+
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. contour: direction inside|outside|center, steps, offset, fillColor / strokeColor (end colours, null keeps the colour), acceleration (\u2212100\u2026100), join. blockShadow: angle (degrees, 0 right, 90 down), distance, color (null: the shape fill colour), opacity, endOpacity (percent; lower than opacity fades it into a long shadow). envelope: style (a warp preset: arc|arcLower|arcUpper|arch|bulge|shellLower|shellUpper|flag|wave|fish|rise|fisheye|inflate|squeeze|twist, or mesh), bend, horizontal, vertical (percent, \u2212100\u2026100), orientation horizontal|vertical, rows, columns, mesh { us, vs, points } (node space; prefer vector.envelope).";
|
|
13606
13807
|
var fail = (message) => {
|
|
13607
13808
|
throw new Error(message);
|
|
13608
13809
|
};
|
|
13609
13810
|
var IDS = { type: "array", items: { type: "string" }, description: "Node ids (default: the selection)." };
|
|
13811
|
+
var PARENT_ID = { type: "string", description: "A group to add into, on top of its children (default: the document). Coordinates are the group's own space (the document's for an unturned top-level group)." };
|
|
13610
13812
|
var ANCHORS = {
|
|
13611
13813
|
type: "array",
|
|
13612
13814
|
items: {
|
|
@@ -13746,6 +13948,11 @@ function createVectorCommands(controller, options = {}) {
|
|
|
13746
13948
|
const prefix = options.prefix ?? "vector.";
|
|
13747
13949
|
const group = options.group ?? "Vector";
|
|
13748
13950
|
const base = { group, ...options.scope ? { scope: options.scope } : {} };
|
|
13951
|
+
const parentOf = (parentId) => {
|
|
13952
|
+
if (parentId === void 0) return {};
|
|
13953
|
+
if (controller.getNode(parentId)?.type !== "group") fail(`"${parentId}" is not a group to add into.`);
|
|
13954
|
+
return { parentId };
|
|
13955
|
+
};
|
|
13749
13956
|
const hasSelection = () => controller.getState().selection.length ? true : "Nothing is selected.";
|
|
13750
13957
|
const ids = (params) => {
|
|
13751
13958
|
const list2 = params?.ids ?? controller.getState().selection;
|
|
@@ -13792,7 +13999,8 @@ function createVectorCommands(controller, options = {}) {
|
|
|
13792
13999
|
...isVectorMaskGroup(n2) ? { mask: vectorMaskSummary(n2) } : {},
|
|
13793
14000
|
...isVectorFrame(n2) ? { frameRect: n2.frame } : {},
|
|
13794
14001
|
...n2.resizing ? { resizing: n2.resizing } : {},
|
|
13795
|
-
...n2.type === "path" && n2.connector ? { connector: n2.connector } : {}
|
|
14002
|
+
...n2.type === "path" && n2.connector ? { connector: n2.connector } : {},
|
|
14003
|
+
...n2.type === "group" && n2.symmetry ? { symmetry: n2.symmetry } : {}
|
|
13796
14004
|
});
|
|
13797
14005
|
if (n2.type === "group") visit(n2.children, depth + 1);
|
|
13798
14006
|
}
|
|
@@ -14673,6 +14881,89 @@ function createVectorCommands(controller, options = {}) {
|
|
|
14673
14881
|
issues: state.constraintIssues
|
|
14674
14882
|
};
|
|
14675
14883
|
};
|
|
14884
|
+
const SYMMETRY_PROPS = {
|
|
14885
|
+
mode: { type: "string", enum: VECTOR_SYMMETRY_MODES, description: "vertical (mirror left / right), horizontal (top / bottom), dual (four quarters), diagonal, or radial (turns round the centre)." },
|
|
14886
|
+
center: { type: "object", properties: { x: { type: "number", description: "Document units (the group's space)." }, y: { type: "number", description: "Document units (the group's space)." } }, required: ["x", "y"], additionalProperties: false, description: "Where the axes cross." },
|
|
14887
|
+
rotation: { type: "number", description: "Turn of the axes, degrees clockwise (default 0)." },
|
|
14888
|
+
copies: { type: "integer", minimum: 2, maximum: 64, description: "Radial: how many turns round the circle (default 6)." },
|
|
14889
|
+
mirror: { type: "boolean", description: "Radial: mirror each turn too, like a kaleidoscope (default false)." }
|
|
14890
|
+
};
|
|
14891
|
+
const symmetryResult = (id) => {
|
|
14892
|
+
const n2 = controller.getNode(id);
|
|
14893
|
+
return n2?.type === "group" && n2.symmetry ? { id, symmetry: n2.symmetry, children: n2.children.map((c) => c.id) } : fail(`"${id}" is not a symmetry group.`);
|
|
14894
|
+
};
|
|
14895
|
+
const symmetryCommands = () => [
|
|
14896
|
+
{
|
|
14897
|
+
...base,
|
|
14898
|
+
id: `${prefix}makeSymmetry`,
|
|
14899
|
+
label: "Make Symmetry\u2026",
|
|
14900
|
+
keywords: ["symmetry", "mirror", "kaleidoscope", "radial", "mandala", "reflect", "live symmetry"],
|
|
14901
|
+
description: "Puts objects sharing a parent (`ids`, default the selection) into a live symmetry group: it draws them with their mirrored or rotated copies, which follow every edit of the originals. center defaults to the objects' centre (the artboard's with no objects: an empty group to add art to with parentId). One undo step. Returns { id, symmetry, children }.",
|
|
14902
|
+
params: { type: "object", properties: { ids: { ...IDS, description: "Objects to repeat (default: the selection; [] for an empty group)." }, ...SYMMETRY_PROPS, name: { type: "string", description: 'Group name (default "Symmetry").' } }, required: ["mode"], additionalProperties: false },
|
|
14903
|
+
undoable: true,
|
|
14904
|
+
run: (_ctx, params) => {
|
|
14905
|
+
const { ids: list2, ...input } = params;
|
|
14906
|
+
const r = controller.makeSymmetry(input, list2 ? { ids: list2 } : {});
|
|
14907
|
+
if (!r.ok) fail(r.message);
|
|
14908
|
+
return symmetryResult(r.id);
|
|
14909
|
+
}
|
|
14910
|
+
},
|
|
14911
|
+
{
|
|
14912
|
+
...base,
|
|
14913
|
+
id: `${prefix}setSymmetry`,
|
|
14914
|
+
label: "Symmetry Options\u2026",
|
|
14915
|
+
keywords: ["symmetry", "mirror", "radial", "axis", "copies"],
|
|
14916
|
+
description: "Changes symmetry groups (`ids`, default the selected one or the one holding the selection): mode, center, rotation, copies, mirror. Pass at least one. One undo step. Returns { groups }.",
|
|
14917
|
+
params: { type: "object", properties: { ids: { ...IDS, description: "Symmetry group ids (default: the selection)." }, ...SYMMETRY_PROPS }, additionalProperties: false },
|
|
14918
|
+
undoable: true,
|
|
14919
|
+
run: (_ctx, params) => {
|
|
14920
|
+
const { ids: list2, ...patch } = params ?? {};
|
|
14921
|
+
if (!Object.keys(patch).length) fail("Pass at least one of mode, center, rotation, copies, mirror.");
|
|
14922
|
+
check(controller.setSymmetry(patch, list2 ? { ids: list2 } : {}));
|
|
14923
|
+
const ids2 = list2 ?? controller.getState().selection.filter((id) => controller.getNode(id)?.type === "group");
|
|
14924
|
+
return { groups: ids2.filter((id) => controller.getNode(id)?.symmetry).map(symmetryResult) };
|
|
14925
|
+
}
|
|
14926
|
+
},
|
|
14927
|
+
{
|
|
14928
|
+
...base,
|
|
14929
|
+
id: `${prefix}releaseSymmetry`,
|
|
14930
|
+
label: "Release Symmetry",
|
|
14931
|
+
keywords: ["symmetry", "release", "expand", "bake"],
|
|
14932
|
+
description: "Stops symmetry groups repeating their children. With expand: true the copies become real, editable objects in the group (new ids); otherwise they go. One undo step. Returns { ids } of the objects expanding added.",
|
|
14933
|
+
params: { type: "object", properties: { ids: { ...IDS, description: "Symmetry group ids (default: the selection)." }, expand: { type: "boolean", description: "Keep the copies as real objects (default false)." } }, additionalProperties: false },
|
|
14934
|
+
undoable: true,
|
|
14935
|
+
enabled: enabledFor,
|
|
14936
|
+
run: (_ctx, params) => {
|
|
14937
|
+
const r = controller.releaseSymmetry({ ...params?.ids ? { ids: params.ids } : {}, ...params?.expand ? { expand: true } : {} });
|
|
14938
|
+
check(r);
|
|
14939
|
+
return { ids: r.ids ?? [] };
|
|
14940
|
+
}
|
|
14941
|
+
},
|
|
14942
|
+
{
|
|
14943
|
+
...base,
|
|
14944
|
+
id: `${prefix}enterSymmetry`,
|
|
14945
|
+
label: "Draw Inside Symmetry",
|
|
14946
|
+
keywords: ["symmetry", "draw inside", "mirror drawing"],
|
|
14947
|
+
description: "Hands the canvas to the user drawing inside a top-level symmetry group: new pen, pencil, shape and text art goes into it, mirrored as it is drawn, until vector.exitSymmetry or Escape. Returns { id }.",
|
|
14948
|
+
params: { type: "object", properties: { id: { type: "string", description: "The symmetry group." } }, required: ["id"], additionalProperties: false },
|
|
14949
|
+
run: (_ctx, params) => {
|
|
14950
|
+
check(controller.enterSymmetry(params.id));
|
|
14951
|
+
return { id: params.id };
|
|
14952
|
+
}
|
|
14953
|
+
},
|
|
14954
|
+
{
|
|
14955
|
+
...base,
|
|
14956
|
+
id: `${prefix}exitSymmetry`,
|
|
14957
|
+
label: "Stop Drawing Inside Symmetry",
|
|
14958
|
+
keywords: ["symmetry", "exit"],
|
|
14959
|
+
description: "New art goes on top of the document again (no symmetry group is entered). Returns { ok: true }.",
|
|
14960
|
+
params: { type: "object", properties: {}, additionalProperties: false },
|
|
14961
|
+
run: () => {
|
|
14962
|
+
controller.exitSymmetry();
|
|
14963
|
+
return { ok: true };
|
|
14964
|
+
}
|
|
14965
|
+
}
|
|
14966
|
+
];
|
|
14676
14967
|
const pdfCommands = () => [
|
|
14677
14968
|
{
|
|
14678
14969
|
...base,
|
|
@@ -15431,12 +15722,16 @@ function createVectorCommands(controller, options = {}) {
|
|
|
15431
15722
|
points: { type: "integer", minimum: 3 },
|
|
15432
15723
|
innerRatio: { type: "number", minimum: 0, maximum: 1 },
|
|
15433
15724
|
name: { type: "string" },
|
|
15725
|
+
parentId: PARENT_ID,
|
|
15434
15726
|
...STYLE_PROPS
|
|
15435
15727
|
},
|
|
15436
15728
|
required: ["kind", "x", "y", "width", "height"]
|
|
15437
15729
|
},
|
|
15438
15730
|
undoable: true,
|
|
15439
|
-
run: (_ctx, params) =>
|
|
15731
|
+
run: (_ctx, params) => {
|
|
15732
|
+
const { parentId, ...input } = params;
|
|
15733
|
+
return { id: controller.addShape(input, parentOf(parentId)) };
|
|
15734
|
+
}
|
|
15440
15735
|
},
|
|
15441
15736
|
{
|
|
15442
15737
|
...base,
|
|
@@ -15444,10 +15739,10 @@ function createVectorCommands(controller, options = {}) {
|
|
|
15444
15739
|
label: "Add Path\u2026",
|
|
15445
15740
|
keywords: ["svg", "path data", "bezier", "curve"],
|
|
15446
15741
|
description: "Adds a path from SVG path data (`d`), in document units.",
|
|
15447
|
-
params: { type: "object", properties: { d: { type: "string" }, name: { type: "string" }, ...STYLE_PROPS }, required: ["d"] },
|
|
15742
|
+
params: { type: "object", properties: { d: { type: "string" }, name: { type: "string" }, parentId: PARENT_ID, ...STYLE_PROPS }, required: ["d"] },
|
|
15448
15743
|
undoable: true,
|
|
15449
15744
|
run: (_ctx, params) => {
|
|
15450
|
-
const id = controller.addPath(params.d, { ...pickStyle(params), ...params.name ? { name: params.name } : {} });
|
|
15745
|
+
const id = controller.addPath(params.d, { ...pickStyle(params), ...params.name ? { name: params.name } : {} }, parentOf(params.parentId));
|
|
15451
15746
|
const node = controller.getNode(id);
|
|
15452
15747
|
if (node?.type === "path" && !node.subpaths.length) {
|
|
15453
15748
|
controller.undo();
|
|
@@ -15504,6 +15799,7 @@ function createVectorCommands(controller, options = {}) {
|
|
|
15504
15799
|
...traceCommands(),
|
|
15505
15800
|
...lottieCommands(),
|
|
15506
15801
|
...pdfCommands(),
|
|
15802
|
+
...symmetryCommands(),
|
|
15507
15803
|
{
|
|
15508
15804
|
...base,
|
|
15509
15805
|
id: `${prefix}setCorners`,
|
|
@@ -16495,6 +16791,8 @@ export {
|
|
|
16495
16791
|
VECTOR_STROKE_SETTING_KEYS,
|
|
16496
16792
|
VECTOR_STYLE_KEYS,
|
|
16497
16793
|
VECTOR_SYMBOL_MAX_DEPTH,
|
|
16794
|
+
VECTOR_SYMMETRY_MODES,
|
|
16795
|
+
VECTOR_SYMMETRY_MODE_LABELS,
|
|
16498
16796
|
VECTOR_TEXT_ALIGNS,
|
|
16499
16797
|
VECTOR_TEXT_ALIGN_LABELS,
|
|
16500
16798
|
VECTOR_TEXT_ALIGN_OPTIONS,
|
|
@@ -16680,6 +16978,7 @@ export {
|
|
|
16680
16978
|
isVectorMaskType,
|
|
16681
16979
|
isVectorMeshGradient,
|
|
16682
16980
|
isVectorShadedPaint,
|
|
16981
|
+
isVectorSymmetryGroup,
|
|
16683
16982
|
isVectorTextTarget,
|
|
16684
16983
|
joinSubpaths,
|
|
16685
16984
|
knifePath,
|
|
@@ -16788,6 +17087,7 @@ export {
|
|
|
16788
17087
|
sanitizeVectorShadedPaint,
|
|
16789
17088
|
sanitizeVectorStrokeSettings,
|
|
16790
17089
|
sanitizeVectorStrokes,
|
|
17090
|
+
sanitizeVectorSymmetry,
|
|
16791
17091
|
sanitizeVectorTextFields,
|
|
16792
17092
|
sanitizeVectorTextFrame,
|
|
16793
17093
|
sanitizeWidthProfile,
|
|
@@ -16820,6 +17120,7 @@ export {
|
|
|
16820
17120
|
subpathSegmentCount,
|
|
16821
17121
|
subpathToMorphContour,
|
|
16822
17122
|
subpathsToBezier,
|
|
17123
|
+
sweepPath,
|
|
16823
17124
|
taperWaveFactor,
|
|
16824
17125
|
tintVectorNode,
|
|
16825
17126
|
toVectorKeyInput,
|
|
@@ -16831,6 +17132,7 @@ export {
|
|
|
16831
17132
|
transformVectorNode,
|
|
16832
17133
|
transformVectorPaint,
|
|
16833
17134
|
transformVectorShadedPaint,
|
|
17135
|
+
transformVectorSymmetry,
|
|
16834
17136
|
translateAnchor,
|
|
16835
17137
|
translateMatrix,
|
|
16836
17138
|
trimIntervals,
|
|
@@ -16995,6 +17297,9 @@ export {
|
|
|
16995
17297
|
vectorStrokes,
|
|
16996
17298
|
vectorSymbolUses,
|
|
16997
17299
|
vectorSymbolsUsedIn,
|
|
17300
|
+
vectorSymmetryAxes,
|
|
17301
|
+
vectorSymmetryDrawn,
|
|
17302
|
+
vectorSymmetryMatrices,
|
|
16998
17303
|
vectorTargetPaint,
|
|
16999
17304
|
vectorTextBoxOutline,
|
|
17000
17305
|
vectorTextCaret,
|