@pixerate/editor 0.140.4 → 0.142.1
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 +173 -33
- package/dist/agent/index.d.cts +1 -0
- package/dist/agent/index.d.ts +1 -0
- package/dist/agent/index.js +147 -7
- package/dist/agent/providers.d.cts +12 -1
- package/dist/agent/providers.d.ts +12 -1
- 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 +69 -19
- package/dist/animation-editor/index.d.cts +1 -0
- package/dist/animation-editor/index.d.ts +1 -0
- package/dist/animation-editor/index.js +54 -4
- package/dist/animation-editor/playback.d.cts +10 -0
- package/dist/animation-editor/playback.d.ts +10 -0
- 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 +255 -171
- package/dist/chart/index.d.cts +1 -0
- package/dist/chart/index.d.ts +1 -0
- package/dist/chart/index.js +244 -160
- package/dist/chart/playback.d.cts +22 -0
- package/dist/chart/playback.d.ts +22 -0
- package/dist/chunk-54GVEVXS.js +408 -0
- package/dist/{chunk-E747F3D5.js → chunk-CC6WKVIH.js} +86 -5
- 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-BSGPXPTW.js → chunk-PEEP2YR7.js} +1 -1
- package/dist/{chunk-VTY64I6H.cjs → chunk-QSM3MDDJ.cjs} +85 -85
- package/dist/{chunk-2RUNJYOX.cjs → chunk-QZFEX2N4.cjs} +86 -5
- 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-LMSFXRAJ.js → chunk-VGJTUCWM.js} +1 -1
- package/dist/chunk-X2HQP7DF.cjs +408 -0
- package/dist/chunk-XH32BATE.cjs +68 -0
- package/dist/{chunk-HDK3T2QS.cjs → chunk-Y4BWZB6J.cjs} +29 -7
- package/dist/chunk-Y6SGC6KO.js +68 -0
- 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 +108 -16
- package/dist/image-editor/index.d.cts +1 -0
- package/dist/image-editor/index.d.ts +1 -0
- package/dist/image-editor/index.js +107 -15
- package/dist/image-editor/playback.d.cts +22 -0
- package/dist/image-editor/playback.d.ts +22 -0
- package/dist/index.cjs +7 -3
- package/dist/index.js +6 -2
- package/dist/paint-editor/index.cjs +73 -25
- package/dist/paint-editor/index.d.cts +1 -0
- package/dist/paint-editor/index.d.ts +1 -0
- package/dist/paint-editor/index.js +68 -20
- package/dist/paint-editor/playback.d.cts +16 -0
- package/dist/paint-editor/playback.d.ts +16 -0
- package/dist/parameters/index.cjs +32 -8
- package/dist/parameters/index.d.cts +1 -0
- package/dist/parameters/index.d.ts +1 -0
- package/dist/parameters/index.js +28 -4
- package/dist/parameters/playback.d.cts +10 -0
- package/dist/parameters/playback.d.ts +10 -0
- package/dist/spreadsheet/index.cjs +7 -3
- package/dist/spreadsheet/index.d.cts +1 -0
- package/dist/spreadsheet/index.d.ts +1 -0
- package/dist/spreadsheet/index.js +6 -2
- package/dist/spreadsheet/playback.d.cts +15 -0
- package/dist/spreadsheet/playback.d.ts +15 -0
- package/dist/tools/index.cjs +40 -3
- package/dist/tools/index.d.cts +3 -0
- package/dist/tools/index.d.ts +3 -0
- package/dist/tools/index.js +39 -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/script.d.cts +77 -0
- package/dist/tools/script.d.ts +77 -0
- package/dist/tools/view.d.cts +2 -4
- package/dist/tools/view.d.ts +2 -4
- package/dist/vector/index.cjs +217 -100
- package/dist/vector/index.d.cts +1 -0
- package/dist/vector/index.d.ts +1 -0
- package/dist/vector/index.js +140 -23
- package/dist/vector/playback.d.cts +13 -0
- package/dist/vector/playback.d.ts +13 -0
- package/dist/video-editor/index.cjs +81 -28
- package/dist/video-editor/index.d.cts +1 -0
- package/dist/video-editor/index.d.ts +1 -0
- package/dist/video-editor/index.js +58 -5
- package/dist/video-editor/playback.d.cts +20 -0
- package/dist/video-editor/playback.d.ts +20 -0
- package/package.json +1 -1
- package/skills/pixerate-agent-tools/SKILL.md +13 -0
- package/skills/pixerate-animation-editor/SKILL.md +1 -0
- package/skills/pixerate-canvas/SKILL.md +3 -0
- package/skills/pixerate-chart/SKILL.md +1 -0
- package/skills/pixerate-image-editor/SKILL.md +2 -2
- package/skills/pixerate-paint-editor/SKILL.md +1 -0
- package/skills/pixerate-parameters/SKILL.md +1 -0
- package/skills/pixerate-spreadsheet/SKILL.md +1 -0
- package/skills/pixerate-vector/SKILL.md +5 -0
- package/skills/pixerate-video-editor/SKILL.md +1 -0
- package/dist/chunk-BTZS3KZY.js +0 -221
- package/dist/chunk-K73HMKQP.js +0 -0
- package/dist/chunk-LACYURUW.cjs +0 -1
- package/dist/chunk-MRD3NXKR.cjs +0 -221
package/dist/chart/index.js
CHANGED
|
@@ -149,7 +149,7 @@ import {
|
|
|
149
149
|
createInstantPresenceClock,
|
|
150
150
|
realPresenceClock,
|
|
151
151
|
tweenPresenceCursor
|
|
152
|
-
} from "../chunk-
|
|
152
|
+
} from "../chunk-PEEP2YR7.js";
|
|
153
153
|
import {
|
|
154
154
|
readZip
|
|
155
155
|
} from "../chunk-CIQIM2IP.js";
|
|
@@ -925,6 +925,242 @@ function chartHitTest(scene, point, measure = (t, s, w = 400) => t.length * s *
|
|
|
925
925
|
return point.x >= 0 && point.y >= 0 && point.x <= scene.width && point.y <= scene.height ? { kind: "chart" } : null;
|
|
926
926
|
}
|
|
927
927
|
|
|
928
|
+
// src/chart/presence.ts
|
|
929
|
+
var ChartPresence = class extends PresenceStore {
|
|
930
|
+
};
|
|
931
|
+
var CHART_PRESENCE_COLORS = PRESENCE_COLORS;
|
|
932
|
+
var realChartClock = realPresenceClock;
|
|
933
|
+
var createInstantChartClock = createInstantPresenceClock;
|
|
934
|
+
function chartPointAnchor(scene, seriesId, index) {
|
|
935
|
+
const mark = scene.marks.find((m) => (m.role === "bar" || m.role === "point") && m.target?.kind === "point" && m.target.seriesId === seriesId && m.target.index === index);
|
|
936
|
+
if (!mark) return null;
|
|
937
|
+
if (mark.kind === "rect") return { x: mark.x + mark.width / 2, y: mark.y };
|
|
938
|
+
if (mark.kind === "circle") return { x: mark.cx, y: mark.cy };
|
|
939
|
+
return null;
|
|
940
|
+
}
|
|
941
|
+
var anchorFor = (scene, role) => {
|
|
942
|
+
const m = scene.marks.find((x) => x.role === role);
|
|
943
|
+
if (!m) return null;
|
|
944
|
+
if (m.kind === "text") return { x: m.x, y: m.y };
|
|
945
|
+
if (m.kind === "rect") return { x: m.x + m.width / 2, y: m.y + m.height / 2 };
|
|
946
|
+
if (m.kind === "line") return { x: (m.x1 + m.x2) / 2, y: (m.y1 + m.y2) / 2 };
|
|
947
|
+
return null;
|
|
948
|
+
};
|
|
949
|
+
function planChartCommand(spec, scene, command, speed = 1) {
|
|
950
|
+
const ms = (n) => Math.round(n / Math.max(0.1, speed));
|
|
951
|
+
const steps = [];
|
|
952
|
+
const note = "note" in command && command.note ? command.note : void 0;
|
|
953
|
+
if (note) steps.push({ type: "say", text: note, ms: ms(500) });
|
|
954
|
+
switch (command.kind) {
|
|
955
|
+
case "say":
|
|
956
|
+
steps.push({ type: "say", text: command.text, ms: ms(900) });
|
|
957
|
+
return steps;
|
|
958
|
+
case "setValue": {
|
|
959
|
+
const at = chartPointAnchor(scene, command.seriesId, command.index);
|
|
960
|
+
const series = spec.series.find((s) => s.id === command.seriesId);
|
|
961
|
+
const from = series?.values[command.index] ?? 0;
|
|
962
|
+
const scale = series?.axis === "secondary" ? scene.valueScale2 ?? scene.valueScale : scene.valueScale;
|
|
963
|
+
if (at && scale) {
|
|
964
|
+
const px = linearMap(command.value, scale.domain, scale.range);
|
|
965
|
+
const to = scale.axis === "y" ? { x: at.x, y: px } : { x: px, y: at.y };
|
|
966
|
+
steps.push({ type: "move", to: at, ms: ms(380) }, { type: "press" }, { type: "drag", to, ms: ms(520), from, value: command.value }, { type: "release" });
|
|
967
|
+
} else steps.push({ type: "drag", to: { x: scene.plot.x + scene.plot.width / 2, y: scene.plot.y + scene.plot.height / 2 }, ms: ms(200), from, value: command.value });
|
|
968
|
+
steps.push({ type: "commit" });
|
|
969
|
+
return steps;
|
|
970
|
+
}
|
|
971
|
+
case "select": {
|
|
972
|
+
const sel = command.selection;
|
|
973
|
+
let to = null;
|
|
974
|
+
if (sel?.kind === "point") to = chartPointAnchor(scene, sel.seriesId, sel.index);
|
|
975
|
+
else if (sel) {
|
|
976
|
+
const m = scene.marks.find((x) => x.target && JSON.stringify(x.target) === JSON.stringify(sel));
|
|
977
|
+
if (m?.kind === "text") to = { x: m.x, y: m.y };
|
|
978
|
+
else if (m?.kind === "rect") to = { x: m.x + m.width / 2, y: m.y + m.height / 2 };
|
|
979
|
+
else if (m?.kind === "circle") to = { x: m.cx, y: m.cy };
|
|
980
|
+
}
|
|
981
|
+
if (to) steps.push({ type: "move", to, ms: ms(380) }, { type: "press" }, { type: "release" });
|
|
982
|
+
steps.push({ type: "commit" });
|
|
983
|
+
return steps;
|
|
984
|
+
}
|
|
985
|
+
case "update": {
|
|
986
|
+
const keys = Object.keys(command.patch);
|
|
987
|
+
const role = keys.includes("title") ? "title" : keys.includes("legend") ? "legend-label" : keys.some((k) => k === "xAxis") ? "axis" : keys.some((k) => k === "yAxis" || k === "yAxis2") ? "tick-label" : null;
|
|
988
|
+
const to = role && anchorFor(scene, role) || { x: scene.plot.x + scene.plot.width / 2, y: scene.plot.y + 12 };
|
|
989
|
+
steps.push({ type: "move", to, ms: ms(380) }, { type: "press" }, { type: "release" }, { type: "commit" });
|
|
990
|
+
return steps;
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
var ChartDirector = class {
|
|
995
|
+
constructor(controller, presence, options) {
|
|
996
|
+
this.controller = controller;
|
|
997
|
+
this.presence = presence;
|
|
998
|
+
this.options = options;
|
|
999
|
+
this.clock = options.clock ?? realChartClock;
|
|
1000
|
+
this.queue = new PerformanceQueue(presence, {
|
|
1001
|
+
clock: this.clock,
|
|
1002
|
+
linger: options.linger,
|
|
1003
|
+
beginGesture: (key) => controller.beginGesture(key),
|
|
1004
|
+
endGesture: () => controller.endGesture()
|
|
1005
|
+
});
|
|
1006
|
+
}
|
|
1007
|
+
controller;
|
|
1008
|
+
presence;
|
|
1009
|
+
options;
|
|
1010
|
+
clock;
|
|
1011
|
+
queue;
|
|
1012
|
+
/** Acts out `commands` in order for `actor`. Resolves with one result per command. */
|
|
1013
|
+
perform(actor, commands) {
|
|
1014
|
+
return this.queue.run(actor, async () => {
|
|
1015
|
+
const results = [];
|
|
1016
|
+
for (const command of commands) results.push(await this.performOne(actor.id, command));
|
|
1017
|
+
return results;
|
|
1018
|
+
});
|
|
1019
|
+
}
|
|
1020
|
+
stale(command) {
|
|
1021
|
+
const spec = this.controller.getSpec();
|
|
1022
|
+
if (command.kind === "setValue") {
|
|
1023
|
+
const s = spec.series.find((x) => x.id === command.seriesId);
|
|
1024
|
+
if (!s) return `The series "${command.seriesId}" no longer exists.`;
|
|
1025
|
+
if (command.index < 0 || command.index >= spec.categories.length) return `Category ${command.index} no longer exists.`;
|
|
1026
|
+
if (!Number.isFinite(command.value)) return "The value must be a finite number.";
|
|
1027
|
+
}
|
|
1028
|
+
return null;
|
|
1029
|
+
}
|
|
1030
|
+
move(id, from, to, ms, each) {
|
|
1031
|
+
return tweenPresenceCursor(this.presence, this.clock, id, from, to, ms, each);
|
|
1032
|
+
}
|
|
1033
|
+
async performOne(id, command) {
|
|
1034
|
+
const stale = this.stale(command);
|
|
1035
|
+
if (stale) return { ok: false, command, message: stale };
|
|
1036
|
+
const steps = planChartCommand(this.controller.getSpec(), this.options.scene(), command, this.options.speed);
|
|
1037
|
+
const where = () => {
|
|
1038
|
+
const a = this.presence.getState().actors.find((x) => x.id === id);
|
|
1039
|
+
return { x: a.x, y: a.y };
|
|
1040
|
+
};
|
|
1041
|
+
{
|
|
1042
|
+
for (const step of steps) {
|
|
1043
|
+
switch (step.type) {
|
|
1044
|
+
case "say":
|
|
1045
|
+
this.presence.set({ id, message: step.text });
|
|
1046
|
+
await this.clock.wait(step.ms);
|
|
1047
|
+
break;
|
|
1048
|
+
case "move":
|
|
1049
|
+
await this.move(id, where(), step.to, step.ms);
|
|
1050
|
+
break;
|
|
1051
|
+
case "press":
|
|
1052
|
+
this.presence.set({ id, pressed: true });
|
|
1053
|
+
break;
|
|
1054
|
+
case "release":
|
|
1055
|
+
this.presence.set({ id, pressed: false });
|
|
1056
|
+
break;
|
|
1057
|
+
case "drag": {
|
|
1058
|
+
if (command.kind !== "setValue") break;
|
|
1059
|
+
const stale2 = this.stale(command);
|
|
1060
|
+
if (stale2) return { ok: false, command, message: stale2 };
|
|
1061
|
+
const label = `${this.presence.getState().actors.find((a) => a.id === id)?.name ?? "Agent"}: edit value`;
|
|
1062
|
+
await this.move(id, where(), step.to, step.ms, (e) => {
|
|
1063
|
+
const v = step.from + (step.value - step.from) * e;
|
|
1064
|
+
this.controller.setValue(command.seriesId, command.index, Number(v.toPrecision(12)), { label });
|
|
1065
|
+
});
|
|
1066
|
+
this.controller.setValue(command.seriesId, command.index, step.value, { label });
|
|
1067
|
+
break;
|
|
1068
|
+
}
|
|
1069
|
+
case "commit": {
|
|
1070
|
+
if (command.kind === "select") this.controller.select(command.selection);
|
|
1071
|
+
else if (command.kind === "update") {
|
|
1072
|
+
const result = this.controller.update(command.patch, command.label ? { label: command.label } : {});
|
|
1073
|
+
if (!result.ok) return { ok: false, command, message: result.message };
|
|
1074
|
+
}
|
|
1075
|
+
break;
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
return { ok: true, command };
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
};
|
|
1083
|
+
|
|
1084
|
+
// src/chart/playback.ts
|
|
1085
|
+
var click = (ref) => [{ type: "target", ref }, { type: "press" }, { type: "release" }];
|
|
1086
|
+
var control = (id) => ({ kind: "control", id });
|
|
1087
|
+
function chartPointRef(series, category) {
|
|
1088
|
+
return { kind: "point", id: JSON.stringify([series, category]) };
|
|
1089
|
+
}
|
|
1090
|
+
function locateChartPoint(spec, scene, ref) {
|
|
1091
|
+
if (ref.kind !== "point") return null;
|
|
1092
|
+
let parsed;
|
|
1093
|
+
try {
|
|
1094
|
+
parsed = JSON.parse(ref.id);
|
|
1095
|
+
} catch {
|
|
1096
|
+
return null;
|
|
1097
|
+
}
|
|
1098
|
+
if (!Array.isArray(parsed)) return null;
|
|
1099
|
+
const [seriesRef, categoryRef] = parsed;
|
|
1100
|
+
const series = spec.series.find((s) => s.id === seriesRef) ?? spec.series.find((s) => s.name === seriesRef);
|
|
1101
|
+
const index = typeof categoryRef === "number" ? categoryRef : spec.categories.findIndex((c) => String(c) === String(categoryRef));
|
|
1102
|
+
if (!series || index < 0) return null;
|
|
1103
|
+
const at = chartPointAnchor(scene, series.id, index);
|
|
1104
|
+
return at ? { x: at.x - 6, y: at.y - 6, width: 12, height: 12 } : null;
|
|
1105
|
+
}
|
|
1106
|
+
function planChartToolPlayback(tool, args) {
|
|
1107
|
+
switch (tool) {
|
|
1108
|
+
case "update_chart": {
|
|
1109
|
+
const steps = [];
|
|
1110
|
+
for (const key of Object.keys(args).slice(0, 4)) {
|
|
1111
|
+
steps.push(...click(key === "type" && typeof args.type === "string" ? { kind: "chart-type", id: args.type } : control(key)));
|
|
1112
|
+
}
|
|
1113
|
+
return steps.length ? steps : null;
|
|
1114
|
+
}
|
|
1115
|
+
case "apply_chart_preset":
|
|
1116
|
+
return [...args.layout ? click(control("preset.layout")) : [], ...args.colors ? click(control("preset.colors")) : []];
|
|
1117
|
+
case "set_chart_values": {
|
|
1118
|
+
const cells = Array.isArray(args.cells) ? args.cells : [];
|
|
1119
|
+
const steps = cells.slice(0, 6).filter((c) => typeof c.series === "string" && (typeof c.category === "string" || typeof c.category === "number")).flatMap((c) => click(chartPointRef(c.series, c.category)));
|
|
1120
|
+
return steps.length ? steps : null;
|
|
1121
|
+
}
|
|
1122
|
+
case "select_chart_element":
|
|
1123
|
+
if (args.kind === "point" && typeof args.series === "string" && args.category !== void 0) return click(chartPointRef(args.series, args.category));
|
|
1124
|
+
return typeof args.kind === "string" && args.kind !== "none" ? click(control(args.kind)) : null;
|
|
1125
|
+
case "set_chart_data":
|
|
1126
|
+
case "import_chart_csv":
|
|
1127
|
+
case "import_chart_mermaid":
|
|
1128
|
+
case "import_chart_ooxml":
|
|
1129
|
+
case "add_chart_series":
|
|
1130
|
+
case "update_chart_series":
|
|
1131
|
+
case "remove_chart_series":
|
|
1132
|
+
case "add_chart_category":
|
|
1133
|
+
case "remove_chart_category":
|
|
1134
|
+
case "transpose_chart":
|
|
1135
|
+
return [{ type: "target", ref: { kind: "grid", id: "data" } }];
|
|
1136
|
+
case "add_chart_trendline":
|
|
1137
|
+
case "remove_chart_trendline":
|
|
1138
|
+
return click(control("trendline.add"));
|
|
1139
|
+
case "render_chart":
|
|
1140
|
+
return [{ type: "target", ref: { kind: "action", id: "download-png" } }];
|
|
1141
|
+
case "undo_chart":
|
|
1142
|
+
return click({ kind: "action", id: "undo" });
|
|
1143
|
+
case "redo_chart":
|
|
1144
|
+
return click({ kind: "action", id: "redo" });
|
|
1145
|
+
default:
|
|
1146
|
+
return null;
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
var DIRECTED = /* @__PURE__ */ new Set(["set_chart_values", "select_chart_element"]);
|
|
1150
|
+
function withChartPlayback(provider, options) {
|
|
1151
|
+
const plan = (tool) => {
|
|
1152
|
+
if (tool.plan || tool.playback !== void 0) return tool;
|
|
1153
|
+
if (options.director && DIRECTED.has(tool.name)) return { ...tool, playback: "self" };
|
|
1154
|
+
return { ...tool, plan: (args) => planChartToolPlayback(tool.name, args) };
|
|
1155
|
+
};
|
|
1156
|
+
const tools = provider.tools;
|
|
1157
|
+
return {
|
|
1158
|
+
...provider,
|
|
1159
|
+
playbackSurface: provider.playbackSurface ?? options.surface ?? "chart",
|
|
1160
|
+
tools: typeof tools === "function" ? () => tools().map(plan) : tools.map(plan)
|
|
1161
|
+
};
|
|
1162
|
+
}
|
|
1163
|
+
|
|
928
1164
|
// src/chart/tools.ts
|
|
929
1165
|
var RENDER_CHART_INSTRUCTIONS = 'Draws the chart without changing it so you can check how it looks: SVG text by default, or a PNG image with format "png" when the host can rasterize. Returns the layout warnings (hidden or thinned labels, dropped markers) alongside. An image costs tokens, so render after a batch of edits rather than after each one, and use it to check what text cannot tell you: overlapping or cut-off labels, a crowded legend, unreadable colours, whether the chart reads at the given size. For values, ids and warnings alone, get_chart is cheaper.';
|
|
930
1166
|
var READ = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
@@ -1488,7 +1724,7 @@ function createChartToolProvider(controller, options = {}) {
|
|
|
1488
1724
|
};
|
|
1489
1725
|
const reads = [getChart, renderChart, checkColors, recommend, getTrendline, listPresets, exportMermaid, exportOoxml];
|
|
1490
1726
|
const writes = [updateChart, setData, setValues, addSeries, updateSeries, removeSeries, addCategory, removeCategory, importCsv, importMermaid, addTrendline, removeTrendline, applyPreset, transpose, select, drag, key, undo, redo];
|
|
1491
|
-
return {
|
|
1727
|
+
return withChartPlayback({
|
|
1492
1728
|
id: options.id ?? "chart",
|
|
1493
1729
|
namespace: options.namespace,
|
|
1494
1730
|
title: "Chart editor",
|
|
@@ -1508,7 +1744,7 @@ function createChartToolProvider(controller, options = {}) {
|
|
|
1508
1744
|
}
|
|
1509
1745
|
});
|
|
1510
1746
|
}
|
|
1511
|
-
};
|
|
1747
|
+
}, { director: !!options.director });
|
|
1512
1748
|
}
|
|
1513
1749
|
|
|
1514
1750
|
// src/chart/stream.ts
|
|
@@ -1643,162 +1879,6 @@ function blendChartScenes(from, to, t) {
|
|
|
1643
1879
|
}
|
|
1644
1880
|
var easeChartTween = (t) => 1 - Math.pow(1 - Math.max(0, Math.min(1, t)), 3);
|
|
1645
1881
|
|
|
1646
|
-
// src/chart/presence.ts
|
|
1647
|
-
var ChartPresence = class extends PresenceStore {
|
|
1648
|
-
};
|
|
1649
|
-
var CHART_PRESENCE_COLORS = PRESENCE_COLORS;
|
|
1650
|
-
var realChartClock = realPresenceClock;
|
|
1651
|
-
var createInstantChartClock = createInstantPresenceClock;
|
|
1652
|
-
function chartPointAnchor(scene, seriesId, index) {
|
|
1653
|
-
const mark = scene.marks.find((m) => (m.role === "bar" || m.role === "point") && m.target?.kind === "point" && m.target.seriesId === seriesId && m.target.index === index);
|
|
1654
|
-
if (!mark) return null;
|
|
1655
|
-
if (mark.kind === "rect") return { x: mark.x + mark.width / 2, y: mark.y };
|
|
1656
|
-
if (mark.kind === "circle") return { x: mark.cx, y: mark.cy };
|
|
1657
|
-
return null;
|
|
1658
|
-
}
|
|
1659
|
-
var anchorFor = (scene, role) => {
|
|
1660
|
-
const m = scene.marks.find((x) => x.role === role);
|
|
1661
|
-
if (!m) return null;
|
|
1662
|
-
if (m.kind === "text") return { x: m.x, y: m.y };
|
|
1663
|
-
if (m.kind === "rect") return { x: m.x + m.width / 2, y: m.y + m.height / 2 };
|
|
1664
|
-
if (m.kind === "line") return { x: (m.x1 + m.x2) / 2, y: (m.y1 + m.y2) / 2 };
|
|
1665
|
-
return null;
|
|
1666
|
-
};
|
|
1667
|
-
function planChartCommand(spec, scene, command, speed = 1) {
|
|
1668
|
-
const ms = (n) => Math.round(n / Math.max(0.1, speed));
|
|
1669
|
-
const steps = [];
|
|
1670
|
-
const note = "note" in command && command.note ? command.note : void 0;
|
|
1671
|
-
if (note) steps.push({ type: "say", text: note, ms: ms(500) });
|
|
1672
|
-
switch (command.kind) {
|
|
1673
|
-
case "say":
|
|
1674
|
-
steps.push({ type: "say", text: command.text, ms: ms(900) });
|
|
1675
|
-
return steps;
|
|
1676
|
-
case "setValue": {
|
|
1677
|
-
const at = chartPointAnchor(scene, command.seriesId, command.index);
|
|
1678
|
-
const series = spec.series.find((s) => s.id === command.seriesId);
|
|
1679
|
-
const from = series?.values[command.index] ?? 0;
|
|
1680
|
-
const scale = series?.axis === "secondary" ? scene.valueScale2 ?? scene.valueScale : scene.valueScale;
|
|
1681
|
-
if (at && scale) {
|
|
1682
|
-
const px = linearMap(command.value, scale.domain, scale.range);
|
|
1683
|
-
const to = scale.axis === "y" ? { x: at.x, y: px } : { x: px, y: at.y };
|
|
1684
|
-
steps.push({ type: "move", to: at, ms: ms(380) }, { type: "press" }, { type: "drag", to, ms: ms(520), from, value: command.value }, { type: "release" });
|
|
1685
|
-
} else steps.push({ type: "drag", to: { x: scene.plot.x + scene.plot.width / 2, y: scene.plot.y + scene.plot.height / 2 }, ms: ms(200), from, value: command.value });
|
|
1686
|
-
steps.push({ type: "commit" });
|
|
1687
|
-
return steps;
|
|
1688
|
-
}
|
|
1689
|
-
case "select": {
|
|
1690
|
-
const sel = command.selection;
|
|
1691
|
-
let to = null;
|
|
1692
|
-
if (sel?.kind === "point") to = chartPointAnchor(scene, sel.seriesId, sel.index);
|
|
1693
|
-
else if (sel) {
|
|
1694
|
-
const m = scene.marks.find((x) => x.target && JSON.stringify(x.target) === JSON.stringify(sel));
|
|
1695
|
-
if (m?.kind === "text") to = { x: m.x, y: m.y };
|
|
1696
|
-
else if (m?.kind === "rect") to = { x: m.x + m.width / 2, y: m.y + m.height / 2 };
|
|
1697
|
-
else if (m?.kind === "circle") to = { x: m.cx, y: m.cy };
|
|
1698
|
-
}
|
|
1699
|
-
if (to) steps.push({ type: "move", to, ms: ms(380) }, { type: "press" }, { type: "release" });
|
|
1700
|
-
steps.push({ type: "commit" });
|
|
1701
|
-
return steps;
|
|
1702
|
-
}
|
|
1703
|
-
case "update": {
|
|
1704
|
-
const keys = Object.keys(command.patch);
|
|
1705
|
-
const role = keys.includes("title") ? "title" : keys.includes("legend") ? "legend-label" : keys.some((k) => k === "xAxis") ? "axis" : keys.some((k) => k === "yAxis" || k === "yAxis2") ? "tick-label" : null;
|
|
1706
|
-
const to = role && anchorFor(scene, role) || { x: scene.plot.x + scene.plot.width / 2, y: scene.plot.y + 12 };
|
|
1707
|
-
steps.push({ type: "move", to, ms: ms(380) }, { type: "press" }, { type: "release" }, { type: "commit" });
|
|
1708
|
-
return steps;
|
|
1709
|
-
}
|
|
1710
|
-
}
|
|
1711
|
-
}
|
|
1712
|
-
var ChartDirector = class {
|
|
1713
|
-
constructor(controller, presence, options) {
|
|
1714
|
-
this.controller = controller;
|
|
1715
|
-
this.presence = presence;
|
|
1716
|
-
this.options = options;
|
|
1717
|
-
this.clock = options.clock ?? realChartClock;
|
|
1718
|
-
this.queue = new PerformanceQueue(presence, {
|
|
1719
|
-
clock: this.clock,
|
|
1720
|
-
linger: options.linger,
|
|
1721
|
-
beginGesture: (key) => controller.beginGesture(key),
|
|
1722
|
-
endGesture: () => controller.endGesture()
|
|
1723
|
-
});
|
|
1724
|
-
}
|
|
1725
|
-
controller;
|
|
1726
|
-
presence;
|
|
1727
|
-
options;
|
|
1728
|
-
clock;
|
|
1729
|
-
queue;
|
|
1730
|
-
/** Acts out `commands` in order for `actor`. Resolves with one result per command. */
|
|
1731
|
-
perform(actor, commands) {
|
|
1732
|
-
return this.queue.run(actor, async () => {
|
|
1733
|
-
const results = [];
|
|
1734
|
-
for (const command of commands) results.push(await this.performOne(actor.id, command));
|
|
1735
|
-
return results;
|
|
1736
|
-
});
|
|
1737
|
-
}
|
|
1738
|
-
stale(command) {
|
|
1739
|
-
const spec = this.controller.getSpec();
|
|
1740
|
-
if (command.kind === "setValue") {
|
|
1741
|
-
const s = spec.series.find((x) => x.id === command.seriesId);
|
|
1742
|
-
if (!s) return `The series "${command.seriesId}" no longer exists.`;
|
|
1743
|
-
if (command.index < 0 || command.index >= spec.categories.length) return `Category ${command.index} no longer exists.`;
|
|
1744
|
-
if (!Number.isFinite(command.value)) return "The value must be a finite number.";
|
|
1745
|
-
}
|
|
1746
|
-
return null;
|
|
1747
|
-
}
|
|
1748
|
-
move(id, from, to, ms, each) {
|
|
1749
|
-
return tweenPresenceCursor(this.presence, this.clock, id, from, to, ms, each);
|
|
1750
|
-
}
|
|
1751
|
-
async performOne(id, command) {
|
|
1752
|
-
const stale = this.stale(command);
|
|
1753
|
-
if (stale) return { ok: false, command, message: stale };
|
|
1754
|
-
const steps = planChartCommand(this.controller.getSpec(), this.options.scene(), command, this.options.speed);
|
|
1755
|
-
const where = () => {
|
|
1756
|
-
const a = this.presence.getState().actors.find((x) => x.id === id);
|
|
1757
|
-
return { x: a.x, y: a.y };
|
|
1758
|
-
};
|
|
1759
|
-
{
|
|
1760
|
-
for (const step of steps) {
|
|
1761
|
-
switch (step.type) {
|
|
1762
|
-
case "say":
|
|
1763
|
-
this.presence.set({ id, message: step.text });
|
|
1764
|
-
await this.clock.wait(step.ms);
|
|
1765
|
-
break;
|
|
1766
|
-
case "move":
|
|
1767
|
-
await this.move(id, where(), step.to, step.ms);
|
|
1768
|
-
break;
|
|
1769
|
-
case "press":
|
|
1770
|
-
this.presence.set({ id, pressed: true });
|
|
1771
|
-
break;
|
|
1772
|
-
case "release":
|
|
1773
|
-
this.presence.set({ id, pressed: false });
|
|
1774
|
-
break;
|
|
1775
|
-
case "drag": {
|
|
1776
|
-
if (command.kind !== "setValue") break;
|
|
1777
|
-
const stale2 = this.stale(command);
|
|
1778
|
-
if (stale2) return { ok: false, command, message: stale2 };
|
|
1779
|
-
const label = `${this.presence.getState().actors.find((a) => a.id === id)?.name ?? "Agent"}: edit value`;
|
|
1780
|
-
await this.move(id, where(), step.to, step.ms, (e) => {
|
|
1781
|
-
const v = step.from + (step.value - step.from) * e;
|
|
1782
|
-
this.controller.setValue(command.seriesId, command.index, Number(v.toPrecision(12)), { label });
|
|
1783
|
-
});
|
|
1784
|
-
this.controller.setValue(command.seriesId, command.index, step.value, { label });
|
|
1785
|
-
break;
|
|
1786
|
-
}
|
|
1787
|
-
case "commit": {
|
|
1788
|
-
if (command.kind === "select") this.controller.select(command.selection);
|
|
1789
|
-
else if (command.kind === "update") {
|
|
1790
|
-
const result = this.controller.update(command.patch, command.label ? { label: command.label } : {});
|
|
1791
|
-
if (!result.ok) return { ok: false, command, message: result.message };
|
|
1792
|
-
}
|
|
1793
|
-
break;
|
|
1794
|
-
}
|
|
1795
|
-
}
|
|
1796
|
-
}
|
|
1797
|
-
return { ok: true, command };
|
|
1798
|
-
}
|
|
1799
|
-
}
|
|
1800
|
-
};
|
|
1801
|
-
|
|
1802
1882
|
// src/chart/office-files.ts
|
|
1803
1883
|
var OfficeChartsError = class extends Error {
|
|
1804
1884
|
constructor(message, options) {
|
|
@@ -2168,6 +2248,7 @@ export {
|
|
|
2168
2248
|
chartMovingAverage,
|
|
2169
2249
|
chartPointAnchor,
|
|
2170
2250
|
chartPointColor,
|
|
2251
|
+
chartPointRef,
|
|
2171
2252
|
chartPresetPatch,
|
|
2172
2253
|
chartQuantile,
|
|
2173
2254
|
chartRasterSize,
|
|
@@ -2231,6 +2312,7 @@ export {
|
|
|
2231
2312
|
layoutChart,
|
|
2232
2313
|
layoutSparkline,
|
|
2233
2314
|
linearMap,
|
|
2315
|
+
locateChartPoint,
|
|
2234
2316
|
monochromeChartPalette,
|
|
2235
2317
|
niceLogScale,
|
|
2236
2318
|
niceScale,
|
|
@@ -2246,6 +2328,7 @@ export {
|
|
|
2246
2328
|
parseChartValue,
|
|
2247
2329
|
parsePartialChartJson,
|
|
2248
2330
|
planChartCommand,
|
|
2331
|
+
planChartToolPlayback,
|
|
2249
2332
|
rasterizeChartSvg,
|
|
2250
2333
|
realChartClock,
|
|
2251
2334
|
recommendChartTypes,
|
|
@@ -2262,5 +2345,6 @@ export {
|
|
|
2262
2345
|
summarizeChart,
|
|
2263
2346
|
summarizeChartSeries,
|
|
2264
2347
|
trendNumberText,
|
|
2265
|
-
uniqueChartSeriesId
|
|
2348
|
+
uniqueChartSeriesId,
|
|
2349
|
+
withChartPlayback
|
|
2266
2350
|
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { AgentToolProvider } from '../tools/registry.cjs';
|
|
2
|
+
import type { PlaybackRef, PlaybackStep } from '../tools/playback.cjs';
|
|
3
|
+
import type { ChartScene, ChartSpec } from './types.cjs';
|
|
4
|
+
/** A point ref: a series (id or name) and a category (index or label), as the tools take them. */
|
|
5
|
+
export declare function chartPointRef(series: string, category: string | number): PlaybackRef;
|
|
6
|
+
/** Where a point ref is drawn in `scene` (a small box around its anchor), or null. */
|
|
7
|
+
export declare function locateChartPoint(spec: ChartSpec, scene: ChartScene, ref: PlaybackRef): {
|
|
8
|
+
x: number;
|
|
9
|
+
y: number;
|
|
10
|
+
width: number;
|
|
11
|
+
height: number;
|
|
12
|
+
} | null;
|
|
13
|
+
/** The cursor steps for one chart tool call (by bare name), or null to fall back to the ids it names. */
|
|
14
|
+
export declare function planChartToolPlayback(tool: string, args: Record<string, any>): PlaybackStep[] | null;
|
|
15
|
+
/**
|
|
16
|
+
* Gives a chart tool provider agent playback on `surface` (default `chart`, where `ChartEditor`
|
|
17
|
+
* attaches). With a director, value changes and selections play through it (`playback: 'self'`).
|
|
18
|
+
*/
|
|
19
|
+
export declare function withChartPlayback(provider: AgentToolProvider, options: {
|
|
20
|
+
director: boolean;
|
|
21
|
+
surface?: string;
|
|
22
|
+
}): AgentToolProvider;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { AgentToolProvider } from '../tools/registry.js';
|
|
2
|
+
import type { PlaybackRef, PlaybackStep } from '../tools/playback.js';
|
|
3
|
+
import type { ChartScene, ChartSpec } from './types.js';
|
|
4
|
+
/** A point ref: a series (id or name) and a category (index or label), as the tools take them. */
|
|
5
|
+
export declare function chartPointRef(series: string, category: string | number): PlaybackRef;
|
|
6
|
+
/** Where a point ref is drawn in `scene` (a small box around its anchor), or null. */
|
|
7
|
+
export declare function locateChartPoint(spec: ChartSpec, scene: ChartScene, ref: PlaybackRef): {
|
|
8
|
+
x: number;
|
|
9
|
+
y: number;
|
|
10
|
+
width: number;
|
|
11
|
+
height: number;
|
|
12
|
+
} | null;
|
|
13
|
+
/** The cursor steps for one chart tool call (by bare name), or null to fall back to the ids it names. */
|
|
14
|
+
export declare function planChartToolPlayback(tool: string, args: Record<string, any>): PlaybackStep[] | null;
|
|
15
|
+
/**
|
|
16
|
+
* Gives a chart tool provider agent playback on `surface` (default `chart`, where `ChartEditor`
|
|
17
|
+
* attaches). With a director, value changes and selections play through it (`playback: 'self'`).
|
|
18
|
+
*/
|
|
19
|
+
export declare function withChartPlayback(provider: AgentToolProvider, options: {
|
|
20
|
+
director: boolean;
|
|
21
|
+
surface?: string;
|
|
22
|
+
}): AgentToolProvider;
|