Under --automation-read-root, prefs.get, prefs.list, prefs.set and
prefs.reset returned the folder preferences (fontsFolder, pluginsFolder,
scratchPrimary, scratchSecondary, recoveryFolder, templatesFolder) and
the export presets' folder even when they were outside the read roots.
Such a folder preference is now null, as ui.inspect leaves it out, and
such a preset's folder is left out. An empty folder and the scratch disk
choices stay; without roots the replies are unchanged.
Art Alt-dragged (Option-dragged on macOS) from the canvas onto a
scatter, art or pattern brush in the Brushes panel becomes its art
(brush.replaceArt). When strokes use the brush, the app checks the art
first, then a dialog offers Apply to Strokes, which redraws them with
the new art, Leave Strokes, which keeps the brush and its strokes as
they were and adds "<name> copy" with the new art as the current brush,
and Cancel. Each change is one undo step.
A pattern brush takes back the tile groups brush.placeArt places, frames
included, and takes other art as its side tile. Calligraphic and
bristle brushes, an empty selection and art with no width are refused.
Art Alt-dragged off the canvas now reaches the panels as the art the
drag started with. Before, the panels got the ids of the copy the drag
previews, which no longer exist once the release over a panel ends the
move.
brush.new now also measures a symbol instance in the selected art by its
symbol's art when it checks that the art has width.
Docs: docs/mcp.md, docs/target-app-parity.md.
When a folder on the way to the Data Recovery folder was missing and
couldn't be made, or was a file, the error named the area folder or the
copy inside it, for example `<recovery>/1794385145-1: Not a directory
(os error 20)`. Errors on the store's folders and files now name the
first folder on the way, from the top, that is not a folder ("<path> is
not a folder: <OS error>") or is missing ("couldn't make <path>: <OS
error>" while the store makes it, "<path> is missing" otherwise). When
every folder on the way is there, the error names the folder or file it
happened on. When reading a folder reports it missing, listing checks
the folders on the way, so a file there is an error and not an empty
list.
A scatter, art or pattern brush dragged from the Brushes panel onto an
empty part of the canvas places a copy of its art there to edit,
centered where it is dropped (brush.placeArt). Dropped on a path, a
brush is still applied to it. A pattern brush is placed as its tiles in
a row, 10 pt apart, each in a group named for its tile, with an
unpainted rectangle at the back of a tile that has a repeat frame.
Calligraphic and bristle brushes have no art and are refused. A symbol
instance in the art is measured by its symbol's art.
Docs: docs/mcp.md, docs/target-app-parity.md.
A filled open path wrote its outline as an open polyline, so with fill
hatches left out (and in R12, and in CNC / CAM) the area lost its closing
edge. Fill outlines now close each open subpath that can enclose an area;
strokes of the same path stay open.
document.exportForScreens without a folder writes into the folder its
exportPreset keeps. When that folder is outside the client's read roots
and the export fails, for example because the folder is also outside the
write roots, the error now names the folder by its name, as the reply of
a successful export leaves it out. A granted root in the same message
stays whole, and a folder the client gives stays whole in the error.
A manifest whose `commands` value is not a list, whose entry is not an
object, or whose command `id` or `label` is not a string was refused with
serde's own text ("invalid type: ..., expected command [0] as {id, label,
params?}"), and no catalog had rows for it or for the reader's other
`commands` messages. The reader now gives its own message for each of
these cases, and the complete-message catalogs translate them, together
with "missing field", "duplicate field" and the manifest prefix with its
line and column.
A save with Use Artboards writes a file per artboard beside the path. Each of them is now checked against the file the document was read from, before the first file is written, so a sibling cannot replace that file without acknowledgeLoss. The interface checks the files beside the path the same way.
docs/gaps.md, docs/file-format-parity.md and docs/ui-parity.md still
listed the CNC preset as open after #5500 added it. They now name DXF
Options' Preset menu and dxfPreset: "cnc" on document.exportDxf; VCarve
QA stays open. The ui-parity row also no longer lists native CIRCLE/ARC
export as pending.
An approval question that a control request, MCP, injected input, or a
file dialog one of them opened leads to now keeps OK disabled and
refuses every confirm, a person's click included. The dialog says to
choose Object › Plug-ins › Install Plug-in…, and ui.installPlugin answers
approval: "personMustStartInstall". The person's own Install Plug-in…,
File › Open or drop inspects the module again and asks a new question
with its half-second delay.
The origin is fixed when the request is made and goes with a native
file dialog's deferred answer and the web picker's answers, which now
arrive apart from drops and from window.vectorcraft.openFile (always
automation). A question about taking another module's place now opens
in the approval dialog, and automation's replace: true no longer skips
it. A module that needs no approval still installs at once.
- Outside Windows a `\` stays part of a hidden library's or sent path's
file name; another platform's absolute path is still split on `\`.
- A hidden relative path is matched after leading `./` and `../` parts
only when they start the path, so `/work/./data/icon.svg` keeps its
text.
- `ui.inspect` and `ui.docking` replies are hidden once, so a library
at the top of the file system shows as `loaded/<file name>` with its
separator.
Boxing the string receiver of a non-strict function flattens it, and reserving the copy can
collect. The callee, receiver and arguments are already off the stack at that point, so they
stay in the temporary roots until the frame holds them; before, an argument object could be
freed and its cell reused by the wrapper. new String(value) roots the converted string the
same way, so what the rope holds is still counted while its copy is reserved.
The Stroke panel menu's Edit Arrowheads… (stroke.arrowheads.edit) opens
Arrowheads.vectorcraft next to the preferences, creating it with one
example head when it is missing. Each symbol in the file is one head,
listed by name after the built-in heads in both arrowhead menus: it
points right, its registration point is the tip, and its height is drawn
as wide as the built-in heads. The file is read at startup and again
each time VectorCraft saves it; stroke.arrowheads.reload and
stroke.arrowheads.list read and list it.
Arrowhead gets a Custom variant, appended after the built-in names, that
carries the head's name and outline, so a document that uses one draws,
saves, reopens and exports it without the arrowheads file. stroke.set
takes {"custom": name} or the {"Custom": {name, path}} form that
document.inspect reports.
Part of #5421.
Convert To Point Type left Dynamic Text on when it turned Block area
type into point type. Point type has no Dynamic Text, but the flag was
saved, and converting the type back to area type turned Block on again
and fitted the lines to the new frame. The conversion now turns it off;
the point type keeps the sizes and leading Block wrote into the
characters, and the conversion is still one undo step.
- A name may hold \u{...} escapes with any number of hexadecimal digits
up to U+10FFFF. An empty, unclosed, out-of-range or surrogate escape is
not part of a name. Each \u{...} escape read in a name is reported as
syntax newer than ES3, with the escape as written.
- # followed by an escaped name start is one private name, also in the
code of an XML literal, and its escapes are read in the report
(this.#app is #app).
- A # and a name at the start of a line is a private name, not a
directive, when the name starts with an escape, or when the line is
inside braces and the name is not a directive's. A private name whose
decoded name would make the line a directive is reported as written.
- The identifier test against vectorcraft-js also compares braced
escapes.
Docs: docs/mcp.md, docs/target-app-parity.md.
draw_shape's rotation also turns rectangles and ellipses; object.reflect's numeric axis is counter-clockwise from horizontal. A test covers that axis and the Scatter brush's rotation range, which every_turn_param_says_which_way_it_turns can't reach.
The hover lists up to 30 notes, fewer when the window is small, and says how many were left out. The docs and command description said it lists them all.
Window > 3D and Materials > Quick Actions > Expand as Wireframes, and the
command effect.expandAsWireframes, replace each selected object that has a
visible 3D effect (Extrude & Bevel, Extrude & Bevel (Classic), Revolve,
Inflate or Rotate) with a group of paths: the edges of the faces the effect
draws for the object as it is turned and projected now.
- Each edge appears once. Edges that meet end to end form one path, closed
where it comes back to its start, and curved edges stay curves. Geometry
effects after the 3D effect reshape the edges as they reshape the drawn
surface.
- The paths have a 0.5 pt black stroke with round joins and no fill. The
group keeps the object's id, name, transparency, attributes, slice and
text wrap, and is selected. A layer stays a layer holding the edges.
- It is one undo step. Nothing selected, no visible 3D effect, a solid that
can't be built or is drawn as its source art, or more than 1,000,000 edges
in one object is an error, and the document does not change.
Docs: docs/mcp.md, docs/three-d.md, docs/effects-parity.md,
docs/target-app-parity.md.
Fixes#6354
Window › Swatch Libraries › Patterns and the Swatches panel's library
menu gain a second built-in pattern library, Grit Textures, with eight
black textures on square grid tiles of 18 to 36 pt: Fine Grain, Coarse
Grit, Sand, Speckle, Stipple, Scratches, Sparse Flecks and Dense Flecks.
Each is drawn in code from a fixed seed, so it is the same every time.
Marks that reach past a tile edge are drawn on the next tile by the
tiling, so the tiles join without a seam.
Docs: docs/mcp.md, docs/target-app-parity.md, ROADMAP.
The check that a PDF/X-1a or PDF/X-3 file has no transparency read names
in literal strings and comments as syntax. The file identifier is a
base64 hash of the file, so a file could now and then hold `/BM` or
`/Lab` there and its export was refused as having blend modes or Lab
colors. The check now leaves out the text of literal strings and
comments as well as stream data.
Window › Swatch Libraries › Gradients gains Organic Fades, a gradient
library of fifteen fades (ten linear, five radial). Each runs through
three to five unevenly spaced stops with off-center midpoints, mixes
with the Perceptual method, and thins out to transparent at the end of
a linear fade or at the edge of a radial one. The colors are computed
from VectorCraft's own OKLCH anchors.
The library also lists in the Swatches panel's library menu, in
swatch.library.list (category "gradients") and in the Gradient panel's
Presets. swatch.library.add keeps each fade's stops, opacities,
midpoints and method in RGB and CMYK documents.
The other built-in libraries are unchanged: their gradients still mix
with Classic and keep centered midpoints, and a test checks it.
- Gradient previews in the Swatch Libraries panel, the Gradient
panel's Presets menu, swatch tiles and the toolbar drew every stop
opaque. Each chip vertex now takes the sampled opacity as its alpha
(freeform points too), and a chip with any translucent vertex draws
a white and gray checkerboard under the gradient. Opaque gradients
draw as before.
- When the preferences are applied, a saved gradient preset whose name
matches a built-in preset, or an earlier saved preset, in any case,
is renamed to the first free "<name> N" (N from 2), so a saved
preset named like a new built-in fade stays listed and can be
applied and deleted.
In distance mode, each pixel took a square root for every background color.
The nearest color is now found by squared distance, and only that distance is
converted to a percentage. The levels do not change.