@pixerate/editor 0.139.1 → 0.140.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 (120) hide show
  1. package/README.md +25 -4
  2. package/dist/agent/formatTools.d.cts +15 -0
  3. package/dist/agent/formatTools.d.ts +15 -0
  4. package/dist/agent/index.cjs +397 -46
  5. package/dist/agent/index.js +365 -14
  6. package/dist/agent/providers.d.cts +5 -3
  7. package/dist/agent/providers.d.ts +5 -3
  8. package/dist/animation-editor/effect-tools.d.cts +1 -1
  9. package/dist/animation-editor/effect-tools.d.ts +1 -1
  10. package/dist/animation-editor/index.cjs +250 -116
  11. package/dist/animation-editor/index.js +228 -94
  12. package/dist/animation-editor/instructions.d.cts +1 -1
  13. package/dist/animation-editor/instructions.d.ts +1 -1
  14. package/dist/animation-editor/parse.d.cts +3 -1
  15. package/dist/animation-editor/parse.d.ts +3 -1
  16. package/dist/animation-editor/tools.d.cts +8 -3
  17. package/dist/animation-editor/tools.d.ts +8 -3
  18. package/dist/bridge/cli.cjs +3 -3
  19. package/dist/bridge/cli.js +2 -2
  20. package/dist/bridge/index.cjs +7 -3
  21. package/dist/bridge/index.d.cts +7 -0
  22. package/dist/bridge/index.d.ts +7 -0
  23. package/dist/bridge/index.js +8 -4
  24. package/dist/bridge/skills.d.cts +9 -0
  25. package/dist/bridge/skills.d.ts +9 -0
  26. package/dist/canvas/effect-tools.d.cts +1 -1
  27. package/dist/canvas/effect-tools.d.ts +1 -1
  28. package/dist/canvas/index.cjs +22 -17
  29. package/dist/canvas/index.js +8 -3
  30. package/dist/chart/file-tools.d.cts +1 -1
  31. package/dist/chart/file-tools.d.ts +1 -1
  32. package/dist/chart/index.cjs +7 -1
  33. package/dist/chart/index.js +7 -1
  34. package/dist/chart/tools.d.cts +1 -1
  35. package/dist/chart/tools.d.ts +1 -1
  36. package/dist/{chunk-BKMU3V6K.js → chunk-5ED73EC6.js} +8 -1
  37. package/dist/{chunk-VRIR53SW.js → chunk-5G3KYRER.js} +2 -1
  38. package/dist/{chunk-KHMVB3SJ.js → chunk-7KWJEYIK.js} +4 -1
  39. package/dist/{chunk-R47NQICB.cjs → chunk-HDCH35UM.cjs} +47 -10
  40. package/dist/{chunk-6NCBFBXA.js → chunk-IQ6KKXOU.js} +1 -1
  41. package/dist/{chunk-PCNCT4ZY.js → chunk-KIBEEN5K.js} +40 -3
  42. package/dist/{chunk-CZRWP6IW.cjs → chunk-N2FGYZ4Q.cjs} +8 -1
  43. package/dist/{chunk-T6Y5FV7G.cjs → chunk-RPW7YL3D.cjs} +2 -1
  44. package/dist/{chunk-3V746PF4.cjs → chunk-RUZQMYXH.cjs} +4 -1
  45. package/dist/{chunk-GUPQ5BNA.cjs → chunk-RWML7TWG.cjs} +44 -44
  46. package/dist/{chunk-HGHXGCKG.cjs → chunk-SVFEVKLF.cjs} +1 -1
  47. package/dist/{chunk-PQMADRCI.js → chunk-UOJS6PUP.js} +1 -1
  48. package/dist/{chunk-BWT4IWLK.cjs → chunk-VKF3PWKR.cjs} +7 -7
  49. package/dist/chunk-WBKLYLZE.js +1156 -0
  50. package/dist/{chunk-TBSPPVTT.js → chunk-XCK7QK5D.js} +1 -1
  51. package/dist/chunk-ZAOOIJ6I.cjs +1156 -0
  52. package/dist/commands/agentTools.d.cts +1 -1
  53. package/dist/commands/agentTools.d.ts +1 -1
  54. package/dist/commands/index.cjs +3 -0
  55. package/dist/commands/index.js +3 -0
  56. package/dist/diagram/index.cjs +3 -0
  57. package/dist/diagram/index.js +3 -0
  58. package/dist/diagram/tools.d.cts +1 -1
  59. package/dist/diagram/tools.d.ts +1 -1
  60. package/dist/effects/index.cjs +32 -32
  61. package/dist/effects/index.js +1 -1
  62. package/dist/effects/tools.d.cts +5 -1
  63. package/dist/effects/tools.d.ts +5 -1
  64. package/dist/extensions/index.cjs +3 -3
  65. package/dist/extensions/index.js +2 -2
  66. package/dist/generation/index.cjs +7 -1
  67. package/dist/generation/index.js +7 -1
  68. package/dist/image-editor/index.cjs +21 -15
  69. package/dist/image-editor/index.js +8 -2
  70. package/dist/image-editor/provider-effect-tools.d.cts +1 -1
  71. package/dist/image-editor/provider-effect-tools.d.ts +1 -1
  72. package/dist/image-editor/tools.d.cts +1 -1
  73. package/dist/image-editor/tools.d.ts +1 -1
  74. package/dist/index.cjs +8 -8
  75. package/dist/index.js +2 -2
  76. package/dist/paint-editor/effect-tools.d.cts +1 -1
  77. package/dist/paint-editor/effect-tools.d.ts +1 -1
  78. package/dist/paint-editor/index.cjs +18 -8
  79. package/dist/paint-editor/index.js +13 -3
  80. package/dist/paint-editor/tools.d.cts +1 -1
  81. package/dist/paint-editor/tools.d.ts +1 -1
  82. package/dist/tools/bridge-client.d.cts +3 -3
  83. package/dist/tools/bridge-client.d.ts +3 -3
  84. package/dist/tools/capture.d.cts +5 -1
  85. package/dist/tools/capture.d.ts +5 -1
  86. package/dist/tools/definitions.d.cts +2 -2
  87. package/dist/tools/definitions.d.ts +2 -2
  88. package/dist/tools/index.cjs +31 -5
  89. package/dist/tools/index.d.cts +3 -0
  90. package/dist/tools/index.d.ts +3 -0
  91. package/dist/tools/index.js +31 -5
  92. package/dist/tools/mcp-server.d.cts +24 -6
  93. package/dist/tools/mcp-server.d.ts +24 -6
  94. package/dist/tools/registry.d.cts +81 -6
  95. package/dist/tools/registry.d.ts +81 -6
  96. package/dist/tools/search.d.cts +30 -0
  97. package/dist/tools/search.d.ts +30 -0
  98. package/dist/tools/skills.d.cts +26 -0
  99. package/dist/tools/skills.d.ts +26 -0
  100. package/dist/tools/view.d.cts +95 -0
  101. package/dist/tools/view.d.ts +95 -0
  102. package/dist/vector/effect-tools.d.cts +1 -1
  103. package/dist/vector/effect-tools.d.ts +1 -1
  104. package/dist/vector/index.cjs +13 -7
  105. package/dist/vector/index.js +8 -2
  106. package/dist/video-editor/effect-tools.d.cts +1 -1
  107. package/dist/video-editor/effect-tools.d.ts +1 -1
  108. package/dist/video-editor/index.cjs +275 -269
  109. package/dist/video-editor/index.js +8 -2
  110. package/dist/video-editor/tools.d.cts +1 -1
  111. package/dist/video-editor/tools.d.ts +1 -1
  112. package/package.json +4 -2
  113. package/skills/README.md +8 -3
  114. package/skills/pixerate-agent-tools/SKILL.md +33 -7
  115. package/skills/pixerate-animation-editor/SKILL.md +7 -0
  116. package/skills/pixerate-rich-text/SKILL.md +18 -4
  117. package/dist/chunk-5RRYDFU2.js +0 -466
  118. package/dist/chunk-SPVIXXIB.cjs +0 -466
  119. /package/dist/{chunk-SMJK5HBJ.js → chunk-MCTQXUXR.js} +0 -0
  120. /package/dist/{chunk-DDF6WQ62.cjs → chunk-R6DFK5OX.cjs} +0 -0
@@ -134,7 +134,7 @@ import {
134
134
  videoTransitionEase,
135
135
  videoValueAt,
136
136
  videoWipeRect
137
- } from "../chunk-6NCBFBXA.js";
137
+ } from "../chunk-IQ6KKXOU.js";
138
138
  import "../chunk-EHLOCVWB.js";
139
139
  import {
140
140
  namedWithSuggestion
@@ -143,7 +143,7 @@ import {
143
143
  EffectsSlot,
144
144
  createEffectToolProvider,
145
145
  isEffectError
146
- } from "../chunk-KHMVB3SJ.js";
146
+ } from "../chunk-7KWJEYIK.js";
147
147
  import "../chunk-V2ZCJRDM.js";
148
148
  import {
149
149
  HistoryManager
@@ -4621,6 +4621,9 @@ function createVideoEditorToolProvider(controller, options = {}) {
4621
4621
  return {
4622
4622
  id: options.id ?? "video",
4623
4623
  namespace: options.namespace,
4624
+ title: "Video editor",
4625
+ description: "Non-linear video editing: assets, tracks and clips, trims, ripples and gaps, transitions and speed, grading and LUTs, keyframes, audio, transcripts, markers, and EDL or ffmpeg export.",
4626
+ skill: "pixerate-video-editor",
4624
4627
  tools: () => readOnlyReason() ? reads : [...reads, ...writes],
4625
4628
  subscribe: (notify) => {
4626
4629
  let last = readOnlyReason();
@@ -4683,6 +4686,9 @@ function createVideoEffectsToolProvider(controller, options = {}) {
4683
4686
  return createEffectToolProvider({
4684
4687
  id: options.id ?? "video-effects",
4685
4688
  namespace: options.namespace,
4689
+ title: "Video effects",
4690
+ description: "Provider effects on video clips, effect clips and effect transitions.",
4691
+ skill: "pixerate-video-editor",
4686
4692
  target: { noun: "clip", id: 'A clip id from get_video_project (e.g. "c1").' },
4687
4693
  applyUses: ["filter", "overlay"],
4688
4694
  applyDetails: "Filters change the clip's picture and overlays draw over it, in stack order, on the picture as it comes from the source, before the clip's grade, placement, opacity and blend; numbers may be keyframed (clip-relative ms). Transitions go through set_video_effect_transition and generators or titles through add_video_effect_clip. The preview renders them frame by frame; the ffmpeg export then needs rendered frames (see export_video_ffmpeg).",
@@ -6,7 +6,7 @@ import { type VideoProject, type VideoSequence } from './types.cjs';
6
6
  export interface VideoEditorToolProviderOptions {
7
7
  /** Provider id (unique per registry). Default `video`. */
8
8
  id?: string;
9
- /** Always prefix tool names with `<namespace>__`. */
9
+ /** Tool-name prefix (`<namespace>__<name>`); defaults to the provider id, `''` for bare names. */
10
10
  namespace?: string;
11
11
  /** The project cannot be edited: write tools are hidden and `get_video_project` says why. A string is the reason. */
12
12
  readOnly?: boolean | string | (() => boolean | string);
@@ -6,7 +6,7 @@ import { type VideoProject, type VideoSequence } from './types.js';
6
6
  export interface VideoEditorToolProviderOptions {
7
7
  /** Provider id (unique per registry). Default `video`. */
8
8
  id?: string;
9
- /** Always prefix tool names with `<namespace>__`. */
9
+ /** Tool-name prefix (`<namespace>__<name>`); defaults to the provider id, `''` for bare names. */
10
10
  namespace?: string;
11
11
  /** The project cannot be edited: write tools are hidden and `get_video_project` says why. A string is the reason. */
12
12
  readOnly?: boolean | string | (() => boolean | string);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pixerate/editor",
3
- "version": "0.139.1",
3
+ "version": "0.140.0",
4
4
  "description": "UI-agnostic rich text and media editing core library",
5
5
  "author": "Pixerate",
6
6
  "license": "MIT",
@@ -341,6 +341,7 @@
341
341
  "prosemirror-markdown": "^1.13.8"
342
342
  },
343
343
  "devDependencies": {
344
+ "@anthropic-ai/sdk": "0.137.0",
344
345
  "@dagrejs/dagre": "^1.1.8",
345
346
  "@tiptap/core": "^2.11.5",
346
347
  "@tiptap/pm": "^2.11.5",
@@ -370,6 +371,7 @@
370
371
  "typecheck": "tsc --noEmit",
371
372
  "test": "vitest run",
372
373
  "test:corpus": "node scripts/fetch-psd-corpus.mjs && PSD_CORPUS=1 vitest run tests/psd-corpus.test.ts",
373
- "build:wasm": "node scripts/build-wet-wasm.mjs"
374
+ "build:wasm": "node scripts/build-wet-wasm.mjs",
375
+ "eval:tools": "vitest run --config vitest.eval.config.ts --disableConsoleIntercept"
374
376
  }
375
377
  }
package/skills/README.md CHANGED
@@ -7,7 +7,7 @@ that uses the tools can load the matching skill.
7
7
 
8
8
  | Skill | Covers |
9
9
  | --- | --- |
10
- | [`pixerate-agent-tools`](pixerate-agent-tools/SKILL.md) | What every editor has in common: the MCP bridge, tool naming and namespaces, `list_commands` / `run_command` / `run_commands`, errors, undo. Load it with any domain skill. |
10
+ | [`pixerate-agent-tools`](pixerate-agent-tools/SKILL.md) | What every editor has in common: the MCP bridge, toolsets and tool naming, finding tools with `list_toolsets` / `search_tools` / `enable_tools` / `get_skill`, `list_commands` / `run_command` / `run_commands`, errors, undo. Load it with any domain skill. |
11
11
  | [`pixerate-rich-text`](pixerate-rich-text/SKILL.md) | Documents and prompts: text, tables, find and replace, charts in documents, prompt variables. |
12
12
  | [`pixerate-spreadsheet`](pixerate-spreadsheet/SKILL.md) | Cells, ranges, rows and columns, filters, merges. |
13
13
  | [`pixerate-canvas`](pixerate-canvas/SKILL.md) | Node-graph canvas, components and variants, arranging, shape booleans, keyframe animation. |
@@ -29,8 +29,13 @@ Copy or symlink the directories into your agent's skills folder, for example for
29
29
  cp -R node_modules/@pixerate/editor/skills/* .claude/skills/
30
30
  ```
31
31
 
32
- Skills use bare tool names (`get_chart`). A host that namespaces providers exposes them as
33
- `<namespace>__get_chart`.
32
+ Skills use bare tool names (`get_chart`). Registries expose them as `<toolset>__get_chart`
33
+ (the provider's namespace, or its id), and accept the bare name when only one toolset has it.
34
+
35
+ They can also be served rather than copied: the MCP bridge (`pixerate-mcp-bridge`) serves them as
36
+ MCP prompts and `skill://<name>/SKILL.md` resources, `createMcpServer(source, { skills })` does
37
+ the same for your own server, and a discovery view (`registry.view({ discovery: { skills } })`)
38
+ adds a `get_skill` tool. In Node, `loadSkillFiles()` from `@pixerate/editor/bridge` reads them.
34
39
 
35
40
  ## Maintaining them
36
41
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: pixerate-agent-tools
3
- description: How to drive any Pixerate editor (rich text, spreadsheet, canvas, vector, chart, diagram, image, animation, video, generation) through its agent tools - finding the right editor over the MCP bridge, reading tool names and namespaces, running editor commands with list_commands / run_command / run_commands, batching with result references, undo, and recovering from tool errors. Use whenever Pixerate editor tools are available, before the domain skill for the editor at hand.
3
+ description: How to drive any Pixerate editor (rich text, spreadsheet, canvas, vector, chart, diagram, image, animation, video, generation) through its agent tools - finding the right editor over the MCP bridge, reading toolset-namespaced tool names, finding tools in a large catalogue with list_toolsets / search_tools / enable_tools and reading a toolset's skill with get_skill, running editor commands with list_commands / run_command / run_commands, batching with result references, undo, and recovering from tool errors. Use whenever Pixerate editor tools are available, before the domain skill for the editor at hand.
4
4
  ---
5
5
 
6
6
  # Driving Pixerate editors with agent tools
@@ -15,16 +15,35 @@ editor domain has its own skill for its tools: `pixerate-rich-text`, `pixerate-s
15
15
 
16
16
  ## How tools are named
17
17
 
18
- - Tool names are `snake_case` verbs on a noun: `get_*` / `list_*` / `find_*` / `render_*` read,
19
- everything else writes.
20
- - When several editors register a tool with the same name, or a host gives a provider a
21
- namespace, the name is prefixed: `chart__get_chart`, `doc-1__find_text`. Skills use the bare
22
- name; match on the suffix after `__`.
18
+ - Tools come in toolsets, one per open editor or feature (`chart`, `video`, `image-editor`,
19
+ `doc-1`), and are named `<toolset>__<tool>`: `chart__get_chart`, `doc-1__find_text`. Skills use
20
+ the bare name; match on the part after `__`.
21
+ - The tool part is a `snake_case` verb on a noun: `get_*` / `list_*` / `find_*` / `render_*`
22
+ read, everything else writes.
23
+ - A bare name (`get_chart`) also works when only one toolset has that tool. When several do (two
24
+ documents open), the error names each full name: pick the one for the editor you mean.
23
25
  - The annotations are reliable: `readOnlyHint: true` never changes anything, `destructiveHint:
24
26
  true` removes content, `idempotentHint: true` is safe to retry.
25
27
  - The tool list changes while you work (an editor mounts, a chart becomes read-only and its
26
28
  write tools disappear). If a tool you used before is gone, list tools again rather than guess.
27
29
 
30
+ ## Finding the right tool
31
+
32
+ A host with many editors open can have hundreds of tools. It may list them all, only the open
33
+ editor's, or (in discovery mode) only `list_toolsets`, `search_tools`, `enable_tools`,
34
+ `disable_tools` and `get_skill` at first.
35
+
36
+ 1. **Know what is open.** `list_toolsets` gives each toolset's title, what it covers, its skill
37
+ and whether its tools are in your list.
38
+ 2. **Search by task, not by guessing names.** `search_tools` with a few plain words ("add a
39
+ trendline", "remove silences") returns the best matches with a one-line summary. Pass
40
+ `toolset` to search one editor.
41
+ 3. **Enable only what you need.** `enable_tools` with the tool names from the search (or a whole
42
+ toolset when you will use many of its tools). The tools then appear in your list. Use
43
+ `disable_tools` to drop a toolset you are done with.
44
+ 4. **Read the skill before working in a toolset.** `get_skill` with the skill `list_toolsets`
45
+ names (or the MCP prompt / `skill://` resource of the same name).
46
+
28
47
  ## Working method
29
48
 
30
49
  1. **Read before you write.** Start with the domain's `get_*` tool. Write tools take the ids,
@@ -51,7 +70,9 @@ it, with `structuredContent.error.code`:
51
70
  Fix the arguments and call again.
52
71
  - `tool_failed`: the editor refused the change (unknown id, out-of-range position, read-only
53
72
  target). Nothing was applied. Read the state again, then retry with valid input.
54
- - `unknown_tool`: the tool is not registered now (the editor closed, or it is read-only).
73
+ - `unknown_tool`: the tool is not registered now (the editor closed, or it is read-only), a
74
+ bare name matches several toolsets (use a full name from the message), or this agent may not
75
+ use that toolset or write at all (the message says which).
55
76
 
56
77
  Never repeat an identical failing call. Never work around a read-only refusal; tell the user.
57
78
 
@@ -60,6 +81,11 @@ Never repeat an identical failing call. Never work around a read-only refusal; t
60
81
  | Tool | Use it to |
61
82
  | --- | --- |
62
83
  | `list_editors` | See which editors are open in the browser and connected to the MCP bridge (id, name, kind, tool count, last activity). Call it first when tools come through the bridge; pass an id or part of a name as `editor` to any tool to pick one when several are open, otherwise the most recently active editor with that tool answers. If none is connected, ask the user to open the app and connect it. |
84
+ | `list_toolsets` | See the toolsets open now: name, title, what each covers, its skill, how many tools it has and whether they are in your tool list (`enabled`: all, some, none). Call it first in a discovery view, then `search_tools` or `enable_tools`. |
85
+ | `search_tools` | Find the tool for a task: pass `query` in plain words (and `toolset` to search one editor, `limit` for more than 10). Returns the best matches first with name, toolset, title, one-sentence summary, whether it only reads and whether it is listed. Follow with `enable_tools`. |
86
+ | `enable_tools` | Add tools to your tool list by full name (`tools`, from `search_tools`) and/or whole `toolsets` (from `list_toolsets`). Returns the names added and how many are listed. Prefer single tools to large toolsets. Unknown names fail and change nothing. Allowed tools can also be called by name without enabling them. |
87
+ | `disable_tools` | Drop tools or whole toolsets you are done with from your tool list, to keep it short. Returns the names removed. |
88
+ | `get_skill` | Read a toolset's skill (markdown) before working with it; pass `file` for one of its reference files (listed at the top). The note at the top says how names are prefixed here. |
63
89
  | `list_commands` | Discover the commands an editor registers: id, label, group, params JSON Schema, shortcuts, and whether each is enabled now (with the reason when it is not). Filter with `query`; pass `enabledOnly: true` to see only what you can run now. |
64
90
  | `run_command` | Run one command by `id` with `params` matching its schema. Disabled commands and unknown params fail with a reason; read it before retrying. |
65
91
  | `run_commands` | Run several commands in order as `steps`. A param string `"$0.id"` or `"$last.id"` is replaced by that path of an earlier step's result, so a step can use an id an earlier step created. Pass `atomic: true` and a `label` to make the batch one undo step that rolls back entirely on failure; without it, steps before a failure stay applied. |
@@ -34,6 +34,8 @@ The full command vocabulary (every type, option and default) is in
34
34
  edits as one undo step (`dry_run: true` first when unsure; `"$0.indexes[0]"` and
35
35
  `"$last.shot"` refer to earlier ops). Refine with `add_commands`, `update_command`,
36
36
  `move_command`, `delete_commands`. Use `write_animation` only to replace every shot.
37
+ For a command type you have not written before, `describe_animation_command` returns its
38
+ exact fields first.
37
39
  4. **Fit and cue.** `fit_animation` to hit a length (keep shots whose pace matters). For music
38
40
  or voiceover, `set_animation_settings` with `beat` or `narration`, read cues with
39
41
  `get_timing_grid`, and give shots `"at": { "beat": n }` or `{ "word": i }`.
@@ -88,6 +90,7 @@ The full command vocabulary (every type, option and default) is in
88
90
  | --- | --- |
89
91
  | `get_animation` | Start here. Returns name, artwork size, length (ms), loop, elements (id, type, name, parent, bounds, solid paints, live effects with numeric params), every shot with each command's index, start, end and `flairPrimitive`, clips, drivers, controls and an issue summary, plus `readOnly` when edits are refused. `includeElements: false` (default true) skips the element list on large artwork. |
90
92
  | `get_shot` | Read one shot as stored (`shot` id) with its start/end and each command's start/end in ms; cheaper than `get_animation` while refining one shot. |
93
+ | `describe_animation_command` | Before writing a command type you have not used yet, or when a write rejects a field: returns the full JSON Schema of each of `types` (e.g. `["enter", "move"]`), with every field's type, range, default and meaning and which are required. The write tools list every command field once in short, prefixed with the types that take it. |
91
94
  | `find_animation_elements` | Find elements whose id or name contains `query` (case-insensitive; `limit` default 20, max 200) when the artwork is large. Returns id, type, name, parent, bounds, paints, effects. |
92
95
  | `get_text_layout` | Before animating outlined text with `split`: returns the `group`'s lines, words and letter ids in reading order. Errors if the element is not a group of paths (convert text to outlines, one path a letter, and group it). |
93
96
  | `get_motion_path` | Check spacing, arcs and landing points as numbers: samples a `node`'s centre (document units) from `from` to `to` ms every `step` ms (default 33, at most 400 samples), with where each moving change starts and ends. |
@@ -150,6 +153,10 @@ refuse.
150
153
  - **Some provider motion cannot be carried over.** Counting, writing text and similar changes are
151
154
  skipped. The result's `notes` say what was left out.
152
155
 
156
+ - **Fields belong to types.** The write tools' command schema lists every field of every type
157
+ once; a field the type does not take (`clip` on a `move`, `to` as a point on a `fade`) is
158
+ refused when the edit is applied, naming the shot, command and field. Call
159
+ `describe_animation_command` for the exact fields of a type rather than guessing.
153
160
  - **Unknown ids are refused** with a "did you mean" suggestion. Take ids from `get_animation` or
154
161
  the elements `set_animation_artwork_svg` returns; never guess them.
155
162
  - **`enter-visible`**: an element that enters while already showing blinks out first. Give an
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: pixerate-rich-text
3
- description: How to read and edit Pixerate rich text documents and prompt editors through agent tools - reading text with document positions (get_text, find_text), minimal-diff edits (replace_range, replace_text, insert_text), selections, tables (edit_table and table.* commands), charts and sparklines embedded in a document, find and replace commands, and prompt editing with templates, variables and instructions (prompt_insert_text, prompt_replace_range, prompt_set_variable, get_editor_state, view_editor). Use when asked to write, rewrite, proofread, restructure or format a document, report, note, heading, paragraph or table, to insert a chart or sparkline into text, or to edit an image-generation or LLM prompt with {{template}}, {variable} and __instruction__ tokens.
3
+ description: How to read and edit Pixerate rich text documents and prompt editors through agent tools - reading text with document positions (get_text, find_text), minimal-diff edits (replace_range, replace_text, insert_text), formatting (format_text for bold, italic, links and colour; set_block_type for headings, lists and quotes; set_text_align), selections, tables (edit_table and table.* commands), charts and sparklines embedded in a document, find and replace commands, and prompt editing with templates, variables and instructions (prompt_insert_text, prompt_replace_range, prompt_set_variable, get_editor_state, view_editor). Use when asked to write, rewrite, proofread, restructure or format a document, report, note, heading, paragraph or table, to insert a chart or sparkline into text, or to edit an image-generation or LLM prompt with {{template}}, {variable} and __instruction__ tokens.
4
4
  ---
5
5
 
6
6
  # Editing rich text documents and prompts
@@ -35,7 +35,11 @@ Errors, namespacing (`doc-1__find_text`) and `run_commands` batching are covered
35
35
  returned by the write, or call `find_text` again; never reuse positions read before a
36
36
  write that came earlier in the document. When making several position-based edits from
37
37
  one read, apply them from the end of the document backwards.
38
- 5. **Check.** `get_text` again (or `find_text` for the new wording) and confirm the result.
38
+ 5. **Format.** Write the words first, then format them: `find_text` (or the write's `range`)
39
+ gives the positions for `format_text` (bold, italic, links, colour...), `set_block_type`
40
+ (headings, lists, quotes, code blocks) and `set_text_align`. Never type markdown such as
41
+ `**bold**` or `# Heading`; it is inserted as those characters.
42
+ 6. **Check.** `get_text` again (or `find_text` for the new wording) and confirm the result.
39
43
  For a prompt, `view_editor` shows how tokens render when layout matters.
40
44
 
41
45
  ## Best practices
@@ -89,6 +93,9 @@ Errors, namespacing (`doc-1__find_text`) and `run_commands` batching are covered
89
93
  | `replace_text` | Find and replace a phrase in one undo step, keeping the found text's formatting. Replaces all matches unless `occurrence` (1-based) is given. Same `matchCase` / `wholeWord` / `regex` flags as `find_text`. Fails when nothing matches. Returns `{replaced, total, ranges}`. |
90
94
  | `insert_text` | Insert literal `text` at `at` (a document position) or at the cursor. Returns the inserted `range`. Use for new sentences or paragraphs; position from `get_text {blocks: true}` (a block's `to` appends to it). |
91
95
  | `replace_selection` | Replace the current selection with literal text (empty string deletes). Use after `set_selection`, or when the user asks to change what they selected. |
96
+ | `format_text` | Set or clear inline formatting on `from`..`to` (or the selection when both are omitted): `bold`, `italic`, `underline`, `strike`, `code` (true sets, false clears), `link` (a URL, or null to remove), `highlight` and `color` (CSS colours, or null), `fontSize` (e.g. `"18px"`, or null). Only the properties you pass change; the schema decides which exist. One undo step; the user's selection stays put. Returns the `range`, its `text` and the `formatting` now on it (`partly` / `mixed` where only some of the text has it). Position from `find_text`. |
97
+ | `set_block_type` | Make every block the range touches (or the one at the cursor) a `paragraph`, `heading` (with `level`, 1 to 4 by default), `bullet_list`, `ordered_list`, `task_list`, `blockquote` or `code_block`. Blocks leave any list or quote first, so one call switches a bulleted list to a numbered one; `paragraph` takes them out of lists and quotes. Returns the resulting `blocks` (type, positions, text, level, align, the list or quote they are `in`). |
98
+ | `set_text_align` | Align every paragraph and heading the range touches: `left`, `center`, `right`, `justify`, or null for the default. Returns the `blocks` with their `align`. Table cells are aligned with `edit_table` `setCellAlignment` instead. |
92
99
  | `set_selection` | Select `from`..`to` (or place the cursor when `to` is omitted). Use to show the user a passage, or to aim `edit_table` and the `table.*` commands at a cell. |
93
100
  | `edit_table` | Insert or edit a table. `operation` is one of the `table.*` command names (`insertTable`, `addRowAfter`, `mergeCells`, `setCellAlignment`, ...). `at` moves the cursor first (a position inside a cell). `insertTable` takes `rows` (default 3, max 100), `cols` (default 3, max 50), `withHeaderRow` (default true); `setCellAlignment` takes `align` (left, center, right, justify, null); `setCellBackground` takes `color` (CSS colour or null). Returns the table size and cursor cell. Only present when the schema has tables. |
94
101
  | `insert_chart` | Insert a chart block at `at` (or the cursor; a position inside a paragraph splits it). `spec` needs `categories` and `series` (`[{name, values}]`, one value per category) and takes the chart presentation fields (`type`, `title`, axes, legend, `stacking`, `palette`, ...). `width` px or null to fill the line (default null), `height` px (default 320). Returns id, pos and stored spec. |
@@ -136,10 +143,17 @@ Run with `run_command` / `run_commands` when the host registers them. Check
136
143
  10. Always use positions from `find_text`, `get_text {blocks: true}` or a write's `range`.
137
144
  - **Stale positions.** Every write shifts later positions. Work back to front, or re-read.
138
145
  - **Literal text only.** The text tools insert plain text; markdown such as `**bold**` or
139
- `# Heading` is inserted as those characters. A newline in `text` starts a new paragraph. To create tables use `edit_table`, not pipe characters.
146
+ `# Heading` is inserted as those characters. A newline in `text` starts a new paragraph.
147
+ Format with `format_text` and `set_block_type` after writing; create tables with
148
+ `edit_table`, not pipe characters.
149
+ - **Formatting a heading.** Headings are already bold in most themes; make a phrase a heading
150
+ with `set_block_type`, not with `format_text` `bold` and a bigger `fontSize`.
151
+ - **Inline code.** In most schemas `code: true` removes the other marks on that text, and a
152
+ code block drops all marks.
140
153
  - **Range limits.** `from` after `to`, or a position beyond the document `size`, is a tool
141
154
  error; nothing is applied.
142
- - **Read-only documents** expose only `get_text`, `find_text` and `list_document_charts`. If
155
+ - **Read-only documents** expose only `get_text`, `find_text` and `list_document_charts` (no
156
+ formatting tools). If
143
157
  the write tools are missing, the document is read-only; tell the user rather than working
144
158
  around it. `edit_table` exists only when tables are enabled, the chart tools only when
145
159
  charts are, `insert_sparkline` only when sparklines are.