Merge pull request #1148 from KnottyDyes/squad/new-art-paint-docs

MCP: drawing tools describe inherited paint and export text options
This commit is contained in:
BFlat 2026-10-11 18:15:10 +07:00 committed by GitHub
commit 6eaaccb717
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 13 additions and 6 deletions

File diff suppressed because one or more lines are too long

View File

@ -203,7 +203,7 @@ pub fn tool_definitions() -> Vec<Value> {
tool(
"draw_path",
"Draw path",
"Create a path from points ([[x,y],…] or [{x,y,in?:[x,y],out?:[x,y]},…] with Bézier handles) or SVG path data `d`, then apply optional paint. Returns the new object id.",
"Create a path from points ([[x,y],…] or [{x,y,in?:[x,y],out?:[x,y]},…] with Bézier handles) or SVG path data `d`, then apply optional paint. Omitted paint fields inherit the current new-art appearance (initially white fill and 1 pt black stroke). For a filled path without an outline, pass an explicit fill and stroke:\"none\". Returns the new object id.",
obj(
json!({
"points": {"type": "array", "description": "Anchors: [x,y] pairs or {x, y, in?, out?, smooth?} objects", "items": {"anyOf": [{"type": "array", "items": {"type": "number"}, "minItems": 2}, {"type": "object"}]}},
@ -220,7 +220,7 @@ pub fn tool_definitions() -> Vec<Value> {
tool(
"draw_shape",
"Draw shape",
"Create a live shape and apply optional paint. rectangle/ellipse: x, y, width, height (rectangle: radius = corner radius). polygon: cx, cy, radius, sides. star: cx, cy, radius1, radius2, points. line: x1, y1, x2, y2. Returns the new object id.",
"Create a live shape and apply optional paint. rectangle/ellipse: x, y, width, height (rectangle: radius = corner radius). polygon: cx, cy, radius, sides. star: cx, cy, radius1, radius2, points. line: x1, y1, x2, y2. Omitted paint fields inherit the current new-art appearance (initially white fill and 1 pt black stroke); lines start with no fill and a visible stroke. For a filled shape without an outline, pass an explicit fill and stroke:\"none\". Returns the new object id.",
obj(
json!({
"shape": {"type": "string", "enum": ["rectangle", "ellipse", "polygon", "star", "line"]},
@ -332,7 +332,7 @@ pub fn tool_definitions() -> Vec<Value> {
tool(
"export",
"Export",
"Export the active document with the engine's document.export (the same bytes in the app and headless), in any format of the `format` enum: vectors (svg/svgz with the artboard as viewBox, eps, dxf, emf, wmf), pdf (one page per artboard: all, or `artboard` / `range`), rasters (one rendered artboard: png, jpg, webp, gif, png8 as an indexed .png, tiff, bmp, tga, psd with its layers), txt (the stories, back to front), vectorcraft or template (a native copy or template; the document keeps its path). run_command document.formats lists each format's options. `selection: true` exports only the selected objects, cropped to their bounds. Template layers are left out; live effects are kept (geometry baked, SVG filters for shadows/glows/blur). Without `path` the bytes come back as dataBase64.",
"Export the active document with the engine's document.export (the same bytes in the app and headless), in any format of the `format` enum: vectors (svg/svgz with the artboard as viewBox, eps, dxf, emf, wmf), pdf (one page per artboard: all, or `artboard` / `range`), rasters (one rendered artboard: png, jpg, webp, gif, png8 as an indexed .png, tiff, bmp, tga, psd with its layers), txt (the stories, back to front), vectorcraft or template (a native copy or template; the document keeps its path). run_command document.formats lists each format's options. For SVG/SVGZ, top-level `outlineText: true` writes text as paths; DXF takes it too (its type is outlined anyway unless `preserve: editability`). PDF instead uses `options.advanced.outlineText: true`, default false (live text). `selection: true` exports only the selected objects, cropped to their bounds. Template layers are left out; live effects are kept (geometry baked, SVG filters for shadows/glows/blur). Without `path` the bytes come back as dataBase64.",
obj(
json!({
"format": {"type": "string", "enum": FORMATS.iter().filter(|f| f.write).map(|f| f.id).collect::<Vec<_>>(), "description": "Default: from the path's extension"},
@ -341,8 +341,8 @@ pub fn tool_definitions() -> Vec<Value> {
"artboard": {"type": "integer", "minimum": 0, "description": "0-based artboard (default: the first; PDF default: all)"},
"range": string("1-based artboards such as \"1-3, 5\" (PDF: one page each; other formats take one)"),
"selection": {"type": "boolean", "description": "Export only the selection, cropped to it"},
"outlineText": {"type": "boolean", "description": "SVG: text as outlines (viewable without the fonts)"},
"options": {"type": "object", "description": "More format options, passed through (see run_command document.formats), e.g. {\"quality\": 80} for jpg"},
"outlineText": {"type": "boolean", "description": "SVG/SVGZ: true writes text as outlines (viewable without the fonts). DXF takes it too (type outlined anyway unless preserve: editability). PDF uses options.advanced.outlineText instead (default false: live text)"},
"options": {"type": "object", "description": "More format options, passed through (see run_command document.formats), e.g. {\"quality\": 80} for jpg or {\"advanced\": {\"outlineText\": true}} for PDF text as outlines (default false: live text)"},
}),
&[],
),

View File

@ -253,6 +253,9 @@ explicit `ids`.
Paint values (`fill`, `stroke`) accept `"#rrggbb"`, `"none"`, `[r,g,b]` (0..1), `{"c","m","y","k"}`, `{"gray"}`,
or a full `paint.setFill` params object (`{"gradient": …}`, `{"swatch": "name"}`).
For `draw_shape` and `draw_path`, omitted paint fields inherit the current [new-art appearance](#new-art).
For a filled shape or path without an outline, pass an explicit `fill` and `stroke: "none"`.
Lines start with no fill and a visible stroke.
The Fill/Stroke proxy commands run through `run_command`: `paint.invert` and `paint.complement` recolour the active
proxy keeping each colour's model, `paint.lastColor` / `paint.lastGradient` re-apply the last solid colour or gradient,
and `paint.recent` returns the recent colours that every paint command (and the eyedropper) feeds.
@ -286,6 +289,9 @@ objects' fills or strokes differ (`fillMixed` / `strokeMixed`, drawn as a "?" pr
| `text_wrap` | `{ids?, offset?, invert?, release?}` | Area type below the objects (same layer) flows around them. |
| `undo` / `redo` | `{}` | Many calls that change nothing record no undo step, for example `object.align` with nothing to move, `object.move` by 0 without `copy` and `object.showAll` with nothing hidden. `undo` (`edit.undo`) after such a call undoes the step before it. `inspect_document` lists the undo steps as `history`. |
For SVG/SVGZ, `export`'s top-level `outlineText: true` writes text as paths; DXF takes it too (its type is outlined anyway unless `preserve: editability`).
PDF instead uses `options: {"advanced": {"outlineText": true}}`; its default is false (live text).
With `mods.shift`, a marquee dragged with the Selection tool toggles the objects it reaches (the selected ones leave
the selection, the others join it, the rest stays), and one dragged with Direct or Group Selection toggles the anchors
inside it (a path left with none leaves the selection, one with all of them is selected whole). The Lasso adds anchors
@ -1693,6 +1699,7 @@ a pin back restores the original; every pin must be on the art's mesh, and empty
## New art
Initially (and after `paint.default`) new art has a white fill and a 1 pt black stroke.
New objects take the fill and stroke proxies (`paint.setFill` / `paint.setStroke` and the weight, whatever is
selected) on top of a template. With nothing selected, `stroke.set` / `stroke.setAdvanced` (cap, join, dashes,
arrowheads, profile…) and `graphicStyle.apply` (every fill, stroke and effect, opacity, blend mode and the link to the