The Pathfinder panel menu's Trap… (object.pathfinder.trap) and Effect › Pathfinder › Trap… (pathfinder.trap, live on groups) share one geometry (vectorcraft_pathops::trap_band, vectorcraft_effects::trap): Thickness, Height/Width, Tint Reduction, Traps with Process Color and Reverse Traps, plus the effect's Precision and Remove Redundant Points. The panel's Trap is one undo step and groups the traps above the topmost selected object. Behaviour from https://helpx.adobe.com/illustrator/using/trapping.html and https://helpx.adobe.com/illustrator/using/pathfinder-panel-overview.html.
Overlapping faces take the highest of each CMYK channel from every covering shape and drop strokes, matching Illustrator's Hard Mix effect.
Co-authored-by: Cursor <cursoragent@cursor.com>
Effect › Pathfinder left type in the group out of all ten operations,
on the canvas, in Expand Appearance and in exports. The text outliner
returns type as a group with one path per run. `leaves` in
crates/effects/src/group.rs took that group as one leaf, and
`geometry` gives no path for a group. A 100 x 100 pt square grouped
with a 100 pt "H" inside it kept all of its 10,000 pt² after Subtract
and Expand Appearance. In the shape modes a member group with type in
front also lost its paint, because it took the style of the outline
group, which has none.
`leaves` now takes the paths and compound paths of the outline art at
every depth, as it does for a member group, and gives each one the
type's opacity and blend mode. The same square keeps 8,684.88 pt² after
Subtract and Expand Appearance, its 10,000 pt² less the glyph's
1,315.12 pt².
Docs: docs/target-app-parity.md.
Type is drawn as its glyph outlines under a geometry effect, in EMF and
WMF export, in DXF export when it is written as outlines, through
Flatten Transparency with Convert All Text to Outlines, and inside an
envelope. Those outlines differed from the type the canvas draws in
four ways. They had no underline or strikethrough bars. A character
stroke on scaled type kept its unscaled weight. An unplaced gradient was
fitted to the glyphs it painted instead of the layout box. A run's
pattern tiles stayed in document space instead of scaling and turning
with the type. A group's or layer's own fills and strokes also painted
the glyphs of the type in it without the bars.
The outlines now include each run's underline and strikethrough bars,
as the canvas has drawn them since #850. Each run's path is made in
text space with its unplaced gradients fixed to the layout box, then
placed by the type's transform, which also scales its stroke weight
and dashes and transforms its pattern tiles. The type's own fills and
strokes have their unplaced gradients fixed to the bounding box of the
layout box in the document, where the canvas fits them.
Geometry effects that move or scale the outlines move and scale the
type's gradients with them: the type's own effects, also inside an
envelope and after Flatten Transparency has converted the type to
outlines, and the effects of a group, symbol instance or envelope that
holds the type. outline_text marks its group with a new node field,
type_outlines, which is saved with the document. reshape_leaves maps
the placed gradients in each marked group through the map that takes
the group's bounds before the effects onto its bounds after them. A
scale out of proportion stretches a radial gradient into an ellipse
and turns the isolines of a diagonal linear gradient, as it does on
type scaled by its own transform. Placed gradients outside those
groups stay where they are.
Geometry effects on a group or layer, and effects on a symbol instance,
blend or repeat, outline the type inside it. outline_nested_text
replaced each type object with a plain group of its outlines, so the
type lost its opacity, blend mode, opacity mask, knockout shape
option, own effects and perspective, and hidden type was drawn,
exported and made visible by Expand Appearance.
outline_nested_text now replaces type with the art that as_art makes
for it, which is also what reshape makes for type with geometry
effects of its own. That art has the type's own geometry effects and
perspective applied and keeps its name, transparency, opacity mask
and other effects. as_art also keeps the object's visibility and
knockout shape option, so hidden type with a geometry effect of its
own is left out of exports. Type in a clip group's clipping path still
becomes its plain outlines and now keeps its visibility.
Effect › Distort & Transform › Transform… was a plain list of fields.
It now has Transform Each's layout: Scale and Move with sliders, Rotate
with an angle dial, then Copies, Reflect X and Y, the reference point and
Random, kept with the effect so editing it from the Appearance panel
shows them again.
- The effect scales, rotates and reflects about the chosen point of the
9-point grid (`reference`, the centre by default).
- Random takes a share of each value, drawn from the object's id: each
object varies its own way and keeps its result on every redraw; a
group's members move together.
- Copies stop before one reaches past 1e9 pt, and the scale and move are
capped, so large values can't overflow.
- Transform Each and the effect share the sections and options code; the
angle dial is a new widget.
- A plain number field now takes the focus when it is a dialog's first
field, so both dialogs open with Scale › Horizontal ready for typing.
Transform Objects, Transform Patterns and Scale Strokes & Effects are not
in the effect yet: the geometry effects reshape paths only.
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>
Shipped code no longer unwraps, expects or panics: every one of the 124
unwrap()/expect()/panic!/unreachable! sites outside tests now handles the
failure (Result/Option, ?, let-else, defaults) and reports errors to the user.
- Lints: workspace clippy denies unwrap_used, expect_used, panic, todo,
unimplemented and unreachable; clippy.toml allows them in tests, and
integration tests, examples and testkit opt out explicitly.
- Safety net (vectorcraft_engine::guard): a panic in a top-level command rolls
the document back and returns EngineError::Internal; a panicking tool is
reset; the MCP server answers with an internal error and keeps serving; the
UI frame and each control request are guarded.
- APIs that hid failures now return them: Rendered::to_png/to_jpeg/to_webp
return Result (JPEG/WebP errors used to write empty files),
FontDb::face returns Option, Region::top returns Option.
- Fuzzing: engine/tests/import_fuzz.rs feeds garbage, hostile and mutated SVG
and PDF through import → render → export (30k cases locally, no panics).
- Docs: AGENTS.md/CLAUDE.md rule, docs/development.md "Robustness" section,
README pointer and a PR template checklist.
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>