@pixerate/editor 0.243.0 → 0.245.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 (113) hide show
  1. package/dist/agent/index.cjs +34 -32
  2. package/dist/agent/index.js +6 -4
  3. package/dist/animation-editor/index.cjs +61 -61
  4. package/dist/animation-editor/index.js +4 -4
  5. package/dist/{brushstrokeRender-274HGNZR.js → brushstrokeRender-4542T5HP.js} +2 -2
  6. package/dist/{brushstrokeRender-C7RJZPMC.cjs → brushstrokeRender-QA5WVIDT.cjs} +5 -5
  7. package/dist/canvas/changeFeed.d.cts +71 -0
  8. package/dist/canvas/changeFeed.d.ts +71 -0
  9. package/dist/canvas/index.cjs +490 -34
  10. package/dist/canvas/index.d.cts +3 -0
  11. package/dist/canvas/index.d.ts +3 -0
  12. package/dist/canvas/index.js +483 -27
  13. package/dist/canvas/proposal-tools.d.cts +21 -0
  14. package/dist/canvas/proposal-tools.d.ts +21 -0
  15. package/dist/canvas/proposals.d.cts +112 -0
  16. package/dist/canvas/proposals.d.ts +112 -0
  17. package/dist/chart/index.cjs +21 -21
  18. package/dist/chart/index.js +2 -2
  19. package/dist/{chunk-6L3WWIDW.js → chunk-4EQY4TZJ.js} +1 -1
  20. package/dist/{chunk-5FZS7J7C.cjs → chunk-4T47Z4J3.cjs} +18 -2
  21. package/dist/{chunk-4I76OCVD.cjs → chunk-5DLCOQOQ.cjs} +16 -1
  22. package/dist/{chunk-4ZHXLFXS.js → chunk-5RFENYO5.js} +1 -1
  23. package/dist/{chunk-SRXWDOUI.js → chunk-7YQNKSQ7.js} +1 -1
  24. package/dist/{chunk-WGN7AUKB.js → chunk-7YW7T5TJ.js} +1 -1
  25. package/dist/{chunk-X3ZINLIP.js → chunk-AU6MWQKZ.js} +1 -1
  26. package/dist/{chunk-OONFIFEU.cjs → chunk-BDIH4DYR.cjs} +23 -23
  27. package/dist/{chunk-AIS56JOO.js → chunk-BVRRIW7F.js} +1 -1
  28. package/dist/{chunk-KK2FWMA2.cjs → chunk-HZ547SGQ.cjs} +1 -1
  29. package/dist/{chunk-3WOZEBXZ.cjs → chunk-IZL5V5RK.cjs} +2 -2
  30. package/dist/{chunk-IXI5KATU.js → chunk-L5PB7EG3.js} +1 -1
  31. package/dist/{chunk-R2FVAKFH.cjs → chunk-M6JORA5Z.cjs} +86 -86
  32. package/dist/{chunk-RNSANXPT.js → chunk-NS62CQ2B.js} +112 -14
  33. package/dist/{chunk-UZU6DIZA.cjs → chunk-NUTMINJZ.cjs} +45 -45
  34. package/dist/{chunk-H4Z72Z4Z.js → chunk-OSTKS3YN.js} +1 -1
  35. package/dist/{chunk-HLBTRSQJ.js → chunk-P3NIPIKS.js} +263 -63
  36. package/dist/{chunk-7V7QMFTI.cjs → chunk-QOBCBGGI.cjs} +2 -2
  37. package/dist/{chunk-UV7OOZJQ.cjs → chunk-SD23XMVJ.cjs} +35 -35
  38. package/dist/{chunk-FQVVO5YA.js → chunk-SGPIVHJB.js} +1 -1
  39. package/dist/{chunk-HQZHOPNE.js → chunk-TBJEMELS.js} +18 -2
  40. package/dist/{chunk-QTMQ5TGA.js → chunk-UCYW4M66.js} +16 -1
  41. package/dist/{chunk-XFYLA3ZO.cjs → chunk-VMROIWLL.cjs} +290 -90
  42. package/dist/{chunk-W7GRGGBH.cjs → chunk-W7L4HUT2.cjs} +8 -8
  43. package/dist/{chunk-FJ2MSI43.cjs → chunk-WKPXOGZZ.cjs} +124 -26
  44. package/dist/{chunk-D2SGV525.cjs → chunk-XZNU4DUX.cjs} +2 -2
  45. package/dist/diagram/index.cjs +2 -2
  46. package/dist/diagram/index.js +1 -1
  47. package/dist/effects/index.cjs +4 -4
  48. package/dist/effects/index.js +2 -2
  49. package/dist/extensions/index.cjs +5 -5
  50. package/dist/extensions/index.js +4 -4
  51. package/dist/gradient/index.cjs +2 -2
  52. package/dist/gradient/index.js +1 -1
  53. package/dist/history/HistoryManager.d.cts +20 -1
  54. package/dist/history/HistoryManager.d.ts +20 -1
  55. package/dist/history/index.cjs +8 -2
  56. package/dist/history/index.js +8 -2
  57. package/dist/history/types.d.cts +31 -0
  58. package/dist/history/types.d.ts +31 -0
  59. package/dist/image-editor/index.cjs +785 -777
  60. package/dist/image-editor/index.js +13 -5
  61. package/dist/index.cjs +16 -10
  62. package/dist/index.js +11 -5
  63. package/dist/kernel-wasm-4KVONDAU.js +9 -0
  64. package/dist/kernel-wasm-TTYRBGAK.cjs +9 -0
  65. package/dist/paint/index.cjs +10 -2
  66. package/dist/paint/index.js +9 -1
  67. package/dist/paint/wet/film.d.cts +19 -1
  68. package/dist/paint/wet/film.d.ts +19 -1
  69. package/dist/paint/wet/gpu-kernels.d.cts +2 -2
  70. package/dist/paint/wet/gpu-kernels.d.ts +2 -2
  71. package/dist/paint/wet/kernel-wasm.d.cts +5 -5
  72. package/dist/paint/wet/kernel-wasm.d.ts +5 -5
  73. package/dist/paint/wet/kernel.d.cts +1 -1
  74. package/dist/paint/wet/kernel.d.ts +1 -1
  75. package/dist/paint/wet/medium.d.cts +3 -1
  76. package/dist/paint/wet/medium.d.ts +3 -1
  77. package/dist/paint/wet/model.d.cts +19 -4
  78. package/dist/paint/wet/model.d.ts +19 -4
  79. package/dist/paint/wet/world.d.cts +34 -8
  80. package/dist/paint/wet/world.d.ts +34 -8
  81. package/dist/paint-editor/backlight.d.cts +77 -0
  82. package/dist/paint-editor/backlight.d.ts +77 -0
  83. package/dist/paint-editor/controller.d.cts +11 -0
  84. package/dist/paint-editor/controller.d.ts +11 -0
  85. package/dist/paint-editor/index.cjs +685 -397
  86. package/dist/paint-editor/index.d.cts +1 -0
  87. package/dist/paint-editor/index.d.ts +1 -0
  88. package/dist/paint-editor/index.js +308 -20
  89. package/dist/paint-editor/paper.d.cts +7 -0
  90. package/dist/paint-editor/paper.d.ts +7 -0
  91. package/dist/paint-editor/wet.d.cts +9 -0
  92. package/dist/paint-editor/wet.d.ts +9 -0
  93. package/dist/parameters/index.cjs +2 -2
  94. package/dist/parameters/index.js +1 -1
  95. package/dist/tools/index.cjs +4 -2
  96. package/dist/tools/index.d.cts +1 -0
  97. package/dist/tools/index.d.ts +1 -0
  98. package/dist/tools/index.js +3 -1
  99. package/dist/tools/origin.d.cts +22 -0
  100. package/dist/tools/origin.d.ts +22 -0
  101. package/dist/vector/index.cjs +964 -964
  102. package/dist/vector/index.js +5 -5
  103. package/dist/video-editor/index.cjs +4 -4
  104. package/dist/video-editor/index.js +2 -2
  105. package/package.json +1 -1
  106. package/skills/pixerate-canvas/SKILL.md +25 -0
  107. package/skills/pixerate-paint-editor/SKILL.md +3 -3
  108. package/skills/pixerate-paint-editor/references/light-paint.md +30 -7
  109. package/skills/pixerate-paint-watercolour/SKILL.md +10 -1
  110. package/skills/pixerate-paint-watercolour/evals/glowing-wash.json +22 -0
  111. package/skills/pixerate-paint-watercolour/evals/stained-glass.json +16 -0
  112. package/dist/kernel-wasm-6FPOLVUZ.cjs +0 -9
  113. package/dist/kernel-wasm-WIMMJUF2.js +0 -9
@@ -10,7 +10,7 @@ import {
10
10
  renderShapeBrushstroke,
11
11
  validateCanvasBrush,
12
12
  validateCanvasBrushPaint
13
- } from "../chunk-IXI5KATU.js";
13
+ } from "../chunk-L5PB7EG3.js";
14
14
  import {
15
15
  PATHFINDER_OPERATIONS,
16
16
  PlanarMap,
@@ -3027,7 +3027,7 @@ function createCanvasArrangeController(options) {
3027
3027
  let resizeStart = null;
3028
3028
  let resizeIndex = null;
3029
3029
  let lastResized = null;
3030
- const selectedIds = (ids) => ids ? [...ids] : options.getSelectedIds?.() ?? options.getNodes().filter((n3) => n3.selected).map((n3) => n3.id);
3030
+ const selectedIds2 = (ids) => ids ? [...ids] : options.getSelectedIds?.() ?? options.getNodes().filter((n3) => n3.selected).map((n3) => n3.id);
3031
3031
  const setGuides = (next) => {
3032
3032
  if (next.length === 0 && guides.length === 0) return;
3033
3033
  guides = next;
@@ -3074,31 +3074,31 @@ function createCanvasArrangeController(options) {
3074
3074
  },
3075
3075
  apply,
3076
3076
  align(edge, ids, alignOptions = {}) {
3077
- return apply(`Align ${edge}`, alignNodes(options.getNodes(), selectedIds(ids), edge, { ...rect2(), ...alignOptions }));
3077
+ return apply(`Align ${edge}`, alignNodes(options.getNodes(), selectedIds2(ids), edge, { ...rect2(), ...alignOptions }));
3078
3078
  },
3079
3079
  distribute(axis, mode = "gaps", ids, distributeOptions = {}) {
3080
3080
  return apply(
3081
3081
  `Distribute ${axis}`,
3082
- distributeNodes(options.getNodes(), selectedIds(ids), axis, mode, { ...rect2(), ...distributeOptions })
3082
+ distributeNodes(options.getNodes(), selectedIds2(ids), axis, mode, { ...rect2(), ...distributeOptions })
3083
3083
  );
3084
3084
  },
3085
3085
  matchSize(dimension, ids, sizeOptions = {}) {
3086
3086
  return apply(
3087
3087
  "Make Same Size",
3088
- matchSize(options.getNodes(), selectedIds(ids), dimension, { ...rect2(), ...sizeOptions })
3088
+ matchSize(options.getNodes(), selectedIds2(ids), dimension, { ...rect2(), ...sizeOptions })
3089
3089
  );
3090
3090
  },
3091
3091
  reorder(operation, ids) {
3092
- return apply(operation, reorderNodes(options.getNodes(), selectedIds(ids), operation, rect2()));
3092
+ return apply(operation, reorderNodes(options.getNodes(), selectedIds2(ids), operation, rect2()));
3093
3093
  },
3094
3094
  bringForward: (ids) => controller.reorder("bringForward", ids),
3095
3095
  sendBackward: (ids) => controller.reorder("sendBackward", ids),
3096
3096
  bringToFront: (ids) => controller.reorder("bringToFront", ids),
3097
3097
  sendToBack: (ids) => controller.reorder("sendToBack", ids),
3098
- lock: (ids) => setLocked("Lock", selectedIds(ids), true),
3099
- unlock: (ids) => setLocked("Unlock", selectedIds(ids), false),
3098
+ lock: (ids) => setLocked("Lock", selectedIds2(ids), true),
3099
+ unlock: (ids) => setLocked("Unlock", selectedIds2(ids), false),
3100
3100
  toggleLock(ids) {
3101
- const list = selectedIds(ids);
3101
+ const list = selectedIds2(ids);
3102
3102
  const set = new Set(list);
3103
3103
  const anyUnlocked = options.getNodes().some((n3) => set.has(n3.id) && !isLocked(n3));
3104
3104
  return anyUnlocked ? controller.lock(list) : controller.unlock(list);
@@ -3112,7 +3112,7 @@ function createCanvasArrangeController(options) {
3112
3112
  */
3113
3113
  combineShapes(operation, ids, combineOptions = {}) {
3114
3114
  const before = options.getNodes();
3115
- const result = combineShapeNodes(before, selectedIds(ids), operation, { ...rect2(), ...combineOptions });
3115
+ const result = combineShapeNodes(before, selectedIds2(ids), operation, { ...rect2(), ...combineOptions });
3116
3116
  if (!result.ok) return result;
3117
3117
  const name = `${operation[0].toUpperCase()}${operation.slice(1)} Shapes`;
3118
3118
  const run = () => options.setNodes(applyShapeCombination(options.getNodes(), result));
@@ -3127,7 +3127,7 @@ function createCanvasArrangeController(options) {
3127
3127
  exclude: (ids, o) => controller.combineShapes("exclude", ids, o),
3128
3128
  divide: (ids, o) => controller.combineShapes("divide", ids, o),
3129
3129
  /** Whether the shape operations can run on `ids` (default: the selection). */
3130
- canCombineShapes: (ids) => canCombineShapeNodes(options.getNodes(), selectedIds(ids)).ok,
3130
+ canCombineShapes: (ids) => canCombineShapeNodes(options.getNodes(), selectedIds2(ids)).ok,
3131
3131
  /**
3132
3132
  * Offset Path: grows (`distance > 0`) or shrinks (`distance < 0`) every shape among
3133
3133
  * `ids` (default: the selection) by `distance` flow units, keeping curves, as one
@@ -3136,7 +3136,7 @@ function createCanvasArrangeController(options) {
3136
3136
  */
3137
3137
  offsetShapes(distance, ids, offsetOptions = {}) {
3138
3138
  const before = options.getNodes();
3139
- const result = offsetShapeNodes(before, selectedIds(ids), distance, { ...rect2(), ...offsetOptions });
3139
+ const result = offsetShapeNodes(before, selectedIds2(ids), distance, { ...rect2(), ...offsetOptions });
3140
3140
  if (!result.ok) return result;
3141
3141
  const run = () => options.setNodes(applyShapeReplacement(options.getNodes(), result));
3142
3142
  const undo = () => options.setNodes(revertShapeCombination(options.getNodes(), result, before));
@@ -3145,7 +3145,7 @@ function createCanvasArrangeController(options) {
3145
3145
  return result;
3146
3146
  },
3147
3147
  /** Whether `offsetShapes` can run on `ids` (default: the selection). */
3148
- canOffsetShapes: (ids) => canOffsetShapeNodes(options.getNodes(), selectedIds(ids)).ok,
3148
+ canOffsetShapes: (ids) => canOffsetShapeNodes(options.getNodes(), selectedIds2(ids)).ok,
3149
3149
  /**
3150
3150
  * Outline Stroke: converts the strokes of the shapes among `ids` (default: the
3151
3151
  * selection) to filled path shapes, as one undoable step. Refuses when a shape is
@@ -3153,7 +3153,7 @@ function createCanvasArrangeController(options) {
3153
3153
  */
3154
3154
  outlineStroke(ids, outlineOptions = {}) {
3155
3155
  const before = options.getNodes();
3156
- const result = outlineShapeNodeStrokes(before, selectedIds(ids), { ...rect2(), ...outlineOptions });
3156
+ const result = outlineShapeNodeStrokes(before, selectedIds2(ids), { ...rect2(), ...outlineOptions });
3157
3157
  if (!result.ok) return result;
3158
3158
  const run = () => options.setNodes(applyShapeReplacement(options.getNodes(), result));
3159
3159
  const undo = () => options.setNodes(revertShapeCombination(options.getNodes(), result, before));
@@ -3162,7 +3162,7 @@ function createCanvasArrangeController(options) {
3162
3162
  return result;
3163
3163
  },
3164
3164
  /** Whether `outlineStroke` can run on `ids` (default: the selection). */
3165
- canOutlineStroke: (ids) => canOutlineShapeNodeStrokes(options.getNodes(), selectedIds(ids)).ok,
3165
+ canOutlineStroke: (ids) => canOutlineShapeNodeStrokes(options.getNodes(), selectedIds2(ids)).ok,
3166
3166
  /**
3167
3167
  * Runs a shortcut action. Scene actions are not handled here (see the scenes store);
3168
3168
  * returns `false` for them and for unknown actions.
@@ -3217,7 +3217,7 @@ function createCanvasArrangeController(options) {
3217
3217
  },
3218
3218
  /** Caches the snap targets for a drag. Optional: `drag` builds them lazily. */
3219
3219
  beginDrag(ids) {
3220
- const list = selectedIds(ids);
3220
+ const list = selectedIds2(ids);
3221
3221
  dragKey = list.slice().sort().join("\0");
3222
3222
  dragIndex = createNodeGuideIndex(options.getNodes(), list, rect2());
3223
3223
  },
@@ -3228,7 +3228,7 @@ function createCanvasArrangeController(options) {
3228
3228
  */
3229
3229
  drag(ids) {
3230
3230
  if (options.snapping === false) return null;
3231
- const list = selectedIds(ids);
3231
+ const list = selectedIds2(ids);
3232
3232
  const key = list.slice().sort().join("\0");
3233
3233
  if (!dragIndex || key !== dragKey) controller.beginDrag(list);
3234
3234
  const result = snapNodeDrag(options.getNodes(), list, {
@@ -3549,10 +3549,10 @@ function measureToLine(a, orientation, at) {
3549
3549
  }
3550
3550
  return out;
3551
3551
  }
3552
- function measureSelection(nodes, selectedIds, hoveredId, options = {}) {
3552
+ function measureSelection(nodes, selectedIds2, hoveredId, options = {}) {
3553
3553
  const none = (selection2 = null) => ({ guides: [], target: null, selection: selection2 });
3554
3554
  const lookup = createNodeLookup(nodes);
3555
- const selected = [...new Set(selectedIds)].map((id) => lookup.get(id)).filter((n3) => !!n3 && n3.hidden !== true);
3555
+ const selected = [...new Set(selectedIds2)].map((id) => lookup.get(id)).filter((n3) => !!n3 && n3.hidden !== true);
3556
3556
  if (selected.length === 0) return none();
3557
3557
  const selection = boundsOf(selected.map((n3) => getNodeRect(n3, lookup, options)));
3558
3558
  if (!selection) return none();
@@ -5209,7 +5209,7 @@ var defaultLabel = (node) => typeof node.data?.label === "string" && node.data.l
5209
5209
  function getTimelineRows(nodes, ids, options = {}) {
5210
5210
  const byId = new Map(nodes.map((n3) => [n3.id, n3]));
5211
5211
  const selection = options.selection ?? [];
5212
- const labelOf2 = options.labelOf ?? defaultLabel;
5212
+ const labelOf3 = options.labelOf ?? defaultLabel;
5213
5213
  const rows = [];
5214
5214
  for (const id of new Set(ids)) {
5215
5215
  const node = byId.get(id);
@@ -5220,7 +5220,7 @@ function getTimelineRows(nodes, ids, options = {}) {
5220
5220
  rows.push({
5221
5221
  id: `${id}:${property}`,
5222
5222
  nodeId: id,
5223
- nodeLabel: labelOf2(node),
5223
+ nodeLabel: labelOf3(node),
5224
5224
  property,
5225
5225
  label,
5226
5226
  enabled: track.enabled !== false,
@@ -5315,7 +5315,7 @@ function createCanvasAnimationController(options) {
5315
5315
  for (const listener of listeners) listener(state);
5316
5316
  };
5317
5317
  player.subscribe(notify);
5318
- const selectedIds = () => options.getSelectedIds?.() ?? options.getNodes().filter((n3) => n3.selected).map((n3) => n3.id);
5318
+ const selectedIds2 = () => options.getSelectedIds?.() ?? options.getNodes().filter((n3) => n3.selected).map((n3) => n3.id);
5319
5319
  const KEEP_FIELDS = ["selected", "dragging", "measured"];
5320
5320
  const replaceNodes = (nodes, replacements, animationOnly = false) => nodes.map((node) => {
5321
5321
  const replacement = replacements.get(node.id);
@@ -5432,7 +5432,7 @@ function createCanvasAnimationController(options) {
5432
5432
  controller.setRecording(!recording);
5433
5433
  },
5434
5434
  /** Seeks to the next keyframe (of the selected nodes, or all) after the playhead. */
5435
- nextKeyframe(ids = selectedIds()) {
5435
+ nextKeyframe(ids = selectedIds2()) {
5436
5436
  const list = [...ids];
5437
5437
  const times = getKeyframeTimes(options.getNodes(), list.length ? { ids: list } : {});
5438
5438
  const next = times.find((t) => t > player.currentTime + ANIMATION_TIME_EPSILON);
@@ -5440,7 +5440,7 @@ function createCanvasAnimationController(options) {
5440
5440
  player.seek(next);
5441
5441
  return next;
5442
5442
  },
5443
- previousKeyframe(ids = selectedIds()) {
5443
+ previousKeyframe(ids = selectedIds2()) {
5444
5444
  const list = [...ids];
5445
5445
  const times = getKeyframeTimes(options.getNodes(), list.length ? { ids: list } : {});
5446
5446
  const prev = [...times].reverse().find((t) => t < player.currentTime - ANIMATION_TIME_EPSILON);
@@ -5497,7 +5497,7 @@ function createCanvasAnimationController(options) {
5497
5497
  addKeyframe(ids, keys, time = player.currentTime) {
5498
5498
  let refs = [];
5499
5499
  commit("Add Keyframe", (nodes) => {
5500
- const result = addKeyframesAtTime(nodes, ids ?? selectedIds(), time, { ...propertyOptions(), ...keys ? { keys } : {} });
5500
+ const result = addKeyframesAtTime(nodes, ids ?? selectedIds2(), time, { ...propertyOptions(), ...keys ? { keys } : {} });
5501
5501
  refs = result.refs;
5502
5502
  return result.nodes;
5503
5503
  });
@@ -5584,7 +5584,7 @@ function createCanvasAnimationController(options) {
5584
5584
  return clipboard;
5585
5585
  },
5586
5586
  /** Pastes at the playhead onto the selected nodes (or the copied ones). */
5587
- pasteKeyframes(data = clipboard, nodeIds = selectedIds(), time = player.currentTime) {
5587
+ pasteKeyframes(data = clipboard, nodeIds = selectedIds2(), time = player.currentTime) {
5588
5588
  if (!data) return [];
5589
5589
  let refs = [];
5590
5590
  commit("Paste Keyframes", (nodes) => {
@@ -5676,7 +5676,7 @@ function createCanvasAnimationController(options) {
5676
5676
  },
5677
5677
  // ----- views & export ---------------------------------------------------------------
5678
5678
  /** Timeline rows for `ids` (default: selected nodes), including the drag preview. */
5679
- timelineRows(ids = selectedIds(), opts = {}) {
5679
+ timelineRows(ids = selectedIds2(), opts = {}) {
5680
5680
  return getTimelineRows(options.getNodes(), ids, { ...propertyOptions(), ...opts, selection, dragDelta: drag?.delta ?? 0 });
5681
5681
  },
5682
5682
  sampleFrames(opts = {}) {
@@ -12198,6 +12198,458 @@ function createCanvasExplosionToolProvider(target, options = {}) {
12198
12198
  subscribe: options.subscribe
12199
12199
  };
12200
12200
  }
12201
+
12202
+ // src/canvas/proposals.ts
12203
+ var CANVAS_PROPOSAL_CLASS = "pixerate-proposal";
12204
+ var toSide = (side) => side === "top" ? "above" : side === "bottom" ? "below" : side ?? "right";
12205
+ var randomId = (kind) => `${kind}-${Math.random().toString(36).slice(2, 9)}`;
12206
+ var joinClass = (a, b) => typeof a === "string" && a ? `${a} ${b}` : b;
12207
+ function createCanvasProposals(options) {
12208
+ const size2 = options.defaultNodeSize ?? { width: 200, height: 60 };
12209
+ const makeId = options.idGenerator ?? randomId;
12210
+ const now = options.now ?? Date.now;
12211
+ let state = { proposals: [] };
12212
+ const listeners = /* @__PURE__ */ new Set();
12213
+ const set = (proposals) => {
12214
+ state = { proposals };
12215
+ listeners.forEach((l) => l(state));
12216
+ };
12217
+ const find = (id) => {
12218
+ const proposal = state.proposals.find((p) => p.id === id);
12219
+ if (!proposal) {
12220
+ const ids = state.proposals.map((p) => p.id);
12221
+ throw new Error(`No proposal "${id}". ${ids.length ? `Pending proposals: ${ids.join(", ")}.` : "There are no pending proposals."} Call list_proposals for ids.`);
12222
+ }
12223
+ return proposal;
12224
+ };
12225
+ const rectOf = (node) => ({
12226
+ x: node.position.x,
12227
+ y: node.position.y,
12228
+ width: node.measured?.width ?? node.width ?? size2.width,
12229
+ height: node.measured?.height ?? node.height ?? size2.height
12230
+ });
12231
+ const missing = (proposal) => {
12232
+ const present = new Set(options.getNodes().map((n3) => n3.id));
12233
+ return proposal.anchors.filter((id) => !present.has(id));
12234
+ };
12235
+ const propose = (input) => {
12236
+ const title = typeof input.title === "string" ? input.title.trim() : "";
12237
+ if (!title) throw new Error("A proposal needs a title: what it adds, in a few words.");
12238
+ const nodesIn = input.nodes ?? [];
12239
+ const edgesIn = input.edges ?? [];
12240
+ if (!nodesIn.length && !edgesIn.length) throw new Error("A proposal needs at least one node or edge.");
12241
+ const canvasNodes = options.getNodes();
12242
+ const canvasIds = new Set(canvasNodes.map((n3) => n3.id));
12243
+ const taken = /* @__PURE__ */ new Set([...canvasIds, ...options.getEdges().map((e) => e.id)]);
12244
+ for (const p of state.proposals) {
12245
+ p.nodes.forEach((n3) => taken.add(n3.id));
12246
+ p.edges.forEach((e) => taken.add(e.id));
12247
+ }
12248
+ const rects = {};
12249
+ for (const n3 of canvasNodes) rects[n3.id] = rectOf(n3);
12250
+ for (const p of state.proposals) for (const n3 of p.nodes) rects[n3.id] = rectOf(n3);
12251
+ const fresh = (kind, wanted) => {
12252
+ if (wanted !== void 0) {
12253
+ if (typeof wanted !== "string" || !wanted) throw new Error(`A ${kind} id must be a non-empty string.`);
12254
+ if (taken.has(wanted)) throw new Error(`Id "${wanted}" is already in use on the canvas or in a pending proposal. Pick another or leave it out.`);
12255
+ taken.add(wanted);
12256
+ return wanted;
12257
+ }
12258
+ let id = makeId(kind);
12259
+ while (taken.has(id)) id = makeId(kind);
12260
+ taken.add(id);
12261
+ return id;
12262
+ };
12263
+ const nodes = [];
12264
+ const edges = [];
12265
+ const anchors = /* @__PURE__ */ new Set();
12266
+ const ownIds = /* @__PURE__ */ new Set();
12267
+ const known = (id) => canvasIds.has(id) || ownIds.has(id);
12268
+ nodesIn.forEach((input2, i) => {
12269
+ if (input2.nearNodeId !== void 0 && !known(input2.nearNodeId)) {
12270
+ throw new Error(`nodes[${i}].nearNodeId "${input2.nearNodeId}" is not on the canvas or earlier in this proposal. Use an id from the canvas state.`);
12271
+ }
12272
+ const id = fresh("node", input2.id);
12273
+ const nodeSize = { width: input2.width ?? size2.width, height: input2.height ?? size2.height };
12274
+ let position = input2.position;
12275
+ if (position && (!Number.isFinite(position.x) || !Number.isFinite(position.y))) {
12276
+ throw new Error(`nodes[${i}].position needs finite x and y.`);
12277
+ }
12278
+ if (!position) {
12279
+ const view = options.visibleRect?.();
12280
+ if (input2.nearNodeId) position = placeBeside(rects, nodeSize, toSide(input2.side), input2.nearNodeId);
12281
+ else if (view) position = placeInView(rects, nodeSize, view);
12282
+ else if (canvasNodes.length || nodes.length) {
12283
+ const last = nodes[nodes.length - 1] ?? canvasNodes[canvasNodes.length - 1];
12284
+ position = placeBeside(rects, nodeSize, "right", last.id);
12285
+ } else position = { x: 100, y: 100 };
12286
+ }
12287
+ const type = input2.type ?? options.defaultNodeType;
12288
+ const node = {
12289
+ id,
12290
+ position,
12291
+ data: { ...input2.data ?? {} },
12292
+ ...type !== void 0 ? { type } : {},
12293
+ ...input2.width !== void 0 ? { width: input2.width } : {},
12294
+ ...input2.height !== void 0 ? { height: input2.height } : {}
12295
+ };
12296
+ nodes.push(node);
12297
+ ownIds.add(id);
12298
+ rects[id] = { ...position, ...nodeSize };
12299
+ if (input2.nearNodeId) {
12300
+ if (canvasIds.has(input2.nearNodeId)) anchors.add(input2.nearNodeId);
12301
+ edges.push({ id: fresh("edge"), source: input2.nearNodeId, target: id });
12302
+ }
12303
+ });
12304
+ edgesIn.forEach((input2, i) => {
12305
+ for (const end of ["source", "target"]) {
12306
+ if (typeof input2[end] !== "string" || !known(input2[end])) {
12307
+ throw new Error(`edges[${i}].${end} "${String(input2[end])}" is not on the canvas or in this proposal.`);
12308
+ }
12309
+ }
12310
+ if (input2.source === input2.target) throw new Error(`edges[${i}] connects "${input2.source}" to itself.`);
12311
+ const id = fresh("edge", input2.id);
12312
+ edges.push({ id, source: input2.source, target: input2.target, ...input2.label ? { label: input2.label } : {} });
12313
+ for (const end of [input2.source, input2.target]) if (canvasIds.has(end)) anchors.add(end);
12314
+ });
12315
+ const proposal = {
12316
+ id: makeId("proposal"),
12317
+ title,
12318
+ ...input.rationale ? { rationale: input.rationale } : {},
12319
+ origin: input.origin ?? options.origin ?? "agent:anonymous",
12320
+ createdAt: now(),
12321
+ nodes,
12322
+ edges,
12323
+ anchors: [...anchors]
12324
+ };
12325
+ while (state.proposals.some((p) => p.id === proposal.id)) proposal.id = makeId("proposal");
12326
+ set([...state.proposals, proposal]);
12327
+ return proposal;
12328
+ };
12329
+ const accept = (id) => {
12330
+ const proposal = find(id);
12331
+ const reason = options.readOnly?.();
12332
+ if (reason) throw new Error(reason);
12333
+ const gone = missing(proposal);
12334
+ if (gone.length) {
12335
+ throw new Error(`Proposal "${id}" connects to ${gone.map((g) => `"${g}"`).join(", ")}, which ${gone.length > 1 ? "are" : "is"} no longer on the canvas. Reject it and propose again.`);
12336
+ }
12337
+ const nodeIds = proposal.nodes.map((n3) => n3.id);
12338
+ const edgeIds = proposal.edges.map((e) => e.id);
12339
+ const clash = options.getNodes().find((n3) => nodeIds.includes(n3.id)) ?? options.getEdges().find((e) => edgeIds.includes(e.id));
12340
+ if (clash) throw new Error(`Id "${clash.id}" was taken on the canvas after proposal "${id}" was made. Reject it and propose again.`);
12341
+ const nodeSet = new Set(nodeIds);
12342
+ const edgeSet = new Set(edgeIds);
12343
+ const add = () => {
12344
+ options.setNodes([...options.getNodes().filter((n3) => !nodeSet.has(n3.id)), ...proposal.nodes.map((n3) => ({ ...n3 }))]);
12345
+ options.setEdges([...options.getEdges().filter((e) => !edgeSet.has(e.id)), ...proposal.edges.map((e) => ({ ...e }))]);
12346
+ };
12347
+ const remove = () => {
12348
+ options.setNodes(options.getNodes().filter((n3) => !nodeSet.has(n3.id)));
12349
+ options.setEdges(options.getEdges().filter((e) => !edgeSet.has(e.id)));
12350
+ };
12351
+ set(state.proposals.filter((p) => p.id !== id));
12352
+ if (options.history) options.history.execute({ name: proposal.title, origin: proposal.origin, execute: add, undo: remove });
12353
+ else add();
12354
+ return { proposalId: id, nodeIds, edgeIds, historyLabel: proposal.title };
12355
+ };
12356
+ const reject = (id) => {
12357
+ const proposal = find(id);
12358
+ set(state.proposals.filter((p) => p.id !== id));
12359
+ return proposal;
12360
+ };
12361
+ const clear = (origin) => {
12362
+ const dropped = state.proposals.filter((p) => origin === void 0 || p.origin === origin).map((p) => p.id);
12363
+ if (dropped.length) set(state.proposals.filter((p) => !dropped.includes(p.id)));
12364
+ return dropped;
12365
+ };
12366
+ const withGhosts = (nodes, edges) => {
12367
+ if (!state.proposals.length) return { nodes: [...nodes], edges: [...edges] };
12368
+ const present = new Set(nodes.map((n3) => n3.id));
12369
+ const ghostNodes = [];
12370
+ const ghostEdges = [];
12371
+ for (const p of state.proposals) {
12372
+ const meta = { id: p.id, title: p.title };
12373
+ for (const n3 of p.nodes) {
12374
+ if (present.has(n3.id)) continue;
12375
+ present.add(n3.id);
12376
+ ghostNodes.push({
12377
+ ...n3,
12378
+ // Flow libraries hide a node until it is measured, and only nodes in the host's state get
12379
+ // measured: give the ghost the size it was placed with.
12380
+ measured: n3.measured ?? { width: n3.width ?? size2.width, height: n3.height ?? size2.height },
12381
+ draggable: false,
12382
+ selectable: false,
12383
+ connectable: false,
12384
+ deletable: false,
12385
+ className: joinClass(n3.className, CANVAS_PROPOSAL_CLASS),
12386
+ data: { ...n3.data, proposal: meta }
12387
+ });
12388
+ }
12389
+ }
12390
+ for (const p of state.proposals) {
12391
+ for (const e of p.edges) {
12392
+ if (!present.has(e.source) || !present.has(e.target)) continue;
12393
+ ghostEdges.push({ ...e, selectable: false, deletable: false, animated: true, className: joinClass(e.className, CANVAS_PROPOSAL_CLASS) });
12394
+ }
12395
+ }
12396
+ return { nodes: [...nodes, ...ghostNodes], edges: [...edges, ...ghostEdges] };
12397
+ };
12398
+ return {
12399
+ getState: () => state,
12400
+ subscribe: (listener) => {
12401
+ listeners.add(listener);
12402
+ return () => {
12403
+ listeners.delete(listener);
12404
+ };
12405
+ },
12406
+ propose,
12407
+ accept,
12408
+ reject,
12409
+ clear,
12410
+ get: (id) => state.proposals.find((p) => p.id === id),
12411
+ missing: (id) => missing(find(id)),
12412
+ withGhosts
12413
+ };
12414
+ }
12415
+
12416
+ // src/canvas/changeFeed.ts
12417
+ var RUNTIME_NODE_KEYS2 = /* @__PURE__ */ new Set(["selected", "dragging", "measured", "resizing"]);
12418
+ var RUNTIME_EDGE_KEYS2 = /* @__PURE__ */ new Set(["selected"]);
12419
+ var selectedIds = (nodes) => nodes.filter((n3) => n3.selected).map((n3) => n3.id);
12420
+ function diffFields(before, after, ignore) {
12421
+ if (before === after) return [];
12422
+ const fields = [];
12423
+ for (const key of /* @__PURE__ */ new Set([...Object.keys(before), ...Object.keys(after)])) {
12424
+ if (ignore.has(key)) continue;
12425
+ const a = before[key];
12426
+ const b = after[key];
12427
+ if (a === b) continue;
12428
+ if (a && b && typeof a === "object" && typeof b === "object" && JSON.stringify(a) === JSON.stringify(b)) continue;
12429
+ fields.push(key);
12430
+ }
12431
+ return fields;
12432
+ }
12433
+ function createCanvasChangeFeed(options) {
12434
+ const now = options.now ?? Date.now;
12435
+ const nodeIgnore = /* @__PURE__ */ new Set([...RUNTIME_NODE_KEYS2, ...options.ignoreNodeKeys ?? []]);
12436
+ const listeners = /* @__PURE__ */ new Set();
12437
+ let nodes = options.getNodes();
12438
+ let edges = options.getEdges();
12439
+ let seq = 0;
12440
+ let pending;
12441
+ const check = () => {
12442
+ const nextNodes = options.getNodes();
12443
+ const nextEdges = options.getEdges();
12444
+ if (nextNodes === nodes && nextEdges === edges) return null;
12445
+ const beforeNodes = new Map(nodes.map((n3) => [n3.id, n3]));
12446
+ const afterNodes = new Map(nextNodes.map((n3) => [n3.id, n3]));
12447
+ const beforeEdges = new Map(edges.map((e) => [e.id, e]));
12448
+ const afterEdges = new Map(nextEdges.map((e) => [e.id, e]));
12449
+ const addedNodes = nextNodes.filter((n3) => !beforeNodes.has(n3.id));
12450
+ const removedNodes = nodes.filter((n3) => !afterNodes.has(n3.id));
12451
+ const changedNodes = [];
12452
+ for (const after of nextNodes) {
12453
+ const before = beforeNodes.get(after.id);
12454
+ if (!before) continue;
12455
+ const fields = diffFields(before, after, nodeIgnore);
12456
+ if (fields.length) changedNodes.push({ before, after, fields });
12457
+ }
12458
+ const addedEdges = nextEdges.filter((e) => !beforeEdges.has(e.id));
12459
+ const removedEdges = edges.filter((e) => !afterEdges.has(e.id));
12460
+ const changedEdges = [];
12461
+ for (const after of nextEdges) {
12462
+ const before = beforeEdges.get(after.id);
12463
+ if (!before) continue;
12464
+ const fields = diffFields(before, after, RUNTIME_EDGE_KEYS2);
12465
+ if (fields.length) changedEdges.push({ before, after, fields });
12466
+ }
12467
+ const selBefore = selectedIds(nodes);
12468
+ const selAfter = selectedIds(nextNodes);
12469
+ const selectionChanged = selBefore.length !== selAfter.length || selBefore.some((id, i) => id !== selAfter[i]);
12470
+ nodes = nextNodes;
12471
+ edges = nextEdges;
12472
+ const edited = addedNodes.length + removedNodes.length + changedNodes.length + addedEdges.length + removedEdges.length + changedEdges.length > 0;
12473
+ if (!edited && !selectionChanged) return null;
12474
+ const commit = edited ? pending : void 0;
12475
+ if (edited) pending = void 0;
12476
+ const change = {
12477
+ seq: ++seq,
12478
+ origin: commit?.kind === "execute" || commit?.kind === "merge" ? commit.origin : "user",
12479
+ ...commit ? { commit } : {},
12480
+ addedNodes,
12481
+ removedNodes,
12482
+ changedNodes,
12483
+ addedEdges,
12484
+ removedEdges,
12485
+ changedEdges,
12486
+ ...selectionChanged ? { selection: { before: selBefore, after: selAfter } } : {},
12487
+ inGesture: nextNodes.some((n3) => n3.dragging || n3.resizing),
12488
+ at: now()
12489
+ };
12490
+ listeners.forEach((l) => l(change));
12491
+ return change;
12492
+ };
12493
+ const noteCommit = (event) => {
12494
+ pending = event;
12495
+ };
12496
+ const offHistory = options.history?.onCommit(noteCommit);
12497
+ const offCanvas = options.subscribe?.(() => {
12498
+ check();
12499
+ });
12500
+ return {
12501
+ check,
12502
+ subscribe: (listener) => {
12503
+ listeners.add(listener);
12504
+ return () => {
12505
+ listeners.delete(listener);
12506
+ };
12507
+ },
12508
+ reset: () => {
12509
+ nodes = options.getNodes();
12510
+ edges = options.getEdges();
12511
+ pending = void 0;
12512
+ },
12513
+ noteCommit,
12514
+ dispose: () => {
12515
+ offHistory?.();
12516
+ offCanvas?.();
12517
+ listeners.clear();
12518
+ }
12519
+ };
12520
+ }
12521
+
12522
+ // src/canvas/proposal-tools.ts
12523
+ var READ2 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
12524
+ var WRITE = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
12525
+ var labelOf2 = (node) => {
12526
+ const label = node.data?.label ?? node.data?.name ?? node.data?.title;
12527
+ return typeof label === "string" && label !== "" ? label : void 0;
12528
+ };
12529
+ var proposalIdArg = {
12530
+ type: "object",
12531
+ properties: {
12532
+ proposalId: { type: "string", minLength: 1, description: "Id of a pending proposal, from propose_nodes or list_proposals." }
12533
+ },
12534
+ required: ["proposalId"],
12535
+ additionalProperties: false
12536
+ };
12537
+ function createCanvasProposalToolProvider(proposals, options = {}) {
12538
+ const readOnlyReason = () => {
12539
+ const ro = typeof options.readOnly === "function" ? options.readOnly() : options.readOnly;
12540
+ return ro ? typeof ro === "string" ? ro : "The canvas is read-only: proposals can be made and rejected but not accepted." : null;
12541
+ };
12542
+ const describe = (p) => ({
12543
+ id: p.id,
12544
+ title: p.title,
12545
+ ...p.rationale ? { rationale: p.rationale } : {},
12546
+ origin: p.origin,
12547
+ nodes: p.nodes.map((n3) => ({ id: n3.id, ...labelOf2(n3) ? { label: labelOf2(n3) } : {}, position: n3.position })),
12548
+ edges: p.edges.map((e) => ({ id: e.id, source: e.source, target: e.target })),
12549
+ anchors: p.anchors,
12550
+ missing: proposals.missing(p.id),
12551
+ createdAt: new Date(p.createdAt).toISOString()
12552
+ });
12553
+ const proposeTool = {
12554
+ name: "propose_nodes",
12555
+ title: "Propose nodes",
12556
+ description: "Suggests nodes and edges to add to the canvas without adding them: they appear as ghosts that the user accepts or dismisses, so use it for contributions the user did not ask for. A node with nearNodeId is placed beside that node and connected from it; others go in free space. Returns the proposal id, the planned node ids and positions, the edge ids and the canvas nodes it builds on (anchors). Follow with accept_proposal only when the user asked for it; otherwise leave the choice to them.",
12557
+ inputSchema: {
12558
+ type: "object",
12559
+ properties: {
12560
+ title: { type: "string", minLength: 1, description: 'What the suggestion adds, in a few words, e.g. "Caption for the hero image". Becomes the undo step name when accepted.' },
12561
+ rationale: { type: "string", description: "Why it fits what the user is doing, in one sentence. Shown to the user beside the ghost." },
12562
+ nodes: {
12563
+ type: "array",
12564
+ description: "Nodes to suggest, in order; a later node may sit beside an earlier one. Default none.",
12565
+ items: {
12566
+ type: "object",
12567
+ properties: {
12568
+ id: { type: "string", description: "Id for the new node (default generated). Must not be in use." },
12569
+ type: { type: "string", description: "Node type as the canvas renders it (default the canvas default)." },
12570
+ data: { type: "object", description: 'Node data, e.g. { "label": "Caption" }. Default {}.' },
12571
+ position: {
12572
+ type: "object",
12573
+ description: "Top-left corner in canvas coordinates (pixels). Default: placed beside nearNodeId or in free space in view.",
12574
+ properties: { x: { type: "number", description: "Canvas x in pixels." }, y: { type: "number", description: "Canvas y in pixels." } },
12575
+ required: ["x", "y"],
12576
+ additionalProperties: false
12577
+ },
12578
+ width: { type: "number", exclusiveMinimum: 0, description: "Width in pixels, for placement (default 200)." },
12579
+ height: { type: "number", exclusiveMinimum: 0, description: "Height in pixels, for placement (default 60)." },
12580
+ nearNodeId: { type: "string", description: "Id of a canvas node, or an earlier node of this proposal, to place it beside and connect from." },
12581
+ side: { type: "string", enum: ["right", "below", "left", "above", "top", "bottom"], description: "Side of nearNodeId to place it on (default right)." }
12582
+ },
12583
+ additionalProperties: false
12584
+ }
12585
+ },
12586
+ edges: {
12587
+ type: "array",
12588
+ description: "Extra edges, between nodes of this proposal or canvas nodes. Default none.",
12589
+ items: {
12590
+ type: "object",
12591
+ properties: {
12592
+ id: { type: "string", description: "Id for the edge (default generated)." },
12593
+ source: { type: "string", description: "Id of the source node (canvas or this proposal)." },
12594
+ target: { type: "string", description: "Id of the target node (canvas or this proposal)." },
12595
+ label: { type: "string", description: "Edge label. Default none." }
12596
+ },
12597
+ required: ["source", "target"],
12598
+ additionalProperties: false
12599
+ }
12600
+ }
12601
+ },
12602
+ required: ["title"],
12603
+ additionalProperties: false
12604
+ },
12605
+ annotations: { title: "Propose nodes", ...WRITE },
12606
+ handler: (args, context) => {
12607
+ const origin = context.actor?.id ? `agent:${context.actor.id}` : options.fallbackOrigin;
12608
+ const proposal = proposals.propose({ title: args.title, rationale: args.rationale, nodes: args.nodes, edges: args.edges, ...origin ? { origin } : {} });
12609
+ const { id: _id, missing: _missing, createdAt: _createdAt, ...rest } = describe(proposal);
12610
+ return { proposalId: proposal.id, ...rest };
12611
+ }
12612
+ };
12613
+ const listTool = {
12614
+ name: "list_proposals",
12615
+ title: "List proposals",
12616
+ description: "Lists the pending proposals (suggested nodes and edges not yet on the canvas): id, title, rationale, who proposed it, its nodes and edges, the canvas nodes it builds on, any of those since removed (missing: it can no longer be accepted), and whether accepting is allowed. Call before accept_proposal or reject_proposal.",
12617
+ inputSchema: { type: "object", properties: {}, additionalProperties: false },
12618
+ annotations: { title: "List proposals", ...READ2 },
12619
+ handler: () => ({ proposals: proposals.getState().proposals.map(describe), readOnly: readOnlyReason() })
12620
+ };
12621
+ const acceptTool = {
12622
+ name: "accept_proposal",
12623
+ title: "Accept a proposal",
12624
+ description: "Adds a pending proposal to the canvas as one undo step, recorded as made by whoever proposed it, and drops it from the pending list. Refuses, changing nothing, when the canvas is read-only or a node the proposal builds on was removed. Returns the added node and edge ids and the undo step name.",
12625
+ inputSchema: proposalIdArg,
12626
+ annotations: { title: "Accept a proposal", ...WRITE },
12627
+ handler: (args) => {
12628
+ const reason = readOnlyReason();
12629
+ if (reason) throw new Error(reason);
12630
+ return proposals.accept(args.proposalId);
12631
+ }
12632
+ };
12633
+ const rejectTool = {
12634
+ name: "reject_proposal",
12635
+ title: "Reject a proposal",
12636
+ description: "Dismisses a pending proposal: its ghosts disappear and the canvas and its history are unchanged. Use it to withdraw a suggestion that no longer fits. Returns the dismissed proposal id and title.",
12637
+ inputSchema: proposalIdArg,
12638
+ annotations: { title: "Reject a proposal", ...WRITE },
12639
+ handler: (args) => {
12640
+ const proposal = proposals.reject(args.proposalId);
12641
+ return { proposalId: proposal.id, title: proposal.title, rejected: true };
12642
+ }
12643
+ };
12644
+ return {
12645
+ id: options.id ?? "canvas-proposals",
12646
+ ...options.namespace !== void 0 ? { namespace: options.namespace } : {},
12647
+ title: "Canvas proposals",
12648
+ description: "Suggest canvas additions as ghosts the user accepts or dismisses, and accept or reject pending suggestions.",
12649
+ skill: "pixerate-canvas",
12650
+ tools: [proposeTool, listTool, acceptTool, rejectTool]
12651
+ };
12652
+ }
12201
12653
  export {
12202
12654
  ANIMATABLE_PROPERTIES,
12203
12655
  ANIMATION_DATA_KEY,
@@ -12215,6 +12667,7 @@ export {
12215
12667
  CANVAS_EFFECT_MISSING_PATTERN,
12216
12668
  CANVAS_EFFECT_PLACES,
12217
12669
  CANVAS_GRADIENT_PRESETS,
12670
+ CANVAS_PROPOSAL_CLASS,
12218
12671
  CANVAS_TOKEN_PROPERTIES,
12219
12672
  CARD_INSPECTION_ZONES,
12220
12673
  CHILD_LAYOUT_DATA_KEY,
@@ -12338,6 +12791,7 @@ export {
12338
12791
  createCanvasAutoLayoutController,
12339
12792
  createCanvasCaptureSurface,
12340
12793
  createCanvasCaptureToolProvider,
12794
+ createCanvasChangeFeed,
12341
12795
  createCanvasComponent,
12342
12796
  createCanvasComponentsController,
12343
12797
  createCanvasDrawController,
@@ -12349,6 +12803,8 @@ export {
12349
12803
  createCanvasGestureRecorder,
12350
12804
  createCanvasInstance,
12351
12805
  createCanvasPlaybackLocator,
12806
+ createCanvasProposalToolProvider,
12807
+ createCanvasProposals,
12352
12808
  createCanvasScenesStore,
12353
12809
  createDefaultStrokeStyle,
12354
12810
  createFanOutTrajectory,