@pixerate/editor 0.140.3 → 0.141.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/agent/canvasPlayback.d.cts +15 -0
- package/dist/agent/canvasPlayback.d.ts +15 -0
- package/dist/agent/index.cjs +144 -23
- package/dist/agent/index.d.cts +1 -0
- package/dist/agent/index.d.ts +1 -0
- package/dist/agent/index.js +125 -4
- package/dist/agent/providers.d.cts +8 -0
- package/dist/agent/providers.d.ts +8 -0
- package/dist/agent/types.d.cts +3 -0
- package/dist/agent/types.d.ts +3 -0
- package/dist/animation/index.cjs +2 -2
- package/dist/animation/index.js +1 -1
- package/dist/animation/presence.d.cts +1 -75
- package/dist/animation/presence.d.ts +1 -75
- package/dist/animation-editor/index.cjs +55 -55
- package/dist/animation-editor/index.js +2 -2
- package/dist/bridge/cli.cjs +3 -3
- package/dist/bridge/cli.js +2 -2
- package/dist/bridge/index.cjs +3 -3
- package/dist/bridge/index.js +2 -2
- package/dist/canvas/index.cjs +336 -646
- package/dist/canvas/index.d.cts +1 -0
- package/dist/canvas/index.d.ts +1 -0
- package/dist/canvas/index.js +44 -354
- package/dist/canvas/playback.d.cts +14 -0
- package/dist/canvas/playback.d.ts +14 -0
- package/dist/chart/index.cjs +7 -7
- package/dist/chart/index.js +1 -1
- package/dist/chunk-6SFREX6H.cjs +406 -0
- package/dist/{chunk-XGOU44RJ.js → chunk-77SG47WT.js} +80 -9
- package/dist/{chunk-2SHFIVC3.js → chunk-DAS7M4RY.js} +1 -1
- package/dist/chunk-DW4CV5H4.js +591 -0
- package/dist/{chunk-UMS6YFA6.js → chunk-EAQ4BGNS.js} +1 -1
- package/dist/{chunk-AGCD3EHB.cjs → chunk-ENIZYNEF.cjs} +7 -7
- package/dist/{chunk-VSR5A22L.cjs → chunk-H6FX45CP.cjs} +35 -35
- package/dist/{chunk-RCUX6CT2.cjs → chunk-HRI3ZMDM.cjs} +110 -39
- package/dist/chunk-MFFE55CS.js +406 -0
- package/dist/{chunk-BSGPXPTW.js → chunk-PEEP2YR7.js} +1 -1
- package/dist/{chunk-RB62U6MS.js → chunk-RFBFTLVN.js} +27 -5
- package/dist/chunk-UBRYHNRU.cjs +591 -0
- package/dist/{chunk-GEY73RUW.cjs → chunk-UJGAA6AK.cjs} +1 -1
- package/dist/{chunk-6UZCFD7Y.js → chunk-VM6JYWXQ.js} +1 -1
- package/dist/{chunk-O3ZU6QIZ.cjs → chunk-XNZWATSB.cjs} +81 -81
- package/dist/{chunk-HDK3T2QS.cjs → chunk-Y4BWZB6J.cjs} +29 -7
- package/dist/commands/index.cjs +37 -1
- package/dist/commands/index.js +36 -0
- package/dist/commands/registry.d.cts +11 -0
- package/dist/commands/registry.d.ts +11 -0
- package/dist/diagram/index.cjs +7 -7
- package/dist/diagram/index.js +1 -1
- package/dist/image-editor/index.cjs +720 -628
- package/dist/image-editor/index.d.cts +1 -0
- package/dist/image-editor/index.d.ts +1 -0
- package/dist/image-editor/index.js +109 -17
- package/dist/image-editor/playback.d.cts +22 -0
- package/dist/image-editor/playback.d.ts +22 -0
- package/dist/paint-editor/index.cjs +13 -13
- package/dist/paint-editor/index.js +3 -3
- package/dist/tools/index.cjs +33 -3
- package/dist/tools/index.d.cts +2 -0
- package/dist/tools/index.d.ts +2 -0
- package/dist/tools/index.js +32 -2
- package/dist/tools/playback.d.cts +205 -0
- package/dist/tools/playback.d.ts +205 -0
- package/dist/tools/presence.d.cts +82 -0
- package/dist/tools/presence.d.ts +82 -0
- package/dist/tools/registry.d.cts +45 -6
- package/dist/tools/registry.d.ts +45 -6
- package/dist/tools/view.d.cts +2 -4
- package/dist/tools/view.d.ts +2 -4
- package/dist/vector/index.cjs +1159 -1042
- package/dist/vector/index.d.cts +1 -0
- package/dist/vector/index.d.ts +1 -0
- package/dist/vector/index.js +142 -25
- package/dist/vector/playback.d.cts +13 -0
- package/dist/vector/playback.d.ts +13 -0
- package/package.json +1 -1
- package/skills/pixerate-agent-tools/SKILL.md +13 -0
- package/skills/pixerate-canvas/SKILL.md +3 -0
- package/skills/pixerate-image-editor/SKILL.md +2 -2
- package/skills/pixerate-vector/SKILL.md +5 -0
- package/dist/chunk-BTZS3KZY.js +0 -221
- package/dist/chunk-MRD3NXKR.cjs +0 -221
- /package/dist/{chunk-K73HMKQP.js → chunk-PLKIYNJZ.js} +0 -0
- /package/dist/{chunk-LACYURUW.cjs → chunk-TNCWKC5M.cjs} +0 -0
package/dist/vector/index.d.cts
CHANGED
|
@@ -52,3 +52,4 @@ export { createCanvasTextShaper, createMetricTextShaper, createOutlineTextShaper
|
|
|
52
52
|
export { loadOpenTypeFont, parseOpenTypeFont, type OpenTypeFont } from '../text/opentype.cjs';
|
|
53
53
|
export type { TextFont, TextShaper } from '../text/types.cjs';
|
|
54
54
|
export * from './effect-tools.cjs';
|
|
55
|
+
export * from './playback.cjs';
|
package/dist/vector/index.d.ts
CHANGED
|
@@ -52,3 +52,4 @@ export { createCanvasTextShaper, createMetricTextShaper, createOutlineTextShaper
|
|
|
52
52
|
export { loadOpenTypeFont, parseOpenTypeFont, type OpenTypeFont } from '../text/opentype.js';
|
|
53
53
|
export type { TextFont, TextShaper } from '../text/types.js';
|
|
54
54
|
export * from './effect-tools.js';
|
|
55
|
+
export * from './playback.js';
|
package/dist/vector/index.js
CHANGED
|
@@ -38,7 +38,7 @@ import {
|
|
|
38
38
|
reverseMorphContour,
|
|
39
39
|
subpathToMorphContour,
|
|
40
40
|
turnMorphContour
|
|
41
|
-
} from "../chunk-
|
|
41
|
+
} from "../chunk-DAS7M4RY.js";
|
|
42
42
|
import {
|
|
43
43
|
DEFAULT_VECTOR_FONT,
|
|
44
44
|
IDENTITY_MATRIX,
|
|
@@ -507,7 +507,7 @@ import {
|
|
|
507
507
|
withVectorStrokes,
|
|
508
508
|
withVectorTargetPaint,
|
|
509
509
|
zigzagPaths
|
|
510
|
-
} from "../chunk-
|
|
510
|
+
} from "../chunk-77SG47WT.js";
|
|
511
511
|
import "../chunk-ORDXMBD4.js";
|
|
512
512
|
import {
|
|
513
513
|
createProvenance
|
|
@@ -4169,8 +4169,8 @@ var Page = class {
|
|
|
4169
4169
|
const fns = list.slice(1).map((s, k) => `<< /FunctionType 2 /Domain [0 1] /C0 ${rgb(list[k].c)} /C1 ${rgb(s.c)} /N 1 >>`);
|
|
4170
4170
|
const fn = fns.length === 1 ? fns[0] : `<< /FunctionType 3 /Domain [${n(list[0].t)} ${n(list[list.length - 1].t)}] /Functions [${fns.join(" ")}] /Bounds [${list.slice(1, -1).map((s) => n(s.t)).join(" ")}] /Encode [${fns.map(() => "0 1").join(" ")}] >>`;
|
|
4171
4171
|
const a = def.attrs;
|
|
4172
|
-
const
|
|
4173
|
-
const coords = def.type === "linear" ? `/ShadingType 2 /Coords [${n(
|
|
4172
|
+
const num2 = (k, d = 0) => a[k] === void 0 ? d : parseFloat(String(a[k]));
|
|
4173
|
+
const coords = def.type === "linear" ? `/ShadingType 2 /Coords [${n(num2("x1"))} ${n(num2("y1"))} ${n(num2("x2", 1))} ${n(num2("y2"))}]` : `/ShadingType 3 /Coords [${n(num2("fx", num2("cx", 0.5)))} ${n(num2("fy", num2("cy", 0.5)))} ${n(num2("fr"))} ${n(num2("cx", 0.5))} ${n(num2("cy", 0.5))} ${n(num2("r", 0.5))}]`;
|
|
4174
4174
|
this.writer.shadingDicts.set(`${this.writer.pageIndex}:${name}`, `<< ${coords} /ColorSpace /DeviceRGB /Function ${fn} /Extend [true true] >>`);
|
|
4175
4175
|
return name;
|
|
4176
4176
|
}
|
|
@@ -4807,28 +4807,28 @@ function gradientOf(it, frame) {
|
|
|
4807
4807
|
}
|
|
4808
4808
|
function effectOf(it, frame, c, id) {
|
|
4809
4809
|
const v = (k) => lottieValueAt(it[k], frame);
|
|
4810
|
-
const
|
|
4810
|
+
const num2 = (k, d = 0) => v(k)[0] ?? d;
|
|
4811
4811
|
let raw = null;
|
|
4812
4812
|
switch (it.ty) {
|
|
4813
4813
|
case "tm":
|
|
4814
|
-
raw = { type: "trim", params: { start:
|
|
4814
|
+
raw = { type: "trim", params: { start: num2("s"), end: num2("e", 100), offset: num2("o"), mode: Number(it.m) === 2 ? "individual" : "simultaneous" } };
|
|
4815
4815
|
break;
|
|
4816
4816
|
case "rd":
|
|
4817
|
-
raw = { type: "roundCorners", params: { radius:
|
|
4817
|
+
raw = { type: "roundCorners", params: { radius: num2("r") } };
|
|
4818
4818
|
break;
|
|
4819
4819
|
case "pb":
|
|
4820
|
-
raw = { type: "puckerBloat", params: { amount:
|
|
4820
|
+
raw = { type: "puckerBloat", params: { amount: num2("a") } };
|
|
4821
4821
|
break;
|
|
4822
4822
|
case "tw": {
|
|
4823
4823
|
const [x = c.x, y = c.y] = v("c");
|
|
4824
|
-
raw = { type: "twist", params: { angle:
|
|
4824
|
+
raw = { type: "twist", params: { angle: num2("a"), center: { x: x - c.x, y: y - c.y } } };
|
|
4825
4825
|
break;
|
|
4826
4826
|
}
|
|
4827
4827
|
case "zz":
|
|
4828
|
-
raw = { type: "zigzag", params: { size:
|
|
4828
|
+
raw = { type: "zigzag", params: { size: num2("s"), ridges: num2("r"), smooth: num2("pt", 1) === 2 } };
|
|
4829
4829
|
break;
|
|
4830
4830
|
case "op":
|
|
4831
|
-
raw = { type: "offset", params: { amount:
|
|
4831
|
+
raw = { type: "offset", params: { amount: num2("a"), join: ["miter", "round", "bevel"][Number(it.lj ?? 1) - 1] ?? "miter", miterLimit: num2("ml", 4) || 4 } };
|
|
4832
4832
|
break;
|
|
4833
4833
|
case "mm":
|
|
4834
4834
|
raw = { type: "merge", params: { mode: MERGE[Number(it.mm ?? 1) - 1] ?? "merge" } };
|
|
@@ -4844,7 +4844,7 @@ function effectOf(it, frame, c, id) {
|
|
|
4844
4844
|
const [sx, sy] = at("s", [100, 100]);
|
|
4845
4845
|
raw = {
|
|
4846
4846
|
type: "repeater",
|
|
4847
|
-
params: { copies:
|
|
4847
|
+
params: { copies: num2("c", 1), offset: num2("o"), position: { x: px, y: py }, anchor: { x: ax - c.x, y: ay - c.y }, rotation: at("r", [0])[0], scale: { x: sx, y: sy }, startOpacity: at("so", [100])[0], endOpacity: at("eo", [100])[0], composite: Number(it.m) === 1 ? "above" : "below" }
|
|
4848
4848
|
};
|
|
4849
4849
|
break;
|
|
4850
4850
|
}
|
|
@@ -6456,11 +6456,11 @@ function segsToSubpath(segs, closed, types) {
|
|
|
6456
6456
|
const last = anchors.pop();
|
|
6457
6457
|
if (last.in) anchors[0].in = last.in;
|
|
6458
6458
|
}
|
|
6459
|
-
const
|
|
6459
|
+
const typed2 = anchors.map((a) => {
|
|
6460
6460
|
const type = types.get(`${a.x},${a.y}`);
|
|
6461
6461
|
return tidy(type ? { ...a, type } : a, !!type);
|
|
6462
6462
|
});
|
|
6463
|
-
return { anchors:
|
|
6463
|
+
return { anchors: typed2, closed };
|
|
6464
6464
|
}
|
|
6465
6465
|
var isZeroSeg = (s) => s.c.every((p) => Math.abs(p[0] - s.c[0][0]) < 1e-9 && Math.abs(p[1] - s.c[0][1]) < 1e-9);
|
|
6466
6466
|
function mergePair(a, b, tol) {
|
|
@@ -8497,10 +8497,10 @@ var VectorEditorController = class _VectorEditorController {
|
|
|
8497
8497
|
if (node?.type !== "path") return { ok: false, message: "There is no such path." };
|
|
8498
8498
|
const g = vectorStrokeWidthGeometry(node);
|
|
8499
8499
|
if (!g || !(g.unit > 0)) return { ok: false, message: "The path has no visible stroke." };
|
|
8500
|
-
const
|
|
8501
|
-
const t =
|
|
8502
|
-
const left =
|
|
8503
|
-
const right =
|
|
8500
|
+
const num2 = (v) => typeof v === "number" && Number.isFinite(v) ? v : void 0;
|
|
8501
|
+
const t = num2(values.t);
|
|
8502
|
+
const left = num2(values.left);
|
|
8503
|
+
const right = num2(values.right);
|
|
8504
8504
|
const scale = (w) => w === void 0 ? void 0 : Math.max(0, w) / g.unit;
|
|
8505
8505
|
const profile = sanitizeWidthProfile(node.strokeWidthProfile);
|
|
8506
8506
|
let points;
|
|
@@ -10768,18 +10768,18 @@ var VectorEditorController = class _VectorEditorController {
|
|
|
10768
10768
|
const sp = pen && node ? node.subpaths[pen.subpath] : void 0;
|
|
10769
10769
|
if (!pen || !node || !sp?.anchors.length) return { ok: false, message: "Start a path with the pen first: typed entry places its next point." };
|
|
10770
10770
|
const last = getAnchorWorld(this.doc, { nodeId: pen.nodeId, subpath: pen.subpath, index: sp.anchors.length - 1 });
|
|
10771
|
-
const
|
|
10771
|
+
const num2 = "(-?(?:\\d+\\.?\\d*|\\.\\d+))";
|
|
10772
10772
|
const t = text.replace(/\s+/g, "");
|
|
10773
10773
|
let target = null;
|
|
10774
10774
|
let m;
|
|
10775
|
-
if (m = t.match(new RegExp(`^@${
|
|
10776
|
-
else if (m = t.match(new RegExp(`^${
|
|
10777
|
-
else if (m = t.match(new RegExp(`^${
|
|
10775
|
+
if (m = t.match(new RegExp(`^@${num2},${num2}$`))) target = { x: last.x + parseFloat(m[1]), y: last.y + parseFloat(m[2]) };
|
|
10776
|
+
else if (m = t.match(new RegExp(`^${num2},${num2}$`))) target = { x: parseFloat(m[1]), y: parseFloat(m[2]) };
|
|
10777
|
+
else if (m = t.match(new RegExp(`^${num2}<${num2}$`))) {
|
|
10778
10778
|
const base = this.snap.polarRelative ? (this.penAngles().angles?.[0] ?? this.snap.angles[0] ?? 0) - (this.snap.angles[0] ?? 0) : 0;
|
|
10779
10779
|
const dir = vectorAngleDirection(parseFloat(m[2]) + base);
|
|
10780
10780
|
const len2 = parseFloat(m[1]);
|
|
10781
10781
|
target = { x: last.x + dir.x * len2, y: last.y + dir.y * len2 };
|
|
10782
|
-
} else if (m = t.match(new RegExp(`^${
|
|
10782
|
+
} else if (m = t.match(new RegExp(`^${num2}$`))) {
|
|
10783
10783
|
const toward = this.pointer;
|
|
10784
10784
|
const d = toward ? Math.hypot(toward.x - last.x, toward.y - last.y) : 0;
|
|
10785
10785
|
if (!toward || d < 1e-9) return { ok: false, message: "Point the pointer the way the distance should go (or type length<angle)." };
|
|
@@ -14974,6 +14974,120 @@ function pencilPressureProfile(points, pressures) {
|
|
|
14974
14974
|
return pressureWidthProfile(s.map((d, i) => ({ t: d / total, pressure: pressures[i] })));
|
|
14975
14975
|
}
|
|
14976
14976
|
|
|
14977
|
+
// src/vector/playback.ts
|
|
14978
|
+
var VECTOR_PLAYBACK_KIND = "vector";
|
|
14979
|
+
function createVectorPlaybackLocator(controller) {
|
|
14980
|
+
return (ref) => {
|
|
14981
|
+
if (ref.kind !== VECTOR_PLAYBACK_KIND && ref.kind !== "item") return null;
|
|
14982
|
+
const node = controller.getNode(ref.id);
|
|
14983
|
+
if (!node) return null;
|
|
14984
|
+
const b = vectorNodeBounds(node, vectorParentMatrix(controller.getState().document.nodes, ref.id) ?? IDENTITY_MATRIX);
|
|
14985
|
+
if (!b) return null;
|
|
14986
|
+
const w = Math.max(b.width, 4);
|
|
14987
|
+
const h = Math.max(b.height, 4);
|
|
14988
|
+
return { x: b.x - (w - b.width) / 2, y: b.y - (h - b.height) / 2, width: w, height: h };
|
|
14989
|
+
};
|
|
14990
|
+
}
|
|
14991
|
+
var num = (v) => typeof v === "number" && Number.isFinite(v);
|
|
14992
|
+
var dragOut = (from, to) => [
|
|
14993
|
+
{ type: "move", to: from },
|
|
14994
|
+
{ type: "press" },
|
|
14995
|
+
{ type: "drag", to },
|
|
14996
|
+
{ type: "release" }
|
|
14997
|
+
];
|
|
14998
|
+
var click = (at) => [{ type: "move", to: at }, { type: "press" }, { type: "release" }];
|
|
14999
|
+
var typed = (text) => {
|
|
15000
|
+
if (typeof text !== "string" || !text.trim()) return [];
|
|
15001
|
+
const line2 = text.replace(/\s+/g, " ").trim();
|
|
15002
|
+
return [{ type: "type", text: line2.length > 60 ? `${line2.slice(0, 59)}\u2026` : line2 }];
|
|
15003
|
+
};
|
|
15004
|
+
function pathPoints(d, max = 24) {
|
|
15005
|
+
let anchors;
|
|
15006
|
+
try {
|
|
15007
|
+
anchors = bezierToSubpaths(d).flatMap((s) => s.anchors.map((a) => ({ x: a.x, y: a.y })));
|
|
15008
|
+
} catch {
|
|
15009
|
+
return [];
|
|
15010
|
+
}
|
|
15011
|
+
if (anchors.length <= max) return anchors;
|
|
15012
|
+
const step = (anchors.length - 1) / (max - 1);
|
|
15013
|
+
return Array.from({ length: max }, (_, i) => anchors[Math.round(i * step)]);
|
|
15014
|
+
}
|
|
15015
|
+
function trace(points) {
|
|
15016
|
+
if (!points.length) return [];
|
|
15017
|
+
const [first, ...rest] = points;
|
|
15018
|
+
const total = rest.reduce((sum, p, i) => sum + Math.hypot(p.x - (i ? rest[i - 1] : first).x, p.y - (i ? rest[i - 1] : first).y), 0);
|
|
15019
|
+
const ms = (p, i) => {
|
|
15020
|
+
const prev = i ? rest[i - 1] : first;
|
|
15021
|
+
return total > 0 ? Math.max(16, 900 * Math.hypot(p.x - prev.x, p.y - prev.y) / total) : 16;
|
|
15022
|
+
};
|
|
15023
|
+
return [{ type: "move", to: first }, { type: "press" }, ...rest.map((p, i) => ({ type: "drag", to: p, ms: ms(p, i) })), { type: "release" }];
|
|
15024
|
+
}
|
|
15025
|
+
var PLANS = {
|
|
15026
|
+
addShape: (p) => {
|
|
15027
|
+
if (![p.x, p.y, p.width, p.height].every(num)) return null;
|
|
15028
|
+
return dragOut({ x: p.x, y: p.y }, { x: p.x + p.width, y: p.y + p.height });
|
|
15029
|
+
},
|
|
15030
|
+
addPath: (p) => typeof p.d === "string" ? trace(pathPoints(p.d)) : null,
|
|
15031
|
+
addText: (p) => {
|
|
15032
|
+
if (typeof p.path === "string") {
|
|
15033
|
+
const points = pathPoints(p.path, 2);
|
|
15034
|
+
return points.length ? [...click(points[0]), ...typed(p.text)] : null;
|
|
15035
|
+
}
|
|
15036
|
+
const x = num(p.x) ? p.x : 0;
|
|
15037
|
+
const y = num(p.y) ? p.y : 0;
|
|
15038
|
+
const start = num(p.width) && num(p.height) ? dragOut({ x, y }, { x: x + p.width, y: y + p.height }) : click({ x, y });
|
|
15039
|
+
return [...start, ...typed(p.text)];
|
|
15040
|
+
},
|
|
15041
|
+
placeSymbol: (p, controller) => {
|
|
15042
|
+
const doc = controller.getState().document;
|
|
15043
|
+
const t = Array.isArray(p.transform) && p.transform.length === 6 ? p.transform : null;
|
|
15044
|
+
const at = t ? { x: t[4], y: t[5] } : { x: num(p.x) ? p.x : doc.width / 2, y: num(p.y) ? p.y : doc.height / 2 };
|
|
15045
|
+
return click(at);
|
|
15046
|
+
},
|
|
15047
|
+
setTextStyle: (p, controller) => {
|
|
15048
|
+
const node = controller.getNode(p.id);
|
|
15049
|
+
if (node?.type !== "text") return null;
|
|
15050
|
+
const rect = createVectorPlaybackLocator(controller)({ kind: VECTOR_PLAYBACK_KIND, id: p.id });
|
|
15051
|
+
if (!rect) return null;
|
|
15052
|
+
const length = Math.max(1, node.text.length);
|
|
15053
|
+
const start = Math.min(length, Math.max(0, num(p.start) ? p.start : 0));
|
|
15054
|
+
const end = Math.min(length, Math.max(start, num(p.end) ? p.end : length));
|
|
15055
|
+
const y = rect.y + rect.height / 2;
|
|
15056
|
+
return [
|
|
15057
|
+
{ type: "focus", rect },
|
|
15058
|
+
...dragOut({ x: rect.x + rect.width * start / length, y }, { x: rect.x + rect.width * end / length, y })
|
|
15059
|
+
];
|
|
15060
|
+
},
|
|
15061
|
+
setMeshPoint: (p, controller) => {
|
|
15062
|
+
const shading = controller.getShading(p.id);
|
|
15063
|
+
const point = shading?.points[p.index];
|
|
15064
|
+
if (!point) return null;
|
|
15065
|
+
return num(p.x) && num(p.y) ? dragOut(point, { x: p.x, y: p.y }) : click(point);
|
|
15066
|
+
}
|
|
15067
|
+
};
|
|
15068
|
+
var placeImage = (p, controller) => {
|
|
15069
|
+
const doc = controller.getState().document;
|
|
15070
|
+
const x = num(p.x) ? p.x : 0;
|
|
15071
|
+
const y = num(p.y) ? p.y : 0;
|
|
15072
|
+
const w = num(p.width) ? p.width : doc.width - x;
|
|
15073
|
+
return dragOut({ x, y }, { x: x + w, y: y + w });
|
|
15074
|
+
};
|
|
15075
|
+
function withVectorPlayback(controller, prefix, commands) {
|
|
15076
|
+
return commands.map((spec) => {
|
|
15077
|
+
if (!spec.id.startsWith(prefix)) return spec;
|
|
15078
|
+
const name = spec.id.slice(prefix.length);
|
|
15079
|
+
const props = spec.params?.properties ?? {};
|
|
15080
|
+
const planner = PLANS[name] ?? (/Image$/.test(name) && "x" in props && "width" in props ? placeImage : void 0);
|
|
15081
|
+
const surface = spec.playbackSurface ?? spec.scope ?? "vector";
|
|
15082
|
+
if (!planner || spec.plan) return { ...spec, playbackSurface: surface };
|
|
15083
|
+
return {
|
|
15084
|
+
...spec,
|
|
15085
|
+
playbackSurface: surface,
|
|
15086
|
+
plan: (_ctx, params) => planner(params ?? {}, controller)
|
|
15087
|
+
};
|
|
15088
|
+
});
|
|
15089
|
+
}
|
|
15090
|
+
|
|
14977
15091
|
// src/vector/commands.ts
|
|
14978
15092
|
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). extrude: mode parallel|perspective, angle (degrees) and depth (units) for parallel, vanishingPoint {x, y} (offset from the middle) and toward (percent of the way there) for perspective, color (null: the shape fill colour), lightAngle (degrees the light comes from, 0 right, -90 above), shading (percent). bevel: width (units), lightAngle (degrees), shading (percent), color (null: the shape fill colour). 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).";
|
|
14979
15093
|
var fail = (message) => {
|
|
@@ -17275,7 +17389,7 @@ function createVectorCommands(controller, options = {}) {
|
|
|
17275
17389
|
}
|
|
17276
17390
|
}
|
|
17277
17391
|
];
|
|
17278
|
-
return [
|
|
17392
|
+
return withVectorPlayback(controller, prefix, [
|
|
17279
17393
|
{
|
|
17280
17394
|
...base,
|
|
17281
17395
|
id: `${prefix}list`,
|
|
@@ -18186,7 +18300,7 @@ function createVectorCommands(controller, options = {}) {
|
|
|
18186
18300
|
return { nodes: controller.getState().document.nodes.length, selection: controller.getState().selection };
|
|
18187
18301
|
}
|
|
18188
18302
|
}
|
|
18189
|
-
];
|
|
18303
|
+
]);
|
|
18190
18304
|
}
|
|
18191
18305
|
|
|
18192
18306
|
// src/vector/generate.ts
|
|
@@ -18680,6 +18794,7 @@ export {
|
|
|
18680
18794
|
VECTOR_PATH_TEXT_BASELINES,
|
|
18681
18795
|
VECTOR_PENCIL_STRING_PX,
|
|
18682
18796
|
VECTOR_PERSPECTIVE_PLANES,
|
|
18797
|
+
VECTOR_PLAYBACK_KIND,
|
|
18683
18798
|
VECTOR_PRESSURE_NOMINAL,
|
|
18684
18799
|
VECTOR_ROTATE_HANDLE_OFFSET,
|
|
18685
18800
|
VECTOR_SPATIAL_MIN,
|
|
@@ -18768,6 +18883,7 @@ export {
|
|
|
18768
18883
|
createVectorGenerationToolProvider,
|
|
18769
18884
|
createVectorMeshGradient,
|
|
18770
18885
|
createVectorMorph,
|
|
18886
|
+
createVectorPlaybackLocator,
|
|
18771
18887
|
cssFontFamily,
|
|
18772
18888
|
curvatureMoveAnchor,
|
|
18773
18889
|
cutSubpathAt,
|
|
@@ -19283,6 +19399,7 @@ export {
|
|
|
19283
19399
|
withVectorAnchorIds,
|
|
19284
19400
|
withVectorDocumentAnchorIds,
|
|
19285
19401
|
withVectorFills,
|
|
19402
|
+
withVectorPlayback,
|
|
19286
19403
|
withVectorStrokes,
|
|
19287
19404
|
withVectorTargetPaint,
|
|
19288
19405
|
zigzagPaths
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { CommandSpec } from '../commands/registry.cjs';
|
|
2
|
+
import type { PlaybackRect, PlaybackRef } from '../tools/playback.cjs';
|
|
3
|
+
import type { VectorEditorController } from './controller.cjs';
|
|
4
|
+
/** The playback kind of a vector node (`{ kind: 'vector', id }`, as in `data-vector-id`). */
|
|
5
|
+
export declare const VECTOR_PLAYBACK_KIND = "vector";
|
|
6
|
+
/** Finds `{ kind: 'vector', id }` (a node's document-space bounds) for agent playback. */
|
|
7
|
+
export declare function createVectorPlaybackLocator(controller: Pick<VectorEditorController, 'getState' | 'getNode'>): (ref: PlaybackRef) => PlaybackRect | null;
|
|
8
|
+
/**
|
|
9
|
+
* Adds agent playback plans to vector commands whose effect has a place but no ids yet (shapes,
|
|
10
|
+
* paths, text, symbols, stylized images) and to edits of a part of a node (a text range, a mesh
|
|
11
|
+
* point). Other commands play from the ids in their params.
|
|
12
|
+
*/
|
|
13
|
+
export declare function withVectorPlayback(controller: VectorEditorController, prefix: string, commands: CommandSpec[]): CommandSpec[];
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { CommandSpec } from '../commands/registry.js';
|
|
2
|
+
import type { PlaybackRect, PlaybackRef } from '../tools/playback.js';
|
|
3
|
+
import type { VectorEditorController } from './controller.js';
|
|
4
|
+
/** The playback kind of a vector node (`{ kind: 'vector', id }`, as in `data-vector-id`). */
|
|
5
|
+
export declare const VECTOR_PLAYBACK_KIND = "vector";
|
|
6
|
+
/** Finds `{ kind: 'vector', id }` (a node's document-space bounds) for agent playback. */
|
|
7
|
+
export declare function createVectorPlaybackLocator(controller: Pick<VectorEditorController, 'getState' | 'getNode'>): (ref: PlaybackRef) => PlaybackRect | null;
|
|
8
|
+
/**
|
|
9
|
+
* Adds agent playback plans to vector commands whose effect has a place but no ids yet (shapes,
|
|
10
|
+
* paths, text, symbols, stylized images) and to edits of a part of a node (a text range, a mesh
|
|
11
|
+
* point). Other commands play from the ids in their params.
|
|
12
|
+
*/
|
|
13
|
+
export declare function withVectorPlayback(controller: VectorEditorController, prefix: string, commands: CommandSpec[]): CommandSpec[];
|
package/package.json
CHANGED
|
@@ -61,6 +61,19 @@ editor's, or (in discovery mode) only `list_toolsets`, `search_tools`, `enable_t
|
|
|
61
61
|
6. **Undo your own mistakes** with the domain's `undo_*` tool or the `history.undo` command, not
|
|
62
62
|
by hand-reverting with more edits.
|
|
63
63
|
|
|
64
|
+
## Playback
|
|
65
|
+
|
|
66
|
+
The host may act your calls out on screen (agent playback): your cursor glides to what a call
|
|
67
|
+
names, presses, drags or types, and the change lands as one undo step. Results are the same with
|
|
68
|
+
or without it, and calls simply take a little longer while it plays.
|
|
69
|
+
|
|
70
|
+
- Do not add waits or poll for the animation; each call returns once its change is applied.
|
|
71
|
+
- Name your targets with the ids read tools return (`ids`, `nodeId`, `layerId`, a range). They are
|
|
72
|
+
also what the cursor heads for, so the user can follow along.
|
|
73
|
+
- A batch (`run_commands`) plays its steps' moves first, then applies once as one undo step.
|
|
74
|
+
- If you connect over MCP, your client's name labels your cursor; several agents get separate
|
|
75
|
+
cursors.
|
|
76
|
+
|
|
64
77
|
## Errors
|
|
65
78
|
|
|
66
79
|
A failed call comes back as an `isError` result whose text says what was wrong and how to fix
|
|
@@ -271,6 +271,9 @@ effects provider (for example Flair); without one the read tools say so and the
|
|
|
271
271
|
`get_editor_state` again, not guess.
|
|
272
272
|
- `canvas_add_node` with `nearNodeId` also adds an edge from that node. Pass an explicit
|
|
273
273
|
`position` (and no `nearNodeId`) for a free-standing design element.
|
|
274
|
+
- With agent playback on, the cursor clicks where `canvas_add_node` will place the node, drags
|
|
275
|
+
`canvas_connect` from source to target, and rings the nodes a layout or arrange command moved.
|
|
276
|
+
Nothing about the calls changes: still read ids with `get_editor_state` and pass them back.
|
|
274
277
|
- `canvas_update_node` changes `data` only. Move nodes with layout, align or distribute commands,
|
|
275
278
|
or by the host's own means; do not expect `position` inside `data` to move anything.
|
|
276
279
|
- Align needs at least two nodes and distribute at least three; locked nodes never move. Shape
|
|
@@ -415,8 +415,8 @@ in the source frame at the document's bit depth, colour mode and profile. Read
|
|
|
415
415
|
|
|
416
416
|
## Pitfalls
|
|
417
417
|
|
|
418
|
-
-
|
|
419
|
-
|
|
418
|
+
- Agent playback (if on) opens each write's panel, then traces `points`, drags boxes or visits the layers and sliders named; results are unchanged.
|
|
419
|
+
- Effects need a shape: on an empty layer they draw nothing. They cannot go on adjustment layers. A clipped layer's effects stay inside the layer it is clipped to.
|
|
420
420
|
- `bevel-emboss` has no `blend` / `opacity`: it uses `highlightBlend`, `highlightOpacity`,
|
|
421
421
|
`shadowBlend` and `shadowOpacity`. Inner shadows and inner glows use `choke`, not `spread`.
|
|
422
422
|
- Glows paint a colour or a gradient, never a pattern; strokes take all three. Pattern effects
|
|
@@ -459,6 +459,11 @@ the animation editor.
|
|
|
459
459
|
|
|
460
460
|
The most common ones are below. Read [references/pitfalls.md](references/pitfalls.md) before working with connectors, frames, masks, filters, text, symbols, constraints, blends, gradient meshes or live corners.
|
|
461
461
|
|
|
462
|
+
- With agent playback on, `vector.addShape` is dragged out from (x, y) to (x + width, y + height),
|
|
463
|
+
`vector.addPath` is traced through its anchors, and text is clicked in and typed out. So give
|
|
464
|
+
shapes their real place and size in the first call rather than adding them at 0, 0 and moving
|
|
465
|
+
them after: the user watches the cursor go where the shape lands. Commands with `ids` visit those
|
|
466
|
+
nodes; nothing else about the calls changes.
|
|
462
467
|
- `d` and anchor positions are in the node's own space; `bounds` are in document space. For
|
|
463
468
|
rotated nodes (`rotation` not 0), `vector.moveAnchor` and `vector.bendSegment` take document
|
|
464
469
|
coordinates, so compute them from the drawn position, not from `d`.
|
package/dist/chunk-BTZS3KZY.js
DELETED
|
@@ -1,221 +0,0 @@
|
|
|
1
|
-
// src/canvas/layout.ts
|
|
2
|
-
import dagre from "@dagrejs/dagre";
|
|
3
|
-
var DEFAULT_NODE_WIDTH = 200;
|
|
4
|
-
var DEFAULT_NODE_HEIGHT = 60;
|
|
5
|
-
var DEFAULT_PLACEMENT_GAP = 48;
|
|
6
|
-
function getCenteredNodePosition(width = 0, height = 0, screenToFlowPosition, screenDimensions) {
|
|
7
|
-
const rect = screenDimensions ?? (typeof document !== "undefined" ? { width: document.documentElement.clientWidth, height: document.documentElement.clientHeight } : { width: 1920, height: 1080 });
|
|
8
|
-
const flowPos = screenToFlowPosition({ x: rect.width / 2, y: rect.height / 2 });
|
|
9
|
-
return {
|
|
10
|
-
x: flowPos.x - width / 2,
|
|
11
|
-
y: flowPos.y - height / 2
|
|
12
|
-
};
|
|
13
|
-
}
|
|
14
|
-
function centerNodes(nodes, screenToFlowPosition, getNodesBounds, screenDimensions) {
|
|
15
|
-
if (nodes.length === 0) {
|
|
16
|
-
return [];
|
|
17
|
-
}
|
|
18
|
-
const bounds = getNodesBounds(nodes);
|
|
19
|
-
const boundingBoxOrigin = { x: bounds.x, y: bounds.y };
|
|
20
|
-
const centeredPosition = getCenteredNodePosition(
|
|
21
|
-
bounds.width,
|
|
22
|
-
bounds.height,
|
|
23
|
-
screenToFlowPosition,
|
|
24
|
-
screenDimensions
|
|
25
|
-
);
|
|
26
|
-
const deltaX = centeredPosition.x - boundingBoxOrigin.x;
|
|
27
|
-
const deltaY = centeredPosition.y - boundingBoxOrigin.y;
|
|
28
|
-
return nodes.map((node) => ({
|
|
29
|
-
...node,
|
|
30
|
-
position: {
|
|
31
|
-
x: node.position.x + deltaX,
|
|
32
|
-
y: node.position.y + deltaY
|
|
33
|
-
}
|
|
34
|
-
}));
|
|
35
|
-
}
|
|
36
|
-
function getLayoutedNodes(nodes, edges, getNodesBounds, options = {}) {
|
|
37
|
-
if (nodes.length === 0) return [];
|
|
38
|
-
const {
|
|
39
|
-
direction = "LR",
|
|
40
|
-
ranksep = 100,
|
|
41
|
-
nodesep = 25,
|
|
42
|
-
defaultNodeWidth = DEFAULT_NODE_WIDTH,
|
|
43
|
-
defaultNodeHeight = DEFAULT_NODE_HEIGHT
|
|
44
|
-
} = options;
|
|
45
|
-
const dagreGraph = new dagre.graphlib.Graph();
|
|
46
|
-
dagreGraph.setDefaultEdgeLabel(() => ({}));
|
|
47
|
-
dagreGraph.setGraph({ rankdir: direction, ranksep, nodesep });
|
|
48
|
-
const nodeIds = new Set(nodes.map((node) => node.id));
|
|
49
|
-
nodes.forEach((node) => {
|
|
50
|
-
const nodeWidth = node.measured?.width ?? node.width ?? defaultNodeWidth;
|
|
51
|
-
const nodeHeight = node.measured?.height ?? node.height ?? defaultNodeHeight;
|
|
52
|
-
dagreGraph.setNode(node.id, { width: nodeWidth, height: nodeHeight });
|
|
53
|
-
});
|
|
54
|
-
edges.forEach((edge) => {
|
|
55
|
-
if (nodeIds.has(edge.source) && nodeIds.has(edge.target)) {
|
|
56
|
-
dagreGraph.setEdge(edge.source, edge.target);
|
|
57
|
-
}
|
|
58
|
-
});
|
|
59
|
-
dagre.layout(dagreGraph);
|
|
60
|
-
return nodes.map((node) => {
|
|
61
|
-
const nodeWithPosition = dagreGraph.node(node.id);
|
|
62
|
-
const nodeWidth = node.measured?.width ?? node.width ?? defaultNodeWidth;
|
|
63
|
-
const nodeHeight = node.measured?.height ?? node.height ?? defaultNodeHeight;
|
|
64
|
-
return {
|
|
65
|
-
...node,
|
|
66
|
-
position: {
|
|
67
|
-
x: nodeWithPosition.x - nodeWidth / 2,
|
|
68
|
-
y: nodeWithPosition.y - nodeHeight / 2
|
|
69
|
-
}
|
|
70
|
-
};
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
function estimateNodeSize(node, defaultWidth = DEFAULT_NODE_WIDTH, defaultHeight = DEFAULT_NODE_HEIGHT) {
|
|
74
|
-
const label = String(node.data?.label ?? node.data?.title ?? node.id ?? "");
|
|
75
|
-
const lines = label.split(/\n|<br\s*\/?>/);
|
|
76
|
-
const longest = Math.max(...lines.map((l) => l.replace(/<[^>]+>/g, "").length), 1);
|
|
77
|
-
const width = Math.min(480, Math.max(defaultWidth, longest * 8 + 48));
|
|
78
|
-
const height = Math.max(defaultHeight, lines.length * 20 + 24);
|
|
79
|
-
return { width, height };
|
|
80
|
-
}
|
|
81
|
-
function boundsOf(rects) {
|
|
82
|
-
if (!rects.length) return null;
|
|
83
|
-
const minX = Math.min(...rects.map((r) => r.x));
|
|
84
|
-
const minY = Math.min(...rects.map((r) => r.y));
|
|
85
|
-
const maxX = Math.max(...rects.map((r) => r.x + r.width));
|
|
86
|
-
const maxY = Math.max(...rects.map((r) => r.y + r.height));
|
|
87
|
-
return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };
|
|
88
|
-
}
|
|
89
|
-
function centre(r) {
|
|
90
|
-
return { x: r.x + r.width / 2, y: r.y + r.height / 2 };
|
|
91
|
-
}
|
|
92
|
-
function overlaps(a, b, pad = 16) {
|
|
93
|
-
return a.x < b.x + b.width + pad && a.x + a.width + pad > b.x && a.y < b.y + b.height + pad && a.y + a.height + pad > b.y;
|
|
94
|
-
}
|
|
95
|
-
function flowSide(direction = "LR") {
|
|
96
|
-
switch (direction) {
|
|
97
|
-
case "LR":
|
|
98
|
-
return "right";
|
|
99
|
-
case "RL":
|
|
100
|
-
return "left";
|
|
101
|
-
case "BT":
|
|
102
|
-
return "above";
|
|
103
|
-
case "TB":
|
|
104
|
-
default:
|
|
105
|
-
return "below";
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
function ensureLayout(nodes, edges, options = {}) {
|
|
109
|
-
if (nodes.length === 0) return [];
|
|
110
|
-
const stored = options.storedPositions ?? {};
|
|
111
|
-
const missing = nodes.filter((n) => !stored[n.id]);
|
|
112
|
-
if (missing.length === 0) {
|
|
113
|
-
return nodes.map((n) => ({
|
|
114
|
-
...n,
|
|
115
|
-
position: { ...stored[n.id] }
|
|
116
|
-
}));
|
|
117
|
-
}
|
|
118
|
-
const autoLayouted = getLayoutedNodes(nodes, edges, void 0, options);
|
|
119
|
-
const autoMap = new Map(
|
|
120
|
-
autoLayouted.map((n) => [n.id, n.position])
|
|
121
|
-
);
|
|
122
|
-
const both = nodes.filter((n) => stored[n.id] && autoMap.has(n.id));
|
|
123
|
-
if (both.length === 0) {
|
|
124
|
-
return autoLayouted;
|
|
125
|
-
}
|
|
126
|
-
let dx = 0;
|
|
127
|
-
let dy = 0;
|
|
128
|
-
for (const n of both) {
|
|
129
|
-
const s = stored[n.id];
|
|
130
|
-
const a = autoMap.get(n.id);
|
|
131
|
-
dx += s.x - a.x;
|
|
132
|
-
dy += s.y - a.y;
|
|
133
|
-
}
|
|
134
|
-
dx /= both.length;
|
|
135
|
-
dy /= both.length;
|
|
136
|
-
return nodes.map((node) => {
|
|
137
|
-
if (stored[node.id]) {
|
|
138
|
-
return {
|
|
139
|
-
...node,
|
|
140
|
-
position: { ...stored[node.id] }
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
const autoPos = autoMap.get(node.id) ?? { x: 0, y: 0 };
|
|
144
|
-
return {
|
|
145
|
-
...node,
|
|
146
|
-
position: {
|
|
147
|
-
x: Math.round(autoPos.x + dx),
|
|
148
|
-
y: Math.round(autoPos.y + dy)
|
|
149
|
-
}
|
|
150
|
-
};
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
|
-
function placeBeside(rects, size, side, nearNodeId, options = {}) {
|
|
154
|
-
const {
|
|
155
|
-
gap = DEFAULT_PLACEMENT_GAP,
|
|
156
|
-
ignore = [],
|
|
157
|
-
maxAttempts = 32
|
|
158
|
-
} = options;
|
|
159
|
-
const skip = new Set([nearNodeId, ...ignore].filter(Boolean));
|
|
160
|
-
const obstacles = Object.entries(rects).filter(([id]) => !skip.has(id)).map(([, r]) => r);
|
|
161
|
-
const anchor = nearNodeId && rects[nearNodeId] || boundsOf(Object.values(rects)) || { x: 0, y: 0, width: 0, height: 0 };
|
|
162
|
-
const anchorCenter = centre(anchor);
|
|
163
|
-
let baseX;
|
|
164
|
-
let baseY;
|
|
165
|
-
switch (side) {
|
|
166
|
-
case "right":
|
|
167
|
-
baseX = anchor.x + anchor.width + gap;
|
|
168
|
-
baseY = anchorCenter.y - size.height / 2;
|
|
169
|
-
break;
|
|
170
|
-
case "left":
|
|
171
|
-
baseX = anchor.x - gap - size.width;
|
|
172
|
-
baseY = anchorCenter.y - size.height / 2;
|
|
173
|
-
break;
|
|
174
|
-
case "above":
|
|
175
|
-
baseX = anchorCenter.x - size.width / 2;
|
|
176
|
-
baseY = anchor.y - gap - size.height;
|
|
177
|
-
break;
|
|
178
|
-
case "below":
|
|
179
|
-
default:
|
|
180
|
-
baseX = anchorCenter.x - size.width / 2;
|
|
181
|
-
baseY = anchor.y + anchor.height + gap;
|
|
182
|
-
break;
|
|
183
|
-
}
|
|
184
|
-
const isHorizontal = side === "right" || side === "left";
|
|
185
|
-
const step = (isHorizontal ? size.height : size.width) + 20;
|
|
186
|
-
for (let i = 0; i < maxAttempts; i++) {
|
|
187
|
-
const offset = i === 0 ? 0 : Math.ceil(i / 2) * step * (i % 2 === 1 ? 1 : -1);
|
|
188
|
-
const candidateBox = {
|
|
189
|
-
x: isHorizontal ? baseX : baseX + offset,
|
|
190
|
-
y: isHorizontal ? baseY + offset : baseY,
|
|
191
|
-
width: size.width,
|
|
192
|
-
height: size.height
|
|
193
|
-
};
|
|
194
|
-
if (!obstacles.some((obstacle) => overlaps(candidateBox, obstacle, 8))) {
|
|
195
|
-
return {
|
|
196
|
-
x: Math.round(candidateBox.x),
|
|
197
|
-
y: Math.round(candidateBox.y)
|
|
198
|
-
};
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
return {
|
|
202
|
-
x: Math.round(baseX),
|
|
203
|
-
y: Math.round(baseY)
|
|
204
|
-
};
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
export {
|
|
208
|
-
DEFAULT_NODE_WIDTH,
|
|
209
|
-
DEFAULT_NODE_HEIGHT,
|
|
210
|
-
DEFAULT_PLACEMENT_GAP,
|
|
211
|
-
getCenteredNodePosition,
|
|
212
|
-
centerNodes,
|
|
213
|
-
getLayoutedNodes,
|
|
214
|
-
estimateNodeSize,
|
|
215
|
-
boundsOf,
|
|
216
|
-
centre,
|
|
217
|
-
overlaps,
|
|
218
|
-
flowSide,
|
|
219
|
-
ensureLayout,
|
|
220
|
-
placeBeside
|
|
221
|
-
};
|