These commands removed, moved or copied one row or object at a time:
the Layers panel's Delete Selection, Duplicate Selection, Collect in
New Layer, row drags, Merge Selected, Flatten Artwork and Release to
Layers, and Cut Artboard, Duplicate Artboard and the Artboard tool's
Alt-drags that copy art. Each edit moved the later rows of the same
layer or group to other indices. The next lookup by id then walked the
tree, and after every fourth such walk Document::index_path rebuilt
the whole lookup cache. Release to Layers also walked the document
twice for each new layer to name and color it. With 25,000 rectangles
in one layer, a release build of vectorcraft-cli took 11.9 s for
Duplicate Selection and 17.7 s for Release to Layers.
The commands now remove, move and copy the rows in one pass over each
layer or group, with Document::remove_many and Document::wrap, and
with copy_above, the copy pass of duplicate_in, which Duplicate
Selection and the artboard copies now share. Release to Layers names
its new layers from one walk of the document. Merge Selected checks
the target layer's objects against a set of the listed rows, and
Delete Selection checks the top-level layers against such a set. In a
document whose ids are unique, the rows keep their order, new rows and
layers take the same ids, names and colors, and the selection, the
undo step and the journal are the same. A release build with this
change takes 98 ms for Duplicate Selection and 26 ms for Release to
Layers.
Docs: docs/target-app-parity.md.
These commands moved selected objects into a hidden or locked layer,
or hid them, and left them selected, with the key object still set
when it was one of them:
- a row dragged into a hidden layer or group (layer.move);
- node.move into a hidden or locked layer or group;
- Merge Selected into a hidden or locked layer;
- Flatten Artwork into a locked layer;
- Collect in New Layer, when the topmost row it collects is in a
hidden or locked layer;
- applying a data set that hides bound objects (dataset.select,
dataset.next, dataset.prev).
They now call Selection::deselect_uneditable after the change, as
layer.setProps, layer.hideOthers and layer.lockOthers do. Every
selected object left hidden or locked is deselected, and the key
object is cleared when it is one of them. Undo restores the objects
and selects them again with the key object. A row drag into a hidden
layer and node.move into a hidden or locked layer still succeed. The
params text of layer.move, node.move, layer.merge, layer.flatten,
layer.collectInNew and dataset.select describes the deselection.
The Layers panel section of docs/mcp.md said that node.move has the
same rules as layer.move; it now says that node.move also moves a row
into a locked layer or group, which layer.move refuses.
Docs: docs/mcp.md, docs/target-app-parity.md.
The Artboard tool and the Artboards panel only ever had one artboard
selected, so Shift-clicking another didn't add it. As in Illustrator:
- Artboard tool: Shift-click adds an artboard to the selection (it
becomes active) or takes one out; a plain click on a selected one keeps
the selection, so a drag moves them all (Alt copies them all, the
copies becoming the selection), and Delete removes them all, one
artboard always staying. The other selected artboards show dashed
bounds; `selected` is a tool option.
- Artboards panel: with the Artboard tool, Shift- or Ctrl/Cmd-click on a
row adds or removes it, every selected row is highlighted, and Delete
Artboard removes them all.
- `artboard.move` and `artboard.delete` take `indices` besides `index`:
several artboards in one undo step, each with its art (an object moved
once where artboards overlap).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Guides on a hidden or locked layer leave the selection (Selection::prune,
run after every edit and selection change), their Layers rows neither
select nor drag them, and guide.move / guide.remove / guide.setLayer
refuse them; guide.setLayer refuses a locked target layer, as dragged
rows are refused there.
- A new guide goes where new art goes (the current layer, else the top
shown and unlocked one; refused when there is none), so it never lands
on a hidden layer and vanishes.
- Layer commands keep guides with their layers: Duplicate (and Alt-drag
copies of rows) copy a layer's guides onto the copy, Merge Selected and
Flatten Artwork put the merged layers' guides on the merged layer and
Flatten discards a hidden layer's. One shared doc predicate for "the
layer a guide is on"; the deleted-layer cleanup moves into the doc.
- Tests: engine tests for the above and their undo, a doc check that an
old guide reads with no layer and none is written, and a headless
Layers panel test of guide rows (select, drag to another layer, locked).
- Translations for the new message; docs and a ROADMAP progress line.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A ruler guide goes on the current layer (guide.add {layer}), shows,
hides, locks and is deleted with its layer, is listed in the Layers panel
as a row that selects it, and moves to another layer (guide.setLayer).
Guides on a hidden layer neither show nor snap; those on a locked layer
can't be picked.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CC5DiGJEZ5ADaQMBEQk4W1
Clicking an object's target circle in the Layers panel always replaced
the selection, so several objects couldn't be picked there. Shift-click
now adds the object (a layer: its art) to the selection, or takes it out
when it is selected already, as in Illustrator; nothing stays targeted
then. layer.target takes add: true for it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Fit to Artwork Bounds fits the art exports draw: hidden objects and
layers, guides and template layers don't count, and the bounds stop at
a layer's clip.
- The comparison with the page catches an object one draws that the
other doesn't (pixels whose neighbours all differ, away from type), a
light colour against white, and, for an EPS whose page is its art's
box, art the layers print outside it.
- textAs: outlines opens a .ai whose type shows from its PDF part, which
has the outlines.
- document.open takes editingData: false to open an Illustrator EPS or
.ai as its page or PDF part only, for print pipelines.
Part of #637.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`artboard.setProps {scaleArt: true}` maps the art fully inside a resized
artboard (as Move Artwork with Artboard gathers it) and its artboard guides
from the old rectangle onto the new one, each side by its own ratio, in one
undo step, and returns the ids scaled. Strokes, effects and corners follow
Scale Strokes & Effects and Scale Corners (`strokes`, `corners`), pattern tiles
Transform Pattern Tiles (`patterns`); locked and hidden art follows
`lockedAndHidden` (default: prefs moveLockedWithArtboard). The resolved choices
are journaled, so a replay scales the same objects the same way. A move that
keeps the size scales nothing.
The Artboard tool's `scaleArt` option (saved with `moveArt`) makes handle
drags proportional, as the public help describes, keeps them proportional at
the 1 pt minimum, and leaves the scaled art out of the Smart Guide targets.
Move and Scale Artwork with Artboard are check boxes in the Control bar and
Properties' Edit Artboards; the artboard size fields there and in the
Transform panel pass the option. Translated in the eight catalogs that have
Move Artwork with Artboard. docs/mcp.md and the ROADMAP updated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Guides dragged out of a ruler did not snap at all (only Shift to the ruler's
ticks): they now go through the engine (`Session::ruler_guide`, a
`NewGuide` previewing `guide.add`, one undo step) and snap as a moved guide
does: with Smart Guides to the edges, centres (so the sides' midpoints) and
anchors of the art and of the artboards, labelled; with Smart Guides off,
View > Snap to Point pulls new and moved guides onto anchors. Moving art
with the Selection tool already snapped flush to artboard edges and centres
with Smart Guides on; a test now covers it.
Artboard guides: `Guide.artboard` holds an artboard id (written only when
set, so canvas guides save as before and older files open unchanged).
`guide.add {artboard}` makes one, `guide.list` reports it; a guide dragged
out of a ruler with the Artboard tool belongs to the active artboard. It is
drawn, picked and snapped to across its artboard only, moves with it
(`artboard.move`, a pure move in `artboard.setProps`, `artboard.rearrange`),
is copied with it (`artboard.duplicate`, Alt-drag copy) and deleted with it
(`artboard.delete`, the guide selection kept in step).
Guides as Layers rows with their own lock and hide (part d) stay open: ruler
guides are not layer nodes; Lock Guides locks them all, and Make Guides
paths are Layers rows already. Listed in the ROADMAP parity row.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The engine kept its own copy of Document::next_layer_name after #353; the
document's now counts sublayers too, so the engine uses it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Art in a sublayer is now selected as objects (clicks, marquee, Select All, the
Select menu), sublayers select in their own colour, and hidden, locked or
template sublayers block clicks. Layer Options gain Preview (per-layer outline)
and Dim Images. New and fixed layer.* commands for the Layers panel: setCurrent
and highlight (rows at any depth), selectAll, move (reparent with cycle and
nesting checks, Alt copies), delete/duplicate rows, merge, flatten, collect,
release to layers, reverse, template, hide/outline/lock others and their
show/preview/unlock all, locate.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Paste (also without formatting) goes to the centre of the view
(edit.paste {center}); Paste in Front/Back with nothing selected go to
the top/bottom of the current layer, in order; Paste on All Artboards
keeps the objects' offset to the artboard they were copied from.
layer.pasteRemembersLayers {on?} (document flag paste_remembers_layers,
saved, document.inspect) pastes objects back into the layers they came
from by name, making missing ones; the Layers panel now has its menu
with the layer commands and the check item. The Paste menu items are
enabled while the system clipboard holds SVG (looked at once per frame
at most, a few times a second).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Clicking a Layers panel target circle runs `layer.target {id}`: a layer gets its art
selected and becomes the target (`Selection.target`) of the appearance, effect,
transparency and opacity-mask commands, which then edit the layer itself; the
Appearance panel lists it. Dragging a circle onto another runs
`appearance.transfer {source, target, copy?}` (Alt copies), dropping it on the trash
clears it. Filled dots also mark groups and layers with fills of their own, masked
objects get a dashed underline, and while an opacity mask is edited the panel lists
only an `<Opacity Mask>` entry and the tab says so.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
layer.clippingMask.toggle {id?} -> {clip}: the top object of the current
layer (or of the one selected group, or of `id`) becomes the clipping path,
unpainted and moved to the bottom so art added later is clipped too; pressing
the button again releases the mask and leaves the path unpainted. One undo
step. The Layers panel button runs it and underlines clipping-path names.
Model: NodeKind::Layer.clip (skipped when false). Clipped layers render, hit
test, bound, and export to SVG and PDF like clip groups (Node::clips /
set_clips); the clip-path helpers are shared with Make/Release Clipping Mask.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>