swatch.library.load, graphicStyle.loadLibrary, symbol.loadLibrary and
brush.loadLibrary read the whole file or decoded data before checking
`name`, so a call with a `name` that is not a string read the file
first, and with a missing file reported the file error instead of the
parameter error. The shared loader now checks every parameter before it
reads anything.
A colorized image's color channel is the paint's samples repeated once a
pixel, and nothing bounded its size: an image colorized in Registration in
a document with many spot swatches could allocate without limit, and an
overflowing length panicked inside repeat. The length is now computed with
checked arithmetic and refused above MAX_RASTER_ALLOC, the image's own
decode budget, and the export leaves such an image out with the existing
"an image couldn't be decoded" warning instead of drawing it uncolored.
Alt in a spiral drag now rounds the fitted segment count to whole winds
of four segments, counted from the segment count when Alt went down.
Ctrl/Cmd takes precedence when both keys are held, and switching back to
Alt starts from the current count with the held inner end kept. Arrow
keys, Escape, release and a new drag clear the held Alt count.
Tests cover both keys together, a switch mid-drag, Escape, the 2 to 1000
bounds and the committed path's anchor count. docs/mcp.md and
docs/target-app-parity.md describe the rule.
The reference app adds or subtracts winds from a spiral with Alt-drag
and changes its decay rate with Ctrl/Cmd-drag. VectorCraft's Spiral
tool did nothing with either key during a drag.
While a spiral is dragged out, Alt or Ctrl/Cmd keeps the spiral's
inner end at the distance from the center it had when the key went
down, and the outer end follows the pointer. With Alt the number of
segments changes to the nearest whole number that fits, within 2 to
1000, so dragging outward adds segments and dragging inward removes
them. With Ctrl/Cmd the decay changes to fit, within 5 to 99.99
percent, the decays a spiral is drawn with. When both keys are held,
Ctrl/Cmd changes the decay. Up/Down with a key still held move the
held radius to the new segment count. The new values stay when the
key is let go, and as the Spiral tool's segments and decay options
for the next spiral. Both keys also work with a 5 percent decay and
hundreds of segments.
Docs: docs/mcp.md, docs/target-app-parity.md.
Effect › Color Effects › Vector Halftone… (addon.color.halftone, also in
Object › Plug-ins › Color Effects) draws its object as the halftone dots
Object › Vector Halftone makes, live: mono (one dot colour, or each dot in
the art's colour under it) or CMYK screens, the five dot shapes,
frequency, angle, invert and clip to the art's outline.
- The screens, dots and caps move to vectorcraft_effects::addons::halftone,
shared by the command (its behaviour and tests unchanged) and the effect.
- The renderer samples the art (vectorcraft_render::addons::halftone) and
keeps the dots by the object's content and what it reads from the
document, so unchanged art isn't sampled again; past 100000 cells per
screen the object draws as it is.
- Expand Appearance turns the object into its dots, and the SVG, PDF, EPS
and AI exporters write them as paths.
- Its dialog reuses the command's fields, without Keep Original.
Deferred: stochastic and radial patterns, a dot-gain curve, per-screen
separation settings, type or symbols as dots.
Path Precision Tools gains the Parametric Shape Tool: ten kinds of shape
(rectangle, ellipse, polygon, star, ring, arrow, cross, heart, gear,
speech bubble) that stay editable as numbers.
- Geometry in vectorcraft_pathops::addons::pathtools::shapes: each kind's
outline, corner rounding limited to the middle of a side, a fingerprint
of the outline, recovery of centre, size and rotation after a move,
turn or scale, and recognition of plain rectangles, ellipses and
regular polygons.
- The tool (parametricShape, All Tools drawer and Object › Plug-ins ›
Path Precision Tools only, no shortcut): drag from the centre (Shift:
45° steps), arrow keys change the count and values while dragging,
handles edit a selected shape, double-click places one.
- Commands addon.pathtools.shape.create / .set / .convert, one undo step
each; params checked (counts 3..1000, sizes up to 16384 pt).
- A shape keeps its numbers in one object-data entry (vc-pathtools-shape)
that SVG export already leaves out; anchor edits make it a plain path.
- Parametric Shape panel, cursor stand-in, catalog rows in all 25
languages, docs and tests.
With no library yet, library.add made and saved "My Library" before it
looked for the group or item to place the new one by, so a bad `group`,
`before` or `after` failed but left an empty library behind. The new
library is now kept only once the item is in it.
Art dragged off the canvas and colours dragged in from elsewhere (swatches, another library's)
used to be added at the end of the ungrouped items, wherever they were dropped. They now land
as items dragged within the list do: on another item of their kind, just before or after it by
the pointer's half and in its group; on a group, into it; away from the items, ungrouped at the
end as before.
library.add takes group and before/after, placed as library.moveItem places an item (the
placement is shared). A library change that fails partway now leaves the library as it was.
People reuse the same gradients across documents and rebuilt them by
hand. The Gradient panel now has a Presets menu: the presets of the
app's built-in gradient libraries, grouped by library (theme), then
the saved ones. Choosing one gives the gradient behind the active
proxy (or a solid paint) the preset's type, stops, method and dither,
keeping its placement, as one undo step, through paint.editGradient.
The panel menu saves the current gradient as a preset (named in a
dialog) and deletes saved ones; Hide/Show Presets toggles the row.
Saved presets are kept with the preferences, next to the other user
preset lists (width profiles, flattener, perspective). Stops linked to
a document swatch keep their colour, unlinked, since a preset is used
in other documents. Built-in presets can't be deleted; names are
unique.
Commands: gradient.presets.list, .apply, .save and .delete. The menu's
rows are drawn only while in view, as its headings are.
Tests: engine tests for list, apply (fill and stroke, placement kept,
one undo step), save (unique names, unlinked swatch stops) and delete;
panel tests for applying from the menu and saving, deleting and
hiding presets from the panel menu, including scrolling the menu to
the saved presets. Docs: gaps G13, target-app and UI parity, ROADMAP.
Patch and triangle mesh shadings of more than 4,096 patches, and strokes
painted with a mesh shading, came in as a flat grey. Illustrator writes
meshes of up to 14,355 patches, and writes a freeform gradient on a
stroke as a stroke painted with a type 7 shading.
- MAX_PATCHES is 16,384, as in the .ai editing-data reader.
- A stroke painted with a mesh shading is the meshes clipped to the area
the stroke paints (stroke_outline: width, caps, joins, miter limit and
dashes, built in the path's space and then transformed); draw_meshes
always clips a stroke's meshes.
Two follow-ups to the empty-page fallback:
- A page counts as empty only when nothing on it was skipped: its only
notes are the page's own (art off the artboards, art past the page). A
page whose only content couldn't be read, such as an image that can't
be decoded, keeps its notes and goes through the usual check against
the editing data, instead of being replaced by it unchecked.
- With textAs: outlines, the document read from the editing data alone
has its type outlined. The usual path takes outlines from the page,
but an empty page (or a text-only placeholder, #1387) has none to give.
A mesh in the editing data that the reader couldn't read made the whole
file come in as its page or PDF part, without its layers. Three cases
were rejected that files write routinely:
- A mesh starts grey, and `/CS` is written only where the colour space
changes, before the corner it applies to, even within a patch. Meshes
with no `/CS`, or one that changed between corners, were unread.
- Named colours (`[c m y k /DeviceCMYK (name) /Process]` or `/Spot`) and
`/NChannel` inks: each corner gives the tint, 1 being the full colour.
- Grids over 64 patches a side or 4,096 patches (files have 97 x 72).
Each corner now takes the colour space last set before it; named
colours paint at their tint and inks overprint at theirs; the limits
are 128 a side and 16,384 patches.
In effect dialogs (like Color Halftone), length fields with defined bounds
(e.g. Max Radius 4..127 pt) were previously checked only after num_field
returned, leaving the field's temporary buffer holding the un-clamped string
(e.g. '0.5 px'). Subsequently entering invalid text caused the field to
fall back to that sub-minimum buffer.
- Added num_field_within to pass effect parameter bounds directly to unit_field.
- When committed, clamp the parsed value within bounds and update the field
buffer to the formatted clamped value so the UI reflects what is applied.
- When invalid text is committed, clear the invalid buffer and trigger a
one-frame border highlight so invalid input is rejected visibly.
normalize_bez ran the sweep without the catch_unwind guard that Sweep::new has,
so an outline_stroke width of 1e200 or more with a round join panicked inside
linesweeper (Left == Ish). The panic is now a Degenerate error and the art is
left unchanged. Adds hostile-number tests for the pathops edit, stroke and
offset functions.
A built-in add-on under Object › Plug-ins › Smart Pen:
- The Smart Pen Tool draws and edits Bézier paths without switching
tools: a click adds the next segment straight or curved (a panel
toggle; Tab flips the segment being placed or the last one), a drag
makes a smooth point (Alt breaks the handle, Shift snaps to 45°, Space
moves the point), a curve after a straight segment joins it tangent.
- On existing paths it selects and moves points, removes a point keeping
the shape (Alt-click), toggles smooth/corner (double-click), drags
handles, reshapes a segment by dragging it and inserts a point on it
(Alt-click); it closes, continues and joins open paths.
- The Smart Pen panel: next segment straight or curved, remove points
keeping shape, make smooth, make corner, retract handles, close or
join.
The tool stays out of both toolbars as shipped; the All Tools drawer
lists it under the add-on's heading. Commands are addon.pen.*; the
existing Pen tool, commands and menus are unchanged.
A built-in add-on under Object › Plug-ins › Path Precision Tools:
- Anchor Eraser Brush: painting over selected paths removes the anchors
under the brush that the outline can do without within a tolerance,
refitting the handles beside them (Alt ignores the tolerance, Cmd/Ctrl
deletes without refitting, pen pressure can scale the brush); one undo
step per stroke.
- Extend Path tool: dragging an end of an open path carries it on
straight, by stretching its last curve or along the circle it curves
on, or shortens it back along itself.
- Measure & Inspect tool: drag to measure distance and angle; hover a
path to read segment and path length, area, curvature, tangent and
anchor angles and handles, in the document's units.
- Anchor Inspector panel: the selected anchor's position and handles as
numbers, with Make Smooth (auto-smooth rule), Make Corner, Equalize
Handles, Remove Points Keep Shape, Add Points and three ways to close.
- Add Points at Crossings and Split at Crossings.
The tools stay out of both toolbars as shipped; the All Tools drawer
lists them under the add-on's heading. Commands are addon.pathtools.*;
the existing commands, tools and menus are unchanged.
A built-in add-on in Effect › Color Effects and Object › Plug-ins › Color Effects:
- Exposure (stops of linear light, offset and gamma), Desaturate and
Invert Colors as live colour adjustments, evaluated in stack order with
those of Effect › Color Adjustments.
- addon.color.filter applies any colour adjustment to the colours
themselves, through the Edit Colors pass, as one undo step.
- A panel picks an adjustment and its values, then adds it as a live
effect or applies it as a filter.
The add-on lives in its own modules (effects, engine and ui-egui addons
folders) and leaves the existing effects, commands and menus as they
were.
A built-in add-on under Object › Plug-ins › Artwork Cleanup:
- Simplify Anchors (Keep Shape) removes anchors while the outline stays
within a tolerance, optionally keeping sharp corners.
- Document Health Check finds and fixes 16 kinds of problems in the
selection or the document (stray points, duplicate and collinear
anchors, tiny handles, nearly closed paths, needless groups, compound
paths and clipping groups, unpainted and invisible objects, duplicate
objects, art off every artboard, empty artboards…), with Show, Fix
Selected and Fix All, each fix one undo step.
- Deep Ungroup and Rejoin Path Pieces.
The add-on lives in its own modules (pathops, engine and ui-egui
addons folders) and leaves the existing commands, tools and menus as
they were.
UPDATE_APP (native builds; craft-update is a native-only dependency) carries our 128 px icon and accent (#e8573f, its colour in ArtCraft Launcher). The updater, the self-update
helper and craft-update's startup prompt all get them through crate::UPDATE_APP; the
prompt draws the icon, the accent and "by ArtCraft" (craft-update's default developer).
craft-update is pinned to storytold/craft-libs main at 1065653e7 (#434).
Clippy fixes for Rust 1.99 in untouched code (same logic):
- crates/svg/src/import/fx.rs
- crates/tools/src/text/tool.rs
A placed (linked) file is put where its matrix takes the canvas point of
art space's origin (the centre of %AI3_TemplateBox). In many files the
matrix takes the corner of the box the file is written with instead, so
the image landed far off its artboard, the layers differed from the
page, and the file came in as its PDF part.
The reader keeps that second placement for each placed file where the
two differ. When the layers don't draw as the page, they are compared
again with those files at their box's corner, and used if that draws
as the page. Files whose layers already match keep their placement.
A placed (linked) file written as an object's editable copy, on %_
lines after its drawn look, has its %AI5_BeginPlace and %AI5_EndPlace
markers on those lines too. The lexer dropped comments after %_ that
don't start a section, so the placed file never began, the ~ that ends
it was an operator the reader didn't know, and the whole file came in
as its PDF part. The lexer now returns those two markers from %_ lines,
and the preview reader skips the %_ its header line starts with.