mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-15 11:16:25 +00:00
Merge upstream main into pencil-no-guides
# Conflicts: # crates/tools/src/draw2/gesture/tests.rs # docs/target-app-parity.md
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# 3D lighting performance
|
||||
|
||||
Measured 2026-10-17 for PR #2706 on one macOS machine.
|
||||
Measured 2026-10-17 for PR #2706 on one macOS machine (an Apple M1 Pro, below); the round seam joins on 2026-11-12 on another (an Apple M4 Pro, in their own section).
|
||||
|
||||
## Method
|
||||
|
||||
@@ -34,6 +34,8 @@ vectorcraft-cli perf
|
||||
|
||||
## Measurements
|
||||
|
||||
Only the legacy white-light row and the white-light comparison below are affected by the round seam joins of 2026-11-12: they were measured on 2026-10-17, and colored-light seams were already round; see [Round seam joins](#round-seam-joins).
|
||||
|
||||
Milliseconds per frame, medians of three five-frame averages. `8` is the CLI default thread count on this machine; `0` selects the single-thread renderer.
|
||||
|
||||
| Inflate scene | Before, 8 | After, 8 | Before, 0 | After, 0 |
|
||||
@@ -66,10 +68,42 @@ The colored fixture uses the same projected mesh before and after. The solid-fil
|
||||
|
||||
For a smooth colored solid fill, all facets share one compound coverage clip and three isolated channel groups. Each channel has an opaque black backdrop; Screen combines the disjoint RGB channels and Multiply applies the source color. Face order is retained in each channel. Surface opacity and outer coverage apply once. The group/clip counts are independent of triangle count, and export remains vector artwork.
|
||||
|
||||
Source gradients retain their independently placed per-facet vector compositor. They remain a more expensive case. Patterns retain their neutral shading approximation. White-light Inflate uses the original polygon shading, paint composition and default seam joins; the seam width retains its 0.05 to 0.75 pt bounds.
|
||||
Source gradients retain their independently placed per-facet vector compositor. They remain a more expensive case. Patterns retain their neutral shading approximation. White-light Inflate uses the original polygon shading and paint composition; the seam width retains its 0.05 to 0.75 pt bounds. Its seams kept the default Miter Join until 2026-11-12, when every 3D seam took round joins (a mitered seam drew thorns past facets seen almost edge-on), so white-light output is no longer identical to the comparison below.
|
||||
|
||||
Geometry/effects tests cover legacy polygons and seam bounds, shared smooth normals, finite ramps, holes and constant group/clip counts. Engine tests cover the batched SVG round trip, vector PDF, expansion, undo, compound holes and surface opacity.
|
||||
|
||||
## Legacy white-light comparison
|
||||
|
||||
Four original synthetic scenes were exported at 1200 x 1200 from unchanged main `f7de3d6a` and the updated implementation. The PNG files match byte for byte in all four cases: the legacy white-lit ellipse above; the same ellipse with both sides, hollow cap, twist 60 degrees, taper 70%, perspective 80 degrees and view Y rotation 145 degrees; an unshaded ellipse; and the transparent source gradient above under the legacy white light. The command recipe was also checked against the measured colored fixture's image pixels.
|
||||
Four original synthetic scenes were exported at 1200 x 1200 from unchanged main `f7de3d6a` and the updated implementation. The PNG files matched (2026-10-17) byte for byte in all four cases: the legacy white-lit ellipse above; the same ellipse with both sides, hollow cap, twist 60 degrees, taper 70%, perspective 80 degrees and view Y rotation 145 degrees; an unshaded ellipse; and the transparent source gradient above under the legacy white light. The command recipe was also checked against the measured colored fixture's image pixels.
|
||||
|
||||
## Round seam joins
|
||||
|
||||
Measured once, on 2026-11-12, on another machine (an Apple M4 Pro with 14 cores) that was not idle: its one-minute load average was 6 to 13, so these are one loaded run, not the idle measurements above. Two `vectorcraft-cli` builds, each in release (`cargo build --release -p vectorcraft-cli`): main at `6d6bbff53`, and that commit with the round seam joins, run in turn, three times each. The measurement predates the change's rebase onto a main whose Rotate (Classic) and Revolve (Classic) draw their faces through Classic's surfaces, so it does not cover their seams. `bench` fits the artboard to 95% of 2880 x 1800 pixels, draws one frame to warm each renderer and reports the average of the frames after it: `threads 8` with the renderer's default workers (one per core it may use, up to 8, one core left free), `threads 0` on the calling thread alone. A cold frame is a whole `run` that opens the scene, builds its 3D art and draws it once.
|
||||
|
||||
White light: extruded type with a cove bevel, an Inflate, an Extrude & Bevel (Classic) star with a classic bevel and a Revolve, no strokes (6,283 nodes drawn). The median of three runs of 20 frames, on 8 threads and on one: main 8.0 ms and 18.3 ms; with the round joins 7.5 ms and 17.7 ms. Cold frames took 0.08 s of processor time on each. The differences are within noise for one loaded run. Not measured: `vectorcraft-cli perf`, the legacy white-light Inflate row above (still the 2026-10-17 figures), frames whose 3D art is rebuilt (while dragging a 3D slider, say) apart from the cold run, and SVG/PDF exports.
|
||||
|
||||
```
|
||||
{"command":"file.new","params":{"width":800,"height":600}}
|
||||
{"command":"text.create","params":{"x":40,"y":120,"text":"SAMPLE TYPE","size":64,"font":"Source Sans 3","color":"#3366cc"}}
|
||||
{"command":"effect.apply","params":{"effect":"threeD.extrude","item":null,"params":{"depth":40,"rotationX":-35,"rotationY":25,"taper":47.5,"bevel":"cove","bevelHeight":2}}}
|
||||
{"command":"path.create","params":{"d":"M100 300C100 245 145 200 200 200C255 200 300 245 300 300C300 355 255 400 200 400C145 400 100 355 100 300Z"}}
|
||||
{"command":"paint.setFill","params":{"color":"#cc6633"}}
|
||||
{"command":"paint.setStroke","params":{"none":true}}
|
||||
{"command":"effect.apply","params":{"effect":"threeD.inflate","item":null,"params":{}}}
|
||||
{"command":"path.create","params":{"d":"M400 200L440 280L520 290L460 340L480 420L400 380L320 420L340 340L280 290L360 280Z"}}
|
||||
{"command":"paint.setFill","params":{"color":"#33aa66"}}
|
||||
{"command":"paint.setStroke","params":{"none":true}}
|
||||
{"command":"effect.apply","params":{"effect":"threeD.classicExtrude","item":null,"params":{"depth":50,"bevel":"classic","bevelHeight":4,"rotationX":80,"rotationY":10}}}
|
||||
{"command":"path.create","params":{"d":"M600 200L640 200L660 300L640 400L600 400Z"}}
|
||||
{"command":"paint.setFill","params":{"color":"#aa33aa"}}
|
||||
{"command":"paint.setStroke","params":{"none":true}}
|
||||
{"command":"effect.apply","params":{"effect":"threeD.revolve","item":null,"params":{}}}
|
||||
```
|
||||
|
||||
The type is set in Source Sans 3, which a build has only with craft-fonts (`CRAFT_FONTS_DIR`, see `docs/development.md` › Fonts); without it the type falls back to another face. To reproduce, save the commands as `scene.jsonl` and, with each build:
|
||||
|
||||
```
|
||||
vectorcraft-cli run --commands scene.jsonl --export scene.vectorcraft
|
||||
vectorcraft-cli bench scene.vectorcraft --iters 20
|
||||
/usr/bin/time -p vectorcraft-cli run --in scene.vectorcraft --export scene.png
|
||||
```
|
||||
|
||||
@@ -107,7 +107,7 @@ the two can still win that race.
|
||||
| `ui.render` | `{path?, scale?, artboard?, data?, traceViews?}` | render an artboard headlessly (PNG with the pixels of `app.export {format: "png", background: "white"}` at the same scale; `artboard`: its 0-based index, default the first; `traceViews: true`: Image Trace objects draw in their View, as on the canvas, instead of their tracing result): written to `path`, else (or with `data: true` as well) sent back as `pngBase64` |
|
||||
| `ui.render` | `{path?, scale?, artboard?, data?}` | render an artboard headlessly (PNG with the pixels of `app.export {format: "png", background: "white"}` at the same scale; `artboard`: its 0-based index, default the first): written to `path`, else (or with `data: true` as well) sent back as `pngBase64` |
|
||||
| `ui.resize` / `ui.focus` | | |
|
||||
| `app.open` / `app.save` / `app.export` / `app.quit` | `{path, importer?, params?}` / `{path?}` / `{path?, format?, artboard?, range?, scale?, …}` | `app.open` reads every format `document.open` reads (see `document.formats`) and returns its result (`{index, title, format, warnings, …}`; `warnings` say what didn't come in as it was, such as an EPS shown as its preview image and why its PostScript couldn't be read), or null when a dialog asks first or a library loads. The status bar (`ui.inspect` → `ui.status`) counts the `warnings` and names the first that says reading the file left something out (the notes that make Save ask before writing over it), else the first; with several, hovering it lists them in that order, as many as fit in the window (at most 30), then how many more. After `app.save`, and `app.export` with a `path`, the status bar counts the reply's `warnings` and names the first, and with several, hovering it lists them in the reply's order (a save's notes start with what the format loses). With `importer` (an importer plug-in's format id, `plugin.<id>`) it runs `file.openWith`: the file opens with that importer, also when a built-in format reads its extension, with the importer's parameters `params` (their defaults when omitted; no dialog asks for them). Without `importer`, `params` go to the importer that opens the file, and a built-in format does not read them. `app.export` encodes through the engine's `document.export` (same options; the document keeps its path) and writes `path` through the host; without `path` it returns `{dataBase64, format, bytes}`, as headless mode does. It refuses a key that no format takes, and an unknown key inside a PDF or EPS option object, before it writes anything (`docs/mcp.md`, Parameter keys). It accepts a key that only another format takes and does not use it: the reply's `warnings` and the status bar name the key ("`quality` was not used: PDF files don't read it"). `app.save` refuses a key that no save format takes, beside the path or in `options`, the same way. `app.quit`, `file.close` and `file.closeAll` first open a `saveChanges` dialog for each modified document (they return `{"pending": "saveChanges"}`): `ui.dialog.confirm` saves, `ui.dialog.set {field: "discard", value: true}` then confirm discards, `ui.dialog.cancel` cancels the whole close or quit |
|
||||
| `app.open` / `app.save` / `app.export` / `app.quit` | `{path, importer?, params?}` / `{path?}` / `{path?, format?, artboard?, range?, scale?, …}` | `app.open` reads every format `document.open` reads (see `document.formats`) and returns its result (`{index, title, format, warnings, …}`; `warnings` say what didn't come in as it was, such as an EPS shown as its preview image and why its PostScript couldn't be read), or null when a dialog asks first or a library loads. The status bar (`ui.inspect` → `ui.status`), after a line about the document's linked files when there is one (Missing linked files below), counts the `warnings` and names the first that says reading the file left something out (the notes that make Save ask before writing over it), else the first; with several, hovering it lists them in that order, as many as fit in the window (at most 30), then how many more. After `app.save`, and `app.export` with a `path`, the status bar counts the reply's `warnings` and names the first, and with several, hovering it lists them in the reply's order (a save's notes start with what the format loses). With `importer` (an importer plug-in's format id, `plugin.<id>`) it runs `file.openWith`: the file opens with that importer, also when a built-in format reads its extension, with the importer's parameters `params` (their defaults when omitted; no dialog asks for them). Without `importer`, `params` go to the importer that opens the file, and a built-in format does not read them. `app.export` encodes through the engine's `document.export` (same options; the document keeps its path) and writes `path` through the host; without `path` it returns `{dataBase64, format, bytes}`, as headless mode does. It refuses a key that no format takes, and an unknown key inside a PDF or EPS option object, before it writes anything (`docs/mcp.md`, Parameter keys). It accepts a key that only another format takes and does not use it: the reply's `warnings` and the status bar name the key ("`quality` was not used: PDF files don't read it"). `app.save` refuses a key that no save format takes, beside the path or in `options`, the same way. `app.quit`, `file.close` and `file.closeAll` first open a `saveChanges` dialog for each modified document (they return `{"pending": "saveChanges"}`): `ui.dialog.confirm` saves, `ui.dialog.set {field: "discard", value: true}` then confirm discards, `ui.dialog.cancel` cancels the whole close or quit |
|
||||
| `app.export` with `useArtboards` | `{path, useArtboards: true, range? \| artboards?, …}` | Export As: PNG, JPEG and WebP write one file per chosen artboard (default all; SVG does so for a `range`), `<path stem>-<artboard>.<ext>`, and return `{path, files: [path…]}`; a PDF keeps them as pages of `path`. `useArtboards: false` covers the bounds of the visible art. The menu's Export As… is `file.exportAs`: the `exportAs` dialog (`format`, `useArtboards`, `all`, `range`), then a save dialog and the format's options: `pngOptions` / `jpgOptions` / `webpOptions`, `svgOptions`, or `savePdf` for a PDF |
|
||||
| `ui.dialog.*` on `gradientStop` | `{field: "color" \| "opacity" \| "location", value}` | double-clicking a stop on the Gradient tool's annotator opens its popover (fields `index`, `x`, `y`, `tab`); set `color` (hex), `opacity` or `location` (percentages) and `ui.dialog.confirm` to apply them to the selected stop. `gradient.selectStop {index}` picks the stop the annotator, the panels and Delete/←/→ (`ui.key`) act on |
|
||||
| `engine.execute` `ui.savePdfDialog` | `{path?, preset?, range?, …document.exportPdf options}` | opens the Save PDF dialog (`file.export.pdf` with no params opens it too). Its fields are the `document.exportPdf` options: set `compatibility` with `ui.dialog.set {field: "compatibility", value: "1.5"}`, a whole section with `{field: "compression", value: {…}}`, the artboards with `__allArtboards: false` and `range`, the visible section with `__section` (General, Compression, Marks and Bleeds, Output, Advanced, Security, Summary). `useArtboards: false` opens it for one page of the visible art's bounds, as Export As with Use Artboards off does: the dialog has no Artboards section and its `__artBounds` field is true. `ui.dialog.confirm` writes `path` (else asks for one), returns `{path, bytes, warnings}` and opens the file when `viewAfterSaving` is set. With `useArtboards: false` it writes the page as `app.export` does and returns `{path, warnings}`, or `{background: true, status}` while Background Export writes it |
|
||||
@@ -648,7 +648,7 @@ agents) opens the `rasterEffectsSettings` dialog. Its fields are what `document.
|
||||
|
||||
Missing linked files: `app.open` of a document whose linked images' files can't be found (`document.open`'s
|
||||
`missingLinks`) opens the `missingLinks` dialog for the first (fields `missing`: `[{name, path, ids}]`, `modified`,
|
||||
`applyToAll`, `path`). `ui.dialog.set {field: "path", value}` then `ui.dialog.confirm` replaces it with that file
|
||||
`notes` (the open's `warnings`), `applyToAll`, `path`). `ui.dialog.set {field: "path", value}` then `ui.dialog.confirm` replaces it with that file
|
||||
(`links.relink`; without `path` a file is picked), and with `applyToAll` the others are looked for by name in the same
|
||||
folder; `ui.dialog.set {field: "discard", value: true}` then confirm ignores it (the images keep their preview), with
|
||||
`applyToAll` the rest too. The next missing file is asked about after each answer; `ui.dialog.cancel` stops asking.
|
||||
@@ -656,11 +656,14 @@ Then, with the preference `updateLinks: "askWhenModified"`, modified linked file
|
||||
`confirm` dialog whose `ui.dialog.confirm` runs `links.update`. The same happens when the app's window comes back to
|
||||
the front and a linked file of the active document changed meanwhile (asked once per change of a file); with
|
||||
`"automatically"` the files are read again at once, with `"manually"` the Links panel shows them as modified.
|
||||
After an open, the status bar's line about modified files (with `"manually"`) or, on the web, about files that can't
|
||||
be read comes first, followed by the line that counts the open's `warnings`; hovering it lists them as for any open.
|
||||
When the line about modified files follows the `missingLinks` dialog, it is followed by that dialog's `notes`.
|
||||
|
||||
Find Linked Files: in the `missingLinks` dialog, `ui.dialog.set {field: "searchFolder", value}` then `ui.dialog.confirm`
|
||||
is Find in Folder…: the dialog becomes `findLinks`, which looks in that folder and its subfolders for every file the
|
||||
dialog still asks about (`links.findFiles`). Fields: `document` (the document's uid), `missing` (`[{name, path, ids}]`),
|
||||
`modified`, `back`, `state` (empty, `searching`, `done`, `stopped` or `failed`), `search` (the search's `id`), `folder`,
|
||||
`modified`, `notes` (from `missingLinks`), `back`, `state` (empty, `searching`, `done`, `stopped` or `failed`), `search` (the search's `id`), `folder`,
|
||||
`found` (`links.findFiles`'s `links`, with the files found), `searched`, `skipped`, `unreadable`, `stopped`, `error`,
|
||||
`picks` (the file chosen for each row of `missing`, or null; with each search result, a row not chosen in the dialog
|
||||
gets its only same file, else its only file found), `touched` (the rows whose file was chosen in the dialog; search
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Effects parity
|
||||
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-10 · **Change:** minor (Effect Gallery: a thumbnail for each filter and an in-dialog preview on an original drawing; the 1–2 h for those is done; Extrude & Bevel, Inflate and Rotate merge contours that cross, touch or overlap, as type often draws a glyph, before building a solid; previously: Extrude & Bevel, Inflate and Rotate apply to groups and layers, their objects turning about one shared axis (#4506); the Transform effect's copies of a path with a fill and a stroke (or several fills and strokes, an even-odd fill, or a partly transparent one) are drawn each above the one before, as Expand Appearance makes them (#5920); Expand Appearance makes each copy of a path's Transform effect an object of its own (#5612); previously: Pixelate › Color Halftone: Max Radius in pixels of the Document Raster Effects resolution, 4–127 px, with older documents converted on opening and radii written back in points for older app versions (#3260); Effect dialogs clamp bounded length inputs immediately on commit and flash rejection on invalid input (#4638); previously: Drop Shadow Darkness uses fixed RGB subtraction and CMYK black addition; scores unchanged; Pathfinder › Trap: the Pathfinder panel's Trap… and Effect › Pathfinder › Trap… add an overprinting strip of the lighter colour where two solid colours meet; recounted with Hard Mix (#3061) and Soft Mix already in the catalogue: Pathfinder 13/13, Illustrator effects 49/50) · **Target:** Adobe Illustrator 2026 (30.x)
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-12 · **Change:** minor (Extrude & Bevel, Inflate and Rotate seams have round joins under a white light and in the 3D (Classic) effects too, no longer reaching past the solid as thorns; previously: Effect Gallery: a thumbnail for each filter and an in-dialog preview on an original drawing; the 1–2 h for those is done; Extrude & Bevel, Inflate and Rotate merge contours that cross, touch or overlap, as type often draws a glyph, before building a solid; previously: Extrude & Bevel, Inflate and Rotate apply to groups and layers, their objects turning about one shared axis (#4506); the Transform effect's copies of a path with a fill and a stroke (or several fills and strokes, an even-odd fill, or a partly transparent one) are drawn each above the one before, as Expand Appearance makes them (#5920); Expand Appearance makes each copy of a path's Transform effect an object of its own (#5612); previously: Pixelate › Color Halftone: Max Radius in pixels of the Document Raster Effects resolution, 4–127 px, with older documents converted on opening and radii written back in points for older app versions (#3260); Effect dialogs clamp bounded length inputs immediately on commit and flash rejection on invalid input (#4638); previously: Drop Shadow Darkness uses fixed RGB subtraction and CMYK black addition; scores unchanged; Pathfinder › Trap: the Pathfinder panel's Trap… and Effect › Pathfinder › Trap… add an overprinting strip of the lighter colour where two solid colours meet; recounted with Hard Mix (#3061) and Soft Mix already in the catalogue: Pathfinder 13/13, Illustrator effects 49/50) · **Target:** Adobe Illustrator 2026 (30.x)
|
||||
|
||||
Every entry of Illustrator's Effect menu, by its public feature name, against VectorCraft's effects catalogue
|
||||
(`effect_catalog()` in `crates/effects/src/lib.rs`) and the Effect menu built from it
|
||||
@@ -179,9 +179,9 @@ VectorCraft choices; an original approximation, never compared with another appl
|
||||
| Item | Ours |
|
||||
|---|---|
|
||||
| Revolve | initial: live, editable profile, rotation and light gizmos, default-on Cap with continuous curved rims, smooth vector shading and round seam joins, SVG/PDF output, Expand Appearance ([revolve.md](revolve.md), #846) |
|
||||
| Extrude & Bevel, Inflate, Rotate | initial: live, depth, twist, taper, solid or hollow caps, five original bevel shapes, Inflate volume, both sides, twist, taper and cap, Rotate of every fill and stroke, groups and layers turned about one shared axis (#4506), 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)) |
|
||||
| Extrude & Bevel, Inflate, Rotate | initial: live, round seam joins, 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, 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 |
|
||||
| 3D (Classic): Extrude & Bevel, Revolve, Rotate | Extrude & Bevel (Classic) initial: live, round seam joins, 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, round seam joins, 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, round seam joins, 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)) |
|
||||
|
||||
@@ -193,6 +193,7 @@ angular cut caps, exact visibility, the rest of 3D Classic (Map Art), Turntable)
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-11-12 | minor | The seams of Extrude & Bevel, Inflate and Rotate under a white light, and of the faces of Extrude & Bevel (Classic), Revolve (Classic) and Rotate (Classic), went from miter to round joins (the seams of Revolve and of colored lights, and 3D (Classic) Wireframe edges, were already round): no thorns on edge-on facets, and facets with no neighbor now have rounded convex corners ([three-d.md](three-d.md#seams)); scores and estimates unchanged |
|
||||
| 2026-11-10 | minor | Effect Gallery: each filter has a thumbnail, and the dialog has a preview of the visible stack (or the browsed filter when the stack is empty). Both are an original landscape drawing passed through the filter ([Filter Gallery overview](https://helpx.adobe.com/photoshop/desktop/effects-filters/get-started-with-filters/filter-gallery.html)). The canvas preview and one-undo OK are unchanged. Remaining hours for the gallery's thumbnails and in-dialog preview: 1–2 → none. Counts unchanged (57/57). |
|
||||
| 2026-11-08 | minor | Extrude & Bevel, Inflate and Rotate merge contours that cross, touch or overlap (a glyph's arm across its stem) before building a solid, so the solid follows the shape as it is filled; others are built as drawn ([three-d.md](three-d.md)); scores and estimates unchanged |
|
||||
| 2026-11-06 | minor | Extrude & Bevel, Inflate and Rotate apply to a group or layer: a solid for every path, compound path and type in it, all turned about one shared axis as the public documentation describes for groups ([three-d.md](three-d.md#groups), #4506); scores and estimates unchanged |
|
||||
|
||||
File diff suppressed because one or more lines are too long
+5
-4
File diff suppressed because one or more lines are too long
@@ -28,7 +28,7 @@ It reads the pen's tilt and barrel rotation on macOS and on Linux under X11 and
|
||||
| Trackpad (smooth scroll, pinch) | yes | yes | precision touchpads | yes | yes | done |
|
||||
| HiDPI / Retina, per-monitor scale | yes | yes | yes | yes | yes | done; a window dragged between monitors of different scale can still grow on Windows (#1459, open); the custom title bar's window on Windows stays truly borderless so the pointer lines up with what is drawn (#1791, #1758; awaiting the reporter's confirmation) ; macOS cursors use aligned 1×/2× native image representations (#2292), covered by headless construction tests; mixed-display transitions and physical cursor sizing remain unverified, no additional hardware validated |
|
||||
| Multiple monitors: panels and document windows on another screen | yes | no (one OS window) | no | no | — | missing: 6–10 h (with multiple windows, gap G7) |
|
||||
| Display colour profile (proof and display through the monitor's ICC) | yes | no | no | no | — | missing: 3–5 h |
|
||||
| Display colour profile (proof and display through the monitor's ICC) | yes | yes: the window is tagged sRGB and macOS converts it | yes: the display's default ICC profile, Windows' own conversion with Advanced Color on | X11: colord or `_ICC_PROFILE`; Wayland: sRGB | — | done on macOS, Windows and X11; Wayland and floating document windows remain |
|
||||
| 3D GPU rendering (Materials, ray tracing) | yes | — | — | — | — | blocked on 3D (gap G3) |
|
||||
|
||||
## Revision history
|
||||
|
||||
@@ -86,7 +86,19 @@ size. Raster exports with Art Optimized anti-aliasing, the default, do not show
|
||||
pixels and 16,384 pixels on a side. A raster export shows the line as the canvas does when it uses
|
||||
Type Optimized anti-aliasing, or when it uses Art Optimized and is larger than either limit.
|
||||
Overlapping stacks the colors instead: a lower color continues under the edge of the color above it,
|
||||
and no background shows along that edge.
|
||||
and no background shows along that edge. With Fills and without Create Strokes, Overlapping also
|
||||
follows a fill rule of VectorCraft's own: each shape is filled whole, and the area of other colors
|
||||
that a shape encloses is traced again as shapes of its own and stacked above it. Each enclosed
|
||||
outline is then fitted once. The [Image Trace presets](https://helpx.adobe.com/illustrator/desktop/manage-objects/traces-mockups-symbols/image-trace-presets.html)
|
||||
page describes Overlapping as stacking shapes where it can and overlapping their edges elsewhere. A
|
||||
shape keeps a hole where the enclosed area holds a transparent pixel or a color that Ignore Color or
|
||||
Keep Colors leaves out. A hole smaller than Noise is filled with the shape's own color, as before.
|
||||
The pixels of an area inside other areas are scanned once more for each area around it, within a
|
||||
work budget of VectorCraft's own: four times the image's pixels (counted as at least 65,536) times
|
||||
its colors, with each area costing its bounding box times the colors in it. An area that costs more
|
||||
than what is left of the budget keeps its holes and is not charged, so a smaller area after it can
|
||||
still be filled.
|
||||
With Create Strokes, or without Fills, shapes keep their holes.
|
||||
|
||||
**Flat Logo with named colors.** With `logoColors` named, Flat Logo decides whether the image is flat
|
||||
art by the image's own colors. It finds them the same way as when no colors are named, and looks for as
|
||||
|
||||
+118
-9
@@ -762,8 +762,7 @@ outline, so these commands do not store a stroke paint or weight for a series th
|
||||
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.
|
||||
even when it is hidden, and store a stroke set on a band.
|
||||
|
||||
`appearance.addFill`, `appearance.addStroke`, `appearance.setItem`, `appearance.removeItem`,
|
||||
`appearance.duplicateItem`, `appearance.moveItem`, `appearance.clear`, `appearance.reduceToBasic`,
|
||||
@@ -789,6 +788,21 @@ The other commands given a series group's id edit the group itself, and the grap
|
||||
`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.
|
||||
|
||||
The graph also stores a paint or stroke weight that one of these commands changes on the topmost visible fill or stroke
|
||||
of a path directly in a series: a weight set with `stroke.set`, `stroke.weightUp` or `stroke.weightDown`; a gradient
|
||||
made, placed or edited with `paint.editGradient`, `paint.setGradientGeom`, `paint.freeform.addPoint`,
|
||||
`paint.freeform.setPoint`, `paint.freeform.deletePoint`, `paint.freeform.addLine` or `paint.freeform.splitLine`; and a
|
||||
color changed by `paint.invert`, `paint.complement`, `edit.colors.invert`, `edit.colors.adjustBalance`,
|
||||
`edit.colors.saturate`, `edit.colors.toCMYK`, `edit.colors.toGrayscale`, `edit.colors.toRGB`,
|
||||
`edit.colors.blendFrontToBack`, `edit.colors.blendHorizontally`, `edit.colors.blendVertically`, `recolor.apply`,
|
||||
`addon.color.filter`, `addon.color.applyNearestSwatch` or the ink limit of `addon.color.printFixes`. The recolor
|
||||
commands store it too when they are given a series group, the graph or a group that holds the graph. A row a command
|
||||
leaves as it was keeps what the graph stores. When one command changes several paths of a series, the frontmost of
|
||||
them sets what the graph stores. A gradient is stored with its placement, and every path of the series takes that
|
||||
placement when the graph is drawn again. The graph does not store a stroke's dashes, caps, joins, arrowheads, width
|
||||
profile or brush. These commands do not store the colors they give a graph's axes and labels, which are drawn again
|
||||
with the paint they had.
|
||||
|
||||
`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
|
||||
kind takes them when the graph is drawn again. The graph saves the paragraph attributes as `valuesPara`,
|
||||
@@ -3015,7 +3029,10 @@ already walks Image Trace. Short agent entry points:
|
||||
is unused, and offers Remove Strokes or Cancel when one of them is in use.
|
||||
- Brushes: `brush.list`, `brush.get {name}`, `brush.apply {name, ids?}`, `brush.new {type, name?, params?, ids?}`,
|
||||
`brush.setCurrent {name}`, `brush.options {name, params?, newName?}`, `brush.delete {name} | {names}`,
|
||||
`brush.duplicate {name, newName?} | {names}`, `brush.freehand`, `object.expandBrush {ids?}`. `brush.new`,
|
||||
`brush.duplicate {name, newName?} | {names}`, `brush.freehand`, `object.expandBrush {ids?}`. A document or brush
|
||||
library file whose brushes repeat a name is read with the first brush of that name as stored and each later one
|
||||
numbered with the first "`<name>` 2", "`<name>` 3"… the file does not have; strokes of the name keep the first
|
||||
brush. `brush.new`,
|
||||
`brush.duplicate` and `brush.options` trim the white space around the name they are given. A blank `name` gives
|
||||
the type's default name ("New Calligraphic Brush" for a calligraphic brush), and a blank `newName` gives
|
||||
"`<name>` copy" in `brush.duplicate` and keeps the name in `brush.options`. A Hue Shift `colorization` given to
|
||||
@@ -5290,6 +5307,13 @@ box is; without `from`, that box is the selection's bounds measured in the turne
|
||||
number is an error. Without `angle`, `from` is a box on the page, as before. The Free Transform tool's Perspective Distort and Free Distort send the selection's turned box
|
||||
this way, so after a rotation they start from the corners the canvas shows.
|
||||
|
||||
After the warp, each warped object's bounding box stands at the angle the warp turns the object's own x axis to at
|
||||
the object's center, as measured before the warp. This covers the objects inside a warped group, compound path or clip
|
||||
group, each at its own center, and the art of a linked opacity mask; an unlinked mask's art keeps its angle. A warp
|
||||
that mirrors the object keeps the angle nearer the old one, and an object whose x axis the warp collapses keeps its
|
||||
angle. `object.resetBoundingBox` squares the boxes to the page again. Corners that equal the corners of the box being
|
||||
warped (`from`, or the selection's bounds) change nothing and add no undo step. This angle rule is VectorCraft's own.
|
||||
|
||||
```json
|
||||
{"name":"run_command","arguments":{"command":"object.distort","params":{"from":[-100,0,0,100],"angle":90,"corners":[[0,100],[0,0],[120,-20],[100,100]]}}}
|
||||
```
|
||||
@@ -5810,6 +5834,21 @@ desktop app): in View › Pixel Preview, on softens placed and embedded bitmaps;
|
||||
`disableAutoAddDelete` (off by default): on, the Pen no longer adds or deletes an anchor when a click lands on a
|
||||
segment or an anchor of a selected path.
|
||||
|
||||
`monitorProfileDisplay` (Preferences › Performance › Use Monitor Profile for Canvas, on by default; desktop app)
|
||||
converts the canvas from sRGB into the ICC profile of the display that shows most of the main window, as the last
|
||||
step before it is drawn: the art, the artboards' paper and the transparency grid. On Windows the profile is the
|
||||
display's default profile for its standard color mode; on X11 it is colord's profile for the RandR output, then the
|
||||
output's `_ICC_PROFILE` property when colord has no usable profile, then the screen's when only one output is active. A display with Windows Advanced
|
||||
Color on (HDR or Automatic Color Management) and macOS windows are converted by the system, and nothing is converted
|
||||
again. In a Wayland session, and where no profile is set or the profile is not an RGB display profile of at most 1 MiB,
|
||||
the canvas stays sRGB. The app reads the display again every 10 seconds and when the window moves to another display.
|
||||
Exports, `ui.render`, the document, panels and thumbnails are not converted; with Proof Colors on, the proof is drawn
|
||||
first and then converted. The art is converted before it is drawn over the converted paper, so the blend of a
|
||||
translucent object or an antialiased edge with the paper can differ slightly from a conversion of the blended color.
|
||||
`ui.inspect` returns `displayProfile`: `{enabled, display, source, profile, from, applied, reason,
|
||||
osManaged}`, where `source` is `profile`, `srgbProfile` (a profile that shows sRGB unchanged), `system`, `none`,
|
||||
`pending` or `unsupported`, `applied` says whether the canvas is converted, and `reason` says why not.
|
||||
|
||||
`ctrlWheelScrollsSideways` (on by default): on, Cmd/Ctrl with a mouse wheel's whole notches scrolls the canvas sideways
|
||||
instead of zooming while `zoomWithMouseWheel` is off; off, Cmd/Ctrl-wheel zooms about the pointer. Alt + Cmd/Ctrl-wheel
|
||||
and a pinch on a Mac trackpad, on a touch screen or in the web build still zoom about the pointer. Under either
|
||||
@@ -7175,7 +7214,8 @@ swatch a gradient is linked to, else `Linear gradient`, `Radial gradient` or `Fr
|
||||
lists them as Gradient Objects and `objects.gradients` counts them; gradient swatches no art uses are not listed; with
|
||||
`selectionOnly`, those in the selection), `gradientNames` (the gradients those objects use), `spotObjects`
|
||||
(`[{id, name, spotColors}]`: every object filled or stroked with a spot color swatch, as a solid color or in the
|
||||
stops of a gradient with a stop above opacity 0, at a tint above 0, leaving out fills and strokes at an opacity of 0,
|
||||
stops of a gradient that color a part of it above opacity 0 (a stop at opacity 0 counts only where it mixes with a
|
||||
stop above opacity 0 over a stretch of some width), at a tint above 0, leaving out fills and strokes at an opacity of 0,
|
||||
and every grayscale image colorized with one, by
|
||||
the same rules as `patternObjects`, with the spot colors it uses; a process
|
||||
color, even one of the same color, and Registration are not spot colors; the spotColors category lists them as Spot
|
||||
@@ -7967,7 +8007,8 @@ CMYK one. Settings saved before these options load with their defaults.
|
||||
Every object keeps the angle of its own axes (counter-clockwise degrees; `document.inspect` reports it as a node's
|
||||
`rotation`, and the selection's shared angle as `selectionRotation`, 0 when the selected objects differ). Transforms
|
||||
turn it with the object while its path geometry is still baked, so after a rotation the bounding box and its handles
|
||||
stay square to it, as in the reference app. `object.rotate {angle, absolute: true}` turns the selection to an angle
|
||||
stay square to it, as in the reference app. `object.distort` turns it as the warp turns the object at its center
|
||||
(see Free Distort on a turned bounding box). `object.rotate {angle, absolute: true}` turns the selection to an angle
|
||||
(the Transform and Properties panels' Rotate field), and `object.setBounds` measures width, height and the reference
|
||||
point along the turned box (x, y stay page coordinates). Objects turned together share the box. A new group starts
|
||||
square to the page. `object.resetBoundingBox` squares the box again without moving the art. It also squares every
|
||||
@@ -8523,6 +8564,44 @@ dialog open.
|
||||
{"name":"run_command","arguments":{"command":"text.setRangeStyle","params":{"id":12,"start":0,"end":4,"tateChuYoko":true,"tcyUpDown":2,"tcyLeftRight":-1}}}
|
||||
```
|
||||
|
||||
## Warichu
|
||||
|
||||
`text.setFormat` and `text.setRangeStyle {warichu?, warichuLines?, warichuGap?, warichuScale?, warichuAlign?}` set the
|
||||
Character panel menu's Warichu and Warichu Settings of the characters (the menu items show with Show East Asian
|
||||
Options). Warichu characters are set at `warichuScale` percent of their size (10 to 100, default 50) and stacked on
|
||||
`warichuLines` lines (a whole number from 1 to 6, default 2) inside their line: one above the other in horizontal type
|
||||
and side by side across the column in vertical type, the first line above or to the right. `warichuGap` is the space
|
||||
between the lines in points (0 to 100, default 0, document points as `baselineShift`). The stack is centered across the
|
||||
line on the center of the line's ideographic em box, and the line keeps the height of the characters' own size.
|
||||
A stretch of warichu characters is one block that takes the settings of its first character; a character with other
|
||||
settings, another size or the other kind of leading (Auto or a number) starts a new one, and a tab, a forced line break or a tate-chu-yoko character ends it. In
|
||||
vertical type a character marked `tateChuYoko` as well is set as tate-chu-yoko at its own size, and two or three digits
|
||||
marked `warichu` are stacked with their block instead of being set across the column. In horizontal type each line's
|
||||
characters are set in their bidi order, so right-to-left text reads from the right. The Insert Aki before the block's
|
||||
first character and after its last is space before and after the block. The text is split between the lines where
|
||||
their lengths come nearest an even share, after a space or a CJK character when there are enough such places, and
|
||||
between any two characters otherwise; a block has no more lines than characters. The block is as long as its longest
|
||||
line and is not broken across lines: a block longer than its line stays whole and runs past the line's end, as No Break
|
||||
text does. `warichuAlign` sets each line along the block: `"left"`, `"center"` or `"right"` (top, center or bottom in
|
||||
vertical type), `"justifyLeft"`, `"justifyCenter"` or `"justifyRight"` (every line but the last spread to the block's
|
||||
length, the last set left, centered or right) or `"justifyAll"`. `"auto"`, the default, sets the lines as
|
||||
`"justifyLeft"` does. These rules, the ranges and the defaults are VectorCraft's own; the public page
|
||||
<https://helpx.adobe.com/illustrator/using/formatting-asian-characters.html> describes the Lines, Line Gap, Scale and
|
||||
Alignment settings. Type on a path sets warichu characters at their own size along the path. The canvas and every
|
||||
export draw the stacked lines; SVG, PDF and the `.ai` writers write type with warichu as outlines, as they do ruby.
|
||||
None of the settings turns `warichu` on. All are saved only when they differ from the defaults, and character styles
|
||||
carry them (`charStyle.new`, `charStyle.setAttrs` and `charStyle.edit` refuse a value outside the range). A value
|
||||
outside its range is refused with `` `warichuLines` must be a whole number from 1 to 6 `` or
|
||||
`` `warichuScale` must be from 10 to 100 ``, naming the key, and an unknown alignment with the list of the values. One
|
||||
undo step; a `text.setFormat` call that changes nothing records none. `ui.warichuSettings` opens the Warichu Settings dialog on the
|
||||
values the selected characters share, a blank field where they differ; OK sends the values that changed and leaves a
|
||||
blank field's value alone. OK with a field that is not a number returns `Lines must be a number`,
|
||||
`Line Gap must be a number` or `Scale must be a number` and keeps the dialog open.
|
||||
|
||||
```json
|
||||
{"name":"run_command","arguments":{"command":"text.setRangeStyle","params":{"id":12,"start":2,"end":8,"warichu":true,"warichuLines":2,"warichuScale":50,"warichuAlign":"auto"}}}
|
||||
```
|
||||
|
||||
## Insert Aki
|
||||
|
||||
`text.setFormat` and `text.setRangeStyle {akiLeft?, akiRight?}` set Insert Aki Left and Insert Aki Right of the
|
||||
@@ -10486,9 +10565,9 @@ type and evening out horizontal scales are not there yet.
|
||||
Path Precision Tools is a built-in add-on for exact anchor and path work: its commands are `addon.pathtools.*`, and in
|
||||
the desktop app it lives in Object › Plug-ins › Path Precision Tools, in its Anchor Inspector panel
|
||||
(`window.panel {panel: "anchorInspector"}`), in its Parametric Shape panel (`window.panel {panel: "parametricShape"}`)
|
||||
and in seven tools that the toolbars don't show until they are added from the All Tools drawer (or chosen with
|
||||
`tool.select`): `anchorEraserBrush`, `extendPath`, `measureInspect`, `parametricShape`, `cornerTool`, `slideAnchor` and
|
||||
`sharedEdge`.
|
||||
and in eight tools that the toolbars don't show until they are added from the All Tools drawer (or chosen with
|
||||
`tool.select`): `anchorEraserBrush`, `extendPath`, `measureInspect`, `parametricShape`, `cornerTool`, `slideAnchor`,
|
||||
`sharedEdge` and `trimAtCrossings`.
|
||||
None has a shortcut. Each edit is one undo step, and an edit that changes nothing makes no step.
|
||||
|
||||
Tools:
|
||||
@@ -10537,6 +10616,12 @@ Tools:
|
||||
different in length, or at over 120° at an end, are left alone. Options (`tool.setOption`, or the panel, kept with the
|
||||
preferences): `diameter` (0.25 to 200 pt, 20), `tolerance` (how near two anchors count as coincident, 0 to 3 pt,
|
||||
0.002) and `together` (Keep Shared Points Together).
|
||||
- **Trim at Crossings Tool** (`trimAtCrossings`): removes stretches of paths between the places where they are crossed,
|
||||
on any path that can be edited, selected or not. A click runs `addon.pathtools.trim` with `at`, for the path within 4
|
||||
screen pixels of the pointer. A drag draws a rectangle and runs it with `rect` on release; once the pointer has
|
||||
gone 3 screen pixels from the press, the gesture stays a drag even when it ends near the press. An Alt-drag draws a
|
||||
freehand line and runs it with `points` on release; a line of more than 65,536 points is dropped. Nothing changes
|
||||
while dragging, and Escape during a drag removes nothing. The tool has no options.
|
||||
|
||||
Commands:
|
||||
|
||||
@@ -10568,7 +10653,9 @@ Commands:
|
||||
straight segment (`straight`) or with both ends made smooth (`smooth`).
|
||||
- `addon.pathtools.crossings {cut?, selfCrossings?, ids?}` adds anchors where the selected paths cross one another (and
|
||||
where each crosses itself, with `selfCrossings`), or with `cut` also cuts them there: a path of one subpath becomes a
|
||||
path per piece. Paths that meet at a shared anchor don't cross there; at most 10,000 segments at once.
|
||||
path per piece. Segments that meet at an anchor they share, or with only segments of no length between them, don't
|
||||
cross there, and they cross where they meet again elsewhere. With `selfCrossings`, a curved segment that loops over
|
||||
itself crosses itself. At most 10,000 segments at once.
|
||||
- `addon.pathtools.divideDashes {dash?, gap?, fit?, removeGaps?}` cuts the selected paths into separate open paths
|
||||
along the curve, each `dash` long (0.01 to 1,000,000 pt, 10 by default) with `gap` between them (0 to 1,000,000 pt,
|
||||
0 by default: the pieces touch), every piece keeping the path's appearance, as one undo step. The gap pieces are left
|
||||
@@ -10620,6 +10707,28 @@ Commands:
|
||||
one that `addon.pathtools.slideAnchor`, `extend` or `setAnchor` moves go with it, in the same undo step; an Extend Path
|
||||
that adds an anchor leaves the old end, and what shares it, where they are. Nothing else in the app changes. It is the
|
||||
`together` option of tool `sharedEdge`, off by default. → `{enabled}`.
|
||||
- `addon.pathtools.trim {at, tolerance?}`, `{rect}` or `{points}` removes stretches of paths. A stretch runs between two
|
||||
neighboring places where the path is crossed, by another path or by itself, or from such a place to an open end.
|
||||
`at` ([x, y]) removes the stretch at that point of the nearest path within `tolerance` (0 to 100 pt, default 3; of
|
||||
paths equally near, the one on top), and a point where two stretches meet is on the one that starts there. `rect`
|
||||
([x, y, width, height]) removes every stretch the rectangle touches. `points` (2 to 100,000 points) removes every
|
||||
stretch the line through them crosses. Exactly one of the three is given, with coordinates within ±10,000,000 pt.
|
||||
Every path that can be edited takes part, selected or not, compound path members included. Hidden and locked paths,
|
||||
guides and clipping paths are not trimmed and do not count as crossing, the members of a compound clipping path
|
||||
included; type, images and symbol instances take no part. In isolation mode only paths inside the isolated object
|
||||
are trimmed, and paths outside it still count as crossing. A path that ends on another marks a place on the other. Paths that lie along each other do not cross there.
|
||||
Crossings are found on the paths' own outlines, without strokes, brushes or effects. A closed path that loses a
|
||||
stretch becomes open. An open path that loses a middle stretch becomes two paths with its appearance, in its place in
|
||||
the stacking order. A path that nothing crosses is removed whole, a compound path that loses its last member is
|
||||
removed, and a live shape becomes a plain path. No anchor is added where a stretch that stays meets another. The
|
||||
pieces of a selected path are selected, and anchors and segments direct-selected on a trimmed path are deselected;
|
||||
the rest of the selection stays as it was. One undo step, none when nothing is removed. Only a path that `at`,
|
||||
`rect` or `points` reaches is searched for crossings. The command is refused when such a path has more than 10,000
|
||||
segments, when more than 200,000 segments of other paths lie in its box, when the number of paths `rect` or `points`
|
||||
reaches times the number of paths that take part is more than 50,000,000, when the paths it trims make more than about
|
||||
60,000,000 pairs of segments to compare in all, when the curves are too tangled to find where they cross, or when
|
||||
checking `points` against the paths would take more than 60,000,000 comparisons. These rules are VectorCraft's own.
|
||||
→ `{ids, removed}`: the paths left of those trimmed, and the stretches removed.
|
||||
- `addon.pathtools.shape.create {center, kind?, width?, height?, rotation?, count?, a?, b?, radius?}` draws a parametric
|
||||
shape with the current paint, selected. `kind`: `rectangle`, `ellipse`, `polygon` (default), `star`, `ring`, `arrow`,
|
||||
`cross`, `heart`, `gear` or `bubble` (a speech bubble). `width` and `height` are 0.01 to 16,384 pt (100);
|
||||
|
||||
+35
-16
File diff suppressed because one or more lines are too long
+30
-3
@@ -86,7 +86,7 @@ object is where the art was.
|
||||
| Bevel both sides | The back is bevelled too. |
|
||||
|
||||
Holes stay holes, with walls of their own. Bevels move each corner along its bisector (mitres are limited to four
|
||||
times the width), so a bevel wider than a narrow part of the shape folds over itself.
|
||||
times the width), so a bevel wider than a narrow part of the shape folds over itself. Each facet has a seam ([Seams](#seams)).
|
||||
|
||||
## Inflate
|
||||
|
||||
@@ -102,7 +102,33 @@ middle.
|
||||
| Volume | 0–100 %. The surface is a membrane under even pressure, held along the outline (and around holes): it rises vertically from the edge and rounds smoothly inside, without creases along the shape's middle. At 50 % a circle becomes a half sphere; 100 % puffs twice as high, 0 % is flat. |
|
||||
| Both sides | The back puffs out too; otherwise it is flat. |
|
||||
|
||||
The surface starts with a grid of 48 cells across the larger side, halved or quartered where it rises steeply near the outline. White-light Inflate retains the existing clipped polygon cells, shading, paint composition and seam joins. With colored lights, simple cells are triangulated with shared border samples, and lighting interpolates shared membrane normals through ordinary RGB vector gradients, including on a puffed back. Solid fills batch those triangles into three channel groups and one coverage clip for the whole surface. Source gradients retain per-facet vector composition and apply transparent coverage once. Seam widths retain the 0.05 to 0.75 pt bounds; colored facets use round joins. Shading is automatic, with no additional dialog option.
|
||||
The surface starts with a grid of 48 cells across the larger side, halved or quartered where it rises steeply near the outline. White-light Inflate retains the existing clipped polygon cells, shading and paint composition. With colored lights, simple cells are triangulated with shared border samples, and lighting interpolates shared membrane normals through ordinary RGB vector gradients, including on a puffed back. Solid fills batch those triangles into three channel groups and one coverage clip for the whole surface. Source gradients retain per-facet vector composition and apply transparent coverage once. Seam widths retain the 0.05 to 0.75 pt bounds, and every facet's seam has round joins ([Seams](#seams)). Shading is automatic, with no additional dialog option.
|
||||
|
||||
## Seams
|
||||
|
||||
Facets side by side, each antialiased on its own, would leave hairlines between them, so 3D facets are drawn with
|
||||
a seam of their own paint, with round joins. In Extrude & Bevel, Inflate, Rotate and the three 3D (Classic) effects a
|
||||
facet's seam is half as wide as the facet is thick, from 0.05 to 0.75 pt; Revolve's seam is always 0.75 pt.
|
||||
|
||||
How a facet carries its seam depends on the lights and the paint:
|
||||
|
||||
- Extrude & Bevel, Inflate and Rotate, when no light is colored (one white light or several): a path filled with
|
||||
the facet's shading and stroked with its seam. With a colored light, Extrude & Bevel and Rotate (planar shading)
|
||||
are drawn the same way.
|
||||
- Inflate with a colored light and shading on: a solid-color fill draws each facet's light ramps with its seam in three channel
|
||||
groups clipped to the union of its facets, so no seam reaches past the surface; a gradient fill fills each facet's
|
||||
ramps through a clip of the facet and its seam, outlined with round joins.
|
||||
- Extrude & Bevel (Classic), Rotate (Classic) and Revolve (Classic): a path and a seam for every face; gradient and
|
||||
pattern faces seam only the base paint, and the shading and highlight layers cover the face alone. The Wireframe
|
||||
surface draws edges only, with no seam.
|
||||
- Revolve, with shading on: when a `lights` list is given (even one of white lights), a solid-color or gradient face fills its light
|
||||
ramps through a clip of the face and its 0.75 pt seam, outlined with round joins. With the single legacy light,
|
||||
a face is a path and a seam; with a colored `lightColor` a gradient face fills through the same kind of clip.
|
||||
|
||||
A facet seen almost edge-on is a sliver, and a seam with mitered joins would reach past the solid as a thorn; a round
|
||||
one reaches no more than half its width past its facet. So where a facet has no neighbor (Rotate's plane, every
|
||||
silhouette corner) its convex corners are drawn rounded by up to 0.375 pt (half the largest seam), except a
|
||||
solid-color Inflate under a colored light, whose clip keeps its corners sharp.
|
||||
|
||||
## Fills and strokes
|
||||
|
||||
@@ -206,7 +232,7 @@ solids are ([Groups](#groups)), turned about one shared axis.
|
||||
|
||||
The flat art turned in 3D about the centre of its bounds. Every fill and stroke is turned with its own paint (a
|
||||
stroke as its outline, so it foreshortens with the art) and shaded as one plane; a plane has two sides, so its
|
||||
back shows when it is turned past 90°.
|
||||
back shows when it is turned past 90°. The plane has a seam ([Seams](#seams)).
|
||||
|
||||
## Rotation presets
|
||||
|
||||
@@ -465,6 +491,7 @@ Release measurements and a repeatable CLI scene are in [3D lighting performance]
|
||||
|
||||
| Date | Change |
|
||||
|---|---|
|
||||
| 2026-11-12 | The seams of Extrude & Bevel, Inflate and Rotate under a white light, and of the faces of Extrude & Bevel (Classic), Revolve (Classic) and Rotate (Classic), went from miter to round joins (the seams of Revolve and of colored lights, and 3D (Classic) Wireframe edges, were already round): no thorns on edge-on facets, and facets with no neighbor now have rounded convex corners ([Seams](#seams)). |
|
||||
| 2026-11-08 | Contours that cross, touch or overlap are merged by vectorcraft-pathops before Extrude & Bevel, Inflate and Rotate build a solid, sharing its limits; others are built as drawn. |
|
||||
| 2026-11-06 | Extrude & Bevel, Inflate and Rotate apply to groups and layers: every path, compound path and type in them turns about one shared axis (#4506). |
|
||||
| 2026-10-21 | Four original lighting presets, shared by all four 3D effects and commands, with effective-setting recognition and existing preview/history behavior. |
|
||||
|
||||
@@ -69,6 +69,7 @@ against Illustrator's public documentation; **estimated** unless noted.
|
||||
| CJK: East Asian Type units (Q, Ha) | done | Preferences › Units › East Asian Type (`unitsAsianType`, Points by default) offers every unit and Q and Ha, a quarter of a millimetre each ([Scripting Guide](https://ai-scripting.docsforadobe.dev/scripting/measurementUnits/): 0.709 pt per Q; [InDesign's unit notation](https://helpx.adobe.com/in/indesign/desktop/layout-and-grid-tools/rulers-and-measure-tools/change-ruler-measurement-units.html): `q`, `h`). The public pages do not say which fields follow it, so no field uses it yet and that waits for a source. Evidence: `q_and_ha_are_a_quarter_millimetre`, `east_asian_type_unit_*` |
|
||||
| CJK: manual tate-chu-yoko | done | Character panel menu › Tate-chu-yoko (`text.setFormat` / `text.setRangeStyle {tateChuYoko}`), with Show East Asian Options: marked characters stand side by side across one em of a vertical column, squeezed to the em when wider; two or three half-width digits still do so without the mark; horizontal type keeps the mark and does not move them. Tate-chu-yoko Settings… (`ui.tateChuYokoSettings`, `{tcyUpDown, tcyLeftRight}` in points) moves a marked block up or down and right or left as one piece. Evidence: `tests_vertical::manual_tate_chu_yoko_sets_marked_characters_across_one_em`, `tests_vertical::tate_chu_yoko_settings_move_a_marked_block_up_down_left_and_right`, `typecmd::tate_chu_yoko_is_a_character_attribute_saved_only_when_on`, `typecmd::tate_chu_yoko_settings_are_character_attributes_saved_only_when_set`, `dialogs::tate_chu_yoko::tests` |
|
||||
| CJK: Standard Vertical Roman Alignment | done | Character panel menu › Standard Vertical Roman Alignment (`text.setFormat` / `text.setRangeStyle {standardVerticalRoman}`), with Show East Asian Options, off by default: in vertical type the marked half-width characters (Latin letters, digits and other characters that would lie on their side) stand upright one below the other, each in its upright cell; spaces keep their width and tate-chu-yoko blocks stay across the column; horizontal type keeps the mark and does not change. Character Style Options has its own checkbox for it. Evidence: `tests_vertical::standard_vertical_roman_alignment_stands_half_width_characters_upright`, `typecmd::standard_vertical_roman_is_a_character_attribute_saved_only_when_on` |
|
||||
| CJK: warichu | done | Character panel menu › Warichu and Warichu Settings… (`text.setFormat` / `text.setRangeStyle {warichu, warichuLines, warichuGap, warichuScale, warichuAlign}`, `ui.warichuSettings`), with Show East Asian Options ([Format East Asian characters](https://helpx.adobe.com/illustrator/using/formatting-asian-characters.html)): marked characters set at a percentage of their size and stacked on 1 to 6 lines inside their line, one above the other in horizontal type and side by side in vertical type, with a line gap and eight alignments; a block stays whole on one line. Saved natively, carried by character styles, drawn on the canvas and in every export (SVG, PDF and `.ai` write such type as outlines). Type on a path sets the characters at their own size. Evidence: `tests::warichu`, `dialogs::warichu::tests`, `typecmd::area_tests::warichu_is_a_character_attribute_set_saved_and_exported` |
|
||||
| CJK: composite fonts | partial | Type › Composite Fonts… (`type.compositeFonts.set`), with Show East Asian Options: a font made of a font per class of character (Kanji, Kana, Punctuation, Symbols, Roman, Numerals), each with its own style, size and baseline in percent of the type's size, Kana, Roman and Numerals with horizontal and vertical scale, and Kana with Scale at Center; New, Delete Font, Import… and Export… (`.vccomposite`, `type.compositeFonts.import` and `.export`) ([Creating composite fonts](https://help.adobe.com/archive/en_US/illustrator/cs3/illustrator_cs3_help.pdf#page=347)). Composite fonts are listed first in the font menus, saved with the document, and their type is laid out per class; SVG and legacy `.ai` write it as outlines. Not yet: custom character sets, the Units menu, Show Sample. Evidence: `text::composite::tests::characters_fall_in_their_classes`, `tests::composite::composite_type_draws_each_class_in_its_font`, `compositefonts::tests`, `dialogs::composite_fonts::tests` |
|
||||
| CJK: ruby | partial | ruby (ふりがな) for live text (`type.ruby`): a reading over a byte range, above (right of the column in vertical type) or below, start/centre/end alignment, size, overhang or squeeze; saved natively, laid out with its line growing, drawn on the canvas, in SVG and PDF (as outlines where ruby is present), in EPS, EMF/WMF and legacy `.ai` (legacy `.ai` writes type with ruby as outlines), and kept by Create Outlines, Expand Appearance and flattening, each glyph where the layout puts it (`typecmd::ruby_tests::create_outlines_keeps_the_ruby_where_it_is_laid_out`) | #633 |
|
||||
| Language per character (Character panel › Language, character styles), text shaped in it | done | `text.setFormat` / `text.setRangeStyle {language}` by name or BCP 47 tag, one of Document Setup's languages (Hindi, Marathi, Gujarati, Bengali, Punjabi, Tamil, Telugu, Kannada, Malayalam, Odia and Urdu added, #4943; Assamese and Sanskrit added, #4947; Serbian: Cyrillic, Serbian: Latin and Croatian); the shaper gets the tag, so the font's language forms apply (OpenType `locl`: Turkish keeps `fi` apart and the dot on its i, #4940); new type takes the document's language; saved as the tag only when set, carried by character styles (#4946). English and eleven Indian languages hyphenate by run language; Sanskrit automatic hyphenation awaits allowlisted patterns (#4947). Not yet: `.ai`/PDF import of a text's language, paragraph styles. Evidence: `features::tests::language_picks_the_fonts_forms`, `features::tests::serbian_gets_the_fonts_serbian_forms`, `typecmd::area_tests::language_is_a_character_attribute_saved_only_when_set`, `tests::typo::indic_language_runs_hyphenate_with_both_composers`, `hyphen::tests::sanskrit_without_allowlisted_patterns_uses_only_exceptions`; spelling is checked in each run's Language (`text.spelling.check`, #4936) |
|
||||
|
||||
+3
-3
@@ -434,7 +434,7 @@ next unit in the order a right-click on a ruler lists them, from Feet back to Po
|
||||
| Pathfinder panel › Pathfinder Options…: Precision, Remove Redundant Points, Divide and Outline Will Remove Unpainted Artwork | done | #3426; `object.pathfinder.options`, kept in the preferences; defaults (0.01 pt, both off) keep the earlier results; [spec](https://helpx.adobe.com/illustrator/desktop/manage-objects/reshape-transform-objects/pathfinder-panel-overview.html) |
|
||||
| Cmd/Ctrl+4 repeats the last successful Shape Mode or Pathfinder operation on the selection | done | Panel operations, direct `object.pathfinder.*` commands and `command.batch` steps (Actions playback) set history; `action.batch`, Trap, compound-shape edits and live effects do not. Repeat uses current Pathfinder Options; [key spec](https://web.archive.org/web/20260726060015/https://helpx.adobe.com/illustrator/using/default-keyboard-shortcuts.html), [menu spec](https://helpx.adobe.com/illustrator/desktop/manage-objects/reshape-transform-objects/pathfinder-panel-overview.html) |
|
||||
| Pathfinder panel: compound shapes (Make, Release and Expand Compound Shape in the panel menu, Alt-click a Shape Mode, a Shape Mode for selected members, the Expand button) | partial | #4522; `object.compoundShape.make`/`setMode`/`release`/`expand`; members stay editable, the area draws, exports and saves; the button of the members' shared mode is lit; blends, envelopes and warped objects are members as they draw; [spec](https://helpx.adobe.com/illustrator/desktop/manage-objects/reshape-transform-objects/create-compound-shapes-with-pathfinder.html); missing: question marks for mixed modes, hit-testing by the area |
|
||||
| Canvas context menu | done | Layers rows, panels and type have none (gap) |
|
||||
| Canvas context menu | done | Right-clicking type opens the canvas menu, with Bullets and Numbering and Spelling. Layer, sublayer, group and object rows in the Layers panel offer Collect for Export (As Single Asset, As Multiple Assets) for the row, or for every highlighted row when it is one of them; artboard rows, library groups and items, the rulers and floating toolbar grips have menus too. Gaps: the Layers row menu has no other commands, guide and blend spine rows have no menu, and other panels have none |
|
||||
| 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 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) |
|
||||
@@ -442,7 +442,6 @@ next unit in the order a right-click on a ruler lists them, from Feet back to Po
|
||||
| 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 |
|
||||
| Gradient panel: delete a stop | done | Delete Stop at the right end of the ramp deletes the selected stop, and a stop dragged down off the ramp is deleted on release, never below two stops, one undo step each; [Gradient panel options](https://helpx.adobe.com/illustrator/desktop/paint-and-fill/create-and-edit-gradients/gradient-tool-and-panel.html); `panels::gradient` test |
|
||||
| SVG Interactivity, Retype, Comments, Version History panels | missing | the last two are cloud features (out of scope) |
|
||||
| Workspaces (save, reset, switch); each remembers the layout changes made in it across switches and restarts until Reset <name> | done | `UiState::workspace_changes` |
|
||||
| Opening a file: after 0.4 s a progress window with the file name, a moving bar (reading counts no steps), how many more files wait, Cancel (Esc: the file doesn't open) and Continue in Background; never over another dialog or progress window | done | #5930; `opening::show`, `file.cancelOpen`, `file.openInBackground`. Save, Place and Close still show only the status bar's spinner (Place and Save run off the UI thread; Close is immediate) |
|
||||
| Window › Help Bar shows or hides the tool-help strip apart from the status bar; kept with the preferences and in saved workspaces; Presentation Mode hides both bars | done | `window.helpBar`; `help_bar_toggle_is_independent_and_saved_in_workspaces`, `help_bar_and_status_bar_render_independently`, `legacy_help_bar_visibility_follows_each_layouts_status_bar` |
|
||||
@@ -465,9 +464,10 @@ next unit in the order a right-click on a ruler lists them, from Feet back to Po
|
||||
| Document Tools add-on (VectorCraft addition): Object › Plug-ins › Document Tools › Batch Trace Folder asks for a folder of images, then a destination folder, traces each image with a preset (optionally expanded) and saves it there as `.vectorcraft`, `.svg`, `.pdf`, `.ai` or `.eps` under its own name (taken names numbered, nothing replaced), closing each image again; the status bar counts the images traced and those that couldn't be; off on the web | done | #4921; `addon.document.batchTraceFolder`, `crates/engine/src/cmd/addons/document/batch_trace.rs`, `crates/ui-egui/src/addons/document.rs` and their tests; not a feature of the reference app |
|
||||
| Document Tools add-on (VectorCraft addition): Object › Plug-ins › Document Tools › New Symbols from Layers makes a symbol of each layer's art named after the layer (the highlighted layers when two or more are, else all); Convert Layers to Symbols also replaces each layer's art with an instance in place; empty layers skipped, one undo step | done | #4927; `addon.document.symbolsFromLayers`, `crates/engine/src/cmd/addons/document.rs`, `crates/ui-egui/src/addons/document.rs` and their tests; not a feature of the reference app, so it is not scored |
|
||||
| Smart Pen add-on (VectorCraft addition): Object › Plug-ins › Smart Pen selects the Smart Pen Tool, which the All Tools drawer lists under its own heading but neither toolbar shows as shipped (no shortcut), and opens the Smart Pen panel (next segment straight or curved; Remove Points Keep Shape, Make Smooth, Make Corner, Retract Handles, Close or Join). The tool draws (click: straight or curved segment, a curve after a straight one tangent; drag: smooth anchor, Alt breaks the handle, Shift 45°, Space moves it; Tab switches a segment; rubber band; close, join, continue) and edits without switching tools (click selects a point, drag moves it, Alt-click removes it keeping the shape, Shift+Alt-click deletes it, double-click toggles smooth/corner; handle drags with Shift and Alt; segment drags reshape, Alt-click adds a point) | done | `addon.pen.*`, `crates/tools/src/addons/smart_pen.rs`, `crates/ui-egui/src/addons/pen.rs` and their tests; not a feature of the reference app, so it is not scored |
|
||||
| Path Precision Tools add-on (VectorCraft addition): Object › Plug-ins › Path Precision Tools selects its seven tools (Anchor Eraser Brush, Extend Path, Measure & Inspect, Parametric Shape, Corner Tool, Slide Anchor Along Path, Shared Edge Merge Tool), which the All Tools drawer lists under their own heading but neither toolbar shows as shipped, opens the Anchor Inspector panel (the selected anchor's X/Y and handle lengths and angles as fields; Make Smooth, Make Corner, Equalize Handles, Remove Points Keep Shape, Add Points, the three ways to close) and the Parametric Shape panel (kind, count, W/H, rotation, the kind's own values and corner radius of the selected parametric shape, or of the tool's next one), and runs Add Points at / Split at Crossings and Convert to Parametric Shape; the Parametric Shape Tool draws ten re-editable kinds from the centre (↑/↓ and ←/→ change their numbers while dragging) and edits a selected one with handles; the Corner Tool cuts editable corners on any path (hover shows the anchor, a click uses its radius and kind, a drag sizes the corner, Shift whole values; a corner's marker selects it and loads its values, drags to resize, to 0 or double-clicked removes it; never past what fits; Alt-marquee cuts every anchor inside) with a Corners section in the Anchor Inspector (radius, kind, selected count, Apply to Selected Anchors); Slide Anchor Along Path drags an anchor along its curve with the segments beside it refitted, Shift snapping where the tangent is a multiple of 45°; the Shared Edge Merge Tool shows, over two paths touching at two coincident anchors, the two stretches and the edge merging them, a click merges them (half way; Shift the upper path, Alt the lower), and near anchors meet or an anchor one path lacks is added to match (Shift+Alt asks for this inside a stretch), with a Shared Edges section in the Anchor Inspector (brush diameter, coincidence 0 to 3 pt, Keep Shared Points Together, which takes coincident anchors along with the add-on's own anchor moves); a double-click on the brush or Extend Path tool opens its options | done | `addon.pathtools.*`, `crates/tools/src/addons/`, `crates/ui-egui/src/addons/pathtools.rs`, `crates/ui-egui/src/addons/pathtools/` and their tests; not a feature of the reference app, so it is not scored |
|
||||
| Path Precision Tools add-on (VectorCraft addition): Object › Plug-ins › Path Precision Tools selects its eight tools (Anchor Eraser Brush, Extend Path, Measure & Inspect, Parametric Shape, Corner Tool, Slide Anchor Along Path, Shared Edge Merge Tool, Trim at Crossings Tool), which the All Tools drawer lists under their own heading but neither toolbar shows as shipped, opens the Anchor Inspector panel (the selected anchor's X/Y and handle lengths and angles as fields; Make Smooth, Make Corner, Equalize Handles, Remove Points Keep Shape, Add Points, the three ways to close) and the Parametric Shape panel (kind, count, W/H, rotation, the kind's own values and corner radius of the selected parametric shape, or of the tool's next one), and runs Add Points at / Split at Crossings and Convert to Parametric Shape; the Parametric Shape Tool draws ten re-editable kinds from the centre (↑/↓ and ←/→ change their numbers while dragging) and edits a selected one with handles; the Corner Tool cuts editable corners on any path (hover shows the anchor, a click uses its radius and kind, a drag sizes the corner, Shift whole values; a corner's marker selects it and loads its values, drags to resize, to 0 or double-clicked removes it; never past what fits; Alt-marquee cuts every anchor inside) with a Corners section in the Anchor Inspector (radius, kind, selected count, Apply to Selected Anchors); Slide Anchor Along Path drags an anchor along its curve with the segments beside it refitted, Shift snapping where the tangent is a multiple of 45°; the Shared Edge Merge Tool shows, over two paths touching at two coincident anchors, the two stretches and the edge merging them, a click merges them (half way; Shift the upper path, Alt the lower), and near anchors meet or an anchor one path lacks is added to match (Shift+Alt asks for this inside a stretch), with a Shared Edges section in the Anchor Inspector (brush diameter, coincidence 0 to 3 pt, Keep Shared Points Together, which takes coincident anchors along with the add-on's own anchor moves); a double-click on the brush or Extend Path tool opens its options | done | `addon.pathtools.*`, `crates/tools/src/addons/`, `crates/ui-egui/src/addons/pathtools.rs`, `crates/ui-egui/src/addons/pathtools/` and their tests; not a feature of the reference app, so it is not scored |
|
||||
| Path Precision Tools add-on (VectorCraft addition): Object › Plug-ins › Path Precision Tools › Divide into Dashes… (Dash and Gap in any unit, Fit to Corners and Ends, Remove Gaps; Preview) cuts the selected paths, or only their direct-selected segments, into open pieces along the curve, keeping their appearance, one undo step | done | #4950; `addon.pathtools.divideDashes`, `crates/pathops/src/addons/pathtools/dashes.rs`, `crates/ui-egui/src/addons/pathtools/dashes.rs` and their tests; not a feature of the reference app, so it is not scored |
|
||||
| Path Precision Tools add-on (VectorCraft addition): Object › Plug-ins › Path Precision Tools › Set Corners… (also a button in the Anchor Inspector's Corners section: Radius in any unit, Corner kind, Anchors: All, Odd-Numbered or Even-Numbered, counted from each path's first anchor; Angle: from … to …°, only the corners whose sides meet at an angle in that range; Preview) cuts corners on the chosen anchors of every selected path, one undo step | done | #5546, #5545; `addon.pathtools.cornerSet` (`every`, `minAngle`, `maxAngle`), `crates/ui-egui/src/addons/pathtools/set_corners.rs` and their tests; not a feature of the reference app, so it is not scored |
|
||||
| Path Precision Tools add-on (VectorCraft addition): Object › Plug-ins › Path Precision Tools › Trim at Crossings Tool (in the All Tools drawer under the add-on's heading, in neither toolbar as shipped, no shortcut) removes stretches of paths between the places where they are crossed, on any editable path, selected or not: a click removes the stretch under the pointer, a drag every stretch its rectangle touches, an Alt-drag every stretch its freehand line crosses; one undo step each; Escape during a drag removes nothing | done | `addon.pathtools.trim` (in `crates/engine/src/cmd/addons/pathtools/trim.rs`), `crates/tools/src/addons/trim.rs` and their tests; not a feature of the reference app, so it is not scored |
|
||||
| Path Precision Tools add-on (VectorCraft addition): Object › Plug-ins › Path Precision Tools › Expand Dashes into Paths turns each selected path's dashed stroke into separate open paths, one per dash, laid out as the stroke draws them (pattern, offset, Align Dashes to Corners and Path Ends), each keeping the stroke with the dashes off; one undo step | done | #4922; `addon.pathtools.expandDashes` (in `crates/engine/src/cmd/addons/pathtools.rs`, using the renderer's dash layout) and its tests; not a feature of the reference app, so it is not scored |
|
||||
| Path Precision Tools add-on (VectorCraft addition): Effect › Path Effects lists its live effects (Dashes to Geometry, Add Anchors, Extend Path, Close Path, Smooth Anchors, Retract Handles, Reverse Direction, Simplify Anchors, Split at Anchors), each with the effect dialog's live Preview except Reverse Direction, which has no options, and listed in the Appearance panel like any effect | done | `addon.path.*`, `crates/effects/src/addons/path.rs`, `crates/ui-egui/src/addons/pathtools.rs` and their tests; not a feature of the reference app, so it is not scored |
|
||||
| Path Precision Tools add-on (VectorCraft addition): Object › Plug-ins › Path Precision Tools selects its four tools (Anchor Eraser Brush, Extend Path, Measure & Inspect, Parametric Shape), which the All Tools drawer lists under their own heading but neither toolbar shows as shipped, opens the Anchor Inspector panel (the selected anchor's X/Y and handle lengths and angles as fields; Make Smooth, Make Corner, Equalize Handles, Remove Points Keep Shape, Add Points, the three ways to close) and the Parametric Shape panel (kind, count, W/H, rotation, the kind's own values and corner radius of the selected parametric shape, or of the tool's next one), and runs Add Points at / Split at Crossings and Convert to Parametric Shape; the Parametric Shape Tool draws ten re-editable kinds from the centre (↑/↓ and ←/→ change their numbers while dragging) and edits a selected one with handles; a double-click on the brush or Extend Path tool opens its options | done | `addon.pathtools.*`, `crates/tools/src/addons/`, `crates/ui-egui/src/addons/pathtools.rs`, `crates/ui-egui/src/addons/pathtools/shape.rs` and their tests; not a feature of the reference app, so it is not scored |
|
||||
|
||||
Reference in New Issue
Block a user