Choosing an Effect > Pathfinder item (Add, Intersect, Exclude, Subtract...)
with several loose objects selected now groups them and applies the live
effect to the group, in one undo step, so the result shows at once and stays
editable. A selection that already holds a group, or a single object, works
as before, and agents get `grouped: true` back when it happens.
Root cause: Pathfinder effects combine the contents of a group or layer.
Applied to loose objects, each one got an effect with nothing to combine, so
nothing visibly changed, while the Pathfinder panel's commands (found by the
command search) act on the selection directly.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The issue asked for non-destructive colour adjustments in the Effect menu
and the Appearance panel that work on vector paints, live type and
embedded images. Only the destructive Edit Colors commands existed, and
the live-effect pipeline only knew geometry and raster effects.
Effect > Color Adjustments adds six effects (adjust.*). They recolour,
in stack order, everything an object paints with: fills and strokes
(gradient stops too), type, gradient meshes, embedded images and a
group's members, each colour keeping its model. The Edit Colors walk over
an object's colours moved to vectorcraft_doc::recolor so the commands
and the live effects share it. The renderer draws adjusted art through
its object-effect path (recoloured images cached within a memory
budget), exports bake the adjusted colours (images as recoloured
copies), and Expand Appearance makes them permanent. The effect dialog
shows sliders, a channel menu and a draggable Curves graph, all previewed
live as one undo step.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
VectorCraft had an Additional Plug-ins Folder preference but nothing loaded from it. Port
PhotoCraft's wasmi plug-in host (same sandbox, manifest and parameter schema) as the new
vectorcraft-plugins crate (L2), extended for vector documents:
- Object filters read the selected paths and compound paths as JSON (native PathData and
Paint forms: geometry, fills, strokes, gradients, opacity) and return the objects to keep,
change, add or delete; the output is validated in full and applied as one undo step
(plugin.run). A failing plug-in leaves the document untouched.
- Live-effect plug-ins are geometry effects in the appearance stack (effect id
plugin.<id>), re-evaluated (and cached) when the object or parameters change, editable,
exported and baked by Expand Appearance; a missing plug-in leaves the geometry as is.
- plugin.list / info / run / install / remove / reload; the preference folder installs
every *.wasm at startup and when it changes; File > Open of a .wasm installs it (web).
- Object > Plug-ins and Effect > Plug-ins menus with dialogs generated from the parameter
schema (live preview), the Appearance panel's fx menu, docs/plugins.md, an original
example plug-in (Desaturate, a Rust crate outside the workspace) and fuzzing of the
plug-in boundary (engine/tests/plugin_fuzz.rs).
Tool plug-ins and paint-changing live effects are left for later (docs/plugins.md).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PDF export now renders the shadows, glows, blurs and feathers of groups,
layers, type, images, symbol instances, live objects and single fills and
strokes (and those inside opacity masks, symbol definitions and pattern
tiles) as images at the document raster effects resolution, instead of
leaving them out with a warning. Shadows and outer glows go under the
untouched vector art; a path whose fills or strokes carry effects is
written as one piece per fill and stroke. Expand Appearance shares the
image helpers (moved to rasterfx.rs); effect images now cover what the
renderer paints (members' shadows included).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Scaling with Scale Strokes & Effects on now scales stroke weights, dash
lengths and dash offsets and every distance parameter of object, fill and
stroke effects (groups and layers too), from new length metadata in the
effects catalogue. Off, nothing painted changes size and type keeps its
character strokes' weight. Scale Corners off keeps live corner radii.
object.scale/transform/transformEach take strokes?/corners? (default: the
preferences) and journal the values they used. The Scale dialog and a new
Transform Each dialog get both checkboxes, kept as the preferences on OK;
the panels' toggles go through prefs.set.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
[Registration] is a built-in swatch that prints 100% on every plate: Separations
Preview shows it on each process and spot plate and PDF export writes it as
/Separation /All. It can't be edited, moved, duplicated, merged or deleted;
swatch.list shows it after None and the Swatches panel applies it as a swatch.
Object > Create Trim Marks strokes the marks in Registration and marks every
artboard when nothing is selected ({style?, allArtboards?}). The preference
japaneseCropMarks (General) switches to Japanese marks: double lines at the
trim and bleed edges plus centre marks. Effect > Crop Marks (cropMarks) is a
live effect whose marks follow the object; rendering, SVG/PDF export and
Expand Appearance draw them. The mark geometry lives in doc::marks.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
effect.expandAppearance now expands the whole appearance: each visible fill becomes a
path of its own and each stroke its outline (a brushed stroke its brush art), grouped
in paint order under the object's id and transparency; geometry effects are baked and
raster effects become an embedded image (shadows below the art, blur/feather/inner glow
replacing it). Type with effects or its own fills is outlined, and a group's or layer's
own fills and strokes are expanded among its members. The command is enabled whenever
an appearance isn't basic. Builds on bake_leaf (effects::expand_leaf / expand_art) and
shares the raster-effect image code with PDF export.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A group's or layer's own fills and strokes paint every member's geometry, below or above the
members as the new contents slot (Appearance.contents_index) says; its geometry effects reshape
the members as one piece and its raster effects apply to the composite (one combined shadow),
respecting knockout groups. Type's own fills and strokes paint under or over its characters.
Render, SVG/PDF (via bake) and Expand Appearance evaluate them alike.
Commands: appearance.* / effect.* take target: "object"|"contents" and layer ids;
appearance.moveItem moves the Contents slot (from: "contents") or an item across it
(contents); appearance.targetContents selects a group's members. Graphic styles applied to a
group now style the group itself. The Appearance panel shows Contents/Characters rows that
drag, and double-click to target the members or edit the characters' paint.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Engine: effect.move {from, to, fromItem?, toItem?, copy?}; appearance.showAllHidden;
appearance.duplicateItem takes to? and indices?; appearance.removeItem takes indices?;
Appearance::has_hidden/show_all. UI: effect.dialog takes index? (edit in place via
effect.setParams) and opens the effectExists question for an effect already in the list.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Outline Stroke (and the stroke part of Expand) now builds each stroke from the
shared canvas geometry: dash shapes, arrowheads, width profiles and inside/outside
alignment, united into one clean path (pathops::stroke_region). Every stroke item
is outlined in paint order (runs of fills stay on copies of the path), stroke
opacity, blend mode and effects move to the new fill, and brushed strokes become
their brush art. The live Effect > Path > Outline Stroke outlines the stroke it
sits on (on a fill or the object: the top stroke) with that stroke's cap, join,
dashes, alignment, profile, arrowheads and weight: GeomContext now carries the
stroke and the fill rule, built per item by the renderer, export baking and
Expand Appearance.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
effect.apply, effect.remove, effect.setParams and the new effect.duplicate
take item (omitted: the Appearance panel's active item, else the object;
null: the object's own effects), so the fx button, the Effect menu, Apply
Last Effect and the effect dialogs (effect.dialog {item}) put the effect on
the selected fill or stroke. effect.list reports each object's item effects
and the active item. appearance.addEffect is an alias of effect.apply.
In the Appearance panel, item effect rows sit under their fill or stroke
with working eyes and inline editors, and can be selected for Duplicate
and Delete; a selected effect row is remembered per object.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>