- packaging/linux/package.sh: one verify_sha256 helper replaces the four
repeated printf|sha256sum -c pipelines.
- packaging/macos/package.sh: stapler_retry copies its positional
arguments into locals before use.
- swatch_options: f64::from(v) instead of v as f64 (same value; the
argument is an f32, so the conversion stays).
shapeBuilder.merge built the planar map of the selection again, on the
thread that runs the command, although the Shape Builder tool had just
built the same map for its hover. The tool now returns its map from a
new Tool::shape_builder_map, and the command uses that map when its
inputs are the merge's inputs and its gap is the merge's gap; otherwise
it builds its own as before. The tool's map has the outline edges, so
erasing and splitting a stroke use it too.
CodeRabbit on #4080: `needed` summed footprint pieces before insertion
deduplicated them, so on a degenerate grid (ten collinear lines, 4,096 pieces
each in ten cells) every item exceeded the budget and went to the scanned list,
making the per-cell assertion vacuous. The cells are now collected in piece
order and consecutive repeats dropped before the budget check and the filing;
the horizontal fixture asserts `rest` is empty and that the lines are filed.
docs/target-app-parity.md: the Path operations area row, the Shape Builder
row and the evidence list record the bounded index (scores unchanged).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014gCpjL3yUhaH3jRp7ksufh
A group counted as a Live Paint group when its name started with "Live
Paint". A plain group named, for example, "Live Painting" was then read
as one. With it and another shape selected, the Shape Builder found no
regions in it, and a merge on the other shape deleted the group and its
paths. Make Live Paint took the group as a Live Paint group to merge
into, and its paths did not become sources.
A Live Paint group now also needs its sources group, the group named
"Live Paint Sources" that Make Live Paint puts in it. A plain group with
such a name is traversed like any other group.
draw_path, draw_shape and object.setProps take opacity in percent (0-100),
but the document.inspect / document.node summary behind doc_inspect,
inspect_document and vectorcraft://object/{id} reported the stored 0-1
fraction under the same name. An agent that read 0.55 and wrote it back
got a nearly invisible object.
The summary now adds opacityPct (0-100, rounded to 1/100 of a percent)
beside the unchanged opacity, and the tool, resource and command
descriptions say which scale each field uses. Round-trip test in the mcp
crate: draw at 55 %, read 55 back from doc_inspect, inspect_document and
the object resource, write it back unchanged.
Follow-up to #4021. The grid filed each piece of a segment under its cells
without checking, so a degenerate grid (collinear horizontal lines: cells a
hundred points wide and a hair tall) stored one segment ~400 times per cell,
and coincident vertical segments (one column, a row per segment) filed every
segment under every row: a quadratic number of references, about a GiB for
16,384 segments within the Shape Builder's limit.
Now a segment is filed once per cell (its pieces come in order, so the cell's
last entry is enough to check), and the grid holds a budget of references
(64 per item plus four rows' or columns' worth, `reference_budget`); the
items past it go to the scanned list, so the index stays O(n·sqrt(n)) in
memory and every lookup still finds every segment through its point.
Regression: `rect_index_holds_a_bounded_number_of_references` (fails without
the change: 4,100 references per cell for ten collinear lines).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014gCpjL3yUhaH3jRp7ksufh
## Summary
`vectorcraft-cli convert` to PDF now passes `preserveEditing: false`, matching
a command-line converter expectation while Save As PDF in the app still uses
the VectorCraft Default preset. `--preserve-editing` opts in and adds a JSON
warning when the native document attachment is written.
## Tests
Integration test in `vectorcraft-cli` checks default PDF output has no editing
attachment and `--preserve-editing` embeds it with a warning.
Closesstorytold/vectorcraft#3627
Co-authored-by: nrq6993-a11y <nrq6993-a11y@users.noreply.github.com>
## Summary
`vectorcraft-cli convert` to PDF now passes `preserveEditing: false`, matching
a command-line converter expectation while Save As PDF in the app still uses
the VectorCraft Default preset. `--preserve-editing` opts in and adds a JSON
warning when the native document attachment is written.
## Tests
Integration test in `vectorcraft-cli` checks default PDF output has no editing
attachment and `--preserve-editing` embeds it with a warning.
Closesstorytold/vectorcraft#3627
Co-authored-by: nrq6993-a11y <nrq6993-a11y@users.noreply.github.com>
Use function paths where a closure only forwarded its argument
(PoisonError::into_inner, OsStr::to_str, FindRange::is_empty), and drop
redundant 'static on associated and module consts. No behaviour change.
An undefined number (--) in `-- -- angle length Bh` is read as a radial
gradient with no highlight, and XC (a color space name after a linked
image's file name) is ignored like its neighbours. Either one used to make
the whole editing data unreadable, so the file opened as its PDF part and
lost its layers and live text. A -- anywhere else is still an operator the
reader doesn't know.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
wasmi compiles each function of a plug-in when it is first called and,
by default, charges the run that calls it 7 instructions for each byte
of the function. The host hands a run its budget in 20 M-instruction
slices and resumes it when a slice runs out. But when a slice runs out
while a function compiles, wasmi returns an error from the call, not an
out-of-fuel pause, and the host reports it as Limit("instruction
budget"). So a plug-in's first run could fail with most of its budget
left, depending on where the slices fell, and the next run, with its
functions compiled, succeeded.
StitchCraft's PES exporter hit it on a design of 98 × 148 mm. In
VectorCraft 0.17.0's host its first export failed with 10 G and with
275 G instructions alike, and its second succeeded, taking under 1 G.
Run on wasmi directly, with the host's slices, the first export failed
in its 36th slice ("required_fuel=174139"), and with compiling free it
finished in 49.
Compiling now costs nothing: wasmi's fuel costs with no cost for
translating or validating, and its default cost for copying. A run pays
for its own instructions only, as many on its first run as on the next.
Compiling every function when the plug-in loads (CompilationMode::Eager)
also fixes it, but loads a 1.4 MB module in 42 ms instead of 10.
The new test fails without the change: a run that takes 1,040
instructions once its functions are compiled failed within them on a
plug-in just loaded.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HhvnnnD5fTFupK8WWq35un
With the Type tool at a caret and no characters selected, choosing an
item in the Character panel menu's Character Direction submenu set the
direction of every character in the type object. The three items are now
disabled until characters are selected.
The Symbol Stainer mixed the color of type characters painted with a
global swatch but kept the swatch name and tint, so the characters'
paint named a swatch whose color it no longer had, and a later edit of
the swatch could put the unstained color back. Their fill and stroke now
become plain colors, as a path's paint does.
With nothing selected, Cmd+/ and Cmd+Alt+/ ran the commands, which put
"select objects or give ids" in the status bar, and the command palette
listed both as available. Without ids and without an Appearance panel
subject (a targeted layer, group or object, or a selected one), the two
commands are now off in menus and the palette, as the panel's buttons
are, and their keys run nothing. Called with ids, they still add to those
objects.
The Paintbrush drops a sample less than a pixel from the last kept
point, and a release there keeps that point. The new test moves the
pointer inside Close Paths When Ends Are Within while the kept point
stays outside it, and checks that the cursor shows no closing ring and
that the release leaves the path open.