Files
vectorcraft/docs/mcp.md
T
bflatasticandClaude Opus 5.5 b36fd67bf4 M3.72: Tile Edge Color dialog and Show Swatch Bounds in pattern editing
Object > Pattern > Tile Edge Color... picks the colour of the tile edge
(a layer-colour preset or a custom colour), stored in the preference
patternTileEdgeColor and passed to the renderer. Pattern Options gains
Show Swatch Bounds: a dashed outline of the part of the tiling the swatch
repeats (the period of brick and hex tilings).

Commands: prefs.set {patternTileEdgeColor}, pattern.options
{showSwatchBounds}, ui.tileEdgeColor. Model: PatternDef.show_swatch_bounds.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-05 01:50:25 +07:00

28 KiB
Raw Blame History

VectorCraft MCP server

vectorcraft-cli mcp runs a Model Context Protocol server on stdio (newline-delimited JSON-RPC 2.0, protocol 2025-06-18; 2025-03-26 and 2024-11-05 also accepted). Agents use it to draw, inspect and look at VectorCraft documents.

It has two backends:

Mode How What works
Remote vectorcraft-cli mcp --connect 127.0.0.1:7979 (the app must run with vectorcraft --control 7979) Everything. Tool calls are forwarded over the control protocol, so you watch the app change live.
Headless vectorcraft-cli mcp --headless An in-process engine session with a CPU renderer. Everything except the UI-only tools (inspect_ui, type_text, open_panel, screenshot {window:true}).

With no flag, the server tries 127.0.0.1:7979 and falls back to headless. Logs go to stderr; stdout carries only protocol messages.

Build and register

cargo build --release -p vectorcraft-cli
claude mcp add vectorcraft -- "$PWD/target/release/vectorcraft-cli" mcp
# or pin a mode:
claude mcp add vectorcraft-headless -- "$PWD/target/release/vectorcraft-cli" mcp --headless
claude mcp add vectorcraft-app -- "$PWD/target/release/vectorcraft-cli" mcp --connect 127.0.0.1:7979

Other clients use the same command in their JSON config:

{"mcpServers": {"vectorcraft": {"command": "/abs/path/target/release/vectorcraft-cli", "args": ["mcp"]}}}

For a live session, start the app first: cargo run --release -p vectorcraft -- --control 7979.

Tools

Coordinates are points in document space: y points down, the origin is the first artboard's top-left, and a new document is 612 × 792 (US Letter). New objects become the selection. Most commands act on the selection or on 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"}). 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. paint.proxies returns what the proxies show: the fill and stroke, which one is active, and whether the selected objects' fills or strokes differ (fillMixed / strokeMixed, drawn as a "?" proxy).

Tool Arguments Notes
list_commands {filter?, enabledOnly?} The command catalogue: id, label, menu, shortcut, params doc, enablement.
run_command {command, params?} Runs any command. Use it for everything without a dedicated tool.
inspect_document {} Artboards, layer tree (ids, kinds, bounds, paint), selection, history, tool.
inspect_ui {} UI state. Remote mode only.
select_tool {tool} selection, directSelection, pen, rectangle, ellipse, polygon, star, lineSegment, …
pointer_gesture {events:[{kind,x,y,mods?}], tool?, mods?} kind is one of down, drag, up, move, doubleclick. Events go through the same path as the mouse.
draw_path {points | d, closed?, fill?, stroke?, strokeWidth?} points is [[x,y],…] or [{x,y,in?,out?,smooth?},…]. d is SVG path data.
draw_shape {shape, …geometry, fill?, stroke?, strokeWidth?} rectangle/ellipse: x,y,width,height (plus radius for corners). polygon: cx,cy,radius,sides. star: cx,cy,radius1,radius2,points. line: x1,y1,x2,y2.
set_paint {fill?, stroke?, strokeWidth?, ids?} Applies to the selection (or ids) and becomes the default for new art.
press_key {key, mods?} Remote: a real key event. Headless: runs the command or tool bound to that shortcut, or sends the key to the busy tool.
type_text {text} Remote only.
invoke_menu {command, params?} Invokes a menu item by command id. Includes UI commands such as view.* and window.* in remote mode.
open_panel {panel} Remote only.
screenshot {path?, scale?, artboard?, window?} Returns MCP image content (image/png, base64) plus a text block. Renders the artboard; window:true captures the app window (remote only).
open_file {path} Opens any readable file as a new active document: .vectorcraft/.drawcraft, .svg/.svgz, .pdf/.ai, .ait, PNG, JPEG, GIF, WebP, TIFF, BMP (an image opens as a document of its pixel size). Templates open as a new untitled document. run_command document.formats lists the formats.
save_file {path?} Saves in the native .vectorcraft format.
export {path?, format?, scale?, artboard?, range?, selection?, outlineText?, options?} svg, pdf, png, jpg, webp or vectorcraft (the list comes from document.formats). When format is omitted, it comes from the path's extension. PDF writes one page per artboard: all of them, or artboard (0-based) / range ("1-3, 5", 1-based); the other formats write one artboard. options carries more format options (e.g. {"quality": 80} for JPEG). selection: true exports the selected objects cropped to their bounds; outlineText: true writes SVG text as paths. Template layers are left out, live effects are kept, and exporting vectorcraft never changes the document's path. Without path the bytes come back as dataBase64. Both backends run the same document.export call.
add_text {text, x?, y?, width?, height?, path?, mode?, pathEffect?, size?, font?, color?} Point type at (x, y); area type with width/height; or path + mode (area/onPath) to flow text in or along a path, with pathEffect (rainbow, skew, 3dRibbon, stairStep, gravity).
apply_effect {effect?, params?, ids?} Appends a live effect. Without effect, returns the effect catalogue with parameters and defaults.
pathfinder {operation, ids?} unite, minusFront, intersect, exclude, divide, trim, merge, crop, outline, minusBack. For a live version, apply the pathfinder.* effect to a group.
transform {ids?, dx?, dy?, rotate?, scale?, scaleX?, scaleY?, reflect?, shear?, origin?, copy?} Runs move, rotate, scale, reflect, shear in that order. With copy, the first step duplicates.
create_graph {type?, x, y, width, height, csv? | series?, categories?, rows?} The nine Illustrator graph types: column, stacked column, bar, stacked bar, line, area, scatter, pie and radar. Edit later with graph.setData / graph.setType via run_command.
text_wrap {ids?, offset?, invert?, release?} Area type below the objects (same layer) flows around them.
undo / redo {}

Appearance stacks: an object can carry several fills and strokes (appearance.addFill, appearance.addStroke), indexed in paint order (0 is painted first, the bottom row of the Appearance panel). paint.setFill, paint.setStroke, stroke.set, stroke.setAdvanced, paint.editGradient, paint.setGradientGeom and transparency.set take item to edit one of them; run_command appearance.setActiveItem {"index": n} makes that row the target of later calls that omit item (as clicking the row in the Appearance panel does) until the selection changes; the proxy of its kind (paint.proxies) and the Gradient tool's annotator then show that row. inspect_document reports it as paint.appearanceItem. Live effects take the same item to apply to one fill or stroke instead of the whole object: run_command effect.apply {"effect": "path.offsetPath", "item": 0}, and effect.remove, effect.setParams (visible toggles one) and effect.duplicate address that item's effects; apply_effect uses the active item. effect.list reports each object's item effects under applied[].items.

Errors (unknown tool, bad arguments, a disabled or failing command) come back as a normal result with isError: true and a message. The model can read the message and retry.

Swatches go through run_command: swatch.list lists every swatch with its colour group, kind and colour; swatch.edit {name, newName?, color?, mode?, global?, spot?} edits one (fills, strokes and text linked to a global or spot swatch follow its colour and name, as one undo step); swatch.delete {names, unlink?} deletes swatches and colour groups in one undo step (art using a deleted global swatch keeps its colour, unlinked). swatch.new {color?, mode?, spot?, global?, group?} saves a colour (into a colour group with group), gradient or pattern; swatch.newGroup {fromArtwork: true, toGlobal?, includeTints?} makes a colour group of the selected art's colours (by default as global swatches the art links to). swatch.move {names, to?, group?} reorders swatches or moves them into or out of a colour group (as dragging them in the Swatches panel does); give colour group names instead to reorder the groups. Dropping a swatch on art in the app runs paint.setFill (or paint.setStroke, the active proxy) with ids: [the object under the pointer]. The Swatches panel menu's commands: swatch.addUsedColors {selection?, global?}, swatch.unused (a query: the names Select All Unused selects), swatch.merge {names} (the first is kept), swatch.ungroup {name} and swatch.sortByKind. Document colour mode: file.new {colorMode: "cmyk"} starts a CMYK document with CMYK default swatches, and RGB colours applied to it (paint.setFill/setStroke colours and gradient stops, swatch.new) are stored as CMYK; Gray stays Gray, and keepModel: true keeps a colour as given. RGB documents keep colours as given. Harmonies, Edit Colors blends, inversions and Recolor Artwork keep each colour's model (a blend between models takes the document's). swatch.new {colors: [...]} saves several colours as swatches in one undo step. color.harmony {color, rule, steps?, variation?, amount?} answers what the Color Guide panel shows: the harmony rule's colours, base first, and per colour its row of 2·steps+1 variations (shades, cool or muted on the left, tints, warm or vivid on the right).

Resources

URI Content
vectorcraft://document document.inspect summary (JSON)
vectorcraft://document/json The complete document model (JSON)

Examples

Draw, look, export:

{"name":"draw_shape","arguments":{"shape":"rectangle","x":72,"y":72,"width":200,"height":120,"radius":12,"fill":"#1e88e5","stroke":"none"}}
{"name":"draw_shape","arguments":{"shape":"star","cx":400,"cy":300,"radius1":90,"radius2":40,"points":5,"fill":"#ffc107","stroke":"#000000","strokeWidth":2}}
{"name":"draw_path","arguments":{"d":"M72 400 C 150 300 250 500 330 400","stroke":"#e53935","strokeWidth":4,"fill":"none"}}
{"name":"screenshot","arguments":{"scale":0.5}}
{"name":"export","arguments":{"path":"/tmp/art.svg"}}

Long-tail commands:

{"name":"list_commands","arguments":{"filter":"align"}}
{"name":"run_command","arguments":{"command":"select.all"}}
{"name":"run_command","arguments":{"command":"object.align","params":{"align":"left"}}}
{"name":"run_command","arguments":{"command":"object.group"}}

Drive a tool like a mouse:

{"name":"pointer_gesture","arguments":{"tool":"ellipse","events":[
  {"kind":"down","x":100,"y":100},{"kind":"drag","x":150,"y":140},{"kind":"up","x":200,"y":180}]}}

Edit a gradient with the Gradient tool's annotator (the bar runs along the vector; stop chips sit 10 px under it, midpoint diamonds 7 px above): a click on the bar adds a stop, dragging a chip moves it (drag it off the bar to delete it, hold Alt to copy it), dragging the end handle changes the vector. The selected stop (gradient.selectStop) takes Delete and ←/→:

{"name":"run_command","arguments":{"command":"paint.setFill","params":{"gradient":{"start":[100,150],"end":[200,150]}}}}
{"name":"pointer_gesture","arguments":{"tool":"gradient","events":[{"kind":"down","x":130,"y":150},{"kind":"up","x":130,"y":150}]}}
{"name":"pointer_gesture","arguments":{"events":[{"kind":"down","x":130,"y":160},{"kind":"drag","x":160,"y":160},{"kind":"up","x":160,"y":160}]}}
{"name":"press_key","arguments":{"key":"Delete"}}

Freeform gradients: paint.editGradient {kind: "freeform"} places four or more colour points inside each selected object (coloured along the stops; mode: "points"|"lines" is the Draw toggle). paint.freeform.get lists the points (document coordinates), lines and the selected point; paint.freeform.addPoint {at, color?, opacity?, spread?, line?}, setPoint {index?, …}, deletePoint {index?}, addLine {points}, splitLine {line, segment, t?} and selectPoint {index|null} edit them (index defaults to the selected point; each edit is one undo step). With the Gradient tool on a freeform gradient a click on a point selects it (drag to move it), a click on a line adds a point on it, a click elsewhere on the art adds a point (in Lines mode joined to the selected one), and Delete removes the selected point:

{"name":"run_command","arguments":{"command":"paint.editGradient","params":{"kind":"freeform","mode":"lines"}}}
{"name":"run_command","arguments":{"command":"paint.freeform.addPoint","params":{"at":[150,150],"color":"#ff3366","spread":20}}}
{"name":"pointer_gesture","arguments":{"tool":"gradient","events":[{"kind":"down","x":180,"y":170},{"kind":"up","x":180,"y":170}]}}

Raw protocol (for debugging):

printf '%s\n' \
  '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"sh","version":"0"}}}' \
  '{"jsonrpc":"2.0","method":"notifications/initialized"}' \
  '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"draw_shape","arguments":{"shape":"ellipse","x":10,"y":10,"width":100,"height":80,"fill":"#ff0000"}}}' \
  '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"inspect_document","arguments":{}}}' \
  | target/release/vectorcraft-cli mcp --headless

Headless batch CLI

vectorcraft-cli commands                          # command catalogue (JSON)
vectorcraft-cli run --in in.svg \
  --cmd select.all --cmd paint.setFill --params '{"color":"#ff0000"}' \
  --export out.svg --export out.png --scale 2
vectorcraft-cli run --cmd file.new --params '{"width":800,"height":600}' \
  --cmd shape.star --params '{"cx":400,"cy":300,"radius1":200,"radius2":90}' \
  --export star.vectorcraft

run prints one JSON line per step (open, cmd, export) and exits non-zero on the first failure. --params applies to the --cmd just before it. run also accepts the host commands file.open, file.save, file.export, file.exportForScreens and tool.select. run --in, convert and info read every format document.open reads (vectorcraft-cli --help lists them).

Transparency and opacity masks

Transparency and opacity-mask commands take ids (or id), so they need no selection. Opacity is a percentage (0..100) in every command (transparency.set, object.setProps, appearance.setItem). transparency.info returns the Transparency panel's values, with null where the objects differ. Making a mask from one object gives it an empty mask and enters mask editing: art drawn then becomes the mask, and the mask commands act on the masked object until transparency.stopEditingOpacityMask. Saves and exports never include the editing layer.

{"name":"run_command","arguments":{"command":"transparency.set","params":{"ids":[12],"opacity":40,"blend":"Multiply"}}}
{"name":"run_command","arguments":{"command":"transparency.makeOpacityMask","params":{"ids":[12,15],"invert":true}}}
{"name":"run_command","arguments":{"command":"transparency.setOpacityMask","params":{"id":12,"clip":false}}}
{"name":"run_command","arguments":{"command":"transparency.info","params":{"ids":[12,20]}}}

Knockout Group has three states: transparency.set {knockout: "on"|"off"|"neutral"} (true = on, false = neutral, the default). In a knockout group each child hides what it covers of the children below it; neutral groups pass the enclosing group's setting to their children, off groups never knock out. knockoutShape: true makes the object's opacity and opacity mask scale how much it knocks out. transparency.togglePageKnockoutGroup and transparency.togglePageIsolatedBlending ({value?}) treat the whole page as a knockout or isolated group; they are saved with the document and undoable, and transparency.info reports them. PDF and SVG write knockout groups as soft-masked groups with the same look (the PDF export reports a warning).

Groups are not isolated unless Isolate Blending is on: a blend mode inside a group with opacity, a blend mode, an opacity mask, knockout or a clip reaches the art below the group, on screen and in PDF (a knockout group's elements then composite against the art below it). SVG has no non-isolated groups, so there such groups stay isolated.

Clipping masks

object.clippingMask.make clips the selected objects by the topmost one, which may be a path, a compound path or a text object (it loses its paint). Compound holes, even-odd fills, glyph outlines and the union of a group's members clip alike on screen, in raster export and in SVG and PDF. object.clippingMask.release turns the clip group into a plain group and keeps the clipping path, unpainted.

{"name":"run_command","arguments":{"command":"select.set","params":{"ids":[12,15]}}}
{"name":"run_command","arguments":{"command":"object.clippingMask.make","params":{}}}

layer.clippingMask.toggle {id?} is the Layers panel's clipping mask button: the top object of the layer id (default: the one selected group, else the current layer) becomes its clipping path (unpainted, moved to the bottom of the layer, so art added later is clipped too); called again it releases the mask. It returns {clip}, and the Layers panel underlines clipping-path names.

Graphic styles

A graphic style holds an appearance (fills, strokes, effects) plus opacity, blend mode, isolate and knockout. graphicStyle.new {name?, id?} captures an object (a group without its own fills or strokes lends its topmost object's, type its characters'). graphicStyle.apply {name, ids?} gives the objects the style and links them; add: true adds the style on top of the existing appearance instead. Linked objects stay linked while they keep the style's look: editing their appearance or transparency breaks the link, and graphicStyle.redefine {name?, id?} updates only the objects still linked. graphicStyle.list returns each style with the ids linked to it and the style of the first selected object; select.same.graphicStyle selects an object's fellow users. Styles keep placed gradients relative to the bounds of the object they were made from, and each object a style is applied to gets them at the same place relative to its own bounds.

{"name":"run_command","arguments":{"command":"graphicStyle.new","params":{"id":12,"name":"Glow"}}}
{"name":"run_command","arguments":{"command":"graphicStyle.apply","params":{"name":"Glow","ids":[15,20]}}}
{"name":"run_command","arguments":{"command":"graphicStyle.redefine","params":{"id":12}}}
{"name":"run_command","arguments":{"command":"graphicStyle.list","params":{}}}

graphicStyle.merge {names, name?} adds a style stacking the fills, strokes and effects of two or more styles (each on top of the ones before it) with the first one's transparency; graphicStyle.move {name, to} reorders the list (what dragging a style in the panel does). Override Character Color (graphicStyle.setOptions {overrideCharColor}, the preference overrideCharColor, on by default) makes a style applied to type replace its characters' fill and stroke with the style's fills and strokes; off, the characters keep their colour under them.

Editing appearance stacks

effect.move {from, to, fromItem?, toItem?, copy?} reorders an effect or moves it between the object's effects (null) and a fill's or stroke's (an item index), as dragging its row in the Appearance panel does; copy: true copies it (Alt-drag). appearance.duplicateItem {index, to?} / {indices} and appearance.removeItem {index | indices} act on several fills/strokes at once, and appearance.showAllHidden makes every hidden fill, stroke and effect visible again. In remote mode, effect.dialog {effect, index, item} opens an applied effect's dialog prefilled (ui.dialog.confirm runs effect.setParams); see the control protocol for the "already applied" question.

Overprint

Each fill and stroke (and each character's fill and stroke) can overprint: its inks print over the inks below instead of knocking them out. object.setOverprint {fill?, stroke?, item?, ids?} sets it (groups set their contents, type its characters too; item aims at one appearance item) and attributes.info {ids?} reads it back (null where the objects differ). Overprint Preview (view.overprintPreview) and Separations Preview show it; rendering approximates it by multiplying. Older files that listed Overprint Black objects in the document get the flags on load.

{"name":"run_command","arguments":{"command":"object.setOverprint","params":{"ids":[12],"stroke":true}}}
{"name":"run_command","arguments":{"command":"attributes.info","params":{"ids":[12]}}}
{"name":"run_command","arguments":{"command":"view.overprintPreview","params":{"on":true}}}

Edit Colors and Recolor Artwork

edit.colors.invert, edit.colors.toCMYK, edit.colors.toGrayscale, edit.colors.toRGB, edit.colors.saturate, edit.colors.adjustBalance and recolor.apply recolour everything inside the selection (or ids) in one undo step: fills, strokes, text, gradient stops, gradient-mesh points, embedded images (a recoloured copy of the image; linked images are left alone) and the tiles of pattern fills and strokes (a recoloured copy saved as a new pattern swatch, e.g. "Dots 2"; the original pattern is untouched). includeImages: false / includePatterns: false leave images or patterns out. The Blend commands also grade gradient meshes, which keep their shading.

{"name":"run_command","arguments":{"command":"recolor.colors","params":{}}}
{"name":"run_command","arguments":{"command":"recolor.apply","params":{"map":{"#ff0000":"#0055ff"},"includeImages":false}}}
{"name":"run_command","arguments":{"command":"edit.colors.adjustBalance","params":{"mode":"cmyk","m":-20,"k":10}}}

Group, layer and type appearance

Groups and layers carry fills, strokes and effects of their own, as in the reference app: their fills and strokes paint every member's geometry, and their effects apply to the members as one piece (one combined drop shadow; a Transform or Warp moves or bends the whole group). Their Contents row (type: Characters) is a slot in the stack: fills and strokes above it paint over the members (characters), those below under them; new items go above it. appearance.moveItem {"from": "contents", "to": n} puts the row above the bottom n items, and an item move takes contents to say where the row ends up in the same undo step; document.node shows the slot as appearance.contents_index. The appearance.*, effect.* and graphicStyle.apply commands edit the selected objects themselves (a group's own stack; layers through ids) or, with target: "contents", the objects inside the groups and layers. appearance.targetContents selects a group's members (double-clicking the Contents row). SVG and PDF export bake a group's own fills, strokes and geometry effects into paths; its raster effects stay a filter on the whole group.

{"name":"run_command","arguments":{"command":"appearance.addFill","params":{"ids":[7]}}}
{"name":"run_command","arguments":{"command":"appearance.moveItem","params":{"ids":[7],"from":"contents","to":1}}}
{"name":"run_command","arguments":{"command":"effect.apply","params":{"ids":[2],"effect":"stylize.dropShadow"}}}
{"name":"run_command","arguments":{"command":"appearance.addStroke","params":{"ids":[7],"target":"contents"}}}

## Swatch libraries

Swatch libraries are read-only sets of swatches computed in code (Web Safe 216, Grays and Neutrals, Earth Tones,
Skin Tone Ramps, Pastels, Brights, Metallic Gradients, Perceptual Scales, Harmony Sets). `swatch.library.list` lists
them (`id`, `name`, `category`, `count`) and `swatch.library.get {library}` returns one's swatches and colour groups
in the `swatch.list` shape (`library` is an id or a name). `swatch.library.add {library, names?}` copies swatches
into the document as one undo step: a colour group's name brings the whole group, a swatch's name the swatch alone,
no names the whole library; swatches the document already has (same name and paint) are reported under `existing`
and not added again. `apply: "fill"|"stroke"` also applies the first one, in the same undo step (what clicking a
swatch in the library panel does). `swatch.resetDefaults {replace?}` brings back the missing default swatches.

```json
{"name":"run_command","arguments":{"command":"swatch.library.get","params":{"library":"earth-tones"}}}
{"name":"run_command","arguments":{"command":"swatch.library.add","params":{"library":"earth-tones","names":["Clay"]}}}

swatch.library.save {path?, format?: "vcswatches"|"gpl"|"css", names?, name?, user?} writes the document's swatches as a library (.vcswatches keeps colour models, global, spot, gradients and colour groups; .gpl is 8-bit RGB; CSS writes custom properties); without path it returns {data}, and user: true saves into the user library folder of the desktop app (listed as category user, User Defined). swatch.library.load {path? | data? | dataBase64?, name?} loads a .vcswatches or .gpl file, or another document's swatches, as a library to add from.

Strokes on type

stroke.set without an item gives type its characters' stroke: weight, cap, join, miter limit and the dash options go to every run (the object keeps no stroke of its own); an item still edits an object-level stroke added with appearance.addStroke, which takes every stroke option (dashes, profile, opacity, blend) like a path's and paints under or over the characters as its place relative to the Characters row says. To stroke some characters, use text.setRangeStyle {id, start, end, strokeOptions: {weight?, cap?, join?, miterLimit?, dash?, dashOffset?, alignDashes?}}. inspect_document reports each object's stroke as strokeOptions (type: its first run's) in stroke.set terms. stroke.set on a group leaves the images and symbol instances in it alone.

Flatten Transparency

object.flattenTransparency {ids?, preset?, …options} turns transparent art into opaque art that looks the same, in one undo step. The targets split into groups of overlapping objects; groups without transparency stay as they are. Each other group becomes one group of atomic regions: paths filled with the flat colour the art showed there (over white; over nothing, keeping alpha, with preserveAlpha: true), plus one image where gradients, patterns, images, opacity masks or raster effects reach (clipped to those regions with clipComplexRegions, a rectangle without). preset is high, medium (the default) or low; option keys (balance 0–100, lineArtPpi, gradientPpi, textToOutlines, strokesToOutlines, clipComplexRegions, antiAlias, preserveAlpha, preserveOverprints) override it, at the top level or in options. balance: 0 rasterizes everything; lower balances rasterize groups that split into many regions. The result reports {ids, vector, rasterized, options}.

{"name":"run_command","arguments":{"command":"object.flattenTransparency","params":{"ids":[12,15],"preset":"high"}}}
{"name":"run_command","arguments":{"command":"object.flattenTransparency","params":{"balance":0,"lineArtPpi":150}}}

## Pattern editing display

In pattern editing mode the tile edge (`pattern.options {showTileEdge}`) and the swatch bounds (`pattern.options
{showSwatchBounds}`: the part of the tiling the swatch repeats, dashed) are drawn in the preference
`patternTileEdgeColor`.

```json
{"name":"run_command","arguments":{"command":"pattern.options","params":{"showSwatchBounds":true}}}
{"name":"run_command","arguments":{"command":"prefs.set","params":{"key":"patternTileEdgeColor","value":"#ff4f4f"}}}