mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-14 05:24:44 +00:00
Merge main into fix/trace-blur-rings
# Conflicts: # docs/image-trace-quality.md
This commit is contained in:
@@ -417,7 +417,10 @@ button (Add Tool…) opens a menu of every tool under the drawer's headings: a c
|
||||
{tool, toolbar}`; the tools already in the toolbar are dimmed under their headings. The drawer has no Show section
|
||||
there. `window.floatTools {tool, toolbar}` floats one of its groups, and a group torn off it shows and hides with
|
||||
it. `window.toolbar.list` returns the toolbars (`ui.custom_toolbars` in `ui.inspect`: name, slots, shown flag,
|
||||
two-column flag, top-left corner, the groups torn off it). They are kept with the workspace they were made in:
|
||||
two-column flag, top-left corner, the groups torn off it, and `dock` and `dock_right` while docked or once docked).
|
||||
`window.toolbar.dock {name, side?, order?}` docks a toolbar in the lane along the window's left or right edge, and
|
||||
`window.toolbar.float {name, x?, y?}` floats it again; dropping its title bar on an edge or dragging it out of its
|
||||
lane does the same (see the docking section in `docs/mcp.md`). They are kept with the workspace they were made in:
|
||||
switching workspaces shows that workspace's toolbars, Reset Workspace keeps them, and New Workspace starts the new
|
||||
workspace with a copy of them.
|
||||
|
||||
|
||||
+1
-1
@@ -126,7 +126,7 @@ On GNOME/Wayland, enable **Preferences › User Interface › System Title Bar**
|
||||
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:
|
||||
|
||||
- **Clipboard:** under Wayland arboard talks to the compositor through the data-control protocol (wlroots compositors such as Sway and Hyprland, KDE Plasma), so bitmaps (`image/png`), SVG markup and text copied in any app paste (#398). Where the compositor lacks the protocol (GNOME's Mutter, [arboard#223](https://github.com/1Password/arboard/issues/223)), arboard falls back to the X11 clipboard through XWayland, which only holds what X11 apps copied. Where there is no X11 either (the Flatpak on a Wayland session: `--socket=fallback-x11` gives it none), Copy and Paste use the compositor's core data-device protocol on the window's own connection through smithay-clipboard: text only (a copy's text or its SVG markup), and only while the window has focus. smithay-clipboard waits for the owner's data with no limit, so its reads run on a worker thread and the UI thread waits 2 s at most: an owner that never sends its data costs one read 2 s, and later reads return at once until it answers. When a read gets no answer in its 2 s, such as a paste's check whether the clipboard still holds what VectorCraft copied, the paste waits on its background thread for that read's answer, up to 10 s after the read was sent, and pastes the text unless it is empty or what VectorCraft copied. A clipboard neither backend opens is tried again after 1 s, doubling to a minute (a Copy or Paste of the user's at most once a second), and logged once when it goes and once when it comes back: before, the background Paste check reconnected and logged a warning every 250 ms. egui's own text paste into fields goes through smithay-clipboard and works either way.
|
||||
- **Clipboard owners that never answer (#510):** reading the clipboard waits on the app that owns it: arboard gives up on an X11 owner after 4 s for each format it tries, and a Wayland read waits for the owner to send its data. So on Linux the check that enables the Paste menu items runs on a background thread with a second clipboard handle (`crates/ui-egui/src/clipboard_probe.rs`, installed as `Services::clipboard_probe`), only while nothing is copied in the app and a document is open, and the window keeps drawing. Every arboard read on Linux and the BSDs, including the UI thread's (a paste, and a Copy or Cut checking what the clipboard held), runs on a worker thread with a handle of its own and waits 2 s at most: an owner that never sends its data costs one read that wait, and later reads fail at once until it answers. A paste's bitmap read waits up to 10 s on the paste's background thread, so the UI thread does not wait for it. When one of a paste's reads gets no answer in its 2 s, or a paste follows a read that has not been answered yet, such as the paste's own check whether the clipboard still holds what VectorCraft copied, the paste waits on that thread for that read's answer, up to 10 s after the read was sent, and pastes what it holds. When the answer is what VectorCraft copied, holds nothing to paste, or does not come, the paste takes the internal clipboard. On X11, quitting within 25 s of a read that got no answer waits for that read to end, so the app's own handle is the last one and hands what it copied to the clipboard manager. Windows and macOS keep the check on the UI thread: Windows only asks which formats the clipboard holds, macOS asks the pasteboard server.
|
||||
- **Clipboard owners that never answer (#510):** reading the clipboard waits on the app that owns it: arboard gives up on an X11 owner after 4 s for each format it tries, and a Wayland read waits for the owner to send its data. So on Linux the check that enables the Paste menu items runs on a background thread with a second clipboard handle (`crates/ui-egui/src/clipboard_probe.rs`, installed as `Services::clipboard_probe`), only while nothing is copied in the app and a document is open, and the window keeps drawing. Every arboard read on Linux and the BSDs, including the UI thread's (a paste, and a Copy or Cut checking what the clipboard held), runs on a worker thread with a handle of its own and waits 2 s at most: an owner that never sends its data costs one read that wait, and later reads fail at once until it answers. A paste's bitmap read waits up to 10 s on the paste's background thread, so the UI thread does not wait for it. When one of a paste's reads gets no answer in its 2 s, or a paste follows a read that has not been answered yet, such as the paste's own check whether the clipboard still holds what VectorCraft copied, the paste waits on that thread for that read's answer, up to 10 s after the read was sent, and pastes what it holds. When the answer is what VectorCraft copied, holds nothing to paste, or does not come, the paste takes the internal clipboard. On X11, quitting within 25 s of a read that got no answer waits for that read to end, so the app's own handle is the last one and hands what it copied to the clipboard manager when one runs. That includes a read of the Paste menu check's handle: quitting waits up to 27 s for the background thread to drop it before the app drops its own, and quits after that wait even when the handle has not been dropped. The app hides its main window before these waits (`hide_before_teardown` in `apps/vectorcraft/src/app.rs`), so an X11 window, an XWayland one included, closes at once; winit cannot hide a native Wayland window, which stays on screen until the waits end. Windows and macOS keep the check on the UI thread: Windows only asks which formats the clipboard holds, macOS asks the pasteboard server.
|
||||
- **Copied files:** files copied in a file manager (`text/uri-list`; `CF_HDROP` on Windows, file URLs on macOS) paste as the first one that is art (SVG, PDF, EPS, EMF/WMF or a bitmap; a `.ai` or `.ait` file from the editing data it holds, else as the PDF or PostScript it holds), before the clipboard's other formats (which include the files' paths as text).
|
||||
- **Dropping files on the window does not work under Wayland:** winit 0.30, which eframe 0.37 runs on, has no Wayland drag and drop ([winit#1881](https://github.com/rust-windowing/winit/issues/1881), added in winit 0.31; [egui#1563](https://github.com/emilk/egui/issues/1563)), so no `dropped_files` arrive. Until eframe moves to winit 0.31: copy the files in the file manager and paste them, use File › Place or Open, or open the window through XWayland, where drops work: set **Preferences › Performance › Linux Display Server** to **X11 (XWayland)** and restart (#1151), or start the app with `WAYLAND_DISPLAY= vectorcraft`. The preference (`linuxDisplayServer`, read at startup in `apps/vectorcraft/src/main.rs`, shown on Linux only) has winit open the window on X11 (`EventLoopBuilderExtX11::with_x11`) when the session is Wayland, `DISPLAY` is set and the X11 libraries winit loads are installed (`apps/vectorcraft/src/xwayland.rs` reads `ldconfig -p` and the usual library directories); otherwise the window opens on Wayland and the log says why. Unlike clearing `WAYLAND_DISPLAY`, it leaves the clipboard on the compositor's own.
|
||||
- **Pens and pen displays under Wayland (#491, #2028):** winit 0.30 doesn't bind the Wayland tablet protocol (`zwp_tablet_v2`; tablet input arrives in winit 0.31, [winit#4318](https://github.com/rust-windowing/winit/pull/4318), [egui#7731](https://github.com/emilk/egui/pull/7731)). Since Plasma 6.3, KWin no longer turns tablet input into pointer input for such apps ([kwin!6336](https://invent.kde.org/plasma/kwin/-/merge_requests/6336), commit [25c65abd](https://invent.kde.org/plasma/kwin/-/commit/25c65abddd95eb87fb892a8594faccbf509ff62f)), and GNOME's Mutter does not turn it into pointer input either (that commit's message): on KWin the pen moves the compositor's cursor over the window, but the app gets no motion or presses and shows none of its own cursors. Until eframe moves to winit 0.31, the app runs under XWayland, which supports the tablet protocol and hands the pen to X11 apps as a pointer: Preferences › Performance › Linux Display Server's Automatic (the default) and X11 (XWayland) When a Pen Is Attached (`x11WithPen`) open the window through XWayland when `/proc/bus/input/devices` lists a pen as the app starts, a device with the `BTN_TOOL_PEN` key and the `ABS_X` and `ABS_Y` axes, and log `pen found: opening the window through XWayland`, as PhotoCraft does (#4967; `VECTORCRAFT_NATIVE_WAYLAND=1` keeps the window on Wayland). For a pen attached after the app started, either run the app under XWayland (Preferences › Performance › Linux Display Server › X11 (XWayland); `WAYLAND_DISPLAY= vectorcraft`, or `env -u WAYLAND_DISPLAY vectorcraft`; for a desktop launcher, put `env WAYLAND_DISPLAY=` before the command in its `Exec=` line), or turn KWin's deprecated emulation back on for the whole session by setting `KWIN_WAYLAND_EMULATE_TABLET=1` in KWin's environment (for example in a file under `~/.config/environment.d/` or in `/etc/environment`) and logging in again. The pen then works as a mouse. Under XWayland the app also reads the pen's pressure (next item); with KWin's emulation on native Wayland the pen has no pressure. Other compositors that don't emulate a pointer for tablets behave the same way.
|
||||
|
||||
+6
-1
@@ -16,7 +16,12 @@ The **Dimension Tool** is in the Modify section of the toolbar. Its strip offers
|
||||
before the release; a longer drag drags out the dimension of the segment under the pointer. A
|
||||
curved segment is measured from end to end. With Smart Guides on, both points also snap into line with other objects'
|
||||
anchors and centres, and the second onto the construction guides through the first; the guides
|
||||
show while hovering, before each click.
|
||||
show while hovering, before each click. VectorCraft's own rules decide where a point lands: an
|
||||
anchor within 8 pixels takes it first; a point on a guide stays on the guide where the pointer
|
||||
is, except that it moves onto a segment within the Smart Guides snapping tolerance, or onto the
|
||||
place where a construction guide crosses another object's alignment line within twice that
|
||||
tolerance; a point that no anchor, guide, grid or pixel snapping places lands on the closest
|
||||
point of a segment within 8 pixels.
|
||||
A linear dimension is aligned, horizontal or vertical, as the
|
||||
[linear dimensions help](https://helpx.adobe.com/illustrator/desktop/measure-and-align/plot-and-measure/plot-linear-dimensions-of-objects.html)
|
||||
describes: after the second click, clicking again places an aligned dimension, and moving the
|
||||
|
||||
@@ -180,7 +180,7 @@ VectorCraft choices; an original approximation, never compared with another appl
|
||||
|---|---|
|
||||
| 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), 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, and Quick Actions › Expand as Wireframes ([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; hard-edged shadows behind or below the object from the first light ([three-d.md](three-d.md#shadows)); the Materials tab's Graphics, document symbols mapped onto Extrude & Bevel's caps and onto a plane, moved with an artboard handle ([three-d.md](three-d.md#graphics)); no base materials, graphics on curved surfaces, soft shadows or ray tracing |
|
||||
| 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, and Quick Actions › Expand as Wireframes ([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; hard-edged shadows behind or below the object from the first light ([three-d.md](three-d.md#shadows)); the Materials tab's Graphics, document symbols mapped onto Extrude & Bevel's caps and onto a plane, moved with an artboard handle, and wrapped around Revolve's side ([three-d.md](three-d.md#graphics)); no base materials, graphics on Inflate or on Extrude & Bevel's walls and bevels, soft shadows or ray tracing |
|
||||
| 3D (Classic): Extrude & Bevel, Revolve, Rotate | Extrude & Bevel (Classic) initial: live, Extrude Depth, Cap, five original bevel shapes with Height and Bevel Extent In or Out, Position presets and rotation gizmo, Perspective, Wireframe, No Shading, Diffuse and Plastic surfaces with one to ten lights, Light Intensity, Ambient Light, Highlight Intensity and Size, Blend Steps, Black, Custom or no Shading Color, Draw Hidden Faces ([create 3D objects](https://helpx.adobe.com/illustrator/desktop/special-effects-styles/create-3d-graphics/create-3d-objects.html)); Revolve (Classic) initial: live, Angle, Cap, Offset from the left or right edge, Position presets and rotation gizmo, Perspective, the same four surfaces, lights, highlight, Blend Steps and Shading Color, groups and layers revolved about one shared axis (same page); Rotate (Classic) initial: live, every fill and stroke turned as one plane, Position presets and rotation gizmo, Perspective, No Shading and Diffuse surfaces with lights, Ambient Light, Blend Steps and Shading Color ([rotate objects in 3D](https://helpx.adobe.com/illustrator/desktop/special-effects-styles/create-3d-graphics/rotate-objects-in-3d.html)); Map Art: none |
|
||||
| Turntable (30.0 beta) | 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)) |
|
||||
|
||||
File diff suppressed because one or more lines are too long
+4
-3
@@ -541,7 +541,7 @@ macOS cursor delivery (#2292) is narrowed to a native host adapter using the exi
|
||||
Ease Out In), Ramp 0–100% and independent color Shift; easing is disabled without a spine.
|
||||
The original polynomial distributions approximate the public description. With the Selection or
|
||||
Blend tool, on-canvas widgets on a blend with a spine set the color Shift and, when the steps follow
|
||||
that spine, the Ramp; a blend made without a spine shows neither widget. The Blend panel shows the
|
||||
that spine, the Ramp; a blend made without a spine shows the color Shift widget alone. The Blend panel shows the
|
||||
values they set. [Public source](https://helpx.adobe.com/illustrator/desktop/manage-colors/apply-transparency-and-blending/blend-panel-overview.html).
|
||||
|
||||
- **Done:** gradient Dither (30.0): the Gradient panel's Dither box (`paint.editGradient` `dither`, also in `paint.setFill`'s
|
||||
@@ -684,8 +684,9 @@ macOS cursor delivery (#2292) is narrowed to a native host adapter using the exi
|
||||
- **Done:** custom document ruler origin (#1212): corner drag with preview, double-click reset to the active artboard, relative X/Y inputs and native save/reopen.
|
||||
- **Done:** View › Rulers › Change to Global / Artboard Rulers (`view.globalRulers`, Cmd+Alt+R): artboard rulers, a new document's, count from the active artboard, each artboard with its own zero point; rulers, X/Y fields and guide readouts follow the mode, which is saved with the document. Estimate unchanged.
|
||||
- **Done (#2849):** View › Rulers › Show Video Rulers (`view.videoRulers`): the rulers show and count the active artboard in video pixels from its top-left corner, a pixel as many points wide as the artboard's Video Ruler Pixel Aspect Ratio and one point tall ([public source](https://helpx.adobe.com/illustrator/desktop/create-manage-artboards/organize-manage-artboards/set-video-display-options-for-artboards.html)); Hide Video Rulers returns them to the General unit and the ruler origin. Shift-snapping a new guide to ruler ticks still uses the General unit's ticks. Estimate unchanged.
|
||||
- **Partial:** custom toolbars (#1759): Window › Toolbars › New Toolbar makes them, kept with the workspace they
|
||||
were made in, and Window › Toolbars › Manage Toolbars renames, copies and deletes them; docking them is missing.
|
||||
- **Done:** custom toolbars (#1759): Window › Toolbars › New Toolbar makes them, kept with the workspace they
|
||||
were made in, and Window › Toolbars › Manage Toolbars renames, copies and deletes them; they dock in lanes along
|
||||
the window's left and right edges (`window.toolbar.dock`, `window.toolbar.float`).
|
||||
Inside the estimate below.
|
||||
- **Done (#1753):** a saved workspace keeps the width of the dock column.
|
||||
- **Done (#4135):** floating panels open in OS windows of their own on the desktop, so they can sit on another monitor; on the web and on Wayland they float inside the window.
|
||||
|
||||
@@ -184,6 +184,47 @@ Tests on code-drawn images: `tests::a_blurred_edge_is_no_ring_of_a_tone_between_
|
||||
blurred into a 10 px ramp, 16 Colors), `tests::grayscale_settles_a_blurred_edge_between_its_own_two_grays`,
|
||||
`tests::grayscale_settles_a_tinted_blurred_edge_by_its_lightness`,
|
||||
`tests::the_photo_presets_keep_the_tones_of_a_blurred_edge` and `quantize::cut_edge::tests`.
|
||||
## Staircases in smooth areas
|
||||
Where a band border in a gradient or a shaded area runs at a slant, its pixels form a staircase whose
|
||||
steps are two or more pixels long. One piece of outline can run along a sharp edge in the image and then
|
||||
along such a border with no junction between them. That piece as a whole is not a contour (see above),
|
||||
and the outline kept a corner at every step. `subpixel::outline` now reads a run of three or more edges of
|
||||
1 to 8 px (`STAIR_MAX`), each turning one way where it starts and the other where it ends, with no
|
||||
junction on it, as a staircase when the run's own cracks pass `subpixel::low_contrast`. A run is cut at
|
||||
any step whose own cracks show half of the step between the two colors or more. The 8 px limit and the
|
||||
one-half cut are VectorCraft's own values. The run's edges are then steps, as one-pixel steps already
|
||||
were: the outline has no corner where two of them meet, and each gives one point, its middle, moved by the
|
||||
mean of its cracks' shifts. Where a run meets an edge that is not a step, the corner between them stays,
|
||||
so a straight edge longer than 8 px next to a staircase stays straight. A straight edge of 8 px or less
|
||||
between two turns of opposite sign is read as one more step of the run. Inside a run, two one-pixel steps
|
||||
between longer ones are read as part of the slope and do not make a notch. A staircase of longer steps,
|
||||
and one whose cracks read as an edge, keep their corners, and Black and White traces do not use the rule.
|
||||
The runs are the same from either side of the border.
|
||||
Measured with the harness below, before and after the change: rows of the "flat colour art" inputs do not
|
||||
change. On gradient and photo inputs, anchors change in 106 rows, 101 of them fewer, by −64% to +6.4%: for
|
||||
example 390 to 142 (Shades of Gray, linear gradients), 1,860 to 1,537 (High Fidelity Photo, linear
|
||||
gradients), 6,766 to 6,542 (High Fidelity Photo, gradient and photo) and 47 to 50 (High Fidelity Photo with
|
||||
Gradients, blurred). On gradient and photo, 6 Colors, 6 Colors with Shapes, with Auto Grouping, without
|
||||
Gradients and enhanced each leave a gap of 0.9 px (was 1.2) and an overlap of 1.0 px (was 0.8). Edge ΔE
|
||||
of Shades of Gray on linear gradients goes from 8.36 to 8.40 (8.39 enhanced), and that of 6 Colors with
|
||||
Gradients on a blurred input from 2.24 to 2.22; other ΔE and edge ΔE values change by 0.01 or less.
|
||||
Lines % changes by −2 to +3, grouped % by −1 to +4, upright % by +1 in 3 rows (Shades of Gray on a blurred
|
||||
input), and specks do not change. On synthetic photos of 800 and 4,000 px traced outside this harness,
|
||||
the corners of rectilinear staircases per 100 px of outline fall from 0.57 to 0.46 and from 1.09 to 0.94
|
||||
with High Fidelity Photo. On the 800 px photo, the 95th percentile of the pixel difference with High
|
||||
Fidelity Photo rises from 6.33 to 6.67, and 16 Colors leaves 2 staircases of steps of 2 px or more where
|
||||
it left none. The tables below are the previous measurement, not a rerun.
|
||||
Tests on code-drawn outlines in `subpixel::tests`:
|
||||
`a_staircase_of_longer_steps_in_a_smooth_area_becomes_the_slope_through_its_steps` (a piece with a
|
||||
staircase of 2 × 3 px steps in a smooth area, a straight run and the same staircase on a sharp edge: the
|
||||
first gives its steps' middles and none of its corners, the straight run keeps the corners at its ends, the
|
||||
second staircase keeps its corners, both regions get the same points, and 10 px steps keep their corners
|
||||
in a smooth area), `a_staircase_that_runs_on_from_a_smooth_area_into_an_edge_keeps_the_edges_corners`,
|
||||
`a_staircase_whose_cracks_do_not_read_as_a_contour_keeps_its_corners` (two flat colors),
|
||||
`a_staircase_step_moves_by_the_mean_shift_of_its_cracks`,
|
||||
`a_staircase_of_mixed_one_pixel_and_longer_steps_is_one_slope_without_a_notch`,
|
||||
`a_run_of_two_steps_keeps_its_corners`, `a_junction_on_a_step_ends_the_staircase_there` and
|
||||
`a_step_whose_cracks_read_as_an_edge_ends_the_staircase_there`.
|
||||
## A simpler contour walk
|
||||
`contour::trace_mask` follows each region's outline along the pixel cracks with the inside on the
|
||||
right. It used to build a table of outgoing directions for every pixel corner in a raster pass and
|
||||
|
||||
@@ -25,6 +25,13 @@ Hindi integer counts use the first plural form for 0 and 1 and the second for 2+
|
||||
Both `@plural` and `@msgplural` rows have two forms. The latter translate status messages when
|
||||
displayed; the engine, control channel and MCP continue to return English messages.
|
||||
|
||||
In diagnostics, "a number of points" is a numeric value in the point unit: write संख्या and
|
||||
पॉइंट, never कई अंक ("many digits"). Keep every bound and alternative the English lists, and
|
||||
every clause such as "all" or "what follows it". Type as a text object is टाइप (एरिया टाइप,
|
||||
पॉइंट टाइप), not प्रकार, which stays for a kind. `hindi_rows_use_the_glossary_term_for_what_their_english_names`
|
||||
in `crates/ui-egui/src/i18n/tests.rs` checks the save, swatch, crop, resolution and path terms
|
||||
and the point unit in every row.
|
||||
|
||||
## Terminology
|
||||
|
||||
| English | Hindi |
|
||||
@@ -42,6 +49,7 @@ displayed; the engine, control channel and MCP continue to return English messag
|
||||
| Fill / Stroke | फ़िल / स्ट्रोक |
|
||||
| Gradient / Mesh / Blend | ग्रेडिएंट / मेश / ब्लेंड |
|
||||
| Pattern / Swatch | पैटर्न / स्वॉच |
|
||||
| Type (text object) / Crop / Resolution | टाइप / क्रॉप / रिज़ॉल्यूशन |
|
||||
| Appearance / Graphic style | अपीयरेंस / ग्राफ़िक स्टाइल |
|
||||
| Symbol / Envelope | सिंबल / एन्वेलप |
|
||||
| Clipping mask / Opacity mask | क्लिपिंग मास्क / ओपेसिटी मास्क |
|
||||
@@ -61,6 +69,10 @@ The draft has 7,877 unique rows, including 2,537 `@msg`, 45 `@msgplural` and 38
|
||||
Its source set combines the sibling catalogs with the current test scanner's UI/undo and error
|
||||
message dumps, so it includes runtime labels outside the literal scanner. Row count is not a
|
||||
percentage of the application's entire interface.
|
||||
On 2026-11-13 the catalog has 8,732 rows, including 3,003 `@msg`, 47 `@msgplural` and 41
|
||||
`@plural` rows. A wording pass on that date corrected 193 rows outside the plug-in
|
||||
messages for meaning, dropped clauses, English left in place and the save, swatch, crop,
|
||||
resolution, path and type terms. It is not a native proofread.
|
||||
|
||||
The comparison covers release `v0.21.1` (`f6aa4309`) and current `main` (`3c7d9e1f`). Their
|
||||
non-English catalogs have no missing Hindi keys except the names deliberately kept in English.
|
||||
|
||||
@@ -29,7 +29,7 @@ Chinese by `imachus`). Only Georgian is recorded as reviewed by a native speaker
|
||||
| English | `en` | source, 100% | all | Latin | — | full | — |
|
||||
| Simplified Chinese (Mandarin) | `zh-hans` | 5,102 rows, 791 of them `@msg` (counted 2026-10-21): menus, `tl!` literals and messages complete when counted | all | CJK UI font from craft-fonts (BIZ UDPGothic) when embedded, else a system font; IME with marked text at the caret; vertical type partial ([type-parity.md](type-parity.md)) | no | full | — (review) |
|
||||
| Spanish | `es` | 4,009 / 4,020 (99.7%) | all (604 messages) | Latin | no | full | — (review) |
|
||||
| Hindi | `hi` | 7,877 rows (2026-11-06): 2,537 `@msg`, 45 `@msgplural`, 38 `@plural`; no gaps in the untranslated report | menus, dialogs, tooltips and scanned messages; contributor-approved loanword terminology; agent wording pass | UI and document text shape with HarfRust; installed desktop Devanagari fallback, or a `Deva` craft-fonts face; web font still needed | contributor terminology review; wider proofread welcome | complete catalog, machine-assisted draft | native review, layout and web font |
|
||||
| Hindi | `hi` | 8,732 rows (2026-11-13): 3,003 `@msg`, 47 `@msgplural`, 41 `@plural`; no gaps in the untranslated report | menus, dialogs, tooltips and scanned messages; contributor-approved loanword terminology; agent wording pass | UI and document text shape with HarfRust; installed desktop Devanagari fallback, or a `Deva` craft-fonts face; web font still needed | contributor terminology review; 2026-11-13 wording pass on messages and longer labels, with a glossary-term test; wider proofread welcome | complete catalog, machine-assisted draft | native review, layout and web font |
|
||||
| Arabic | `ar` | 0 | none | document text: bidi layout and Paragraph Direction; interface: no right-to-left layout, no Arabic shaping in egui | no | none | 25–40 |
|
||||
| French | `fr` | 4,020 / 4,020 (100%) | all | Latin | no | full | — (review) |
|
||||
| Portuguese | `pt-br` | 6,106 catalog entries (counted 2026-10-31 on `main` at `d26dd933a`): menus, `tl!` literals and messages complete when counted; one/other plurals | all | Latin | contributor is a Brazilian Portuguese speaker; further native review welcome | full | — (review) |
|
||||
|
||||
+280
-60
@@ -1,6 +1,6 @@
|
||||
# VectorCraft MCP server
|
||||
|
||||
> **Last updated:** 2026-11-11 · **Change:** Save location-refusal error (#6146); existing response shapes retained.
|
||||
> **Last updated:** 2026-11-13 · **Change:** Envelopes: a top object's side whose pieces are all one curve split at anchors follows that curve's parameter (#7097); existing response shapes retained. Previously: Save location-refusal error (#6146); existing response shapes retained.
|
||||
|
||||
`vectorcraft-cli mcp` runs a [Model Context Protocol](https://modelcontextprotocol.io) server on stdio
|
||||
(newline-delimited JSON-RPC 2.0; see [Protocol](#protocol) for version negotiation). Agents use it to
|
||||
@@ -630,7 +630,7 @@ sampler.
|
||||
| `answer_dialog` | `{set?: [{field, value?}], action?}` | Remote only. Sets fields of the app's open dialog in the order given with one `ui.dialog.set {fields, action?}` (a missing `value` is `null`). The app stores all of them or none, then answers that same dialog with `action` in the same request: `confirm` (OK) or `cancel`. Another connection cannot open a dialog between the two steps. When the app refuses the `ui.dialog.set`, for example because no dialog is open, the call is an error and the dialog is not confirmed or canceled. `set` cannot change a `__` field other than the dialog's controls held under a `__` name (such as Save PDF's `__section` or the Preferences `__search`): the `__command` and `__params` of a `confirm` or `command` dialog, and every other `__` field that holds what OK acts on, are refused with "the `<kind>` dialog cannot set protected field `<field>`", so OK runs what the dialog was opened for. `action` alone is sent as `ui.dialog.confirm` or `ui.dialog.cancel`. Give `set`, `action` or both; `set` holds at most 256 fields. `inspect_ui` shows the open dialog and its fields as `ui.dialog`. Returns `{dialog, result}`: the dialog after the fields were set (or `null`) and the reply to `confirm` or `cancel` (or `null`). After `invoke_menu` `app.quit`, `file.close` or `file.closeAll` replies `{"pending": "saveChanges"}`, `{action: "confirm"}` saves, `{set: [{field: "discard", value: true}], action: "confirm"}` closes without saving and `{action: "cancel"}` cancels the close or quit. |
|
||||
| `invoke_menu` | `{command, params?}` | Invokes a menu item by command id. UI commands such as `view.*` and `window.*` are in `command_list` with `ui: true`; running them needs the desktop app (`--connect`). |
|
||||
| `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`. |
|
||||
| `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`. An app that does not send the image back writes a window capture without `path` to a file in a new folder inside the system's temporary folder (on Unix only the user can open it); the server reads the file and then removes the folder, also when the capture or the read fails. |
|
||||
| `open_file` | `{path, importer?, params?}` | Opens any readable file as a new active document: `.vectorcraft`/`.drawcraft`, `.vctemplate`, `.svg`/`.svgz`, `.pdf`/`.ai`, `.ait`, `.eps`/`.epsf`, `.ps`, `.dxf`, `.emf`, `.wmf`, PICT (`.pct`/`.pic`/`.pict`, and a version 2 picture of any extension), HP-GL (`.plt`/`.hpgl`/`.hgl`/`.hpg`, and a file of an extension no other format reads that starts with plotter instructions), 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`), JPEG XL (`.jxl`), PSD (`.psd`/`.pdd`)/PSB (an image opens as a document of its pixel size; a PSD or PSB file with its layers as layers, or as its merged image through `run_command document.open` with `layers: false`; a JPEG XL file as its first frame). 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). A file of an extension only an installed importer plug-in lists opens with that importer ([Plug-ins](#plug-ins)); `importer: "plugin.<id>"` opens the file with the importer it names, which must list the file's extension, also one a built-in format reads (in the app, as File › Open With does), and `params` gives that importer's parameters (their defaults when omitted). `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; `.eps`: by default one file whose bounding box fits the visible art, the first artboard when no art shows; `options.useArtboards: true` makes the chosen artboard the page and, with two or more chosen, the file at the path is the central file of the visible art and each artboard is also written to `<name>_<artboard>.eps` beside it, listed in the reply's `files`). 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. A key in `options` that no save format takes is an error, and nothing is written (see Parameter keys). 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. Location refusals return `READ_ONLY_LOCATION: <reason>` without a fallback panel for automation; see [Save location errors](#save-location-errors). |
|
||||
| `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`, `hpgl` (a `.plt` plot file for plotters and cutters), `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, WMF and HP-GL 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. |
|
||||
@@ -640,7 +640,7 @@ sampler.
|
||||
| `transform` | `{ids?, dx?, dy?, rotate?, scale?, scaleX?, scaleY?, reflect?, shear?, origin?, copy?}` | Runs move, rotate, scale, reflect, shear in that order. `rotate` is in degrees counter-clockwise; a positive `shear` moves the top to the right. With `copy`, the first step duplicates. |
|
||||
| `create_graph` | `{type?, x, y, width, height, csv? \| series?, categories?, rows?}` | The nine Illustrator graph types: column, stacked column, bar, stacked bar, line, area, scatter, pie and radar. An empty CSV cell or a `null` in `rows` is a blank value; a number in straight quotes is a label. Edit later with `graph.setData` / `graph.setType` via `run_command`. `graph.column {design, columnType: vertical\|uniform\|repeating\|sliding, each, fractions: chop\|scale}` draws the columns or bars of the series picked with Group Selection (or `seriesIndexes`, or all of them) with a graph design saved by `graph.design`; with no `design` it returns the series' current design and options. Type in the design that holds a `%` followed by two digits shows each column's value, with at least the first digit's places before the decimal point and the second digit's places after it. |
|
||||
| `text_wrap` | `{ids?, offset?, invert?, release?}` | Area type below the objects (same layer) flows around them. |
|
||||
| `undo` / `redo` | `{}` | Many calls that change nothing record no undo step, for example `object.align` with nothing to move, `object.move` by 0 without `copy` and `object.showAll` with nothing hidden. `undo` (`edit.undo`) after such a call undoes the step before it. `inspect_document` lists the undo steps as `history`. `run_command` with `edit.clearHistory` removes every undo and redo step of the active document and returns `{cleared}`, the number of steps removed; the document stays as it is, and the command records no undo step. `run_command` with `edit.newDocumentFromState` and `{index?, created?}` makes a new document holding the art as it was at that state and makes it the active document, and returns `{index, title}`. `index` is a row of the History panel, with 0 the oldest state kept, and an omitted `index` uses the current state. An `index` that names no state is an error and changes nothing. `created` is File Info's created date in Unix seconds or null, and defaults to now. The new document takes the next `Untitled-N` name, is marked unsaved, has nothing selected and has no steps to undo or redo. It is out of symbol, opacity-mask and pattern editing, and the art drawn in a pattern's tile is stored in the pattern, as `object.pattern.done` stores it. The source document and its steps stay as they are, except that typing or a drag in progress is first kept as a step. While the Type tool edits type, `undo` and `redo` put its caret, with no characters selected, at the end of the text the step changed: after the text it puts back or retypes, or where the text it takes out was. A step that changes no characters, such as a formatting change, leaves the caret and the selection where they are. |
|
||||
| `undo` / `redo` | `{}` | Many calls that change nothing record no undo step, for example `object.align` with nothing to move, `object.move` by 0 without `copy` and `object.showAll` with nothing hidden. `undo` (`edit.undo`) after such a call undoes the step before it. `inspect_document` lists the undo steps as `history`. `run_command` with `edit.clearHistory` removes every undo and redo step of the active document and returns `{cleared}`, the number of steps removed; the document stays as it is, and the command records no undo step. `run_command` with `edit.newDocumentFromState` and `{index?, created?}` makes a new document holding the art as it was at that state and makes it the active document, and returns `{index, title}`. `index` is a row of the History panel, with 0 the oldest state kept, and an omitted `index` uses the current state. An `index` that names no state is an error and changes nothing. `created` is File Info's created date in Unix seconds or null, and defaults to now. The new document takes the next `Untitled-N` name, is marked unsaved, has nothing selected and has no steps to undo or redo. It is out of symbol, opacity-mask and pattern editing, and the art drawn in a pattern's tile is stored in the pattern, as `object.pattern.done` stores it. The source document and its steps stay as they are, except that typing or a drag in progress is first kept as a step. When a command keeps a drag whose preview Real-time Drawing off had not applied yet (`edit.undo`, `edit.redo`, `edit.clearHistory`, `edit.newDocumentFromState` and the other commands that end a drag first), and applying that preview gives a warning, the command's result carries it as `previewWarning`, and as `warning` too when the command gives no warning of its own; the app's status bar shows `warning`. While the Type tool edits type, `undo` and `redo` put its caret, with no characters selected, at the end of the text the step changed: after the text it puts back or retypes, or where the text it takes out was. A step that changes no characters, such as a formatting change, leaves the caret and the selection where they are. |
|
||||
|
||||
For example, create editable Japanese area type with the engine's vertical writing mode:
|
||||
|
||||
@@ -758,9 +758,31 @@ designs keep their own paint. A row that had no
|
||||
paint before the command and has none after it does not change the paint 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.
|
||||
not store a series' paint.
|
||||
|
||||
`appearance.addFill`, `appearance.addStroke`, `appearance.setItem`, `appearance.removeItem`,
|
||||
`appearance.duplicateItem`, `appearance.moveItem`, `appearance.clear`, `appearance.reduceToBasic`,
|
||||
`appearance.showAllHidden`, `appearance.transfer` (as its `target`), `graphicStyle.apply`, and `transparency.set` with a
|
||||
fill or stroke `item`, given a series group's id or the selected series group, edit the paths directly in the group as
|
||||
if each had been given, and the group keeps no rows of its own. A series group with no path directly in it, for example
|
||||
one drawn with a column design, and a series group that has a fill or stroke row of its own, as a document saved by an
|
||||
earlier version can hold, are edited themselves by these commands, and `appearance.moveItem` with `from: "contents"`
|
||||
moves the group's own Contents row. `appearance.clear`, `appearance.reduceToBasic`, `appearance.showAllHidden` and
|
||||
`graphicStyle.breakLink` edit the group as well as its paths. `graphicStyle.apply` without `add` and
|
||||
`appearance.transfer` onto the group clear the group's own effects, opacity, blend mode, isolation, knockout and style
|
||||
link, and `graphicStyle.apply` with `add` unlinks the group. With `appearance.transfer`, a `source` that is one of the
|
||||
target group's paths keeps its look on a move, and a `source` that is the group's only path is an error.
|
||||
`graphicStyle.redefine` gives the style to the paths directly in a series group linked to it, whether or not the group
|
||||
has rows of its own, links them, and clears and unlinks the group; the source and the paths linked to the style whose
|
||||
look was edited keep their look. Read as a source, by `graphicStyle.new`, `graphicStyle.redefine` or
|
||||
`appearance.transfer`, a series group that has no fill, stroke, effect, opacity, blend mode, isolation, knockout or
|
||||
style link of its own gives the look and the style link of the topmost path directly in it, and a move with
|
||||
`appearance.transfer` clears each of those paths; a series group that has one of them is read itself.
|
||||
|
||||
The other commands given a series group's id edit the group itself, and the graph does not store what they set on it:
|
||||
`transparency.set` and `object.setProps` with an opacity or blend mode for the object, the `effect.*` commands and
|
||||
`appearance.addEffect`, and the paint, stroke and gradient commands with a fill or stroke `item`, which is a row of the
|
||||
group's own stack. The Appearance panel and `appearance.setActiveItem` read the selected group's own rows.
|
||||
|
||||
`text.setFormat` without `start` and `end`, on a graph or on its labels, stores the character and paragraph attributes
|
||||
it sets for each kind of label it reaches (value axis numbers, category labels, legend labels), and every label of that
|
||||
@@ -969,7 +991,11 @@ SVG writes one file per artboard of a `range`); `useArtboards: false` exports th
|
||||
its effects paint, the effects of groups, type and images included. `artboard.fitToArt` measures the art the same
|
||||
way. `document.exportPdf {useArtboards: false}` writes that one page as well, and ignores `artboard`, `artboards` and
|
||||
`range`. A PDF of that page, from either command, carries no Preserve Editing data; when Preserve Editing is on (as it
|
||||
is in VectorCraft Default), the export comes back with a warning that says so.
|
||||
is in VectorCraft Default), the export comes back with a warning that says so. A `.ai` export with
|
||||
`useArtboards: false` writes that one page too, without the native document and without the editing copy for other
|
||||
apps (`editingData`), and always comes back with the warning `Preserve editing was left out: an .ai file of the art's
|
||||
bounds would replace the document's artboards when reopened`; with `pdfCompatible: false` it is refused, whatever
|
||||
`editingData` says. A legacy version 7 `.ai` (`aiVersion: "7"`) of the art's bounds is written as before.
|
||||
Export As PDF continues in the Save PDF dialog with Use Artboards on or off; with it off, the dialog has no
|
||||
Artboards section and the page is the bounds of the visible art.
|
||||
|
||||
@@ -1036,7 +1062,8 @@ and `flattener` options over it (as `object.flattenTransparency` takes them); im
|
||||
transparency and rasterized areas are clipped to their regions. Layers the file leaves out (non-printing ones, unless
|
||||
`includeNonPrinting` or `createLayers` is set) are left out of the flattening. A file that would still have transparency fails the
|
||||
export. PDF/X-1a and PDF/X-3 files are PDF 1.3 files too.
|
||||
A page with a side longer than 14,400 pt is written with a `UserUnit` (PDF 1.6): its longer side divided by 14,400,
|
||||
In PDF/A-2b files, `.ai` saves and files written with `longPagesInPoints: false`, a page with a side longer than
|
||||
14,400 pt is written with a `UserUnit` (PDF 1.6): its longer side divided by 14,400,
|
||||
rounded up to the next thousandth, with the page's sizes and coordinates in those units, so that no side is longer than
|
||||
14,400 units (ISO 32000-1, Annex C.2). A PDF 1.5 file with such a page is written as PDF 1.6, with a warning, and
|
||||
keeps PDF 1.5's encryption (128-bit RC4). A PDF/A-2b file at PDF 1.4 with such a page is written as PDF 1.6 too, with a
|
||||
@@ -1045,9 +1072,10 @@ unless the page is too narrow for that (below)
|
||||
([veraPDF rule 6.1.13-11](https://github.com/veraPDF/veraPDF-validation-profiles/wiki/PDFA-Parts-2-and-3-rules#rule-6113-11);
|
||||
PDF/A-2 files may declare PDF 1.0 to 1.7, [rule 6.1.2-1](https://github.com/veraPDF/veraPDF-validation-profiles/wiki/PDFA-Parts-2-and-3-rules#rule-612-1)).
|
||||
PDF/X files and other PDF 1.3 and 1.4 files write such a page in points, and apps
|
||||
that keep to the limit cut it to 200 in. `longPagesInPoints: true` (off by default; "Write pages longer than 200 in at
|
||||
that keep to the limit cut it to 200 in. `longPagesInPoints` (on by default; "Write pages longer than 200 in at
|
||||
full size in points" in the Save PDF dialog's General section) writes such a page in points at every PDF version, without
|
||||
a `UserUnit`, and a PDF 1.5 file stays PDF 1.5; the warning then says the page is written in points. The option applies
|
||||
a `UserUnit`, and a PDF 1.5 file stays PDF 1.5; the warning then says the page is written in points. Readers that
|
||||
ignore `UserUnit` show such a page at its full size. The option applies
|
||||
only to files without a standard: PDF/X files write such a page in points anyway, and PDF/A files keep the `UserUnit`, which
|
||||
keeps their page boundaries within PDF/A-2's limit of 14,400 units (ISO 19005-2, 6.1.13), a PDF/A file at PDF 1.4
|
||||
included (written as PDF 1.6). The dialog disables the
|
||||
@@ -1434,8 +1462,10 @@ preferences (the folder the desktop app uses, so both see the same ones; `VECTOR
|
||||
start, after the profiles above are registered (#6335). Saved settings that name a profile that is no longer
|
||||
there, or a damaged file, leave the defaults (logged), and the next change writes over the file.
|
||||
`edit.assignProfile` tags the document only: colors show and convert through the profiles it assigns, and the
|
||||
working spaces and the file stay as they are. The `workingCmyk` target of `view.proofSetup` simulates the working
|
||||
CMYK space in such a document too.
|
||||
working spaces and the file stay as they are. The profiles in use are those of the document in front, after
|
||||
`file.new`, `document.open`, `document.activate`, `file.close`, `file.revert`, `edit.undo`, `edit.redo` and a
|
||||
failed `command.batch` too; with none assigned, or no document open, the working spaces are. The `workingCmyk`
|
||||
target of `view.proofSetup` simulates the working CMYK space in such a document too.
|
||||
|
||||
Not remembered: the document, anything else. Nothing is read or written when
|
||||
`VECTORCRAFT_NO_PREFS` is set, and a server confined with `--automation-read-root` or
|
||||
@@ -1777,7 +1807,7 @@ vectorcraft-cli run --cmd file.new --params '{"width":600,"height":200}' --cmd
|
||||
### Parameter schemas
|
||||
|
||||
Some commands have a machine-readable parameter schema: at present a small set including `view.capsLock`, `view.saved.new`,
|
||||
`view.saved.edit`, `view.saved.list`, `view.transparencyGrid`, `view.snapToGlyph.options` and `engine.apiReference`
|
||||
`view.saved.edit`, `view.saved.list`, `view.transparencyGrid`, `view.snapToGlyph.options`, `view.snapToPixel.options` and `engine.apiReference`
|
||||
(most of the catalogue still documents params in prose only; schemas grow command by command). The engine's
|
||||
`engine.commands` list gives such a command a `schema` field: an object schema in the shape of JSON Schema 2020-12
|
||||
(https://json-schema.org/draft/2020-12). Its root has `$schema` (the 2020-12 dialect), `description` when the
|
||||
@@ -1830,9 +1860,10 @@ as the English gives them.
|
||||
|
||||
An omitted value with a `default` takes it (`rotation` 0 in `view.saved.new`); the journal keeps the params as they
|
||||
were given. Saved steps played from a journal or an action keep a key the schema does not name, unless its value nests
|
||||
more than 16 levels deep, and the values of the parameters it names are checked as in a new call. The schemas of built-in commands belong to API level 3
|
||||
more than 16 levels deep, and the values of the parameters it names are checked as in a new call. The schemas of built-in commands belong to API level 4
|
||||
(`vectorcraft_engine::schemas::API_VERSION`); a change to any of them raises the level. Level 2 added
|
||||
`engine.apiReference`; level 3 says that `rotation` in `view.saved.new` and `view.saved.list` turns clockwise. Commands that plug-ins add have no schema here.
|
||||
`engine.apiReference`; level 3 says that `rotation` in `view.saved.new` and `view.saved.list` turns clockwise; level 4
|
||||
adds `view.snapToPixel.options`. Commands that plug-ins add have no schema here.
|
||||
|
||||
`engine.apiReference {}` → `{markdown}` returns the command API reference, written from these schemas each time it
|
||||
runs; no file of it is kept. It needs no open document and changes nothing. The reference has a `##` section for each
|
||||
@@ -1947,8 +1978,10 @@ app through the global object `vc`, and writes to the Script Console and runs ot
|
||||
file). Its preprocessor lines are read as the script's are. `timeout` is a number of milliseconds from 0; the file
|
||||
is read at once and `timeout` is not waited on. The run's fuel and limits apply to the file. An empty path, a
|
||||
missing file and a refused path throw errors the script can catch.
|
||||
- `$.fileName` is the file being run, which is the file `$.evalFile` is running while it runs, and is empty for a
|
||||
script given as `source`. `$.includePath` is the current `#includepath` list, separated by `;`. `$.engineName` is
|
||||
- `$.fileName` is the file of the code that reads it: the script, a file it included with `#include`, or a file
|
||||
`$.evalFile` ran, also when a function that file defined is called after `$.evalFile` returned. It is empty in code
|
||||
from a script given as `source`. In code that `eval` or `Function` compiled it is the file being run, which is the
|
||||
file `$.evalFile` is running while it runs. `$.includePath` is the current `#includepath` list, separated by `;`. `$.engineName` is
|
||||
the name `#targetengine` gave the engine the script runs in (`VectorCraft` without the line) and is read-only.
|
||||
- `alert(message[, title, errorIcon])`, `confirm(message[, noAsDflt, title])` and `prompt(message, preset[, title])`
|
||||
open a dialog, described below. `vc.api.has("dialogs")` is true.
|
||||
@@ -2018,7 +2051,7 @@ VectorCraft's own, and `vc.api.has("dollar")` is true where they are available:
|
||||
| `global` | the global object |
|
||||
| `hiresTimer` | the microseconds since the run last read it, or since the run started; `0` on the web |
|
||||
| `level`, `memCache` | `0`; setting `memCache` throws |
|
||||
| `line`, `stack` | the line of the code that reads it; the running code, outermost first, one a line as `name:line` (`[global]` for the script's own code, `[anonymous]` for a function without a name), at most 64 lines |
|
||||
| `line`, `stack` | the line of the code that reads it, counted in the file that code is in (the script, a file it included or a file `$.evalFile` ran, in this run or an earlier run of its named engine); the running code, outermost first, one a line as `name@file:line` (`[global]` for the script's own code, `[anonymous]` for a function without a name; the file as `$.fileName` gives it, or the run's name for a script given as `source`), at most 64 lines. Code that `eval` or `Function` compiled keeps the line of the source they compiled, in the file `[eval]`; code whose place a named engine no longer keeps is at line `0` of `[unknown]` |
|
||||
| `locale` | the interface's language as a locale such as `de` or `pt_BR` (`en` when the interface follows the system); a script can set `ll` or `ll_RR`, and `null` or `""` sets the interface's again |
|
||||
| `localize` | `false`; while `true`, `String(object)` of a localization object gives its text for `$.locale` |
|
||||
| `os` | `Windows`, `macOS`, `Linux`, `FreeBSD`, `Unix` or `Web`, without a version |
|
||||
@@ -2092,6 +2125,9 @@ no engines, and the engines it left are dropped when their own thread next uses
|
||||
for 8 MiB of source maps, the oldest going first, and a run whose script does not compile keeps none. An error in
|
||||
code whose place is gone, or in code that `eval` or `Function` compiled, is reported without a line and column, and
|
||||
the code still runs.
|
||||
- `$.fileName` in code an earlier run compiled names the file that code is in, by the same places: the earlier run's
|
||||
script, a file it included or a file its `$.evalFile` ran, not the calling run's file. It is empty in code from an
|
||||
earlier script given as `source`, even when that run had a name, and in code whose place is gone.
|
||||
- `vc`, `$`, `alert`, `confirm` and `prompt` act for the run that calls them, including a copy an earlier run kept in a
|
||||
global. `vc.args` is the calling run's `args`, through a `vc` object an earlier run kept too. An engine
|
||||
holds no document: `vc.document` is a copy, read when it is called. What a run sets on `$` (`$.locale`,
|
||||
@@ -2473,8 +2509,8 @@ them again with the key object. When the call changes nothing, it records no und
|
||||
Other `object.setProps` calls leave the selection unchanged.
|
||||
|
||||
`object.unlockAll` and `object.showAll` unlock or show every locked or hidden object in the document and select
|
||||
them → `{count}`. In isolation mode they take only the objects inside the isolated object. With `scope: "group"` they
|
||||
take only the objects inside the groups that hold the selected objects:
|
||||
them → `{count}`. Ruler guides locked or hidden on their own are counted, and are selected as guides. In isolation
|
||||
mode they take only the objects inside the isolated object. With `scope: "group"` they take only the objects inside the groups that hold the selected objects:
|
||||
for each selected object, the group nearest above it, or the object itself when it is a group. The objects of a
|
||||
group inside another such group are counted once. With no selected object in a group, the call returns the error
|
||||
"nothing selected is in a group" and changes nothing. `scope: "document"` is the default, and any other value is
|
||||
@@ -2672,6 +2708,43 @@ kept with the workspace, and built-in workspaces and workspaces saved without it
|
||||
{"name":"invoke_menu","arguments":{"command":"window.toolsBesideCanvas","params":{"on":true}}}
|
||||
```
|
||||
|
||||
## Docking toolbars made with New Toolbar
|
||||
|
||||
A toolbar made with New Toolbar floats when it is made. `window.toolbar.dock {name, side?, order?}` (Dock to Left and
|
||||
Dock to Right in the context menu of the toolbar's title bar, remote mode, `invoke_menu`) docks it in a lane along the
|
||||
window's left or right edge. On the left, the lane is right of the Tools panel when the Tools panel is docked at the
|
||||
window's edge. With Keep Tools Beside the Canvas on and the Tools panel docked on the left, the lane is right of the
|
||||
Tools panel beside the canvas, and dropping a title bar on the Tools panel or on the lane docks the toolbar there. `side` is `left` or `right` (`start` and `end` also work); without it, the toolbar docks at the edge it
|
||||
docked at last, or at the left the first time. Toolbars docked at one edge stack from the top. `order` is the
|
||||
toolbar's place in that stack, 0 at the top, from 0 to the number of other toolbars docked there; without it, the
|
||||
toolbar goes at the end, or stays where it is when it is already docked at that edge. Each toolbar takes an equal
|
||||
share of the lane's height and its tools scroll in it, and the lane is as wide as its widest toolbar. When the lane
|
||||
is too short to give each toolbar 88 points of height, the stack wraps into more columns, left to right, and the lane
|
||||
widens, so no toolbar covers another. A lane takes at most half the width the canvas and panels would have (beside
|
||||
the canvas, it also leaves the canvas at least 200 points, and the canvas keeps room for one column); when that
|
||||
many columns still give a toolbar less than 88 points, the toolbars in those columns show only their title bars, which
|
||||
still float, dock and show the context menu. A column too short for all of its title bars shows as many as fit, and
|
||||
the mouse wheel over the column scrolls through the others, one toolbar per notch.
|
||||
`window.toolbar.float {name, x?, y?}` (Float Toolbar in the same menu) floats it with its top-left corner at `x`, `y`
|
||||
in screen points, or where it floated last when both are omitted. Both commands answer
|
||||
`{toolbar, floating, side, order, pos}`: `side` is the edge the toolbar docks at (while it floats, the edge it docked
|
||||
at last), `order` its place in that edge's stack (null while it floats) and `pos` where it floats (while it is docked,
|
||||
where it floated last). A missing or unknown name, a `side` other than left or right, an `order` that is not a whole
|
||||
number in range, or only one of `x` and `y` is an error and changes nothing. `window.toolbar.list` reports `floating`,
|
||||
`side` and `order` for each toolbar.
|
||||
|
||||
With the pointer, dropping a floating toolbar's title bar on the window's left or right edge, or on that edge's lane,
|
||||
docks it at the end of that edge's stack; the target lights up while the title bar is dragged over it. Dragging a
|
||||
docked toolbar's title bar out of its lane floats it under the pointer. Escape, or the window losing focus, during
|
||||
the drag puts the toolbar back where it was. Hiding a docked toolbar keeps its place, renaming it keeps its place, a
|
||||
copy made with Manage Toolbars' + floats, and deleting one closes up the stack. Placement is kept with the workspace.
|
||||
Toolbars saved before docking existed load floating. The lanes, the edge targets and the stacking are VectorCraft's
|
||||
own layout rules.
|
||||
|
||||
```json
|
||||
{"name":"invoke_menu","arguments":{"command":"window.toolbar.dock","params":{"name":"Toolbar 1","side":"left","order":0}}}
|
||||
```
|
||||
|
||||
## Learn panel
|
||||
|
||||
Window › Learn and the Explore tutorials button beside the search icon at the right end of the app bar show and hide
|
||||
@@ -2683,13 +2756,34 @@ toggles it (`show` omitted or null), and answers whether it shows; Window › Le
|
||||
The panel counts as hidden while the dock is hidden or a full screen mode hides the panels. Showing it shows a hidden
|
||||
dock; in a full screen mode it makes Learn the front panel, which shows when the mode ends, and answers false. Any
|
||||
other value of `show` is an error and changes nothing. `learn.list {}` → `{skills: [{id, title, tutorials: [{id, title, steps}]}]}`, in the order the Skills tab
|
||||
lists them, where `steps` is the number of steps. `learn.show {tutorial}` shows the panel on its Skills tab with that
|
||||
lists them, where `steps` is the number of steps. `learn.skills {}` shows the panel on its Skills tab with the list of
|
||||
skills, with no skill and no tutorial open, as the Quick skill guide card and Back to skills do, and answers what
|
||||
`learn.list` answers. `learn.show {tutorial}` shows the panel on its Skills tab with that
|
||||
tutorial's steps → `{skill, tutorial, title, steps: [text]}`. A missing, non-string or unknown `tutorial` is an error
|
||||
and changes nothing. Behavior reference:
|
||||
and changes nothing.
|
||||
|
||||
Under a tutorial's steps, View more opens the tutorial's practice sample, a small drawing of VectorCraft's own with the
|
||||
art its steps work on, as a new untitled document that becomes the active one; Save asks where to save it. Once the
|
||||
sample is open, Finish tutorial marks the tutorial finished. A finished tutorial shows Next Up with the title of the
|
||||
next tutorial in the same skill, which Next Up shows without opening its sample. A skill's last tutorial, finished,
|
||||
says so and shows Back to skills instead; Next Up never moves to another skill. Which tutorials are finished is kept
|
||||
while the app runs, and the skill rings and counts do not show it yet. These are VectorCraft's own rules; the help
|
||||
page also plays a short video, which VectorCraft does not have. `learn.openSample {tutorial}` runs View more →
|
||||
`{tutorial, index, title}` of the new document, and moves the Learn view to that tutorial; each call opens another
|
||||
copy and leaves the open documents as they are. `learn.finish {tutorial}` runs Finish tutorial →
|
||||
`{tutorial, finished: true, next}`, where `next` is the next tutorial's id in the skill, or null after the skill's
|
||||
last one; the tutorial's sample must have been opened, and finishing it again keeps one entry. `learn.next {tutorial}`
|
||||
runs Next Up on a finished tutorial and shows the panel on the next one → `{skill, tutorial, title}`; on a tutorial
|
||||
not finished, or a skill's last tutorial, it is an error. For all three, a missing, non-string or unknown `tutorial`
|
||||
is an error, and an error changes nothing. Behavior reference:
|
||||
[Quick skill guide](https://helpx.adobe.com/illustrator/desktop/get-started/learn-the-basics/learn-skills-quick-skill-guide.html).
|
||||
|
||||
```json
|
||||
{"name":"invoke_menu","arguments":{"command":"learn.show","params":{"tutorial":"pen-paths"}}}
|
||||
{"name":"invoke_menu","arguments":{"command":"learn.openSample","params":{"tutorial":"pen-paths"}}}
|
||||
{"name":"invoke_menu","arguments":{"command":"learn.finish","params":{"tutorial":"pen-paths"}}}
|
||||
{"name":"invoke_menu","arguments":{"command":"learn.next","params":{"tutorial":"pen-paths"}}}
|
||||
{"name":"invoke_menu","arguments":{"command":"learn.skills","params":{}}}
|
||||
```
|
||||
|
||||
A step that names a tool shows the tool's name as a blue link. A click on it, or Enter or Space while it has the
|
||||
@@ -2721,12 +2815,22 @@ vertical guide, the y of a horizontal one, in points) → `{index}`. With `artbo
|
||||
artboard guide: it runs across that artboard only, moves with it (`artboard.move`, a pure move in
|
||||
`artboard.setProps`, `artboard.rearrange`), scales with it (`artboard.setProps {scaleArt}`), is copied with it (`artboard.duplicate`, `artboard.move {copy}`) and is
|
||||
deleted with it (`artboard.delete`); without, a canvas guide runs across the whole canvas. `guide.list` →
|
||||
`[{index, vertical, pos, selected, artboard?}…]` (`artboard` only for artboard guides).
|
||||
`[{index, id, vertical, pos, selected, artboard?, layer?, hidden, locked, shown, editable}…]` (`artboard` only for
|
||||
artboard guides; `id` is the guide's node and `layer` the layer it is on; `hidden` and `locked` are its own state,
|
||||
`shown` and `editable` also take its layer into account). `layer.setProps {ids: [id…], visible?, locked?}` hides or
|
||||
locks guides on their own, as the eye and lock on a guide's row in the Layers panel do; a hidden guide is not drawn
|
||||
and does not snap, and a locked one is drawn and snaps but can't be selected, moved or deleted.
|
||||
`guide.select {indexes: [index…], toggle?}` selects guides on their own (the art is deselected; `toggle` adds or
|
||||
removes them) → `{selected}`. `guide.move {index, pos}` puts one guide somewhere, `guide.move {dx?, dy?, copy?}`
|
||||
moves the selected ones (vertical guides by `dx`, horizontal ones by `dy`; `copy` leaves them and selects the
|
||||
moved copies), and `guide.remove {index?}` deletes one guide or the selected ones → `{count}`; each is one undo
|
||||
step. With guides selected, `edit.clear` (Delete) deletes them and `object.nudge` (the arrow keys) nudges them.
|
||||
moved copies), and `guide.remove {index?, indexes?}` deletes one guide, the guides `indexes` (not with `index`; an
|
||||
index given twice counts once; a hidden or locked guide among them is an error and nothing is deleted) or the
|
||||
selected ones → `{count}`; each is one undo step. An `indexes` list of `guide.select`, `guide.remove` or
|
||||
`guide.setLayer` holds at most 10,000 entries; a longer one is an error. With guides selected, `edit.clear` (Delete) deletes them and `object.nudge` (the
|
||||
arrow keys) nudges them. Object › Lock › Selection (`object.lock`) and Object › Hide › Selection (`object.hide`) lock
|
||||
or hide the selected guides on their own, with the selected art, in one undo step, except in isolation mode.
|
||||
`object.unlockAll` and `object.showAll` with the default scope, outside isolation mode, also unlock or show the
|
||||
guides locked or hidden on their own and select them as guides.
|
||||
View › Guides › Lock Guides (`view.guides.lock`) deselects them and the paths made into guides, in every open
|
||||
document, and refuses these commands until unlocked. While it is on, a command that selects art, such as `edit.undo`,
|
||||
`edit.redo`, `object.exitIsolation`, `object.unlockAll`, `object.showAll` or `edit.paste`, leaves the guides out.
|
||||
@@ -2916,6 +3020,13 @@ already walks Image Trace. Short agent entry points:
|
||||
Tilt goes from its first value with the pen lying flat to its second upright, and on Bearing or Rotation from its
|
||||
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).
|
||||
- Freehand Fidelity: the `fidelity` of `path.freehand` and `brush.freehand` is in points, 1.5 pt when left out. A
|
||||
value must be from 0.000015625 pt (0.01 / 640) to 100 / 0.0313 pt (about 3194.89 pt), and a value outside that range
|
||||
is rejected with an error. The Pencil and the Paintbrush give Fidelity in screen pixels, 0.01 to 100 px, and send it
|
||||
divided by the zoom (0.0313 to 640) and kept within that range, so a stroke is fitted at the same tolerance on screen
|
||||
at every zoom. A stroke
|
||||
that continues a path (`extend`) closes it when it ends within four times the Fidelity of the path's other end, at
|
||||
least 6 pt and at most 400 pt. The Blob Brush's `path.blob` Fidelity stays in points, 0.01 to 100 pt.
|
||||
- Variables: `variable.list`, `variable.define {name, kind: text|visibility|image|graph}`, `variable.bind {variable, ids?}`,
|
||||
`variable.makeTextDynamic`, `variable.makeVisibilityDynamic`, `variable.makeImageDynamic`, `variable.makeGraphDynamic`
|
||||
(`variable.bind` and `variable.makeTextDynamic` refuse type that already has another text variable and name it),
|
||||
@@ -3016,15 +3127,18 @@ already walks Image Trace. Short agent entry points:
|
||||
the file at `path`, else a picked one, or the file's text `data`, adds its set after the other sets and returns
|
||||
`{set, name, actions}`. A set named like one already in the panel gets the next free number (`Print 2`), and the
|
||||
other sets and the current set stay as they are. An action set file (`.vcactions`) is JSON:
|
||||
`{"format": "vcactions", "version": 1 to 5, "name", "actions": [{"name", "steps": [{"command", "params", "excluded"?}]}]}`, each step
|
||||
`{"format": "vcactions", "version": 1 to 6, "name", "actions": [{"name", "steps": [{"command", "params", "excluded"?}]}]}`, each step
|
||||
a command id and its params as `command.batch` takes them, or a stop: the command `action.stop` with
|
||||
`{message, allowContinue}`. A Select Object step is the command `select.byNote` with `{note, caseSensitive,
|
||||
wholeWord}`, and a Select Path step is the command `select.storedPath` with `{id, fingerprint}`. `excluded: true` preserves a step but omits it from playback;
|
||||
an absent or false flag includes the step. Files with Select Path steps use version 5, files with Select Object steps
|
||||
and no Select Path step use version 4, files with stops and neither use version 3, and files with excluded steps and
|
||||
none of these use version 2, so older builds refuse them instead of playing the excluded steps or failing at a stop, a
|
||||
Select Object step or a Select Path step; other files use version 1, and version 1 to 4 files still load. A file with another `format` or a `version` other than
|
||||
1 to 5, a stop whose message is not text or whose `allowContinue` is not true or false, a Select Object step whose params `ui.action.insertSelectObject` would refuse, 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
|
||||
wholeWord}`, and a Select Path step is the command `select.storedPath` with `{id, fingerprint}`. A View menu step is
|
||||
the id of a View menu command that the app runs itself (`view.outline`, `view.zoomIn`, `view.rotate` and the others
|
||||
`ui.action.insertMenuItem` lists) with the item's params. `excluded: true` preserves a step but omits it from playback;
|
||||
an absent or false flag includes the step. Files with View menu steps use version 6, files with Select Path steps and
|
||||
no View menu step use version 5, files with Select Object steps and neither use version 4, files with stops and none
|
||||
of these use version 3, and files with excluded steps and none of these use version 2, so older builds refuse them
|
||||
instead of playing the excluded steps or failing at a stop, a Select Object step, a Select Path step or a View menu
|
||||
step; other files use version 1, and version 1 to 5 files still load. A file with another `format` or a `version` other than
|
||||
1 to 6, a stop whose message is not text or whose `allowContinue` is not true or false, a Select Object step whose params `ui.action.insertSelectObject` would refuse, a View menu step whose params are not an object, 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. So is a file whose set `ui.actionSet.save` would write larger than 8 MiB (a file with
|
||||
less white space, a set name that gets a number, or an `.aia` set), with the error `the action set would be larger
|
||||
than 8 MiB`. The Actions panel menu's Save Actions… and Load Actions… run these; Load Actions… is
|
||||
@@ -3063,7 +3177,9 @@ already walks Image Trace. Short agent entry points:
|
||||
action set would be larger than 8 MiB`): it does not run, and the recording goes on. A batch (`command.batch`) is
|
||||
such a command too. A command whose step grows past a limit only as it runs, from values it adds to its step,
|
||||
keeps its edit and result; the status bar names the limit, later recorded commands do not run, and
|
||||
`ui.action.stop` leaves its step out. A stop that playback reaches
|
||||
`ui.action.stop` leaves its step out. So does a `script.run` whose commands, or a tool's or panel's edit whose
|
||||
step, takes the recording past a limit: the status bar names the limit when the run or the edit ends, and
|
||||
`ui.action.stop` keeps the steps that fit. A stop that playback reaches
|
||||
then is not recorded, and the status bar shows the reason. `ui.action.stop` leaves out any recorded steps still past
|
||||
either limit and shows which one in the status bar.
|
||||
- Actions: `ui.action.options {set, action, name?, key?, cmd?, shift?, color?}` changes the action at
|
||||
@@ -3089,7 +3205,12 @@ already walks Image Trace. Short agent entry points:
|
||||
here and in Batch…. An action with an included stop plays up to the stop at any speed and then waits, with its
|
||||
message box open, until `ui.action.continue` or `ui.action.stop`. At Accelerated the steps between two stops are one
|
||||
undoable batch each. The result is then `{results, pending, atStop?}`, with `atStop: true` when the action already
|
||||
waits. Batch… refuses an action with an included stop, and a stop that is excluded does not hold playback.
|
||||
waits. Batch… refuses an action with an included stop, and a stop that is excluded does not hold playback. A View
|
||||
menu step (`ui.action.insertMenuItem`) plays at every speed in its place among the steps, as its menu item runs, and
|
||||
adds no undo step. At Accelerated the steps before it and the steps after it are one undoable batch each, and the
|
||||
result is `{results}` with every step's result in order. A step that fails ends the playback with its error: the
|
||||
batch it is in changes nothing, and the steps before that batch stay done. While another action records, the View
|
||||
menu step is recorded too. Batch… refuses an action with an included View menu step.
|
||||
- Actions: `ui.action.insertStop {set?, action?, step?, message?, allowContinue?}` inserts a stop. With `set` and
|
||||
`action`, the stop goes into that action, after step `step`, else after its last step, and the command returns
|
||||
`{set, action, step}`. Without them it goes into the recording in progress, after the steps recorded so far, and
|
||||
@@ -3103,11 +3224,17 @@ already walks Image Trace. Short agent entry points:
|
||||
(`message`, `allowContinue`, `set`, `action`, `step`), whose OK runs this.
|
||||
- Actions: `ui.action.insertMenuItem {set?, action?, step?, command, params?}` inserts a menu item's command as a step
|
||||
without running it. `command` and `params` (default: `{}`) must be those of an item in the menus that can be a step:
|
||||
an item that runs a document command without opening a dialog first, outside the File, Window and Help menus, and
|
||||
not Undo, Redo, a Paste command, Object › Align (its items add the Align To choice when clicked), Object › Image
|
||||
an item that runs a document command, or a View menu item that the app runs itself (Outline, Pixel Preview, Trim
|
||||
View, Presentation Mode, Screen Mode, the zoom, fit and Rotate View items, and the show, hide and snap items), without
|
||||
opening a dialog first, outside the File, Window and Help menus, and not Undo, Redo, a Paste command, Object › Image
|
||||
Trace › Make or Make and Expand (the menu traces off the UI thread, with progress and Cancel), Object › Pattern ›
|
||||
Make or Edit Pattern (the menu also opens the Pattern Options panel), a preference
|
||||
toggle, an Actions command or a recent-font, saved-selection or saved-view slot. Disabled items are listed, and playback checks the step when it runs. With `set` and `action`, the
|
||||
toggle, an Actions command, a Perspective Grid preset of the preferences or a recent-font, saved-selection or saved-view slot. Disabled items are listed, and playback checks the step when it runs. An Object › Align item's step
|
||||
keeps the `to` its click sends at insertion (`key` while the selection has a key object or key guide, `artboard` for one selected
|
||||
object or with Align to Artboard, else `selection`), so a later Align To choice does not change it, and a step that
|
||||
aligns to the key object fails in playback when the selection has no key then. With anchor points selected the click
|
||||
sends no `to`, and neither does the step. These are VectorCraft's own rules. A
|
||||
View menu step plays as `ui.action.play` describes. With `set` and `action`, the
|
||||
step goes into that action, after step `step`, else after its last step, becomes the panel's selected step, and the
|
||||
command returns `{set, action, step}`. Without them it goes into the recording in progress and returns
|
||||
`{recording: true}`. A command no such item runs, params that are not an object, an index past the last set, action
|
||||
@@ -3528,12 +3655,16 @@ effect of each selected object, in one undo step: `face` is `front` (default) or
|
||||
offset in points of the graphic's center from the center of the object's bounds in the face's plane, `scale` is a
|
||||
percentage of the symbol's size (1..10000; omitted, 100 or less so the graphic fits inside the object) and
|
||||
`rotation` is in degrees counterclockwise (-360..360). Without `index` each object's first 3D effect takes it, and `item` is refused.
|
||||
Every object's 3D effect must be Extrude & Bevel with Cap on (front only at a depth of 0) or Rotate (the Plane type,
|
||||
front only), and `symbol` must name a document symbol; otherwise the command is refused and nothing changes. It returns `{ids, graphic}`.
|
||||
Every object's 3D effect must be Extrude & Bevel with Cap on (front only at a depth of 0), Rotate (the Plane type,
|
||||
front only) or Revolve (front only: its swept side), and `symbol` must name a document symbol; otherwise the command is refused and nothing changes. It returns `{ids, graphic}`.
|
||||
On Revolve, `x` and `y` are measured on the side unrolled flat from its middle, and a graphic that does not fit
|
||||
starts scaled to fit the half of the side seen from the front ([three-d.md](three-d.md#graphics)).
|
||||
|
||||
The graphics are the `graphics` parameter of `threeD.extrude` and `threeD.rotate`, which `effect.setParams` also
|
||||
The graphics are the `graphics` parameter of `threeD.extrude`, `threeD.rotate` and `threeD.revolve`, which `effect.setParams` also
|
||||
edits: an array of up to 64 `{symbol, face, x, y, scale, rotation}` objects, drawn on the face turned,
|
||||
foreshortened and shaded with it and clipped to it ([Map artworks on 3D object](https://helpx.adobe.com/illustrator/desktop/special-effects-styles/create-3d-graphics/map-artwork-on-3d-objects.html)).
|
||||
Revolve takes graphics on its swept side and shades them with the object's light ([the archived reference, page 185](https://web.archive.org/web/20210601162814/https://helpx.adobe.com/pdf/illustrator_reference.pdf#page=185));
|
||||
how a graphic wraps around the side is VectorCraft's own rule.
|
||||
A graphic naming a symbol the document does not have is refused, unless the effect already holds a graphic of it.
|
||||
The drawing rules are VectorCraft's own; see [three-d.md](three-d.md#graphics).
|
||||
|
||||
@@ -3769,6 +3900,32 @@ excluded take the palette as their new colors in row order, the colors repeating
|
||||
{"name":"run_command","arguments":{"command":"recolor.pickTheme","params":{"picks":[{"at":[120,80]},{"rect":[200,40,320,140]}],"colors":4}}}
|
||||
```
|
||||
|
||||
`recolor.weigh {map, weights?, ids?}` is the dialog's Prominent Colors bar. It takes rows as `recolor.apply` does and
|
||||
returns them as `map`, each with `from` as a list, and `shares`: for each row, its percent of the uses (the `count` of
|
||||
`recolor.colors`) of the current colors of the rows that are not excluded, and 0 for an excluded row. A use counts for
|
||||
the row that `recolor.apply` recolors it with (rows with a new color first, an exact color before a hex color, then
|
||||
the first row that lists it), and otherwise for the first other row that is not excluded and lists it. A current
|
||||
color that no art uses counts nothing. Without `weights` the
|
||||
rows come back unchanged. `weights` holds one number of 0 or more per row; an excluded row's weight is ignored, and
|
||||
at least one other row needs a weight above 0. As VectorCraft's own rule, current colors then move one at a time
|
||||
between the rows that are not excluded and have a new color (`to`), as long as a move brings each row's share of the uses nearer its share of the
|
||||
weights. Of those moves, it takes first the color nearest in Lab to the first color of the row it goes to, compared
|
||||
with the row it leaves. A row keeps its first color, and the tints of one global swatch in a row move together. A
|
||||
color that the first color of another row with a new color also lists stays where it is. When a color moves, other
|
||||
rows with a new color drop their own entries for it, so `recolor.apply` recolors it with the row it moved to. The
|
||||
colors that can move are compared with the rows at most 50,000,000 times in all; when those colors times the rows
|
||||
that are not excluded pass that, no color moves. Colors that stay in a row keep their order, and the colors that come
|
||||
to it follow them. The command changes nothing; `recolor.apply` with the returned `map` recolors the art. In the Recolor Artwork dialog the
|
||||
bar sits under the Edit tab's wheel: each row with a share is a part as wide as that share, in the row's new color,
|
||||
the largest first. Dragging the edge between two parts moves width between them, and when the drag ends the widths
|
||||
become the `weights` field, which moves the rows' current colors and previews the result. The New Color Group menu
|
||||
beside the link button runs `swatch.newGroup` right away, as its own undo step: Save All Colors saves the new colors
|
||||
of the rows that are not excluded, in row order, and Save Prominent Colors saves the bar's colors in the bar's order.
|
||||
|
||||
```json
|
||||
{"name":"run_command","arguments":{"command":"recolor.weigh","params":{"map":[{"from":["rgb 255 0 0","rgb 128 0 204"],"to":"#00ff00"},{"from":["rgb 0 0 255"],"to":"#ffff00"}],"weights":[1,1]}}}
|
||||
```
|
||||
|
||||
The `recolor.*` commands refuse parameters of the wrong form. A `limitTo` or `method` that is not a string gets the
|
||||
error for an unknown library or method. Other wrong-form parameters get an error that names them.
|
||||
`includeImages`, `includePatterns`, a row's `exclude`, `order`, `saturationBrightness` and the `white`, `black` and
|
||||
@@ -4306,6 +4463,13 @@ and `layerRows`, the rows highlighted in the panel.
|
||||
draws and is clicked in outline, Ctrl/Cmd-click its eye), `dimImages` (0–100, or false) and `color` (an index 0–26,
|
||||
`#rrggbb` or a preset name; a hex color with an alpha part, `#rrggbbaa` or `#rgba`, is an error, and so it is in
|
||||
`layer.new` and `layer.newSublayer`). Several rows change in one undo step (a drag down the eye or lock column).
|
||||
A ruler guide's row has its own eye and lock: `ids` may name ruler guides (their `id` in `guide.list`), which take
|
||||
`visible` and `locked`. They can be changed while the guide's layer is hidden or locked, and the guide shows
|
||||
or can be edited only when its layer allows it as well. Alt-click on a guide row's eye or lock acts on the other
|
||||
layers, as on any row in that layer. A click on a guide row selects the guide (`guide.select`) and clears the
|
||||
highlighted rows (`layer.highlight {ids: [], mode: "set"}`), so Delete then runs `edit.clear` on the guide; with no
|
||||
row highlighted, the trash button runs `edit.clear` on the selected guides and art, and guide rows dropped on the
|
||||
trash are deleted (`guide.remove {indexes}`).
|
||||
- **Dragging rows**: `layer.move {ids, target, place?: above|below|inside, copy?}` moves rows beside a row or into a
|
||||
layer or group (on top of its contents), keeping their stacking order; `copy` (Alt-drag) moves copies. Layers go
|
||||
only in layers or at the top level and objects in layers and groups (an object placed beside a top-level layer goes
|
||||
@@ -4603,7 +4767,9 @@ and those of the object shape the outline of the clip group, the gradient fits t
|
||||
box, as the canvas paints the fill; the expanded art does not keep them. With `fill: false` gradient and pattern fills
|
||||
stay live. `object.expand.info` answers which options have something to expand in the selection
|
||||
(`{object, fill, stroke, gradient, appearance, symbolArt?}`; `gradient` says whether Fill has a gradient fill, which Expand
|
||||
Gradient To applies to; `appearance` whether the selection has appearance attributes Expand Appearance expands first,
|
||||
Gradient To applies to, that it turns into art: it is false when every such fill repeats or reflects in more than 256
|
||||
runs across the box it fills, which for type, symbol art included, is the box of each outline Object makes of a character,
|
||||
ruby character, underline or strikethrough; `appearance` whether the selection has appearance attributes Expand Appearance expands first,
|
||||
for which Object → Expand… is dimmed in the menus; `symbolArt: {fill, stroke, gradient}`, present when the selection
|
||||
holds symbol instances that `object` expands, whether only their art holds it, which Fill and Stroke reach only with
|
||||
`object` on), and `object.mesh.create` on a gradient-filled object colours the
|
||||
@@ -4923,9 +5089,10 @@ round, such as a rectangle, stays as it is. Closed paths stay closed and open pa
|
||||
{"name":"run_command","arguments":{"command":"object.path.smooth","params":{"level":80}}}
|
||||
```
|
||||
|
||||
In the desktop app, Object › Path › Smooth opens the slider (`ui.menuDialog {command: "object.path.smooth"}`, dialog
|
||||
`smoothSlider` with field `level`) at the Auto-Smooth level and previews the result until `ui.dialog.confirm`;
|
||||
`ui.smoothAuto` moves the open slider back to the Auto-Smooth level.
|
||||
In the desktop app, Object › Path › Smooth and the canvas context menu's Smooth… (listed while the selection holds a
|
||||
path) open the slider (`ui.menuDialog {command: "object.path.smooth"}`, dialog `smoothSlider` with field `level`) at
|
||||
the Auto-Smooth level, and the slider previews the result until `ui.dialog.confirm`; `ui.smoothAuto` moves the open
|
||||
slider back to the Auto-Smooth level.
|
||||
|
||||
## Editing a path with the Curvature tool
|
||||
|
||||
@@ -5381,8 +5548,12 @@ the selected artboards (those the Artboard tool has selected, else the active on
|
||||
`artboard.fitToSelection` calls it runs without `index`. Both include MCP's `run_command` calls in remote mode. The
|
||||
Artboards panel menu's Fit to Artwork Bounds also passes the selected artboards. A batch passes its `artboard` on to
|
||||
each of their steps that names no `index`, as the step's `index`. When the document a step runs in has no artboard at
|
||||
that index, the step gets that document's last artboard. An action recorded in the Actions panel leaves `index` and
|
||||
`indices` out of these steps, and they resize the artboard that is active when the action plays.
|
||||
that index, the step gets that document's last artboard. An `artboard.fitToArt` step that names neither `index` nor
|
||||
`indices`, while the Artboard tool is chosen with several artboards selected when the step runs, gets those artboards
|
||||
as its `indices` instead, and the batch's journal entry records them, so a replay of the journal fits the same
|
||||
artboards. A step's own `index` or `indices` is kept. An action recorded in the Actions panel leaves `index` and
|
||||
`indices` out of these steps: when the action plays, Fit to Artwork Bounds resizes the artboards the Artboard tool then
|
||||
has selected (two or more), else the active artboard, and Fit to Selected Art resizes the active artboard.
|
||||
|
||||
```json
|
||||
{"name":"run_command","arguments":{"command":"object.align","params":{"horizontal":"left","to":"artboard","artboard":1}}}
|
||||
@@ -5644,6 +5815,23 @@ know or a value that isn't a boolean is refused and changes nothing.
|
||||
{"name":"run_command","arguments":{"command":"view.snapToGlyph.options","params":{"angular":false,"anchors":false}}}
|
||||
```
|
||||
|
||||
The Pixel Snapping Options (the desktop app's Control bar › Snapping menu › Pixel Snapping Options…, described on the
|
||||
help page,
|
||||
<https://helpx.adobe.com/illustrator/desktop/measure-and-align/grids-and-guides/draw-pixel-perfect-art.html>):
|
||||
`view.snapToPixel.options {drawing?, moving?,
|
||||
scaling?}` (or `prefs.get`/`prefs.set` with key `pixelSnap`, a partial object) reads and sets which edits View › Snap to
|
||||
Pixel lands on whole pixels. All three are on by default, which is VectorCraft's own default. `drawing` covers the
|
||||
points the drawing tools place, the rulers' origin and measured points; `moving` covers the selection, its anchors and
|
||||
segments, artboards and ruler guides moved by dragging, and the Rotate, Reflect and Shear tools' drags; `scaling`
|
||||
covers the edges a bounding-box, Free Transform, artboard or slice handle drags, and the Scale tool's drag. An edit
|
||||
whose option is off snaps as it does with Snap to Pixel off. With Snap to Pixel off, the options do nothing. `{}` reads
|
||||
them; a key it doesn't know or a value that isn't a boolean is refused and changes nothing. Align New Objects to Pixel
|
||||
Grid and the objects' pixel-aligned property (see Align to Pixel Grid) do not depend on these options.
|
||||
|
||||
```json
|
||||
{"name":"run_command","arguments":{"command":"view.snapToPixel.options","params":{"scaling":false}}}
|
||||
```
|
||||
|
||||
With Smart Guides on, a bounding-box handle dragged with the Selection or Free Transform tool (`mods.shift`
|
||||
proportional, `mods.alt` from the centre) lands on another object's anchor or centre (labelled "anchor" or
|
||||
"center"), else its corners and side line up with the edges and centres of the other objects and the artboards (a
|
||||
@@ -5871,8 +6059,8 @@ Preferences. `prefs.reset` resets the preferences at once, without the question.
|
||||
|
||||
`prefs.export {path?}` writes the preferences as a JSON file, `{"format": "vectorcraft-preferences", "version": 1,
|
||||
"prefs": {…}}`, and replies `{path, count}`; without `path` it replies `{data, count}` with the file's text. The file
|
||||
holds every preference `prefs.list` lists and the `eyedropper`, `perspectiveWidget`, `pathfinder` and `glyphSnap`
|
||||
groups. It leaves out the folder preferences (`fontsFolder`, `pluginsFolder`, `recoveryFolder`, `templatesFolder`) and
|
||||
holds every preference `prefs.list` lists and the `eyedropper`, `perspectiveWidget`, `pathfinder`, `glyphSnap` and
|
||||
`pixelSnap` groups. It leaves out the folder preferences (`fontsFolder`, `pluginsFolder`, `recoveryFolder`, `templatesFolder`) and
|
||||
saved presets. An export over 1 MB, the most `prefs.import` reads, is an error and writes nothing.
|
||||
`prefs.import {path | data}` applies such a file and replies `{imported}`, the number of preferences it
|
||||
set. It checks every value first, as `prefs.set` does: a file over 1 MB, malformed JSON, another `format`, a newer
|
||||
@@ -6560,8 +6748,8 @@ path isn't followed) when it isn't. The desktop app also checks the active docum
|
||||
comes back to the front, following the same preference. `links.check` reports every link's `status` (`ok`, `modified`,
|
||||
`missing`), `links.update {ids?}` reads modified files again and `links.relink {ids?, path | folder}` points images at
|
||||
another file (or each at the file of its name in a folder); images keep their bounds, one undo step each.
|
||||
`links.relink`'s `scope` picks which links take the new file (Relink's Replace choice): `selected` (the default) relinks `ids`; `all` also relinks every other object in the layers linked to the same file as
|
||||
one of them; `missingInFolder` relinks `ids` to `path`, then every other missing link to the file of its name in
|
||||
`links.relink`'s `scope` picks which links take the new file (Relink's Replace choice): `selected` (the default) relinks `ids`; `all` also relinks every other stored object linked to the same file as
|
||||
one of them, in the layers, opacity-mask art, symbols, graph designs and patterns; `missingInFolder` relinks `ids` to `path`, then every other missing link to the file of its name in
|
||||
`path`'s folder, and lists the names not there in `notFound` (with `copy`, only missing images are looked for); `each` takes `paths: [{ids, path}]` in place of `ids`,
|
||||
`path` and `folder` and relinks each link to its own file. An unknown scope, `paths` without `each`, `each` with `ids`,
|
||||
`path` or `folder`, an entry without `path` or `ids`, an id in two entries and `missingInFolder` with `folder` are
|
||||
@@ -6569,8 +6757,10 @@ errors, and nothing is relinked. Each call is one undo step. The Links panel's R
|
||||
(`ui.relinkDialog`) with a Replace menu of these four choices. A PNG, JPEG,
|
||||
another file (or each at the file of its name in a folder); images keep their bounds, one undo step each.
|
||||
`links.update`, and `document.open` when it reads a modified file, also read the file again for the images and placed
|
||||
documents inside symbols, graph designs, patterns and opacity masks that show the same content (by default also for
|
||||
those that only that art shows); they have no ids, so the results do not list them. Saving a document also reads it
|
||||
documents inside symbols, graph designs, patterns and opacity masks that show the same content. Those objects have ids
|
||||
of their own: `links.list`, `links.check`, `links.findFiles`, the `missingLinks`, `modifiedLinks` and `updatedLinks`
|
||||
rows and the link watch list them, and every `links.*` command takes their ids. Opening a document gives an object
|
||||
there whose id is 0 or already used by another object a new id, and the next save writes it. Saving a document also reads it
|
||||
again for the placed documents of it inside that art in the other open documents. A PNG, JPEG,
|
||||
GIF or WebP file whose pixels can't be read is not shown: `links.relink` fails with "the image's pixels can't be
|
||||
read", and `links.update`, or `document.open` when it reads the file, lists it as missing, its images keeping what they
|
||||
@@ -6810,8 +7000,11 @@ listed in `warnings`. Binary DXF and DWG files answer an error saying to save th
|
||||
## Links panel
|
||||
|
||||
`links.list {show?: all|missing|modified|embedded, sort?: name|kind|status}` lists every image in the layers, top
|
||||
first, as the Links panel does: `{id, name, linked, status: ok|modified|missing|embedded, format, pixelWidth,
|
||||
pixelHeight, path?, found?, page?, preview?, note?}` (`note`: the image takes more than the decode allowance, 2 GiB
|
||||
first, as the Links panel does, then every image and placed document in opacity-mask art and in the art of symbols,
|
||||
graph designs and patterns, one row per stored object (never one per symbol instance or pattern tile): `{id, name,
|
||||
linked, status: ok|modified|missing|embedded, format, pixelWidth, pixelHeight, path?, found?, page?, preview?, note?,
|
||||
owner?}` (`owner`, for an object outside the layer tree: `{kind: layers|symbol|graphDesign|pattern, name?, maskOf?}`,
|
||||
`maskOf` naming the object whose opacity mask holds it; `note`: the image takes more than the decode allowance, 2 GiB
|
||||
or 512 MiB in the web app, as RGBA or as decoded, and it is drawn at the largest size within the allowance ("shown at
|
||||
reduced size"; the document keeps the whole file) or, when it can't be read that way or has more pixels than the
|
||||
allowance has bytes, drawn as a crossed gray box on the canvas and left out of exports ("too large to draw"); `document.open` and `file.place` say the same in their `warnings`). `links.info {id?}` is the Link Info: `image.info`'s fields plus
|
||||
@@ -6828,7 +7021,8 @@ bounds of another visible object that has one of those or a gradient with a tran
|
||||
a character's fill or stroke); a DCS image with transparency of its own counts as such an object. Bounds are cut to the
|
||||
bounds of the clipping paths of the clip groups and clipping layers holding an object. The check looks at
|
||||
every object in the layers each time the list is read. A `dcsTransparency` that is not true or false is an error.
|
||||
`links.goTo {id}` selects an image; `links.embed {ids?}` keeps linked files' pixels in the document (an image whose
|
||||
`links.goTo {id}` selects an image (`onCanvas: true`); for an object outside the layer tree it clears the selection and
|
||||
returns `{id, onCanvas: false, owner}`, and the panel says the link has no place on the canvas. `links.embed {ids?}` keeps linked files' pixels in the document (an image whose
|
||||
file is missing stays linked: relink it first); `links.unembed {id, path}` writes an embedded image to a file
|
||||
(another extension converts it) and links to it, and without `path` returns `{name, dataBase64}`.
|
||||
`links.placementOptions {ids?, preserve?: transforms|bounds|fileDimensions|fit|fill, align?: topLeft…bottomRight,
|
||||
@@ -9525,7 +9719,12 @@ outline. On a tie, the anchor met first along the outline in the order it was dr
|
||||
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
|
||||
its curve parameter, so content spreads evenly along a segment without handles. A side whose pieces, from corner to
|
||||
corner, are all one cubic curve split at anchors (each within 0.02 pt of that curve's piece) follows that curve's
|
||||
parameter instead, so splitting such a side's curve without changing its shape (Add Anchor Points, or a file that
|
||||
saves a curve in pieces) leaves how the side shares out the content as it was. Corners found from the outline can
|
||||
still move, since one at the outline's nearest point snaps onto an anchor within 0.5% of its segment's parameter. A
|
||||
side only partly made of one curve keeps the polygon shares. 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.
|
||||
A warp bends the content's bounds as one Bézier patch. The style sets the patch's control points from the bend and
|
||||
@@ -9777,8 +9976,9 @@ the Selection and Blend tools show the same values as widgets
|
||||
16 px above and below the spine's halfway point (where the boxes of three or more other visible objects hold that
|
||||
spot, a widget moves out in 16 px steps, up to 144 px, joined to the halfway point by a line): the upper one sets
|
||||
`colorShift` and the lower one, shown only when the steps follow the spine as `ramp` needs, sets `ramp`, by one per screen pixel dragged along the spine and by one per arrow key
|
||||
during the drag (ten with Shift). Each drag is one undo step, and `press_key` Escape or a switch to another tool
|
||||
during it puts the value back:
|
||||
during the drag (ten with Shift). A blend made without a spine shows the upper widget alone, placed against the
|
||||
straight lines between its key centers that its steps are laid out along, which are not drawn. Each drag is one undo
|
||||
step, and `press_key` Escape or a switch to another tool during it puts the value back:
|
||||
|
||||
```json
|
||||
{"name":"run_command","arguments":{"command":"object.blend.setEasing","params":{"id":40,"ramp":35}}}
|
||||
@@ -9896,11 +10096,26 @@ order along the path changes: Space, the start, Pivot, Rotate and the children's
|
||||
new place along the path counted from 0. `object.objectsOnPath.selectMember {member}` takes the same kind of `member`
|
||||
and returns `{group, member}`.
|
||||
|
||||
`object.objectsOnPath.detach {member?}` takes one object off the path: `member`, or without it the object chosen with
|
||||
the Select/Move widget of the one selected group (otherwise it fails with "choose the object to detach with its
|
||||
Select/Move widget"). `member` takes the same kind of object as `moveMember`, and neither it nor the group may be
|
||||
hidden or locked. The object leaves the group and goes just above it in the group's layer or group, staying where it
|
||||
is drawn, and becomes the selection; when the group is itself an object on another group's path, the object goes just
|
||||
above that outer group, so it does not join its path. The objects after it move up the path in their order: with Auto Space they spread
|
||||
evenly again (on an open path the first and last on its ends while two or more are left), and a Space value and the
|
||||
start are kept, drawn as close as the path has room for. Hidden and locked objects left in the group move up too. The
|
||||
group, its path and its options stay even with one object or none left, and an object moved back into it joins the
|
||||
path. It is one undo step, and undo puts the object back on the path with the choice it had. It returns
|
||||
`{group, member}`. In the desktop app, Detach in the Properties panel's Objects on Path Options section sends it, and
|
||||
is dimmed until one group is selected with an object chosen. To take several objects off at once, drag their rows out
|
||||
of the group in the Layers panel (`layer.move`).
|
||||
|
||||
```json
|
||||
{"name":"run_command","arguments":{"command":"tool.setOption","params":{"tool":"objectsOnPath","values":{"pivot":7,"rotate":30}}}}
|
||||
{"name":"run_command","arguments":{"command":"object.objectsOnPath.attach","params":{"path":30,"ids":[12,15,18]}}}
|
||||
{"name":"run_command","arguments":{"command":"object.objectsOnPath.options","params":{"pivot":7,"rotate":15}}}
|
||||
{"name":"run_command","arguments":{"command":"object.objectsOnPath.options","params":{"spacing":24,"start":0}}}
|
||||
{"name":"run_command","arguments":{"command":"object.objectsOnPath.detach","params":{"member":15}}}
|
||||
{"name":"run_command","arguments":{"command":"object.objectsOnPath.expand","params":{}}}
|
||||
```
|
||||
|
||||
@@ -9913,8 +10128,12 @@ justified text gets even word spacing, ragged text (left, centre or right aligne
|
||||
that fits to the next line to avoid a lone short word on the last line or a full line next to a short one.
|
||||
Single-line fills each line as far as it goes. Point type and type on a path have no line width, so both composers
|
||||
give the same result there. A paragraph whose characters differ in line metrics (type size, font, leading or vertical
|
||||
scale, or an inline graphic taller than the text) is composed with Every-line in rectangular area type, rows and
|
||||
columns included; in area type of another shape, or with text wrap, it falls back to Single-line.
|
||||
scale, or an inline graphic taller than the text) is composed with Every-line in area type of any shape, rows,
|
||||
columns and text wrap included. In a frame that is not a rectangle, or with text wrap, each line it tries is measured
|
||||
where the lines above it put it, across the line's own height, so a taller line that reaches where the frame is
|
||||
narrower, or beside a wrap object, gets the room there. Such a paragraph falls back to Single-line when the frame has
|
||||
no room for all of it, or when the search for its breaks passes VectorCraft's own limits (1,000,000 lines tried and
|
||||
2,000,000 baseline steps for one paragraph, 2,000,000 lines and 4,000,000 steps for all the paragraphs of a frame).
|
||||
The UI command `type.lineComposer` (Cmd+Alt+Shift+C, in remote mode `press_key {key: "C", mods: {cmd: true, alt: true,
|
||||
shift: true}}` or `invoke_menu`) sets `singleLine` when every paragraph of the selected type (or every paragraph the
|
||||
Type tool's selection touches) uses Every-line, else `everyLine`, and returns the composer it set.
|
||||
@@ -11007,4 +11226,5 @@ the error text. The interactive fallback applies only to ordinary File > Save, n
|
||||
|
||||
| Date | Change |
|
||||
|---|---|
|
||||
| 2026-11-13 | Envelopes: a top object's side whose pieces are all one curve split at anchors follows that curve's parameter (#7097). |
|
||||
| 2026-11-11 | Document READ_ONLY_LOCATION for saves (#6146); no response-shape change. |
|
||||
|
||||
+12
-1
@@ -264,7 +264,13 @@ capability model proposed for PhotoCraft plug-ins
|
||||
hexadecimal digits covers nothing. `plugin.remove` forgets the grant, and so does a successful `plugin.install` of a
|
||||
module that lists no permissions under that id, so the earlier bytes need a new approval. When `plugin.remove` can't
|
||||
remove the grant from `grants.json`, it returns an error, the plug-in stays installed, and a second `plugin.remove`
|
||||
tries again. A refused install leaves the grant as it is. When an install of a module that lists no permissions can't
|
||||
tries again. A refused install leaves the grant, the plug-in installed with the id, the `Plug-ins` folder and the
|
||||
list of disabled plug-ins as they are. When another session installs a plug-in with the id or changes its grant
|
||||
while `plugin.install` checks a module, the install is refused, before anything is written to the `Plug-ins` folder,
|
||||
if the other plug-in would need `replace: true` or the changed grant no longer approves the module. A
|
||||
`plugin.remove` in another session waits until the install has written the `Plug-ins` folder, and then removes the
|
||||
module and its grant. Loading the `Plug-ins` folder or a plug-ins folder in another session waits for it too. When
|
||||
an install of a module that lists no permissions can't
|
||||
write the module to the `Plug-ins` folder, or can't remove the grant from `grants.json`, the folder keeps the module
|
||||
it held and `grants.json` keeps the grant. The new module runs until the session ends. When the grant can't be
|
||||
removed and the module already stored can't be read back or written back, the new module stays in the folder, and
|
||||
@@ -773,6 +779,11 @@ is a piece drawn by itself, in the order returned, with paints of its own:
|
||||
starts at 1 pt, miter join, butt cap, miter limit 10.
|
||||
- An effect on a fill (`_context.item` `{"fill": i}`) returns only `fills`, which replace that fill on each piece; an
|
||||
effect on a stroke returns only `strokes`. The object's other fills and strokes stay where they are.
|
||||
- Each fill or stroke such an effect returns keeps the effects after it in that fill's or stroke's stack. A later
|
||||
live effect, and a later geometry effect on strokes, runs once on each of them in paint order: it is given the
|
||||
piece's `fills` and `strokes` with `_context.item` naming that one (`{"fill": 1}` for the second fill on the
|
||||
piece), and its result replaces only that fill or stroke. A run that fails, is refused, is deferred or would pass
|
||||
the budget leaves its own fill or stroke as it was, and the others still run.
|
||||
- The effects after it in the stack apply to the pieces together, the reference box being the bounds of all of them.
|
||||
Bounds, raster effects, Pathfinder effects, compound shapes and Envelope Options › Distort Appearance use the pieces
|
||||
as they are drawn. Outside outline mode, an image is also hit where the pieces of its own fills and strokes paint; a
|
||||
|
||||
+84
-18
File diff suppressed because one or more lines are too long
+59
-22
@@ -117,11 +117,20 @@ The rest is our reading:
|
||||
each side face of the fill's solid that is turned toward the viewer is drawn before every face of the same
|
||||
shape's strokes, turned toward the viewer, whose bounds overlap it, so the stroke's walls cover the fill's walls
|
||||
at concave corners. This applies to strokes on closed paths without dashes, a width profile or a brush, painted
|
||||
with a solid color or a gradient without transparent stops; with other strokes, and without caps, the faces keep
|
||||
their depth order. Otherwise
|
||||
each solid is drawn on its own with its opacity and blending, the lower item's first. With a light that is not
|
||||
white, each solid is also drawn on its own when one of them is a puffed, shaded Inflate surface in a solid color
|
||||
(drawn as one composite) or is painted with a gradient that has transparent stops (drawn with an opacity mask).
|
||||
with a solid color or a gradient without transparent stops, under Extrude & Bevel (both kinds). Under Inflate
|
||||
the fill can rise in front of such a stroke, so it is drawn like the other strokes. Other strokes (dashed, with a
|
||||
width profile or a brush, on an open subpath, or in a paint that may show through) leave parts of the fill's edge
|
||||
uncovered, such as the gaps between dashes. Each face of such a stroke that passes through a face of the fill's
|
||||
solid, or through a face of another of the shape's strokes, where the two overlap in the drawing is cut where
|
||||
their depths meet, and the faces of the shape's fill and strokes that overlap are drawn in the order of their
|
||||
depths where they overlap, with caps on or off. A fill wall in a gap stays in its own depth order. Inflate's
|
||||
curved surfaces follow this only as closely as their flat facets do. A solid painted with a gradient that has
|
||||
transparent stops under a light that is not white is drawn with an opacity mask: its faces keep their places in
|
||||
this order, in runs that each carry the mask, and so do its graphics. A member of a 3D group with its own opacity
|
||||
mask or blending mode draws its fill's and strokes' faces in this order inside that mask or blending mode when
|
||||
they are opaque with Normal blending. Otherwise each solid is drawn on its own with its opacity and blending, the
|
||||
lower item's first. With a light that is not white, each solid is also drawn on its own when one of them is a
|
||||
puffed, shaded Inflate surface in a solid color (drawn as one composite).
|
||||
- The solids turn, twist and taper about the center of the bounds of all their shapes, Inflate's grid covers
|
||||
those bounds, and with Perspective one eye sees every solid. A stroke too narrow to hold a point of Inflate's
|
||||
grid stays flat.
|
||||
@@ -150,8 +159,11 @@ them all. The members stay editable: moving or editing one reshapes the solids.
|
||||
inside the 3D group applies to the solids of that group's members together. An opacity mask on
|
||||
a member masks its solids, and one on a group inside the 3D group masks the solids of that group's members
|
||||
together. The mask stays where it is on the page; it does not turn with the solids. A disabled mask is ignored.
|
||||
- When a member, or a group inside the 3D group, has an opacity mask or a blending mode other than Normal, each
|
||||
solid is drawn on its own, the backmost member's first, as when a solid is transparent.
|
||||
- When a member, or a group inside the 3D group, has an opacity mask or a blending mode other than Normal, the
|
||||
members' faces are not drawn in one shared order. Each member whose fills and strokes are opaque with Normal
|
||||
blending draws their faces in one order of its own inside its masks and blending modes, as described under
|
||||
[Fills and strokes](#fills-and-strokes). Otherwise each solid is drawn on its own, the backmost member's first, as
|
||||
when a solid is transparent.
|
||||
- When every solid is opaque, all members' faces are drawn in one back-to-front order; otherwise each solid is drawn
|
||||
on its own, the backmost member's first.
|
||||
- Hidden members and guides are left out. A group holding a live object other than a blend (an envelope, a mesh, a
|
||||
@@ -308,8 +320,9 @@ Our reading:
|
||||
The public [Map artworks on 3D object](https://helpx.adobe.com/illustrator/desktop/special-effects-styles/create-3d-graphics/map-artwork-on-3d-objects.html)
|
||||
page describes graphics: art kept with the document and placed on single surfaces of a 3D object, and the
|
||||
[3D and Materials panel options](https://helpx.adobe.com/illustrator/desktop/special-effects-styles/create-3d-graphics/3d-materials-panel-options.html)
|
||||
page lists Graphics and Add Materials and Graphics on the Materials tab. VectorCraft maps graphics onto planar faces:
|
||||
Extrude & Bevel's front and back caps, and the plane of the Plane type (Rotate).
|
||||
page lists Graphics and Add Materials and Graphics on the Materials tab. VectorCraft maps graphics onto
|
||||
Extrude & Bevel's front and back caps, the plane of the Plane type (Rotate), and the swept side of Revolve, which the
|
||||
public page's example of a label on a bottle describes.
|
||||
|
||||
- The panel's **Materials** tab shows the document's graphics as thumbnails. A graphic is a document symbol, as
|
||||
the public page allows existing symbols to be used. **Add as Single Graphic** keeps the selected art as a new
|
||||
@@ -318,7 +331,8 @@ Extrude & Bevel's front and back caps, and the plane of the Plane type (Rotate).
|
||||
- Clicking a thumbnail maps that graphic onto the front of the 3D effect of each selected object
|
||||
(`threeD.mapGraphic`), in one undo step. A graphic larger than the object starts scaled down to fit inside it.
|
||||
- Below the thumbnails the tab lists the graphics mapped onto the first selected object. The selected one shows
|
||||
its Face (Front or Back; Plane has only a front), X and Y (the offset of its center from the center of the
|
||||
its Face (Front or Back; Plane and Revolve show no Face, as a plane has only a front and Revolve's graphics go
|
||||
on its side), X and Y (the offset of its center from the center of the
|
||||
object's bounds, in the face's plane), Scale (a percentage of the symbol's size) and Rotation
|
||||
(counterclockwise), and **Remove Graphic** takes it off. Each change is one undo step.
|
||||
- While the tab is open, a blue handle sits on the center of each mapped graphic whose face is turned toward the
|
||||
@@ -337,6 +351,26 @@ These rules are VectorCraft's own:
|
||||
the viewer is not drawn.
|
||||
- On the back cap, X runs to the right as the back is seen from behind, so the graphic reads the right way round
|
||||
there.
|
||||
- On Revolve a graphic lies on the swept side, which has one face (Front), unrolled flat. X runs around the axis:
|
||||
the angle from the middle of the side times the profile's distance from the axis at that point, so a graphic
|
||||
keeps its size at every distance and wraps farther around the axis where the profile comes nearer to it. Y runs
|
||||
along the profile, toward its lower end, measured from the middle of its length; a profile's edges on the axis
|
||||
sweep nothing and add no length. On a closed profile that does not touch the axis, Y is measured from where its
|
||||
outer side crosses the middle of its height, and the graphic is cut on its inner side. The middle of the side
|
||||
is the middle of the part of the sweep that faces the viewer before the object is turned, which is the part at
|
||||
90° with the axis on the left and at 270° with it on the right (the middle of the sweep when no part faces the
|
||||
viewer). On a compound profile the graphics go on its longest contour. Each face
|
||||
of the side draws the part of the graphic that falls on it, shaded as the face is shaded, so the graphic narrows
|
||||
toward the silhouette and is not drawn where the side's outside faces away or past the ends of the sweep; nearer
|
||||
faces drawn after it cover it. A full turn cuts the graphic at the back, on the edge between two segments nearest
|
||||
half a turn from the middle, and the end caps take no graphic; a part
|
||||
that runs past the end of the profile reaches the curved rim of the cap and stops there. On a group or layer the
|
||||
graphics go once, on the side of the member with the longest profile. Curves
|
||||
are cut into straight pieces within 0.05 pt before they are mapped, and an opaque part takes a 0.3 pt stroke of
|
||||
its paint over the seams between faces; a part filled with a pattern, or whose gradient has a transparent stop
|
||||
or point, takes none. A graphic larger than the half of the side seen from the front starts
|
||||
scaled to fit it. The panel shows no handle for a Revolve's graphics; X and Y move them. Expand Appearance keeps
|
||||
every face of a surface with graphics.
|
||||
- The symbol's fills and strokes are drawn as filled areas, a stroke as its outline, and their gradients and
|
||||
patterns are placed with the graphic. Images, hidden objects,
|
||||
guides and clipping paths in the symbol are left out, and clipping groups draw their art unclipped. Instances
|
||||
@@ -345,12 +379,15 @@ These rules are VectorCraft's own:
|
||||
- Without perspective, the graphic maps exactly. With perspective, straight lines stay straight and each curve is
|
||||
cut into 8 cubic pieces before it is mapped. The part of a graphic at or behind the eye is left out.
|
||||
- An object takes up to 64 graphics. One graphic draws up to 4,096 fills and strokes, and the graphics of one 3D
|
||||
effect draw up to 400,000 path elements together. Commands refuse a graphic past either limit. A loaded file
|
||||
effect draw up to 400,000 path elements together (on Revolve, 400,000 points after the curves are cut, and up to
|
||||
2,000,000 once they are cut at the faces, with up to 64,000,000 points cut together, and the copies of their
|
||||
paints in the parts take up to 256 MiB per object, apart from those of the surfaces). Commands refuse a graphic
|
||||
past either limit. A loaded file
|
||||
draws the object without a graphic past the first limit, and without all of its graphics past the second.
|
||||
- A hollow Extrude & Bevel has no caps, so its graphics are not drawn until Cap is turned on again, and
|
||||
`threeD.mapGraphic` refuses to map a new one onto it. Changing the type to Revolve or Inflate
|
||||
drops the graphics, and changing between Extrude and Plane keeps them, except that Plane drops the graphics
|
||||
on the back cap.
|
||||
`threeD.mapGraphic` refuses to map a new one onto it. Changing the type to Inflate drops the graphics, and
|
||||
changing between Extrude, Plane and Revolve keeps them, except that Plane and Revolve drop the graphics on the
|
||||
back cap; on Revolve the front's graphics go on its side.
|
||||
- `effect.apply` and `effect.setParams` refuse a graphic that names a symbol the document does not have, unless
|
||||
the effect already holds a graphic of that symbol. A graphic whose symbol is deleted is no longer drawn. Renaming a symbol renames it in the graphics that use it,
|
||||
in the layers, in the art of symbols, patterns, graph designs, brushes and opacity masks, and in graphic
|
||||
@@ -364,9 +401,9 @@ These rules are VectorCraft's own:
|
||||
uses: `rotationX`, `rotationY`, `rotationZ`, `perspectiveAngle` (degrees), `shade`, `lightColor` (`#rrggbb`, default `#ffffff`), `lightIntensity` (%), `lightRotation`,
|
||||
`lightHeight` (degrees), `lightSoftness` (%), `ambient` (%, to 200), `lightBehind`. Lengths are points and scale with the object (Scale Strokes & Effects).
|
||||
Commands validate the shape and the parameters before the document changes. All four also take `lights`: null (the default, use the earlier single-light fields), or an array of one to ten objects. Each object takes `color` (opaque `#rrggbb`, white), `intensity` (0..100%, 80), `rotation` (-180..180 degrees, 125.26), `height` (0..90 degrees, 30), `softness` (0..100%, 0), and `behind` (boolean, false). Omitted settings use those defaults. An explicit list replaces the earlier single light; `ambient` and `shade` remain shared. Set `lights` to null to return to the single-light fields. Invalid lists, counts, keys and values are rejected before editing; malformed loaded lists fall back to the earlier light safely. All four take `shadow` (boolean, false), `shadowPosition` (`behind` or `below`), `shadowDistance` (0..100%, 0) and `shadowBounds` (10..400%, 100) ([Shadows](#shadows)); values out of range are rejected before editing.
|
||||
`threeD.extrude` and `threeD.rotate` take `graphics` ([Graphics](#graphics)): an array of up to 64 objects, each
|
||||
with `symbol` (the name of a document symbol), `face` (`front` or `back`, default `front`; `threeD.rotate` takes
|
||||
`front` only), `x` and `y` (points, default 0), `scale` (1..10000%, default 100) and `rotation` (-360..360 degrees,
|
||||
`threeD.extrude`, `threeD.rotate` and `threeD.revolve` take `graphics` ([Graphics](#graphics)): an array of up to 64 objects, each
|
||||
with `symbol` (the name of a document symbol), `face` (`front` or `back`, default `front`; `threeD.rotate` and
|
||||
`threeD.revolve` take `front` only), `x` and `y` (points, default 0), `scale` (1..10000%, default 100) and `rotation` (-360..360 degrees,
|
||||
default 0). Other keys, values out of range and graphics on the other 3D effects are rejected before editing.
|
||||
|
||||
## What differs from the public documentation
|
||||
@@ -376,11 +413,11 @@ and [Create 3D objects](https://helpx.adobe.com/illustrator/desktop/special-effe
|
||||
pages, and the archived Extrude & Bevel option list (depth 0–2,000, cap on/off, bevel height, bevel extent in or
|
||||
out, perspective). No Adobe software, assets, presets or bevel shapes were used.
|
||||
|
||||
- **Materials** (base and Adobe Substance), graphics on curved surfaces (Revolve, Inflate and Extrude & Bevel's
|
||||
walls and bevels), soft shadows, shadows of lights after the first, and **ray-traced rendering** are not built:
|
||||
shading uses directional lights, in the paint of the fill or stroke the solid is built for
|
||||
([Fills and strokes](#fills-and-strokes)), and the shadow is hard-edged ([Shadows](#shadows)). Graphics map
|
||||
onto planar faces only ([Graphics](#graphics)).
|
||||
- **Materials** (base and Adobe Substance), graphics on Inflate and on Extrude & Bevel's walls and bevels, soft
|
||||
shadows, shadows of lights after the first, and **ray-traced rendering** are not built: shading uses directional
|
||||
lights, in the paint of the fill or stroke the solid is built for ([Fills and strokes](#fills-and-strokes)), and
|
||||
the shadow is hard-edged ([Shadows](#shadows)). Graphics map onto planar faces and Revolve's side only
|
||||
([Graphics](#graphics)).
|
||||
- The bevel shapes and their names are our own; custom bevel paths are not supported.
|
||||
- Visibility is a painter's algorithm: faces of a closed solid turned away are left out, and the rest are drawn
|
||||
back to front, with a flat cap or flat back turned toward the viewer drawn after all of them. Concave solids
|
||||
|
||||
+3
-3
@@ -25,10 +25,10 @@ against Illustrator's public documentation; **estimated** unless noted.
|
||||
| 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 whose double-click on type chose the Type tool (kept until another tool is chosen or another document or window becomes active, so later edits with the Type tool return there too), or to the Selection tool when there is no such tool, as when the Type tool was chosen from the toolbar or after such a switch (#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; Type › Type Orientation sets every frame of a thread, and a thread's frames share one writing direction; 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)) |
|
||||
| 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)); a frame's empty last paragraph keeps a format given to it when the story flows again |
|
||||
| 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); Direct Selection shows the anchors and direction handles of selected type on a path's path and drags both, the brackets keeping their fractions of the path and the text reflowing along it (#3980, #3565; `text.reshapePath`, `text.setPathHandle`), as the [Direct Selection page](https://helpx.adobe.com/illustrator/using/tool-techniques/direct-selection-tool.html) describes for a path; Type › Dynamic Text (`type.dynamicText`, also on the Contextual Task Bar) sizes type on a path to fill the span between its brackets and fits it again after each edit, as the [Dynamic Text overview](https://helpx.adobe.com/photoshop/desktop/text-typography/work-with-dynamic-text/dynamic-text-overview.html) describes; the 0.1 pt steps, the 0.1 to 1,296 pt range and keeping the drawn sizes when it is turned off or threaded are VectorCraft's own rules (`crates/text/src/tests/fit.rs`, `crates/engine/src/tests/dynamic_text.rs`) |
|
||||
| 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` |
|
||||
| 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 the same Paragraph Style Options dialog as the panel menu, with General, Basic Paragraph Formats, Tabs, Composition, Hyphenation, Justification and East Asian Composition Settings. 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`, `dialogs::para_style_options::tests::every_section_draws_its_fields`, `dialogs::para_style_options::tests::tabs_section_edits_the_style_stops` |
|
||||
| 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. |
|
||||
@@ -48,7 +48,7 @@ against Illustrator's public documentation; **estimated** unless noted.
|
||||
| Hyphenation… and Justification… options | done | Eleven Indian languages use attributed patterns and preserve syllables in both composers (#4947). Hyphenation… (`ui.hyphenation`, `text.setFormat`) sets each paragraph's Words Longer Than, After First, Before Last, Hyphen Limit, Hyphenation Zone (Single-line Composer only) and Hyphenate Capitalized Words, and paragraph styles carry them (#2310). Justification… (`ui.justification`, `text.setFormat`, #2755) sets Word Spacing, Letter Spacing and Glyph Scaling (Minimum, Desired, Maximum), Auto Leading and Single Word Justification; Desired applies to every line, justified lines and the Every-line Composer use the ranges. Vertical type isn't glyph scaled; type on a path doesn't use them. Evidence: `crates/text/src/tests/justify.rs`, `dialogs::justification::tests` |
|
||||
| Roman Hanging Punctuation | done | Paragraph panel menu › Roman Hanging Punctuation, `text.setFormat {romanHangingPunctuation}` (#2756): per paragraph, Optical Margin Alignment's punctuation and amounts without the letters; paragraph styles carry it. Evidence: `tests::roman_hanging_punctuation_hangs_punctuation_but_not_letters`, `typecmd::area_tests::roman_hanging_punctuation_is_set_per_paragraph_and_saved_only_when_on` |
|
||||
| Hyphenation… and Justification… options | done | Eleven Indian languages use attributed patterns and preserve syllables in both composers (#4947). Hyphenation… (`ui.hyphenation`, `text.setFormat`) sets each paragraph's Words Longer Than, After First, Before Last, Hyphen Limit, Hyphenation Zone (Single-line Composer only) and Hyphenate Capitalized Words, and paragraph styles carry them (#2310). Justification… (`ui.justification`, `text.setFormat`, #2755) sets Word Spacing, Letter Spacing and Glyph Scaling (Minimum, Desired, Maximum), Auto Leading and Single Word Justification; Desired applies to every line, justified lines and the Every-line Composer use the ranges. Vertical type isn't glyph scaled; type on a path doesn't use them. Auto Leading also sets the Leading the Character panel shows for Auto type, the leading Alt+↑/↓ (`type.step`) steps from, per paragraph, and the lines Fill with Placeholder Text counts. Evidence: `crates/text/src/tests/justify.rs`, `dialogs::justification::tests`, `tests_prefs::auto_leading_steps_and_fills_from_the_paragraph_auto_leading`, `panels::character` test `leading_field_shows_the_paragraph_auto_leading` |
|
||||
| Tab stops and leaders; Tabs panel | partial | Tabs panel and stops with leaders in the model (`text.tabs.set`); a stop drags from where the press landed (#1458); leaders fill the tab's gap, repeated on a grid so they line up from line to line (#1877); Ctrl-dragging a stop (Command on macOS) moves all the stops together; in right-aligned area type the text before a line's last tab sits at its stops, from the left edge, and the text after it against the right edge, as Illustrator's own layout in a user's `.ai` sets a price list (evidence: `tests::right_aligned_area_type_sets_the_text_after_its_last_tab_against_the_edge`; centred and justified lines are still aligned as a whole) |
|
||||
| Tab stops and leaders; Tabs panel | partial | Tabs panel and stops with leaders in the model (`text.tabs.set`); a stop drags from where the press landed (#1458); leaders fill the tab's gap, repeated on a grid so they line up from line to line (#1877); Ctrl-dragging a stop (Command on macOS) moves all the stops together; in right-aligned area type the text before a line's last tab sits at its stops, from the left edge, and the text after it against the right edge, as Illustrator's own layout in a user's `.ai` sets a price list (evidence: `tests::right_aligned_area_type_sets_the_text_after_its_last_tab_against_the_edge`; centred lines are still aligned as a whole); in justified area type the text up to a line's last tab keeps its spacing and its tabs their stops, and the text after the last tab takes the line's room to the far edge, VectorCraft's own rule (evidence: `tests::justify::a_justified_line_with_a_tab_spreads_the_text_after_it_to_the_edge` and the other tab tests in `crates/text/src/tests/justify.rs`) |
|
||||
| Hidden characters (Show Hidden Characters) | done | `type.hiddenCharacters` |
|
||||
| Spell check (Check Spelling, Auto Spell Check, custom dictionary) | partial | the engine (#4936): `text.spelling.check` lists the unknown words of the document's type, each run in its Language, at the bytes `text.editRange` changes, and `text.spelling.suggest` gives suggestions, both from craft-proof, each paragraph on its own (English from the first dictionary it finds: a Hunspell dictionary in the user's dictionaries folder, the SCOWL dictionary built in from craft-i18n, a system Hunspell dictionary, and last the public-domain Moby word list built into it; other languages from the dictionaries craft-proof finds for them). The custom dictionary commands are done: `text.spelling.addWord`, `removeWord` and `changeWord` (Add, and Edit Custom Dictionary's Add, Delete and Change), and `text.spelling.dictionary` lists the words, saved to `Custom Dictionary.txt` beside the preferences; Ignore All: `text.spelling.ignoreAll` skips a word in the active document while it is open. Auto Spell Check is done: Edit › Spelling › Auto Spell Check (`edit.autoSpellCheck`, off at first, saved with the view settings) draws a red wavy line under the unknown words of the visible type, leaves out type with effects, and follows edits, the custom dictionary and Ignore All. A right-click on an underlined word lists the words its dictionary suggests (each replaces it in one undo step, `text.editRange`), or No Suggestions, then Ignore All and Add to Dictionary, and a right-click on type has Spelling › Auto Spell Check, checked while it is on. Edit › Edit Custom Dictionary… lists the custom dictionary's words, with an Entry field and Add, Delete and Change, applied on Done (Cancel leaves the dictionary as it was). The Check Spelling dialog remains. Evidence: `crates/engine/src/tests/spelling.rs`, `crates/ui-egui/src/canvas/tests.rs` (`auto_spell_check_*`), `crates/ui-egui/src/tests/contextmenu.rs` (the right-click), `crates/ui-egui/src/dialogs/custom_dictionary.rs` (the dialog). |
|
||||
| Smart Punctuation, Change Case, Find & Replace | done | |
|
||||
|
||||
+9
-6
@@ -161,7 +161,8 @@ tools, never checked side by side) isn't captured row by row.
|
||||
| Node-editing cursors: Direct Selection's white arrow with a hollow or filled square over an anchor (path unselected or selected); the Reshape Segment cursor over a curved segment (Direct Selection, Anchor Point, the Pen with Alt); the Anchor Point caret for the Pen with Alt; Group Selection's plus (also Direct Selection with Alt); a filled arrow while dragging that turns hollow on a snap; a double arrowhead for an Alt-drag copy | partial | as the public manual describes them, drawn in code; no cue over handles (none documented) |
|
||||
| Anchor Point and Curvature tools' own cursors | done | the caret on the anchor it converts; the pen nib with a curve badge |
|
||||
| Free Transform's Cmd/Ctrl side-shear cursor | done | two arrows passing along the side (ShearH, ShearV), instead of the resize arrow across it |
|
||||
| Cursors of their own for Lasso, Magic Wand, the freehand tools, Shaper, Live Paint Bucket, Measure, Print Tiling, the symbolism tools, vertical type, Scissors (over a segment and away), Mesh and Puppet Warp | partial | each tool returns its own cursor and Use Precise Cursors turns them into the crosshair; until they're drawn they borrow the crosshair, the I-beam, the Pen's add cursor or not-allowed |
|
||||
| Live Paint Bucket cursors | partial | a filled bucket over a face a click fills, a brush over an edge it paints, an empty bucket where it paints nothing, following Paint Fills, Paint Strokes and Shift; the Eyedropper with Alt; the crosshair with Use Precise Cursors. No cursor swatch preview |
|
||||
| Cursors of their own for Lasso, Magic Wand, the freehand tools, Shaper, Measure, Print Tiling, the symbolism tools, vertical type, Scissors (over a segment and away), Mesh and Puppet Warp | partial | each tool returns its own cursor and Use Precise Cursors turns them into the crosshair; until they're drawn they borrow the crosshair, the I-beam, the Pen's add cursor or not-allowed |
|
||||
| Blob Brush and Eraser: the tip's outline at the pointer | done | before a press and while painting, the outline of the tip (its size, angle and roundness, at the zoom) follows the pointer, black on a white halo, round a small centre dot; `[` / `]` and Tool Options change it at once; precise cursors (Caps Lock) show only the crosshair; it goes when the pointer leaves the canvas, while Cmd/Ctrl lends a selection tool and while Alt lends the Blob Brush the Smooth tool (#4977); `crates/tools/src/draw2/gesture.rs` and its tests While the button is down a round Blob Brush shows the outline of the area it will add, rounded at both ends, not a line as wide as the brush that ends square (#4343). |
|
||||
| Busy cursor during long operations | done | Background open, save and export show the system progress cursor (gap G1) |
|
||||
| Each anchor snaps to Smart Guides and construction angles | done | `DrawSnap` |
|
||||
@@ -249,7 +250,7 @@ tools, never checked side by side) isn't captured row by row.
|
||||
| A double-click on a ruler adds a guide at the pointer: a vertical one on the top ruler, a horizontal one on the left ruler (swapped in a view turned 90°, where the rulers read the other document axis; the nearer axis in between), exactly where the pointer is (no snapping), shown even with guides hidden, one undo step (`guide.add`); both clicks of the pair must be on that ruler, and the first adds nothing. The [public page on rulers](https://helpx.adobe.com/illustrator/desktop/measure-and-align/grids-and-guides/use-rulers.html) doesn't describe this gesture, so it follows the request in #5239 | done | #5239; an artboard guide with the Artboard tool, as a drag from a ruler makes one; `canvas/tests.rs` `double_clicking_a_ruler_adds_a_guide_at_that_position`, `a_canvas_click_then_a_ruler_click_adds_no_guide`, `a_ruler_double_click_follows_a_rotated_view` |
|
||||
| Escape cancels an existing ruler-guide press, move or copy | done | Selection and Direct/Group Selection; app-input regressions cover preselected guides, document/interaction-start selection, Undo/Redo and saved state, later on-canvas motion/release and temporary borrowing from idle Pen. All eight checks and the Direct Selection Escape control passed in current full CI. [Validation evidence](target-app-parity.md#evidence-what-ships-today-by-area) |
|
||||
| Ruler origin: corner drag with preview, snapped as a drawn point is (Smart Guides, Snap to Point and the ruler guides, pixels, the grid), double-click reset to the active artboard, relative X/Y fields, native save/reopen | done | #1212; `document.setRulerOrigin`, `document.resetRulerOrigin`; geometry and command coordinates stay absolute |
|
||||
| Ruler guides as Layers rows: shown, hidden, locked and deleted with their layer; rows dragged to another layer | done | `guide.setLayer`; guides from older files go on a layer |
|
||||
| Ruler guides as Layers rows: shown, hidden, locked and deleted with their layer; rows dragged to another layer; each row's own eye and lock; a row dropped on the trash deletes its guide | done | `guide.setLayer`; guides from older files go on a layer; `layer.setProps` on a guide's id hides or locks it alone; Object › Lock/Hide › Selection, Unlock All and Show All reach guides; `guide.remove {indexes}` |
|
||||
| Objects made into guides: drawn in the guide colour and style of Preferences; Lock Guides locks them too (no select, move or delete); a dragged selection snaps to ruler guides with Smart Guides on, by the nearest point of the path when pressed on its stroke or beside its edge, so the path lands exactly on the guide | done | #1534 (#1543, #1583); #3701 |
|
||||
| A selected ruler guide's X or Y in the Transform panel; typing a value moves it | not scored | #1659 (part of #1597); several guides move together; not in Properties or the Control bar. Not established by the documentation we could find: the help pages on guides, rulers and the Transform, Control and Properties panels (read again on 2026-10-14) don't describe it, and the one public statement is a user's [community answer](https://community.adobe.com/questions-652/adding-a-new-custom-guide-785586), which is not documentation. Kept as a convenience pending the owner's decision; no parity claim |
|
||||
| Alt swaps a ruler guide's orientation while dragging | missing | Alt-drag copies the selected guides ([Use rulers](https://helpx.adobe.com/illustrator/desktop/measure-and-align/grids-and-guides/use-rulers.html)); `guide.move` `{copy: true}` |
|
||||
@@ -382,7 +383,7 @@ next unit in the order a right-click on a ruler lists them, from Feet back to Po
|
||||
|---|---|---|
|
||||
| Effect > Warp Options: style previews, orientation choices and percent controls | done | #1760; focused input, mixed-style and history checks passed; original captures reviewed. No geometry or optional Properties changes. |
|
||||
| Command search: Up and Down move through the results, Enter runs the highlighted one | done | #1798 (#1757) |
|
||||
| Learn panel: Window › Learn and Explore tutorials on the app bar open it; For you holds a Quick skill guide card, Skills lists VectorCraft's own skills with tutorial counts and empty progress rings, a tutorial shows its numbered steps, Back goes up a level; a tool's name in a step is a link that marks the tool where the toolbars show it (its button, its group's flyout, a torn-off strip, a toolbar made with New Toolbar or the All Tools drawer) without choosing it | done | [the help page](https://helpx.adobe.com/illustrator/desktop/get-started/learn-the-basics/learn-skills-quick-skill-guide.html); `learn.list`, `learn.show`, `learn.locateTool`; the mark's look and 3-second lifetime are VectorCraft's own rules; `panels::learn::tests`, `toolbar::tests` |
|
||||
| Learn panel: Window › Learn and Explore tutorials on the app bar open it; For you holds a Quick skill guide card, Skills lists VectorCraft's own skills with tutorial counts and empty progress rings, a tutorial shows its numbered steps, Back goes up a level; a tool's name in a step is a link that marks the tool where the toolbars show it (its button, its group's flyout, a torn-off strip, a toolbar made with New Toolbar or the All Tools drawer) without choosing it; View more opens the tutorial's practice sample as a new untitled document, Finish tutorial then marks it finished, and Next Up shows the next tutorial in the same skill (no video) | done | [the help page](https://helpx.adobe.com/illustrator/desktop/get-started/learn-the-basics/learn-skills-quick-skill-guide.html); `learn.list`, `learn.skills`, `learn.show`, `learn.locateTool`, `learn.openSample`, `learn.finish`, `learn.next`; the mark's look and 3-second lifetime are VectorCraft's own rules; `panels::learn::tests`, `toolbar::tests` |
|
||||
| Pathfinder panel: a group selected alone counts its nested shapes, so an expanded stroked object keeps the Shape Modes enabled | done | #1642 (#1635) |
|
||||
| Selected Grid Repeat shows row, column and corner handles and spacing sliders; bounding-box handles take priority where they meet | done | #2691, `tools/src/repeat_grid.rs`; [public behavior reference](https://helpx.adobe.com/illustrator/desktop/paint-and-fill/create-and-edit-patterns/set-grid-repeat-options.html); drags preview and commit `object.repeat.options` as one undo step, Escape cancels; Radial Repeat has no handles yet |
|
||||
| Grid Repeat Options (Object › Repeat › Options…) has a Preview checkbox: the repeat on the canvas follows the fields while the dialog is open, Cancel puts the original back without a history step, OK keeps the previewed values as one undo step | done | #2651; [public behavior reference](https://helpx.adobe.com/illustrator/desktop/paint-and-fill/create-and-edit-patterns/set-grid-repeat-options.html) lists the Preview option for the grid options only, so Radial and Mirror Repeat Options have none; `dialogs/command.rs` tests |
|
||||
@@ -424,7 +425,7 @@ next unit in the order a right-click on a ruler lists them, from Feet back to Po
|
||||
| Attributes fill-rule controls with a compound member selected | done | Edits the compound's rule; direction still edits only the member; rendered-hole and Undo/Redo regression tests (#1197) |
|
||||
| Make Compound Path on a group (such as outlined type) keeps its backmost path's paint; compound paths joined into one keep their holes | done | #1537 |
|
||||
| Symbol libraries: Window › Symbol Libraries (Basic Shapes, UI Frames, Map Markers, Inventory Icons, Skill Icons, 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`; five built-in libraries (Basic Shapes, UI Frames with default 9-slice, Map Markers, Inventory Icons, Skill Icons; 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) |
|
||||
| Brush libraries: Window › Brush Libraries (Art Ribbons, Ink and Wash, Calligraphic Nibs, Bristle Brushes, Pattern Borders, Scatter Shapes, Game Trails, Energy Beams, Dry Media, 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`; nine 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; 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) |
|
||||
@@ -436,7 +437,7 @@ next unit in the order a right-click on a ruler lists them, from Feet back to Po
|
||||
| Canvas context menu | done | Layers rows, panels and type have none (gap) |
|
||||
| SVG Interactivity panel: JavaScript for each object's events and the document's linked JavaScript files, written to SVG and read back as text | done | `svgInteractivity.*`, `ui.javascriptFilesDialog` |
|
||||
| Retype, Comments, Version History panels | missing | the last two are cloud features (out of scope) |
|
||||
| Blend panel (30.7) | partial | Window › Blend provides Type (Ease In, Ease Out, Ease In Out, Ease Out In), Ramp 0–100% and independent color Shift, alongside the existing blend controls. Easing is disabled without a spine. Original polynomial distributions approximate the publicly documented behavior; on-canvas easing handles remain missing. [Public source](https://helpx.adobe.com/illustrator/desktop/manage-colors/apply-transparency-and-blending/blend-panel-overview.html) |
|
||||
| Blend panel (30.7) | partial | Window › Blend provides Type (Ease In, Ease Out, Ease In Out, Ease Out In), Ramp 0–100% and independent color Shift, alongside the existing blend controls. Easing is disabled without a spine. Original polynomial distributions approximate the publicly documented behavior. On-canvas Appearance and Easing widgets set Shift and Ramp; a blend without a spine shows the Appearance widget alone. [Public source](https://helpx.adobe.com/illustrator/desktop/manage-colors/apply-transparency-and-blending/blend-panel-overview.html) |
|
||||
| Gradient panel: Dither (30.0) | done | Dither box under the stops (`paint.editGradient` `dither`); dimmed behind the Stroke proxy, fills only; `panels::gradient` test |
|
||||
| Gradient panel: Method, Classic or Perceptual (30.0) | done | Method menu under the Stroke buttons for linear and radial gradients (`paint.editGradient` `method`); [public source](https://helpx.adobe.com/illustrator/desktop/paint-and-fill/create-and-edit-gradients/control-perceptual-interpolation-in-gradients.html); `panels::gradient` test |
|
||||
| Gradient panel: Presets (30.0) | done | Presets menu by library (theme) plus Saved: applies a preset to the gradient behind the active proxy, keeping its placement, one undo step; panel menu Save Gradient Preset…, Delete Gradient Preset, Hide/Show Presets (`gradient.presets.*`); `panels::gradient` tests |
|
||||
@@ -479,7 +480,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` |
|
||||
| Style panels: a double-click on a user character style's row opens its Character Style Options, and on a paragraph style's row opens the same Paragraph Style Options as the panel menu, with General, Basic Paragraph Formats, Tabs, Composition, Hyphenation, Justification and East Asian Composition Settings; 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.paraStyleOptions` (`paraStyle.edit`); `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`, `dialogs::para_style_options::tests::every_section_draws_its_fields`, `dialogs::para_style_options::tests::tabs_section_edits_the_style_stops` |
|
||||
|
||||
## Look and feel
|
||||
|
||||
@@ -489,6 +490,8 @@ next unit in the order a right-click on a ruler lists them, from Feet back to Po
|
||||
|
||||
- [x] Recolor Artwork › Color Theme Picker: with the button beside the tabs on, a click on the canvas takes the color palette of an object or image, a drag takes the palette of the art inside its marquee, and Shift adds more picks; the rows that aren't excluded take the palette as their new colors and the art previews them ([Recolor artwork](https://helpx.adobe.com/illustrator/desktop/manage-colors/modify-colors/recolor-artwork.html)). The number and order of the picked colors are VectorCraft's own rule (`recolor.pickTheme`). Tests: `theme_picks_give_the_rows_the_palette_of_the_art_picked` and `the_theme_picker_takes_clicks_and_shift_drags_on_the_canvas` in `crates/ui-egui/src/dialogs/recolor.rs`, `theme_picker_*` in `crates/engine/src/tests/recolor.rs`.
|
||||
|
||||
- [x] Recolor Artwork › Prominent Colors: with art, a bar under the Edit tab's wheel shows the new colors, each as wide as its share of the art; dragging the edge between two parts raises one color's weight and lowers the other's, and the art previews the result; the New Color Group menu has Save All Colors and Save Prominent Colors ([Recolor options overview](https://helpx.adobe.com/illustrator/desktop/manage-colors/modify-colors/recolor-options-overview.html)). How a share is measured and how a weight moves colors between rows are VectorCraft's own rules (`recolor.weigh`). Tests: `weights_move_the_rows_colors_and_the_art_previews_them`, `dragging_a_prominent_edge_moves_colors_between_rows` and `save_all_and_prominent_colors_make_color_groups` in `crates/ui-egui/src/dialogs/recolor.rs`, `weigh_*` in `crates/engine/src/tests/recolor.rs`.
|
||||
|
||||
- [x] Recolor Artwork Edit color chips scroll within the screen, preserving the wheel and actions (#3416); 5, 20, 200 and 400 colors, resizing and UI scaling, final-chip editing and preview/history covered by egui_kittest.
|
||||
|
||||
- [x] Status messages and bounded readouts remain stable as values, canvas hover and background jobs change; ordinary values fit all registered languages and units, and optional groups yield in narrow windows (regressions; contributor rebuilt and confirmed the original-file status-bar scenario on 2026-10-19). Sample widths are cached per UI and refreshed only when language, document units or pixels per point changes.
|
||||
|
||||
Reference in New Issue
Block a user