@pixerate/editor 0.79.0 → 0.81.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 (70) hide show
  1. package/README.md +13 -3
  2. package/dist/agent/index.cjs +102 -6
  3. package/dist/agent/index.cjs.map +1 -1
  4. package/dist/agent/index.d.cts +4 -2
  5. package/dist/agent/index.d.ts +4 -2
  6. package/dist/agent/index.js +101 -5
  7. package/dist/agent/index.js.map +1 -1
  8. package/dist/{builtins-BKYlHH1s.d.ts → builtins-CV1fDj64.d.ts} +5 -1
  9. package/dist/{builtins-1kqwLUnb.d.cts → builtins-c4w0eAYl.d.cts} +5 -1
  10. package/dist/{chunk-2CJ3LPYQ.js → chunk-424H3P4I.js} +13 -295
  11. package/dist/chunk-424H3P4I.js.map +1 -0
  12. package/dist/{chunk-UN33YOXW.cjs → chunk-PA5S7KPC.cjs} +293 -2
  13. package/dist/chunk-PA5S7KPC.cjs.map +1 -0
  14. package/dist/{chunk-IB3ZHQAX.js → chunk-PTYWCFFW.js} +29 -4
  15. package/dist/chunk-PTYWCFFW.js.map +1 -0
  16. package/dist/{chunk-JQ3BB3E6.js → chunk-PXDEFEG2.js} +293 -2
  17. package/dist/chunk-PXDEFEG2.js.map +1 -0
  18. package/dist/{chunk-YU4WQE5M.cjs → chunk-TAPXWP2B.cjs} +95 -377
  19. package/dist/chunk-TAPXWP2B.cjs.map +1 -0
  20. package/dist/{chunk-HXDMZQTD.cjs → chunk-TPOT575P.cjs} +29 -4
  21. package/dist/{chunk-IB3ZHQAX.js.map → chunk-TPOT575P.cjs.map} +1 -1
  22. package/dist/commands/index.cjs +2 -2
  23. package/dist/commands/index.d.cts +1 -1
  24. package/dist/commands/index.d.ts +1 -1
  25. package/dist/commands/index.js +1 -1
  26. package/dist/generation/index.cjs +932 -791
  27. package/dist/generation/index.cjs.map +1 -1
  28. package/dist/generation/index.d.cts +266 -240
  29. package/dist/generation/index.d.ts +266 -240
  30. package/dist/generation/index.js +926 -785
  31. package/dist/generation/index.js.map +1 -1
  32. package/dist/image-editor/index.cjs +266 -2
  33. package/dist/image-editor/index.cjs.map +1 -1
  34. package/dist/image-editor/index.d.cts +12 -1
  35. package/dist/image-editor/index.d.ts +12 -1
  36. package/dist/image-editor/index.js +265 -1
  37. package/dist/image-editor/index.js.map +1 -1
  38. package/dist/index.cjs +3 -3
  39. package/dist/index.cjs.map +1 -1
  40. package/dist/index.js +16 -16
  41. package/dist/spreadsheet/index.cjs +3 -3
  42. package/dist/spreadsheet/index.cjs.map +1 -1
  43. package/dist/spreadsheet/index.js +16 -16
  44. package/dist/video-editor/index.cjs +461 -101
  45. package/dist/video-editor/index.cjs.map +1 -1
  46. package/dist/video-editor/index.d.cts +67 -3
  47. package/dist/video-editor/index.d.ts +67 -3
  48. package/dist/video-editor/index.js +426 -66
  49. package/dist/video-editor/index.js.map +1 -1
  50. package/package.json +3 -1
  51. package/skills/README.md +55 -0
  52. package/skills/pixerate-agent-tools/SKILL.md +75 -0
  53. package/skills/pixerate-animation-editor/SKILL.md +155 -0
  54. package/skills/pixerate-animation-editor/references/commands.md +123 -0
  55. package/skills/pixerate-canvas/SKILL.md +230 -0
  56. package/skills/pixerate-chart/SKILL.md +190 -0
  57. package/skills/pixerate-diagram/SKILL.md +134 -0
  58. package/skills/pixerate-generation/SKILL.md +109 -0
  59. package/skills/pixerate-image-editor/SKILL.md +139 -0
  60. package/skills/pixerate-parameters/SKILL.md +83 -0
  61. package/skills/pixerate-rich-text/SKILL.md +160 -0
  62. package/skills/pixerate-spreadsheet/SKILL.md +146 -0
  63. package/skills/pixerate-vector/SKILL.md +191 -0
  64. package/skills/pixerate-vector/references/commands.md +138 -0
  65. package/skills/pixerate-video-editor/SKILL.md +173 -0
  66. package/dist/chunk-2CJ3LPYQ.js.map +0 -1
  67. package/dist/chunk-HXDMZQTD.cjs.map +0 -1
  68. package/dist/chunk-JQ3BB3E6.js.map +0 -1
  69. package/dist/chunk-UN33YOXW.cjs.map +0 -1
  70. package/dist/chunk-YU4WQE5M.cjs.map +0 -1
@@ -0,0 +1,146 @@
1
+ ---
2
+ name: pixerate-spreadsheet
3
+ description: How to read and edit a Pixerate spreadsheet through agent tools - reading cells and formula results in A1 notation (get_range), writing values and formulas in bulk (set_range, set_cell), inserting and deleting rows and columns with reference shifting, merging, unmerging and transposing ranges, and the spreadsheet.* commands for filters and hidden rows. Covers tidy-data layout, formulas versus values, supported functions (SUM, XLOOKUP, FILTER, LAMBDA and more) and formula errors such as #REF!, #DIV/0! and #SPILL!. Use when asked to fill, clean, restructure, calculate, total or summarise data in a spreadsheet, sheet, grid, table of cells or workbook.
4
+ ---
5
+
6
+ # Editing spreadsheets
7
+
8
+ A spreadsheet is a grid of rows and columns addressed in **A1 notation**: columns are
9
+ letters (`A`, `B`, ..., `AA`), rows are 1-based numbers, a range is `A1:C10`. Each cell has
10
+ **raw input** (what was typed, e.g. `=SUM(B2:B9)` or `1,234`) and a **computed value**
11
+ (`4200`), plus an error code when evaluation fails. There are no cell ids; the address is the
12
+ handle. Typed input is parsed like a spreadsheet app: `1,234`, `$5`, `10%`, `(100)` become
13
+ numbers, `TRUE` becomes a boolean, `3/4/2026` becomes the ISO date `2026-03-04`, and a
14
+ leading `'` forces text.
15
+
16
+ Errors, namespacing and `run_commands` batching are in the `pixerate-agent-tools` skill.
17
+
18
+ ## Working method
19
+
20
+ 1. **Read.** `get_range` on the area you will touch (and its header row). The result gives
21
+ the sheet size (`sheet.rows`, `sheet.columns`), `values`, `raw` and `errors`. Read a
22
+ generous range such as `A1:Z50` when you do not know where the data is; it is clamped to
23
+ the sheet.
24
+ 2. **Plan the layout** before writing: where the header row goes, which columns hold inputs
25
+ and which hold formulas, where totals go.
26
+ 3. **Write in blocks.** One `set_range` per rectangular block (headers plus data, or a whole
27
+ formula column) instead of many `set_cell` calls. It is one undo step, grows the sheet to
28
+ fit, and refuses the whole write if any target cell is read-only.
29
+ 4. **Check.** Every write returns `errors` for the cells it wrote; `get_range` the dependent
30
+ area (totals, lookups) to confirm the computed values. Fix every `#` error before you
31
+ finish.
32
+ 5. **Restructure deliberately.** Use `insert_rows` / `insert_columns` to make room so
33
+ formulas shift with the data; never move data by rewriting it cell by cell.
34
+
35
+ ## Best practices
36
+
37
+ - **Tidy data.** One header row of short, unique, plain-text names. One variable per column,
38
+ one record per row, one data type per column. No blank rows or columns inside a data
39
+ region, no subtotals mixed into the data, no notes in data cells.
40
+ - **Inputs, then calculations, then outputs.** Keep raw inputs in their own cells or columns
41
+ and derive everything else with formulas, so a change to an input flows through. Never
42
+ type a computed number over a formula.
43
+ - **Formulas over pasted values** whenever the result depends on other cells (totals,
44
+ ratios, lookups). Write a literal value only for genuine inputs.
45
+ - **No magic numbers.** Put rates and thresholds in a labelled cell and reference it with an
46
+ absolute reference (`=B2*$F$1`), rather than writing `=B2*0.2`.
47
+ - **Whole-column formulas.** Write a calculated column as one `set_range` with a formula per
48
+ row (`[["=B2*C2"], ["=B3*C3"], ...]`), or use a dynamic array once at the top
49
+ (`=B2:B100*C2:C100`) and leave the cells below it empty for the spill.
50
+ - **Ranges that grow.** Totals over a whole column (`=SUM(B:B)`) or over a range that
51
+ includes a spare row stay correct when rows are appended; put totals above the data or in a
52
+ separate column if you use whole-column references, so the total does not include itself.
53
+ - **Prefer robust lookups.** `XLOOKUP` or `INDEX`/`MATCH` with exact match over `VLOOKUP`
54
+ with a hard-coded column number, which breaks when a column is inserted.
55
+ - **Handle expected errors explicitly** with `IFERROR` / `IFNA` around lookups and divisions,
56
+ and only where an error is expected, so real problems still show.
57
+ - **Keep data regions unmerged.** Merged cells break sorting, filtering, transposing and
58
+ formulas; use them only for titles outside the data.
59
+ - **Consistent types.** Dates as dates (ISO text `2026-03-04` is safe), numbers without
60
+ units in the cell (put the unit in the header: `Revenue (USD)`), percentages either as
61
+ `10%` or `0.1` throughout a column.
62
+
63
+ ## Supported formulas
64
+
65
+ Operators: `+ - * / ^ & = <> < > <= >=`, whole-column (`A:A`) and absolute (`$A$1`)
66
+ references, spill references (`A1#`). Functions, by group:
67
+
68
+ - Math: SUM, PRODUCT, ROUND, ROUNDUP, ROUNDDOWN, INT, ABS, SIGN, SQRT, POWER, MOD, CEILING,
69
+ FLOOR, PI, RAND, RANDBETWEEN.
70
+ - Statistics: AVERAGE, COUNT, COUNTA, COUNTBLANK, MIN, MAX, MEDIAN, MODE, STDEV, VAR, LARGE,
71
+ SMALL, RANK.
72
+ - Conditional: SUMIF(S), COUNTIF(S), AVERAGEIF(S), MAXIFS, MINIFS.
73
+ - Logical: IF, IFS, IFERROR, IFNA, SWITCH, AND, OR, XOR, NOT.
74
+ - Lookup: XLOOKUP, VLOOKUP, HLOOKUP, INDEX, MATCH.
75
+ - Text: CONCAT, TEXTJOIN, UPPER, LOWER, PROPER, TRIM, LEN, LEFT, RIGHT, MID, FIND, SEARCH,
76
+ SUBSTITUTE, REPLACE, REPT, EXACT, VALUE, TEXT. (No CONCATENATE; use `&` or CONCAT.)
77
+ - Date: TODAY, NOW, DATE, YEAR, MONTH, DAY, WEEKDAY, DAYS, EDATE, EOMONTH, NETWORKDAYS,
78
+ DATEDIF.
79
+ - Information: ISBLANK, ISNUMBER, ISTEXT, ISERROR, ISNA.
80
+ - Dynamic arrays: FILTER, SORT, SORTBY, UNIQUE, SEQUENCE, TRANSPOSE, RANDARRAY, LET.
81
+ - Lambda: LAMBDA, MAP, REDUCE, SCAN, BYROW, BYCOL, MAKEARRAY, ISOMITTED.
82
+
83
+ An unlisted function gives `#NAME?`. Error codes: `#DIV/0!`, `#VALUE!`, `#REF!` (a referenced
84
+ cell was deleted), `#NAME?`, `#N/A` (lookup miss), `#NUM!`, `#CYCLE!` (circular reference),
85
+ `#SPILL!` (an array result is blocked by non-empty cells or the sheet edge), `#CALC!`,
86
+ `#ERROR!`.
87
+
88
+ ## Tool reference
89
+
90
+ ### Read
91
+
92
+ | Tool | Use it to |
93
+ | --- | --- |
94
+ | `get_range` | Read a cell or range (`range`: `"B2"` or `"A1:C5"`). Returns `range` (clamped to the sheet, null if outside it), `values` (computed, row by row), `raw` (the input or formula text), `errors` (`[{cell, error}]`), `merges` (merged ranges touching it, e.g. `["A1:C1"]`; a merged range keeps its value in its top-left cell) and `sheet` size. Read before every write and after it to check computed results. |
95
+
96
+ ### Write
97
+
98
+ | Tool | Use it to |
99
+ | --- | --- |
100
+ | `set_range` | Write a 2D block of raw inputs from `start` (top-left cell), row by row, as one undo step. Strings starting with `=` are formulas; `null` or `""` clears a cell; numbers and booleans are stored as typed. Up to 10000 rows by 1000 columns. The sheet grows to fit. All-or-nothing: any read-only target cell fails the whole write. Returns the written `range`, `written` count, `errors` and new `sheet` size. The default write tool. |
101
+ | `set_cell` | Set one cell's raw input (`cell` in A1, `value` string, number or boolean; `=` starts a formula). Returns `raw` and the computed `value`. Fails outside the sheet (it does not grow it; use `set_range` or `insert_rows` first) and on read-only cells. Use for a single fix, not for filling data. |
102
+ | `insert_rows` | Insert `count` (default 1, max 1000) empty rows before row number `before` (1-based; one past the last row appends). Formula references below shift down. |
103
+ | `delete_rows` | Delete `count` rows from row `start` with their contents. References below shift up; formulas that pointed at deleted cells become `#REF!`. Read dependents first. |
104
+ | `insert_columns` | Insert `count` empty columns before column letter `before` (one past the last column appends). References to the right shift. |
105
+ | `delete_columns` | Delete `count` columns from column letter `start` with their contents. References shift left; references to deleted cells become `#REF!`. |
106
+ | `merge_cells` | Merge a `range` of at least two cells into one showing the top-left value, as one undo step. Every other value in the range is cleared, and the result lists the `cleared` cells: move content into the top-left cell first. Refused when the range partly overlaps an existing merge (the error names it), touches read-only cells or a spill range, or leaves the sheet. Use for titles above a table, never inside data. |
107
+ | `unmerge_cells` | Split every merge touching a `range` (a single cell is enough) back into cells; the value stays top-left. Returns the ranges unmerged; fails when there are none (`get_range` lists them). Unmerge before sorting, filtering or transposing a region. |
108
+ | `transpose_range` | Swap rows and columns of a `range` in place, anchored at its top-left (`A1:C2` becomes `A1:B3`), moving values, formulas and formats; formulas that pointed into the range follow their cells. Cells the new shape covers outside the old range are overwritten, so check that area is empty first. Refused across merges (unmerge first), read-only cells or spills. Returns the new range. |
109
+
110
+ ## Commands
111
+
112
+ Run with `run_command` when the host registers them. Merge, unmerge and transpose act on the
113
+ **user's current selection** and are disabled with "Select a range first." without one; use
114
+ the `merge_cells`, `unmerge_cells` and `transpose_range` tools instead, which take a range.
115
+ Use these commands only when the user asks you to act on what they selected. When there is
116
+ nothing to do they fail with the reason.
117
+
118
+ | Command | Use it to |
119
+ | --- | --- |
120
+ | `spreadsheet.toggleFilters` | Turn filtering on or off (existing filter rules are kept). Filters hide rows in the view only; data and formulas are unchanged. |
121
+ | `spreadsheet.clearFilters` | Remove all filter rules. Disabled when there are none. |
122
+ | `spreadsheet.unhideAll` | Show every hidden row and column. Do this before reasoning about what the user sees versus what `get_range` returns. |
123
+ | `spreadsheet.mergeCells` | Merge the user's selected range (as `merge_cells`). Destroys every value except the top-left one. |
124
+ | `spreadsheet.unmergeCells` | Remove every merge intersecting the user's selection (as `unmerge_cells`). |
125
+ | `spreadsheet.transposeRange` | Transpose the user's selected range in place (as `transpose_range`). |
126
+
127
+ ## Pitfalls
128
+
129
+ - **Raw versus computed.** `values` holds results, `raw` holds what to edit. When copying or
130
+ moving a formula, copy from `raw`; `set_range` writes references as given (it does not
131
+ offset relative references the way paste or fill-down does), so write each row's formula
132
+ with its own row number.
133
+ - **Strings that look like formulas or numbers.** Any string starting with `=` becomes a
134
+ formula; `"007"` becomes the number 7. Prefix with `'` to keep text (`"'007"`).
135
+ - **Read-only cells.** Formula-type columns, read-only columns and read-only cells refuse
136
+ writes; `set_range` names the cells and writes nothing. Write around them, or tell the user.
137
+ - **Spills.** Leave the cells below and right of a dynamic-array formula empty; anything there
138
+ turns the anchor into `#SPILL!`. Spilled cells show values in `get_range` but have empty
139
+ `raw` and cannot be edited on their own; edit the anchor formula.
140
+ - **Deleting rows or columns** turns references to the deleted cells into `#REF!`, and ranges
141
+ that cross the deletion shrink. Check `get_range` on dependent totals afterwards.
142
+ - **Hidden and filtered rows** are still in the sheet and in `get_range` results and are still
143
+ counted by `SUM`; only the view hides them.
144
+ - **Dates** are stored as ISO text (`2026-03-04`); compute with date functions, not string
145
+ operations.
146
+ - **Large ranges.** Read only what you need; a full read of a big sheet costs many tokens.
@@ -0,0 +1,191 @@
1
+ ---
2
+ name: pixerate-vector
3
+ description: How to draw and edit vector artwork in the Pixerate vector editor through its vector.* commands - adding shapes and SVG paths, fills, strokes, gradients (linear, radial, conic, Oklab interpolation), stroke alignment, arrowheads, variable-width and tapered strokes, live corner radii, boolean operations and Pathfinder (unite, subtract, divide, trim), Shape Builder, paint bucket, live path effects (trim paths, repeater, zig zag, offset), envelope warps and free distort, blends and morphing, anchor editing (join, smooth, simplify, scissors, knife, eraser), align, distribute, group, stacking order, and SVG import and export. Use when creating an icon, logo, illustration, glyph, badge or any Bezier path artwork, or editing an SVG in a Pixerate vector editor.
4
+ ---
5
+
6
+ # Pixerate vector editor
7
+
8
+ The vector document is an artboard (`width` x `height` in document units, y down) holding a tree
9
+ of **nodes**: `path` nodes (one or more subpaths of Bezier anchors, with fill, stroke and stroke
10
+ settings) and `group` nodes. Groups can also be live booleans, live blends, or carry a live
11
+ effect stack. Every command is a `vector.*` command run with `run_command` / `run_commands` (see
12
+ `pixerate-agent-tools` for batching with `"$0.id"` references, `atomic: true` and error codes).
13
+
14
+ - **Node ids** come from `vector.list` and from what writes return (`{ id }`, `{ ids }`).
15
+ - **Anchors** are `{ nodeId, subpath, index }`: subpath number within the path, then anchor
16
+ number within the subpath, both from 0. Commands that take `anchors` default to the points
17
+ selected with the direct tool; those that take `ids` default to the selection.
18
+ - **Paint** is a CSS colour, `null` for none, or a gradient object
19
+ `{ type, stops: [{ offset, color, opacity?, midpoint? }], ... }`.
20
+ - Coordinates are document units. A rotated node stores its geometry in its own space: the
21
+ `bounds` that `vector.list` reports are document-space, its `d` is the node's own.
22
+
23
+ Parameter details (gradient fields, effect parameters, width profiles, envelopes) are in
24
+ [references/commands.md](references/commands.md).
25
+
26
+ ## Working method
27
+
28
+ 1. **Read.** `vector.list` gives the artboard size, every node depth first (id, type, name,
29
+ bounds, rotation, fill, stroke, `d`, effects, blend and boolean info) and the selection.
30
+ 2. **Plan in layers.** Decide the shapes, their stacking (bottom to top) and their grouping
31
+ before drawing. Start from primitives (`vector.addShape`) and combine them; write raw `d`
32
+ only for curves primitives cannot make.
33
+ 3. **Write in batches.** Put a construction sequence in one `run_commands` with `atomic: true`
34
+ and a `label`, chaining ids (`"$0.id"`, `"$last.ids"`), so it is one undo step that applies
35
+ all or nothing.
36
+ 4. **Prefer live, expand last.** Use `live: true` booleans, path effects, envelopes, live
37
+ corners and blends while designing; bake with `vector.expandAppearance`,
38
+ `vector.expandBlend` or `vector.outlineStroke` only when the user needs plain paths.
39
+ 5. **Check.** `vector.list` again: bounds where you meant them, no stray nodes, sensible names.
40
+ `vector.exportSvg` gives the final markup; review it, or render it if you can, before handing
41
+ it over.
42
+
43
+ ## Best practices
44
+
45
+ - **Clean paths.** Use the fewest anchors that describe the shape: anchors at extrema (top,
46
+ bottom, left, right of a curve) and at true corners, handles horizontal or vertical at extrema,
47
+ each handle about a third of its segment. Run `vector.removeRedundantPoints` after
48
+ booleans, knife and pencil work; `vector.smooth` for lumpy curves; `vector.deleteAnchors`
49
+ keeps the outline by refitting neighbours.
50
+ - **Live corners over drawn arcs.** Give rectangles, polygons and stars a `cornerRadius`
51
+ (`vector.addShape`) or set it with `vector.setCorners`; the anchors stay sharp and editable and
52
+ radii shrink to fit short sides. Keep one radius scale across a design.
53
+ - **Non-destructive first.** Live booleans (`vector.boolean` with `live: true`), path effects
54
+ and envelopes keep the operands editable. A destructive boolean or Pathfinder replaces its
55
+ inputs; do that last, and only when asked for flat output.
56
+ - **Boolean vs Pathfinder vs Shape Builder.** `vector.boolean` for a single result shape (union
57
+ for silhouettes, subtract for cut-outs, intersect, exclude). `vector.pathfinder` when you need
58
+ every region separately (divide), hidden parts removed (trim, merge) or a crop. Shape Builder
59
+ when you want to merge or delete particular regions picked by point.
60
+ - **Strokes.** Use `strokeAlign: "inside"` for icons and UI shapes so the outer size stays exact,
61
+ `outside` for outlines around artwork; open paths always stroke centred. Use round caps and
62
+ joins for friendly line icons, miter for geometric ones. Keep one stroke width across an icon
63
+ set (for example 1.5 or 2 units on a 24-unit grid).
64
+ - **Icon grid.** Use a square artboard (24, 32 or 48 units), keep a padding margin, place
65
+ coordinates on whole or half units so strokes render crisp, and align optical centres.
66
+ - **Gradients.** Two to four stops are usually enough. Use `interpolation: "oklab"` for
67
+ perceptually even blends without the grey or muddy midpoint sRGB gives between saturated hues;
68
+ `midpoint` to shift the half-way point instead of adding stops. Prefer linear or radial for
69
+ portability; conic and diamond export as SVG patterns.
70
+ - **Grouping and naming.** Group the parts of one object (`vector.group` with a `name`), name
71
+ paths that matter (`name` on add), and keep the tree shallow.
72
+ - **SVG hygiene.** Export with `precision` 2 or 3 (default 3); higher only for tiny artboards.
73
+ Expand effects, blends and variable-width strokes before handing SVG to tools that do not read
74
+ Pixerate's `data-vector-*` attributes; other readers see the drawn appearance but not the live
75
+ source.
76
+
77
+ ## Commands
78
+
79
+ ### Read
80
+
81
+ | Command | Use it to |
82
+ | --- | --- |
83
+ | `vector.list` | Read the document: `{ width, height, nodes, selection, tool }`. Each node has id, type, name, depth, document-space `bounds`, `rotation` (degrees clockwise), visible, locked, selected, and for paths fill, stroke, strokeWidth and `d`; groups list `children`, `blend`, `liveBoolean`, `effects`. Call it first and after any batch. |
84
+ | `vector.shapeBuilderFaces` | List the regions the given paths divide the plane into: path data, area, a point inside each and the ids of paths filling it. Use the points with `vector.shapeBuilder`. |
85
+ | `vector.exportSvg` | Get the document as standalone SVG markup (`{ svg }`); `precision` 0 to 8 decimals (default 3). |
86
+
87
+ ### Create and delete
88
+
89
+ | Command | Use it to |
90
+ | --- | --- |
91
+ | `vector.addShape` | Add a `kind` `rect`, `ellipse`, `polygon` (`sides`, at least 3), `star` (`points`, `innerRatio` 0 to 1) or `line` at `x`, `y`, `width`, `height` (all required; for a line, width and height are the end's offset). `cornerRadius` and `cornerKind` give live corners; any style field and `name` apply. Uses the editor's default style for anything not given. Returns `{ id }`. |
92
+ | `vector.addPath` | Add a path from SVG path data `d` (absolute or relative M, L, H, V, C, S, Q, T, A, Z; arcs and quadratics become cubics) in document units, with `name` and style fields; unset style comes from the editor defaults. Fails when `d` has no points. Returns `{ id }`. |
93
+ | `vector.importSvg` | Add the shapes of SVG markup `svg` on top of the document, or replace the document with `replace: true`. Reads paths, basic shapes, groups, transforms and linear and radial gradients; skips text, images, masks, filters and `use`. |
94
+ | `vector.delete` | Delete nodes (`ids`). |
95
+
96
+ ### Style
97
+
98
+ | Command | Use it to |
99
+ | --- | --- |
100
+ | `vector.setStyle` | Set `fill`, `stroke`, `strokeWidth`, `strokeLinecap` (butt, round, square), `strokeLinejoin` (miter, round, bevel), `strokeDasharray`, `fillRule` (nonzero, evenodd), `strokeAlign` (center, inside, outside; closed shapes only), `startArrow` / `endArrow` (triangle, arrow, open, circle, square, bar, or null), `arrowAlign` (extend, tip), `startArrowScale` / `endArrowScale` (multiples of stroke width, default 1), `strokeWidthProfile` on `ids`. Groups apply to every path inside. Pass at least one field. |
101
+ | `vector.setGradient` | Edit the gradient of the fill (`target` default) or stroke of `ids`: `type` (linear, radial, conic, reflected, diamond), `stops`, `angle` (degrees, 0 up, clockwise), `cx` / `cy` / `r`, explicit `start` / `end` / `width` / `focal`, `units`, `spread`, `interpolation` (srgb default, linear, oklab), `smoothness`, `strokeMode`, `aspect`, `reverse`. Missing fields keep their value; a solid colour becomes a gradient from it to white. Returns the gradient. |
102
+ | `vector.setCorners` | Set live corner `radius` (0 makes them sharp) and / or `kind` (round, inverted, chamfer) on `anchors`, else the selected points, else every corner of `ids`. |
103
+ | `vector.setWidthProfile` | Give strokes a variable width: a `preset` (uniform, taperStart, taperEnd, taperBoth, bulge, pinch, teardrop, wave, pressure; `uniform` removes it), explicit `points`, or a parametric `taper` and / or `wave`. Returns the profile points. |
104
+ | `vector.setWidthPoint` | Set one width point of path `id`: `index` of an existing point (from the profile `vector.setWidthProfile` returns) or none to add one at `t` (0 to 1); `left` / `right` are side widths in document units. Returns the profile. |
105
+
106
+ ### Transform and arrange
107
+
108
+ | Command | Use it to |
109
+ | --- | --- |
110
+ | `vector.transform` | Move by `dx`, `dy`, scale by `sx`, `sy` (along the selection box axes; `sy` defaults to `sx`; negative flips), rotate by `rotate` degrees clockwise about the combined centre, or set each node to absolute `angle` about its own centre, applied in that order. |
111
+ | `vector.skew` | Skew by `ax` degrees horizontally and `ay` degrees vertically (each -89.9 to 89.9) about the box centre or `origin`. |
112
+ | `vector.distort` | Free Distort in perspective: give `corners`, the four new corners of the selection box (top-left, top-right, bottom-right, bottom-left) in document units, forming a convex quad. `tolerance` (default 0.05) controls curve fidelity. Returns the new bounds. |
113
+ | `vector.align` | Align `ids` on `edge` (left, center, right, top, middle, bottom) to their combined bounds, or to the artboard with `to: "artboard"` (also the default for a single node). |
114
+ | `vector.distribute` | Give three or more nodes equal gaps in `direction` horizontal or vertical. |
115
+ | `vector.arrange` | Change stacking `order` within each node's parent: front, forward, backward, back. |
116
+ | `vector.group` | Group nodes that share a parent, with an optional `name`. Returns `{ id }`. |
117
+ | `vector.ungroup` | Replace groups with their children (ungrouping a blend expands it). |
118
+ | `vector.select` | Select nodes by `ids` (`add: true` to extend; an empty list clears). Selection is the default target of most commands. |
119
+
120
+ ### Combine
121
+
122
+ | Command | Use it to |
123
+ | --- | --- |
124
+ | `vector.boolean` | Combine two or more paths by `operation` union, subtract (upper shapes from the lowest), intersect or exclude into one new path. With `live: true` the shapes become editable operands of a live boolean group instead (with a lone live group selected, its operation changes). Returns `{ id }`. |
125
+ | `vector.pathfinder` | Run a Pathfinder `operation` over paths bottom to top: `divide` (every face its own shape), `trim` (hidden parts removed), `merge` (trim, then same-fill parts joined), `crop` (top shape crops the rest), `outline` (outlines cut into open strokes), `minusBack` (top minus everything below). Results replace the inputs, grouped when several. Returns `{ ids }`. |
126
+ | `vector.shapeBuilder` | Merge the faces a pointer path touches into one shape, or delete them (and touched line pieces and edges) with `erase: true`. `points` is `[[x, y], ...]` in document units (one point is a click; use points from `vector.shapeBuilderFaces`), `tolerance` for edge picks. Returns counts. |
127
+ | `vector.fillRegion` | Paint bucket: fill the area visible outlines enclose around `point` `[x, y]` with a new path in the current fill (islands stay holes). `gap` closes gaps up to that size between loose ends. Returns `{ id }`. |
128
+ | `vector.outlineStroke` | Turn strokes into filled shapes of exactly the painted area (alignment, caps, joins, dashes, arrowheads, width profiles included), above a copy keeping the fill. Returns the new ids. |
129
+
130
+ ### Live effects and envelopes
131
+
132
+ | Command | Use it to |
133
+ | --- | --- |
134
+ | `vector.addEffect` | Add a live path effect `type` (trim, roundCorners, puckerBloat, twist, zigzag, wiggle, offset, merge, repeater, envelope) with `params` to `ids`, at `index` in the stack (default last). Effects apply top to bottom. Returns `{ effects: [{ nodeId, effectId }] }`. |
135
+ | `vector.updateEffect` | Change effect `effectId` on `nodeId`: `params` (merged), `enabled`, or move it to `index` (0 applies first). Returns the node's effect stack. |
136
+ | `vector.removeEffect` | Remove effect `effectId` from `nodeId`. |
137
+ | `vector.envelope` | Warp with a live envelope: a `preset` (arc, arcLower, arcUpper, arch, bulge, shellLower, shellUpper, flag, wave, fish, rise, fisheye, inflate, squeeze, twist) with `bend`, `horizontal`, `vertical` (percent, -100 to 100) and `orientation`; or a `mesh` of `rows` x `columns` (1 to 16, optional control `points`); or `topObject: true` (top closed path becomes the envelope), `release: true`, `expand: true`. Reapplying changes an existing envelope. |
138
+ | `vector.expandAppearance` | Bake path effects, envelopes and live booleans of `ids` (and everything inside) into plain paths. Returns the ids. |
139
+
140
+ ### Blends
141
+
142
+ | Command | Use it to |
143
+ | --- | --- |
144
+ | `vector.blend` | Make a live blend of two or more paths or groups sharing a parent (bottom to top, or the order of `ids` with `keepOrder`): shape and paint morph through in-betweens. `spacing` steps (default; `steps` default 5), distance (`distance` default 20) or smoothColor; `orientToSpine`; `linear` for straight anchor paths; `starts` maps key ids to start anchors. Returns `{ id }`. |
145
+ | `vector.blendOptions` | Change `spacing`, `steps`, `distance`, `orientToSpine`, `linear` of blends; in-betweens regenerate. |
146
+ | `vector.replaceSpine` | With one blend and one path given, make the path the blend's spine; keys spread along it by arc length. |
147
+ | `vector.expandBlend` | Turn blends into plain groups of editable keys and in-betweens. Returns the group ids. |
148
+ | `vector.releaseBlend` | Remove the in-betweens and give back the keys (and a replaced spine as an unpainted path). Returns their ids. |
149
+
150
+ ### Path editing
151
+
152
+ | Command | Use it to |
153
+ | --- | --- |
154
+ | `vector.moveAnchor` | Move anchor (`nodeId`, `subpath`, `index`) to `x`, `y` in document units, carrying its handles; `curvature: true` bends its two segments like the Curvature tool instead (default: the `curvatureMoves` editing setting, off). |
155
+ | `vector.bendSegment` | Bend segment `segment` (anchor `segment` to the next) of `nodeId` / `subpath` so the curve passes through `x`, `y` at parameter `t` (default 0.5). |
156
+ | `vector.deleteAnchors` | Delete `anchors`. `keepShape` (default the editor setting, on) refits the neighbours so the outline keeps its shape. |
157
+ | `vector.join` | Join open subpaths of `ids`, nearest ends first (ends within `tolerance` merge, others get a straight segment); a single open path is closed. |
158
+ | `vector.average` | Move `anchors` to their average: same y (`axis` horizontal), same x (vertical) or same point (both, default). |
159
+ | `vector.removeRedundantPoints` | Drop anchors that can go without moving the outline more than `tolerance` units (default 0.5). |
160
+ | `vector.smooth` | Pull handles of `ids` (or of `anchors`) towards smooth tangents by `amount` 0 to 1 (default 1). |
161
+ | `vector.cut` | Scissors: cut `nodeId` at the outline point nearest `x`, `y`, or cut at `anchors`. A closed path opens; an open one splits in two. Returns the ids. |
162
+ | `vector.knife` | Cut closed paths along a polyline `points` (at least two `[x, y]`) wherever it crosses them edge to edge, leaving no gap. Cuts `ids`, else the selection, else every path crossed. Returns the pieces. |
163
+ | `vector.erase` | Erase along a polyline `points` with a round eraser of diameter `size` (default the eraser setting, 10): fills lose the area, outlines are cut. Returns the changed ids. |
164
+
165
+ ### Editor settings
166
+
167
+ | Command | Use it to |
168
+ | --- | --- |
169
+ | `vector.setEditing` | Set editing behaviour: `keepShapeOnDelete`, `curvatureMoves`, `pencilSmoothing` (0 to 1), `recognizeShapes`, `eraserSize`, `pencilPressure` (pen, all, off). Returns the settings. |
170
+ | `vector.setTool` | Switch the interactive tool (select, direct, pen, pencil, rect, ellipse, polygon, star, line, scissors, knife, eraser, width, shapeBuilder, paintBucket, blend, gradient, envelope). Only for handing the canvas to the user in a given mode; commands do not need a tool. |
171
+
172
+ ## Pitfalls
173
+
174
+ - The `d` in `vector.list` draws live corners cut, which adds anchors. On a path with corner
175
+ radii, anchor indices counted from `d` do not match the stored anchors; count anchors on a path
176
+ without corners, or clear corners first.
177
+ - `d` and anchor positions are in the node's own space; `bounds` are in document space. For
178
+ rotated nodes (`rotation` not 0), `vector.moveAnchor` and `vector.bendSegment` take document
179
+ coordinates, so compute them from the drawn position, not from `d`.
180
+ - `vector.boolean` without `live` fails when the result is empty (shapes that do not overlap)
181
+ and consumes its inputs. Subtract removes upper shapes from the lowest: restack with
182
+ `vector.arrange` first.
183
+ - `vector.blend`, `vector.group` and live booleans need nodes that share a parent.
184
+ - Blend in-betweens are locked and regenerate; edit the keys, not the steps.
185
+ - `strokeAlign` inside and outside only apply when every subpath is closed.
186
+ - Stroke widths, corner radii and effect sizes are kept when scaling: scale them yourself if the
187
+ design should grow proportionally.
188
+ - `vector.importSvg` without `replace` adds on top; with `replace: true` it discards the current
189
+ document (undoable, but confirm with the user first).
190
+ - A command that fails changes nothing; read its message (for example "Nothing is selected; pass
191
+ ids.") and retry with the missing input.
@@ -0,0 +1,138 @@
1
+ # Vector command parameters
2
+
3
+ Detail for the `vector.*` commands in `../SKILL.md`. Units are document units unless noted;
4
+ angles are degrees, clockwise on screen (y down).
5
+
6
+ ## Paint and gradients
7
+
8
+ A paint (`fill`, `stroke`) is a CSS colour string, `null` (none), or a gradient object that needs
9
+ `type` and at least one stop:
10
+
11
+ ```json
12
+ { "type": "linear", "angle": 90, "interpolation": "oklab",
13
+ "stops": [{ "offset": 0, "color": "#f43f5e" }, { "offset": 1, "color": "#7c3aed", "midpoint": 0.4 }] }
14
+ ```
15
+
16
+ | Field | Meaning |
17
+ | --- | --- |
18
+ | type | `linear`, `radial`, `conic` (angle sweep), `reflected` (linear mirrored about the start), `diamond`. |
19
+ | stops | `{ offset 0-1, color, opacity? 0-1, midpoint? 0.05-0.95 }`; `midpoint` is where the two colours are half mixed (default 0.5). |
20
+ | angle | Shorthand direction: 0 is up. Linear / reflected direction across the box (default 180, top to bottom); conic start angle and diamond turn (default 90). |
21
+ | cx, cy, r | Shorthand centre and radius of radial / conic / diamond, fractions of the box (default 0.5). |
22
+ | start, end, width | Explicit frame `{ x, y }`: start (centre for radial / conic / diamond), end of the main axis (the radius), end of the secondary axis (aspect; default square and as long). Wins over the shorthand. |
23
+ | focal, focalRadius | Radial focal point (SVG fx / fy) and focal circle radius as a fraction of the radius (0-0.99). |
24
+ | units | `objectBoundingBox` (default: fractions of the shape's box, follows the box) or `userSpaceOnUse` (the node's own coordinates, follows scale and skew exactly). |
25
+ | spread | `pad` (default), `reflect`, `repeat`. |
26
+ | interpolation | `srgb` (default, SVG's own), `linear` (linear light), `oklab` (perceptual). Non-sRGB ramps export as extra stops. |
27
+ | smoothness | 0-1: bends the ramp along a spline through the stops (0 straight). |
28
+ | strokeMode | On strokes: `within` (default, like a fill), `along` (0 to 1 along each subpath), `across` (left edge to right edge). Along / across export as patterns. |
29
+
30
+ `vector.setGradient` also takes `target` (`fill` default, or `stroke`), `aspect` (secondary axis
31
+ length over main axis length), `reverse: true` (flip stops and midpoints), and `focal: null` /
32
+ `width: null` to remove them. Missing fields keep their current value.
33
+
34
+ ## Stroke settings
35
+
36
+ | Field | Values |
37
+ | --- | --- |
38
+ | strokeWidth | Number, at least 0. Default from the editor defaults (1 when unset). |
39
+ | strokeLinecap | `butt`, `round`, `square`. |
40
+ | strokeLinejoin | `miter`, `round`, `bevel`. |
41
+ | strokeDasharray | Array of dash and gap lengths. |
42
+ | strokeAlign | `center` (default), `inside`, `outside`. Only on paths whose subpaths are all closed. |
43
+ | startArrow, endArrow | `triangle`, `arrow`, `open`, `circle`, `square`, `bar`, or `null`. On the start of the first subpath and the end of the last one, when open. A head is 4 x its weight long and wide. |
44
+ | arrowAlign | `extend` (default: tip past the end point, path keeps its length) or `tip` (tip on the end point, stroke shortened). |
45
+ | startArrowScale, endArrowScale | Head weight as a multiple of the stroke width (default 1). |
46
+ | fillRule | `nonzero`, `evenodd`. |
47
+
48
+ ## Variable-width strokes
49
+
50
+ A width profile is a list of `{ t, left, right }`: `t` is the position along each subpath by
51
+ length (0-1), `left` / `right` how far each side reaches as a multiple of half the stroke width
52
+ (1 = uniform; left is left looking along the path). Sides interpolate with a monotone cubic, so
53
+ they never overshoot; two points at one `t` make a step. `null` or `[]` is uniform.
54
+
55
+ `vector.setWidthProfile` takes one of:
56
+
57
+ - `preset`: `uniform` (removes the profile), `taperStart`, `taperEnd`, `taperBoth`, `bulge`,
58
+ `pinch`, `teardrop`, `wave`, `pressure`.
59
+ - `points`: the explicit list above.
60
+ - `taper` (fractions, all default 0): `startLength` / `endLength` (share of the path each taper
61
+ covers), `startWidth` / `endWidth` (width at the end as a fraction; 0 is a point),
62
+ `startEase` / `endEase` (0 linear, 1 a quarter circle bulging out).
63
+ - `wave`: `amount` 0-1 (default 0.5; the width swings between 1 - amount and 1), `cycles`
64
+ (default 4), `phase` degrees (default 0). `taper` and `wave` combine.
65
+
66
+ `vector.setWidthPoint` sets one point with `left` / `right` in **document units** (not multiples),
67
+ by `index` into the returned profile, or adds one at `t` when `index` is left out.
68
+
69
+ ## Live corners
70
+
71
+ `cornerRadius` (on `vector.addShape`) and `radius` (on `vector.setCorners`) are in document
72
+ units; `kind` / `cornerKind` is `round` (default), `inverted` (an arc cut into the shape) or
73
+ `chamfer` (a straight bevel). A corner is any non-smooth anchor where two sides meet, except the
74
+ ends of an open subpath. Radii that do not fit shrink so each cut takes at most half of a side.
75
+
76
+ ## Path effects
77
+
78
+ `vector.addEffect` and `vector.updateEffect` take `params`; missing ones keep their value or the
79
+ default below. Lengths are in the node's own units, angles degrees, percentages 0-100.
80
+
81
+ | Type | Parameters (defaults) | Effect |
82
+ | --- | --- | --- |
83
+ | trim | start 0, end 50 (%), offset 0 (deg), mode `simultaneous` or `individual` | Keep the part between start and end; `individual` trims all paths as one length in stacking order. Good for line-drawing reveals. |
84
+ | roundCorners | radius 10 | Arc of that radius at every corner. |
85
+ | puckerBloat | amount 30 (-100 to 100) | Positive bloats segments outward, negative makes spikes. |
86
+ | twist | angle 45, center {x 0, y 0} (offset from the middle) | Turn more the farther from the centre. |
87
+ | zigzag | size 5, ridges 4, smooth false | Each segment split into ridges + 1 pieces pushed alternately to either side. |
88
+ | wiggle | size 5, detail 6, smooth true, speed 2, correlation 50, phase 0, seed 1, time 0 (s) | Deterministic noise displacement; animate `time` to animate it. |
89
+ | offset | amount 5, join `miter`, miterLimit 4, copies 1, copyOffset 0 | Grow or shrink; copies make concentric rings. |
90
+ | merge | mode `add` (also `merge`, `subtract`, `intersect`, `exclude`) | Combine the shapes above it into one, in the bottom shape's style. |
91
+ | repeater | copies 3, offset 0, position {x 100, y 0}, anchor {x 0, y 0}, rotation 0, scale {x 100, y 100} (%), startOpacity 100, endOpacity 100 (%), composite `below` | Copy i is moved, rotated and scaled k = i + offset times about the anchor; fractional copies fade the last one. Radial patterns: position {0, 0}, rotation 360 / copies. |
92
+ | envelope | style `arc`, bend 50, horizontal 0, vertical 0, orientation `horizontal`, rows 2, columns 2, mesh null | Prefer `vector.envelope`. |
93
+
94
+ Effects apply in stack order (index 0 first) to everything above them; effects after a repeater
95
+ act on its copies. A node with effects exports as `<g data-vector-live>`: other SVG readers see
96
+ the drawn result. Use `vector.expandAppearance` for plain paths.
97
+
98
+ ## Envelopes and distortion
99
+
100
+ `vector.envelope` (one of these per call):
101
+
102
+ - **Warp**: `preset` one of `arc`, `arcLower`, `arcUpper`, `arch`, `bulge`, `shellLower`,
103
+ `shellUpper`, `flag`, `wave`, `fish`, `rise`, `fisheye`, `inflate`, `squeeze`, `twist`;
104
+ `bend`, `horizontal`, `vertical` in percent (-100 to 100); `orientation` `horizontal` or
105
+ `vertical`.
106
+ - **Mesh**: `mesh: { rows, columns, points? }` (1-16 each, default 2 x 2). `points` is the full
107
+ control grid row by row in the node's own space: (3 x columns + 1) x (3 x rows + 1) points.
108
+ Not combinable with `preset`.
109
+ - `topObject: true`: the topmost selected closed path becomes the envelope of the others
110
+ (`mesh.rows` / `mesh.columns` set its grid).
111
+ - `release: true`: remove the envelope and get its shape back as a path.
112
+ - `expand: true`: bake it (same as `vector.expandAppearance`).
113
+
114
+ `vector.distort` maps the selection box's corners (clockwise from the top left, in the box's own
115
+ rotation) to four new points forming a convex quad: a perspective map in which straight lines
116
+ stay straight. `vector.skew`: `x' = x + tan(ax) * y` along the box's axes.
117
+
118
+ ## Blends
119
+
120
+ | Option | Meaning |
121
+ | --- | --- |
122
+ | spacing | `steps` (default), `distance`, `smoothColor` (one step per two colour levels of difference, at most 256). |
123
+ | steps | In-betweens between each pair of keys (1-1000, default 5). |
124
+ | distance | Spacing along the spine (default 20). |
125
+ | orientToSpine | Turn in-betweens with a replaced spine. |
126
+ | linear | Straight-line anchor paths instead of the rotation-aware morph. |
127
+ | keepOrder | (`vector.blend` only) blend in `ids` order instead of stacking order. |
128
+ | starts | (`vector.blend` only) `{ keyId: anchorIndex }`: where each key's first subpath starts, to stop twisting. |
129
+
130
+ In-betweens have ids `<blend id>~1`, `~2`, ... and are locked; colours mix in OKLab.
131
+
132
+ ## Shape Builder, Pathfinder and paint bucket
133
+
134
+ All three work in document space with every transform applied. A filled path takes part as its
135
+ fill; an unfilled stroked path takes part as the area its stroke paints. Pathfinder `divide` and
136
+ `outline` also run on a single path; the other operations need two or more overlapping paths. Shape Builder
137
+ `points` should come from `vector.shapeBuilderFaces` (`point` of each face) so a click lands
138
+ inside the intended face.