mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-09 04:54:45 +00:00
Merge main into perf/contours-cover-lists
This commit is contained in:
@@ -100,7 +100,7 @@ the two can still win that race.
|
||||
| `ui.key` / `ui.text` | `{key, shift?, alt?, cmd?}` / `{text}` | synthetic keyboard input |
|
||||
| `ui.move` | `{x, y}` | screen-point pointer move |
|
||||
| `ui.click` / `ui.drag` | `{x, y, button?, count?, shift?, alt?, ctrl?, cmd?}` / `{x, y, toX, toY, steps?, count?, button?, shift?, alt?, ctrl?, cmd?}` | egui pointer input; see synthetic input budgets above |
|
||||
| `ui.wheel` | `{x, y, dy?, dx?, unit?: "line"\|"point", shift?, alt?, cmd?}` | a mouse wheel turn over screen point (x, y): `dy` notches up (+) or down, `dx` sideways. Over the canvas the wheel scrolls and Cmd- or Alt-wheel (Option on the Mac) zooms about the pointer; with the `zoomWithMouseWheel` preference the wheel and Alt-wheel zoom about the pointer, Shift-wheel scrolls up and down and Cmd-wheel (Ctrl on Windows and Linux) sideways. Over a focused numeric field (click it first) each notch steps its value as Up/Down do (Shift: ten, Cmd/Ctrl: a tenth) and the panel stays put; over anything else in a panel the wheel scrolls it |
|
||||
| `ui.wheel` | `{x, y, dy?, dx?, unit?: "line"\|"point", shift?, alt?, cmd?}` | a mouse wheel turn over screen point (x, y): `dy` notches up (+) or down, `dx` sideways. Over the canvas the wheel scrolls, Cmd-wheel (Ctrl on Windows and Linux) scrolls sideways and Alt-wheel (Option on the Mac) zooms about the pointer (with the `ctrlWheelScrollsSideways` preference off, Cmd-wheel zooms too); with the `zoomWithMouseWheel` preference the wheel and Alt-wheel zoom about the pointer, Shift-wheel scrolls up and down and Cmd-wheel (Ctrl on Windows and Linux) sideways. Over a focused numeric field (click it first) each notch steps its value as Up/Down do (Shift: ten, Cmd/Ctrl: a tenth) and the panel stays put; over anything else in a panel the wheel scrolls it. Over the canvas, the wheel preferences in `docs/mcp.md` change what these keys do |
|
||||
| `ui.set` | `{brightness?, panel?, rulers?, outline?, grid?, smartGuides?, boundingBox?, controlBar?, imageTracePreview?}` | `outline`: View › Outline for the active document only (each document has its own, a document opens in Preview, and `ui.inspect` shows it as `view.outline`; an error without a document). `imageTracePreview`: the Image Trace panel's Preview (`ui.inspect` shows it as `ui.image_trace_preview`) |
|
||||
| `ui.dialog.set` / `.confirm` / `.cancel` | `{field, value}` or `{fields: [{field, value}…]}` | fill and submit the open dialog. `ui.dialog.set` takes the fields the dialog has (`ui.inspect`), `__` fields, `discard` on a dialog with a discard button, `preview` on one with a live preview, the fields that the dialog reads but adds only when a control changes (such as `searchFolder`, or `copy` in the Transform dialogs), and the fields it passes to the command it runs: every parameter of the `command` dialog's command (`ui.paramDialog`), and the `textureImage` that Load Texture… sets in the Glass and Texturizer effects; any other field is an error that lists the dialog's fields, and the dialog stays as it was `fields` sets the list (at most 256 items) in order (a missing `value` is `null`) and checks every item first: when one is refused, the call is an error and no field changes |
|
||||
| `ui.screenshot` | `{path?, data?}` | capture the window (PNG), written to `path`; `data: true` sends it back as `pngBase64` too. The inline PNG is capped at 64 MiB: with a `path` the file is still written and `pngBase64` is omitted when the image is larger, while a path-less `data: true` request fails if either the raw RGBA image or the encoded PNG exceeds the cap. Needs a presented frame: with the screen locked or the window minimized/covered it fails after ~8 s with an explanatory error |
|
||||
@@ -126,7 +126,7 @@ the two can still win that race.
|
||||
| `engine.execute` `file.exportSelection` | `{multiple?}` | File › Export Selection…: collects the selected objects as one asset (`assets.add`; one per object with `multiple: true`) and opens `exportForScreens` on its Assets tab with just them checked → `{assets}`. `document.exportSelection` still exports the selection in one go, without the dialog |
|
||||
| CSS Properties panel | `window.panel {panel: "cssProperties"}`; `engine.execute` `css.copy` / `css.exportFile` | the panel shows `css.selection` of the selection (after Generate CSS, while nothing is selected, `css.generate`); its menu holds the options the commands take (`units`, `position`, `dimensions`, `unnamed`, `rasterize`). `css.copy {scope?, …options}` copies the CSS to the clipboard → `{css, rules}`; `css.exportFile {path?, scope?, …options}` writes `css.export` to `path` (else a picked file; the web downloads it) with the pictures of rasterized art next to it → `{path, rules, images, warnings}`, and the status bar shows the first of `warnings` as Export As shows an export's notes |
|
||||
|
||||
| `ui.dialog.*` on `importPdf` | `{field: "page" \| "allPages" \| "range" \| "cropTo" \| "password", value}` | opening (`app.open`, `file.open`) a PDF or `.ai` with several pages or a password, or placing one (`file.place` without `page`), opens the Import PDF dialog (`mode`: `open` or `place`; `pageCount`). While `__locked` is true, set `password` and `ui.dialog.confirm` to unlock it (a one-page file then opens or is placed). Then set `allPages: false` and `range` ("2-3, 5") to open some pages, or `page` to place one, and `cropTo` (`bounding`, `art`, `crop`, `trim`, `bleed`, `media`); `ui.dialog.confirm` opens or places them (placing keeps the other `file.place` params, such as `link`, `template` and `at`, in `__place`). `document.open {pages, cropTo, password}` and `file.place {page, crop, password}` do the same without the dialog |
|
||||
| `ui.dialog.*` on `importPdf` | `{field: "page" \| "allPages" \| "range" \| "cropTo" \| "password", value}` | opening (`app.open`, `file.open`) a PDF, `.ai` or `.ait` with a password, or one with several pages unless it is a `.ai` or `.ait` with its editing data or carries its VectorCraft document (those open whole), or placing (`file.place` without `page`) any of them with several pages or a password, opens the Import PDF dialog (`mode`: `open` or `place`; `pageCount`). While `__locked` is true, set `password` and `ui.dialog.confirm` to unlock it (a one-page file then opens or is placed). Then set `allPages: false` and `range` ("2-3, 5") to open some pages, or `page` to place one, and `cropTo` (`bounding`, `art`, `crop`, `trim`, `bleed`, `media`); `ui.dialog.confirm` opens or places them (placing keeps the other `file.place` params, such as `link`, `template` and `at`, in `__place`). `document.open {pages, cropTo, password}` and `file.place {page, crop, password}` do the same without the dialog |
|
||||
|
||||
Swatch editors: `engine.execute` with `ui.swatchOptions {name}` opens the `swatchOptions` dialog for a colour swatch
|
||||
(fields `name`, `spot`, `global`, `mode`: `gray`/`rgb`/`hsb`/`lab`/`cmyk`/`web`, `color`: `"#rrggbb"` or a colour object,
|
||||
@@ -328,7 +328,15 @@ not commands, so drive them with `ui.click` if needed. Close runs `app.quit` (th
|
||||
modified documents), and empty bar space and the 5 pt window edges move and resize the window. Preferences › User
|
||||
Interface › System Title Bar (`systemTitleBar`, read when the app starts) gives the window its OS decorations back
|
||||
instead: the OS title then shows the active document (`*name — VectorCraft` with unsaved changes) and the app bar
|
||||
drops its brand mark. On macOS the window buttons are centred on the app bar; the web build is unchanged.
|
||||
drops its brand mark. On Linux the app bar also drops its brand mark whenever the desktop draws the window's frame, with
|
||||
System Title Bar on or off. On macOS the window buttons are centred on the app bar; the web build is unchanged.
|
||||
|
||||
On Linux and the BSDs, Preferences › User Interface › VectorCraft Title Bar on Every Desktop (`appTitleBar`, read
|
||||
when the app starts, off by default) turns off the desktop's frame and uses the app bar as the title bar in the
|
||||
sessions where the desktop would draw the frame: X11 sessions, Wayland compositors that draw server-side decorations
|
||||
such as KDE Plasma, and a window opened through XWayland. System Title Bar and `VECTORCRAFT_TITLEBAR` (`app`, or
|
||||
`system` or `desktop`) take precedence over it. The checkbox is dimmed while either applies, and a note under it names
|
||||
each one that applies.
|
||||
|
||||
Fill/Stroke chips and panel shortcuts: the Control bar's and Properties' Fill and Stroke chips bring their proxy
|
||||
forward (`paint.toggleActive {fill}`) and open a popover with the Swatches panel (Shift-click: the Color panel's mixer);
|
||||
@@ -428,7 +436,9 @@ below). Dragging a tab, a group's drag bar or an icon out of the dock and droppi
|
||||
floats it; dropping it on a group's tabs, on a group's upper or lower edge or beside a column docks it there. On
|
||||
the desktop each floating window is an OS window of its own; on the web and on Wayland it floats inside the app
|
||||
window. `ui.toolbar_pos` in `ui.inspect` is the Tools panel's corner (null: docked); `window.panel.float` and
|
||||
`window.panel.dock` with `panel: "tools"` float it at `x`, `y` or dock it on the window's left edge.
|
||||
`window.panel.dock` with `panel: "tools"` float it at `x`, `y` or dock it on the window's left edge. With
|
||||
`window.toolsBesideCanvas {on?}` (Window › Toolbars › Keep Tools Beside the Canvas, off by default; `ui.tools_beside_canvas`)
|
||||
the docked Tools panel sits between left-side panels and the canvas, and `window.panel.dock` docks it there.
|
||||
|
||||
Flatten Transparency: `ui.flattenTransparencyDialog` opens the `flattenTransparency` dialog for the selection
|
||||
(fields `preset`: a preset name, setting it loads that preset's options; the option keys of
|
||||
@@ -666,9 +676,11 @@ with.
|
||||
|
||||
DXF Options: Export As… with the DXF format (`file.exportAs {format: "dxf"}`, then the save dialog), or
|
||||
`ui.dxfOptionsDialog {path?, …document.exportDxf options}` for agents, opens the `dxfOptions` dialog. Its fields are
|
||||
`document.export` params: `version`, `unit` (a unit name such as `Millimeters`), `scale`, `scaleLineweights`, `colors`
|
||||
(`8`, `16`, `256`, `true`), `rasterFormat` (`png`, `jpeg`), `preserve` (`appearance`, `editability`), `selectedOnly`,
|
||||
`alterPaths`, `outlineText`, plus `path` and the artboard choice. `ui.dialog.confirm` checks them (a bad value, or
|
||||
`document.export` params: `dxfPreset` (`custom`, `cnc`), `version`, `unit` (a unit name such as `Millimeters`), `scale`,
|
||||
`scaleLineweights`, `colors` (`8`, `16`, `256`, `true`), `rasterFormat` (`png`, `jpeg`), `preserve` (`appearance`,
|
||||
`editability`), `selectedOnly`, `alterPaths`, `outlineText`, plus `path` and the artboard choice. Setting `dxfPreset` to
|
||||
`cnc` sets the fields it sets (see `document.exportDxf`), and `dxfPreset` reads `custom` again once one of them is
|
||||
changed; setting it to `custom` puts back the defaults. `ui.dialog.confirm` checks them (a bad value, or
|
||||
Export Selected Art Only with nothing selected, keeps the dialog open), remembers them for the next DXF Options and
|
||||
writes the file (asking for a path when there is none). Export As also lists DWG, greyed out: setting its `format` to
|
||||
`dwg` shows, and on confirm answers, the hint to export DXF instead.
|
||||
|
||||
+1
-1
@@ -118,7 +118,7 @@ A file opened from the file manager (double-click, Open With, a drop on the exec
|
||||
|
||||
## Linux: Wayland and X11
|
||||
|
||||
On GNOME/Wayland, enable **Preferences › User Interface › System Title Bar** and restart to use winit's font-free Adwaita window controls (`wayland-csd-adwaita-notitle`); the existing custom title bar remains the Linux default.
|
||||
On GNOME/Wayland, enable **Preferences › User Interface › System Title Bar** and restart to use winit's font-free Adwaita window controls (`wayland-csd-adwaita-notitle`); the existing custom title bar remains the Linux default. On X11, on a Wayland compositor that draws server-side decorations such as KDE Plasma, and in a window opened through XWayland, enable **Preferences › User Interface › VectorCraft Title Bar on Every Desktop** and restart to use the app bar as the title bar instead of the desktop's frame. `VECTORCRAFT_TITLEBAR=app`, `=system` or `=desktop` chooses the frame for one run and takes precedence over VectorCraft Title Bar on Every Desktop.
|
||||
|
||||
The window runs natively on Wayland (eframe's `wayland` feature) and on X11. On machines with two GPUs it renders on the one the desktop runs on unless Preferences say otherwise; see [Desktop graphics processor](#desktop-graphics-processor) (#502). The system clipboard (`apps/vectorcraft/src/clipboard.rs`) is arboard with its `wayland-data-control` feature:
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Effects parity
|
||||
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-06 · **Change:** minor (Extrude & Bevel, Inflate and Rotate apply to groups and layers, their objects turning about one shared axis (#4506); the Transform effect's copies of a path with a fill and a stroke (or several fills and strokes, an even-odd fill, or a partly transparent one) are drawn each above the one before, as Expand Appearance makes them (#5920); Expand Appearance makes each copy of a path's Transform effect an object of its own (#5612); previously: Pixelate › Color Halftone: Max Radius in pixels of the Document Raster Effects resolution, 4–127 px, with older documents converted on opening and radii written back in points for older app versions (#3260); Effect dialogs clamp bounded length inputs immediately on commit and flash rejection on invalid input (#4638); previously: Drop Shadow Darkness uses fixed RGB subtraction and CMYK black addition; scores unchanged; Pathfinder › Trap: the Pathfinder panel's Trap… and Effect › Pathfinder › Trap… add an overprinting strip of the lighter colour where two solid colours meet; recounted with Hard Mix (#3061) and Soft Mix already in the catalogue: Pathfinder 13/13, Illustrator effects 49/50) · **Target:** Adobe Illustrator 2026 (30.x)
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-08 · **Change:** minor (Extrude & Bevel, Inflate and Rotate merge contours that cross, touch or overlap, as type often draws a glyph, before building a solid; previously: Extrude & Bevel, Inflate and Rotate apply to groups and layers, their objects turning about one shared axis (#4506); the Transform effect's copies of a path with a fill and a stroke (or several fills and strokes, an even-odd fill, or a partly transparent one) are drawn each above the one before, as Expand Appearance makes them (#5920); Expand Appearance makes each copy of a path's Transform effect an object of its own (#5612); previously: Pixelate › Color Halftone: Max Radius in pixels of the Document Raster Effects resolution, 4–127 px, with older documents converted on opening and radii written back in points for older app versions (#3260); Effect dialogs clamp bounded length inputs immediately on commit and flash rejection on invalid input (#4638); previously: Drop Shadow Darkness uses fixed RGB subtraction and CMYK black addition; scores unchanged; Pathfinder › Trap: the Pathfinder panel's Trap… and Effect › Pathfinder › Trap… add an overprinting strip of the lighter colour where two solid colours meet; recounted with Hard Mix (#3061) and Soft Mix already in the catalogue: Pathfinder 13/13, Illustrator effects 49/50) · **Target:** Adobe Illustrator 2026 (30.x)
|
||||
|
||||
Every entry of Illustrator's Effect menu, by its public feature name, against VectorCraft's effects catalogue
|
||||
(`effect_catalog()` in `crates/effects/src/lib.rs`) and the Effect menu built from it
|
||||
@@ -11,7 +11,7 @@ Part of [target-app-parity.md](target-app-parity.md); open work is in [gaps.md](
|
||||
|
||||
| Group | Illustrator | VectorCraft | % | Remaining (h) |
|
||||
|---|---:|---:|---:|---:|
|
||||
| Illustrator effects (vector and stylize) | 50 | 49 | 98% | 4–8 |
|
||||
| Illustrator effects (vector and stylize) | 50 | 50 | 100% | — |
|
||||
| Photoshop effects (raster, Effect Gallery) | 57 | 57 | 100% | 1–2 (Effect Gallery thumbnails and in-dialog preview) |
|
||||
| 3D and Materials | 4 (+3 Classic) | 4 (initial: Extrude & Bevel, Revolve, Inflate, Rotate) | ~25% | 25–45 |
|
||||
| Beyond Illustrator: Effect › Color Adjustments (6), effect plug-ins (WebAssembly) | — | 6 + plug-ins | — | — |
|
||||
@@ -27,7 +27,7 @@ Part of [target-app-parity.md](target-app-parity.md); open work is in [gaps.md](
|
||||
| Pathfinder | Add, Intersect, Exclude, Subtract, Minus Back, Divide, Trim, Merge, Crop, Outline, Hard Mix, Soft Mix, Trap | 13/13 | Trap traps only solid fills (gradients and patterns hide what is below them but don't trap) and spreads each colour's visible area as a whole; the public page gives no default values, so Trap's 0.25 pt, 100% and 40% are VectorCraft's own |
|
||||
| Rasterize | Rasterize… (as a live effect) | 1/1 | — |
|
||||
| Stylize | Drop Shadow, Feather, Inner Glow, Outer Glow, Round Corners, Scribble | 6/6 | Scribble Options' Settings presets |
|
||||
| SVG Filters | Apply SVG Filter… and the filter list | 0/1 | the whole submenu (SVG filters on import round-trip already) |
|
||||
| SVG Filters | Apply SVG Filter… and the filter list | 1/1 | The submenu lists the document's own filters: VectorCraft ships no default filters. A filter that is the object's last effect is written to SVG as a `<filter>` element; otherwise SVG export draws the object as an image. A filter on a turned or skewed object in an imported SVG is left out with a warning |
|
||||
| Warp | Arc, Arc Lower, Arc Upper, Arch, Bulge, Shell Lower, Shell Upper, Flag, Wave, Fish, Rise, Fisheye, Inflate, Squeeze, Twist | 15/15 | warp point editing in envelopes; Arc is a circular arc in the object's own proportions (#1578) |
|
||||
|
||||
Document Raster Effects Settings exists. When the 64 million pixel cap on an effect image lowers
|
||||
@@ -179,20 +179,21 @@ VectorCraft choices; an original approximation, never compared with another appl
|
||||
| Item | Ours |
|
||||
|---|---|
|
||||
| Revolve | initial: live, editable profile, rotation and light gizmos, default-on Cap with continuous curved rims, smooth vector shading and round seam joins, SVG/PDF output, Expand Appearance ([revolve.md](revolve.md), #846) |
|
||||
| Extrude & Bevel, Inflate, Rotate | initial: live, depth, twist, taper, solid or hollow caps, five original bevel shapes, Inflate volume, both sides, twist, taper and cap, Rotate of every fill and stroke, groups and layers turned about one shared axis (#4506), Position presets, rotation and light gizmos, SVG/PDF output, Expand Appearance ([three-d.md](three-d.md)) |
|
||||
| Extrude & Bevel, Inflate, Rotate | initial: live, depth, twist, taper, solid or hollow caps, five original bevel shapes, Inflate volume, both sides, twist, taper and cap, Rotate of every fill and stroke, groups and layers turned about one shared axis (#4506), contours that cross, touch or overlap merged first ([three-d.md](three-d.md)), Position presets, rotation and light gizmos, SVG/PDF output, Expand Appearance ([three-d.md](three-d.md)) |
|
||||
| Materials panel, lighting, ray-traced render | Window › 3D and Materials panel with the object types (Plane, Extrude, Revolve, Inflate) and the Object, Rotation and Lighting settings of the applied effect ([three-d.md](three-d.md#3d-and-materials-panel)); one to ten directional lights with per-light Color (opaque RGB, white by default), Intensity, Rotation, Height, Softness and neutral Ambient Light, Revolve and colored Inflate use smooth vector shading; Extrude & Bevel and Rotate retain planar shading; original Standard, Diffuse, Top Left and Right lighting rigs; no materials, shadows or ray tracing |
|
||||
| 3D (Classic): Extrude & Bevel, Revolve, Rotate | none |
|
||||
| Turntable (30.0 beta) | none |
|
||||
| Export 3D objects (OBJ, USDA, glTF) | none |
|
||||
| Export 3D objects (OBJ, USDA, glTF) | initial: Asset Export's Export 3D Object collects an object with Extrude & Bevel, Revolve, Inflate or Rotate as a 3D asset, and Export writes its solids as a USDA (the default), USDZ, glTF or OBJ mesh with a material in each solid's paint color (`assets.add3D`, `assets.set3DFormat`, `assets.export3D`); no textures, map art or shading ([3D export help](https://helpx.adobe.com/illustrator/desktop/special-effects-styles/create-3d-graphics/export-3d-vector-artwork.html)) |
|
||||
|
||||
The `three-d` crate (depends on `geom` and `pathops`, with no UI or GPU dependencies) builds, rotates, projects, shades and depth-sorts the surfaces;
|
||||
the effects crate turns them into art. What's left (materials and shadows, ray-traced rendering,
|
||||
angular cut caps, exact visibility, 3D Classic, Turntable, 3D export) is 25–45 h.
|
||||
angular cut caps, exact visibility, 3D Classic, Turntable) is 25–45 h.
|
||||
|
||||
## Revision history
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-11-08 | minor | Extrude & Bevel, Inflate and Rotate merge contours that cross, touch or overlap (a glyph's arm across its stem) before building a solid, so the solid follows the shape as it is filled; others are built as drawn ([three-d.md](three-d.md)); scores and estimates unchanged |
|
||||
| 2026-11-06 | minor | Extrude & Bevel, Inflate and Rotate apply to a group or layer: a solid for every path, compound path and type in it, all turned about one shared axis as the public documentation describes for groups ([three-d.md](three-d.md#groups), #4506); scores and estimates unchanged |
|
||||
| 2026-11-06 | minor | The Transform effect's copies of a path or compound path whose fills and strokes stack (a fill and a stroke, several of either, an even-odd fill, or a partly transparent or blended one) are drawn each as an object of its own above the one before, as Expand Appearance makes them, instead of one path of every copy whose fill lay under every copy's stroke (#5920). A single opaque stroke or nonzero fill still draws as one path. Counts unchanged. |
|
||||
| 2026-11-04 | minor | Expand Appearance of a path or compound path whose Transform effect makes copies gives a group of one object per copy, each with the path's fills and strokes, instead of one compound path of every copy; copies of copies nest (#5612). Counts unchanged. |
|
||||
|
||||
+44
-11
File diff suppressed because one or more lines are too long
+9
-15
@@ -1,9 +1,10 @@
|
||||
# Gaps
|
||||
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-07 · **Change:** minor (Indian-language hyphenation review and license allowlist, #4947; opening a slow file shows a progress window, part of #5930; Hindi catalog and contributor loanword preferences; agent wording pass complete; wider native proofreading welcome; an image zoomed in on is separated, colorized or proofed only where it shows (#4155); scores and estimates unchanged; a document's first frame renders on the render worker, so opening a heavy file no longer freezes the window; scores and estimates unchanged; large images in CMYK documents are shrunk before they are separated into ink planes (#4155); scores and estimates unchanged; `.ai` paths with a Calligraphic brush open brushed, with the 6D Art Pen's channels, and Windows reads the pen's tilt and barrel rotation, #372; scores and estimates unchanged; Compound Shapes add-on, beyond Illustrator; scores and estimates unchanged; Contour add-on, beyond Illustrator; scores and estimates unchanged; a slow first frame is waited for instead of restarting without the graphics adapter, and the menu bar no longer waits for the installed fonts' scan; scores and estimates unchanged) · **Target:** Adobe Illustrator 2026 (30.x)
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-07 · **Change:** minor (Tools stays beside the canvas with left-side panels; new gradients follow document color mode; Selection QoL: marquee modes and visible feedback, #5313; Indian-language hyphenation review and license allowlist, #4947; opening a slow file shows a progress window, part of #5930; Hindi catalog and contributor loanword preferences; agent wording pass complete; wider native proofreading welcome; an image zoomed in on is separated, colorized or proofed only where it shows (#4155); scores and estimates unchanged; a document's first frame renders on the render worker, so opening a heavy file no longer freezes the window; scores and estimates unchanged; large images in CMYK documents are shrunk before they are separated into ink planes (#4155); scores and estimates unchanged; `.ai` paths with a Calligraphic brush open brushed, with the 6D Art Pen's channels, and Windows reads the pen's tilt and barrel rotation, #372; scores and estimates unchanged; Compound Shapes add-on, beyond Illustrator; scores and estimates unchanged; Contour add-on, beyond Illustrator; scores and estimates unchanged; a slow first frame is waited for instead of restarting without the graphics adapter, and the menu bar no longer waits for the installed fonts' scan; scores and estimates unchanged) · **Target:** Adobe Illustrator 2026 (30.x)
|
||||
|
||||
## Feature submission evidence
|
||||
|
||||
**Feature evidence last updated:** 2026-11-02.
|
||||
| 2026-11-06 | minor | Opening a file that takes longer than 0.4 s shows a progress window: the file name, a moving bar (reading reports no steps), how many more files wait, Cancel (Esc; the file doesn't open) and Continue in Background (`file.cancelOpen`, `file.openInBackground`); it never opens over another dialog or progress window (part of #5930); scores and estimates unchanged |
|
||||
Raster rendering fits and preflattens curved stroke outlines more tightly only below four times the raster tolerance, retaining thin-band coverage without changing stroke weight or vector export geometry. Current cached character/object outlines, cropped long strokes, gradient clips and effect rasters share the helper; cropped-region reuse and guarded flattening remain. The unchanged `fractional_curved_strokes_retain_coverage_between_notches` regression covers fractional weights, rotation, phase, opacity and f32-rounded endpoints. This is a quality/cost tradeoff, not a speed claim. Scores and estimates unchanged.
|
||||
|
||||
@@ -37,6 +38,8 @@ Artboard Options forwards the active Artboard tool's Scale Artwork with Artboard
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-11-03 | minor | Docked Tools stays between left-side panels and the canvas; redocking accepts canvas and window edges. Requested layout choice; scores and estimates unchanged. |
|
||||
| 2026-11-02 | minor | Selection QoL: saved marquee modes, screen drag direction with a 3 px dead zone, and translated mode/E feedback (#5313); VectorCraft addition, scores and estimates unchanged. |
|
||||
| 2026-11-07 | minor | Indian-language hyphenation (#4947): eleven MIT-licensed pattern sets, with grapheme and shaping-cluster protection in both composers and existing paragraph limits. Assamese and Sanskrit are selectable; Sanskrit automatic patterns remain pending an allowlisted source. Scores and estimates unchanged. |
|
||||
| 2026-11-05 | minor | G15: long open strokes with an undashed width profile are outlined near the view while keeping profile positions on the full path; a 200,000-segment outline took 59.95 ms before and 8.44 ms after in local median runs. Closed and dashed profile strokes remain whole; estimate unchanged. |
|
||||
| 2026-11-05 | minor | G15: Direct Selection reuses one document hit result when choosing the cursor over a path; a 200,000-anchor path's segment cursor took 58.15 ms before and 29.33 ms after in local median runs. Cursor behavior is unchanged; estimate unchanged. |
|
||||
@@ -184,7 +187,7 @@ from G14 and the budget run of G15: **~170–270 h** one agent, ~50–80 h wall
|
||||
|
||||
## G9 Illustrator `.ai` and EPS files from real users
|
||||
|
||||
- **Done (2026-10-30):** from an audit of a user's `.ai`/EPS files: All Caps and Small Caps; placed files at their box's corner; pages cropped to the art; gradient mesh corners with handle weights of 0 and the transparency written after a mesh, a masked mesh and a blend; a layer's state block with the stroke style; type on a path spaced as the file lays it out (the distance from the path under Align to Path comes from VectorCraft's font metrics, and the fit under Gravity does not reproduce the file's layout); EPS10 legacy-format type; a PDF of some artboards compared on the artboard its page shows. Comparison limits remain unchanged. This narrows G9; scores and estimates unchanged.
|
||||
- **Done (2026-10-30):** from an audit of a user's `.ai`/EPS files: All Caps and Small Caps; placed files at their box's corner; pages cropped to the art; gradient mesh corners with handle weights of 0 and the transparency written after a mesh, a masked mesh and a blend; a layer's state block with the stroke style; type on a path spaced as the file lays it out (the distance from the path under Align to Path is measured from the top of each character's em box, half the height of the top of its H or the bottom of its font's bounding box, and the fit under Gravity does not reproduce the file's layout); EPS10 legacy-format type; a PDF of some artboards compared on the artboard its page shows. Comparison limits remain unchanged. This narrows G9; scores and estimates unchanged.
|
||||
|
||||
- **Save-back update (2026-10-26):** ordinary EPS Save retains page margins and the whole editable document; source-loss confirmation remains. Import fidelity gaps and estimates below are unchanged.
|
||||
|
||||
@@ -621,9 +624,9 @@ from G14 and the budget run of G15: **~170–270 h** one agent, ~50–80 h wall
|
||||
as a `.vectorcraft` library into the user library folder (listed under User Defined) or a file
|
||||
(`brush.libraries`, `brush.addFromLibrary`, `brush.saveLibrary`, `brush.loadLibrary`).
|
||||
- **Missing:** the Art brush's Overlap; more built-in brush, symbol and graphic-style libraries (original,
|
||||
generated in code, never Adobe's); dynamic symbols' on-canvas editing (Direct Selection of an object inside a
|
||||
dynamic instance, with the Fill/Stroke controls and Appearance panel then setting its change) and their `.ai`
|
||||
read and write; Global Edit of groups holding type or
|
||||
generated in code, never Adobe's); dynamic symbols' on-canvas editing beyond a solid fill and stroke on a path,
|
||||
compound path or type object inside a dynamic instance (Direct Selection selects it, and the Fill/Stroke controls set
|
||||
its change) and their `.ai` read and write; Global Edit of groups holding type or
|
||||
images, rotated copies as matches, Shift-click to leave a match out and highlighting matches before the start;
|
||||
9-slice guides outside the symbol's art (a dragged guide stops at the art's edge).
|
||||
- **Estimate:** 14–24 h.
|
||||
@@ -634,7 +637,7 @@ from G14 and the budget run of G15: **~170–270 h** one agent, ~50–80 h wall
|
||||
Extrude & Bevel, Inflate and Rotate with Position presets ([three-d.md](three-d.md), #1407). Colored Inflate has automatic smooth vector lighting from shared membrane normals. White-light Inflate keeps its existing appearance. All four take one to ten colored directional lights, with neutral ambient applied once, a light list and independent previewing controls. Standard, Diffuse, Top Left and Right select original rigs, shared with commands; manual settings show Custom.
|
||||
- **Missing:** materials (base, Substance, graphics), shadows,
|
||||
ray-traced rendering, angular cut caps, exact visibility for intersecting and concave surfaces, 3D Classic,
|
||||
Turntable, 3D export (OBJ, USDA, glTF).
|
||||
Turntable, textures, map art and shading in 3D export.
|
||||
- **Impact:** specialist; Materials is the one menu stub left.
|
||||
- **Estimate:** 25–45 h; plan in `plan/` before coding.
|
||||
|
||||
@@ -899,15 +902,6 @@ trap, and the defaults (0.25 pt, 100%, 40%) are VectorCraft's own, the pages giv
|
||||
| 2026-10-22 | minor | Affinity import: master pages, tables, paragraph formats, text scale, shadows, glows, outlines, overlays, underlines, strikethrough, CMYK pixel layers through the document's profile and editable embedded documents, text placed as Affinity places it (AF.5, from storytold/designcraft#291). No entry closed, estimates unchanged. Hostile files stay bounded: one budget for the whole read (layers, pixels, characters, table cells, embedded documents included), a work budget for overlays, capped master page copies, objects past `MAX_COORD` left out; the import fuzzer and limit tests cover tables, paragraphs, effects, overlays, master pages, CMYK pixels and embedded documents. |
|
||||
| 2026-10-22 | minor | Recolor Artwork Edit chips scroll within the available screen height (#3416); small palettes retain their tab height; scores and estimates unchanged. |
|
||||
| 2026-10-21 | minor | G17: filter plug-ins keep data with the document (`documentData`), as its foreign data, so the native file needs no section of its own; engine and unit regressions. No entry closed, estimates unchanged. |
|
||||
| 2026-10-22 | minor | Artboard Options honors Scale Artwork with Artboard for preset, orientation and typed-size changes; both Fits keep artwork stationary; scores and estimates unchanged. |
|
||||
| 2026-10-22 | minor | G8: stacked geometry effects make at most 2 million anchors of a path and about 8 million lines to draw: Roughen, Zig Zag, Free Distort, Twist, the warps and Transform build within it, and an effect that would still pass it is left out (#3578). No entry closed, estimates unchanged. |
|
||||
| 2026-10-22 | minor | G13: gradient Method (30.0), Classic or Perceptual, in the Gradient panel, on the canvas, in raster exports and as images in SVG and PDF exports (with Dither, a Perceptual fill takes its noise); G13 estimate 14–24 h → 13–23 h. |
|
||||
| 2026-10-22 | minor | G8: SVG images in SVG images share the depth cap (any data URL type usvg reads as SVG) and SVGZ images one 512 MB unpacking cap; past either, an image is left out with a warning (#3562, #3563). No entry closed, estimates unchanged. |
|
||||
| 2026-10-22 | minor | G2: the Effect Gallery shipped (#2883): Effect › Effect Gallery… browses the Artistic, Brush Strokes, Distort, Sketch, Stylize and Texture filters, edits each filter's settings, builds an ordered stack (add, reorder, hide, remove) with a live canvas preview, and OK applies it as separate appearance effects in one undo step; remaining: filter thumbnails and a preview area inside the dialog; G2 estimate 4–6 → 1–2 h; Raster effects 82% → 85% (power-user view 49% → 52%), estimated, a modest move because the named missing dialog landed without thumbnails or an in-dialog preview. |
|
||||
| 2026-10-22 | minor | G19: PDF export asks viewers to display the document title only when File Info has a Document Title or an explicit export title is supplied; untitled documents keep the PDF file name in the viewer title bar (#3646); scores and estimates unchanged. |
|
||||
| 2026-10-22 | minor | G4: colour emoji fonts with bitmap glyphs (`sbix`: Apple Color Emoji; `CBDT`: Noto Color Emoji) draw on the canvas and export: PDF Type 3 glyphs or images, SVG images with outlined text, EPS and legacy `.ai` images, Create Outlines images; COLR and OpenType SVG fonts remain; estimate unchanged. |
|
||||
| 2026-10-22 | minor | G13: gradient Dither (30.0) in the Gradient panel, on the canvas, in raster exports and as images in SVG and PDF exports; G13 estimate 15–25 h → 14–24 h. |
|
||||
| 2026-10-22 | minor | G2: Effect › Sketch › Conté Crayon (Foreground Level, Background Level, Texture, Scaling, Relief, Light Direction, Invert; a black crayon in the dark areas and a white one in the light areas on textured mid-grey paper; ranges and defaults unverified VectorCraft choices); measured Photoshop-style filters 57/57, the Effect Gallery remains (4–6 h). |
|
||||
| 2026-10-21 | minor | Blend panel Type and Ramp control step easing with a separate color Shift (#2539); Blend Options retains spacing and orientation; polynomial curves are original approximations. Scores and estimates unchanged. |
|
||||
| 2026-10-21 | minor | M3: highlighted-text Eyedropper sampling preserves ranges and rejects unsupported source/target transparency atomically; regression-tested; scores and estimates unchanged. |
|
||||
| 2026-10-21 | minor | Shape Builder Gap Detection shares Live Paint’s spatial gap finder and temporary merge bridges (#2526); Custom is capped at 72 pt in the existing options dialog. Scores and estimates unchanged. |
|
||||
|
||||
@@ -51,6 +51,13 @@ traced fills and strokes take the library color without a link to its swatch. Th
|
||||
spot and tint swatches. Tints trace at the color shown by the tint swatch. Editing a swatch later
|
||||
does not recolor the trace. Colors from other swatch libraries are also unlinked.
|
||||
|
||||
**Ignore Color, background only.** Ignore Color leaves out every area of the chosen color. With
|
||||
`"ignoreBackground": true` beside `"ignoreWhite": true` in the params of `imageTrace.make` or
|
||||
`imageTrace.makeAndExpand`, it leaves out only the areas of that color that reach the image's edge,
|
||||
joined through pixels above, below or to either side, and traces the areas of it that other colors
|
||||
enclose: black line work inside a panel stays when the black around the panel is left out. Flat Logo
|
||||
leaves out every white area whatever `ignoreBackground` is.
|
||||
|
||||
**Document Library** traces with the library's colors as they are. Each pixel takes the library
|
||||
color nearest to it in lightness and hue, with a difference in hue or chroma counted three times
|
||||
as much as one in lightness, so a gray or a muted brown takes a black, white or other neutral
|
||||
|
||||
+524
-45
@@ -106,7 +106,7 @@ the suite) keep the agent to the folders you give it:
|
||||
|
||||
- Every file a command reads must lie inside a **read root**: `open_file`, `file.place`, relinking and
|
||||
updating links, the images an SVG links to, swatch library, graphic style library, symbol library, brush library and colour-profile loads, plug-ins,
|
||||
`file.newFromTemplate`, preset imports, shortcut sets (`shortcutSet.read`), the folders `text.findFontFiles` and `links.findFiles` search, the
|
||||
`file.newFromTemplate`, preset imports, shortcut sets (`shortcutSet.read`), action sets (`actionSet.read`), the folders `text.findFontFiles` and `links.findFiles` search, the
|
||||
scripts `script.check` reads and the files they include.
|
||||
- Every file a command writes must lie inside a **write root**: `save_file`, `export`, the save and
|
||||
export commands, Export for Screens, Package, Export for Web, print to file, `screenshot {path}`,
|
||||
@@ -269,6 +269,22 @@ chain (layer first) and `limit` caps `matches` (default 100; `0` only counts); w
|
||||
`selected`, the number of objects selected. `document.json` stays whole: it is the fidelity path, not the way to
|
||||
look around.
|
||||
|
||||
`run_command document.compare {path, artboard?, background?, threshold?, diffPath?}` measures how far an
|
||||
artboard is from an image file (PNG, JPEG, WebP, TIFF or BMP). It renders the
|
||||
artboard (default 0) at the image's size, as `export` draws a PNG: the scale is the image's width in pixels over
|
||||
the artboard's width in points, and an image whose height differs from the artboard's height at that scale by
|
||||
more than one pixel is an error that names both sizes. The render and the image are both flattened on
|
||||
`background` (`"#rrggbb"`, default `"#ffffff"`). The reply is `{width, height, rmse, over, total, threshold}`:
|
||||
`rmse` is the root mean square of the R, G and B differences on a 0 to 1 scale, rounded to 6 decimals, and
|
||||
`over` counts the pixels with a channel that differs by more than `threshold` (0 to 1, default 0.08) of the
|
||||
total `total`. `diffPath` writes a PNG of each pixel's absolute R, G and B differences (black where the two
|
||||
match) and adds `diffPath` to the reply. As in a PNG export, linked images and placed documents are drawn
|
||||
from their files rather than from the previews saved for them. The reply's `warnings` are a PNG export's, in
|
||||
the same order: type on the artboard that doesn't fit its frame, an embedded image that couldn't be decoded (it
|
||||
is missing from the render), type in a font or style that isn't available, and a linked file that can't be read
|
||||
(its preview is drawn). `path` is read through the automation read root, and `diffPath` is written through the
|
||||
write root. The command does not change the document, and it is not available in the web app.
|
||||
|
||||
### Completions
|
||||
|
||||
`completion/complete` answers for a prompt argument (`ref/prompt`) or a template variable
|
||||
@@ -387,7 +403,10 @@ counterparts, `image.info`, `links.info`, `links.goTo`, `links.unembed`, `shaper
|
||||
`transparency.editOpacityMask`, `transparency.viewOpacityMask`, `symbol.edit`, the `object.blend.spine.*` commands
|
||||
and `path.curvature`) refuse an `id` that is not a non-negative integer (`"abc"`, `"5"`, `true`) with an error and
|
||||
change nothing; an omitted or null `id` keeps the default. A command that leaves out an object selected inside a
|
||||
selected group also leaves it out when `ids` list it together with a group that holds it.
|
||||
selected group also leaves it out when `ids` list it together with a group that holds it. Every command that takes
|
||||
`ids` (or `slices`, for the slice commands) refuses a list with an entry that is not a non-negative integer, or a value
|
||||
that is not a list, and changes nothing; it does not act on the other entries. The error for an entry names the key,
|
||||
the entry's index (from 0) and its value: "`ids` entry 1 is true, not a non-negative integer object id".
|
||||
|
||||
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"}`).
|
||||
@@ -443,10 +462,12 @@ opens the picker through `run_command` with the remote backend.
|
||||
| `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. `panel` is a panel id (`layers`, `swatches`, `colorGuide`, …, as `window.panel` takes) or its display label (`"Color Guide"`), in any case. |
|
||||
| `screenshot` | `{path?, scale?, artboard?, window?, max_side?, traceViews?}` | Returns MCP image content (`image/png`, base64) plus a text block. Renders the artboard with the pixels of a PNG `export` with `background: "white"` at the same scale; `traceViews:true` draws Image Trace objects in the view set with `imageTrace.setView`, as in the app's window; `window:true` captures the app window (remote only), as `ui_screenshot` does, and `max_side` (1–4096, window captures only) scales the returned image down as described for `ui_screenshot`. With `path` the backend (the headless session or the app) writes the PNG there too; a window capture written there keeps its full size with `max_side`. |
|
||||
| `open_file` | `{path}` | Opens any readable file as a new active document: `.vectorcraft`/`.drawcraft`, `.vctemplate`, `.svg`/`.svgz`, `.pdf`/`.ai`, `.ait`, `.eps`/`.epsf`, `.ps`, `.dxf`, `.emf`, `.wmf`, PNG (`.png`/`.pns`), JPEG, GIF, WebP, TIFF, BMP (`.bmp`/`.dib`/`.rle`), Targa (`.tga`/`.vda`/`.icb`/`.vst`), PCX, Pixar (`.pxr`), JPEG 2000 (`.jpf`/`.jpx`/`.jp2`/`.j2k`/`.j2c`/`.jpc`), HEIC/HEIF (`.heic`/`.heif`), PSD (`.psd`/`.pdd`)/PSB (an image opens as a document of its pixel size; a Photoshop file as its merged image). Templates (`.vctemplate`, `.ait`) open as a new untitled document. PDF, `.ai` and SVG files saved with Preserve Editing reopen as the document they carry. The reply is `document.open`'s: its `warnings` say what didn't come in as it was (an EPS whose PostScript can't be read opens as its preview, and the warning names the PostScript error, the operator and the procedure). `run_command document.formats` lists the formats. |
|
||||
| `save_file` | `{path?, compress?, version?, preview?, precision?, options?}` | Runs `document.save`: the document's own file in its own format (native `.vectorcraft` unless it was opened from or saved as SVG, PDF or a restorable `.ai`; then `warnings` say what that format loses). A path's extension picks the format (`.vectorcraft`, `.vctemplate`, `.pdf`, `.svg`, `.svgz`, `.ai`: a PDF carrying the native document, which reopens editable). For a native file, `compress: true` gzips it (default: the `useCompression` preference, Preferences › File Handling › Use Compression), `version` (1 to 4) writes it for an older VectorCraft (1 and 2 are never compressed, and `version: 2` with `compress: true` is an error), `preview: true` embeds a PNG of the first artboard, and `precision` (0 to 9) rounds path anchors and handles to that many decimal places for that save only (colors, transforms and type stay exact). `options` passes the format's save options as `run_command document.formats` lists them. When `compress`, `version`, `preview` or `precision` is given both at the top level and in `options` with different values, the call is an error (`` `compress: true` and `options.compress: false` disagree: give the option once ``) and nothing is written. The save drops each option the written format doesn't read. The reply's `warnings` then name each such option given (for example `` `compress` was not used: SVG files don't read it `` for an `.svg` path, and `` `options.preview` was not used: … `` for a key in `options`; a `.ai` file reads `compress` but not `version`, `preview` or `precision`). `run_command document.save` and the other save commands refuse any option given beside the path and in `options` with different values, and give the same warning for a top-level `compress`, `version`, `preview` or `precision`. The headless session and the app receive the same `app.save` params, and the app is also sent `wait: true`: the call returns once the file is written, or with the error (such as a path outside the write root), even with Background Save on. When the save asks first (the question before replacing a file that opened with losses, or on macOS and Linux the file dialog for an untitled document without `path`), the reply is `{pending}` or `"cancelled"` as before, and the save that runs after the answer uses the Background Save preference. |
|
||||
| `open_file` | `{path}` | Opens any readable file as a new active document: `.vectorcraft`/`.drawcraft`, `.vctemplate`, `.svg`/`.svgz`, `.pdf`/`.ai`, `.ait`, `.eps`/`.epsf`, `.ps`, `.dxf`, `.emf`, `.wmf`, PNG (`.png`/`.pns`), JPEG, GIF, WebP, TIFF, BMP (`.bmp`/`.dib`/`.rle`), Targa (`.tga`/`.vda`/`.icb`/`.vst`), PCX, Pixar (`.pxr`), JPEG 2000 (`.jpf`/`.jpx`/`.jp2`/`.j2k`/`.j2c`/`.jpc`), PSD (`.psd`/`.pdd`)/PSB (an image opens as a document of its pixel size; a Photoshop file as its merged image). Templates (`.vctemplate`, `.ait`) open as a new untitled document. PDF, `.ai` and SVG files saved with Preserve Editing reopen as the document they carry. The reply is `document.open`'s: its `warnings` say what didn't come in as it was (an EPS whose PostScript can't be read opens as its preview, and the warning names the PostScript error, the operator and the procedure). `run_command document.formats` lists the formats. |
|
||||
| `save_file` | `{path?, compress?, version?, preview?, precision?, options?}` | Runs `document.save`: the document's own file in its own format (native `.vectorcraft` unless it was opened from or saved as SVG, PDF or a restorable `.ai`; then `warnings` say what that format loses). A path's extension picks the format (`.vectorcraft`, `.vctemplate`, `.pdf`, `.svg`, `.svgz`, `.ai`: a PDF carrying the native document, which reopens editable). For a native file, `compress: true` gzips it (default: the `useCompression` preference, Preferences › File Handling › Use Compression), `version` (1 to 4) writes it for an older VectorCraft (1 and 2 are never compressed, and `version: 2` with `compress: true` is an error), `preview: true` embeds a PNG of the first artboard, and `precision` (0 to 9) rounds path anchors and handles to that many decimal places for that save only (colors, transforms and type stay exact). `options` passes the format's save options as `run_command document.formats` lists them. When `compress`, `version`, `preview` or `precision` is given both at the top level and in `options` with different values, the call is an error (`` `compress: true` and `options.compress: false` disagree: give the option once ``) and nothing is written. The save drops each option the written format doesn't read. The reply's `warnings` then name each such option given (for example `` `compress` was not used: SVG files don't read it `` for an `.svg` path, and `` `options.preview` was not used: … `` for a key in `options`; a `.ai` file reads `compress` but not `version`, `preview` or `precision`). For a `.ai` file, these warnings name the kind of `.ai` written: a legacy .ai (version 7) for `aiVersion: "7"`, a non-PDF-compatible .ai for `pdfCompatible: false`, and a PDF-compatible .ai otherwise, including a save that reuses the options the document was last saved with. `run_command document.save` and the other save commands refuse any option given beside the path and in `options` with different values, and give the same warnings for a top-level `compress`, `version`, `preview` or `precision` and for each key in `options` that the format doesn't read. The headless session and the app receive the same `app.save` params, and the app is also sent `wait: true`: the call returns once the file is written, or with the error (such as a path outside the write root), even with Background Save on. When the save asks first (the question before replacing a file that opened with losses, or on macOS and Linux the file dialog for an untitled document without `path`), the reply is `{pending}` or `"cancelled"` as before, and the save that runs after the answer uses the Background Save preference. |
|
||||
| `export` | `{path?, format?, scale?, artboard?, range?, selection?, outlineText?, options?}` | `svg`, `svgz`, `pdf`, `ai` (the PDF-compatible `.ai` that Save writes, which carries the document when every artboard is written in order), `eps`, `dxf`, `emf`, `wmf`, `png`, `jpg`, `webp`, `gif`, `png8` (an indexed `.png`), `tiff`, `bmp`, `tga`, `psd` (layered), `txt` (the document's text), `vectorcraft` or `template` (a native template). The tool's `format` enum and `document.formats` list them, generated from the engine's format table. When `format` is omitted, it comes from the path's extension. PDF and `.ai` write one page per artboard: all of them, or `artboard` (0-based) / `range` (`"1-3, 5"`, 1-based). SVG and SVGZ write one file per chosen artboard. EPS writes one file of the visible art; with `artboard`, `range`, `options.artboards` or `options: {"useArtboards": true}` it writes one file per chosen artboard, after a central file of the visible art when there are two or more, and `useArtboards: false` keeps the one file. Rasters, DXF, EMF and WMF write one artboard, or one file per chosen artboard with `options: {"useArtboards": true}`. Rasters also take `options: {"rect": [x, y, width, height]}` (page points, y down): that area of the page at the given `ppi`/`scale`, without an artboard and without changing the document; it is refused with `artboard`, `artboards`, `range` or `useArtboards`, with a non-positive or non-finite size, and for non-raster formats. `options` carries more format options (e.g. `{"quality": 80}` for JPEG). `selection: true` exports the selected objects cropped to their bounds (the reply adds their `bounds`, and reports `format` and the encoder's `warnings` as a whole-document export does); `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?, fit?, fitMinPercent?, path?, mode?, pathEffect?, size?, font?, color?, justify?, vertical?}` | Point type at (x, y) (`justify`: `left`, `center` or `right` starts, centres or ends each line on x); area type with `width`/`height` (`fit`: `none`, `autoHeight`, `shrinkText`, as `text.areaOptions`); or `path` + `mode` (`area`/`onPath`) to flow text in or along a path, with `pathEffect` (`rainbow`, `skew`, `3dRibbon`, `stairStep`, `gravity`); `justify` (also `auto`, `justifyAll`) aligns the paragraphs of every kind, as `text.setStyle` does later. `vertical: true` uses the existing vertical writing mode for every kind (default `false`, horizontal). Returns `{id}`, with `overflow: true` when the text doesn't fit its frame or path. |
|
||||
| `add_text` | `{text, x?, y?, width?, height?, fit?, fitMinPercent?, path?, mode?, pathEffect?, size?, font?, color?, justify?, vertical?}` | Point type at (x, y) (`justify`: `left`, `center` or `right` starts, centres or ends each line on x); area type with `width`/`height` (`fit`: `none`, `autoHeight`, `shrinkText`, as `text.areaOptions`); or `path` + `mode` (`area`/`onPath`) to flow text in or along a path, with `pathEffect` (`rainbow`, `skew`, `3dRibbon`, `stairStep`, `gravity`; SVG export writes type on a path with any effect other than `rainbow` as outlines, with a warning); `justify` (also `auto`, `justifyAll`) aligns the paragraphs of every kind, as `text.setStyle` does later. `vertical: true` uses the existing vertical writing mode for every kind (default `false`, horizontal). Returns `{id}`, with `overflow: true` when the text doesn't fit its frame or path. |
|
||||
| `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 (`effect.apply` groups several loose selected objects first). In remote desktop mode, `run_command` and `invoke_menu` can both call `pathfinder.repeat` with `{}`. Successful panel operations, direct `object.pathfinder.*` commands, and `command.batch` steps (including Actions panel playback) set its history. Repeat applies it to the current selection using current Pathfinder Options. Trap, compound-shape edits, live effects and `action.batch` do not set history. With no history it returns "no Pathfinder operation applied yet". |
|
||||
| `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. |
|
||||
@@ -465,6 +486,12 @@ for horizontal writing. This is the same option as `text.create` / `text.createI
|
||||
on the OpenType `vert` feature, so a font's vertical glyph alternates are used; it does not change the engine's
|
||||
CJK composition.
|
||||
|
||||
`type.orientation.vertical` and `type.orientation.horizontal` (Type › Type Orientation) switch existing type objects
|
||||
(the selection, or `ids`) and reply `{vertical, ids}`. The writing direction is a setting of the whole thread: the
|
||||
commands set every frame of a selected frame's thread, and `ids` lists them all. Threading frames gives the thread its
|
||||
first frame's direction, frames taken out of a thread keep theirs, and a file whose frames of one thread differ opens
|
||||
with the first frame's direction in all of them.
|
||||
|
||||
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).
|
||||
|
||||
@@ -542,18 +569,23 @@ stroke instead of the whole object: `run_command effect.apply {"effect": "path.o
|
||||
|
||||
On a path directly inside a graph series, `appearance.setItem`, `appearance.addFill`, `appearance.addStroke`,
|
||||
`appearance.removeItem`, `appearance.moveItem`, `appearance.duplicateItem`, `appearance.clear`,
|
||||
`appearance.reduceToBasic`, `appearance.showAllHidden`, `appearance.transfer` and `appearance.copyFrom` store the paint,
|
||||
weight and opacity of the topmost visible fill and stroke on the graph. When the graph is drawn again, columns, bars,
|
||||
wedges, areas, markers and legend swatches take the stored fill and stroke. A thin line takes the stored stroke and has
|
||||
no fill. A Filled Lines band takes the stored fill, or the stored stroke when no fill is stored and that stroke has
|
||||
paint, and has a 0.25 pt black outline, so these commands do not store a stroke paint or weight for a series that
|
||||
draws a band. They still store a stroke opacity set on a band, and the band's outline takes it. Graph
|
||||
designs keep their own paint. A row that had no paint before the command and has none after it does not change what the
|
||||
graph stores. `paint.setFill`, `paint.setStroke`, `paint.none` and the commands that apply one paint kind to the other
|
||||
store the topmost row of the kind even when it is hidden, and store a stroke set on a band.
|
||||
`stroke.set`, `paint.editGradient`, `paint.swap`, `paint.default`, graphic styles and the recolor commands do not store a
|
||||
series' paint. An `appearance.*` command given a series group's id edits the group's own rows, and the graph does not
|
||||
store them.
|
||||
`appearance.reduceToBasic`, `appearance.showAllHidden`, `appearance.transfer`, `appearance.copyFrom`, `paint.default`,
|
||||
`graphicStyle.apply` and `graphicStyle.redefine` (on the marks still linked to the style) store the paint, weight and
|
||||
opacity of the topmost visible fill and stroke on the graph. `graphicStyle.apply` with `add` stores only the kinds of row
|
||||
that are visible in the style. `paint.swap` stores the swapped paints and the stroke weight, keeps the stored opacity,
|
||||
and does not store a hidden topmost row that it swaps. The graph does not store the rest of a graphic style's look (more
|
||||
fill and stroke rows, effects, the object's opacity and blend mode, and the link to the style), and a mark loses it when
|
||||
the graph is drawn again. When the graph is drawn again, columns, bars, wedges, areas, markers and legend swatches take
|
||||
the stored fill and stroke. A thin line takes the stored stroke and has no fill. A Filled Lines band takes the stored
|
||||
fill, or the stored stroke when no fill is stored and that stroke has paint, and has a 0.25 pt black outline, so these
|
||||
commands do not store a stroke paint or weight for a series that draws a band. Except for `paint.swap`, they still store
|
||||
a stroke opacity set on a band, and the band's outline takes it. Graph designs keep their own paint. A row that had no
|
||||
paint before the command and has none after it does not change what the graph stores. `paint.setFill`,
|
||||
`paint.setStroke`, `paint.none` and the commands that apply one paint kind to the other store the topmost row of the kind
|
||||
even when it is hidden, and store a stroke set on a band. `stroke.set`, `paint.editGradient` and the recolor commands do
|
||||
not store a series' paint. An `appearance.*` command or `graphicStyle.apply` given a series group's id, and
|
||||
`graphicStyle.redefine` on a series group linked to the style, edit the group's own rows, and the graph does not store
|
||||
them.
|
||||
|
||||
`effect.apply {"effect": "path.outlineObject"}` (Effect › Path › Outline Object) takes no parameters. Type that carries
|
||||
it is drawn, exported and expanded as its glyph outlines and stays editable type, and the effects after it reshape
|
||||
@@ -568,7 +600,8 @@ global or spot swatch follow its colour and name, as one undo step, in the art,
|
||||
designs, pattern tiles, graphic styles and the art of brushes); `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
|
||||
or pattern (a gradient swatch holds no link to the swatch its gradient came from, and a pattern swatch holds the
|
||||
pattern untransformed); `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
|
||||
@@ -663,8 +696,8 @@ effect colors that new art takes; Undo restores their original values and Redo r
|
||||
colors of 3D effects stay RGB.
|
||||
Gray colors stay Gray and print
|
||||
on the black plate only. RGB grays are colors like any
|
||||
other: to CMYK they separate through the profile into four-colour greys and a rich black, as Illustrator converts
|
||||
them. `grays: "black"` puts RGB greys with R = G = B on the black plate instead, K = their grey value (the inks Edit Colors ›
|
||||
other: to CMYK they separate through the profile into light grays in cyan, magenta and yellow only, darker
|
||||
four-color grays and a rich black. `grays: "black"` puts RGB greys with R = G = B on the black plate instead, K = their grey value (the inks Edit Colors ›
|
||||
Convert to Grayscale before the switch would give); other colors convert as usual. The reply's `changed` counts the
|
||||
colors that changed in the art, symbols, graph designs and pattern tiles; it does not count the colors of graphic
|
||||
styles and brushes.
|
||||
@@ -1669,6 +1702,21 @@ changes neither option. Behavior reference: [View artwork](https://helpx.adobe.c
|
||||
{"name":"invoke_menu","arguments":{"command":"ui.navigatorPanelOptions","params":{"color":"Light Blue","solidDashes":true}}}
|
||||
```
|
||||
|
||||
## Tools panel placement
|
||||
|
||||
By default the docked Tools panel sits at the window's left edge, outside any panels docked on the left.
|
||||
`window.toolsBesideCanvas {on?}` (Window › Toolbars › Keep Tools Beside the Canvas, remote mode, `invoke_menu`)
|
||||
docks it between those panels and the canvas instead (`on: true`), back at the window's edge (`on: false`), or
|
||||
toggles it (`on` omitted or null), and answers the new state. Any other value of `on` is an error and changes
|
||||
nothing. With the setting on, a floating Tools panel docks when it is dropped on the canvas's left edge as well as
|
||||
on the window's left edge, and `window.panel.dock {panel: "tools"}` docks it beside the canvas. A floating Tools
|
||||
panel stays floating when the setting changes. The setting is VectorCraft's own layout option, off by default; it is
|
||||
kept with the workspace, and built-in workspaces and workspaces saved without it keep Tools at the window's edge.
|
||||
|
||||
```json
|
||||
{"name":"invoke_menu","arguments":{"command":"window.toolsBesideCanvas","params":{"on":true}}}
|
||||
```
|
||||
|
||||
## Ruler guides
|
||||
|
||||
Ruler guides are numbered in the order they were made. `guide.add {vertical, pos, artboard?}` makes one (the x of a
|
||||
@@ -1749,9 +1797,42 @@ already walks Image Trace. Short agent entry points:
|
||||
art for itself only and stays linked. `symbol.instance.setAppearance {id?, path, fill?, stroke?, opacity?, blend?}`
|
||||
names the object by `path`, child indices in paint order from the art's root down through its groups (`[]` is the
|
||||
root; `[1, 0]` is the first object of the art's second member when that member is a group). `fill` and `stroke` take
|
||||
a colour string or the paint params of `paint.setFill` (`color`, `none`, `swatch`, `tint`, `gradient`), `opacity` is
|
||||
0..100 and `blend` a blend mode name; `null` gives one back to the symbol. It is refused for a static symbol and for
|
||||
a path that names no object. `symbol.instance.reset {ids?}` drops the selected instances' changes (the Properties
|
||||
a colour string or the paint params of `paint.setFill` (`color`, `none`, `swatch`, `tint`, `gradient`). Paths,
|
||||
compound paths, type, groups and layers take both. A symbol instance takes a solid color or `none` as its fill,
|
||||
which stains its art, and no gradient or pattern fill and no stroke. An image takes a fill or stroke only when that
|
||||
fill or stroke has a Convert to Shape or Outline Object effect. A guide, blend, envelope, Repeat, Intertwine group,
|
||||
gradient mesh or placed document takes neither. A refused fill or stroke (VectorCraft's own rule) gives an error
|
||||
that names the key and the object, and nothing of the call is applied; `opacity`, `blend` and `null` are taken for
|
||||
every object, so a stored change can be taken back. `opacity` is 0..100 and `blend` a blend mode name; `null` gives
|
||||
one back to the symbol. It is refused for a static symbol and for a path that names no object. On the canvas (VectorCraft's own rule), a Direct Selection click on an instance of a
|
||||
dynamic symbol selects the path, compound path or type object of its art under the pointer and outlines it
|
||||
(`symbol.instance.selectPart {id, path}`; Alt or Shift selects the instance whole). While it is selected,
|
||||
`paint.setFill` and `paint.setStroke` with a solid color or none, `paint.invert` and `paint.complement` on a solid
|
||||
color, all without `ids`, `id` or `item`, and the Eyedropper's `appearance.copyFrom` with a solid fill and stroke
|
||||
change that object's fill or stroke for this instance only, each as one undo step. A painted stroke on type without a
|
||||
weight gets 1 pt. A gradient or pattern for the object is refused with a status message, and so are `paint.invert` and
|
||||
`paint.complement` on type whose characters differ in color, Eyedropper options that pick up neither color, an
|
||||
Eyedropper source that is not a path, compound path or type (a symbol instance or a group, for which the paint defaults
|
||||
stay as they are too), and a click
|
||||
or `symbol.instance.selectPart` on any other object of the art (a group, image, blend or nested instance among them).
|
||||
The commands that change the selected objects without `ids` are refused the same way and change nothing, among them
|
||||
opacity and blending mode, moving and transforming, `path.moveAnchors`, `file.place` with `replace`, Puppet Warp, Delete
|
||||
and Cut, Group, Hide, Lock, Arrange, Expand,
|
||||
Recolor Artwork, plug-in filters, effects, the gradient commands, `gradient.selectStop`, the Appearance panel's rows and
|
||||
`symbol.instance.setAppearance`. A Cmd-drag that lends the Selection or Group Selection tool selects the instance whole
|
||||
first and moves it. `swatch.unused` and `recolor.colors` count the fills and strokes an instance keeps for objects of its
|
||||
art. Commands that change nothing in the document, such as `attributes.info`, `css.selection`, `css.export`,
|
||||
`effect.list` and `object.expand.info`, read the instance. These commands do not check for a selected object and use the instance:
|
||||
`edit.copy` copies the instance whole; `document.exportSelection`, `document.export` with `selectionOnly` and
|
||||
selection-mode `document.exportForScreens` export it whole; `artboard.fitToSelection` fits the artboard to the whole instance;
|
||||
`object.liquify` without `ids` takes the instance as its target and, since it reshapes paths only, leaves it as it is
|
||||
and lists it in `skipped` when the brush reaches it; `object.isolate` without `id` isolates the instance and clears the
|
||||
selection; `library.add` without `ids` adds a copy of the whole instance as a `graphic`, and its fill and stroke kinds
|
||||
read the instance rather than the selected object; `select.save` saves the instance, and `select.recall` then selects it
|
||||
whole. Direct Selection passes over hidden, locked and template objects of the art, and
|
||||
`symbol.instance.selectPart` refuses a path to one or to an object inside one, and an instance that is hidden or
|
||||
locked or sits in a hidden or locked group or layer. Choosing another selection tool selects the instance whole again.
|
||||
`symbol.instance.reset {ids?}` drops the selected instances' changes (the Properties
|
||||
panel's Reset). Redefining the symbol (`symbol.update`) reshapes every instance and keeps each change whose path the
|
||||
new art still has; `symbol.breakLink` bakes the changes into the expanded art; `symbol.edit` edits the symbol's own
|
||||
art, and each edit there keeps the changes whose path the art still has; making the symbol static drops them, and
|
||||
@@ -1812,7 +1893,8 @@ already walks Image Trace. Short agent entry points:
|
||||
first value at −180° to its second at 180°. A stroke without that input draws the brush's own value (a Scatter
|
||||
brush's value half way between the two).
|
||||
- Variables: `variable.list`, `variable.define {name, kind: text|visibility|image|graph}`, `variable.bind {variable, ids?}`,
|
||||
`variable.makeTextDynamic`, `variable.makeVisibilityDynamic`, `variable.makeImageDynamic`, `variable.makeGraphDynamic`,
|
||||
`variable.makeTextDynamic`, `variable.makeVisibilityDynamic`, `variable.makeImageDynamic`, `variable.makeGraphDynamic`
|
||||
(`variable.bind` and `variable.makeTextDynamic` refuse type that already has another text variable and name it),
|
||||
`variable.unbind`, `variable.rename`, `variable.delete`, `variable.highlight` (image values are file paths, graph
|
||||
values CSV as `graph.setData`). `variable.lock {locked?}` (Lock Variables) locks or unlocks the variables;
|
||||
without `locked` it toggles, and the lock is saved with the document. While the variables are locked,
|
||||
@@ -1905,7 +1987,8 @@ already walks Image Trace. Short agent entry points:
|
||||
instead of playing the excluded steps or failing at a stop; other files use version 1. A file with another `format` or a `version` other than
|
||||
1, 2 or 3, a stop whose message is not text or whose `allowContinue` is not true or false, a file larger than 8 MiB, one with more than 1,000 actions and one with an action of more than 10,000 steps are
|
||||
refused, and no set is added. The Actions panel menu's Save Actions… and Load Actions… run these; Load Actions… is
|
||||
disabled where there is no open dialog (the web).
|
||||
disabled where there is no open dialog (the web). `ui.actionSet.load` also reads the action sets other apps save as
|
||||
text (`.aia`); see "Action sets from other apps".
|
||||
- Actions: `ui.action.rename {set, action, name}` renames the Actions panel's action at `action` in set `set` (0 is
|
||||
the top set) to `name` with spaces trimmed from both ends, keeps its steps, function key and color, and returns
|
||||
`{name}`. An index past the last set or action, or an empty name, is an error, and then nothing is renamed.
|
||||
@@ -1998,6 +2081,17 @@ already walks Image Trace. Short agent entry points:
|
||||
- Image Trace: `imageTrace.presets`, `imageTrace.make {id?, preset?, params?, view?}` (or `imageTrace.makeAndExpand`),
|
||||
`imageTrace.setView`, `imageTrace.expand`, `imageTrace.release`. A key inside `params` that is not one of the trace
|
||||
settings, such as `colours`, is an error that names it and the nearest setting (`colors`), as for a command's own keys.
|
||||
With `byColor: true`, `imageTrace.expand` and `imageTrace.makeAndExpand` put each color's paths in a group of their
|
||||
own, named by the global swatch the color links to (a tint with its percentage, as `Sky 50%`) or as `#rrggbb`;
|
||||
gradient fills share a group named `Gradients`. The groups stack in the order of the lowest path in each, and each
|
||||
keeps its paths' order. For either Expand command, a path that would move under a path of another
|
||||
color whose painted bounds, effects and shadows included, come within one document point of it starts another group
|
||||
of its color instead of joining an earlier one. Paths whose painted bounds come within one document point of an
|
||||
intervening color stay in separate groups to preserve their stacking order; at small view or raster-export scales,
|
||||
regrouped paths farther apart can still share antialiased pixels, so edge pixels may differ. In a Flat Logo trace of a
|
||||
black ring around a white disc around a black dot, black gets two groups. `layer.releaseToLayers` on the expanded group then
|
||||
gives each group a sublayer. A trace made with `autoGrouping` is refused. Expanding by color also refuses a trace
|
||||
with a live Pathfinder effect.
|
||||
`imageTrace.presets.save {name?, newName?, preset?, enhanced?, params?}` saves tracing settings as a preset kept with
|
||||
the preferences: `params` over `preset`'s (default: the saved preset `name`, else Default), checked as `imageTrace.make`
|
||||
checks them; without `name` it is a new "Tracing Preset N", and `newName` renames a saved preset (the reply's
|
||||
@@ -3091,6 +3185,63 @@ it. The native format keeps the events and the files.
|
||||
{"name":"run_command","arguments":{"command":"svgInteractivity.addFile","params":{"file":"menu.js"}}}
|
||||
```
|
||||
|
||||
## SVG filters
|
||||
|
||||
Effect › SVG Filters lists the document's SVG filters below Apply SVG Filter… and Import SVG Filter…; choosing one
|
||||
applies it to the selection. `svgFilter.list {}` returns them as `filters: [{name, xml}]`. Each is one `<filter>`
|
||||
element whose `id` is its name, with 1 to 64 primitives and at most 64 KB of XML (`feTurbulence` octaves up to 10,
|
||||
`feConvolveMatrix` kernels up to 9 cells a side, `feMorphology` radii and `kernelUnitLength` up to 100 and
|
||||
`stdDeviation` up to 500 user units, elements nested at most 16 deep). It holds only filter primitives,
|
||||
what they hold, and `desc` and `title`: no scripts, no event attributes, and images only as PNG, JPEG, GIF or WebP
|
||||
`data:` URLs of at most 4096 × 4096 pixels. A document
|
||||
holds at most 64. `svgFilter.define {xml, replace?}` adds
|
||||
a filter after the others, or with `replace` replaces the filter of that name, which keeps its name; a name another
|
||||
filter has is refused, and the same filter again records no undo step. `svgFilter.delete {name}` removes one, and `svgFilter.import
|
||||
{path?|svg?}` adds the `<filter>` elements of an SVG file (at most 16 MB, not SVGZ, the first 256 filters) or of SVG text, leaving out the names the
|
||||
document already has and the filters `svgFilter.define` would refuse (`{added, skipped}`). Each change is one undo
|
||||
step. `svgFilter.apply {name, ids?|id?, item?}` applies one as the live effect `svg.filter`, as `effect.apply` does,
|
||||
in one undo step. The effect (`{name, xml, scale, origin}`) names the document's filter: editing the filter changes
|
||||
what every object that uses it draws, in the edit's one undo step, and an application after an edit takes the edited
|
||||
filter. Deleting a filter that objects use leaves their effects in place, still named, drawing nothing (their `xml`
|
||||
empty) until a filter of that name is defined or imported again. Opened from such an effect, Apply SVG Filter shows the
|
||||
name above the list, not selectable. `effect.apply {effect: "svg.filter", params: {xml}}` takes a filter
|
||||
directly and names it by its `id`; an `xml` that isn't one such filter is an error. `ui.svgFilterDialog {}` opens Apply
|
||||
SVG Filter (New, Edit, Delete, Import…), and from the Appearance panel it edits which filter an applied effect runs;
|
||||
`ui.importSvgFilter {}` picks an SVG file and imports its filters.
|
||||
|
||||
The canvas, raster export, printing and PDF draw the filter with the object as its source graphic, its user space
|
||||
starting at `origin` (`[x, y]` in points, `[0, 0]` by default) with its units `scale` points (1 by default), its
|
||||
object bounding box the drawn object's, and at the Document Raster Effects resolution when the view is finer. The
|
||||
filter runs on coarser pixels when a morphology radius or kernel unit would span more than 32 of them, or a standard
|
||||
deviation more than 512. An effect whose XML these rules refuse (from a file or a script) is not drawn or exported. The
|
||||
filter is drawn and written rebuilt from its filter elements and their filter attributes alone, without comments,
|
||||
text, descriptions or other attributes. An image in a filter is drawn only when its bytes are a PNG, JPEG, GIF or WebP
|
||||
within the pixel limit. A filter region in user space given in percentages is measured against the object's box (x
|
||||
and y from its top-left corner), and one in em or ex or left out takes the default region of that box (10% beyond
|
||||
each side); these are VectorCraft's own rules. Scale Strokes & Effects scales
|
||||
`scale`. SVG export writes the filter as a `<filter>` element when it is the object's last effect, its only pixel
|
||||
effect and `scale` is 1 (with a region measured against the object's box, its only raster effect), with the object in a
|
||||
group that places the filter's user space and such a region written in user units. The filter is written in SVG 1.1
|
||||
terms: `feImage`'s reference as `xlink:href`; each `feDropShadow` as the blur, offset, flood, composite and merge that
|
||||
[Filter Effects](https://www.w3.org/TR/filter-effects-1/#feDropShadowElement) gives as its equivalent; colors as
|
||||
`#rrggbb` with a flood color's alpha in `flood-opacity`; `image-rendering` as `optimizeSpeed` or `optimizeQuality`;
|
||||
the inputs `BackgroundImage`, `BackgroundAlpha`, `FillPaint` and `StrokePaint` as `SourceGraphic`, and an input that
|
||||
names no earlier result as the previous primitive's result;
|
||||
and an `feComposite` operator SVG 1.1 lacks, or `edgeMode` on a primitive other than `feConvolveMatrix`, left out, as
|
||||
the canvas draws them. A filter with an `feBlend` mode SVG 1.1 lacks (`overlay` and the others), an `feDropShadow`
|
||||
whose `flood-color` is `currentColor` or with `primitiveUnits="objectBoundingBox"`, or more than 64 primitives once
|
||||
its shadows are expanded, has no SVG 1.1 form. Neither does a filter whose written form, with its region and id, is
|
||||
one SVG import would not read, such as one longer than 64 KB. In that case, otherwise, and with the SVG Tiny 1.2 profile, the object
|
||||
becomes an image. SVG import keeps a filter that the live effects (Drop Shadow, the
|
||||
glows, Gaussian Blur, Feather) can't express as an `svg.filter` effect holding the filter's XML, with `scale` and
|
||||
`origin` from the object's user space, unless that user space is turned, skewed or scaled past 0.001 to 1000 points
|
||||
to a unit, or the filter is styled by the document's style sheets: such a filter is left out with a warning. The native format keeps the document's filters and the effects.
|
||||
|
||||
```json
|
||||
{"name":"run_command","arguments":{"command":"svgFilter.define","params":{"xml":"<filter id=\"Soft\"><feGaussianBlur stdDeviation=\"2\"/></filter>"}}}
|
||||
{"name":"run_command","arguments":{"command":"svgFilter.apply","params":{"name":"Soft","ids":[12]}}}
|
||||
```
|
||||
|
||||
## Removing anchor points
|
||||
|
||||
`path.removeAnchors {}` (Object › Path › Remove Anchor Points) removes the direct-selected anchors (`select.anchors
|
||||
@@ -3344,6 +3495,56 @@ Absolute target, so it leaves objects that already have that size as they are; r
|
||||
{"name":"run_command","arguments":{"command":"object.transformEach","params":{"relative":false,"scaleH":50,"scaleV":50}}}
|
||||
```
|
||||
|
||||
## Align to Pixel Grid
|
||||
|
||||
`object.setPixelAligned {ids?|id?, on?}` turns the pixel-aligned property of the objects given (default: the selected
|
||||
objects) on or off (`on` defaults to true), as the Transform panel's Align to Pixel Grid checkbox does (described on
|
||||
the help page,
|
||||
<https://helpx.adobe.com/illustrator/desktop/get-started/learn-the-basics/pixel-preview-mode-for-web-graphics.html>).
|
||||
It returns `{ids}`, the objects whose property changed. While the property is on:
|
||||
|
||||
- The object's horizontal and vertical straight segments sit on whole points, or on half points when a stroke centered
|
||||
on the path has an odd weight, so that the stroke's edges fall on the pixel grid. A stroke that is hidden or has no
|
||||
paint does not count. Its stroke weights are whole points, at least 1.
|
||||
- Every move, scale, rotation, reflection, shear, Transform Each, Align or Distribute move (of objects or of
|
||||
direct-selected anchors), Transform panel change, move of direct-selected anchors or of one anchor
|
||||
(`path.moveAnchor`), new anchors from `path.setAnchors`, live shape change (`object.setLiveShape`), move of a
|
||||
compound path's path on its own, and artboard move or resize that carries the art (`artboard.move` with
|
||||
`moveArt`, `artboard.setProps` with art, Rearrange Artboards) snaps those segments again, as do the art copies of `artboard.move` with `copy` and Duplicate
|
||||
Artboards, the copies that `edit.duplicate` and the paste commands move, and `object.slice.move` of an object slice,
|
||||
and so does every `stroke.set`, `stroke.weightUp` and `stroke.weightDown` edit, which also rounds the new weight. An
|
||||
appearance edit that adds, removes, hides, repaints or reweighs a stroke snaps them again too:
|
||||
`appearance.setItem`, `appearance.addStroke`, `appearance.removeItem`, `appearance.clear`,
|
||||
`appearance.reduceToBasic`, `appearance.showAllHidden`, `appearance.transfer` (both objects), `appearance.copyFrom`
|
||||
(the Eyedropper), `paint.setStroke` and `graphicStyle.apply`, in the same undo step as the edit, as is every member
|
||||
of an active Global Edit that such an edit or move reaches. Every other command that changes a pixel-aligned object
|
||||
(for example Object › Path › Average) snaps it again as part of its undo step. Each anchor that such a segment shares moves with its handles, so diagonal segments and curves keep their shape apart from those
|
||||
anchors. A rotated shape with no horizontal or vertical segment is left as it is. Pixel-aligned art of a linked
|
||||
opacity mask snaps when its object moves.
|
||||
- Coordinates that differ stay at least 1 pt apart within a subpath, so a narrow shape does not collapse. A
|
||||
coordinate on a whole point snaps to the half point above it and one on a half point to the whole point below it, so
|
||||
hiding and showing an odd stroke returns the path to where it was. A placed gradient and the art of a linked opacity
|
||||
mask move with the snapped anchors, and so do pattern tiles when the move transforms patterns. A pixel-aligned member
|
||||
of an Objects on Path group snaps again after the group places it on its path.
|
||||
- A live rectangle, polygon, line or pie is moved and scaled as a whole to the snapped bounds, and stays live. A full
|
||||
ellipse has only curves and is left as it is. A path with Live Corners snaps the outline its corners are cut from and keeps
|
||||
its Live Corners. A compound path snaps each of its paths with the compound path's stroke.
|
||||
- Make Compound Path from paths or compound paths that include a pixel-aligned one gives a pixel-aligned compound path
|
||||
and snaps it; its paths do not keep the property, and a path inside a compound path cannot take it alone (an error).
|
||||
Release Compound Path gives each released path the property of the compound path. A path pasted into a compound
|
||||
path, alone or from a pasted compound path, drops its own property and snaps with the compound path.
|
||||
|
||||
Turning the property on snaps the objects at once; turning it off keeps their geometry. These rules are VectorCraft's
|
||||
own: only paths and compound paths can be aligned, and type, images, groups, guides and other objects are an error
|
||||
that leaves the document as it was. The change is one undo step, and when every object already has the value nothing
|
||||
changes and no undo step is made. The property is saved in the native file (`pixel_aligned` in `document.node`), and
|
||||
files saved without it read back with it off.
|
||||
|
||||
```json
|
||||
{"name":"run_command","arguments":{"command":"object.setPixelAligned","params":{"on":true}}}
|
||||
{"name":"run_command","arguments":{"command":"object.setPixelAligned","params":{"ids":[12],"on":false}}}
|
||||
```
|
||||
|
||||
## Live Corners
|
||||
|
||||
`object.setLiveShape {id?, ids?, radius?, kind?, corners?, items?}` sets the corners of any path (one undo step): a live
|
||||
@@ -3461,6 +3662,13 @@ They list such a command while the user has changed its shortcut (`overridden: t
|
||||
shortcut for that command runs what a click on the item runs: Object › Path › Clean Up…, Print Ink Fixes… and Edit ›
|
||||
Find and Replace… open their dialogs.
|
||||
|
||||
Each installed filter plug-in's Object › Plug-ins item is its own row, with id `plugin:<id>` (the plug-in's id), its
|
||||
menu label and no default shortcut, so two filters with the same name have two rows. `shortcuts.set {id:
|
||||
"plugin:<id>", shortcut}`, `shortcuts.list` and Import Shortcut Set use that id, `shortcuts.exportText` writes one line
|
||||
for the row under its menu path and label, and the key runs what a click on the item runs, `plugin.dialog {id}`. A
|
||||
removed plug-in's row goes away and its key runs nothing; its shortcut stays saved and applies again when a plug-in
|
||||
with the same id is installed.
|
||||
|
||||
`shortcuts.exportText {path?}` saves the current set's shortcut list as a UTF-8 text file, as Edit › Keyboard
|
||||
Shortcuts › Export Text… does with the dialog's set as edited so far. The file starts with a "Keyboard Shortcuts" line
|
||||
and a "Set:" line with the set's name, followed by a Tools section and a Menu Commands section. Each section lists the
|
||||
@@ -3486,7 +3694,16 @@ Actions panel plays an action as a `command.batch`, omitting steps whose playbac
|
||||
cleared. An action set saved as `.vcactions` keeps each excluded step with `excluded: true`; loading
|
||||
an earlier version 1 set without that flag includes every step. The Actions panel menu's Batch… runs
|
||||
`action.batch`: the same steps on every readable file in a folder (or every data set of the open document), with
|
||||
destination `none` | `saveAndClose` | `folder` and Override Open / Save / Export. For a Data Sets source,
|
||||
destination `none` | `saveAndClose` | `folder` and Override Open / Save / Export. With a Data Sets source,
|
||||
`saveAndClose` saves the open document over its own file after each data set, so the file keeps only the last one,
|
||||
and a document that was never saved, was converted from an older version or was restored by Data Recovery is
|
||||
refused before a data set is selected, unless a recorded Save or Save As step (not in the template format) writes a
|
||||
file and makes it the document's own first. When `destinationFolder` is set and Override Save points a recorded Save or
|
||||
Save As step into it, that step makes each data set's file the document's own, and `saveAndClose` saves each data
|
||||
set to its own file. The result carries `warning` when every data set saves over the same file:
|
||||
with `saveAndClose` without such a step, or with a Save, Save a Copy, Save as Template or export step (PDF, EPS, DXF, Save for Web and
|
||||
Save for Office Documents included) that writes a file and that the batch does not point into `destinationFolder`. The dialog shows the same
|
||||
warning. For a Data Sets source,
|
||||
`datasetFileNaming?: fileNumber | fileDataSetName | dataSetName` chooses File + Number (`source001`),
|
||||
File + Data Set Name (`source_Alpha`), or Data Set Name (`Alpha`). An omitted parameter keeps File + Data Set Name
|
||||
for existing callers; the dialog starts with File + Number. A folder source ignores this parameter. The folder
|
||||
@@ -3656,6 +3873,12 @@ desktop app): in View › Pixel Preview, on softens placed and embedded bitmaps;
|
||||
`disableAutoAddDelete` (off by default): on, the Pen no longer adds or deletes an anchor when a click lands on a
|
||||
segment or an anchor of a selected path.
|
||||
|
||||
`ctrlWheelScrollsSideways` (on by default): on, Cmd/Ctrl-wheel scrolls the canvas sideways instead of zooming while
|
||||
`zoomWithMouseWheel` is off; off, Cmd/Ctrl-wheel zooms about the pointer. Alt + Cmd/Ctrl-wheel and a pinch on a Mac
|
||||
trackpad, on a touch screen or in the web build still zoom about the pointer. With `zoomWithMouseWheel` off, once a
|
||||
trackpad gesture holds Alt, it zooms until it ends, also after Alt is let go. The control channel's
|
||||
`ui.wheel` with `cmd: true` turns the wheel with Cmd/Ctrl held.
|
||||
|
||||
`gridlineEvery` (72 pt by default) and `gridSubdivisions` (8 by default) set the document grid that View › Show Grid
|
||||
draws, and View › Snap to Grid snaps to its subdivisions. Changing either sets the grid of every open document.
|
||||
`file.new` gives a new document that grid, and `document.open`, `file.newFromTemplate` and `file.revert` give it to
|
||||
@@ -3750,6 +3973,9 @@ Pen's second anchor at (150, 431), in line with the square's centre.
|
||||
|
||||
- `placeholderText` (on by default): type the Type tools place (`pointer_gesture` with `type`, `areaType`…) starts with
|
||||
placeholder text, selected, so `type_text` replaces it; `text.create` and `text.createInPath` take `placeholder: true`.
|
||||
- `typedLists` (on by default; Type › Start Lists From Typed Markers): a list marker and a space typed with the Type tool
|
||||
at the start of a paragraph start a list (see `text.startList`). Off, the Type tool leaves them as typed text;
|
||||
`text.startList`, `text.setFormat {list}` and the Bullets and Numbered List buttons work as before.
|
||||
- `typeSizeIncrement`, `trackingIncrement`, `baselineShiftIncrement`: what `type.step {attribute: "size" | "leading" |
|
||||
"tracking" | "kerning" | "baselineShift", by?}` steps by, on the text range given, the type objects in `ids`, the
|
||||
Type tool's selected text or the selected type objects. `type.size.increase` / `type.size.decrease` (Cmd+Shift+. and
|
||||
@@ -3930,7 +4156,7 @@ field with text clears it, and Escape in the empty field closes the dialog.
|
||||
`document.setup` with no params reports the document setup: units, the bleed ([top, bottom, left, right] in pt, drawn
|
||||
as a red outline around each artboard), the transparency grid (size and two colours; the first is also the simulated
|
||||
paper colour), the flattener preset and Discard White Overprint (Overprint Preview keeps white overprints visible while
|
||||
it is on), the type options (language and its quotes, Use Typographer's Quotes for typed quotes, superscript, subscript
|
||||
it is on), the type options (language and its quotes, Use Typographer's Quotes for typed straight quotes and a typed `”` where a quote opens, superscript, subscript
|
||||
and small caps proportions, SVG text export) and the background contents (white: raster exports are white behind the
|
||||
art). Pass any of these keys to change them in one undo step; `document.setUnits` stays as an alias for `units`.
|
||||
A file whose bleed (0 to 72 pt a side), superscript and subscript sizes (1 to 500%) and positions (-500 to 500%) or
|
||||
@@ -4084,6 +4310,15 @@ selects them. `edit.paste {artboardsAt: [x, y]}` instead centers the copied artb
|
||||
value that is not `[x, y]` fails with `` `artboardsAt` must be [x, y] ``. `artboard.duplicate {index? | indices?, art?}` does the same in one step → `{index, indices, ids}`.
|
||||
Window › Artboards › Duplicate Artboards passes the selected artboards (those the Artboard tool has selected, else the
|
||||
active one) as `indices`, and a row dragged onto New Artboard passes its artboard as `index`.
|
||||
`artboard.new {beside?, side}` adds an empty artboard the size of artboard `beside` (default: the last), 20 pt from
|
||||
that side of it, and `artboard.duplicate {index, side}` puts the copies there instead, together as they lay on that side
|
||||
of the artboards they copy; `side` is `"left"`, `"right"`, `"top"` or `"bottom"`. Another `side` fails with
|
||||
`` `side` must be "left", "right", "top" or "bottom" ``, `beside` without `side` fails with `` `beside` needs `side` ``,
|
||||
and `artboard.new` refuses `side` given with `x`, `y`, `width` or `height`; each leaves the document and its undo
|
||||
history as they were. With the Artboard tool and one artboard selected, a button with a plus shows just outside the
|
||||
middle of each edge where an artboard of the same size fits on that side (within the canvas and overlapping no other
|
||||
artboard): a click runs `artboard.new {beside, side}`, an Alt-click `artboard.duplicate {index, side, art: true}`, and
|
||||
the new artboard becomes the active one. An Alt-click on a locked artboard's button does nothing.
|
||||
`artboard.move {copy: true, moveArt: true}` is the Artboard tool's Alt-drag. `artboard.duplicate` and `artboard.move`
|
||||
also move the pattern tiles of the copies when `patterns` is true (default: prefs `transformPatternTiles`);
|
||||
`edit.paste` leaves the tiles of a pasted artboard's art where they were.
|
||||
@@ -4348,7 +4583,7 @@ image `object.rasterize` makes with the same options.
|
||||
## Glass textures
|
||||
|
||||
Glass (`distort.glass`) takes an image file as its surface in `params.textureImage`, as `{path}` or
|
||||
`{name?, dataBase64}`: a PNG, JPEG, GIF, WebP, TIFF, BMP, Targa, PSD, PSB, PCX, Pixar or JPEG 2000 file, decoded within the pixel allowance the
|
||||
`{name?, dataBase64}`: a PNG, JPEG, GIF, WebP, TIFF, BMP, Targa, PSD, PSB, PCX, Pixar, JPEG 2000 or HEIC/HEIF file, decoded within the pixel allowance the
|
||||
renderer draws images in, counted as RGBA. `effect.apply` and `effect.setParams` store the image's gray levels in the effect as a grayscale PNG
|
||||
in base64 and set `texture: "loaded"` unless the params give a `texture`. `effect.list` reports the stored string,
|
||||
and a command given that string stores it unchanged. Any other string, a file that is not an image, or an image past
|
||||
@@ -4373,6 +4608,14 @@ its file was found. Only files on this computer, or on the network share the doc
|
||||
on, are looked at: a path to another computer, a device or a URL counts as missing. On Windows, a document opened from
|
||||
a mapped drive (`Z:\…`) is on the share the drive is mapped to, and links on that share (`\\server\share\…`) are
|
||||
looked at. A link on a drive mapped to another share (`Y:\…`) counts as missing, from a document on this computer too.
|
||||
The links of an open document keep their relative paths from the file it was opened from (for a `.ai` file another
|
||||
app wrote, that file), also after a save to another folder. When a link's file is not at its path, a save and Package
|
||||
write the path relative to the new file of the place the file is found, or for a missing file of the place that
|
||||
relative path names, and a document made with New Document from State keeps the same places, so a document moved while
|
||||
its linked files were missing finds them once they are back in that folder. In the open document, a link
|
||||
is looked for at its path, then at its relative path from the folder of the file the document was opened from and from
|
||||
the document's own folder, then by name in those two folders. A link found away from its path takes the relative path
|
||||
of the place it was found.
|
||||
The result lists `missingLinks`
|
||||
(their images show the preview), `modifiedLinks` (left as they were; read again only with the preference
|
||||
`updateLinks: "automatically"`, then they are in `updatedLinks`), each as `{name, path, ids}`, with `refused` (why the
|
||||
@@ -4580,8 +4823,12 @@ and every stroke a line. `alterPaths` writes as filled outlines those strokes (w
|
||||
wider than the widest lineweight (2.11 mm), and every stroke in R13 and R14, which have no lineweights; it keeps other
|
||||
strokes as lines. `outlineText` outlines type, `selectedOnly` writes only the
|
||||
selected objects in their layers (every export takes it), and `useArtboards: true` writes one drawing per chosen
|
||||
artboard holding the art over it. What DXF can't hold (gradients and patterns as one colour, blending, opacity masks,
|
||||
raster effects, clipping) comes back in `warnings`. In R13 and later, an image that can't be decoded is left out with
|
||||
artboard holding the art over it. `dxfPreset: "cnc"` (CNC / CAM; default `"custom"`) sets the options for cutting
|
||||
software that the call does not give: version `2000` (the oldest version that has both lightweight polylines and lineweights), `unit:
|
||||
"mm"` and `scale: 1`, `colors: 256` (all version 2000 holds), `preserve: "editability"` with `alterPaths: false` (every
|
||||
stroke a center line), `outlineText: true` (type as paths), and `rasterFormat: "png"`. DXF Options has the same choice as its Preset menu,
|
||||
which shows Custom again once a field it sets is changed. What DXF can't hold (gradients and patterns as one colour,
|
||||
blending, opacity masks, raster effects, clipping) comes back in `warnings`. In R13 and later, an image that can't be decoded is left out with
|
||||
no linked file, and `warnings` carries "an image couldn't be decoded and is missing from the picture" once for all such
|
||||
images.
|
||||
|
||||
@@ -4592,6 +4839,7 @@ opened.
|
||||
```json
|
||||
{"name":"run_command","arguments":{"command":"document.exportDxf","params":{"path":"/tmp/plan.dxf","version":"2013","unit":"mm","scale":10,"preserve":"editability"}}}
|
||||
{"name":"export","arguments":{"path":"/tmp/plan.dxf","options":{"useArtboards":true,"colors":256}}}
|
||||
{"name":"run_command","arguments":{"command":"document.exportDxf","params":{"path":"/tmp/sign.dxf","dxfPreset":"cnc"}}}
|
||||
```
|
||||
|
||||
## DXF import
|
||||
@@ -4663,8 +4911,13 @@ document, objects, graphicStyles, brushes, spotColors, patterns, gradients, symb
|
||||
embeddedImages, repeats), `brushNames` (the Brushes panel's brushes; with `selectionOnly`, the brushes the selected
|
||||
objects' strokes use), `repeatObjects` (`[{id, name, type, instances, rows?, cols?}]`: every Repeat object, those in
|
||||
groups and in other repeats included, with its type `radial`, `grid` or `mirror` and the number of instances it makes,
|
||||
and a grid's `rows` and `cols`; with `selectionOnly`, the Repeat objects in the selection)
|
||||
and `pathLength` (pt: the total length of the paths, compound paths' pieces included and guides left
|
||||
and a grid's `rows` and `cols`; with `selectionOnly`, the Repeat objects in the selection), `patternObjects`
|
||||
(`[{id, name, patterns}]`: every object filled or stroked with a pattern, once each, those in groups and type objects
|
||||
whose drawn characters use a pattern included, hidden fills and strokes, strokes with no width, guides, a compound path
|
||||
member's own fills and strokes, an image's fills and strokes that no Convert to Shape or Outline Object effect gives a
|
||||
shape, and characters that draw nothing (spaces and line breaks without an underline or strikethrough) left out, with
|
||||
the patterns it uses, which the patterns category lists as Pattern Objects and `objects.patterns` counts; with `selectionOnly`, those in the selection),
|
||||
`patternNames` (the patterns those objects use) and `pathLength` (pt: the total length of the paths, compound paths' pieces included and guides left
|
||||
out, which objects lists as Path Length in the document's units, say for a cut line or an LED strip along the letters);
|
||||
`format: "text"` returns the plain-text report Document Info › Save… (`docInfo.save {path?, selectionOnly?, category?}`:
|
||||
only `category` when given, else every category) and the package report write.
|
||||
@@ -4708,7 +4961,8 @@ The Slice tool (`slice`, Shift+K) and the Slice Selection tool (`sliceSelection`
|
||||
`object.slice.create {x, y, width, height}` (the Slice tool's drag; it snaps to ruler guides), `object.slice.select
|
||||
{slices?, toggle?}`, `object.slice.move {slices?, dx, dy}` (an object slice moves its object),
|
||||
`object.slice.setRect {id, x, y, width, height}` (user slices) and `object.slice.delete {slices?}`. Slice ids are user
|
||||
slice ids and the ids of objects with an object slice.
|
||||
slice ids and the ids of objects with an object slice. `object.slice.select` with `slices` left out or null deselects
|
||||
the slices.
|
||||
|
||||
```json
|
||||
{"name":"run_command","arguments":{"command":"object.slice.create","params":{"x":0,"y":0,"width":200,"height":80}}}
|
||||
@@ -4902,8 +5156,12 @@ or in `options` (`file.formatOptions {format}` lists them with their values):
|
||||
- `includeLinked: true` keeps linked images' own pixels in the file (they stay linked), not just the previews.
|
||||
- `embedProfiles` (default true) carries the ICC profiles the document is tagged with that were loaded from files;
|
||||
opening the file installs them where they are missing (a warning names one that can't be used).
|
||||
- `pdfCompatible`: native files (default false) also carry a PDF of every artboard (`pdf` in the file); `.ai` files
|
||||
- `pdfCompatible`: native files (default true) also carry a PDF of every artboard (`pdf` in the file). This makes saves
|
||||
larger and adds PDF rendering work. Set it to false to leave the PDF out; Save remembers that choice. `.ai` files
|
||||
(default true) with false write blank pages around the native document (smaller; other apps show empty pages).
|
||||
Native files without artboards and Data Recovery copies omit the PDF.
|
||||
Reopening a native file keeps its saved PDF preference, falling back to whether it declared a PDF in older files.
|
||||
Existing files saved without a PDF remain compact.
|
||||
- `.ai` only: `compress` (default true) is the PDF option `compression.compressText`.
|
||||
- The editing copy of a `.ai` or `.ait` file (`editingData`) names its active artboard (`CropAreaActive`): the active
|
||||
artboard of the app's view when the app saves or exports the file, otherwise the artboard the document opened on (the
|
||||
@@ -5027,6 +5285,38 @@ renderer measures for what the art draws, its effects included.
|
||||
A layer id in `ids` (12 above) is the same as Collect for Export on that Layers row: every object under the layer
|
||||
becomes an asset (or one asset with `multiple: false`).
|
||||
|
||||
### 3D assets
|
||||
|
||||
Asset Export's menu item Export 3D Object (`assets.add3D {ids?, format?}`) collects each selected object (or `ids`)
|
||||
that carries Extrude & Bevel, Revolve, Inflate or Rotate as a 3D asset, named after the object; an object already
|
||||
collected as a 3D asset keeps it, and an object without such an effect is refused. A 3D asset's Format is `usda` (the
|
||||
default), `usdz`, `gltf` or `obj`; the panel shows a Format row for the 3D assets it would export, and
|
||||
`assets.set3DFormat {assets, format}` sets it (an undo step only when the format changes). `assets.list` gives each
|
||||
asset's `format3D` (null for a picture asset).
|
||||
|
||||
`assets.export3D {assets?, folder?, zip?}` writes each 3D asset (default: all of them) as a mesh file named after it:
|
||||
`.usda`, `.usdz`, `.gltf` (glTF 2.0, its buffer embedded) or `.obj` with its `.mtl` (whitespace and `#` in an OBJ's
|
||||
name become `_`). Every solid of the object (the
|
||||
fill's, each stroke's, a group's members') is its own mesh, with a two-sided material in the color it is painted
|
||||
(a gradient's stops averaged, a pattern gray). The mesh holds the solid's faces before they are projected onto the
|
||||
page, those turned away from the viewer included, at the object's 3D rotation, y up, about the point the object turns
|
||||
about: in points (USD's layer gives `metersPerUnit`), in meters in glTF. Files that would share a name get `-2`, `-3` and so on.
|
||||
With `zip`, the files go into one ZIP named after the document with `-3D` added (`Untitled-1-3D.zip`), or
|
||||
`3D Assets.zip` when the document's title gives no file name.
|
||||
An object whose face has a hole that crosses the face's outline or another hole is refused, by `assets.add3D` and
|
||||
`assets.export3D` alike, rather than exported with the hole filled. So is an object whose meshes would hold more than
|
||||
2,000,000 triangles together, VectorCraft's own limit.
|
||||
`assets.export` leaves 3D assets out and refuses one named in its `assets`. On the 3D export page
|
||||
(<https://helpx.adobe.com/illustrator/desktop/special-effects-styles/create-3d-graphics/export-3d-vector-artwork.html>)
|
||||
the 3D asset's Format is picked in Asset Export, with USDA first; the file layouts follow the glTF 2.0 specification
|
||||
(<https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html>) and OpenUSD (<https://openusd.org/release/index.html>).
|
||||
|
||||
```json
|
||||
{"name":"run_command","arguments":{"command":"assets.add3D","params":{"ids":[12],"format":"gltf"}}}
|
||||
{"name":"run_command","arguments":{"command":"assets.set3DFormat","params":{"assets":[40],"format":"obj"}}}
|
||||
{"name":"run_command","arguments":{"command":"assets.export3D","params":{"folder":"/tmp/meshes"}}}
|
||||
```
|
||||
|
||||
## CSS Properties
|
||||
|
||||
`css.selection {ids?, units?, position?, dimensions?, unnamed?, rasterize?}` returns the CSS web pages style the
|
||||
@@ -5556,6 +5846,53 @@ dialog open.
|
||||
{"name":"run_command","arguments":{"command":"text.setRangeStyle","params":{"id":12,"start":0,"end":4,"tateChuYoko":true,"tcyUpDown":2,"tcyLeftRight":-1}}}
|
||||
```
|
||||
|
||||
## Composite Fonts
|
||||
|
||||
A composite font sets each class of character in a font of its own
|
||||
([Creating composite fonts](https://help.adobe.com/archive/en_US/illustrator/cs3/illustrator_cs3_help.pdf#page=347)).
|
||||
`type.compositeFonts.set {fonts: [{name, parts}]}` replaces the active document's composite fonts as one undo step,
|
||||
and adds no step when nothing changes. `parts` holds `kanji` (the base font), `kana`, `punctuation`, `symbols`, `roman`
|
||||
and `numerals`, each `{font, style?, size?, baseline?, hScale?, vScale?, scaleAtCenter?}`; a part left out copies the
|
||||
`kanji` part. Which characters fall in each class is VectorCraft's own rule: Kanji takes ideographs, full-width
|
||||
letters and digits and every character no other class takes; Kana takes hiragana and katakana of both widths;
|
||||
Punctuation takes East Asian and full-width punctuation, quotes and dashes; Symbols takes arrows, math, shapes and
|
||||
other symbols; Roman takes half-width letters, their punctuation and spaces; Numerals takes the digits 0 to 9.
|
||||
|
||||
`size` (10 to 400, 100 by default) and `baseline` (-100 to 100, 0 by default; positive raises) are percentages of the
|
||||
type's size, VectorCraft's own ranges. `hScale` and `vScale` (10 to 400, 100 by default) scale Kana, Roman and
|
||||
Numerals only, and `scaleAtCenter` (Kana only) scales kana from the center of the em box instead of the baseline. A
|
||||
value out of range, a scale on another class, an unknown class or key, a name that is empty, longer than 255
|
||||
characters, shared by two fonts (in any case) or the name of an installed font, and a part set in a composite font are
|
||||
each refused with an error, and nothing changes. A document keeps at most 256.
|
||||
|
||||
Type set in a composite font names it as its family (`text.setStyle {font: "My Composite"}`), and the font menus list
|
||||
composite fonts first. The layout sets each character in its class's font, a letter and its combining marks together.
|
||||
A composite font taken out of the document leaves its type naming it, and the type shows as missing. Composite fonts
|
||||
are saved with the document. SVG and legacy `.ai` write type in one of the document's composite fonts as outlines, and
|
||||
SVG, PDF, EPS and legacy `.ai` export draw it in the font's parts also when the document was read without an open app.
|
||||
`type.compositeFonts.list` returns the document's composite fonts.
|
||||
|
||||
`text.replaceFont` and `addon.cleanup.replaceFonts` with a composite font as the new font set the type in it by its own
|
||||
name, and the type keeps its style. `text.fonts` lists a composite font by its name; its `status` is the worst among the
|
||||
parts its characters are drawn in, and `missingGlyphs` counts the characters that their part's font lacks.
|
||||
`text.missingFonts`, File › Package and the warnings about fonts that aren't available name the part fonts that the
|
||||
characters are drawn in. `text.glyphAlternates` lists the alternates of a character from its part's font.
|
||||
|
||||
`type.compositeFonts.export {path?, names?, fonts?}` writes the document's composite fonts (all, or those `names`
|
||||
lists), or the `fonts` given, to a `.vccomposite` file; without `path` it returns the file's text as `data`.
|
||||
`type.compositeFonts.import {path | data | dataBase64, apply?}` reads a file of at most 4 MB. With `apply` (the
|
||||
default) its fonts join the document's, replacing a font of the same name, as one undo step; with `apply: false` it
|
||||
only returns them. Opening a `.vccomposite` file imports it.
|
||||
|
||||
Type › Composite Fonts… (shown with Show East Asian Options) opens the Composite Fonts dialog on the document's fonts:
|
||||
Font picks one, and a table sets each class's font, style, size, baseline and scales. New adds a font based on the one
|
||||
picked, Delete Font takes it out, Import… adds the fonts of a file and Export… writes the one picked. OK runs
|
||||
`type.compositeFonts.set` with every font as one undo step; a refused font keeps the dialog open.
|
||||
|
||||
```json
|
||||
{"name":"run_command","arguments":{"command":"type.compositeFonts.set","params":{"fonts":[{"name":"My Composite","parts":{"kanji":{"font":"Source Han Sans"},"roman":{"font":"Source Sans 3","size":95,"baseline":-2},"numerals":{"font":"Source Sans 3"}}}]}}}
|
||||
```
|
||||
|
||||
## Optical Margin Alignment
|
||||
|
||||
`type.opticalMarginAlignment {on?: bool}` (Type › Optical Margin Alignment) turns Optical Margin Alignment on or off
|
||||
@@ -5641,13 +5978,37 @@ the text. Return at the end of a list item starts another item in the same list.
|
||||
set, and paragraph styles carry it: a style captured from a paragraph without a list turns the list off. Reset Panel
|
||||
turns it off. The change is one undo step.
|
||||
|
||||
`text.setFormat {listAlign: "left"|"right"}` (Bullets and Numbering › Alignment) sets where the marker stands before
|
||||
the first line's text. With `"left"`, the default, the marker starts where the first line starts, at the left indent
|
||||
plus the first-line indent. With `"right"` the marker ends where the text starts, against the text. The text starts at
|
||||
the same place with either alignment, so numbers of different widths aligned right end at the same place, and a number
|
||||
that reaches past the left indent ends at the next tab stop, where the text starts. In a right-to-left list paragraph a
|
||||
marker aligned right starts where the text ends. `listAlign` sets the paragraphs that are in a list, and those that the
|
||||
same call puts in one; a paragraph in no list stays out of one. A list keeps its alignment when it changes between
|
||||
bullets and numbers, and a list that is turned off and on again starts aligned left. An unknown value is an error and
|
||||
changes nothing. The list saves the alignment (`"align": "right"`) only when it is right.
|
||||
|
||||
`text.setFormat {listLevel: 1..9}` (Bullets and Numbering › Level) sets the level of the list paragraphs it touches, and
|
||||
of those that the same call puts in a list; a paragraph in no list stays out of one. The value is a whole number from 1
|
||||
to 9 (`2` or `2.0`); any other value is an error and changes nothing. Each level past the first
|
||||
sets the paragraph 18 pt further in than its left indent: its marker, its text and the lines it wraps to move together,
|
||||
and in a right-to-left list paragraph they move in from the right. A list keeps its level when it changes between
|
||||
bullets and numbers, and a list that is turned off and on again starts at level 1. The list saves the level
|
||||
(`"level": 3`) only when it is not 1. In the Type tool, Tab with the caret at the start of a list paragraph (before its
|
||||
first character, with nothing selected) runs `text.setFormat {listLevel}` with the next level, and Shift+Tab with the
|
||||
level before; each is one undo step, and the text is unchanged. Tab at level 9 and Shift+Tab at level 1 do nothing.
|
||||
Anywhere else, with characters selected, or in a paragraph in no list, Tab and Shift+Tab insert a tab.
|
||||
|
||||
A numbered paragraph's number counts the numbered paragraphs of its story up to and including it: the count runs through
|
||||
consecutive list paragraphs, through the frames of threaded type in thread order, and starts again at 1 after a
|
||||
paragraph in no list. An empty paragraph has no number and is not counted, and a bulleted paragraph keeps its bullet and
|
||||
is not counted. Letters run from A to Z, then AA to ZZ, then AAA; roman numerals use IV, IX, XL, XC, CD and CM; 01 and
|
||||
is not counted. Each level counts its own numbers: a list paragraph that has text sets the counts of the levels
|
||||
deeper than its own back to 0, so a deeper numbered paragraph after it counts from 1, and a paragraph back at a
|
||||
shallower level goes on with that level's count. Letters run from A to Z, then AA to ZZ, then AAA; roman numerals use IV, IX, XL, XC, CD and CM; 01 and
|
||||
001 keep every digit past 99 and 999; letters and roman numerals past 3999 are written in Arabic digits. In a
|
||||
right-to-left paragraph the number reads left to right with its period at its left. Each threaded frame saves the count
|
||||
that its earlier frames carry into it (`listCount`, only when it is not 0). Type that is in no thread counts from 1:
|
||||
that its earlier frames carry into it at level 1 (`listCount`, only when it is not 0) and at the levels past it
|
||||
(`listLevelCounts`, level 2 first, only when one of them is not 0). Type that is in no thread counts from 1:
|
||||
after Remove Threading or Release Selection, in a frame converted to point type, and in every copy of a frame (pasted,
|
||||
duplicated, copied in the Layers panel, or taken out of a symbol or a placed file). A symbol made of a thread keeps the
|
||||
numbers in the symbol's art.
|
||||
@@ -5668,12 +6029,29 @@ Type › Bullets and Numbering › Apply Bullets and the canvas context menu's B
|
||||
same menus runs `type.applyNumbers {number?}`. Without `number` it runs `text.setFormat {list: "number"}`, and with it
|
||||
it runs `text.setFormat {number}`.
|
||||
|
||||
More Options at the end of the Paragraph panel's Bullets and Numbered List presets runs `ui.bulletsAndNumbering {tab?: "bullets"|"numbers"}`. It opens the Bullets and Numbering
|
||||
dialog (`bulletsAndNumbering`) on the paragraphs the Paragraph panel acts on, on that tab; without `tab` it opens on
|
||||
Numbers when the paragraphs are a numbered list and on Bullets otherwise. On both tabs the Level field, above the
|
||||
presets, holds the paragraphs' list level (1 to 9; 1 for paragraphs in no list). The Bullets tab has the five bullet
|
||||
presets and the Numbers tab has None and the seven number styles. The Position group has Alignment (Left or Right),
|
||||
Left Indent and First Line Indent. The dialog opens with the values the Paragraph panel shows; where the paragraphs
|
||||
differ, no preset is picked and the field is blank. Its fields are `tab`, `list` (`none`, `bullet` or `number`: the
|
||||
kind of the preset picked), `bullet`, `number`, `listAlign`, `listLevel`, `leftIndent` and `firstLineIndent` (points),
|
||||
and `ui.dialog.set` sets them, including those the dialog opened blank or without. The type shows the dialog's values while it is open. A preset picked for paragraphs that are in no list and have
|
||||
no indents fills in 18 pt and -18 pt, and None takes them out again while they are unchanged. OK runs `text.setFormat`
|
||||
with the values that changed, as one undo step, and Cancel puts the type back as it was. When a preset puts the
|
||||
paragraphs in a list, OK also sends the indents the dialog shows, and the paragraphs take them, 0 included. OK does not
|
||||
send an Alignment or Level change for paragraphs that stay in no list. With no type selected, or
|
||||
with an unknown `tab`, `ui.bulletsAndNumbering` is an error.
|
||||
|
||||
Type › Bullets and Numbering › Convert to Text runs `type.convertListToText` on the selected type's paragraphs, or on
|
||||
those the Type tool's selection touches, and that runs `text.convertListToText {ids?, start?, end?}`. The marker of
|
||||
each list paragraph becomes characters at the start of the paragraph: the bullet, or the number and its period as the
|
||||
paragraph showed it, then a tab. They are set in the marker's font, size and color: the style of the paragraph's first
|
||||
character without the attributes the marker leaves out. The paragraph leaves its list. When the marker's tab went to
|
||||
the left indent, the paragraph gets a left-aligned tab stop without a leader there, in place of any stop there, so that
|
||||
character without the attributes the marker leaves out. The paragraph leaves its list. A paragraph at a list level
|
||||
past the first keeps the level's indent in its left indent, so its marker and text stay where they were. A marker aligned right
|
||||
(`listAlign` `right`) is written the same way: its characters go to the first line's start, where a marker aligned left
|
||||
is drawn, and the text after its tab stays where it was. When the marker's tab went to the left indent, the paragraph gets a left-aligned tab stop without a leader there, in place of any stop there, so that
|
||||
the text after the tab starts where it started after the marker. When the marker's tab went to a tab stop, the
|
||||
converted tab goes to the same place when that stop is left-aligned and no stop there or past it has a leader. When a
|
||||
stop there or past it has a leader or is not left-aligned, or a right, center or decimal stop lies between the marker
|
||||
@@ -5703,18 +6081,23 @@ next to the same character, and that frame becomes the selection when it was not
|
||||
Typing starts a list too. When the Type tool types a space on its own (one key press, or `type_text {text: " "}`) right
|
||||
after `1.` or `1)`, `A.` or `A)`, or one of `*`, `#`, `>` and `+` at the start of a paragraph that is in no list, the
|
||||
typed characters and the space are removed and the paragraph becomes a numbered list in 1, 2, 3 or A, B, C, or a
|
||||
bulleted list with the filled dot. A list started with `1)` or `A)` also writes its numbers with a period. A paragraph
|
||||
bulleted list: `*` gives the filled dot (•), `+` the hollow circle (◦), `#` the filled square (▪) and `>` the dash
|
||||
(–). A list started with `1)` or `A)` also writes its numbers with a period. A paragraph
|
||||
whose left and first-line indents are both 0 gets 18 pt and -18 pt. The tool runs `text.startList {id, at}`, with `at`
|
||||
the byte after the space, as an undo step of its own after the typing: one Undo puts the characters back as text with no
|
||||
list, and typing goes on after them; Redo removes them again, and typing goes on before the paragraph's text. The same
|
||||
characters later in a paragraph start nothing, and so do list characters that arrive in one piece with the space: a
|
||||
paste, an IME commit, or `type_text` of a longer string. From a script, `text.startList {id, at?}` (`at` defaults to the end of the text) does
|
||||
paste, an IME commit, or `type_text` of a longer string. With the `typedLists` preference off (Preferences › Type ›
|
||||
Start Lists From Typed Markers), the Type tool starts no list from typed characters. From a script, `text.startList {id, at?}` (`at` defaults to the end of the text) does
|
||||
the same with the text before `at` and returns `started` and `caret`. When the list starts, `caret` is the byte where
|
||||
the paragraph's text now starts; when the text before `at` starts no list, nothing changes, `started` is false and
|
||||
`caret` is `at`.
|
||||
```json
|
||||
{"name":"run_command","arguments":{"command":"text.setFormat","params":{"bullet":"square"}}}
|
||||
{"name":"run_command","arguments":{"command":"text.setFormat","params":{"number":"upperRoman"}}}
|
||||
{"name":"run_command","arguments":{"command":"text.setFormat","params":{"listAlign":"right"}}}
|
||||
{"name":"run_command","arguments":{"command":"text.setFormat","params":{"listLevel":2,"start":4,"end":4}}}
|
||||
{"name":"invoke_menu","arguments":{"command":"ui.bulletsAndNumbering","params":{"tab":"numbers"}}}
|
||||
{"name":"run_command","arguments":{"command":"text.convertListToText","params":{}}}
|
||||
```
|
||||
|
||||
@@ -5936,8 +6319,12 @@ Type on a path flows between a start and an end bracket, stored as fractions of
|
||||
Path Options: `end: null` puts the end bracket back at the end of the path (or once round a closed one); `flip`
|
||||
then turns the type to the other side of its path, the path running the other way and the brackets swapping ends so
|
||||
the type keeps its stretch of the path; `alignToPath` runs the `ascender`, `descender`, `center` or `baseline` (the
|
||||
default) along the path; `spacing` (points) closes glyphs up round the outside of curves and opens them up round the
|
||||
inside. With none of them it queries the first selected type on a path:
|
||||
default) along the path, each character by its own font, size and vertical scale: `ascender` runs the top of the
|
||||
font's em box along it (its ideographic em box, else an em box centered on the cap height), `descender` runs the
|
||||
bottom of the font's bounding box along it, and `center` runs a line at half the height of the top of the font's H
|
||||
above the baseline along it (in vertical type, `ascender` and `descender` move the characters half an em with their
|
||||
horizontal scale, and `center` leaves them on the path); `spacing` (points) closes glyphs up round the outside of
|
||||
curves and opens them up round the inside. With none of them it queries the first selected type on a path:
|
||||
`{start, end, flip: false, effect, alignToPath, spacing}`. The Options dialog shows Effect, Flip, Align to Path and
|
||||
Spacing and leaves the brackets where they are. As in the reference app, the Selection and Direct Selection tools
|
||||
show selected type on a path's brackets: dragging the start or end bracket (`pointer_gesture`) sets where the type
|
||||
@@ -6097,22 +6484,67 @@ runs it where it is called, so the call may take minutes; `notifications/cancell
|
||||
A plug-in whose manifest lists permissions (`permissions` in its `plugin.inspect` entry, with `needsApproval: true`)
|
||||
installs only with `grant: [permission]` listing every one of them: show the user the list and ask first, and pass
|
||||
the entry's `hash` as `hash` so that a module that changed since is refused. Without `grant`, `plugin.install` returns
|
||||
an error naming the permissions needed. The grant is kept with the module's hash; a module
|
||||
with the same id that lists no new permission installs without `grant`, and `plugin.remove` forgets the grant. A
|
||||
an error naming the permissions needed. The grant is kept with the module's hash; without a `Plug-ins` folder, a
|
||||
module with the same id that lists no new permission installs without `grant`. A grant kept in a `Plug-ins` folder
|
||||
covers only the module with that hash, so another module under the id needs `grant` again. `plugin.remove` forgets the
|
||||
grant. A
|
||||
filter without `doc.write` or `state` that returns output needing them gets an error and the document is unchanged.
|
||||
A plug-in of API level 2 (`api: 2` in its entry) that lists `progress` may report its progress, see Cancel and write
|
||||
log lines: `notifications/cancelled` makes its `vc_cancelled` return 1, and its log lines go to the server's log
|
||||
under its id. A module that imports anything else, or imports these without `api` 2 and `progress`, is refused by
|
||||
`plugin.install` and `plugin.inspect` with an error naming the import.
|
||||
under its id. One that lists `settings` or `cache` keeps settings or a cache of its own in the `Plug-ins` folder
|
||||
(VectorCraft's own caps: 256 settings and 1 MiB, 512 MiB of cache): `plugin.list` and `plugin.info` give the cache's
|
||||
size as `cacheBytes`, `plugin.clearCache {id?}` empties the cache of one plug-in or of all of them and returns
|
||||
`{cleared: [id], bytesFreed}`, replacing a plug-in keeps both, and `plugin.remove` deletes both (also for an id that
|
||||
isn't installed but still has them). A module with other bytes than the plug-in installed with its id, or, with none
|
||||
installed, one whose id has settings or a cache in the
|
||||
`Plug-ins` folder (`needsReplace: true` in its `plugin.inspect` entry), installs only with `replace: true`: ask the
|
||||
user first, since it takes that plug-in's place and gets its settings and cache. Without it, `plugin.install` returns
|
||||
an error naming the plug-in. The same module installs again without `replace`, and `replace: false` refuses a module
|
||||
whose id is installed. A module that imports
|
||||
anything else, or imports one of these without `api` 2 and the import's permission, is refused by `plugin.install` and
|
||||
`plugin.inspect` with an error naming the import and the permission.
|
||||
`plugin.install` rejects a `replace` or `allowHeavy` value that is not a boolean, a `grant` that is not a list of
|
||||
permission names, and a `hash` that is not the module's SHA-256. `prefs.set` returns an error and
|
||||
changes nothing when a new `pluginsFolder` is missing, is not a folder or can't be listed. It does not check an empty
|
||||
value or the folder the preference already holds, and the web build does not check folders.
|
||||
|
||||
Safe Mode starts VectorCraft without plug-ins: `vectorcraft --safe-mode`, `vectorcraft-cli --safe-mode <subcommand>`, or
|
||||
the choice the desktop app offers when the last launch stopped while a plug-in was loading (Disable and Continue, Start
|
||||
Normally, Start in Safe Mode). It names that plug-in without saying it caused the stop. Until the user picks Disable and
|
||||
Continue or Start Normally, the next launch asks again, also after a `--safe-mode` launch, which asks nothing.
|
||||
`vectorcraft --safe-mode` opens its files in a window of its own, and on Windows and Linux a file opened from the file
|
||||
manager while the app is in Safe Mode starts a window with plug-ins. Files given on the command line, or opened from
|
||||
the file manager while the choice is up, open after the user picks. On Windows and Linux, when the choice is Start in Safe
|
||||
Mode, the files from the file manager open in a new window with plug-ins. `vectorcraft-cli --safe-mode mcp` serves a headless
|
||||
session and refuses `--connect`. In Safe Mode no plug-in loads or
|
||||
runs: `plugin.install`, `plugin.run`, `plugin.reload` and exporters return an error, and a live-effect plug-in draws its
|
||||
object's geometry unchanged while the object keeps the effect: `effect.list` gives that effect `skipped: true`, and the
|
||||
Appearance panel shows "(Safe Mode)" after its name and the plug-in's id in its tooltip. `effect.expandAppearance` returns an
|
||||
error and changes nothing when an object it would expand holds such an effect, in it or in a symbol it places. `vectorcraft` rejects an option it does not know (such as
|
||||
`--safe-mod`) instead of opening it as a file; `--` before a file name that starts with `-` opens it. The web build keeps
|
||||
no installed plug-ins from one page load to the next and has no launch marker, so it never offers the choice. `plugin.safeMode` returns `{active, source, disabled,
|
||||
pendingItem}`; a command does not turn Safe Mode on or off. `plugin.setEnabled {id | file, enabled}` turns a plug-in on or
|
||||
off for the next launch, as Help › Safe Mode's Enable on Re-launch does; it does not load, unload or uninstall anything
|
||||
now, and `plugin.install` of a disabled plug-in turns it on. Turning a plug-in on by `id` or by installing it also turns
|
||||
on the file it is stored in, which names it when it stopped a launch while loading; when the new version can't be saved
|
||||
over that file, the plug-in stays disabled. `plugin.list` reports `safeMode` and `disabled`, and
|
||||
`plugin.reload` skips disabled plug-ins. A change to the disabled list is saved on top of the list the file holds at
|
||||
that moment, so a change another window saved to the same preferences meanwhile is kept. When the list file can't be
|
||||
read (it is too large) or holds another format or version, it is left as it is; a file that isn't JSON is replaced.
|
||||
`plugin.setEnabled` returns `saved: false` when its change isn't in the plug-in folder: the session has none (a server
|
||||
confined with `--automation-read-root` or `--automation-write-root`), the list there can't be read or written, or it
|
||||
already holds 1,000 plug-ins, as another window may have saved it. The
|
||||
change stays in the process and is saved with the next change that saves, and the app shows a status message. When
|
||||
Disable and Continue can't save the plug-in it turns off, this launch skips it and the next launch asks again.
|
||||
|
||||
```json
|
||||
{"name":"run_command","arguments":{"command":"plugin.safeMode","params":{}}}
|
||||
{"name":"run_command","arguments":{"command":"plugin.setEnabled","params":{"id":"org.example.wobble","enabled":true}}}
|
||||
{"name":"run_command","arguments":{"command":"plugin.install","params":{"path":"/plugins/desaturate.wasm"}}}
|
||||
{"name":"run_command","arguments":{"command":"plugin.run","params":{"id":"org.vectorcraft.example.desaturate","params":{"amount":60}}}}
|
||||
{"name":"run_command","arguments":{"command":"effect.apply","params":{"effect":"plugin.org.example.wobble","params":{"size":4}}}}
|
||||
{"name":"run_command","arguments":{"command":"plugin.install","params":{"path":"/plugins/tiles-2.wasm","replace":true}}}
|
||||
{"name":"run_command","arguments":{"command":"plugin.clearCache","params":{"id":"org.example.tiles"}}}
|
||||
```
|
||||
|
||||
## Colour adjustments
|
||||
@@ -6375,6 +6807,18 @@ Object → Envelope Distort wraps the selection in a live envelope: `object.enve
|
||||
arcLower, arcUpper, arch, bulge, shellLower, shellUpper, flag, wave, fish, rise, fisheye, inflate, squeeze or twist;
|
||||
`bend`, `h` and `v` in % from -100 to 100; `horizontal` or `orientation`), `object.envelope.makeWithMesh` (`rows`,
|
||||
`cols`: 1–50) and `object.envelope.makeWithTopObject` (the topmost selected path becomes the envelope).
|
||||
A top object's outline is split into four sides at four corners. Each corner is the anchor nearest a corner of the
|
||||
outline's bounding box among the anchors within 47.5% of the box's width and height from that box corner that count as
|
||||
corners: an anchor with a handle 0.01 pt long or shorter, or one whose tangent unit vectors differ by 0.01 or more in
|
||||
x or y and turn out of the outline. In this test a straight segment counts as having its handles a third of the way
|
||||
along it, so an anchor between two straight segments longer than 0.03 pt is a corner only when it turns out of the
|
||||
outline. On a tie, the anchor met first along the outline in the order it was drawn wins.
|
||||
Without such an anchor, the corner is the outline's point nearest the box corner, moved onto the anchor at the end of
|
||||
its segment when within 0.5% of the segment's parameter. Each piece of a side between anchors and corners takes a
|
||||
share of the content's width or height in proportion to the length of its control polygon, spread along the piece by
|
||||
its curve parameter, so content spreads evenly along a segment without handles. An envelope opened from an `.ai` file
|
||||
keeps the corners the file saves, and they stay on the same anchors when the envelope is moved, rotated or
|
||||
reflected. These are VectorCraft's own rules, and existing top-object envelopes redraw by them.
|
||||
`object.envelope.info` reads the selected envelope's settings (`type`, the warp's or mesh's values, `fidelity` and
|
||||
the options, `editing`), or with no envelope selected the options new envelopes get. With an envelope selected,
|
||||
`object.envelope.resetWithWarp` and `object.envelope.resetWithMesh` (`rows`, `cols`, `maintainShape`: true keeps
|
||||
@@ -6474,7 +6918,8 @@ bounding-box handles scale it in plane space (`perspective.transform`; Shift kee
|
||||
centre), and `press_key` `5` during a drag switches the move to perpendicular to the plane (press again to switch
|
||||
back). Holding Shift during an in-plane move constrains each object's displacement to an axis or 45° diagonal of its
|
||||
own plane. `perspective.move` accepts `constrain: true` (default false) and adjusts Snap to Grid along the constrained
|
||||
direction on the first object's plane and depth.
|
||||
direction on the first object's plane and depth. With Snap to Grid, every object on the first object's plane moves
|
||||
by the same plane offset, whatever its depth, and the edge of their joint bounds nearer a gridline lands on it.
|
||||
`press_key` Escape during a move, a resize or a plane widget drag cancels it and puts the objects and the
|
||||
grid back. The arrow keys nudge a selection in perspective by the keyboard increment (`perspective.nudge`; Shift ×10, Alt
|
||||
copies). Object › Transform › Transform Again repeats the last perspective move or scale in plane space.
|
||||
@@ -6742,6 +7187,40 @@ the entry names and decodes the codes that VectorCraft's default shortcuts agree
|
||||
{"name":"run_command","arguments":{"command":"importMatches.set","params":{"matches":[{"kind":"name","name":"Group","target":"object.group"},{"kind":"key","name":"901","target":"G"}]}}}
|
||||
```
|
||||
|
||||
## Action sets from other apps
|
||||
|
||||
`actionSet.read {path? | data? | dataBase64?, name?}` reads an action set another app saved as text (an `.aia` file
|
||||
that starts with `/version`) without changing anything. Give exactly one of `path`, `data` and `dataBase64`. It returns
|
||||
the set's name (`set`, else the file's name, else empty), its `version`, and its `actions`, each with its `name` and
|
||||
`steps`. A step lists its `name` (the file's `/internalName`), its `label` (the `/localizedName` it is shown with, or
|
||||
null when it has none or it is blank), `on` (false when the file sets `/isOn 0`), `params` (how many recorded values it
|
||||
has) and its `line`. `unread` lists the tokens the reader skipped, with their lines. The reader stops at 8 MiB, 16 open
|
||||
blocks, 1,000 actions, 10,000 steps in an action and 100,000 steps in the set, and cuts names at 1,024 bytes. It sets
|
||||
`truncated` when it reaches one of these limits, when the text ends inside a block or a value or after a field's name,
|
||||
when `/actionCount`, `/eventCount` or a step's `/parameterCount` differs from the actions, steps or recorded values read
|
||||
(a negative count, one too large for a number and one that is not a number always differ), or when a hexadecimal name,
|
||||
label or recorded `/value` is not as many bytes as its count says. Text that does not start with `/version` and a
|
||||
number is an error.
|
||||
|
||||
`ui.actionSet.load` (the Actions panel menu's Load Actions…) reads such a file too, from `path`, a picked file or
|
||||
`data`, and adds its set after the other sets with all its actions. The set's name is the file's `/name`, else the
|
||||
file's name, else `Actions`. A step with a label and no recorded values comes in as the VectorCraft command with that
|
||||
label, in English or in the interface language, in any case and without a final `…`, when exactly one menu command has
|
||||
that label and that command is directly in a top menu, can be recorded in actions, is what its menu bar item runs with
|
||||
no values and opens no dialog (Group, Ungroup). A submenu's items, file and document commands, Paste, Undo, Redo and
|
||||
add-on commands are never matched. The step runs with no params, and a step that is off in the file is excluded from
|
||||
playback. Other steps are left out, including every step with no label and every step recorded with values (recorded
|
||||
menu items too). The reply lists the first 1,000 in `skipped` (`{action, step}`, the step by its label, else its name),
|
||||
`leftOut` counts them, and the status bar says how many were left out. An action with no name is called `Action N`, by
|
||||
its place in the file. Function keys and colors are not read. A file marked `truncated` is refused, and no set is added.
|
||||
Text that starts `/version` and is not an action set gives "not an action set file". Tokens in `unread` do not stop a
|
||||
load.
|
||||
|
||||
```json
|
||||
{"name":"run_command","arguments":{"command":"actionSet.read","params":{"path":"/Users/me/Prep.aia"}}}
|
||||
{"name":"run_command","arguments":{"command":"ui.actionSet.load","params":{"path":"/Users/me/Prep.aia"}}}
|
||||
```
|
||||
|
||||
## Artwork Cleanup add-on
|
||||
|
||||
Artwork Cleanup is a built-in add-on: its commands are `addon.cleanup.*`, and in the desktop app it lives in Object ›
|
||||
|
||||
+81
-18
@@ -23,12 +23,13 @@ This page is the contract for plug-in authors and the reference for the host (`c
|
||||
|
||||
| Command | Params | What it does |
|
||||
|---|---|---|
|
||||
| `plugin.list` | `{}` | `{"plugins": [{id, name, version, kind, author, description, params, paramsSchema, effect?, format?, extensions?, budget?, size, source, api, permissions, hash}], "folder": report}` (`api` is the manifest's [plug-in API level](#permissions); `budget: "heavy"` for a [heavy filter](#heavy-filters); `permissions` lists what it [may do](#permissions), `hash` is the module's SHA-256) |
|
||||
| `plugin.list` | `{}` | `{"plugins": [{id, name, version, kind, author, description, params, paramsSchema, effect?, format?, extensions?, budget?, size, source, api, permissions, hash, cacheBytes}], "folder": report}` (`api` is the manifest's [plug-in API level](#permissions); `budget: "heavy"` for a [heavy filter](#heavy-filters); `permissions` lists what it [may do](#permissions), `hash` is the module's SHA-256; `cacheBytes` is the size of its [cache](#settings-and-cache)) |
|
||||
| `plugin.info` | `{"id"}` | One plug-in: the `plugin.list` entry plus `manifest`, `defaults` and `lastError` (a live effect's last failure). |
|
||||
| `plugin.run` | `{"id", "params"?: {…}, "ids"?: [...]}` (plug-in params may also be top-level keys) | Runs an object filter on the selection (or `ids`). One undo step; the result is selected, except the objects it locked or made guides. |
|
||||
| `plugin.install` | `{"path": "/x/y.wasm"}` (desktop) or `{"dataBase64": "…", "name"?}`, `"replace": bool = true`, `"allowHeavy": bool = false`, `"grant"?: [permission]`, `"hash"?: "sha256 hex"` | Validates and installs a module; returns its `plugin.list` entry. The desktop app and `vectorcraft-cli` keep it in the `Plug-ins` folder next to the preferences, so it is installed again after a restart (#2541). A [heavy filter](#heavy-filters) installs only with `allowHeavy: true`, once the user agreed. A plug-in whose manifest lists [permissions](#permissions) installs only when `grant` lists every one of them, once the user agreed. With `hash`, a module whose SHA-256 differs is refused. |
|
||||
| `plugin.inspect` | as `plugin.install`: `{"path"}` or `{"dataBase64", "name"?}` | Validates a module without installing it; returns the `plugin.list` entry it would have, plus `needsApproval` (true when `plugin.install` needs `grant`). |
|
||||
| `plugin.remove` | `{"id"}` | Uninstalls, and deletes it from the `Plug-ins` folder. |
|
||||
| `plugin.install` | `{"path": "/x/y.wasm"}` (desktop) or `{"dataBase64": "…", "name"?}`, `"replace"?: bool`, `"allowHeavy": bool = false`, `"grant"?: [permission]`, `"hash"?: "sha256 hex"` | Validates and installs a module; returns its `plugin.list` entry. The desktop app and `vectorcraft-cli` keep it in the `Plug-ins` folder next to the preferences, so it is installed again after a restart (#2541). A module with other bytes than the plug-in installed with its id, or, with none installed, one whose id has [settings and a cache](#settings-and-cache) in the `Plug-ins` folder, installs only with `replace: true`, once the user agreed; it takes that plug-in's place and gets its settings and cache. The same module installs again without `replace`, and `replace: false` refuses a module whose id is installed. A [heavy filter](#heavy-filters) installs only with `allowHeavy: true`, once the user agreed. A plug-in whose manifest lists [permissions](#permissions) installs only when `grant` lists every one of them, once the user agreed. With `hash`, a module whose SHA-256 differs is refused. |
|
||||
| `plugin.inspect` | as `plugin.install`: `{"path"}` or `{"dataBase64", "name"?}` | Validates a module without installing it; returns the `plugin.list` entry it would have, plus `needsApproval` (true when `plugin.install` needs `grant`) and `needsReplace` (true when `plugin.install` needs `replace: true`). |
|
||||
| `plugin.remove` | `{"id"}` | Uninstalls, and deletes it from the `Plug-ins` folder with its [settings and cache](#settings-and-cache). |
|
||||
| `plugin.clearCache` | `{"id"?}` | Deletes every entry in the [cache](#settings-and-cache) of plug-in `id`, or of every installed plug-in; settings stay. Returns `{"cleared": [id], "bytesFreed"}`. |
|
||||
| `plugin.reload` | `{"path"?: "folder"}` (default: the preference folder) | Installs every `*.wasm` in a folder; a bad module is reported and skipped, and so are a heavy filter and a plug-in whose permissions the user hasn't granted (nobody was asked). |
|
||||
|
||||
Live effects are applied like any effect: `effect.apply {"effect": "plugin.<id>", "params": {…}}`, edited with
|
||||
@@ -42,7 +43,9 @@ In the app, installed filters appear under **Object › Plug-ins**, next to **In
|
||||
Plug-ins**; live effects under **Effect › Plug-ins** and in the Appearance panel's effect menu. A plug-in with
|
||||
parameters gets a dialog generated from its schema (numbers, whole numbers, checkboxes, dropdowns, text, lists
|
||||
of numbers and colors, labelled, explained and sorted into sections as its manifest says) with a live preview; without
|
||||
parameters it runs at once. Parameters too many for the window's height scroll inside the dialog, which keeps its
|
||||
parameters it runs at once. Edit › Keyboard Shortcuts lists each installed filter under Object › Plug-ins, where
|
||||
it can be given a shortcut (`plugin:<id>`); the shortcut stays saved while the plug-in is removed and applies again
|
||||
when it is reinstalled. Parameters too many for the window's height scroll inside the dialog, which keeps its
|
||||
heading and buttons in view. Exporters are formats of **File › Export › Export As**, where Use
|
||||
Artboards is greyed out (the plug-in writes the whole document); one with parameters asks for them in a dialog of the
|
||||
same kind once the file is picked, and its Export button writes the file. **File › Open** of a `.wasm` file installs
|
||||
@@ -67,7 +70,7 @@ The host is [`wasmi`](https://github.com/wasmi-labs/wasmi), a pure-Rust WebAssem
|
||||
|
||||
| Limit | Default | On violation |
|
||||
|---|---|---|
|
||||
| Host imports | none at API level 1; at level 2 only the three [host imports](#host-imports-api-level-2): no WASI, file system, network, clock or randomness | module rejected at install, naming the import |
|
||||
| Host imports | none at API level 1; at level 2 only the [host imports](#host-imports-api-level-2): no WASI, file system, network, clock or randomness | module rejected at install, naming the import |
|
||||
| Module size | 32 MiB | rejected |
|
||||
| Linear memory | 512 MiB per instance (input and parameters: at most half) | `memory.grow` returns -1; oversized input or initial memory fails |
|
||||
| Output | 64 MiB of JSON | `Limit("output size")` |
|
||||
@@ -116,14 +119,17 @@ capability model proposed for PhotoCraft plug-ins
|
||||
| `effect.render` | effect | Change how the objects its effect is applied to are drawn. |
|
||||
| `export.write` | exporter | Write the document as a file in its own format. |
|
||||
| `progress` | all | Show its progress, see Cancel and write log lines through the [host imports](#host-imports-api-level-2). Needs `api` 2. |
|
||||
| `settings` | all | Keep settings of its own between runs and sessions ([settings and cache](#settings-and-cache)). Needs `api` 2. |
|
||||
| `cache` | all | Keep a cache of its own, which the user can clear ([settings and cache](#settings-and-cache)). Needs `api` 2. |
|
||||
|
||||
- A manifest without `permissions` gets the ones its kind implies, as plug-ins did before the key existed: a filter
|
||||
`doc.read`, `doc.write` and `state`; an effect `doc.read` and `effect.render`; an exporter `doc.read` and
|
||||
`export.write`. Such a plug-in installs without a prompt. This rule is VectorCraft's own. A filter whose list is
|
||||
empty may do none of these, and also installs without a prompt.
|
||||
- An effect or an exporter that lists permissions lists both of its implied ones. A filter may list any of its three.
|
||||
Any kind may add `progress`, which no kind implies. An unknown name, a name listed twice, a name that doesn't apply
|
||||
to the kind, more than 16 names, `progress` with an `api` below 2, or one of the names kept for a later plug-in API
|
||||
Any kind may add `progress`, `settings` and `cache`, which no kind implies. An unknown name, a name listed twice, a
|
||||
name that doesn't apply to the kind, more than 16 names, `progress`, `settings` or `cache` with an `api` below 2, or
|
||||
one of the names kept for a later plug-in API
|
||||
(`ui.panel`, `ui.tool`) is refused when the module is installed, and the error names it.
|
||||
- **Installing asks first.** Install Plug-in… and File › Open show the plug-in's name, id, version, the SHA-256 of
|
||||
the file and each permission in plain words, and install it once the user clicks OK, if the file still has the
|
||||
@@ -132,14 +138,22 @@ capability model proposed for PhotoCraft plug-ins
|
||||
`plugin.install` refuses the module, naming the permissions it needs, unless `grant` lists them all, which an agent
|
||||
passes once the user agreed (`plugin.inspect`'s `needsApproval` tells it beforehand), with `hash` set to the
|
||||
`plugin.inspect` entry's `hash` so that the module installed is the one the user saw.
|
||||
- **Replacing asks first.** When the file is another module than the plug-in installed with its id, or, with none
|
||||
installed, its id has settings and a cache in the `Plug-ins` folder, Install Plug-in… and File › Open show its id
|
||||
and SHA-256 and ask whether to install it in place of that plug-in, which gives it the settings and cache kept for
|
||||
the id. `plugin.install` refuses such a module, naming it, unless `replace` is `true`, which an agent passes once
|
||||
the user agreed (`plugin.inspect`'s `needsReplace` tells it beforehand). The Additional Plug-ins Folder and
|
||||
`plugin.reload` do not ask.
|
||||
- The grant is recorded with the plug-in's id, the module's hash and the permissions, in `grants.json` in the
|
||||
`Plug-ins` folder. Installing a module with the same id that lists no new permission needs no new approval; one that
|
||||
lists more asks again. `plugin.remove` forgets the grant. An entry of `grants.json` that this version can't use (a
|
||||
`Plug-ins` folder. Without a `Plug-ins` folder, installing a module with the same id that lists no new permission
|
||||
needs no new approval; one that lists more asks again. A grant kept in a `Plug-ins` folder covers only the module
|
||||
with the recorded hash: another module under the id needs `grant` again, even when it lists the same permissions,
|
||||
and does not get the id's settings and cache until then. `plugin.remove` forgets the grant. An entry of `grants.json` that this version can't use (a
|
||||
permission it doesn't know, an invalid id) is skipped and stays in the file until its plug-in is granted again or
|
||||
removed. A `grants.json` that is not a JSON list is never overwritten, and the file is never written larger than
|
||||
1 MiB, the most that is read. When a `Plug-ins` folder is in use, only the grants kept
|
||||
in it count for `plugin.install`, `plugin.inspect`, `plugin.reload` and the Additional Plug-ins Folder. At startup,
|
||||
a stored plug-in whose permissions are not granted is skipped. The Additional Plug-ins Folder and `plugin.reload`
|
||||
a stored plug-in whose permissions are not granted to that module is skipped. The Additional Plug-ins Folder and `plugin.reload`
|
||||
install only plug-ins whose permissions were granted, and report the others.
|
||||
- The host enforces the grant on a filter run: without `doc.read` the filter is given no objects; without `state` its
|
||||
`documentData` is `null` and an output that sets it is refused; without `doc.write` an output that changes the
|
||||
@@ -148,7 +162,8 @@ capability model proposed for PhotoCraft plug-ins
|
||||
imports](#host-imports-api-level-2). A higher one is refused. `plugin.list` and `plugin.info` give it as `api`.
|
||||
- Parameter declarations are unchanged by permissions (`params`, below).
|
||||
|
||||
Every run gets a **fresh instance**, so no state survives between calls. Traps, exhausted budgets, malformed
|
||||
Every run gets a **fresh instance**, so no state survives between calls except what a plug-in writes to its
|
||||
[settings and cache](#settings-and-cache). Traps, exhausted budgets, malformed
|
||||
modules, bad manifests, out-of-range pointers, negative return codes and invalid output all become errors, and the
|
||||
document is left untouched: a filter's output is checked completely before one edit applies it. A live effect that
|
||||
fails draws the object's geometry unchanged; `plugin.info` reports why (`lastError`).
|
||||
@@ -182,9 +197,10 @@ module's memory.
|
||||
|
||||
### Host imports (API level 2)
|
||||
|
||||
A plug-in whose manifest gives `"api": 2` and lists the `progress` [permission](#permissions) may import these
|
||||
A plug-in whose manifest gives `"api": 2` and lists the [permission](#permissions) an import needs may import these
|
||||
functions from module `env` (the module a Rust or C toolchain gives `extern` functions by default). `vc_abi_version`
|
||||
still returns `1`.
|
||||
still returns `1`. `vc_progress`, `vc_cancelled` and `vc_log` need `progress`; the `vc_settings_*` imports need
|
||||
`settings` and the `vc_cache_*` imports need `cache` ([settings and cache](#settings-and-cache)).
|
||||
|
||||
| Import | Signature | Meaning |
|
||||
|---|---|---|
|
||||
@@ -193,8 +209,8 @@ still returns `1`.
|
||||
| `vc_log` | `(level, ptr, len) -> i32` | Writes the UTF-8 text at `ptr` as a log line of `level` (0 error, 1 warning, 2 information, 3 debug). Returns `0` when written, `1` when the run's log budget is spent and the line was dropped, `-1` when the text doesn't lie inside the module's memory, `-2` when it is not UTF-8, `-3` for another level. |
|
||||
|
||||
- The host checks the imports when the module is installed: an import it doesn't offer, one with another signature,
|
||||
and one the manifest doesn't allow (an `api` below 2, or no `progress` permission) refuse the module, and the error
|
||||
names the import.
|
||||
and one the manifest doesn't allow (an `api` below 2, or without the import's permission) refuse the module, and the
|
||||
error names the import and the permission.
|
||||
- A filter's or an exporter's progress is shown as a share: a heavy filter's progress window and the export's progress
|
||||
window draw a bar with a percentage, and Cancel there makes `vc_cancelled` return `1`. A plug-in that checks it can
|
||||
stop early, and the host discards what it returns after the Cancel or after its time budget ran out; one that
|
||||
@@ -208,6 +224,53 @@ still returns `1`.
|
||||
text, and the host reads at most 1 MiB of log text in a run; past any of these, one "log truncated" line is written
|
||||
and the rest are dropped.
|
||||
|
||||
### Settings and cache
|
||||
|
||||
A plug-in with the `settings` permission keeps named values between runs and sessions, and one with `cache` keeps
|
||||
named entries that the user can clear (#2191). It names each value by a key and never by a path. Each import takes
|
||||
the key as `(key, key_len)`, the UTF-8 bytes at `key` in its memory:
|
||||
|
||||
| Import | Signature | Meaning |
|
||||
|---|---|---|
|
||||
| `vc_settings_get` | `(key, key_len, out, out_cap) -> i32` | The setting's length in bytes. When it fits in the `out_cap` bytes at `out`, its bytes are copied there; otherwise nothing is copied. |
|
||||
| `vc_settings_set` | `(key, key_len, value, value_len) -> i32` | Sets the setting to the `value_len` bytes at `value`. Returns `0`. |
|
||||
| `vc_settings_delete` | `(key, key_len) -> i32` | Removes the setting. Returns `0`. |
|
||||
| `vc_cache_read` | `(key, key_len, out, out_cap) -> i32` | As `vc_settings_get`, for the cache entry. |
|
||||
| `vc_cache_write` | `(key, key_len, value, value_len) -> i32` | As `vc_settings_set`, for the cache entry. |
|
||||
| `vc_cache_clear` | `(key, key_len) -> i32` | Removes the cache entry; with `key_len` 0, every entry. Returns `0`. |
|
||||
|
||||
A call that fails returns `-1` when the key has no value, `-2` when a key, value or buffer doesn't lie inside the
|
||||
module's memory, `-3` when the key is not a valid key, `-4` when the write would pass a cap (nothing changes), `-5`
|
||||
when there is nowhere to keep anything, `-6` when reading or writing the file failed, and `-7` when the run has used
|
||||
its 10,000 storage calls or its 1 GiB of storage reads and writes. Each call counts the bytes it reads and writes: a
|
||||
settings call the whole settings file it reads, and a set or delete also the whole file it writes; a cache call the
|
||||
entry it reads or writes. A read counts them even when the value doesn't fit and nothing is copied. A call that would
|
||||
pass the 1 GiB returns `-7` before it reads or writes anything.
|
||||
|
||||
- A key is 1 to 64 characters from `A-Z`, `a-z`, `0-9`, `_` and `-`, and is not a Windows device name (`CON`, `PRN`,
|
||||
`AUX`, `NUL`, `COM0` to `COM9`, `LPT0` to `LPT9`, in any case). Keys differ in case: `tile` and `Tile` are two.
|
||||
- These caps are VectorCraft's own values: at most 256 settings of at most 64 KiB each, in a settings file of at most
|
||||
1 MiB; cache entries of at most 64 MiB each, at most 4,096 entries and 512 MiB per plug-in. The cache has no
|
||||
automatic eviction: a write past a cap fails with `-4`, and the plug-in or the user clears entries. A cache write
|
||||
also fails with `-4` when the `cache` folder holds more than 8,192 items; clearing the cache removes every file in
|
||||
it.
|
||||
- The desktop app and `vectorcraft-cli` keep them in a folder named from the id under `storage/` in the `Plug-ins`
|
||||
folder (ids that differ only in case get two folders): `settings.json` and a
|
||||
`cache` folder with one file per entry, named by the host. A settings file that is too large or doesn't parse is
|
||||
moved to `settings.unreadable.json`, replacing an earlier one there, and the settings start empty. A link in that
|
||||
folder is refused (`-5`). Writes go to a temporary file that then replaces the old one; a temporary file a failed
|
||||
write leaves in the `cache` folder does not count toward the caps, and clearing the cache removes it.
|
||||
- A plug-in reaches only the storage of its own id. Replacing it with another module of the same id
|
||||
(`plugin.install` with `replace: true`, after the user agreed) keeps the storage; `plugin.remove` deletes it, and a run of the plug-in still going gets `-5` from every storage call after that.
|
||||
`plugin.remove` first renames the folder (adding `.removed` to its name). When that fails, `plugin.remove` fails
|
||||
and the plug-in stays installed with its storage as it was. Files that can't be deleted after the rename stay in the
|
||||
`.removed` folder, where no plug-in reaches them, and the next removal of a plug-in with that id deletes them.
|
||||
`plugin.remove` with the id of a plug-in that isn't installed deletes the storage kept for that id, when there is
|
||||
any.
|
||||
`plugin.clearCache` empties the cache and leaves the settings, and `plugin.list` and
|
||||
`plugin.info` give the cache's size as `cacheBytes`.
|
||||
- Without a `Plug-ins` folder (the web build, and embedders that attach none) the storage calls return `-5`.
|
||||
|
||||
### Manifest
|
||||
|
||||
```json
|
||||
@@ -282,8 +345,8 @@ object: its geometry (`type`, `path`, `fillRule`, `bounds`) and its `fills` and
|
||||
from before these give geometry only). The paints are read only: an effect may draw as wide as a stroke or use a
|
||||
fill's colour to decide its shape, but it changes only the geometry.
|
||||
|
||||
An **exporter** gets something else: the document as a native `.vectorcraft` file's JSON, as `document.save` writes it
|
||||
but without indentation (the format is documented in [`crates/format/src/lib.rs`](../crates/format/src/lib.rs)). That is every layer, object,
|
||||
An **exporter** gets something else: the native `.vectorcraft` document JSON without indentation, optional preview/PDF
|
||||
renditions or save-preference metadata (the format is documented in [`crates/format/src/lib.rs`](../crates/format/src/lib.rs)). That is every layer, object,
|
||||
appearance and effect record, artboard, swatch and symbol, so an exporter reads whatever the document holds; it checks
|
||||
`version`, since a later host may write a newer one. Images of 8 KiB or more are listed in `images` with their MIME
|
||||
type and `blob` but without their data, which follows the JSON in a saved file; smaller ones keep their base64 `data`.
|
||||
|
||||
+1
-1
@@ -164,7 +164,7 @@ to the target triple, so host build scripts aren't affected.
|
||||
AppStream metainfo, the MIME type for VectorCraft documents, the icons and the licence files.
|
||||
|
||||
**Document types.** The desktop entry's `MimeType` lists every format File › Open reads but PSD,
|
||||
PSB, `.ps` PostScript, Targa, PCX, Pixar and JPEG 2000, so file managers list VectorCraft under Open With for them.
|
||||
PSB, `.ps` PostScript, Targa, PCX, Pixar, JPEG 2000 and HEIC/HEIF, so file managers list VectorCraft under Open With for them.
|
||||
`ai.storyteller.vectorcraft.mime.xml` declares the types that shared-mime-info lacks: VectorCraft
|
||||
documents and templates, `.ait` templates and Affinity files (`application/x-affinity`). An `.af`
|
||||
file gets the Affinity type by its content, and `.afdesign` and `.afpub` files by their extension.
|
||||
|
||||
+8
-8
@@ -1,6 +1,6 @@
|
||||
# Roadmap: milestones and what's next
|
||||
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-07 · **Change:** minor (Indian-language hyphenation review and license allowlist, #4947; Hindi catalog and contributor loanword preferences; full wording review in progress; Effect dialogs: a colour swatch beside a hex colour opens the Color Picker, #5365; shape tools move the selection from its centre point and turn it from the zone outside a box corner, #5477; scores and estimates unchanged) · **Target:** Adobe Illustrator 2026 (30.x)
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-08 · **Change:** minor (Character Styles panel: a double-click on a style's row opens its Character Style Options; the dialog keeps a fixed width and scrolls its sections, so its buttons stay on screen) · **Target:** Adobe Illustrator 2026 (30.x)
|
||||
|
||||
## Feature submission evidence
|
||||
|
||||
@@ -36,11 +36,14 @@ M7 type: Touch Type moves a right-to-left character along its line and up from i
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-11-08 | minor | Character Styles panel: a double-click on a user style's row opens its Character Style Options (`ui.charStyleOptions`); the dialog keeps a fixed width and scrolls its sections in a shorter window, so OK and Cancel stay on screen. Tests `panels::text_styles::tests::double_clicking_a_character_style_row_opens_its_options` and `dialogs::char_style_options::tests::the_sections_scroll_in_a_window_shorter_than_the_general_list`. Scores and estimates unchanged. |
|
||||
| 2026-11-02 | minor | Selection QoL: saved marquee modes, screen drag direction with a 3 px dead zone, and translated mode/E feedback (#5313); VectorCraft addition, scores and estimates unchanged. |
|
||||
| 2026-11-07 | minor | Indian-language hyphenation (#4947): eleven MIT-licensed pattern sets, with grapheme and shaping-cluster protection in both composers and existing paragraph limits. Assamese and Sanskrit are selectable; Sanskrit automatic patterns remain pending an allowlisted source. Scores and estimates unchanged. |
|
||||
| 2026-11-05 | minor | Effect dialogs: a colour swatch beside a hex colour field follows typed values, and a double-click opens the Color Picker over the dialog, whose OK fills the field (#5365); scores and estimates unchanged. |
|
||||
| 2026-11-05 | minor | Selection Tools add-on: Select Linked, Embedded, Missing and Modified select the images and placed documents with that link status (Object › Plug-ins › Selection Tools and the Links panel menu; Shift adds), and Select by Link Status… lists them by name, status and format to pick from, optionally zooming to them; what is hidden, locked, on a template layer or outside the isolated group is left out and the status bar says how many (#5526, a VectorCraft addition); scores and estimates unchanged (estimated). |
|
||||
| 2026-11-05 | minor | Pencil and Paintbrush: a new stroke with Keep selected off leaves nothing selected, the earlier selection included, while Keep selected on selects only the new path (#5752); scores and estimates unchanged. |
|
||||
| 2026-11-05 | minor | Layers panel: a layer whose Layer Options › Print is off shows its name italic, as the reference application shows non-printing layers, and keeps it while the row is dragged (#5739); scores and estimates unchanged. |
|
||||
| 2026-11-04 | minor | M7: Select Text by Font takes a scope: the document, chosen artboards or chosen layers; Find Font's Find In offers Document, Artboard (the active one) and Layers (the selected ones, else the current one) (#5529, a VectorCraft addition); estimates unchanged. |
|
||||
| 2026-11-04 | minor | M7: Find Font's Replace With Font lists family and style rows with a search, and the list and the document's font list scroll on their own (#4972); scores and estimates unchanged. |
|
||||
| 2026-11-04 | minor | Selection Tools add-on: Select by Artboards selects the objects overlapping, fully inside or fully outside several chosen artboards, from a dialog that lists, searches and multi-selects the artboards and fits one in the window on double-click (#5525, #5548, #5549, a VectorCraft addition); scores and estimates unchanged. |
|
||||
| 2026-11-04 | minor | M4: raster/PSD exports default to document resolution; CLI run/convert expose --ppi, matching the engine and MCP precedence. Scores and hours unchanged. |
|
||||
@@ -119,11 +122,11 @@ native wording review, layout checks and a web Devanagari font remain. [Notes](l
|
||||
|---|---|---|---|
|
||||
| M0 | Skeleton + vertical slice | ✅ done | — |
|
||||
| M1 | Selection, transform, layers, MCP (common command tools, strict keys, session resources and version-aware result hints) | ✅ mostly done (document-tab artwork drag with lossless resource transfer and one target Undo; malformed MCP app replies discard the connection without replay, #1761; bounded control socket waits and connection-slot recovery, #1726; bounded synthetic control input, #1709; no-op anchor Align keeps Undo, Redo and saved state (#1180 follow-up); transform reference point snaps to anchors/centres; rotated objects keep a rotated bounding box and their angle; Free Transform, Scale and Reflect along a rotated box pending; the Transform fields take one Tab each, the W/H link after them) | 4–6 |
|
||||
| M2 | Drawing tools + smart guides | ✅ mostly done (Polygon/Star exact-size count persistence, with repeated-drag, tool-switch and Cancel regression coverage; Curvature point markers without direction handles (#1236, in part); Direct Selection segment click/Delete preserves neighboring edges, #1278; Flare, Reshape, Live Corners widget dragging and per-corner radii and kinds landed, on any path's corners; Shaper rough-shape recognition and orientation steps, the remaining Pen modifier nuances; Shaper Groups with editable sources and separate fill/stroke edits landed; custom ruler origin with drag preview, active-artboard reset, relative X/Y fields and native round-trip (#1212); construction widget/refinements pending); a shape just drawn moves by its centre point and turns from the zone outside a corner with its tool still active (#5477); Tangent and straight-segment perpendicular snapping use saved Smart Guides Geometric Guides preferences and Control bar quick access (#2537); no View submenu | 12–18 |
|
||||
| M2 | Drawing tools + smart guides | ✅ mostly done (Polygon/Star exact-size count persistence, with repeated-drag, tool-switch and Cancel regression coverage; Curvature point markers without direction handles (#1236, in part); Direct Selection segment click/Delete preserves neighboring edges, #1278; Flare, Reshape, Live Corners widget dragging and per-corner radii and kinds landed, on any path's corners; Shaper rough-shape recognition and orientation steps, the remaining Pen modifier nuances; Shaper Groups with editable sources and separate fill/stroke edits landed; custom ruler origin with drag preview, active-artboard reset, relative X/Y fields and native round-trip (#1212); construction widget/refinements pending); a shape just drawn moves by its centre point and turns from the zone outside a corner with its tool still active (#5477); Tangent and straight-segment perpendicular snapping use saved Smart Guides Geometric Guides preferences and Control bar quick access (#2537); no View submenu; Copy and Cut with the Pen or Curvature tool take the anchors a Cmd/Ctrl-lent Direct Selection picked (#6123) | 12–18 |
|
||||
| M2 | Drawing tools + smart guides | ✅ mostly done (Polygon/Star exact-size count persistence, with repeated-drag, tool-switch and Cancel regression coverage; Curvature point markers without direction handles (#1236, in part); Direct Selection segment click/Delete preserves neighboring edges, #1278; Flare, Reshape, Live Corners widget dragging and per-corner radii and kinds landed, on any path's corners; Shaper rough-shape recognition and orientation steps, the remaining Pen modifier nuances; Shaper Groups with editable sources and separate fill/stroke edits landed; custom ruler origin with drag preview, active-artboard reset, relative X/Y fields and native round-trip (#1212); construction widget/refinements pending); Tangent and straight-segment perpendicular snapping use saved Smart Guides Geometric Guides preferences and Control bar quick access (#2537); no View submenu | 12–18 |
|
||||
| M3 | Paint & appearance (swatches, color, gradient, stroke, appearance, transparency, styles) | ✅ done (M3.7–M3.98): swatches, groups, libraries, tints, Lab spots and Registration; Eyedropper styles highlighted text only (atomic transparency rejection); Eyedropper reads visible locked and outside-isolation sources (#1251); Color Picker, Color panel, Color Guide, Color Themes, Edit Colors and Recolor Artwork (screen-bounded Edit chip list, #3416); gradients that follow every transform, the annotator, linked stops, freeform gradients, focal points, gradients on strokes and Expand; visible strokes when paint is added to inherited None/zero-width art (#1253); stroke geometry, arrowheads, dashes fitted to corners, stroke on type, width profiles and the Width tool (Shift-double-click enables adjoining adjustment in Width Point Edit; finite-arithmetic follow-up regressions and full CI passed ([Validation evidence](target-app-parity.md#evidence-what-ships-today-by-area))), Scale Strokes and preview bounds; Appearance targeting, container appearance, target circles, Expand Appearance; knockout, isolation, blend accuracy, CMYK blending, overprint, Attributes, masks and clipping, Flatten Transparency; graphic styles, links and libraries; CSS library export preserves fractional linear and radial gradient stop positions. Left: freeform gradients in SVG/PDF, mixed spot/process gradients in SVG and PDF gradients mixing a spot color with RGB or Lab stops export as stops or process colors; PDF export writes dithered gradient fills with spot stops, and Perceptual spot gradients with RGB or Lab stops other than white or more than 4,096 stops on their curve, as images in process colors; confirm the Scale Strokes & Effects default; Recolor model selection is available through the engine and MCP only (#2520); the dialog retains its existing controls | 4–8 |
|
||||
| M2 | Drawing tools + smart guides | ✅ mostly done (Curvature point markers without direction handles (#1236, in part); Direct Selection segment click/Delete preserves neighboring edges, #1278; Flare, Reshape, Live Corners widget dragging and per-corner radii and kinds landed, on any path's corners; Shaper rough-shape recognition and orientation steps, the remaining Pen modifier nuances; Shaper Groups with editable sources and separate fill/stroke edits landed; custom ruler origin with drag preview, active-artboard reset, relative X/Y fields and native round-trip (#1212); construction widget/refinements pending) | 12–18 |
|
||||
| M4 | Files (native, SVG, PDF, raster, Export for Screens, clipboard interop) | ✅ done (M4.14–M4.98 on 2026-10-05): Save As/Save a Copy/Revert/templates, Data Recovery and background save, SVG import and export fidelity (units, text, symbols, filters, SVGZ, Preserve Editing, SVG Options), shared guarded PDF writer and windowed reader ([pdf-backend.md](pdf-backend.md)), PDF import (colours, layers, masks, editable text, security) and export (presets, marks, bleed, ICC and output intent, raster effects, subset fonts, PDF/X-1a, X-3 and X-4, PDF layers, overprint, page thumbnails, fast web view, PDF 1.3), Place and Links, Package, EPS and DXF in and out (EPS legacy mesh corners, vector opacity masks and raster page comparison verified; closed SPLINE flags round-trip and circular paths export as native CIRCLE/ARC, #1299), EMF/WMF, TIFF/BMP/Targa/PSD/GIF/PNG-8 export, Print and print presets, slices, Save for Web, TIFF in Export for Screens and Asset Export, clipboard flavours, File Info; AF.1–AF.4 add Affinity import (native layers, artboards, vectors, text and images from Affinity 1–3 files; the embedded preview only as a warned fallback; AF.4 expands current `.af` fixtures and every-board round-trip validation); EPS Save and Save As keep an opened EPS as EPS with its page frame and complete editable VectorCraft document (2026-10-26; G9 import fidelity unchanged). Left: DWG (use DXF), PSD placement as layers, overprint read back from PDF, Affinity export, polish | 3–6 (existing scope; Affinity export unestimated) |
|
||||
| M4 | Files (native, SVG, PDF, raster, Export for Screens, clipboard interop) | ✅ done (M4.14–M4.98 on 2026-10-05): Save As/Save a Copy/Revert/templates, Data Recovery and background save, SVG import and export fidelity (units, text, symbols, filters, SVGZ, Preserve Editing, SVG Options), shared guarded PDF writer and windowed reader ([pdf-backend.md](pdf-backend.md)), PDF import (colours, layers, masks, editable text, security) and export (presets, marks, bleed, ICC and output intent, raster effects, subset fonts, PDF/X-1a, X-3 and X-4, PDF layers, overprint, page thumbnails, fast web view, PDF 1.3), Place and Links, Package, EPS and DXF in and out (EPS legacy mesh corners, vector opacity masks and raster page comparison verified; closed SPLINE flags round-trip and circular paths export as native CIRCLE/ARC, #1299), EMF/WMF, TIFF/BMP/Targa/PSD/GIF/PNG-8 export, Print and print presets, slices, Save for Web, TIFF in Export for Screens and Asset Export, clipboard flavours, File Info; AF.1–AF.4 add Affinity import (native layers, artboards, vectors, text and images from Affinity 1–3 files; the embedded preview only as a warned fallback; AF.4 expands current `.af` fixtures and every-board round-trip validation); EPS Save and Save As keep an opened EPS as EPS with its page frame and complete editable VectorCraft document (2026-10-26; G9 import fidelity unchanged). Left: DWG (use DXF), PSD placement as layers, overprint read back from PDF, Affinity export, polish; SVG CSS classes survive export and repeated import in all four styling modes (#2480); current-main integration retains event attributes and scripts; SVG CSS classes survive export and repeated import in all four styling modes (#2480); current-main integration retains event attributes and scripts | 3–6 (existing scope; Affinity export unestimated) |
|
||||
| M3 | Paint & appearance (swatches, color, gradient, stroke, appearance, transparency, styles) | ✅ done (M3.7–M3.98): swatches, groups, libraries, tints, Lab spots and Registration; Eyedropper styles highlighted text only (atomic transparency rejection); Eyedropper reads visible locked and outside-isolation sources (#1251); Color Picker, Color panel, Color Guide, Color Themes, Edit Colors and Recolor Artwork (screen-bounded Edit chip list, #3416); gradients that follow every transform, the annotator, linked stops, freeform gradients, focal points, gradients on strokes and Expand; visible strokes when paint is added to inherited None/zero-width art (#1253); stroke geometry, arrowheads, dashes fitted to corners, stroke on type, width profiles and the Width tool (Shift-double-click enables adjoining adjustment in Width Point Edit), Scale Strokes and preview bounds; Appearance targeting, container appearance, target circles, Expand Appearance; knockout, isolation, blend accuracy, CMYK blending, overprint, Attributes, masks and clipping, Flatten Transparency; graphic styles, links and libraries; CSS library export preserves fractional linear and radial gradient stop positions. Left: freeform gradients in SVG/PDF, mixed spot/process gradients in SVG and PDF gradients mixing a spot color with RGB or Lab stops export as stops or process colors; PDF export writes dithered gradient fills with spot stops, and Perceptual spot gradients with RGB or Lab stops other than white or more than 4,096 stops on their curve, as images in process colors; confirm the Scale Strokes & Effects default | 4–8 |
|
||||
| M5 | Performance | 🟡 background render + caches + MT done; `vectorcraft-cli bench` and `vectorcraft-cli perf` (budget suite); opaque solid-fill knockout paths draw once in hard-edge/supersampled raster export, with analytical-AA compositing unchanged; file format v2 opens 3× faster (50k paths: 722 → 244 ms); raster effects (glows, shadows, blur, feather) no longer force the whole frame single-threaded (filtered offscreen per effect, verified equal to the single-threaded reference); Craquelure/Mosaic Tiles/Stained Glass distance searches optimized with pixel-invariance checks and the `texture_drag_perf` probe (#1257); effect-heavy demos need a clean-machine benchmark; dirty-region rendering, GPU backend spike pending | 15–25 |
|
||||
| M6 | Path operations (Pathfinder, Shape Builder, offset…) | ✅ mostly done (live compound shapes: Make, Alt-click a Shape Mode, member modes, Release, Expand (#4522); single-result Pathfinder names and SVG IDs retained (#1293); Divide open-cutting-path geometry, appearance and history verified (#1307; existing segment cap remains); Simplify preview/counts and rewritten-path component selection verified (#1272; the slider opens at the Auto-Simplify level; a Direct Selection part of a path simplifies on its own); Compound appearance and member fill-rule edits verified (#1197); Boolean precision on almost-horizontal edges fixed and the property tests made deterministic; Shape Builder gap detection, large-offset bug open); Shape Builder Gap Detection shares Live Paint’s spatial gap finder and temporary merge bridges (#2526); Custom is capped at 72 pt in the existing options dialog | 3–6 |
|
||||
@@ -180,6 +183,7 @@ separate. Scores and hours unchanged. [Behavior and command details](development
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-11-07 | minor | M2: with the Pen or Curvature tool, Edit › Copy and Cut take the anchors and segments a Cmd/Ctrl-lent Direct Selection picked, not the whole path (#6123); estimates unchanged |
|
||||
| 2026-11-06 | minor | M2: a shape just drawn moves by its centre point (Show Center) and turns from the rotate zone just outside a bounding-box corner with its tool still active, as the Selection tool's gestures do (#5477); estimates unchanged. |
|
||||
| 2026-11-06 | minor | Hindi (`hi`): 7,877-row machine-assisted catalog, zero/one singular plurals, desktop font fallback and optional Devanagari craft-fonts fallback; all 55 translation tests pass; native review and a web font remain; scores and estimates unchanged |
|
||||
| 2026-11-04 | minor | New Document: the units chosen in Preset Details belong to the chosen preset; Recent and Saved cards keep their own units; scores and estimates unchanged. |
|
||||
@@ -191,8 +195,6 @@ separate. Scores and hours unchanged. [Behavior and command details](development
|
||||
| 2026-11-03 | minor | M7: Touch Type moves right-to-left characters along their line while keeping text editable; first-logical-character restriction retained. Estimates unchanged. |
|
||||
| 2026-10-30 | patch | M5: opaque solid-fill knockout paths avoid redundant erase/add layers in hard-edge frames and supersampled raster export; exact-pixel regression coverage retains analytical-AA rounding and translucent knockout behavior; scores and estimates unchanged |
|
||||
| 2026-11-03 | minor | M7: retain composition trimming in rotated character placement and rotation metadata; estimates unchanged. |
|
||||
| 2026-10-30 | minor | M4: G9: `.ai`/EPS editing data: a blend takes the transparency (opacity, blend mode, knockout) in its state block after its record, so its steps knock each other out as the page draws them; a user's file comes in 0.6% from its page instead of 1.3%. Scores and estimates unchanged. |
|
||||
| 2026-10-30 | minor | M4: File formats: `.ai`/EPS editing-data fidelity from an audit of a user's files: All Caps and Small Caps (#4708); placed files at their box's corner, kept where they draw closer to the page (#4664, #4723, #4742); pages cropped to the art, with `UserUnit` (#4658, #4727); gradient mesh corners with handle weights of 0 and the state written after a mesh (#4738, #4744, #4748); type on a path spaced as the file lays it out (#4743); synthetic regressions in `crates/eps`; scores and estimates unchanged. |
|
||||
| 2026-10-29 | minor | M6: Pathfinder: live compound shapes (#4522): the panel menu's Make, Release and Expand Compound Shape, Alt-clicking a Shape Mode, a selected member's Shape Mode and the Expand button act; scores unchanged |
|
||||
| 2026-10-26 | minor | M4/G9: EPS Save and Save As: an opened EPS saves back to its own path as EPS, keeping the chosen artboard's page frame and transparent margins and the complete editable VectorCraft document; Save's TIFF preview is capped at 1024 px (Export keeps 2048); partly read, preview-only or damaged-editing-data sources still need confirmation before they are overwritten; it does not write Illustrator's own editing data (#868), and G9's real-file import fidelity is unchanged; scores and estimates unchanged |
|
||||
| 2026-10-25 | minor | M10/G1: a selected Grid Repeat shows handles: the one below the grid adds or removes rows, the one right of it columns, the one past its bottom-right corner both, and the sliders between the first two columns and rows set the horizontal and vertical spacing; each drag is one undo step and Escape cancels it (#2691); estimates unchanged |
|
||||
@@ -211,9 +213,6 @@ separate. Scores and hours unchanged. [Behavior and command details](development
|
||||
| 2026-10-22 | minor | G2: the Effect Gallery shipped (#2883): Effect › Effect Gallery… browses the Artistic, Brush Strokes, Distort, Sketch, Stylize and Texture filters, edits each filter's settings, builds an ordered stack (add, reorder, hide, remove) with a live canvas preview, and OK applies it as separate appearance effects in one undo step; remaining: filter thumbnails and a preview area inside the dialog; G2 estimate 4–6 → 1–2 h; Raster effects 82% → 85% (power-user view 49% → 52%), estimated, a modest move because the named missing dialog landed without thumbnails or an in-dialog preview. |
|
||||
| 2026-10-22 | minor | G2: Effect › Sketch › Conté Crayon (Foreground Level, Background Level, Texture, Scaling, Relief, Light Direction, Invert; a black crayon in the dark areas and a white one in the light areas on textured mid-grey paper; ranges and defaults unverified VectorCraft choices); measured Photoshop-style filters 57/57, the Effect Gallery remains (4–6 h). |
|
||||
| 2026-10-22 | minor | Recolor Artwork Edit chips scroll within the available screen height (#3416); small palettes retain their tab height; scores and estimates unchanged. |
|
||||
| 2026-10-22 | minor | Artboard Options honors Scale Artwork with Artboard for preset, orientation and typed-size changes; both Fits keep artwork stationary; scores and estimates unchanged. |
|
||||
| 2026-10-22 | minor | G2: the Effect Gallery shipped (#2883): Effect › Effect Gallery… browses the Artistic, Brush Strokes, Distort, Sketch, Stylize and Texture filters, edits each filter's settings, builds an ordered stack (add, reorder, hide, remove) with a live canvas preview, and OK applies it as separate appearance effects in one undo step; remaining: filter thumbnails and a preview area inside the dialog; G2 estimate 4–6 → 1–2 h; Raster effects 82% → 85% (power-user view 49% → 52%), estimated, a modest move because the named missing dialog landed without thumbnails or an in-dialog preview. |
|
||||
| 2026-10-22 | minor | G2: Effect › Sketch › Conté Crayon (Foreground Level, Background Level, Texture, Scaling, Relief, Light Direction, Invert; a black crayon in the dark areas and a white one in the light areas on textured mid-grey paper; ranges and defaults unverified VectorCraft choices); measured Photoshop-style filters 57/57, the Effect Gallery remains (4–6 h). |
|
||||
| 2026-10-22 | minor | Font pickers list recently applied families first (#3515), using the existing recent-font limit; search, filters, previews and keyboard selection share the same rows. Scores and estimates unchanged. |
|
||||
| 2026-10-21 | minor | Blend panel Type and Ramp control step easing with a separate color Shift (#2539); Blend Options retains spacing and orientation; polynomial curves are original approximation. Scores and estimates unchanged. |
|
||||
| 2026-10-21 | minor | M14: workspaces keep the layout changes made in them across switches and restarts until Reset <name> (UI.7); estimates unchanged |
|
||||
@@ -224,6 +223,7 @@ separate. Scores and hours unchanged. [Behavior and command details](development
|
||||
| 2026-10-21 | minor | Shape Builder Gap Detection shares Live Paint’s spatial gap finder and temporary merge bridges (#2526); Custom is capped at 72 pt in the existing options dialog. Scores and estimates unchanged. |
|
||||
| 2026-10-21 | minor | Recolor model selection is available through the engine and MCP only (#2520); the dialog retains its existing controls. Scores and estimates unchanged. |
|
||||
| 2026-10-21 | minor | Tangent and straight-segment perpendicular snapping use saved Smart Guides Geometric Guides preferences and Control bar quick access (#2537); no View submenu; Recolor model selection is available through the engine and MCP only (#2520); the dialog retains its existing controls. Scores and estimates unchanged. |
|
||||
| 2026-10-21 | minor | SVG CSS classes survive export and repeated import in all four styling modes (#2480); current-main integration retains event attributes and scripts. Scores and estimates unchanged. |
|
||||
| 2026-10-21 | minor | 3D: original Standard, Diffuse, Top Left and Right lighting presets; command access, effective-setting recognition and preview/history; scores and estimates unchanged |
|
||||
| 2026-10-20 | minor | Polygon and Star exact-size placement remembers the chosen count for later drags and dialog openings; Cancel preserves the previous count; existing opening gestures retained; scores and hours unchanged. |
|
||||
| 2026-10-20 | minor | M12: consolidated three duplicate milestone rows into one, retaining distinct Image Trace and Graphs details and the quick-preset wording correction; status, scores and 6–10 h estimate unchanged. |
|
||||
|
||||
+82
-32
File diff suppressed because one or more lines are too long
+12
-1
@@ -17,6 +17,14 @@ Preview changes are temporary until OK; Cancel restores the document; OK is one
|
||||
3D effect: edit its options in the Appearance panel or the 3D and Materials panel, or remove it before applying
|
||||
another.
|
||||
|
||||
Each solid follows its shape as it is filled. Separate and nested contours are built as drawn. Contours that cross,
|
||||
touch or run along each other or themselves, as type often draws a glyph, are first merged into one outline by
|
||||
[`vectorcraft-pathops`](../crates/pathops/README.md), keeping every contour but the numerical debris a boolean leaves.
|
||||
Whether contours meet is judged on the outline as it is followed (see the curve tolerance below), so curves that
|
||||
overlap by less than that are built as drawn. All three effects share pathops'
|
||||
[limits](../crates/pathops/README.md#limits): a shape it refuses is built from its contours as drawn, where it can be.
|
||||
An open subpath is closed by a straight line either way.
|
||||
|
||||
## 3D and Materials panel
|
||||
|
||||
**Window › 3D and Materials** opens a panel that edits the 3D effect of the selection without a dialog, as the
|
||||
@@ -228,7 +236,9 @@ out, perspective). No Adobe software, assets, presets or bevel shapes were used.
|
||||
effect per object.
|
||||
- Curves are followed within 1/2000 of the shape's size (at least 0.05 pt), so a small curve takes a few points
|
||||
and a large one up to 32. Extrude & Bevel and Inflate take up to 2,048 outline points (a stroke's outline is
|
||||
counted on its own), Rotate (which only turns the outline) 65,536.
|
||||
counted on its own), Rotate (which only turns the outline) 65,536. The limit is counted on the shape as drawn and,
|
||||
when its contours meet, again on the merged outline, which can have more points (bars crossing in a grid trace
|
||||
every hole between them); past it, the shape is too complex for the effect.
|
||||
- **3D (Classic)** (the track cube, surface types, blend steps, map art), Turntable and 3D export are separate,
|
||||
unbuilt items.
|
||||
|
||||
@@ -238,6 +248,7 @@ Release measurements and a repeatable CLI scene are in [3D lighting performance]
|
||||
|
||||
| Date | Change |
|
||||
|---|---|
|
||||
| 2026-11-08 | Contours that cross, touch or overlap are merged by vectorcraft-pathops before Extrude & Bevel, Inflate and Rotate build a solid, sharing its limits; others are built as drawn. |
|
||||
| 2026-11-06 | Extrude & Bevel, Inflate and Rotate apply to groups and layers: every path, compound path and type in them turns about one shared axis (#4506). |
|
||||
| 2026-10-21 | Four original lighting presets, shared by all four 3D effects and commands, with effective-setting recognition and existing preview/history behavior. |
|
||||
| 2026-10-17 | Smooth colored Inflate lighting and surface batching; legacy white-light appearance and the 0.05 seam minimum preserved; shared light Color and multiple lights remain vector output. |
|
||||
|
||||
+12
-4
@@ -1,6 +1,6 @@
|
||||
# Type parity
|
||||
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-07 · **Change:** minor (Indian-language hyphenation review and license allowlist, #4947; Bulgarian among the languages, with its quote marks and the fonts' Bulgarian forms, #5945; previously minor: Show Snap to Glyph Options scrolls to the options, with a Snap to Glyph checkbox, #5273; scores and estimates unchanged) · **Target:** Adobe Illustrator 2026 (30.x)
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-08 · **Change:** minor (Character Styles panel: a double-click on a style's row opens its Character Style Options; the dialog keeps a fixed width and scrolls its sections, so its buttons stay on screen) · **Target:** Adobe Illustrator 2026 (30.x)
|
||||
|
||||
Type is Illustrator's largest single area by use (weight 13 of 105 across "Type core" and "Type advanced" in
|
||||
[target-app-parity.md](target-app-parity.md)). This checklist lists the features one by one. Status is from the
|
||||
@@ -21,17 +21,20 @@ against Illustrator's public documentation; **estimated** unless noted.
|
||||
| Mouse wheel over the closed font-family field | done | #5253: Character, Properties and Control step selected text through the family list using saved font filters (excluding search text), one undo step per notch; the style is matched and the list stops at either end. Escape and leaving the field keep the change. Order, bounds and Undo grouping are VectorCraft's choices; scores unchanged. |
|
||||
| Soft return (forced line break, Shift+Enter) | done | Shift+Enter inserts a soft return (U+2028), breaking the line without starting a new paragraph; paragraph spacing (space before/after) and first-line indents apply only at paragraph ends; continuation lines in lists do not repeat the marker; soft return lines in justified text do not spread (#2754) |
|
||||
| Native font-family labels | partial | With Show Font Names in English off, localized legacy names are used when typographic names contain no native label (#2208); loaded-font and catalog-only regressions. Choosing among multiple native languages is unchanged. |
|
||||
| Point, area and type-on-a-path type; vertical variants | done / partial | vertical point, area and path type have initial support; fullwidth `!` / `?` keep the nominal glyph upright when no vertical alternate exists (Unicode Tu); in a non-rectangular area a word too wide for the top lines moves down to the first line that holds it (#1615); Escape while typing ends the edit, keeps the type selected and switches back to the tool that was active before type editing began (kept while clicks move editing to other text), or to the Selection tool when there was none (#1802), and Cmd+Enter (Ctrl+Enter on Windows and Linux) does the same unless a command is bound to it; `text.create` and `text.createInPath` take `justify` (#1752); MCP `add_text` forwards `vertical` to both commands; the Type and Vertical Type tools make area type when a closed path's outline is clicked and type on a path when an open one is, with pointers that say which, as the public help describes ([Create text](https://web.archive.org/web/20220127090642/https://helpx.adobe.com/illustrator/using/creating-text.html), [Create type on a path](https://web.archive.org/web/20220127090635/https://helpx.adobe.com/illustrator/using/creating-type-path.html)) |
|
||||
| Point, area and type-on-a-path type; vertical variants | done / partial | vertical point, area and path type have initial support; fullwidth `!` / `?` keep the nominal glyph upright when no vertical alternate exists (Unicode Tu); in a non-rectangular area a word too wide for the top lines moves down to the first line that holds it (#1615); Escape while typing ends the edit, keeps the type selected and switches back to the tool that double-clicked into the type, or to the Selection tool (#1802), and Cmd+Enter (Ctrl+Enter on Windows and Linux) does the same unless a command is bound to it; `text.create` and `text.createInPath` take `justify` (#1752); MCP `add_text` forwards `vertical` to both commands; the Type and Vertical Type tools make area type when a closed path's outline is clicked and type on a path when an open one is, with pointers that say which, as the public help describes ([Create text](https://web.archive.org/web/20220127090642/https://helpx.adobe.com/illustrator/using/creating-text.html), [Create type on a path](https://web.archive.org/web/20220127090635/https://helpx.adobe.com/illustrator/using/creating-type-path.html)) |
|
||||
| Point, area and type-on-a-path type; vertical variants | done / partial | vertical point, area and path type have initial support; fullwidth `!` / `?` keep the nominal glyph upright when no vertical alternate exists (Unicode Tu); in a non-rectangular area a word too wide for the top lines moves down to the first line that holds it (#1615); Escape while typing ends the edit, keeps the type selected and switches to the Selection tool (#1802); `text.create` and `text.createInPath` take `justify` (#1752); MCP `add_text` forwards `vertical` to both commands; Type › Type Orientation sets every frame of a thread, and a thread's frames share one writing direction |
|
||||
| Point, area and type-on-a-path type; vertical variants | done / partial | vertical point, area and path type have initial support; fullwidth `!` / `?` keep the nominal glyph upright when no vertical alternate exists (Unicode Tu); in a non-rectangular area a word too wide for the top lines moves down to the first line that holds it (#1615); Escape while typing ends the edit, keeps the type selected and switches to the Selection tool (#1802), and Cmd+Enter (Ctrl+Enter on Windows and Linux) does the same unless a command is bound to it; `text.create` and `text.createInPath` take `justify` (#1752); MCP `add_text` forwards `vertical` to both commands; the Type and Vertical Type tools make area type when a closed path's outline is clicked and type on a path when an open one is, with pointers that say which, as the public help describes ([Create text](https://web.archive.org/web/20220127090642/https://helpx.adobe.com/illustrator/using/creating-text.html), [Create type on a path](https://web.archive.org/web/20220127090635/https://helpx.adobe.com/illustrator/using/creating-type-path.html)) |
|
||||
| Area Type Options (rows, columns, inset, first baseline, Text Flow by rows or by columns, Auto Size, Shrink Text to Fit) | done | Text Flow fills the cells down each column first (By Columns, the default, as files from before it open) or across each row first (By Rows), in the dialog and `text.areaOptions {flow}` (#4978); the commands that make or restyle type say when it does not fit its frame; MCP `add_text` takes Auto Size and Shrink Text to Fit (#1471) |
|
||||
| Threaded text, Fit Headline, Text Wrap | done | Fit Headline sees wrapping in a frame one line tall (#1444); a thread holds area type and type on a path in any mix, as Illustrator links type in an area or along a path ([help](https://helpx.adobe.com/illustrator/using/manage-text-area.html)) |
|
||||
| Threading from the ports: selected area type and type on a path show an in port and an out port, empty, with an arrow on a side where the frame is threaded, or with a red "+" in the out port when the text doesn't fit; a click on either port loads the text; a click on a closed path, area type or type on a path threads into it, a click on empty canvas makes a frame of the same kind, shape and size there, a drag draws a rectangular frame; the frame placed comes after the clicked one from its out port and before it from its in port (the story then starts there); Escape or another tool cancels; a double-click on a threaded port breaks the thread there | partial | #2572: the Selection tool, `text.thread.add {from, to?, rect?, at?, before?}`, as the reference app's help describes ports and threading ([archived help, Threading text between objects](https://web.archive.org/web/20210119051048/https://helpx.adobe.com/illustrator/using/creating-text.html), [create text threads](https://helpx.adobe.com/illustrator/desktop/design-with-text/add-manage-text/create-text-threads-between-objects.html)); area type's in port sits on the left side below the top-left corner, type on a path's just before its start bracket; Show Text Threads draws its lines between the same ports; with more than 1,000 such objects selected no ports are drawn. a double-click on a port where the frame is threaded breaks the thread there, the story flowing into the frames before the break and the frames after it left empty, still threaded with each other when two or more (`text.thread.break`, [archived help](https://web.archive.org/web/20220127090642/https://helpx.adobe.com/illustrator/using/creating-text.html)). Remaining: the ports only take clicks with the Selection tool, and the loaded cursor borrows the I-beam until it's drawn |
|
||||
| Type on a Path effects and options; brackets | done | #429; Type on a Path Options has a Preview checkbox (#5360, as public tutorials of the dialog show) |
|
||||
| Character and Paragraph panels, styles with overrides | done | Character-style Auto-leading resets, partial definitions, local leading overrides, override markers, Undo/Redo and native serialization have regression coverage; differing paragraph alignments leave the shared alignment buttons unselected (headless regressions, full integration CI and visual review pass); mixed-value display for other paragraph fields remains missing |
|
||||
| Character and Paragraph panels, styles with overrides | done | Character-style Auto-leading resets, partial definitions, local leading overrides, override markers, Undo/Redo and native serialization have regression coverage; differing paragraph alignments leave the shared alignment buttons unselected (headless regressions, full integration CI and visual review pass); mixed-value display for other paragraph fields remains missing. Double-clicking a user character style's row opens its Character Style Options, and the dialog keeps a fixed width while its sections scroll when the window is shorter, so its buttons stay on screen; a paragraph style's row opens its Paragraph Style Options, the rename dialog the panel menu opens. Evidence: `panels::text_styles::tests::double_clicking_a_character_style_row_opens_its_options`, `dialogs::char_style_options::tests::the_sections_scroll_in_a_window_shorter_than_the_general_list` |
|
||||
| Copy or Cut selected characters, then paste as separate text art | done | A Type-range copy keeps the selected characters' font family, size and color when pasted on the canvas after leaving text editing, in the same document or another. On desktop the clipboard offers plain text to text consumers and rich art for canvas Paste; Paste Without Formatting while editing uses the destination text's style. `tests::clipboard::type_range_copy_stays_styled_when_pasted_as_art` (#5636) |
|
||||
| Character size and horizontal scale after object/group scaling | done | #1034: fields and setters compensate the stored affine; point size follows the transformed em-height axis, not the glyph ink bounds. Range edits, keyboard increments, leading and baseline shift use document points; rotation, reflection and shear remain editable. |
|
||||
| Preserve font sizes while scaling a group | missing | Separate enhancement; scaling still scales text with the other artwork. |
|
||||
| OpenType panel, Glyphs panel, alternates | done | Highlight Alternate Glyphs preference (#394, off by default) paints pink behind OpenType substitutions on screen when on (required shaping such as Arabic joining forms and the lam-alef ligature, including a lam-alef older fonts file under `liga`, is not highlighted; an optional feature that changes the ligature is); stylistic sets ss01–ss20, stylistic and titling alternates, proportional and lining figures, superscript and subscript are character-style features (`text.setStyle {features}`, #1607); the OpenType panel's Position menu sets superscript, subscript, numerator or denominator glyphs (`sups`, `subs`, `numr`, `dnom`). The OpenType panel's Stylistic Sets menu lists the selected font's `ss01`–`ss20` features, using a font-supplied name where available and `Set N` otherwise; several sets can be active, and selecting an active one removes it. For a mixed-font selection it uses the first selected character's font, a VectorCraft design choice ([public help](https://helpx.adobe.com/illustrator/desktop/design-with-text/special-characters-glyphs/add-stylistic-sets-to-selected-text.html), [OpenType feature specification](https://learn.microsoft.com/en-us/typography/opentype/spec/features_pt)). The Glyphs panel highlights the character selected with the Type tool (a range's first character, else the one before the caret) and scrolls it into view as the selection moves (#4908; `panels::glyphs` tests); its Show menu lists Unicode ranges and Alternates for Current Selection, the selected character's alternate glyphs from the font's `GSUB` table, one of which a double-click draws for that character (`text.setGlyphAlternate`); the glyph-cell pop-up of alternates is not there yet |
|
||||
| Font menu: samples, live preview, filters, favourites, recent families; font matching by any name; Find Font | done | #3515: recently applied families appear first, once each; missing families are omitted and the existing Number of Recent Fonts setting applies; #339; script filter: Japanese, Latin, Thai; the font scan on Linux also reads the folders fontconfig's configuration lists, such as TeX fonts under `/usr/share/texmf/fonts` (#1548, fixes #1529; not verified on Linux) Replace With Font lists family and style rows, one click setting both, with a search over them; its list scrolls on its own, apart from the document's font list (#4972). |
|
||||
| Font menu: samples, live preview, filters, favourites, recent families; font matching by any name; Find Font | done | #3515: recently applied families appear first, once each; missing families are omitted and the existing Number of Recent Fonts setting applies; #339; script filter: Japanese, Latin, Thai; the font scan on Linux also reads the folders fontconfig's configuration lists, such as TeX fonts under `/usr/share/texmf/fonts` (#1548, fixes #1529; not verified on Linux); Select Text by Font takes a scope: the document, chosen artboards or chosen layers; Find Font's Find In offers Document, Artboard (the active one) and Layers (the selected ones, else the current one) (#5529, a VectorCraft addition); Replace With Font lists family and style rows, one click setting both, with a search over them; its list scrolls on its own, apart from the document's font list (#4972). |
|
||||
| Missing glyphs set in an installed font made for their script (Thai, Lao, Khmer, Myanmar first; then any font that has them) | done | Thai: Leelawadee UI, Tahoma, Thonburi, Sukhumvit Set, Noto Sans Thai, TLWG |
|
||||
| Full font-name matching (OpenType name ID 4) | done | #1258: loaded/cataloged faces and Missing Fonts searches; localized names and variable default faces; Windows font-service QA pending |
|
||||
| Variable fonts | done | named instances as styles; Character panel › Variable Font sets each axis (`fontAxes`); the font menu's Font Technology › Variable lists only variable font families, with the script, kind and ★ filters ([Find, apply, and adjust variable fonts](https://helpx.adobe.com/illustrator/desktop/design-with-text/fonts-and-scripts/find-apply-and-adjust-variable-fonts.html)); a family with a variable file beside static ones counts as variable. Evidence: `font_menu::tests::the_variable_filter_lists_only_variable_families`, `tests_axes::a_family_with_variation_axes_is_variable`, `tests_sysfonts::a_family_with_a_variable_file_beside_static_ones_is_variable` |
|
||||
@@ -49,7 +52,7 @@ against Illustrator's public documentation; **estimated** unless noted.
|
||||
| Hidden characters (Show Hidden Characters) | done | `type.hiddenCharacters` |
|
||||
| Spell check (Check Spelling, Auto Spell Check, custom dictionary) | missing | menu stubs; needs an openly licensed dictionary |
|
||||
| Smart Punctuation, Change Case, Find & Replace | done | |
|
||||
| Alt + numeric-keypad codes while typing (Windows: `Alt+0176` → °) | partial | #5108: on Windows the character Windows posts when Alt comes up after keypad digits is typed at the caret like any other, in the typing's undo step, and the keypad digits typed with Alt run no shortcut (`windows_alt_codes` tests; not yet tried on a Windows machine). `type.insert {code}` (Windows Alt+0 code, Windows-1252 for 128–159) and `{unicode}` (hex code point) insert a character by its code (`menucmds::insert_a_character_by_its_code`). macOS and Linux have no such system convention and egui reports a keypad digit as the top-row digit, so there it does nothing; a floating panel window doesn't receive the character |
|
||||
| Alt + numeric-keypad codes while typing (Windows: `Alt+0176` → °) | partial | #5108: on Windows the character Windows posts when Alt comes up after keypad digits is typed at the caret like any other, in the typing's undo step, and the keypad digits typed with Alt run no shortcut. With NumLock off the keypad keys (Insert, End, arrows, Clear, Home, Page Up/Down without the extended-key flag) count as digits too and don't move the caret (`windows_alt_codes` unit tests; neither NumLock on nor off has been tried on a Windows machine yet). `type.insert {code}` (Windows Alt+0 code, Windows-1252 for 128–159) and `{unicode}` (hex code point) insert a character by its code (`menucmds::insert_a_character_by_its_code`). macOS and Linux have no such system convention and egui reports a keypad digit as the top-row digit, so there it does nothing; a floating panel window doesn't receive the character |
|
||||
| Caret: the arrows and Delete step over whole clusters (Thai consonant with its marks, combining accents, emoji); Backspace removes one character | done | in text with right-to-left characters the arrows move in visual order and stop on both sides of a character drawn with no width, such as a zero width non-joiner |
|
||||
| Touch Type tool | done | moves, scales and rotates one character through its kerning, baseline shift, scales and rotation (`text.touchType`); a character with a preceding logical character on the same line can move along the line in either reading direction; the first logical character moves only up and down. Positive `dx` follows reading order. These direction rules are VectorCraft's choices. |
|
||||
| Retype (identify fonts in outlines/images) | missing | Illustrator's uses a cloud model |
|
||||
@@ -65,6 +68,7 @@ against Illustrator's public documentation; **estimated** unless noted.
|
||||
| CJK: East Asian Type units (Q, Ha) | done | Preferences › Units › East Asian Type (`unitsAsianType`, Points by default) offers every unit and Q and Ha, a quarter of a millimetre each ([Scripting Guide](https://ai-scripting.docsforadobe.dev/scripting/measurementUnits/): 0.709 pt per Q; [InDesign's unit notation](https://helpx.adobe.com/in/indesign/desktop/layout-and-grid-tools/rulers-and-measure-tools/change-ruler-measurement-units.html): `q`, `h`). The public pages do not say which fields follow it, so no field uses it yet and that waits for a source. Evidence: `q_and_ha_are_a_quarter_millimetre`, `east_asian_type_unit_*` |
|
||||
| CJK: manual tate-chu-yoko | done | Character panel menu › Tate-chu-yoko (`text.setFormat` / `text.setRangeStyle {tateChuYoko}`), with Show East Asian Options: marked characters stand side by side across one em of a vertical column, squeezed to the em when wider; two or three half-width digits still do so without the mark; horizontal type keeps the mark and does not move them. Tate-chu-yoko Settings… (`ui.tateChuYokoSettings`, `{tcyUpDown, tcyLeftRight}` in points) moves a marked block up or down and right or left as one piece. Evidence: `tests_vertical::manual_tate_chu_yoko_sets_marked_characters_across_one_em`, `tests_vertical::tate_chu_yoko_settings_move_a_marked_block_up_down_left_and_right`, `typecmd::tate_chu_yoko_is_a_character_attribute_saved_only_when_on`, `typecmd::tate_chu_yoko_settings_are_character_attributes_saved_only_when_set`, `dialogs::tate_chu_yoko::tests` |
|
||||
| CJK: Standard Vertical Roman Alignment | done | Character panel menu › Standard Vertical Roman Alignment (`text.setFormat` / `text.setRangeStyle {standardVerticalRoman}`), with Show East Asian Options, off by default: in vertical type the marked half-width characters (Latin letters, digits and other characters that would lie on their side) stand upright one below the other, each in its upright cell; spaces keep their width and tate-chu-yoko blocks stay across the column; horizontal type keeps the mark and does not change. Character Style Options has its own checkbox for it. Evidence: `tests_vertical::standard_vertical_roman_alignment_stands_half_width_characters_upright`, `typecmd::standard_vertical_roman_is_a_character_attribute_saved_only_when_on` |
|
||||
| CJK: composite fonts | partial | Type › Composite Fonts… (`type.compositeFonts.set`), with Show East Asian Options: a font made of a font per class of character (Kanji, Kana, Punctuation, Symbols, Roman, Numerals), each with its own style, size and baseline in percent of the type's size, Kana, Roman and Numerals with horizontal and vertical scale, and Kana with Scale at Center; New, Delete Font, Import… and Export… (`.vccomposite`, `type.compositeFonts.import` and `.export`) ([Creating composite fonts](https://help.adobe.com/archive/en_US/illustrator/cs3/illustrator_cs3_help.pdf#page=347)). Composite fonts are listed first in the font menus, saved with the document, and their type is laid out per class; SVG and legacy `.ai` write it as outlines. Not yet: custom character sets, the Units menu, Show Sample. Evidence: `text::composite::tests::characters_fall_in_their_classes`, `tests::composite::composite_type_draws_each_class_in_its_font`, `compositefonts::tests`, `dialogs::composite_fonts::tests` |
|
||||
| CJK: ruby | partial | ruby (ふりがな) for live text (`type.ruby`): a reading over a byte range, above (right of the column in vertical type) or below, start/centre/end alignment, size, overhang or squeeze; saved natively, laid out with its line growing, drawn on the canvas, in SVG and PDF (as outlines where ruby is present), in EPS, EMF/WMF and legacy `.ai` (legacy `.ai` writes type with ruby as outlines), and kept by Create Outlines, Expand Appearance and flattening, each glyph where the layout puts it (`typecmd::ruby_tests::create_outlines_keeps_the_ruby_where_it_is_laid_out`) | #633 |
|
||||
| Language per character (Character panel › Language, character styles), text shaped in it | done | `text.setFormat` / `text.setRangeStyle {language}` by name or BCP 47 tag, one of Document Setup's languages (Hindi, Marathi, Gujarati, Bengali, Punjabi, Tamil, Telugu, Kannada, Malayalam, Odia and Urdu added, #4943; Assamese and Sanskrit added, #4947; Serbian: Cyrillic, Serbian: Latin and Croatian); the shaper gets the tag, so the font's language forms apply (OpenType `locl`: Turkish keeps `fi` apart and the dot on its i, #4940); new type takes the document's language; saved as the tag only when set, carried by character styles (#4946). English and eleven Indian languages hyphenate by run language; Sanskrit automatic hyphenation awaits allowlisted patterns (#4947). Not yet: spelling by it, `.ai`/PDF import of a text's language, paragraph styles. Evidence: `features::tests::language_picks_the_fonts_forms`, `features::tests::serbian_gets_the_fonts_serbian_forms`, `typecmd::area_tests::language_is_a_character_attribute_saved_only_when_set`, `tests::typo::indic_language_runs_hyphenate_with_both_composers`, `hyphen::tests::sanskrit_without_allowlisted_patterns_uses_only_exceptions` |
|
||||
| Language per character (Character panel › Language, character styles), text shaped in it | done | `text.setFormat` / `text.setRangeStyle {language}` by name or BCP 47 tag, one of Document Setup's languages (Hindi, Marathi, Gujarati, Bengali, Punjabi, Tamil, Telugu, Kannada, Malayalam, Odia and Urdu added, #4943; Serbian: Cyrillic, Serbian: Latin and Croatian; Bulgarian, #5945); the shaper gets the tag, so the font's language forms apply (OpenType `locl`: Turkish keeps `fi` apart and the dot on its i, #4940); new type takes the document's language; saved as the tag only when set, carried by character styles (#4946). Not yet: hyphenation and spelling by it, `.ai`/PDF import of a text's language, paragraph styles. Evidence: `features::tests::language_picks_the_fonts_forms`, `features::tests::serbian_gets_the_fonts_serbian_forms`, `typecmd::area_tests::language_is_a_character_attribute_saved_only_when_set` |
|
||||
@@ -79,11 +83,15 @@ Character Styles menu New/Redefine and footer New capture the first selected cha
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-11-08 | minor | Style panels: a double-click on a user character style's row opens its Character Style Options (`ui.charStyleOptions`), and on a paragraph style's row its Paragraph Style Options (rename); the Character Style Options dialog keeps a fixed width and scrolls its sections in a shorter window, so OK and Cancel stay on screen. Tests `panels::text_styles::tests::double_clicking_a_character_style_row_opens_its_options` and `dialogs::char_style_options::tests::the_sections_scroll_in_a_window_shorter_than_the_general_list`. Scores and estimates unchanged. |
|
||||
| 2026-11-07 | minor | Alt + numeric-keypad codes with NumLock off: the keypad keys arrive as Insert, End, arrows, Clear, Home and Page Up/Down, which Windows still composes into the code; with Alt held they now count as digits and are taken out of the frame instead of moving the caret, while the separate navigation keys (extended-key flag) keep their meaning (follow-up to #5939). Scores and estimates unchanged. |
|
||||
| 2026-11-07 | minor | Indian-language hyphenation (#4947): eleven MIT-licensed pattern sets, with grapheme and shaping-cluster protection in both composers and existing paragraph limits. Assamese and Sanskrit are selectable; Sanskrit automatic patterns remain pending an allowlisted source. Scores and estimates unchanged. |
|
||||
| 2026-11-06 | minor | Alt + numeric-keypad codes (`Alt+0176` → °) type their character at the caret on Windows, and `type.insert` inserts a character by `code` or `unicode` (#5108); scores and estimates unchanged |
|
||||
| 2026-11-06 | minor | Snap to Glyph › Glyph Bounds: each glyph's box gives four corners a drawn point lands on, also on a curved side (`B`), and its box and edges turn with rotated type (#5112); scores and estimates unchanged |
|
||||
| 2026-11-05 | minor | Character panel › Show Snap to Glyph Options scrolls the panel down to the Snap to Glyph section, which comes after every character attribute and could sit out of sight, and the section starts with a Snap to Glyph checkbox (View › Snap to Glyph) so its dimmed options can be turned on there (#5273); scores and estimates unchanged |
|
||||
| 2026-11-05 | minor | Release Type on a Path joins the Type Tools add-on: type on a path splits into point type and its path (#5532, beyond Illustrator). Scores and estimates unchanged. |
|
||||
| 2026-11-04 | minor | Select Text by Font takes a scope: the document, chosen artboards or chosen layers; Find Font's Find In offers Document, Artboard (the active one) and Layers (the selected ones, else the current one) (#5529, a VectorCraft addition); scores and estimates unchanged. |
|
||||
| 2026-11-04 | minor | Typographer's Quotes: a lone typed `”` (U+201D) is set like a straight `"` where a quote opens (at the start, after a space), taking the document's opening quote, and stays `”` where one closes: the macOS Serbian Cyrillic layout has no straight quote and types `”` on Shift+2, which now gives „…” (#5247). `“ „` and the single quotes `‘ ’ ‚` stay as typed (that layout's apostrophe key types `’`, and `’90s` keeps its apostrophe); pasted text keeps its quotes; with the option off `”` stays as typed. Evidence: `docsetup::a_typed_closing_double_quote_opens_where_a_quote_opens`; scores unchanged |
|
||||
| 2026-11-04 | minor | A Type-range Copy or Cut publishes styled art alongside plain text, so a later canvas Paste keeps its character formatting after editing ends (#5636). Scores and estimates unchanged. |
|
||||
| 2026-11-03 | minor | Glyphs panel adds Alternates for Current Selection. A chosen alternate changes one character's drawn glyph while keeping its Unicode text; character-style capture does not copy that per-character choice. Scores and estimates unchanged. |
|
||||
| 2026-11-04 | minor | Find Font's Replace With Font lists family and style rows, one click setting both, with a search over them; the list scrolls apart from the document's font list and refreshes after each replacement (#4972); scores and estimates unchanged. |
|
||||
|
||||
+12
-9
@@ -1,6 +1,6 @@
|
||||
# UI and interaction parity
|
||||
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-06 · **Change:** minor (Drop Shadow and glow dialogs: spinner arrows, #5367, #5368; Stroke Weight Up and Down shortcuts, #5797; Layers: Rename (`ui.rename`) opens the name field of the selected layer, group or object, #5324; Properties in Edit Artboards: Transform section above the Artboards section, #5219; scrubby labels: the Control bar's Stroke: and Opacity: links and the Properties panel's Stroke link scrub their fields, #4088; Properties: Quick Actions has Repeat Options for one selected repeat, #5181; Direct Selection: Shift-click picks several blend spine points, which drag together, #5285; Direct Selection: Cmd/Ctrl held lends the Selection tool and shows its bounding box, #3901; Join tool trims two crossing open paths and joins them at the crossing, #5844; Control bar: Paragraph: link and Align left/center/right while type is selected, #5372; shape tools: a press on the selection's centre point moves it and one in the rotate zone outside a box corner turns it, #5477; scores and estimates unchanged) · **Target:** Adobe Illustrator 2026 (30.x; Units › East Asian Type acts, with Q and Ha units; scores unchanged)
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-08 · **Change:** minor (Character Styles panel: a double-click on a style's row opens its Character Style Options; the dialog keeps a fixed width and scrolls its sections, so its buttons stay on screen) · **Target:** Adobe Illustrator 2026 (30.x; Units › East Asian Type acts, with Q and Ha units; scores unchanged)
|
||||
|
||||
## Feature submission evidence
|
||||
|
||||
@@ -39,6 +39,8 @@ Artboard Options forwards the active Artboard tool's Scale Artwork with Artboard
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-11-08 | minor | Style panels: a double-click on a user character style's row opens its Character Style Options (`ui.charStyleOptions`), and on a paragraph style's row its Paragraph Style Options (rename); the Character Style Options dialog keeps a fixed width and scrolls its sections in a shorter window, so OK and Cancel stay on screen. Tests `panels::text_styles::tests::double_clicking_a_character_style_row_opens_its_options` and `dialogs::char_style_options::tests::the_sections_scroll_in_a_window_shorter_than_the_general_list`. Scores and estimates unchanged. |
|
||||
| 2026-11-02 | minor | Selection QoL: saved marquee modes, screen drag direction with a 3 px dead zone, and translated mode/E feedback (#5313); VectorCraft addition, scores and estimates unchanged. |
|
||||
| 2026-10-30 | minor | Home screen: welcome, New / Open and Community are centred and the large Discord button uses the theme accent, part of #4684; scores and estimates unchanged (estimated) |
|
||||
| 2026-11-06 | minor | Snap to Grid: a straight segment dragged with Direct Selection lands its anchors on the grid, not the pressed point (#3835); scores and estimates unchanged |
|
||||
| 2026-11-06 | minor | Drop Shadow: a swatch beside Color follows the hex and a double-click opens the Color Picker over the dialog, whose OK fills Color (#5364); scores and estimates unchanged |
|
||||
@@ -130,7 +132,7 @@ tools, never checked side by side) isn't captured row by row.
|
||||
| Click the first anchor to close; the drag shapes the closing curve | done | |
|
||||
| Click the last anchor to retract its outgoing handle; drag from it to pull a new one | done | |
|
||||
| Alt over a handle, anchor or segment acts as the Anchor Point tool | done | |
|
||||
| Cmd/Ctrl lends the last-used selection tool | done | the path being drawn continues afterwards; with Direct Selection (the default until a selection tool is chosen) a Cmd drag moves an anchor of the path being drawn, moves a straight segment or bends a curved one, one undo step each, and a Cmd-click away from art ends the path; with Selection the hidden bounding box of the path being drawn takes no press, so the drag moves the path (#4980) |
|
||||
| Cmd/Ctrl lends the last-used selection tool | done | the path being drawn continues afterwards; with Direct Selection (the default until a selection tool is chosen) a Cmd drag moves an anchor of the path being drawn, moves a straight segment or bends a curved one, one undo step each, and a Cmd-click away from art ends the path; with Selection the hidden bounding box of the path being drawn takes no press, so the drag moves the path (#4980); anchors or segments the lent Direct Selection picks are what Copy and Cut take, as with Direct Selection chosen, while Copy with the Pen's own last anchor selected takes the whole path (#6123) |
|
||||
| Click an open path's end to continue it; click another path's end to join | done | #776 |
|
||||
| Rubber Band preview | done | Preferences option |
|
||||
| Auto Add/Delete on a selected path; Shift or the preference disables it | done | |
|
||||
@@ -190,7 +192,7 @@ tools, never checked side by side) isn't captured row by row.
|
||||
| Alt with Direct Selection makes a marquee Group Selection's for the drag: it selects every path it touches, whole (Shift toggles them), and the Group Selection pointer stays until the release | done | #4890 |
|
||||
| Direct Selection: a click on a selected object's centre point (Attributes › Show Center) selects the object whole, and a drag from it moves the object in one undo step | done | #4891 |
|
||||
| Escape cancels a Direct Selection drag | done | #1803 (#1743) |
|
||||
| Live Corners widgets (radius readout, Alt-click cycles kind, double-click the Corners dialog) | done | a Direct Selection click on a widget selects its corner (#1239); a press-and-drag on a widget of a path selected whole still rounds every corner (#908), and adding widgets to the selection by Shift-click (#1232) is missing; the bounding box hides while a widget is dragged with the Selection tool (#1229); a round corner next to a curved side curves smoothly instead of sticking out of the shape (#1512); a corner rounds until its cut reaches its neighbours' cuts, so one corner of a square alone reaches the whole side (#2332) |
|
||||
| Live Corners widgets (radius readout, Alt-click cycles kind, double-click the Corners dialog) | done | a Direct Selection click on a widget selects its corner (#1239), and with every corner selected a Shift-click on a widget picks that corner alone instead of deselecting it (#5188); a press-and-drag on a widget of a path selected whole still rounds every corner (#908), and adding widgets to the selection by Shift-click (#1232) is missing; the bounding box hides while a widget is dragged with the Selection tool (#1229); a round corner next to a curved side curves smoothly instead of sticking out of the shape (#1512); a corner rounds until its cut reaches its neighbours' cuts, so one corner of a square alone reaches the whole side (#2332) |
|
||||
| Corners between curved sides (#1144), Relative rounding | done | #1144 closed; Relative rounding in the Corners dialog (Relative / Absolute, radius as a percentage of each corner's maximum, kept as the shape is resized; `object.setLiveShape` `relativeRadii`, #3091, `tests_livecorners::relative_corner_rounding_keeps_fraction_on_resize`) |
|
||||
| Pie widgets on a live ellipse: drag one to set Pie Start or End Angle, double-click one to make the ellipse whole | done | Selection tool, with the bounding box showing |
|
||||
| A shape just drawn shows its bounding box and Live Shape widgets with the shape tool still active, and the selection can be moved and turned without switching tools | done | #5477: Rectangle, Rounded Rectangle, Ellipse, Polygon and Star keep the selection's bounding box, corner widgets and pie widgets on show while they draw nothing; a drag on a corner or pie widget adjusts it (arrows step the corner kind, Escape cancels), a press on the selection's centre point (Attributes › Show Center) moves the selection — the Selection tool's move arrow, snapping and Alt copy — a press just outside a corner of the box turns it about the centre (the Selection tool's rotate zone and cursor), and a press anywhere else draws (so a second shape drawn from the first one's centre moves the first: press elsewhere or deselect first). Public descriptions: [Live Shapes](https://helpx.adobe.com/illustrator/using/live-shapes.html) (live shapes adjust without switching tools) and [CreativePro, Working with Live Shapes](https://creativepro.com/?p=23921) (a widget shows in every corner on release; drag one toward the centre to round). The bounding-box handles show but scale only with the Selection tool, so a press on a corner still starts a new shape there; double-clicking a widget opens nothing with a shape tool. Tests `a_shape_tool_drags_the_selected_shapes_widgets` and `a_shape_tool_moves_the_selection_by_its_centre_point_and_turns_it_from_a_corner` |
|
||||
@@ -287,7 +289,7 @@ tools, never checked side by side) isn't captured row by row.
|
||||
| Artboard tool: the canvas right-click menu has Lock Artboards (Lock Selected, Lock All Except Selected, Lock All) and Unlock Artboards (Unlock Selected, Unlock All) | done | #2531; `artboard.setProps` with `locked` for each artboard named; the lock itself is #2592 |
|
||||
| Document Setup → Edit Artboards applies valid settings, closes the dialog and activates the Artboard tool | done | Pointer-click tests cover successful handoff, invalid settings, OK, Cancel and Undo in `dialogs/document_setup.rs`. |
|
||||
| Escape leaves Artboard editing for Selection; during a drag it first cancels the gesture | done | Headless egui key events cover idle Escape, active-drag cancellation and a subsequent Escape in `tests/distortkeys.rs`. |
|
||||
| Escape while typing ends the edit, keeps the type selected and switches to the Selection tool | done | #1802 (#1686, #1656) |
|
||||
| Escape while typing ends the edit, keeps the type selected and switches back to the tool that was active before type editing began (kept while clicks move editing to other text), or to the Selection tool when there was none | done | #1802 (#1686, #1656) |
|
||||
| Selection tool: selected area type and type on a path show an in port and an out port (empty, an arrow where threaded, the red "+" of overflow); a click on either loads the text cursor; a click on a closed path, on empty canvas or a drag threads the text there, after the clicked frame from its out port, before it from its in port; Escape or another tool drops it; a double-click on a threaded port breaks the thread there | partial | #2572 (`text.thread.add`, `before` for the in port); the out port sits on the frame's right side above the bottom-right corner handle and the in port on its left side below the top-left one, so the handles can still be grabbed; a double-click on a threaded port breaks the thread (`text.thread.break`, [archived help](https://web.archive.org/web/20220127090642/https://helpx.adobe.com/illustrator/using/creating-text.html)); the loaded cursor borrows the I-beam |
|
||||
| Shift-click selects several artboards (Artboard tool, Artboards panel); they move, Alt-copy and delete together | done | `artboard.move`/`artboard.delete` `indices` (#1139); in the panel, Shift- and Ctrl/Cmd-click work with any tool by switching to the Artboard tool (#5698); panel menu, trash and Properties share selected-set deletion; all-selected retains artboard 1 and a single board cannot be deleted, with pointer-event and Undo/Redo coverage |
|
||||
| Artboards panel: drag a row above or below another to reorder the artboards (as Move Up / Move Down do) | done | #4687; a line shows where the row lands, `artboard.reorder` in one undo step, the moved artboard becomes active; public forum answers describe the drag |
|
||||
@@ -365,7 +367,8 @@ next unit in the order a right-click on a ruler lists them, from Feet back to Po
|
||||
| Live trace result bounds and selection highlights exclude the retained bitmap; source-image views retain it | done | All TraceView modes and rotated result bounds regression-covered; ordinary hidden group behavior retained |
|
||||
| Image Trace panel: the Preview checkbox before Trace chooses whether a setting change traces the selected Image Trace object again at once | done | Per the public documentation, Preview shows the result of the current settings and Trace traces with them (<https://web.archive.org/web/20250831090623/https://helpx.adobe.com/illustrator/using/image-trace.html>). Preview is on by default and kept with the UI preferences; Reset to Default leaves it. Off, changes wait in the panel until Trace applies them as one undo step, or until Preview is turned on again. Changes stay with the object they were made for while another object is selected, and come back when it is selected again. `imageTrace.preview {on?}`, `ui.set {imageTracePreview}`; `panels/image_trace.rs` headless tests (`with_preview_off_a_slider_change_waits_for_trace`, `turning_preview_on_traces_the_changes_that_waited`, `preview_turned_on_with_nothing_selected_traces_when_the_object_is_selected_again`, `settings_that_wait_stay_with_their_object`, `settings_that_wait_come_back_when_their_object_is_selected_again`, `settings_that_wait_are_dropped_when_their_object_changed_since`, `preview_is_kept_with_the_preferences_and_reset_to_default_leaves_it`) |
|
||||
| Toolbar without group labels by default, one or two columns; All Tools drawer by flyout group with shortcuts, its menu (Reset, Basic, Advanced) and Show section | done | #1751; a preference brings the labels back; `toolbar.show` sets the Fill/Stroke, Coloring, Draw Mode and Screen Mode controls |
|
||||
| Actions panel: ≡ › Save Actions… saves the current set with all its actions to a file and ≡ › Load Actions… adds a saved set ([Manage a set of actions](https://helpx.adobe.com/illustrator/desktop/automate-visualize-data/automate-actions/manage-a-set-of-actions.html)) | partial | `ui.actionSet.save`, `ui.actionSet.load`; `panels/actions.rs` tests. The file is VectorCraft's own `.vcactions` JSON; the reference app's `.aia` files and Reset, Clear and Replace Actions remain |
|
||||
| Actions panel: ≡ › Save Actions… saves the current set with all its actions to a file and ≡ › Load Actions… adds a saved set ([Manage a set of actions](https://helpx.adobe.com/illustrator/desktop/automate-visualize-data/automate-actions/manage-a-set-of-actions.html)) | partial | `ui.actionSet.save`, `ui.actionSet.load`; `panels/actions.rs` tests. The file is VectorCraft's own `.vcactions` JSON; Reset, Clear and Replace Actions remain |
|
||||
| Actions panel: ≡ › Load Actions… also reads action sets saved as `.aia` files ([Actions panel overview](https://helpx.adobe.com/illustrator/desktop/automate-visualize-data/automate-actions/actions-panel-overview.html)) | partial | `actionSet.read`, `ui.actionSet.load`; `tests/actionset.rs`, `panels/actions.rs` tests, `import_fuzz`. Only steps with a label and no recorded values come in, as menu commands that run with no values and open no dialog, matched by label; the other steps, recorded menu items included, are left out and counted |
|
||||
| Actions panel: ≡ › Action Options… renames the selected action and sets its function key and color ([Actions panel overview](https://helpx.adobe.com/illustrator/desktop/automate-visualize-data/automate-actions/actions-panel-overview.html)) | partial | `ui.action.options`; `panels/actions.rs` tests (part of #1629). The color shows nowhere until Button Mode exists |
|
||||
| Actions panel: ≡ › Playback Options… plays actions Accelerated, Step by Step or with a pause between steps ([Specify playback speed](https://helpx.adobe.com/illustrator/desktop/automate-visualize-data/automate-actions/specify-playback-speed.html)) | done | `ui.action.playbackOptions`; `panels/actions.rs` tests. The pause is a whole number of seconds from 1 to 60 (VectorCraft's own range); Batch… plays at full speed |
|
||||
| Actions panel: a clicked action stays selected for Play Current Selection and Delete Selection | partial | #1853 (part of #1629); editing actions and action shortcuts remain |
|
||||
@@ -384,7 +387,7 @@ next unit in the order a right-click on a ruler lists them, from Feet back to Po
|
||||
| Symbol libraries: Window › Symbol Libraries (Basic Shapes, User Defined, Other Library…, Save Symbols…) and the Symbols panel's Symbol Libraries Menu button and its menu's Open Symbol Library / Save Symbol Library…; a click on a library symbol adds it to the document's Symbols (one undo step, it becomes the current symbol), Shift/Cmd-clicks select for Add to Symbols, and a symbol dragged onto the canvas is added and placed where it is dropped | done | [public source](https://helpx.adobe.com/illustrator/desktop/manage-objects/traces-mockups-symbols/create-or-import-symbol-libraries.html), [Symbols panel options](https://helpx.adobe.com/illustrator/desktop/manage-objects/traces-mockups-symbols/symbols-panel-options.html), [placing from a library](https://helpx.adobe.com/illustrator/desktop/manage-objects/traces-mockups-symbols/create-and-place-symbols.html); `window.symbolLibrary`, `window.symbolLibrary.other`, `ui.saveSymbolLibrary` (dialog `saveSymbolLibrary`), `window.userSymbolLibrary1`…`10`; `panels::tests_symbol_libraries`; only one built-in library (original, generated in code) |
|
||||
| Brush libraries: Window › Brush Libraries (Art Ribbons, Calligraphic Nibs, Pattern Borders, Scatter Shapes, User Defined, Other Library…, Save Brushes…) and the Brushes panel's Brush Libraries Menu button and its menu's Open Brush Library / Save Brush Library…; a click on a library brush adds it to the document's Brushes (one undo step, it becomes the current brush, and selected paths take it in the same step), Shift/Cmd-clicks select for Add to Brushes, a brush dragged onto a path is added and applied to it and one dragged onto the Brushes panel is added; thumbnails render with the library's patterns and symbols | done | [public source](https://helpx.adobe.com/illustrator/desktop/paint-and-fill/apply-and-edit-strokes/create-new-brush-libraries.html), [import brushes](https://helpx.adobe.com/illustrator/desktop/paint-and-fill/apply-and-edit-strokes/import-brushes-from-brush-libraries-or-other-files.html), [Brushes panel overview](https://helpx.adobe.com/illustrator/desktop/paint-and-fill/apply-and-edit-strokes/brushes-panel-overview.html); `window.brushLibrary`, `window.brushLibrary.other`, `ui.saveBrushLibrary` (dialog `saveBrushLibrary`), `window.userBrushLibrary1`…`10`; `panels::tests_brush_libraries`; four built-in libraries (original, generated in code) |
|
||||
| Symbols panel: New Symbol opens Symbol Options (Name) before making the symbol; Alt-click skips it | partial | #1560 (#1566); Registration 9-point grid in Symbol Options (`symbol.new` / `symbol.place`); Export Type (Graphic / Movie Clip) and Enable Guides for 9-Slice Scaling (scaled instances keep their corners; in symbol editing mode the guides are drawn over the art and the Selection tool drags them); Symbol Type (Dynamic Symbol / Static Symbol, new symbols dynamic; #4938) |
|
||||
| Dynamic symbols: an instance changes the fill, stroke, opacity and blend of objects in its symbol's art and stays linked; Reset in the Properties panel's Quick Actions and the Symbols panel menu (Reset Symbol Instance) | partial | #4938; `symbol.instance.setAppearance` (by child-index path) and `symbol.instance.reset`; redefining keeps the changes, Break Link bakes them; on-canvas Direct Selection of a part inside an instance (with the Fill/Stroke controls then setting its change) remains |
|
||||
| Dynamic symbols: an instance changes the fill, stroke, opacity and blend of objects in its symbol's art and stays linked; Reset in the Properties panel's Quick Actions and the Symbols panel menu (Reset Symbol Instance) | partial | #4938; `symbol.instance.setAppearance` (by child-index path) and `symbol.instance.reset`; redefining keeps the changes, Break Link bakes them; Direct Selection of a path, compound path or type object inside an instance, with the Fill/Stroke controls setting its solid fill or stroke, is on canvas; on-canvas editing beyond a solid fill and stroke, and `.ai` read and write, remain |
|
||||
| Pathfinder Trim, Merge and Crop remove strokes; Merge joins same-fill objects whatever their strokes | done | #1570 (#1572) |
|
||||
| Pathfinder panel on one group selected alone; a greyed-out button says what it needs | partial | #1450; the group's members are combined; one plain path selected alone stays disabled (the public documentation doesn't say what the operations do to a single path) |
|
||||
| Pathfinder Divide: an open cutting line splits a filled path | done | #1307; straight, crossed, bent and curved cutters, holes and frontmost appearance regression-tested; native automation: independent piece movement, one Undo/Redo, saved-document round trip and window capture; existing bounded-map fallback remains |
|
||||
@@ -434,6 +437,7 @@ next unit in the order a right-click on a ruler lists them, from Feet back to Po
|
||||
| Color Effects add-on (VectorCraft addition): Object › Plug-ins › Color Effects › Find Nearest Swatch… picks a Library (Document Swatches, a built-in library, or a library or colour book the user saved or loaded) and Fill and Stroke, lists each colour of the selection with its three closest swatches (chip, name, ΔE 2000), and Apply gives each colour its nearest swatch (global and spot swatches linked; a library's swatches added to the document first), one undo step | done | #4923; `addon.color.nearestSwatch`, `addon.color.applyNearestSwatch`, `crates/engine/src/cmd/addons/color/nearest.rs`, `crates/ui-egui/src/addons/color/nearest.rs` and their tests; not a feature of the reference app, so it is not scored |
|
||||
| Selection Tools add-on (VectorCraft addition): Object › Plug-ins › Selection Tools › Select by Artboards… lists every artboard (number, name, width × height in the document's units), filters them by name, chooses several (click, Shift-click for a range, Cmd/Ctrl-click to toggle; Select All / None act on the rows shown; a count of those chosen), fits a row's artboard in the window on double-click and makes it active, and on OK selects the objects overlapping, fully inside or fully outside the chosen artboards (Overlapping is All on Active Artboard's test) | done | #5525, #5548, #5549; `addon.select.byArtboards`, `crates/engine/src/cmd/addons/select.rs`, `crates/ui-egui/src/addons/select.rs` and their tests; not a feature of the reference app |
|
||||
| Selection Tools add-on (VectorCraft addition): Select Linked, Select Embedded, Select Missing and Select Modified in Object › Plug-ins › Selection Tools and the Links panel menu (off when no image has that status; Shift adds to the selection) select the images and placed documents with that link status, leaving out hidden, locked, template-layer and outside-isolation ones, which the status bar counts (e.g. "Selected 9 missing images; 3 more are hidden or locked"); Select by Link Status… lists them with name, status and format, searches by name, filters by status, picks with checkboxes and All / None, and selects with Zoom to Selection on by default | done | #5526; `addon.select.byLinkStatus`, `crates/engine/src/cmd/addons/select.rs`, `crates/ui-egui/src/addons/select/link_status.rs` and their tests; not a feature of the reference app |
|
||||
| Style panels: a double-click on a user character style's row opens its Character Style Options, and on a paragraph style's row its Paragraph Style Options (rename), and the Character Style Options dialog keeps a fixed width, its sections scrolling when the window is shorter so OK and Cancel stay on screen | done | `ui.charStyleOptions`, `ui.paramDialog` (`paraStyle.rename`); `panels::text_styles::tests::double_clicking_a_character_style_row_opens_its_options`, `dialogs::char_style_options::tests::the_sections_scroll_in_a_window_shorter_than_the_general_list` |
|
||||
|
||||
## Look and feel
|
||||
|
||||
@@ -478,6 +482,8 @@ separate. Scores and hours unchanged. [Behavior and command details](development
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-11-07 | minor | Pen and Curvature tool with Cmd/Ctrl held: Edit › Copy and Cut take the anchors and segments the lent Direct Selection picked, as with Direct Selection chosen, not the whole path; with the Pen's own last anchor selected Copy still takes the whole path (#6123); scores and estimates unchanged |
|
||||
| 2026-11-07 | minor | Live Corners: with Direct Selection, while every corner of a path is selected, a Shift-click on a corner widget picks that corner alone instead of deselecting it (#5188); adding a hidden corner's widget by Shift-click stays open (#1232); scores and estimates unchanged |
|
||||
| 2026-11-06 | minor | Keyboard shortcuts: Cmd/Ctrl+Alt+. and Cmd/Ctrl+Alt+, (Stroke Weight Up and Down) step each selected stroke's weight, or the next object drawn's (#5797); scores and estimates unchanged |
|
||||
| 2026-11-06 | minor | Properties: Quick Actions has Repeat Options for one selected radial, grid or mirror repeat, opening Object › Repeat › Options with its values (#5181); scores and estimates unchanged |
|
||||
| 2026-11-06 | minor | Control bar: with type selected, a Paragraph: link (the Paragraph panel in a popover) and the Align left, Align center and Align right buttons follow the Character controls; the bar leaves them out from its right end when short of room, after X/Y/W/H and the Align buttons (#5372); scores and estimates unchanged |
|
||||
@@ -594,9 +600,6 @@ separate. Scores and hours unchanged. [Behavior and command details](development
|
||||
| 2026-10-22 | minor | Gradient panel: the Method menu, Classic or Perceptual (Illustrator 30.0); scores and estimates unchanged. |
|
||||
| 2026-10-22 | minor | Gradient panel: the Dither box (Illustrator 30.0); scores and estimates unchanged. |
|
||||
| 2026-10-22 | minor | Recolor Artwork Edit chips scroll within the available screen height (#3416); small palettes retain their tab height; scores and estimates unchanged. |
|
||||
| 2026-10-22 | minor | Artboard Options honors Scale Artwork with Artboard for preset, orientation and typed-size changes; both Fits keep artwork stationary; scores and estimates unchanged. |
|
||||
| 2026-10-22 | minor | Gradient panel: the Method menu, Classic or Perceptual (Illustrator 30.0); scores and estimates unchanged. |
|
||||
| 2026-10-22 | minor | Gradient panel: the Dither box (Illustrator 30.0); scores and estimates unchanged. |
|
||||
| 2026-10-21 | minor | Blend panel Type and Ramp control step easing with a separate color Shift (#2539); Blend Options retains spacing and orientation; polynomial curves are original approximations. Scores and estimates unchanged. |
|
||||
| 2026-10-21 | minor | Workspaces keep the layout changes made in them when switching away and back, and across restarts; Reset <name> returns to the saved layout; score unchanged (estimated) |
|
||||
| 2026-10-21 | minor | Panels dragged by the mouse join a dock group as tabs, split it top/bottom or become icons in the icon column; dock tabs close from their context menu; score unchanged (estimated) |
|
||||
|
||||
Reference in New Issue
Block a user