@pixerate/editor 0.132.0 → 0.134.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/dist/animation-editor/index.cjs +55 -55
- package/dist/animation-editor/index.d.cts +4 -4
- package/dist/animation-editor/index.d.ts +4 -4
- package/dist/animation-editor/index.js +2 -2
- package/dist/{bezier-oCBfrGDG.d.cts → bezier-J8i4uqSH.d.cts} +1 -1
- package/dist/{bezier-0IHDCvv_.d.ts → bezier-lNEOp0Jx.d.ts} +1 -1
- package/dist/canvas/index.d.cts +7 -7
- package/dist/canvas/index.d.ts +7 -7
- package/dist/{chunk-MZXQTKUM.cjs → chunk-24ATT2PE.cjs} +10 -6
- package/dist/chunk-24ATT2PE.cjs.map +1 -0
- package/dist/{chunk-AHUYMDYW.js → chunk-2HC4DRF4.js} +10 -6
- package/dist/chunk-2HC4DRF4.js.map +1 -0
- package/dist/{chunk-YRZ6NVE3.js → chunk-6CTZAGZ2.js} +235 -4
- package/dist/chunk-6CTZAGZ2.js.map +1 -0
- package/dist/{chunk-ECVI5QRE.js → chunk-7RJ6P7MI.js} +2 -2
- package/dist/{chunk-G5FX56KX.js → chunk-ESIWZMMK.js} +51 -11
- package/dist/chunk-ESIWZMMK.js.map +1 -0
- package/dist/{chunk-IEYXYMRQ.js → chunk-HHTCDFZC.js} +99 -5
- package/dist/chunk-HHTCDFZC.js.map +1 -0
- package/dist/{chunk-W6M7C7R3.cjs → chunk-NVTHUPJ6.cjs} +236 -5
- package/dist/chunk-NVTHUPJ6.cjs.map +1 -0
- package/dist/{chunk-OYPJGGF3.cjs → chunk-T6TV6HY6.cjs} +36 -36
- package/dist/{chunk-OYPJGGF3.cjs.map → chunk-T6TV6HY6.cjs.map} +1 -1
- package/dist/{chunk-55UEZIU4.cjs → chunk-YAFS2QFZ.cjs} +231 -191
- package/dist/chunk-YAFS2QFZ.cjs.map +1 -0
- package/dist/{chunk-YYJKIESX.cjs → chunk-Z2H7KECK.cjs} +153 -59
- package/dist/chunk-Z2H7KECK.cjs.map +1 -0
- package/dist/effects/index.d.cts +4 -4
- package/dist/effects/index.d.ts +4 -4
- package/dist/{export-D-gkjBkB.d.cts → export-BGdT02aL.d.cts} +10 -10
- package/dist/{export-CfAogLEr.d.cts → export-DMeG6E06.d.ts} +1 -1
- package/dist/{export-ByJvAvR7.d.ts → export-Dng22YB8.d.ts} +10 -10
- package/dist/{export-Crl82sbE.d.ts → export-KzubBKo7.d.cts} +1 -1
- package/dist/{helpers-BCd2-PAR.d.ts → helpers-Coa4e2j_.d.ts} +35 -1
- package/dist/{helpers-CoIeXQnW.d.cts → helpers-DHl28yLO.d.cts} +35 -1
- package/dist/image-editor/index.cjs +983 -874
- package/dist/image-editor/index.cjs.map +1 -1
- package/dist/image-editor/index.d.cts +32 -13
- package/dist/image-editor/index.d.ts +32 -13
- package/dist/image-editor/index.js +124 -15
- package/dist/image-editor/index.js.map +1 -1
- package/dist/{opentype-BDahNRTe.d.cts → opentype-BWR7Qv8W.d.cts} +1 -1
- package/dist/{opentype-BQFEvy-t.d.ts → opentype-Dfcx6wFx.d.ts} +1 -1
- package/dist/paint/index.cjs +8 -2
- package/dist/paint/index.cjs.map +1 -1
- package/dist/paint/index.d.cts +14 -3
- package/dist/paint/index.d.ts +14 -3
- package/dist/paint/index.js +7 -1
- package/dist/paint-editor/index.cjs +78 -78
- package/dist/paint-editor/index.d.cts +7 -7
- package/dist/paint-editor/index.d.ts +7 -7
- package/dist/paint-editor/index.js +3 -3
- package/dist/{pathfinder-DaVdT8jq.d.ts → pathfinder-Celbi3e6.d.ts} +1 -1
- package/dist/{pathfinder-01ZgAwqV.d.cts → pathfinder-D8KQ6blQ.d.cts} +1 -1
- package/dist/{pool-D2A3WTt9.d.ts → pool-8JZGWHvR.d.ts} +1 -1
- package/dist/{pool-D6a45MoE.d.cts → pool-BfuxBKTd.d.cts} +1 -1
- package/dist/{rand-pQQ2sJTk.d.ts → rand-BaqEOs1Y.d.ts} +17 -4
- package/dist/{rand-DTXAssW1.d.cts → rand-DdpFzCo6.d.cts} +17 -4
- package/dist/raster/index.cjs +2 -2
- package/dist/raster/index.d.cts +4 -4
- package/dist/raster/index.d.ts +4 -4
- package/dist/raster/index.js +1 -1
- package/dist/{svg-DELNVerw.d.ts → svg-CxxqG3_W.d.ts} +2 -2
- package/dist/{svg-CcDz7Zq2.d.cts → svg-pwXWq6s2.d.cts} +2 -2
- package/dist/{tools-BFvkFnRj.d.cts → tools-3EBjR91b.d.cts} +1 -1
- package/dist/{tools-D7ws-OKL.d.ts → tools-y1M6O3UT.d.ts} +1 -1
- package/dist/vector/index.cjs +1642 -1046
- package/dist/vector/index.cjs.map +1 -1
- package/dist/vector/index.d.cts +275 -93
- package/dist/vector/index.d.ts +275 -93
- package/dist/vector/index.js +607 -11
- package/dist/vector/index.js.map +1 -1
- package/dist/video-editor/index.d.cts +4 -4
- package/dist/video-editor/index.d.ts +4 -4
- package/dist/{warp-2N9wkOkL.d.ts → warp-C1gwu2G_.d.ts} +1 -1
- package/dist/{warp-DErXW5rz.d.cts → warp-Ceqdz7kj.d.cts} +1 -1
- package/package.json +1 -1
- package/skills/pixerate-image-editor/SKILL.md +1 -1
- package/skills/pixerate-image-editor/references/retouching.md +3 -2
- package/skills/pixerate-vector/SKILL.md +12 -53
- package/skills/pixerate-vector/references/pitfalls.md +62 -0
- package/dist/chunk-55UEZIU4.cjs.map +0 -1
- package/dist/chunk-AHUYMDYW.js.map +0 -1
- package/dist/chunk-G5FX56KX.js.map +0 -1
- package/dist/chunk-IEYXYMRQ.js.map +0 -1
- package/dist/chunk-MZXQTKUM.cjs.map +0 -1
- package/dist/chunk-W6M7C7R3.cjs.map +0 -1
- package/dist/chunk-YRZ6NVE3.js.map +0 -1
- package/dist/chunk-YYJKIESX.cjs.map +0 -1
- /package/dist/{chunk-ECVI5QRE.js.map → chunk-7RJ6P7MI.js.map} +0 -0
package/dist/vector/index.js
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
applyHomography,
|
|
13
13
|
homographyFromPoints,
|
|
14
14
|
homographyKeepsQuad,
|
|
15
|
+
invertHomography,
|
|
15
16
|
orderQuad,
|
|
16
17
|
solve8
|
|
17
18
|
} from "../chunk-GX332W2C.js";
|
|
@@ -42,7 +43,7 @@ import {
|
|
|
42
43
|
reverseMorphContour,
|
|
43
44
|
subpathToMorphContour,
|
|
44
45
|
turnMorphContour
|
|
45
|
-
} from "../chunk-
|
|
46
|
+
} from "../chunk-7RJ6P7MI.js";
|
|
46
47
|
import {
|
|
47
48
|
DEFAULT_VECTOR_FONT,
|
|
48
49
|
IDENTITY_MATRIX,
|
|
@@ -83,6 +84,7 @@ import {
|
|
|
83
84
|
VECTOR_PARAGRAPH_STYLE_KEYS,
|
|
84
85
|
VECTOR_PATHFINDER_OPERATIONS,
|
|
85
86
|
VECTOR_PATH_TEXT_BASELINES,
|
|
87
|
+
VECTOR_PERSPECTIVE_PLANES,
|
|
86
88
|
VECTOR_PRESSURE_NOMINAL,
|
|
87
89
|
VECTOR_SPATIAL_MIN,
|
|
88
90
|
VECTOR_STROKE_GRADIENT_MODES,
|
|
@@ -206,6 +208,7 @@ import {
|
|
|
206
208
|
isVectorMaskActive,
|
|
207
209
|
isVectorMaskGroup,
|
|
208
210
|
isVectorMaskType,
|
|
211
|
+
isVectorMasterPage,
|
|
209
212
|
isVectorMeshGradient,
|
|
210
213
|
isVectorShadedPaint,
|
|
211
214
|
isVectorSymmetryGroup,
|
|
@@ -271,6 +274,7 @@ import {
|
|
|
271
274
|
rerouteVectorConnectors,
|
|
272
275
|
resizeWarpMesh,
|
|
273
276
|
resolveVectorLenses,
|
|
277
|
+
resolveVectorMasterPages,
|
|
274
278
|
resolveVectorSymbols,
|
|
275
279
|
reverseSubpath,
|
|
276
280
|
reverseVectorGradient,
|
|
@@ -317,6 +321,7 @@ import {
|
|
|
317
321
|
splitWarpMeshV,
|
|
318
322
|
starSubpath,
|
|
319
323
|
stripVectorLensViews,
|
|
324
|
+
stripVectorMasterArt,
|
|
320
325
|
stripVectorSymbolArt,
|
|
321
326
|
strokePositionPoint,
|
|
322
327
|
strokeWidthProfileOf,
|
|
@@ -411,6 +416,8 @@ import {
|
|
|
411
416
|
vectorMaskedGeometry,
|
|
412
417
|
vectorMaskedLocalBounds,
|
|
413
418
|
vectorMaskedShapes,
|
|
419
|
+
vectorMasterArt,
|
|
420
|
+
vectorMasterPages,
|
|
414
421
|
vectorMeshColorAt,
|
|
415
422
|
vectorMeshFromOutline,
|
|
416
423
|
vectorMeshLines,
|
|
@@ -425,6 +432,7 @@ import {
|
|
|
425
432
|
vectorNodeToBezier,
|
|
426
433
|
vectorNodesNear,
|
|
427
434
|
vectorOperandOperation,
|
|
435
|
+
vectorPages,
|
|
428
436
|
vectorPaintLayerNodes,
|
|
429
437
|
vectorPaintSolid,
|
|
430
438
|
vectorPaintToSvg,
|
|
@@ -493,7 +501,7 @@ import {
|
|
|
493
501
|
withVectorStrokes,
|
|
494
502
|
withVectorTargetPaint,
|
|
495
503
|
zigzagPaths
|
|
496
|
-
} from "../chunk-
|
|
504
|
+
} from "../chunk-HHTCDFZC.js";
|
|
497
505
|
import {
|
|
498
506
|
bezierPathBounds,
|
|
499
507
|
bezierPathToSvg,
|
|
@@ -834,6 +842,131 @@ function releaseVectorBlend(group, newId) {
|
|
|
834
842
|
return [...keys, group.transform ? transformVectorNode(path, m) : path];
|
|
835
843
|
}
|
|
836
844
|
|
|
845
|
+
// src/vector/perspective.ts
|
|
846
|
+
function vectorPerspectivePlanes(p) {
|
|
847
|
+
return p.vanishingPoints.length <= 1 ? ["floor", "side", "front"] : ["floor", "left", "right"];
|
|
848
|
+
}
|
|
849
|
+
function sanitizeVectorPerspective(value) {
|
|
850
|
+
if (!value || typeof value !== "object") return null;
|
|
851
|
+
const r = value;
|
|
852
|
+
const isPt = (v) => !!v && typeof v === "object" && Number.isFinite(v.x) && Number.isFinite(v.y);
|
|
853
|
+
if (!Array.isArray(r.vanishingPoints) || r.vanishingPoints.length < 1 || r.vanishingPoints.length > 3 || !r.vanishingPoints.every(isPt) || !isPt(r.origin)) return null;
|
|
854
|
+
const origin = { x: r.origin.x, y: r.origin.y };
|
|
855
|
+
const vps = r.vanishingPoints.map((v) => ({ x: v.x, y: v.y }));
|
|
856
|
+
if (vps.some((v) => Math.hypot(v.x - origin.x, v.y - origin.y) < 1e-6)) return null;
|
|
857
|
+
const out = { vanishingPoints: vps, origin };
|
|
858
|
+
if (typeof r.gridSize === "number" && r.gridSize > 0 && Number.isFinite(r.gridSize)) out.gridSize = Math.min(1e3, r.gridSize);
|
|
859
|
+
if (typeof r.extent === "number" && Number.isFinite(r.extent)) out.extent = Math.min(100, Math.max(1, Math.round(r.extent)));
|
|
860
|
+
if (r.visible === false) out.visible = false;
|
|
861
|
+
return out;
|
|
862
|
+
}
|
|
863
|
+
function towards(o, vp, want) {
|
|
864
|
+
const d = Math.hypot(vp.x - o.x, vp.y - o.y);
|
|
865
|
+
let a = 1 / d;
|
|
866
|
+
if (want === "right" ? vp.x - o.x < 0 : vp.y - o.y > 0) a = -a;
|
|
867
|
+
return [a * vp.x, a * vp.y, a];
|
|
868
|
+
}
|
|
869
|
+
function vectorPerspectivePlaneMap(p, plane) {
|
|
870
|
+
if (!vectorPerspectivePlanes(p).includes(plane)) return null;
|
|
871
|
+
const o = p.origin;
|
|
872
|
+
const [v1, v2, v3] = p.vanishingPoints;
|
|
873
|
+
const right = [1, 0, 0];
|
|
874
|
+
const up = v3 ? towards(o, v3, "up") : [0, -1, 0];
|
|
875
|
+
let x;
|
|
876
|
+
let y;
|
|
877
|
+
if (p.vanishingPoints.length <= 1) {
|
|
878
|
+
if (plane === "floor") [x, y] = [right, towards(o, v1, "up")];
|
|
879
|
+
else if (plane === "side") [x, y] = [towards(o, v1, "right"), up];
|
|
880
|
+
else [x, y] = [right, up];
|
|
881
|
+
} else if (plane === "floor") [x, y] = [towards(o, v2, "right"), towards(o, v1, "up")];
|
|
882
|
+
else if (plane === "left") [x, y] = [towards(o, v1, "right"), up];
|
|
883
|
+
else [x, y] = [towards(o, v2, "right"), up];
|
|
884
|
+
return [x[0], y[0], o.x, x[1], y[1], o.y, x[2], y[2], 1];
|
|
885
|
+
}
|
|
886
|
+
function vectorPerspectiveFlatToPlane(p, plane) {
|
|
887
|
+
const h = vectorPerspectivePlaneMap(p, plane);
|
|
888
|
+
if (!h) return null;
|
|
889
|
+
const o = p.origin;
|
|
890
|
+
return (q) => {
|
|
891
|
+
const u = q.x - o.x;
|
|
892
|
+
const v = o.y - q.y;
|
|
893
|
+
const w = h[6] * u + h[7] * v + h[8];
|
|
894
|
+
if (!(w > 1e-6)) return null;
|
|
895
|
+
return applyHomography(h, { x: u, y: v });
|
|
896
|
+
};
|
|
897
|
+
}
|
|
898
|
+
function vectorPerspectivePlaneToFlat(p, plane) {
|
|
899
|
+
const h = vectorPerspectivePlaneMap(p, plane);
|
|
900
|
+
const inv = h ? invertHomography(h) : null;
|
|
901
|
+
if (!inv) return null;
|
|
902
|
+
const o = p.origin;
|
|
903
|
+
return (q) => {
|
|
904
|
+
const f = applyHomography(inv, q);
|
|
905
|
+
if (!f) return null;
|
|
906
|
+
const w = h[6] * f.x + h[7] * f.y + h[8];
|
|
907
|
+
if (!(w > 1e-6)) return null;
|
|
908
|
+
return { x: o.x + f.x, y: o.y - f.y };
|
|
909
|
+
};
|
|
910
|
+
}
|
|
911
|
+
function vectorPerspectiveMapPath(p, plane, path) {
|
|
912
|
+
const f = vectorPerspectiveFlatToPlane(p, plane);
|
|
913
|
+
if (!f) return null;
|
|
914
|
+
let behind = false;
|
|
915
|
+
const out = mapBezierPath(
|
|
916
|
+
path,
|
|
917
|
+
(q) => {
|
|
918
|
+
const r = f(q);
|
|
919
|
+
if (!r) {
|
|
920
|
+
behind = true;
|
|
921
|
+
return q;
|
|
922
|
+
}
|
|
923
|
+
return r;
|
|
924
|
+
},
|
|
925
|
+
0.1
|
|
926
|
+
);
|
|
927
|
+
return behind ? null : out;
|
|
928
|
+
}
|
|
929
|
+
function vectorPerspectiveGridLines(p, plane) {
|
|
930
|
+
const h = vectorPerspectivePlaneMap(p, plane);
|
|
931
|
+
if (!h) return [];
|
|
932
|
+
const g = p.gridSize ?? 20;
|
|
933
|
+
const n2 = p.extent ?? 12;
|
|
934
|
+
const max = n2 * g;
|
|
935
|
+
const lo = (axis) => axis === "y" && plane !== "floor" ? 0 : -max;
|
|
936
|
+
const w = (u, v) => h[6] * u + h[7] * v + h[8];
|
|
937
|
+
const at = (u, v) => applyHomography(h, { x: u, y: v });
|
|
938
|
+
const segment = (u0, v0, u1, v1) => {
|
|
939
|
+
const wa = w(u0, v0);
|
|
940
|
+
const wb = w(u1, v1);
|
|
941
|
+
const min = 0.05;
|
|
942
|
+
if (wa < min && wb < min) return null;
|
|
943
|
+
let t0 = 0;
|
|
944
|
+
let t1 = 1;
|
|
945
|
+
if (wa < min) t0 = (min - wa) / (wb - wa);
|
|
946
|
+
if (wb < min) t1 = (min - wa) / (wb - wa);
|
|
947
|
+
const a = at(u0 + (u1 - u0) * t0, v0 + (v1 - v0) * t0);
|
|
948
|
+
const b = at(u0 + (u1 - u0) * t1, v0 + (v1 - v0) * t1);
|
|
949
|
+
return a && b ? { a, b } : null;
|
|
950
|
+
};
|
|
951
|
+
const out = [];
|
|
952
|
+
for (let k = lo("x") / g; k <= n2; k++) {
|
|
953
|
+
const s = segment(k * g, lo("y"), k * g, max);
|
|
954
|
+
if (s) out.push(s);
|
|
955
|
+
}
|
|
956
|
+
for (let k = lo("y") / g; k <= n2; k++) {
|
|
957
|
+
const s = segment(lo("x"), k * g, max, k * g);
|
|
958
|
+
if (s) out.push(s);
|
|
959
|
+
}
|
|
960
|
+
return out;
|
|
961
|
+
}
|
|
962
|
+
function vectorPerspectivePreset(points, width, height) {
|
|
963
|
+
const horizon = height * 0.35;
|
|
964
|
+
const origin = { x: width / 2, y: height * 0.8 };
|
|
965
|
+
const vps = points === 1 ? [{ x: width / 2, y: horizon }] : [{ x: -width * 0.3, y: horizon }, { x: width * 1.3, y: horizon }];
|
|
966
|
+
if (points === 3) vps.push({ x: width / 2, y: height * 3 });
|
|
967
|
+
return { vanishingPoints: vps, origin, gridSize: Math.max(4, Math.round(Math.min(width, height) / 20)), extent: 12 };
|
|
968
|
+
}
|
|
969
|
+
|
|
837
970
|
// src/vector/constraints/lm.ts
|
|
838
971
|
var MAX_ROWS = 800;
|
|
839
972
|
var maxAbs = (v) => v.reduce((m, a) => Number.isFinite(a) ? Math.max(m, Math.abs(a)) : Infinity, 0);
|
|
@@ -2310,7 +2443,7 @@ var lensResolved = /* @__PURE__ */ new WeakMap();
|
|
|
2310
2443
|
function resolvedLensNodes(doc) {
|
|
2311
2444
|
const hit = lensResolved.get(doc.nodes);
|
|
2312
2445
|
if (hit) return hit;
|
|
2313
|
-
const nodes = resolveVectorLenses(doc).nodes;
|
|
2446
|
+
const nodes = resolveVectorLenses(resolveVectorMasterPages(doc)).nodes;
|
|
2314
2447
|
lensResolved.set(doc.nodes, nodes);
|
|
2315
2448
|
return nodes;
|
|
2316
2449
|
}
|
|
@@ -2414,6 +2547,21 @@ function shadingOverlay(state) {
|
|
|
2414
2547
|
}
|
|
2415
2548
|
return out;
|
|
2416
2549
|
}
|
|
2550
|
+
function perspectiveOverlay(state) {
|
|
2551
|
+
const grid = state.document.perspective;
|
|
2552
|
+
if (!grid || grid.visible === false) return null;
|
|
2553
|
+
const r = (n2) => Math.round(n2 * 10) / 10;
|
|
2554
|
+
const planes = vectorPerspectivePlanes(grid).map((plane) => ({
|
|
2555
|
+
plane,
|
|
2556
|
+
active: state.perspectivePlane === plane,
|
|
2557
|
+
d: vectorPerspectiveGridLines(grid, plane).map(({ a, b }) => {
|
|
2558
|
+
const p = toScreen(state, a);
|
|
2559
|
+
const q = toScreen(state, b);
|
|
2560
|
+
return `M${r(p.x)} ${r(p.y)}L${r(q.x)} ${r(q.y)}`;
|
|
2561
|
+
}).join("")
|
|
2562
|
+
}));
|
|
2563
|
+
return { planes, vanishingPoints: grid.vanishingPoints.map((v) => toScreen(state, v)), origin: toScreen(state, grid.origin) };
|
|
2564
|
+
}
|
|
2417
2565
|
function symmetryOverlay(state) {
|
|
2418
2566
|
const ids = /* @__PURE__ */ new Set([...state.selection, ...state.symmetryTarget ? [state.symmetryTarget] : []]);
|
|
2419
2567
|
const out = [];
|
|
@@ -2727,6 +2875,7 @@ function getVectorOverlayRenderData(state) {
|
|
|
2727
2875
|
connectorSites: connectorSiteOverlay(state),
|
|
2728
2876
|
shading: shadingOverlay(state),
|
|
2729
2877
|
symmetry: symmetryOverlay(state),
|
|
2878
|
+
perspective: perspectiveOverlay(state),
|
|
2730
2879
|
trackingPoints: (state.trackingPoints ?? []).map((p) => toScreen(state, p)),
|
|
2731
2880
|
typedEntry: state.typedEntry ? { text: state.typedEntry, ...state.pointer ? toScreen(state, state.pointer) : { x: 0, y: 0 } } : null
|
|
2732
2881
|
};
|
|
@@ -3535,10 +3684,10 @@ ${offset}
|
|
|
3535
3684
|
var pdfString = (s) => `(${s.replace(/[\\()]/g, (c) => `\\${c}`).replace(/[^\x20-\x7e]/g, "?")})`;
|
|
3536
3685
|
function vectorDocumentToPdf(doc, options = {}) {
|
|
3537
3686
|
const notes = /* @__PURE__ */ new Set();
|
|
3538
|
-
doc = resolveVectorLenses(doc);
|
|
3687
|
+
doc = resolveVectorLenses(resolveVectorMasterPages(doc));
|
|
3539
3688
|
const scale = options.scale ?? 1;
|
|
3540
3689
|
const compress = options.compress !== false;
|
|
3541
|
-
const frames = options.pages === "artboards" ?
|
|
3690
|
+
const frames = options.pages === "artboards" ? vectorPages(doc) : [];
|
|
3542
3691
|
if (options.pages === "artboards" && !frames.length) notes.add("There are no artboards (top-level frames): the whole drawing is one page.");
|
|
3543
3692
|
const docs = frames.length ? frames.map((f) => vectorFrameDocument(doc, f.id, findVectorNode)) : [doc];
|
|
3544
3693
|
const w = new PdfWriter();
|
|
@@ -3805,7 +3954,7 @@ function vectorDocumentToLottie(doc, options = {}) {
|
|
|
3805
3954
|
const fps = options.fps ?? 30;
|
|
3806
3955
|
const op = Math.max(1, Math.round(options.frames ?? 1));
|
|
3807
3956
|
const shapes = [];
|
|
3808
|
-
if (!options.nodes) doc = resolveVectorLenses(doc);
|
|
3957
|
+
if (!options.nodes) doc = resolveVectorLenses(resolveVectorMasterPages(doc));
|
|
3809
3958
|
for (const n2 of [...options.nodes ?? doc.nodes].reverse()) {
|
|
3810
3959
|
const g = nodeGroup(n2, notes);
|
|
3811
3960
|
if (g) shapes.push(g);
|
|
@@ -6987,6 +7136,7 @@ var VectorEditorController = class _VectorEditorController {
|
|
|
6987
7136
|
typedEntry: this.typed,
|
|
6988
7137
|
shadingPoint: this.getShadingSelection(),
|
|
6989
7138
|
symmetryTarget: this.symmetryTarget && this.doc.nodes.some((n2) => n2.id === this.symmetryTarget) ? this.symmetryTarget : null,
|
|
7139
|
+
perspectivePlane: this.perspectivePlane && this.doc.perspective && vectorPerspectivePlanes(this.doc.perspective).includes(this.perspectivePlane) ? this.perspectivePlane : null,
|
|
6990
7140
|
canUndo: h.canUndo,
|
|
6991
7141
|
canRedo: h.canRedo,
|
|
6992
7142
|
undoLabel: h.undoName,
|
|
@@ -7003,7 +7153,7 @@ var VectorEditorController = class _VectorEditorController {
|
|
|
7003
7153
|
out = { ...out, symbols: out.symbols.map((s) => s.id === edit.symbolId ? { ...s, nodes: out.nodes } : s) };
|
|
7004
7154
|
}
|
|
7005
7155
|
out = resolveVectorSymbols(out);
|
|
7006
|
-
return resolveVectorLenses(rerouteVectorConnectors(this.solved(out)));
|
|
7156
|
+
return resolveVectorLenses(resolveVectorMasterPages(rerouteVectorConnectors(this.solved(out))));
|
|
7007
7157
|
}
|
|
7008
7158
|
/**
|
|
7009
7159
|
* `doc` with its constraints solved (geometry edited since the last solve moving least) and
|
|
@@ -7497,7 +7647,7 @@ var VectorEditorController = class _VectorEditorController {
|
|
|
7497
7647
|
return vectorDocumentToSvg(this.storedDocument(), options);
|
|
7498
7648
|
}
|
|
7499
7649
|
toJSON() {
|
|
7500
|
-
return cloneVectorDocument(stripVectorLensViews(stripVectorSymbolArt(this.storedDocument())));
|
|
7650
|
+
return cloneVectorDocument(stripVectorMasterArt(stripVectorLensViews(stripVectorSymbolArt(this.storedDocument()))));
|
|
7501
7651
|
}
|
|
7502
7652
|
/** Adds a node (ids are kept unless taken). Returns its id. */
|
|
7503
7653
|
addNode(node, options = {}) {
|
|
@@ -9514,6 +9664,109 @@ var VectorEditorController = class _VectorEditorController {
|
|
|
9514
9664
|
this.notify();
|
|
9515
9665
|
}
|
|
9516
9666
|
// -----------------------------------------------------------------------------------------
|
|
9667
|
+
// Perspective drawing
|
|
9668
|
+
perspectivePlane = null;
|
|
9669
|
+
/** The document's perspective grid, or null. */
|
|
9670
|
+
getPerspective() {
|
|
9671
|
+
return this.doc.perspective ?? null;
|
|
9672
|
+
}
|
|
9673
|
+
/**
|
|
9674
|
+
* Sets the document's perspective grid (CorelDRAW's Perspective Drawing): 1 to 3 vanishing
|
|
9675
|
+
* points, the origin where its planes meet, the cell size and extent, and whether it shows;
|
|
9676
|
+
* `null` removes it. One undo step.
|
|
9677
|
+
*/
|
|
9678
|
+
setPerspective(grid) {
|
|
9679
|
+
let next = null;
|
|
9680
|
+
if (grid) {
|
|
9681
|
+
next = sanitizeVectorPerspective(grid);
|
|
9682
|
+
if (!next) return { ok: false, message: "A perspective grid needs 1 to 3 vanishing points { x, y } away from an origin { x, y }." };
|
|
9683
|
+
}
|
|
9684
|
+
this.change(next ? "Perspective Grid" : "Remove Perspective Grid", () => {
|
|
9685
|
+
const { perspective: _p, ...rest } = this.doc;
|
|
9686
|
+
this.doc = next ? { ...rest, perspective: next } : rest;
|
|
9687
|
+
});
|
|
9688
|
+
if (!next) this.perspectivePlane = null;
|
|
9689
|
+
return { ok: true, perspective: next };
|
|
9690
|
+
}
|
|
9691
|
+
/**
|
|
9692
|
+
* Draws new rectangles, ellipses, polygons and stars on a plane of the perspective grid (their
|
|
9693
|
+
* drag box is taken on the plane, so they recede with it), or flat again with `null`.
|
|
9694
|
+
*/
|
|
9695
|
+
setPerspectivePlane(plane) {
|
|
9696
|
+
if (plane !== null) {
|
|
9697
|
+
const grid = this.doc.perspective;
|
|
9698
|
+
if (!grid) return { ok: false, message: "There is no perspective grid: set one with vector.setPerspective first." };
|
|
9699
|
+
const planes = vectorPerspectivePlanes(grid);
|
|
9700
|
+
if (!planes.includes(plane)) return { ok: false, message: `This grid's planes are ${planes.join(", ")}.` };
|
|
9701
|
+
}
|
|
9702
|
+
this.perspectivePlane = plane;
|
|
9703
|
+
this.notify();
|
|
9704
|
+
return { ok: true };
|
|
9705
|
+
}
|
|
9706
|
+
/**
|
|
9707
|
+
* Lays objects onto a plane of the perspective grid: each is read flat, relative to the grid's
|
|
9708
|
+
* origin (right and up), and projected onto the plane, so art near the origin keeps its size and
|
|
9709
|
+
* art further along recedes. Paths and groups are mapped in document space (their transforms
|
|
9710
|
+
* baked in); text and instances must be converted to outlines first. One undo step. Returns
|
|
9711
|
+
* the ids changed.
|
|
9712
|
+
*/
|
|
9713
|
+
attachToPerspective(plane, options = {}) {
|
|
9714
|
+
const grid = this.doc.perspective;
|
|
9715
|
+
if (!grid) return { ok: false, message: "There is no perspective grid: set one with vector.setPerspective first." };
|
|
9716
|
+
const planes = vectorPerspectivePlanes(grid);
|
|
9717
|
+
if (!planes.includes(plane)) return { ok: false, message: `This grid's planes are ${planes.join(", ")}.` };
|
|
9718
|
+
const ids = [...new Set(options.ids ?? this.selectedRoots())];
|
|
9719
|
+
if (!ids.length) return { ok: false, message: "Select objects to put on the plane first." };
|
|
9720
|
+
const next = /* @__PURE__ */ new Map();
|
|
9721
|
+
const project = (n2, m) => {
|
|
9722
|
+
const own = n2.transform ? multiplyMatrices(m, n2.transform) : m;
|
|
9723
|
+
if (n2.type === "text" || n2.type === "instance") return `"${n2.id}" is ${n2.type === "text" ? "text" : "a symbol instance"}: convert it to outlines first (vector.createOutlines${n2.type === "instance" ? " after vector.detachInstance" : ""}).`;
|
|
9724
|
+
if (n2.type === "group") {
|
|
9725
|
+
const children = [];
|
|
9726
|
+
for (const c of n2.children) {
|
|
9727
|
+
const r = project(c, own);
|
|
9728
|
+
if (typeof r === "string") return r;
|
|
9729
|
+
children.push(r);
|
|
9730
|
+
}
|
|
9731
|
+
const { transform: _t2, ...rest2 } = n2;
|
|
9732
|
+
return { ...rest2, children };
|
|
9733
|
+
}
|
|
9734
|
+
const flat = transformBezierPath(subpathsToBezier(n2.subpaths), own);
|
|
9735
|
+
const mapped = vectorPerspectiveMapPath(grid, plane, flat);
|
|
9736
|
+
if (!mapped) return `"${n2.id}" reaches beyond the plane's horizon: move it nearer the origin, or the vanishing points further out.`;
|
|
9737
|
+
const { transform: _t, ...rest } = n2;
|
|
9738
|
+
return { ...rest, subpaths: bezierToSubpaths(mapped) };
|
|
9739
|
+
};
|
|
9740
|
+
for (const id of ids) {
|
|
9741
|
+
const loc = locateVectorNode(this.doc.nodes, id);
|
|
9742
|
+
if (!loc) return { ok: false, message: `There is no node "${id}".` };
|
|
9743
|
+
const node = loc.list[loc.index];
|
|
9744
|
+
if (node.locked) return { ok: false, message: `"${id}" is locked; unlock it first.` };
|
|
9745
|
+
const parentM = this.parentMatrixOf(id);
|
|
9746
|
+
const r = project(node, parentM);
|
|
9747
|
+
if (typeof r === "string") return { ok: false, message: r };
|
|
9748
|
+
const inv = invertMatrix(parentM);
|
|
9749
|
+
next.set(id, isIdentityMatrix(inv) ? r : transformVectorNode(r, inv));
|
|
9750
|
+
}
|
|
9751
|
+
this.change(`Attach to ${plane[0].toUpperCase()}${plane.slice(1)} Plane`, () => {
|
|
9752
|
+
this.setDoc(mapTree(this.doc.nodes, (n2) => next.get(n2.id) ?? n2));
|
|
9753
|
+
});
|
|
9754
|
+
return { ok: true, ids };
|
|
9755
|
+
}
|
|
9756
|
+
/** A shape's subpaths drawn on the active perspective plane from its flat drag box, or null to keep it flat. */
|
|
9757
|
+
perspectiveShape(kind, start, end) {
|
|
9758
|
+
const grid = this.doc.perspective;
|
|
9759
|
+
const plane = this.perspectivePlane;
|
|
9760
|
+
if (!grid || !plane || kind === "line" || !vectorPerspectivePlanes(grid).includes(plane)) return null;
|
|
9761
|
+
const toFlat = vectorPerspectivePlaneToFlat(grid, plane);
|
|
9762
|
+
const a = toFlat?.(start);
|
|
9763
|
+
const b = toFlat?.(end);
|
|
9764
|
+
if (!a || !b) return null;
|
|
9765
|
+
const flat = this.createShapeNode({ kind, ...boundsFromPoints(a, b) });
|
|
9766
|
+
const mapped = vectorPerspectiveMapPath(grid, plane, subpathsToBezier(flat.subpaths));
|
|
9767
|
+
return mapped ? bezierToSubpaths(mapped) : null;
|
|
9768
|
+
}
|
|
9769
|
+
// -----------------------------------------------------------------------------------------
|
|
9517
9770
|
// PDF
|
|
9518
9771
|
/**
|
|
9519
9772
|
* The document as a vector PDF (see `vectorDocumentToPdf`): one page of the artboard, or a page
|
|
@@ -10312,6 +10565,146 @@ var VectorEditorController = class _VectorEditorController {
|
|
|
10312
10565
|
});
|
|
10313
10566
|
return { ok: true, id };
|
|
10314
10567
|
}
|
|
10568
|
+
// -----------------------------------------------------------------------------------------
|
|
10569
|
+
// Pages and master pages
|
|
10570
|
+
/**
|
|
10571
|
+
* The document's pages (top-level frames that are not master pages, in order: `number` from 1)
|
|
10572
|
+
* with the master each uses, and its master pages.
|
|
10573
|
+
*/
|
|
10574
|
+
getPages() {
|
|
10575
|
+
const pages = vectorPages(this.doc);
|
|
10576
|
+
const masters = vectorMasterPages(this.doc);
|
|
10577
|
+
const box = (f) => ({ x: f.frame.x, y: f.frame.y, width: f.frame.width, height: f.frame.height });
|
|
10578
|
+
return {
|
|
10579
|
+
pages: pages.map((p, i) => ({ id: p.id, name: p.name ?? `Page ${i + 1}`, number: i + 1, masterId: p.frame.masterId && masters.some((m) => m.id === p.frame.masterId) ? p.frame.masterId : null, bounds: box(p) })),
|
|
10580
|
+
masters: masters.map((m) => ({ id: m.id, name: m.name ?? "Master", usedBy: pages.filter((p) => p.frame.masterId === m.id).map((p) => p.id), bounds: box(m) }))
|
|
10581
|
+
};
|
|
10582
|
+
}
|
|
10583
|
+
/** Where a new page or master goes: right of every top-level frame, or below them for a master. */
|
|
10584
|
+
nextPageRect(master) {
|
|
10585
|
+
const frames = this.doc.nodes.filter(isVectorFrame);
|
|
10586
|
+
const pages = vectorPages(this.doc);
|
|
10587
|
+
const like = pages[pages.length - 1]?.frame ?? frames[frames.length - 1]?.frame;
|
|
10588
|
+
const width = like?.width ?? this.doc.width;
|
|
10589
|
+
const height = like?.height ?? this.doc.height;
|
|
10590
|
+
if (!frames.length) return { x: 0, y: 0, width, height };
|
|
10591
|
+
const gap = Math.max(20, Math.round(width * 0.1));
|
|
10592
|
+
if (master) {
|
|
10593
|
+
const bottom = Math.max(...frames.map((f) => f.frame.y + f.frame.height));
|
|
10594
|
+
const left = Math.min(...frames.map((f) => f.frame.x));
|
|
10595
|
+
return { x: left, y: bottom + gap * 2, width, height };
|
|
10596
|
+
}
|
|
10597
|
+
const right = Math.max(...pages.map((f) => f.frame.x + f.frame.width), ...pages.length ? [] : frames.map((f) => f.frame.x + f.frame.width));
|
|
10598
|
+
const top = pages.length ? Math.min(...pages.map((f) => f.frame.y)) : Math.min(...frames.map((f) => f.frame.y));
|
|
10599
|
+
return { x: right + gap, y: top, width, height };
|
|
10600
|
+
}
|
|
10601
|
+
/**
|
|
10602
|
+
* Adds a page: a frame the size of the last page (or the document), to the right of the others,
|
|
10603
|
+
* after page `after` in the page order (default last), using master page `masterId` (default:
|
|
10604
|
+
* the master the last page uses). The first page added to a document without frames covers the
|
|
10605
|
+
* artboard and takes the existing top-level art in. One undo step; selects it. Returns its id.
|
|
10606
|
+
*/
|
|
10607
|
+
addPage(input = {}) {
|
|
10608
|
+
const pages = vectorPages(this.doc);
|
|
10609
|
+
if (input.masterId && !isVectorMasterPage(this.doc.nodes.find((n2) => n2.id === input.masterId))) return { ok: false, message: `"${input.masterId}" is not a master page (add one with vector.addMasterPage).` };
|
|
10610
|
+
if (input.after !== void 0 && !pages.some((p) => p.id === input.after)) return { ok: false, message: `"${input.after}" is not a page.` };
|
|
10611
|
+
const first = !this.doc.nodes.some(isVectorFrame);
|
|
10612
|
+
const rect = this.nextPageRect(false);
|
|
10613
|
+
const id = this.newId();
|
|
10614
|
+
const masterId = input.masterId === void 0 ? pages[pages.length - 1]?.frame.masterId ?? null : input.masterId;
|
|
10615
|
+
const adopted = first ? this.doc.nodes.filter((n2) => !n2.locked && n2.visible !== false && !n2.blendStep) : [];
|
|
10616
|
+
const page = {
|
|
10617
|
+
id,
|
|
10618
|
+
type: "group",
|
|
10619
|
+
name: input.name ?? `Page ${pages.length + 1}`,
|
|
10620
|
+
frame: { ...rect, fill: "#ffffff", ...masterId ? { masterId } : {} },
|
|
10621
|
+
children: adopted
|
|
10622
|
+
};
|
|
10623
|
+
const taken = new Set(adopted.map((n2) => n2.id));
|
|
10624
|
+
this.change("Add Page", () => {
|
|
10625
|
+
const rest = this.doc.nodes.filter((n2) => !taken.has(n2.id));
|
|
10626
|
+
const at = input.after ? rest.findIndex((n2) => n2.id === input.after) + 1 : rest.length;
|
|
10627
|
+
this.setDoc([...rest.slice(0, at), page, ...rest.slice(at)]);
|
|
10628
|
+
this.selection = [id];
|
|
10629
|
+
this.anchors = [];
|
|
10630
|
+
this.editingId = null;
|
|
10631
|
+
});
|
|
10632
|
+
return { ok: true, id };
|
|
10633
|
+
}
|
|
10634
|
+
/**
|
|
10635
|
+
* Adds an empty master page (a frame with `master` set, the size of the last page) below the
|
|
10636
|
+
* pages. Art drawn in it shows on every page that uses it; text can show `{page}` and `{pages}`.
|
|
10637
|
+
* With `assignTo` (page ids, or `all`), those pages use it. One undo step; selects it.
|
|
10638
|
+
*/
|
|
10639
|
+
addMasterPage(input = {}) {
|
|
10640
|
+
const pages = vectorPages(this.doc);
|
|
10641
|
+
const assign = input.assignTo === "all" ? pages.map((p) => p.id) : input.assignTo ?? [];
|
|
10642
|
+
for (const pid of assign) if (!pages.some((p) => p.id === pid)) return { ok: false, message: `"${pid}" is not a page.` };
|
|
10643
|
+
const rect = this.nextPageRect(true);
|
|
10644
|
+
const id = this.newId();
|
|
10645
|
+
const master = { id, type: "group", name: input.name ?? `Master ${String.fromCharCode(65 + vectorMasterPages(this.doc).length % 26)}`, frame: { ...rect, master: true }, children: [] };
|
|
10646
|
+
const set = new Set(assign);
|
|
10647
|
+
this.change("Add Master Page", () => {
|
|
10648
|
+
this.setDoc([...this.doc.nodes.map((n2) => set.has(n2.id) && isVectorFrame(n2) ? { ...n2, frame: { ...n2.frame, masterId: id } } : n2), master]);
|
|
10649
|
+
this.selection = [id];
|
|
10650
|
+
this.anchors = [];
|
|
10651
|
+
this.editingId = null;
|
|
10652
|
+
});
|
|
10653
|
+
return { ok: true, id };
|
|
10654
|
+
}
|
|
10655
|
+
/** Makes pages use master page `masterId`, or none with null. One undo step. */
|
|
10656
|
+
setPageMaster(masterId, options = {}) {
|
|
10657
|
+
const pages = vectorPages(this.doc);
|
|
10658
|
+
const ids = options.ids ?? this.selection.filter((id) => pages.some((p) => p.id === id));
|
|
10659
|
+
if (!ids.length) return { ok: false, message: "Select a page (a top-level frame) first." };
|
|
10660
|
+
for (const id of ids) if (!pages.some((p) => p.id === id)) return { ok: false, message: `"${id}" is not a page${isVectorMasterPage(this.getNode(id)) ? " (it is a master page)" : ""}.` };
|
|
10661
|
+
if (masterId !== null && !isVectorMasterPage(this.doc.nodes.find((n2) => n2.id === masterId))) return { ok: false, message: `"${masterId}" is not a master page.` };
|
|
10662
|
+
const set = new Set(ids);
|
|
10663
|
+
this.change(masterId ? "Apply Master Page" : "Remove Master Page", () => {
|
|
10664
|
+
this.setDoc(
|
|
10665
|
+
this.doc.nodes.map((n2) => {
|
|
10666
|
+
if (!set.has(n2.id) || !isVectorFrame(n2)) return n2;
|
|
10667
|
+
const { masterId: _m, ...frame } = n2.frame;
|
|
10668
|
+
return { ...n2, frame: masterId ? { ...frame, masterId } : frame };
|
|
10669
|
+
})
|
|
10670
|
+
);
|
|
10671
|
+
});
|
|
10672
|
+
return { ok: true, ids: [...ids] };
|
|
10673
|
+
}
|
|
10674
|
+
/** Moves page `id` to position `index` (0-based) in the page order. One undo step. Returns the new order. */
|
|
10675
|
+
movePage(id, index) {
|
|
10676
|
+
const pages = vectorPages(this.doc);
|
|
10677
|
+
const from = pages.findIndex((p) => p.id === id);
|
|
10678
|
+
if (from < 0) return { ok: false, message: `"${id}" is not a page.` };
|
|
10679
|
+
if (!Number.isInteger(index) || index < 0 || index >= pages.length) return { ok: false, message: `index must be from 0 to ${pages.length - 1}.` };
|
|
10680
|
+
if (index === from) return { ok: true, order: pages.map((p) => p.id) };
|
|
10681
|
+
const order = pages.map((p) => p.id);
|
|
10682
|
+
order.splice(index, 0, ...order.splice(from, 1));
|
|
10683
|
+
const slots = this.doc.nodes.map((n2, i) => pages.some((p) => p.id === n2.id) ? i : -1).filter((i) => i >= 0);
|
|
10684
|
+
const byId = new Map(pages.map((p) => [p.id, p]));
|
|
10685
|
+
this.change("Move Page", () => {
|
|
10686
|
+
const nodes = this.doc.nodes.slice();
|
|
10687
|
+
slots.forEach((slot, k) => nodes[slot] = byId.get(order[k]));
|
|
10688
|
+
this.setDoc(nodes);
|
|
10689
|
+
});
|
|
10690
|
+
return { ok: true, order };
|
|
10691
|
+
}
|
|
10692
|
+
/**
|
|
10693
|
+
* Goes to a page (or master page): selects it and brings it into view, fitted to a canvas of
|
|
10694
|
+
* `size` screen pixels when given, otherwise at the current zoom with its corner near the
|
|
10695
|
+
* canvas's top-left. Not an undo step.
|
|
10696
|
+
*/
|
|
10697
|
+
goToPage(id, options = {}) {
|
|
10698
|
+
const n2 = this.doc.nodes.find((x) => x.id === id);
|
|
10699
|
+
if (!isVectorFrame(n2)) return { ok: false, message: `"${id}" is not a page or master page.` };
|
|
10700
|
+
const b = vectorNodeBounds(n2) ?? { x: n2.frame.x, y: n2.frame.y, width: n2.frame.width, height: n2.frame.height };
|
|
10701
|
+
this.selection = [id];
|
|
10702
|
+
this.anchors = [];
|
|
10703
|
+
if (options.size) this.zoomToFit(options.size, { bounds: b });
|
|
10704
|
+
else this.setViewport({ x: 40 - b.x * this.viewport.zoom, y: 40 - b.y * this.viewport.zoom });
|
|
10705
|
+
this.notify();
|
|
10706
|
+
return { ok: true };
|
|
10707
|
+
}
|
|
10315
10708
|
/**
|
|
10316
10709
|
* Frame Selection: puts the selected (or given) objects, which must share a parent, into a new
|
|
10317
10710
|
* frame fitted to their bounds plus `padding` (document units, default 0), in their place in the
|
|
@@ -12305,7 +12698,9 @@ var VectorEditorController = class _VectorEditorController {
|
|
|
12305
12698
|
const y2 = drag.start.y + h;
|
|
12306
12699
|
bounds = boundsFromPoints(start, { x: x2, y: y2 });
|
|
12307
12700
|
}
|
|
12308
|
-
const
|
|
12701
|
+
const kind = drag.tool === "frame" ? "rect" : drag.tool;
|
|
12702
|
+
const onPlane = drag.tool !== "frame" ? this.perspectiveShape(kind, start, { x: bounds.x === start.x ? bounds.x + bounds.width : bounds.x, y: bounds.y === start.y ? bounds.y + bounds.height : bounds.y }) : null;
|
|
12703
|
+
const shaped = onPlane ? { subpaths: onPlane } : this.createShapeNode({ kind, ...bounds });
|
|
12309
12704
|
this.replaceNode(drag.nodeId, { ...node, subpaths: shaped.subpaths });
|
|
12310
12705
|
this.interaction = { type: "draw", tool: drag.tool, nodeId: drag.nodeId, bounds };
|
|
12311
12706
|
this.notify(true);
|
|
@@ -14634,7 +15029,8 @@ function createVectorCommands(controller, options = {}) {
|
|
|
14634
15029
|
name: { type: "string", description: "Layer name (default the text's start)." },
|
|
14635
15030
|
fill: PAINT,
|
|
14636
15031
|
stroke: PAINT,
|
|
14637
|
-
strokeWidth: { type: "number", minimum: 0, description: "Stroke width (default 1)." }
|
|
15032
|
+
strokeWidth: { type: "number", minimum: 0, description: "Stroke width (default 1)." },
|
|
15033
|
+
parentId: { type: "string", description: "A group (frame, master page, symmetry group) to add it into, on top of its children (default: the top of the document). On a master page, {page} and {pages} show each page's number and the page count." }
|
|
14638
15034
|
},
|
|
14639
15035
|
required: ["text"],
|
|
14640
15036
|
additionalProperties: false
|
|
@@ -14654,7 +15050,7 @@ function createVectorCommands(controller, options = {}) {
|
|
|
14654
15050
|
...params.paragraph ? { paragraph: params.paragraph } : {},
|
|
14655
15051
|
...params.fill !== void 0 ? { fill: checkPaint(params.fill, "fill") } : {},
|
|
14656
15052
|
...params.stroke !== void 0 ? { stroke: checkPaint(params.stroke, "stroke") } : {}
|
|
14657
|
-
});
|
|
15053
|
+
}, parentOf(params.parentId));
|
|
14658
15054
|
} catch (e) {
|
|
14659
15055
|
fail(e instanceof Error ? e.message : String(e));
|
|
14660
15056
|
}
|
|
@@ -15166,6 +15562,86 @@ function createVectorCommands(controller, options = {}) {
|
|
|
15166
15562
|
}
|
|
15167
15563
|
}
|
|
15168
15564
|
];
|
|
15565
|
+
const PLANE = { type: "string", enum: [...VECTOR_PERSPECTIVE_PLANES], description: "A plane of the grid: floor, left and right (2 or 3 vanishing points), or floor, side and front (1 point)." };
|
|
15566
|
+
const perspectiveResult = () => {
|
|
15567
|
+
const grid = controller.getPerspective();
|
|
15568
|
+
return { perspective: grid, planes: grid ? vectorPerspectivePlanes(grid) : [], drawingOn: controller.getState().perspectivePlane };
|
|
15569
|
+
};
|
|
15570
|
+
const perspectiveCommands = () => [
|
|
15571
|
+
{
|
|
15572
|
+
...base,
|
|
15573
|
+
id: `${prefix}getPerspective`,
|
|
15574
|
+
label: "Perspective Grid",
|
|
15575
|
+
keywords: ["perspective", "grid", "vanishing point", "horizon"],
|
|
15576
|
+
description: "Reads the document's perspective grid: { perspective: { vanishingPoints, origin, gridSize, extent, visible } or null, planes (the planes it has), drawingOn (the plane new shapes are drawn on, or null) }.",
|
|
15577
|
+
params: { type: "object", properties: {}, additionalProperties: false },
|
|
15578
|
+
run: () => perspectiveResult()
|
|
15579
|
+
},
|
|
15580
|
+
{
|
|
15581
|
+
...base,
|
|
15582
|
+
id: `${prefix}setPerspective`,
|
|
15583
|
+
label: "Perspective Grid\u2026",
|
|
15584
|
+
keywords: ["perspective", "grid", "vanishing point", "one point", "two point", "three point", "horizon", "drawing in perspective"],
|
|
15585
|
+
description: "Sets the document's perspective grid (CorelDRAW's Perspective Drawing): 1 vanishing point (planes floor, side, front), 2 (floor, left, right; walls recede to the first and second) or 3 (the third is where the walls' verticals meet). Put the vanishing points on the horizon line and the origin below it, where the planes meet. One undo step. Returns the grid as vector.getPerspective does.",
|
|
15586
|
+
params: {
|
|
15587
|
+
type: "object",
|
|
15588
|
+
properties: {
|
|
15589
|
+
vanishingPoints: { type: "array", minItems: 1, maxItems: 3, items: { ...POINT, description: "A vanishing point (document units)." }, description: "1 to 3 vanishing points, document units." },
|
|
15590
|
+
origin: { ...POINT, description: "Where the planes meet (document units), not on a vanishing point." },
|
|
15591
|
+
gridSize: { type: "number", exclusiveMinimum: 0, description: "Grid cell size at the origin, document units (default 20)." },
|
|
15592
|
+
extent: { type: "integer", minimum: 1, maximum: 100, description: "Cells drawn out from the origin along each axis (default 12)." },
|
|
15593
|
+
visible: { type: "boolean", description: "Show the grid on the canvas (default true)." }
|
|
15594
|
+
},
|
|
15595
|
+
required: ["vanishingPoints", "origin"],
|
|
15596
|
+
additionalProperties: false
|
|
15597
|
+
},
|
|
15598
|
+
undoable: true,
|
|
15599
|
+
run: (_ctx, params) => {
|
|
15600
|
+
check(controller.setPerspective(params));
|
|
15601
|
+
return perspectiveResult();
|
|
15602
|
+
}
|
|
15603
|
+
},
|
|
15604
|
+
{
|
|
15605
|
+
...base,
|
|
15606
|
+
id: `${prefix}removePerspective`,
|
|
15607
|
+
label: "Remove Perspective Grid",
|
|
15608
|
+
keywords: ["perspective", "grid", "remove"],
|
|
15609
|
+
description: "Removes the perspective grid (art already on its planes stays as drawn). One undo step. Returns { perspective: null }.",
|
|
15610
|
+
params: { type: "object", properties: {}, additionalProperties: false },
|
|
15611
|
+
undoable: true,
|
|
15612
|
+
run: () => {
|
|
15613
|
+
check(controller.setPerspective(null));
|
|
15614
|
+
return { perspective: null };
|
|
15615
|
+
}
|
|
15616
|
+
},
|
|
15617
|
+
{
|
|
15618
|
+
...base,
|
|
15619
|
+
id: `${prefix}setPerspectivePlane`,
|
|
15620
|
+
label: "Draw on Perspective Plane",
|
|
15621
|
+
keywords: ["perspective", "plane", "draw", "floor", "wall"],
|
|
15622
|
+
description: "Makes the Rectangle, Ellipse, Polygon and Star tools draw on a plane of the grid (their drag box is taken on the plane, so shapes recede with it), or flat again with plane null. Not an undo step. Returns the grid as vector.getPerspective does.",
|
|
15623
|
+
params: { type: "object", properties: { plane: { ...PLANE, type: ["string", "null"], enum: [...VECTOR_PERSPECTIVE_PLANES, null], description: `${PLANE.description} null draws flat.` } }, required: ["plane"], additionalProperties: false },
|
|
15624
|
+
run: (_ctx, params) => {
|
|
15625
|
+
check(controller.setPerspectivePlane(params.plane));
|
|
15626
|
+
return perspectiveResult();
|
|
15627
|
+
}
|
|
15628
|
+
},
|
|
15629
|
+
{
|
|
15630
|
+
...base,
|
|
15631
|
+
id: `${prefix}attachToPerspective`,
|
|
15632
|
+
label: "Attach to Perspective",
|
|
15633
|
+
keywords: ["perspective", "attach", "plane", "project", "wall", "floor", "sign"],
|
|
15634
|
+
description: "Lays objects (`ids`, default the selection) onto a plane of the grid: each is read flat relative to the grid origin (right and up) and projected, so art near the origin keeps its size and further art recedes. Draw or place the flat art beside the origin first. Text and instances must be outlines (vector.createOutlines). One undo step. Returns { ids }.",
|
|
15635
|
+
params: { type: "object", properties: { ids: { ...IDS, description: "Objects to project (default: the selection)." }, plane: PLANE }, required: ["plane"], additionalProperties: false },
|
|
15636
|
+
undoable: true,
|
|
15637
|
+
enabled: enabledFor,
|
|
15638
|
+
run: (_ctx, params) => {
|
|
15639
|
+
const r = controller.attachToPerspective(params.plane, params.ids ? { ids: params.ids } : {});
|
|
15640
|
+
check(r);
|
|
15641
|
+
return { ids: r.ids ?? [] };
|
|
15642
|
+
}
|
|
15643
|
+
}
|
|
15644
|
+
];
|
|
15169
15645
|
const pdfCommands = () => [
|
|
15170
15646
|
{
|
|
15171
15647
|
...base,
|
|
@@ -15646,6 +16122,109 @@ function createVectorCommands(controller, options = {}) {
|
|
|
15646
16122
|
];
|
|
15647
16123
|
const frameResult = (id) => controller.getFrames().find((f) => f.id === id) ?? fail(`"${id}" is not a frame.`);
|
|
15648
16124
|
const FRAME_PAINT = { ...PAINT, description: `The frame's background, drawn below its children. ${PAINT.description}` };
|
|
16125
|
+
const pagesResult = () => controller.getPages();
|
|
16126
|
+
const pageCommands = () => [
|
|
16127
|
+
{
|
|
16128
|
+
...base,
|
|
16129
|
+
id: `${prefix}listPages`,
|
|
16130
|
+
label: "Pages",
|
|
16131
|
+
keywords: ["pages", "master page", "multipage", "page numbers", "document pages"],
|
|
16132
|
+
description: "Lists the document's pages (top-level frames that are not master pages, in order) and its master pages: { pages: [{ id, name, number, masterId, bounds }], masters: [{ id, name, usedBy, bounds }] }. Place master art inside the master bounds.",
|
|
16133
|
+
params: { type: "object", properties: {}, additionalProperties: false },
|
|
16134
|
+
run: () => pagesResult()
|
|
16135
|
+
},
|
|
16136
|
+
{
|
|
16137
|
+
...base,
|
|
16138
|
+
id: `${prefix}addPage`,
|
|
16139
|
+
label: "Add Page",
|
|
16140
|
+
keywords: ["page", "add page", "new page", "insert page", "multipage"],
|
|
16141
|
+
description: "Adds a page: a frame the size of the last page (or the document) right of the others, after page `after` (default last), using master `masterId` (default: the last page's master; null for none). The first page of a document without frames covers the artboard and takes its art in. Add art to it with parentId. One undo step. Returns { id } and the pages.",
|
|
16142
|
+
params: {
|
|
16143
|
+
type: "object",
|
|
16144
|
+
properties: {
|
|
16145
|
+
name: { type: "string", description: 'Page name (default "Page n").' },
|
|
16146
|
+
masterId: { type: ["string", "null"], description: "Master page id, or null for none (default: the last page's master)." },
|
|
16147
|
+
after: { type: "string", description: "Page id to insert after (default: at the end)." }
|
|
16148
|
+
},
|
|
16149
|
+
additionalProperties: false
|
|
16150
|
+
},
|
|
16151
|
+
undoable: true,
|
|
16152
|
+
run: (_ctx, params) => {
|
|
16153
|
+
const r = controller.addPage(params ?? {});
|
|
16154
|
+
check(r);
|
|
16155
|
+
return { id: r.id, ...pagesResult() };
|
|
16156
|
+
}
|
|
16157
|
+
},
|
|
16158
|
+
{
|
|
16159
|
+
...base,
|
|
16160
|
+
id: `${prefix}addMasterPage`,
|
|
16161
|
+
label: "Add Master Page",
|
|
16162
|
+
keywords: ["master page", "template page", "header", "footer", "page numbers"],
|
|
16163
|
+
description: 'Adds an empty master page (a frame below the pages, not a page itself). Art added to it (parentId: its id) shows on every page using it, laid out by each object\'s resizing constraints; text there can show {page} and {pages}. `assignTo` page ids or "all" make pages use it. One undo step. Returns { id } and the pages.',
|
|
16164
|
+
params: {
|
|
16165
|
+
type: "object",
|
|
16166
|
+
properties: {
|
|
16167
|
+
name: { type: "string", description: 'Master name (default "Master A", "Master B", \u2026).' },
|
|
16168
|
+
assignTo: { anyOf: [{ type: "string", enum: ["all"] }, { ...IDS }], description: 'Pages that use it: "all" or page ids (default none).' }
|
|
16169
|
+
},
|
|
16170
|
+
additionalProperties: false
|
|
16171
|
+
},
|
|
16172
|
+
undoable: true,
|
|
16173
|
+
run: (_ctx, params) => {
|
|
16174
|
+
const r = controller.addMasterPage(params ?? {});
|
|
16175
|
+
check(r);
|
|
16176
|
+
return { id: r.id, ...pagesResult() };
|
|
16177
|
+
}
|
|
16178
|
+
},
|
|
16179
|
+
{
|
|
16180
|
+
...base,
|
|
16181
|
+
id: `${prefix}setPageMaster`,
|
|
16182
|
+
label: "Apply Master Page",
|
|
16183
|
+
keywords: ["master page", "apply master", "page template"],
|
|
16184
|
+
description: "Makes pages (`ids`, default the selected pages) use master page `masterId`, or none with null. One undo step. Returns the pages.",
|
|
16185
|
+
params: { type: "object", properties: { ids: { ...IDS, description: "Page ids (default: the selected pages)." }, masterId: { type: ["string", "null"], description: "Master page id, or null for none." } }, required: ["masterId"], additionalProperties: false },
|
|
16186
|
+
undoable: true,
|
|
16187
|
+
run: (_ctx, params) => {
|
|
16188
|
+
check(controller.setPageMaster(params.masterId, params.ids ? { ids: params.ids } : {}));
|
|
16189
|
+
return pagesResult();
|
|
16190
|
+
}
|
|
16191
|
+
},
|
|
16192
|
+
{
|
|
16193
|
+
...base,
|
|
16194
|
+
id: `${prefix}movePage`,
|
|
16195
|
+
label: "Move Page",
|
|
16196
|
+
keywords: ["page order", "reorder pages", "move page"],
|
|
16197
|
+
description: "Moves page `id` to position `index` (0-based) in the page order; page numbers follow. One undo step. Returns the pages.",
|
|
16198
|
+
params: { type: "object", properties: { id: { type: "string", description: "The page." }, index: { type: "integer", minimum: 0, description: "New position, 0 for first." } }, required: ["id", "index"], additionalProperties: false },
|
|
16199
|
+
undoable: true,
|
|
16200
|
+
run: (_ctx, params) => {
|
|
16201
|
+
check(controller.movePage(params.id, params.index));
|
|
16202
|
+
return pagesResult();
|
|
16203
|
+
}
|
|
16204
|
+
},
|
|
16205
|
+
{
|
|
16206
|
+
...base,
|
|
16207
|
+
id: `${prefix}goToPage`,
|
|
16208
|
+
label: "Go to Page",
|
|
16209
|
+
keywords: ["go to page", "navigate", "show page", "zoom to page"],
|
|
16210
|
+
description: "Selects a page or master page and brings it into view for the user (fitted when the canvas size is given). Not an undo step. Returns { id }.",
|
|
16211
|
+
params: {
|
|
16212
|
+
type: "object",
|
|
16213
|
+
properties: {
|
|
16214
|
+
id: { type: "string", description: "Page or master page id." },
|
|
16215
|
+
canvasWidth: { type: "number", exclusiveMinimum: 0, description: "Canvas width in screen pixels, to fit the page (optional)." },
|
|
16216
|
+
canvasHeight: { type: "number", exclusiveMinimum: 0, description: "Canvas height in screen pixels, to fit the page (optional)." }
|
|
16217
|
+
},
|
|
16218
|
+
required: ["id"],
|
|
16219
|
+
additionalProperties: false
|
|
16220
|
+
},
|
|
16221
|
+
run: (_ctx, params) => {
|
|
16222
|
+
const size = params.canvasWidth && params.canvasHeight ? { width: params.canvasWidth, height: params.canvasHeight } : void 0;
|
|
16223
|
+
check(controller.goToPage(params.id, size ? { size } : {}));
|
|
16224
|
+
return { id: params.id };
|
|
16225
|
+
}
|
|
16226
|
+
}
|
|
16227
|
+
];
|
|
15649
16228
|
const frameCommands = () => [
|
|
15650
16229
|
{
|
|
15651
16230
|
...base,
|
|
@@ -15995,6 +16574,7 @@ function createVectorCommands(controller, options = {}) {
|
|
|
15995
16574
|
...symbolCommands(),
|
|
15996
16575
|
...constraintCommands(),
|
|
15997
16576
|
...frameCommands(),
|
|
16577
|
+
...pageCommands(),
|
|
15998
16578
|
...connectorCommands(),
|
|
15999
16579
|
...trackingCommands(),
|
|
16000
16580
|
...shadingCommands(),
|
|
@@ -16002,6 +16582,7 @@ function createVectorCommands(controller, options = {}) {
|
|
|
16002
16582
|
...lottieCommands(),
|
|
16003
16583
|
...pdfCommands(),
|
|
16004
16584
|
...symmetryCommands(),
|
|
16585
|
+
...perspectiveCommands(),
|
|
16005
16586
|
...lensCommands(),
|
|
16006
16587
|
{
|
|
16007
16588
|
...base,
|
|
@@ -17052,6 +17633,7 @@ export {
|
|
|
17052
17633
|
VECTOR_PATH_ACTIONS,
|
|
17053
17634
|
VECTOR_PATH_TEXT_BASELINES,
|
|
17054
17635
|
VECTOR_PENCIL_STRING_PX,
|
|
17636
|
+
VECTOR_PERSPECTIVE_PLANES,
|
|
17055
17637
|
VECTOR_PRESSURE_NOMINAL,
|
|
17056
17638
|
VECTOR_ROTATE_HANDLE_OFFSET,
|
|
17057
17639
|
VECTOR_SPATIAL_MIN,
|
|
@@ -17248,6 +17830,7 @@ export {
|
|
|
17248
17830
|
isVectorMaskActive,
|
|
17249
17831
|
isVectorMaskGroup,
|
|
17250
17832
|
isVectorMaskType,
|
|
17833
|
+
isVectorMasterPage,
|
|
17251
17834
|
isVectorMeshGradient,
|
|
17252
17835
|
isVectorShadedPaint,
|
|
17253
17836
|
isVectorSymmetryGroup,
|
|
@@ -17335,6 +17918,7 @@ export {
|
|
|
17335
17918
|
resizeWarpMesh as resizeVectorMesh,
|
|
17336
17919
|
resolveVectorBlendOptions,
|
|
17337
17920
|
resolveVectorLenses,
|
|
17921
|
+
resolveVectorMasterPages,
|
|
17338
17922
|
resolveVectorSymbols,
|
|
17339
17923
|
reverseMorphContour,
|
|
17340
17924
|
reverseSubpath,
|
|
@@ -17358,6 +17942,7 @@ export {
|
|
|
17358
17942
|
sanitizeVectorGradient,
|
|
17359
17943
|
sanitizeVectorLens,
|
|
17360
17944
|
sanitizeVectorMask,
|
|
17945
|
+
sanitizeVectorPerspective,
|
|
17361
17946
|
sanitizeVectorResizing,
|
|
17362
17947
|
sanitizeVectorShadedPaint,
|
|
17363
17948
|
sanitizeVectorStrokeSettings,
|
|
@@ -17387,6 +17972,7 @@ export {
|
|
|
17387
17972
|
splitWarpMeshV as splitVectorMeshV,
|
|
17388
17973
|
starSubpath,
|
|
17389
17974
|
stripVectorLensViews,
|
|
17975
|
+
stripVectorMasterArt,
|
|
17390
17976
|
stripVectorSymbolArt,
|
|
17391
17977
|
strokePositionPoint,
|
|
17392
17978
|
strokeWidthProfileOf,
|
|
@@ -17519,6 +18105,8 @@ export {
|
|
|
17519
18105
|
vectorMaskedGeometry,
|
|
17520
18106
|
vectorMaskedLocalBounds,
|
|
17521
18107
|
vectorMaskedShapes,
|
|
18108
|
+
vectorMasterArt,
|
|
18109
|
+
vectorMasterPages,
|
|
17522
18110
|
vectorMeshColorAt,
|
|
17523
18111
|
warpMeshColumns as vectorMeshColumns,
|
|
17524
18112
|
warpMeshControlBounds as vectorMeshControlBounds,
|
|
@@ -17539,6 +18127,7 @@ export {
|
|
|
17539
18127
|
vectorNodeToBezier,
|
|
17540
18128
|
vectorNodesNear,
|
|
17541
18129
|
vectorOperandOperation,
|
|
18130
|
+
vectorPages,
|
|
17542
18131
|
vectorPaintLayerNodes,
|
|
17543
18132
|
vectorPaintSolid,
|
|
17544
18133
|
vectorPaintSwatch,
|
|
@@ -17554,6 +18143,13 @@ export {
|
|
|
17554
18143
|
vectorPathTextPositions,
|
|
17555
18144
|
vectorPathWorldBezier,
|
|
17556
18145
|
vectorPathfinderShape,
|
|
18146
|
+
vectorPerspectiveFlatToPlane,
|
|
18147
|
+
vectorPerspectiveGridLines,
|
|
18148
|
+
vectorPerspectiveMapPath,
|
|
18149
|
+
vectorPerspectivePlaneMap,
|
|
18150
|
+
vectorPerspectivePlaneToFlat,
|
|
18151
|
+
vectorPerspectivePlanes,
|
|
18152
|
+
vectorPerspectivePreset,
|
|
17557
18153
|
vectorPolarAngles,
|
|
17558
18154
|
vectorPolarIncrementOf,
|
|
17559
18155
|
vectorRepeaterCopies,
|