@pixerate/editor 0.180.0 → 0.182.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.
Files changed (67) hide show
  1. package/dist/agent/index.cjs +39 -39
  2. package/dist/agent/index.js +8 -8
  3. package/dist/animation/index.cjs +2 -2
  4. package/dist/animation/index.js +1 -1
  5. package/dist/canvas/index.cjs +6 -6
  6. package/dist/canvas/index.js +2 -2
  7. package/dist/chart/index.cjs +169 -164
  8. package/dist/chart/index.d.cts +1 -0
  9. package/dist/chart/index.d.ts +1 -0
  10. package/dist/chart/index.js +13 -8
  11. package/dist/chart/layout-streamgraph.d.cts +15 -0
  12. package/dist/chart/layout-streamgraph.d.ts +15 -0
  13. package/dist/chart/spec.d.cts +1 -1
  14. package/dist/chart/spec.d.ts +1 -1
  15. package/dist/chart/types.d.cts +2 -1
  16. package/dist/chart/types.d.ts +2 -1
  17. package/dist/{chunk-KPWG3PSW.js → chunk-23E5GI2U.js} +8 -2
  18. package/dist/{chunk-IMHRN4ZZ.js → chunk-3MO3ZS7E.js} +3 -3
  19. package/dist/{chunk-5EMS4BZG.cjs → chunk-3SLBXKAW.cjs} +15 -7
  20. package/dist/{chunk-GXEC4FS6.cjs → chunk-5DQPDXOM.cjs} +82 -76
  21. package/dist/{chunk-ORZF4JOO.js → chunk-6ZZKRH7R.js} +3 -1
  22. package/dist/{chunk-FHNGNL3V.cjs → chunk-CZBRY4SW.cjs} +51 -51
  23. package/dist/{chunk-WL4IN36A.js → chunk-EHTX34RE.js} +13 -5
  24. package/dist/{chunk-ZXTO6U7T.js → chunk-GI3AVES4.js} +1 -1
  25. package/dist/{chunk-34UCPHYO.js → chunk-GOBOCZZI.js} +2 -2
  26. package/dist/{chunk-VKHJJUBK.cjs → chunk-HUAISCUX.cjs} +22 -18
  27. package/dist/{chunk-O2ANJFUF.js → chunk-IVSWRVB4.js} +8 -1
  28. package/dist/{chunk-SWTUM32H.cjs → chunk-K7ENM55P.cjs} +8 -1
  29. package/dist/{chunk-OLCHKGGO.js → chunk-L6Y7TSQ4.js} +5 -1
  30. package/dist/{chunk-TUXKLM5W.cjs → chunk-N76AMOKE.cjs} +224 -42
  31. package/dist/{chunk-RLOIEDA3.cjs → chunk-O7QXVGMP.cjs} +16 -16
  32. package/dist/{chunk-R2VHVQVY.js → chunk-PI2UYMZY.js} +3 -3
  33. package/dist/{chunk-E45AIIWY.cjs → chunk-RUONPPMC.cjs} +8 -8
  34. package/dist/{chunk-GTF4RYXJ.cjs → chunk-SOSBOS5T.cjs} +22 -22
  35. package/dist/{chunk-NJGFSOPP.cjs → chunk-U4QN36YT.cjs} +2 -2
  36. package/dist/{chunk-FKYGM35R.js → chunk-UFEDHACQ.js} +2 -2
  37. package/dist/{chunk-OJQVKJYD.js → chunk-WKMUBATU.js} +183 -1
  38. package/dist/{chunk-OUO3DSRT.cjs → chunk-WRZ6C4TU.cjs} +3 -1
  39. package/dist/commands/index.cjs +3 -3
  40. package/dist/commands/index.js +2 -2
  41. package/dist/diagram/index.cjs +7 -7
  42. package/dist/diagram/index.js +1 -1
  43. package/dist/export/index.cjs +4 -4
  44. package/dist/export/index.js +3 -3
  45. package/dist/extensions/index.cjs +7 -7
  46. package/dist/extensions/index.js +6 -6
  47. package/dist/image-editor/controller.d.cts +2 -0
  48. package/dist/image-editor/controller.d.ts +2 -0
  49. package/dist/image-editor/index.cjs +135 -115
  50. package/dist/image-editor/index.js +28 -8
  51. package/dist/image-editor/playback.d.cts +14 -4
  52. package/dist/image-editor/playback.d.ts +14 -4
  53. package/dist/image-editor/selection/segmentation.d.cts +3 -0
  54. package/dist/image-editor/selection/segmentation.d.ts +3 -0
  55. package/dist/index.cjs +13 -13
  56. package/dist/index.js +7 -7
  57. package/dist/paint-editor/index.cjs +6 -6
  58. package/dist/paint-editor/index.js +1 -1
  59. package/dist/tools/index.cjs +4 -4
  60. package/dist/tools/index.js +3 -3
  61. package/dist/tools/playback.d.cts +4 -1
  62. package/dist/tools/playback.d.ts +4 -1
  63. package/dist/tools/presence.d.cts +15 -3
  64. package/dist/tools/presence.d.ts +15 -3
  65. package/dist/tools/registry.d.cts +7 -1
  66. package/dist/tools/registry.d.ts +7 -1
  67. package/package.json +1 -1
@@ -12,6 +12,7 @@ export * from './stats.cjs';
12
12
  export * from './trend.cjs';
13
13
  export * from './errorbars.cjs';
14
14
  export * from './layout.cjs';
15
+ export * from './layout-streamgraph.cjs';
15
16
  export { MAX_CHART_DATA_LABELS, MAX_CHART_LINE_POINTS, MAX_CHART_MARKERS } from './layout-cartesian.cjs';
16
17
  export * from './svg.cjs';
17
18
  export * from './raster.cjs';
@@ -12,6 +12,7 @@ export * from './stats.js';
12
12
  export * from './trend.js';
13
13
  export * from './errorbars.js';
14
14
  export * from './layout.js';
15
+ export * from './layout-streamgraph.js';
15
16
  export { MAX_CHART_DATA_LABELS, MAX_CHART_LINE_POINTS, MAX_CHART_MARKERS } from './layout-cartesian.js';
16
17
  export * from './svg.js';
17
18
  export * from './raster.js';
@@ -17,7 +17,7 @@ import {
17
17
  TRENDLINE_PROPS,
18
18
  VALUE,
19
19
  WIDTH
20
- } from "../chunk-34UCPHYO.js";
20
+ } from "../chunk-GOBOCZZI.js";
21
21
  import {
22
22
  CHART_OOXML_CONTENT_TYPE,
23
23
  CHART_OOXML_NS,
@@ -25,7 +25,7 @@ import {
25
25
  chartFormatToCode,
26
26
  chartFromOoxml,
27
27
  chartToOoxml
28
- } from "../chunk-OLCHKGGO.js";
28
+ } from "../chunk-L6Y7TSQ4.js";
29
29
  import {
30
30
  CHART_COLOR_SCHEMES,
31
31
  CHART_LAYOUT_PRESETS,
@@ -47,7 +47,7 @@ import {
47
47
  monochromeChartPalette,
48
48
  sparklineToSvg,
49
49
  summarizeChart
50
- } from "../chunk-KPWG3PSW.js";
50
+ } from "../chunk-23E5GI2U.js";
51
51
  import "../chunk-KGRZMHZB.js";
52
52
  import {
53
53
  CHART_DATE_STEPS,
@@ -85,6 +85,7 @@ import {
85
85
  formatChartValueWithCode,
86
86
  getChartMap,
87
87
  layoutChart,
88
+ layoutStreamgraph,
88
89
  linearMap,
89
90
  listChartMaps,
90
91
  matchChartMapRegions,
@@ -99,7 +100,7 @@ import {
99
100
  suggestChartReferences,
100
101
  summarizeChartSeries,
101
102
  trendNumberText
102
- } from "../chunk-OJQVKJYD.js";
103
+ } from "../chunk-WKMUBATU.js";
103
104
  import {
104
105
  CHART_AXIS_KINDS,
105
106
  CHART_AXIS_SCALES,
@@ -193,7 +194,7 @@ import {
193
194
  shadeChartColor,
194
195
  simulateChartVision,
195
196
  uniqueChartSeriesId
196
- } from "../chunk-ORZF4JOO.js";
197
+ } from "../chunk-6ZZKRH7R.js";
197
198
  import "../chunk-O6OGNDND.js";
198
199
  import "../chunk-II2WIF5Z.js";
199
200
  import {
@@ -206,7 +207,7 @@ import {
206
207
  createInstantPresenceClock,
207
208
  realPresenceClock,
208
209
  tweenPresenceCursor
209
- } from "../chunk-O2ANJFUF.js";
210
+ } from "../chunk-IVSWRVB4.js";
210
211
  import {
211
212
  readZip
212
213
  } from "../chunk-CIQIM2IP.js";
@@ -407,7 +408,10 @@ function recommendForShape(shape) {
407
408
  add("line", "Line", "The categories are dates: a line shows change over time.");
408
409
  add("area", "Area", "Shows change over time with volume.");
409
410
  add("bar", "Column", "Compares each period.");
410
- if (shape.series > 1) add("area", "Stacked area", "Shows how the parts add up over time.", "stacked");
411
+ if (shape.series > 1) {
412
+ add("area", "Stacked area", "Shows how the parts add up over time.", "stacked");
413
+ add("streamgraph", "Streamgraph", "Shows changing proportions and overall volume as an organic stream.");
414
+ }
411
415
  if (shape.series >= 5 && shape.points >= 3) add("barrace", "Bar race", "Many series over time: an animated ranking shows who leads when.");
412
416
  return out;
413
417
  }
@@ -1338,7 +1342,7 @@ function chartHitTest(scene, point, measure = (t, s, w = 400) => t.length * s *
1338
1342
  }
1339
1343
 
1340
1344
  // src/chart/tooltip.ts
1341
- var VALUE_FAMILIES = /* @__PURE__ */ new Set(["cartesian", "xy", "pie", "radar", "waterfall", "funnel", "parliament", "slope"]);
1345
+ var VALUE_FAMILIES = /* @__PURE__ */ new Set(["cartesian", "xy", "pie", "radar", "waterfall", "funnel", "parliament", "slope", "streamgraph"]);
1342
1346
  var SLICE_FAMILIES = /* @__PURE__ */ new Set(["pie", "funnel", "parliament"]);
1343
1347
  function valueFormat(spec, series) {
1344
1348
  return series.format ?? (series.axis === "secondary" ? spec.yAxis2.format : spec.yAxis.format);
@@ -3446,6 +3450,7 @@ export {
3446
3450
  isXyChart,
3447
3451
  layoutChart,
3448
3452
  layoutSparkline,
3453
+ layoutStreamgraph,
3449
3454
  linearMap,
3450
3455
  listChartMaps,
3451
3456
  locateChartPoint,
@@ -0,0 +1,15 @@
1
+ import { type FamilyResult, type LayoutCtx } from './layout-shared.cjs';
2
+ import type { ChartRect, ChartSeries } from './types.cjs';
3
+ /**
4
+ * Lays out a streamgraph: series stacked symmetrically around a center baseline (silhouette offset).
5
+ *
6
+ * For each category index i:
7
+ * total(i) = sum_{s} v_s(i) (where v_s(i) >= 0)
8
+ * y0(i) = -0.5 * total(i)
9
+ *
10
+ * Layers stack upwards from y0:
11
+ * layer_s: from y_bottom = y0 + prefix_sum to y_top = y_bottom + v_s(i)
12
+ *
13
+ * The value domain is symmetric: [-maxHalf, maxHalf].
14
+ */
15
+ export declare function layoutStreamgraph(ctx: LayoutCtx, area: ChartRect, visible: ChartSeries[]): FamilyResult;
@@ -0,0 +1,15 @@
1
+ import { type FamilyResult, type LayoutCtx } from './layout-shared.js';
2
+ import type { ChartRect, ChartSeries } from './types.js';
3
+ /**
4
+ * Lays out a streamgraph: series stacked symmetrically around a center baseline (silhouette offset).
5
+ *
6
+ * For each category index i:
7
+ * total(i) = sum_{s} v_s(i) (where v_s(i) >= 0)
8
+ * y0(i) = -0.5 * total(i)
9
+ *
10
+ * Layers stack upwards from y0:
11
+ * layer_s: from y_bottom = y0 + prefix_sum to y_top = y_bottom + v_s(i)
12
+ *
13
+ * The value domain is symmetric: [-maxHalf, maxHalf].
14
+ */
15
+ export declare function layoutStreamgraph(ctx: LayoutCtx, area: ChartRect, visible: ChartSeries[]): FamilyResult;
@@ -19,7 +19,7 @@ export declare const CHART_NUMBER_STYLES: readonly NonNullable<ChartNumberFormat
19
19
  /** Labels for pickers, shared by the React and Svelte components. */
20
20
  export declare const CHART_TYPE_LABELS: Readonly<Record<ChartType, string>>;
21
21
  /** How a chart type is laid out. */
22
- export type ChartFamily = 'cartesian' | 'xy' | 'pie' | 'radar' | 'waterfall' | 'histogram' | 'box' | 'funnel' | 'treemap' | 'slope' | 'likert' | 'parliament' | 'sunburst' | 'sankey' | 'barrace' | 'choropleth';
22
+ export type ChartFamily = 'cartesian' | 'xy' | 'pie' | 'radar' | 'waterfall' | 'histogram' | 'box' | 'funnel' | 'treemap' | 'slope' | 'likert' | 'parliament' | 'sunburst' | 'sankey' | 'streamgraph' | 'barrace' | 'choropleth';
23
23
  /** A colour-blind-friendly categorical palette (Okabe–Ito order, tuned for light and dark backgrounds). */
24
24
  export declare const DEFAULT_CHART_PALETTE: readonly string[];
25
25
  export declare const DEFAULT_CHART_THEME: ChartTheme;
@@ -19,7 +19,7 @@ export declare const CHART_NUMBER_STYLES: readonly NonNullable<ChartNumberFormat
19
19
  /** Labels for pickers, shared by the React and Svelte components. */
20
20
  export declare const CHART_TYPE_LABELS: Readonly<Record<ChartType, string>>;
21
21
  /** How a chart type is laid out. */
22
- export type ChartFamily = 'cartesian' | 'xy' | 'pie' | 'radar' | 'waterfall' | 'histogram' | 'box' | 'funnel' | 'treemap' | 'slope' | 'likert' | 'parliament' | 'sunburst' | 'sankey' | 'barrace' | 'choropleth';
22
+ export type ChartFamily = 'cartesian' | 'xy' | 'pie' | 'radar' | 'waterfall' | 'histogram' | 'box' | 'funnel' | 'treemap' | 'slope' | 'likert' | 'parliament' | 'sunburst' | 'sankey' | 'streamgraph' | 'barrace' | 'choropleth';
23
23
  /** A colour-blind-friendly categorical palette (Okabe–Ito order, tuned for light and dark backgrounds). */
24
24
  export declare const DEFAULT_CHART_PALETTE: readonly string[];
25
25
  export declare const DEFAULT_CHART_THEME: ChartTheme;
@@ -17,12 +17,13 @@
17
17
  * - `sunburst` draws `tree` as rings from the centre out (or, without a tree, the first series
18
18
  * as one ring); a `treemap` with a `tree` nests each group's rectangles inside it.
19
19
  * - `sankey` draws `links` as flows between columns of nodes.
20
+ * - `streamgraph` stacks areas symmetrically around a center baseline (silhouette offset).
20
21
  * - `barrace` reads each category as a time point and each series as a name, and draws the
21
22
  * top `raceTopN` names at one moment as ranked horizontal bars (an animated ranking).
22
23
  * - `choropleth` shades the regions of a registered map (`map`) by the first series, each
23
24
  * category naming a region by id (ISO alpha-3 for countries) or name.
24
25
  */
25
- export type ChartType = 'bar' | 'line' | 'area' | 'scatter' | 'bubble' | 'pie' | 'donut' | 'radar' | 'waterfall' | 'histogram' | 'box' | 'funnel' | 'treemap' | 'slope' | 'likert' | 'parliament' | 'sunburst' | 'sankey' | 'barrace' | 'choropleth';
26
+ export type ChartType = 'bar' | 'line' | 'area' | 'scatter' | 'bubble' | 'pie' | 'donut' | 'radar' | 'waterfall' | 'histogram' | 'box' | 'funnel' | 'treemap' | 'slope' | 'likert' | 'parliament' | 'sunburst' | 'sankey' | 'streamgraph' | 'barrace' | 'choropleth';
26
27
  /** How a series is drawn in a cartesian chart. */
27
28
  export type ChartSeriesType = 'bar' | 'line' | 'area' | 'scatter';
28
29
  /** One data value; `null` is a gap (missing value). */
@@ -17,12 +17,13 @@
17
17
  * - `sunburst` draws `tree` as rings from the centre out (or, without a tree, the first series
18
18
  * as one ring); a `treemap` with a `tree` nests each group's rectangles inside it.
19
19
  * - `sankey` draws `links` as flows between columns of nodes.
20
+ * - `streamgraph` stacks areas symmetrically around a center baseline (silhouette offset).
20
21
  * - `barrace` reads each category as a time point and each series as a name, and draws the
21
22
  * top `raceTopN` names at one moment as ranked horizontal bars (an animated ranking).
22
23
  * - `choropleth` shades the regions of a registered map (`map`) by the first series, each
23
24
  * category naming a region by id (ISO alpha-3 for countries) or name.
24
25
  */
25
- export type ChartType = 'bar' | 'line' | 'area' | 'scatter' | 'bubble' | 'pie' | 'donut' | 'radar' | 'waterfall' | 'histogram' | 'box' | 'funnel' | 'treemap' | 'slope' | 'likert' | 'parliament' | 'sunburst' | 'sankey' | 'barrace' | 'choropleth';
26
+ export type ChartType = 'bar' | 'line' | 'area' | 'scatter' | 'bubble' | 'pie' | 'donut' | 'radar' | 'waterfall' | 'histogram' | 'box' | 'funnel' | 'treemap' | 'slope' | 'likert' | 'parliament' | 'sunburst' | 'sankey' | 'streamgraph' | 'barrace' | 'choropleth';
26
27
  /** How a series is drawn in a cartesian chart. */
27
28
  export type ChartSeriesType = 'bar' | 'line' | 'area' | 'scatter';
28
29
  /** One data value; `null` is a gap (missing value). */
@@ -14,7 +14,7 @@ import {
14
14
  r2,
15
15
  sameChartSelection,
16
16
  summarizeChartSeries
17
- } from "./chunk-OJQVKJYD.js";
17
+ } from "./chunk-WKMUBATU.js";
18
18
  import {
19
19
  CHART_TYPE_LABELS,
20
20
  DEFAULT_CHART_PALETTE,
@@ -47,7 +47,7 @@ import {
47
47
  parseChartValue,
48
48
  shadeChartColor,
49
49
  uniqueChartSeriesId
50
- } from "./chunk-ORZF4JOO.js";
50
+ } from "./chunk-6ZZKRH7R.js";
51
51
  import {
52
52
  parseCsv,
53
53
  parseTsv
@@ -607,6 +607,12 @@ function describeChart(spec, series = spec.series.filter((s) => !s.hidden).map((
607
607
  const pct = (v) => `${Math.round(v * 100)}%`;
608
608
  return `${head} of ${spec.categories.length} questions with ${answers.length} answers from ${answers[0]?.name} to ${answers[answers.length - 1]?.name}. Most positive: ${best[0]?.c} (${pct(best[0]?.share ?? 0)}); least: ${best[best.length - 1]?.c} (${pct(best[best.length - 1]?.share ?? 0)}).`;
609
609
  }
610
+ if (family === "streamgraph") {
611
+ const n = spec.categories.length;
612
+ const totals = spec.categories.map((_, i) => spec.series.filter((x) => !x.hidden).reduce((sum, s) => sum + Math.max(0, s.values[i] ?? 0), 0));
613
+ const maxTotal = Math.max(0, ...totals);
614
+ return `${head} of ${series.length} series over ${n} categories${n ? ` (${spec.categories[0]} to ${spec.categories[n - 1]})` : ""}, stacked symmetrically around a center baseline with a peak volume of ${fmt(maxTotal)}.`;
615
+ }
610
616
  if (family === "waterfall") {
611
617
  const s = spec.series.find((x) => !x.hidden);
612
618
  const steps = s.values.filter((v, i) => v !== null && Number.isFinite(v) && !/\b(sub)?total\b/i.test(spec.categories[i] ?? ""));
@@ -7,7 +7,7 @@ import {
7
7
  import {
8
8
  CHART_OOXML_NS,
9
9
  chartFromOoxml
10
- } from "./chunk-OLCHKGGO.js";
10
+ } from "./chunk-L6Y7TSQ4.js";
11
11
  import {
12
12
  compareDocuments
13
13
  } from "./chunk-V5OOP74P.js";
@@ -34,10 +34,10 @@ import {
34
34
  searchDocument,
35
35
  sliceContainsTable,
36
36
  syncInitialContent
37
- } from "./chunk-R2VHVQVY.js";
37
+ } from "./chunk-PI2UYMZY.js";
38
38
  import {
39
39
  chartDataToTable
40
- } from "./chunk-ORZF4JOO.js";
40
+ } from "./chunk-6ZZKRH7R.js";
41
41
  import {
42
42
  PIXERATE_DOCUMENT_MIME,
43
43
  getClipboardData,
@@ -1,7 +1,7 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class;
2
2
 
3
3
 
4
- var _chunkSWTUM32Hcjs = require('./chunk-SWTUM32H.cjs');
4
+ var _chunkK7ENM55Pcjs = require('./chunk-K7ENM55P.cjs');
5
5
 
6
6
  // src/tools/playback.ts
7
7
  var ARG_KINDS = {
@@ -143,7 +143,7 @@ var AgentPlayback = (_class = class {
143
143
  __init7() {this.running = 0}
144
144
  __init8() {this.calls = 0}
145
145
  constructor(options = {}) {;_class.prototype.__init.call(this);_class.prototype.__init2.call(this);_class.prototype.__init3.call(this);_class.prototype.__init4.call(this);_class.prototype.__init5.call(this);_class.prototype.__init6.call(this);_class.prototype.__init7.call(this);_class.prototype.__init8.call(this);_class.prototype.__init9.call(this);
146
- this.clock = _nullishCoalesce(options.clock, () => ( _chunkSWTUM32Hcjs.realPresenceClock));
146
+ this.clock = _nullishCoalesce(options.clock, () => ( _chunkK7ENM55Pcjs.realPresenceClock));
147
147
  this.speed = _nullishCoalesce(options.speed, () => ( 1));
148
148
  this.reads = _nullishCoalesce(options.reads, () => ( "skip"));
149
149
  this.linger = _nullishCoalesce(options.linger, () => ( 1500));
@@ -206,7 +206,7 @@ var AgentPlayback = (_class = class {
206
206
  const base = _nullishCoalesce(info, () => ( this.defaultActor));
207
207
  let actor = this.actors.get(base.id);
208
208
  if (!actor) {
209
- actor = { info: { ...base, color: _nullishCoalesce(base.color, () => ( _chunkSWTUM32Hcjs.PRESENCE_COLORS[this.actors.size % _chunkSWTUM32Hcjs.PRESENCE_COLORS.length])) }, queue: Promise.resolve(), version: 0 };
209
+ actor = { info: { ...base, color: _nullishCoalesce(base.color, () => ( _chunkK7ENM55Pcjs.PRESENCE_COLORS[this.actors.size % _chunkK7ENM55Pcjs.PRESENCE_COLORS.length])) }, queue: Promise.resolve(), version: 0 };
210
210
  this.actors.set(base.id, actor);
211
211
  } else if (_optionalChain([info, 'optionalAccess', _12 => _12.name]) && info.name !== actor.info.name) actor.info = { ...actor.info, name: info.name };
212
212
  return actor;
@@ -294,6 +294,13 @@ var AgentPlayback = (_class = class {
294
294
  let committed = false;
295
295
  const gate = run.steps.some((s) => s.type === "stage") ? createStageGate() : null;
296
296
  if (gate) call.context.stage = gate.wait;
297
+ call.context.perform = async (extra) => {
298
+ for (const step of extra) {
299
+ if (step.type === "commit" || step.type === "stage" || step.type === "open") continue;
300
+ record(step);
301
+ await this.step(presence, locate, id, step, wait, instant);
302
+ }
303
+ };
297
304
  let pending = null;
298
305
  try {
299
306
  for (const step of run.steps) {
@@ -338,12 +345,13 @@ var AgentPlayback = (_class = class {
338
345
  }
339
346
  } catch (error) {
340
347
  _optionalChain([gate, 'optionalAccess', _42 => _42.open, 'call', _43 => _43()]);
341
- presence.set({ id, pressed: false, message: `\u2717 ${error instanceof Error ? error.message : String(error)}`.slice(0, 140) });
348
+ presence.set({ id, pressed: false, gesture: void 0, message: `\u2717 ${error instanceof Error ? error.message : String(error)}`.slice(0, 140) });
342
349
  await wait(900);
343
350
  throw error;
344
351
  } finally {
345
352
  if (!readOnly) _optionalChain([surface, 'access', _44 => _44.endGesture, 'optionalCall', _45 => _45()]);
346
- presence.set({ id, pressed: false });
353
+ call.context.perform = void 0;
354
+ presence.set({ id, pressed: false, gesture: void 0 });
347
355
  }
348
356
  if (isErrorResult(result)) {
349
357
  const text = _nullishCoalesce(_optionalChain([result, 'access', _46 => _46.content, 'optionalAccess', _47 => _47.find, 'call', _48 => _48((c) => c.type === "text"), 'optionalAccess', _49 => _49.text]), () => ( "The tool failed."));
@@ -400,10 +408,10 @@ var AgentPlayback = (_class = class {
400
408
  presence.set({ id, message: step.text });
401
409
  return wait(_nullishCoalesce(step.ms, () => ( readingTime(step.text))));
402
410
  case "press":
403
- presence.set({ id, pressed: true });
411
+ presence.set({ id, pressed: true, gesture: step.gesture });
404
412
  return wait(90);
405
413
  case "release":
406
- presence.set({ id, pressed: false });
414
+ presence.set({ id, pressed: false, gesture: void 0 });
407
415
  return wait(60);
408
416
  case "type": {
409
417
  const total = _nullishCoalesce(step.ms, () => ( Math.min(900, 40 * step.text.length + 150)));