Commit Graph
1017 Commits
Author SHA1 Message Date
vangel76andClaude Opus 5.5 7cd6b5d983 Effects: Expand Appearance and export give each Transform copy of a gradient path its own gradient (#2490)
A path with a Transform effect that makes copies and a gradient was still merged into one path by bake_leaf and expand_leaf, so the gradient spanned every copy. Route it through reshape / expand_outlined like the renderer does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 13:20:26 +07:00
dotCooCoo ee61583606 Artboards: commands given an index that names no artboard fail instead of editing another one
artboard.setProps and artboard.fitToSelection read an `index` that is
negative, fractional, a string or null as 0 and edited the first
artboard, and artboard.setProps edited the first artboard when the
call named no `index`. artboard.duplicate, artboard.copy and
artboard.cut took the Artboard tool's artboard for such an `index`.
artboard.reorder failed for it with "missing index".

These commands now read `index` as artboard.delete, artboard.move and
artboard.fitToArt do, and fail with "no such artboard" when it names
no artboard; the document and the clipboard stay as they were.
artboard.setProps without `index` fails with "missing index". Without
`index`, artboard.fitToSelection still fits the first artboard and the
copy commands still take the Artboard tool's artboard.

Docs: docs/mcp.md.
2026-10-17 13:20:23 +07:00
NetterSilverandClaude Haiku 5.5 92647fa5b6 Quote graph data CSV labels so they round-trip through graph.setData
Found while testing crates/doc/src/graph.rs:429 (GraphSpec::to_csv) and crates/engine/src/cmd/graph.rs:85 (parse_csv)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 13:20:23 +07:00
dotCooCoo 1e3886c053 Document Raster Effects Settings: a file's resolution outside 1 to 2400 ppi opens in range
document.rasterEffectsSettings accepts a resolution from 1 to 2,400
ppi, but a file's raster_effects_ppi opened as it was saved. With 0,
-5 or 5000 in the file, object.rasterize without a ppi param failed
with "ppi must be between 1 and 2400", and document.rasterEffectsSettings
and document.info reported the stored value. With 0 or -5, EPS and
PDF export wrote a freeform gradient as a 1 x 1 px image, and EMF
export wrote every gradient as one. A saved New Document preset in the
preferences kept such a value too.

A file's or a saved preset's resolution outside 1 to 2,400 ppi is now
read as the nearer end of that range. Documents with a resolution in
range open as before.

Docs: docs/mcp.md (resolution, rasterEffectsPpi).
2026-10-17 13:20:23 +07:00
Brian TorresandClaude Opus 5.5 7c80b286c7 Fix #2540: Object → Expand expands Intertwine groups
Expand had nothing for Intertwine groups. It reported success but left
the group live (it only dropped the members' live shapes), and its
Stroke and Fill options could not reach the members, so a second Expand
found nothing to do. Ungroup takes apart plain groups only, so it did
nothing either.

Expand's Object option now turns every Intertwine group in the selection
(inside groups too, inner ones first) into a plain group of what it
draws: its objects, keeping their ids and order, then each part drawn
over the others as a clip group. The group keeps its id, place,
transparency and appearance, everything happens in one undo step, and
the dialog enables Object for an Intertwine group. Ungroup then takes
the result apart, as with an expanded blend or repeat.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 13:20:23 +07:00
vangel76andClaude Opus 5.5 91fa3af21d Export: raster document.export takes a page rectangle (rect) (#2412)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 13:20:23 +07:00
bflatastic 424a49604c Layers: Merge Selected keeps to the highlighted layers, as documented (#2383)
Reverts the fallback that merged the layers of art selected on the canvas when no
layer row is highlighted: Illustrator's Merge Selected merges the highlighted rows
into the last one highlighted.
2026-10-17 13:06:52 +07:00
vangel76andClaude Opus 5.5 fdc08e25d6 Layers: Merge Selected merges the layers of art selected on the canvas (#2383)
With no highlighted rows and art selected in two or more layers (Select All), layer.merge merges those layers; the panel menu enables it then.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 13:06:51 +07:00
vangel76andClaude Opus 5.5 1ff7ac7557 Layers: Merge Selected with a layer and its sublayer highlighted merges into the last top-level layer (#2383)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 13:06:51 +07:00
vangel76andClaude Opus 5.5 d39e02b3fe Type: selected overflowing type shows its red out port with any tool (#2323)
The overflow marker was drawn by the Type tools only, so with the Selection tool a text box smaller than its text showed no sign that text was hidden. Session::overlays now adds the marker of every selected area type and type on a path that overflows, unless a Type tool is active (it draws its own). The verdict is cached per object and font generation.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 13:06:51 +07:00
vangel76andClaude Opus 5.5 57c79dc0b4 PNG export: an sRGB chunk marks the colours as sRGB, embedIcc turns it off (#2221)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 13:06:51 +07:00
dotCooCoo efdb04db8a Lint: action_batch.rs compiles without an unused import on wasm32
On main, cargo xtask wasm printed an unused-import warning for json in
crates/engine/src/cmd/fileio/action_batch.rs, and this check reported
it as an error:

    RUSTFLAGS=-Dwarnings cargo check -p vectorcraft-engine --target wasm32-unknown-unknown

Every use of json! in action_batch.rs is in code compiled only for
native targets. The wasm32 version of action_batch uses Value only.

The json import now has the same #[cfg(not(target_arch = "wasm32"))]
attribute as the code that uses it. Native builds import the same
names as before.
2026-10-17 12:50:37 +07:00
NetterSilverandClaude Haiku 5.5 8ca4cd2cbf Fix graph axis labels saturating beyond the i64 range
Found while testing crates/engine/src/cmd/graph.rs:193 (fmt_value)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-17 12:50:37 +07:00
dotCooCoo 3d2e8bbe82 PDF export: Add Around is clamped when a file opens, and art too large for f64 gets no effect image
document.rasterEffectsSettings accepts addAround from 0 to 1,000 pt,
but a file's raster_effects.addAround opened as it was saved. With
addAround 1e300, the area of a raster effect image overflowed f64,
the image scale became 0 and the image got the transform
[inf, NaN, NaN, inf, x, y]. PDF export left that image out, so the
drop shadow was missing.

A file's addAround now opens clamped to 0 to 1,000 pt. An effect
image whose area or scale is not finite is not made. Export then
keeps the object with its effects, and Expand Appearance expands it
without an image, as when its PNG can't be encoded.

Docs: docs/mcp.md (addAround).
2026-10-17 12:50:36 +07:00
bflatastic 0af1741e24 Crop Image: the RGBA size check can't overflow on a huge header 2026-10-17 12:50:36 +07:00
dotCooCoo 6b0d1ed1c0 Crop Image: trim checks the image's RGBA size before decoding it
Crop Image's trim (object.cropImage {trim: true}) decoded the image
within MAX_RASTER_ALLOC (2 GB) and then converted it to RGBA. The
decoder holds the decoded image, before conversion, to that allowance,
so a gray or 1-bit image within it could take up to four times as much
once converted.

Trim now reads the image's size from its header first and, when
width × height × 4 is over the allowance, fails before anything is
decoded, with the check and message Load Texture uses: "an image of
W × H pixels is too large to draw". Images within the allowance are
trimmed as before.
2026-10-17 12:48:19 +07:00
dotCooCoo 9bee299dd5 Render: an export no longer warns about images another thread could not decode
A raster export compared the process-wide count of images that could
not be decoded before and after it drew, and warned that "an image
couldn't be decoded and is missing from the picture" when the count
rose. Any other thread that failed to decode an image in that time
raised the count too: a second export, the UI thread drawing the
canvas, or the canvas, thumbnail and placed-document workers drawing a
document with such an image. The export then warned about an image it
does not contain. In the engine's tests,
options_not_applied_yet_and_document_features_warn failed in 5 of 60
runs of the tests_raster and tests_pdf* tests.

The count is now kept per thread. An export reads it on the thread it
draws on. That thread decodes every image the export draws that is not
already in the shared image store, and an image that failed to decode
is never stored.
2026-10-17 12:48:19 +07:00
Marco Arnulfo f31d91bf1a Layers: a .ai another app wrote opens with its top-level layers closed, as its groups (fixes #1475) 2026-10-17 12:26:14 +07:00
Fabio William Conceição 0ffe0c7c0e Part of #394: Highlight Alternate Glyphs defaults to off. 2026-10-17 12:26:13 +07:00
Michael GiesonandClaude Opus 5.5 2d0da1472f Cursors: 36 more tool states get cursors of their own, listed in cursors.toml
Node editing as the public manual describes it: Direct Selection's anchor squares (hollow
or filled), Reshape Segment over a curved segment, Group Selection's plus (also Direct
Selection with Alt), the arrow hollow while a drag snaps, and Alt-copy arrowheads. The
Anchor Point caret, the Curvature pen and Free Transform's side-shear arrows (ShearH,
ShearV) are drawn in code. Lasso, the freehand, symbolism and other tools return cursors
of their own that borrow their old look until drawn (Cursor::stand_in).

crates/tools/src/cursors.toml lists every Cursor value, when it shows and its hotspot,
for whoever draws them; `cargo xtask cursors` (in ci) warns about a missing, unknown,
repeated or incomplete entry and never fails. The busy cursor is listed as missing (G1).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-17 12:26:12 +07:00
dotCooCoo 18b472092e Guides: Release Guides turns selected ruler guides into paths
View › Guides › Release Guides only cleared the guide flag on paths
made with Make Guides. Ruler guides could not become paths by any
route, and with only ruler guides selected the command released every
guide path in the document instead.

Release Guides now also releases the selected ruler guides. Each one
becomes an open straight path with no fill or stroke at the top of the
guide's layer: an artboard guide runs across its artboard, and a
canvas guide runs across the bounds of all the artboards. The ruler
guide is deleted, the released paths are selected, and the release is
one undo step. With no guide selected, every guide path is released,
as before.

view.guides.release takes index (a ruler guide) and ids (guide paths,
and the guide paths inside them). Both are refused while guides are
locked, and index takes only a guide on a shown, unlocked layer.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-16 16:07:21 +07:00
GameDirection 6fc79c33b7 Export for Screens: batch exporting with name patterns, folders and presets (#1935)
Issue #1935 asks for batch exports of many logo variations in many
formats, each format in its own folder. This builds on Export for
Screens, which already writes every chosen artboard in every format row.

Names: a file name pattern (`name`) names every file alike. Tokens:
<filename> (the document), <name> (the artboard, asset, layer or
object), <index>, a run of # (a counter, zero-padded to the run's
length, from counterStart; counterPer item or file), YYYYMMDD,
YYYY-MM-DD, <date>, <time>, <YYYY>, <MM>, <DD>, <format>, <scale> and
<suffix>. A trailing .ext is dropped. Words are not changed: only the
date patterns and the bracketed tokens are. `date` sets the day (the
default is today, UTC). Different files that a pattern names alike get
-2, -3... Without a pattern, two rows with one name still write the
first row only, as before.

Folders: `folders` puts all files in one folder, a folder per row (as
Create Sub-folders did), per extension, per item, or per item and then
extension.

What is exported: besides artboards, assets and the full document,
`layers` (each layer's art alone, sublayers included) and `selection`
(one file of the selection, or a file per object).

Formats: rows can also be EPS, AI and VectorCraft (a document of the
item alone, its one artboard). A PDF row with printer's marks (PDF
Print in the dialog: trim, registration, colour bars, page information,
suffix -print) sits next to a plain PDF row.

Presets: document.exportPresets.list, .save and .delete keep batch
export presets with the preferences, and `exportPreset` uses one under
the call's own params. Built-in: Logo Package (SVG, PNG 1x and 2x, PDF
and print PDF, a folder per format) and Print-Ready PDF.

Dialog: Layers and Selection tabs with thumbnails; an Export Preset
menu with Save and Delete; Folders; File Name with Insert for the
tokens, Start at, Prefix, and an example of the first file's name. The
OK button says Export Layer or Export Selection on those tabs.

Tests: the pattern tokens, the request's example (SVG, PNG, PDF and
print PDF for artboards 1-3, a folder per extension, the print PDF a
bigger page), folders by item and both, the counter by item and by
file, numbered duplicates, layers and the selection, EPS, AI and
VectorCraft per artboard, presets (built-in, saved, used, replaced,
deleted, kept with the preferences), bad params, and the dialog (every
tab, the example name, a pattern export into folders, the Layers and
Selection tabs, presets applied and saved). The three tests that
refused EPS and VectorCraft rows now check those files. New labels
are translated in all 19 catalogs.
2026-10-16 15:27:55 +07:00
dotCooCoo 24583effe0 Paragraph: the Hyphenation dialog sets each paragraph's hyphenation limits
The Paragraph panel menu's Hyphenation… was always disabled, and
automatic hyphenation used fixed limits: words of 6 letters or more,
3 letters on each side of the hyphen, any number of hyphenated lines
in a row, and capitalized words hyphenated.

Each paragraph now has hyphenation options: Words Longer Than, After
First, Before Last, Hyphen Limit, Hyphenation Zone and Hyphenate
Capitalized Words. The defaults are the fixed limits, and documents
keep their line breaks. The options are saved only when they differ
from the defaults. text.setFormat takes wordsLongerThan, afterFirst,
beforeLast, hyphenLimit, hyphenationZone and hyphenateCapitalized, and
paragraph styles carry the options. Hyphen Limit applies with both
composers. Hyphenation Zone applies with the Single-line Composer: a
line whose text before the next word already ends within the zone
breaks before that word instead of hyphenating it.

Hyphenation… is enabled with type selected and opens a Hyphenation
dialog (ui.hyphenation) on the values the Paragraph panel shows. OK
runs text.setFormat with the values that changed, as one undo step.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-16 15:27:55 +07:00
turtwig b795d15d69 Artboard tool: a double-click on an object fits one artboard, and the canvas name renames
A double-click on an object or group fits one artboard to the visible bounds and does not open Artboard Options. The second click does not fit another artboard. Other artboards stay. Double-clicking empty artboard space still opens Artboard Options. Double-clicking the name drawn above an artboard renames it.
2026-10-16 15:27:54 +07:00
Gert Pellin 065e237f7f Align Stroke on live type: tests for the Type tool's selection, docs (#2294)
The Stroke panel enables Align Stroke while the Type tool edits text, and
styles the selected characters. docs: mcp.md (stroke.set and strokeOptions
align on type), type-parity and target-app-parity rows.
2026-10-16 15:27:54 +07:00
Gert Pellin ca0673e0bc Align Stroke inside or outside on live type (#2294)
The characters' stroke takes Align Stroke like an object stroke: CharStyle
keeps stroke_align (written only when not centred), stroke.set and
text.setRangeStyle strokeOptions apply align to type, and the Stroke panel
enables the buttons for type. Canvas, PDF and EPS draw it around the glyphs
through stroke_layer(); SVG keeps the text live and writes the aligned
stroke on the glyph outlines, clipped or masked. Type's visual bounds grow
with its character strokes.
2026-10-16 15:27:54 +07:00
dotCooCoo adea2d307d Print: Print and Print Preview warn about type that doesn't fit its frame
Area type and type on a path whose text doesn't fit print without the
text past the end of the frame. text.create, text.createInPath,
text.setText and text.setStyle report it in their replies, but
file.print and print.preview gave no warning, and the Print dialog's
Summary showed none.

Both commands now add a warning that counts the area type and type on
a path that prints and doesn't fit, and gives their ids (the first 20,
then how many more). It counts the objects that the fallback font
warning counts: visible objects on the layers that Print Layers picks,
on the paper of the artboards or tiles that print. The walk that finds
the fonts of the printed type also collects these ids. Type in the art
of symbols, patterns, brushes, opacity masks and placed documents is
not named.

Docs: docs/mcp.md (Print, Fitting area type), docs/target-app-parity.md
(Type).
2026-10-16 15:27:54 +07:00
dotCooCoo dfe215ca30 Effects: Effect › Path › Outline Object turns type into live, editable outlines
Effect › Path had Offset Path and Outline Stroke but not Outline Object.
The new effect (path.outlineObject) has no options: the Effect menu
applies it at once, and effect.apply refuses any parameter. It is a
geometry effect that returns its input. Type already reaches geometry
effects as its glyph outlines, so type that carries it is drawn,
exported (PDF and SVG as paths, with no font) and expanded as those
outlines, stays editable type, and the effects after it reshape the
outlines. Paths, compound paths and images draw as before, and no
bounds change: with Use Preview Bounds on, type is still measured by
its layout box.

Every complete catalog gets a row for the label.

Docs: docs/effects-parity.md, docs/target-app-parity.md (an evidence
line), docs/mcp.md (the effect, and what Expand Appearance does to
type).
2026-10-16 15:27:54 +07:00
dotCooCoo bc8e42d8c7 Export: the art's bounds take in the effects of groups, type and images
The bounds of the visible art (`vectorcraft_render::encode::art_bounds`)
are the crop of Export with Use Artboards off, EPS without artboards,
Export for Screens' Full Document and Save for Web (Legacy) with Clip to
Artboard off, and the size Fit to Artwork Bounds gives an artboard. They
measured a group or layer by its members and left out its own effects,
and measured type and images without their effects. A group's drop
shadow, or the shadow of a line of type, was cut off at the image's edge
and left outside the fitted artboard. They also counted a Shaper group's
transparent source art.

Each visible object is now measured by `vectorcraft_render::effect_bounds`,
the measure of Export Selection's crop. A group or layer without effects
of its own is still measured by its visible members, skipping a Shaper
group's source art. A group or layer with a drop shadow, a glow or another
raster effect is measured without its hidden members, guides and template
layers, unless it is a Shaper group or also has a geometry, Pathfinder,
Crop Marks or 3D effect or a visible effect on its own fill or stroke.
The SVG of a chosen artboard also keeps an object whose effects alone
reach the artboard.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-16 15:27:54 +07:00
dotCooCoo d973805269 Type: geometry effects on a type object's own fills and strokes are drawn and exported
A geometry effect applied to one of a type object's own fills or
strokes (effect.apply with item) was kept but not drawn or exported
unless the type also had a geometry effect or perspective of its own.
With a geometry effect, the renderer measured the type for culling
without the fill's or stroke's effects, so an outline that reached past
the glyphs was not drawn once the glyphs left the view.

Type whose own fills or strokes have a visible geometry effect is now
drawn, culled and exported through its outlines, the same way as type
with an object-level geometry effect. Each effect reshapes the whole
outline that its fill or stroke paints. SVG, PDF, EPS and the other
vector exports write such type as paths. Type that holds inline
graphics stays type, as before.
2026-10-16 15:27:54 +07:00
dotCooCoo 56acb8d3b6 Select: Update Selection replaces the recalled saved selection with the current selection
The Select menu had no Update Selection: to add objects to a saved
selection or take objects out of it, the selection had to be saved
again under the same name. Select › Update Selection (`select.update`)
now gives the saved selection last recalled the objects that are
selected, in one undo step. It is enabled while objects are selected
and the document still holds that saved selection.

Each open document keeps session ids for its saved selections, so the
recalled one is found under a new name after Edit Selection…, and after
Undo and Redo. Deleting it disables Update Selection until another
saved selection is recalled or the delete is undone.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-16 15:27:54 +07:00
Marco Arnulfo 403b335039 Effects: Effect › Sketch › Halftone Pattern redraws an object through a halftone screen of dots, rings or lines 2026-10-16 15:27:53 +07:00
dotCooCoo ddfd08f321 Blob Brush: Keep selected and Merge only with selection options
A Blob Brush stroke merged with every touching closed path of its
color that had no stroke, and the blob it drew or merged into was
always left selected. The Blob Brush Tool Options had Size only.

The Blob Brush Tool Options now have Keep selected and Merge only
with selection, both off by default. A blob that a stroke draws or
merges into is no longer left selected unless Keep selected is on,
and the rest of the selection stays as it was. While Merge only with
selection is on, a stroke merges only with selected blobs, and with
nothing selected it draws a new blob. The options persist like the
tool's Size, and path.blob takes keepSelected and mergeOnlySelection,
both false by default. Keep selected stays on by default for the
Pencil and Paintbrush.

Docs: docs/target-app-parity.md, docs/control-protocol.md.
2026-10-16 15:27:53 +07:00
dotCooCoo 3b683bbeec Ellipse: dragging a pie widget on the canvas sets its pie angle
The Selection tool shows two pie widgets just outside a selected live
ellipse while the bounding box shows: one at the Pie Start Angle and
one at the Pie End Angle. Dragging one sets its angle to the angle of
the outline's point that lies in the direction of the pointer from the
ellipse's center, in one undo step, through `object.setLiveShape`'s
`pieStart` or `pieEnd`. Double-clicking one makes the ellipse whole
again (0° to 360°). Where the two widgets coincide, as on a whole
ellipse, a press takes the End widget.

Docs: docs/target-app-parity.md, docs/ui-parity.md.
2026-10-16 15:27:53 +07:00
Fabio 38dd835af6 G5: Symbol Options Export Type (Graphic / Movie Clip)
Store Export Type on symbols for Animate handoff; New Symbol and Symbol Options set it, and symbol.list reports it.
2026-10-16 15:27:52 +07:00
dotCooCoo 21b4e70150 Shaper: an arrow widget switches a Shaper Group between Face Selection and Construction mode
A Shaper Group had no arrow widget for switching between Face Selection
and Construction mode.

With the Shaper or Selection tool active, a selected Shaper Group, or a
group with one of its faces selected, now shows an arrow beside the
middle of the right side of its source shapes' bounds. A click on it
isolates the source shapes (object.isolate). A second click leaves
isolation with the group selected (object.exitIsolation). The arrow
points right in Face Selection mode and left in Construction mode.

In Construction mode a Shaper click selects an original shape of the
isolated group. Before, it selected the whole group outside the
isolation, and shaper.select with source could pick an original of
another Shaper Group lying above it.

Docs: docs/shaper.md, docs/target-app-parity.md.
2026-10-16 15:00:07 +07:00
dotCooCoo 6dfdf643d9 Type: Cmd/Ctrl+Shift+X resets horizontal scale to 100%
The reference app resets the horizontal scale of type to 100% with
Cmd/Ctrl+Shift+X. VectorCraft had no command for it, and the chord
cut the selection: egui reports it as a Cut with Shift held.

type.resetHorizontalScale (Reset Horizontal Scale, default
Cmd+Shift+X) sets the horizontal scale to 100% in the text the Type
tool has selected, or else in all the text of every selected type
object, in one undo step. The value is the one the Character panel
shows, so a type object stretched to twice its width keeps 50% stored.
The vertical scale does not change. At a caret the command leaves the
text as it is. Type objects given in ids are reset in full, as
type.resetTracking does.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-16 14:58:09 +07:00
dotCooCoo ad1e8d1112 Type: Cmd/Ctrl+Alt+Shift+. and , step the font size by five increments
No command held Cmd/Ctrl+Alt+Shift+. and Cmd/Ctrl+Alt+Shift+,, so the
chords reached Increase and Decrease Font Size (Cmd/Ctrl+Shift+. and ,)
and changed the size by one Size/Leading increment.

Two commands, type.size.increaseByFive and type.size.decreaseByFive,
now hold the chords. They step the font size of the selected type, or
of the text the Type tool has selected, by five times the Size/Leading
increment (Preferences › Type). Agents reach them with press_key too.
Their labels have rows in every complete catalog.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-16 14:58:09 +07:00
dotCooCoo f46b0f7dc4 PDF export: a page larger than 14,400 pt is written with a UserUnit
PDF export and .ai saves wrote every page in points. ISO 32000-1
(Annex C.2) gives 14,400 units as the longest page side, and a page
with a longer side got a media box past that limit. A PDF/A-2b file
with such a page failed veraPDF's page size rule (6.1.13).

Such a page now gets a UserUnit (PDF 1.6): its longer side divided by
14,400 and rounded up to the next thousandth, with the page's sizes
and coordinates in those units. A 20,000 × 10,000 pt artboard is
written as a 14,398.85 × 7,199.42 page with /UserUnit 1.389, and
VectorCraft's PDF import reads it back at 20,000 × 10,000 pt. Pages
up to 14,400 pt, PDF 1.3 to 1.5 files, PDF/X files and printing are
written as before.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-16 14:58:09 +07:00
dotCooCoo cc3299dc0f Artboards: Fit to Artwork Bounds fits each selected artboard to the art on it
Fit to Artwork Bounds resized the active artboard to the bounds of all
the art in the document, wherever that art was. With art on two
artboards, fitting one of them stretched it over both.

artboard.fitToArt now takes `indices` and fits each artboard to the
art on it, in one undo step. An object counts for every artboard its
drawn bounds overlap, and the artboard is fitted to all of its bounds,
also where it reaches past the artboard's edge. Art flush with an edge
from outside does not count. An artboard with no art on it keeps its
size and place, and the command fails with "no artwork" when none of
its artboards has art. Object › Artboards and the Artboards panel menu
pass the selected artboards (the Artboard tool's, else the active one),
and a recorded action leaves them out. Fit to Selected Art still
resizes the active artboard.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-16 14:58:09 +07:00
dotCooCoo ebc2857549 Align: Distribute Objects uses the spacing value with a key object
With a key object, the Align panel's six Distribute Objects buttons
ignored the Distribute Spacing value. They kept the outermost objects
in place, spaced the others evenly between them and could move the
key object.

object.distribute now takes spacing. While the selection has a key
object, the key object stays in place, with the compound path or
selected group that contains it, and the objects' left edges, centers
or right edges (top edges, centers or bottom edges) end up spacing
points apart, outward from the key object's, in their order on that
line. With 0, the field's default, every object ends on the key
object's line. Two objects are enough, and to and artboard are not
used. The panel sends the value with the Distribute Objects buttons
while there is a key object, as it does with the Distribute Spacing
buttons. Without a key object, or with anchor points selected,
object.distribute does not use spacing and works as before. A spacing
that is not a number is an error.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-16 14:58:08 +07:00
VictorandClaude Opus 5.5 d049e69b95 G1: Remove Anchor Points selects the next anchor (#2241)
After Object › Path › Remove Anchor Points the anchor that follows each
removed one is selected: round the end of a closed subpath, or the one
before it at an open subpath's end. Running the command again goes on
along the path, without picking each anchor first. Several anchors,
subpaths and paths each get their own next anchor; a path that goes
leaves nothing selected; one undo step restores the anchors and the
selection.

The Delete key still selects the remainder whole so a second Delete
removes it, and the Delete Anchor Point tool still leaves the path
selected whole.

Fixes #2241

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 14:58:08 +07:00
Marco Arnulfo bb66070841 Anchor Point tool: a click on a handle end retracts that handle only (fixes #2267) 2026-10-16 14:58:08 +07:00
dotCooCoo 88088e99bb Variables: selecting a data set reports the area type it overflows
dataset.select, dataset.next and dataset.prev rewrite bound type with
the data set's text but replied only {name, applied, skipped}. A long
value could push lines out of a fixed frame and the reply had no
overflow key, while text.setText answers overflow: [id] for the same
text.

The three commands now add overflow: [id...] with the area type and
type on a path whose text they rewrote and that doesn't fit, through
typecmd::with_overflow, as text.setText does. An object that two text
variables rewrite is named once. Type that the data set left alone is
not named, and the key is left out when all of the rewritten text
fits.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-16 14:58:08 +07:00
dotCooCoo 837d2b5667 Variables: a quoted text cell in a data set CSV keeps its leading and trailing spaces
dataset.import trimmed every cell, quoted or not. dataset.export quotes
a text value with leading or trailing spaces, so a value such as
"  padded " came back from its own export as "padded".

The CSV reader now trims an unquoted cell as before and keeps a quoted
cell as written between its quotes, spaces included. White space
between the closing quote and the next comma or line end is still
dropped. Image, graph and visibility cells, data set names and header
cells are trimmed as before.
2026-10-16 14:57:25 +07:00
Marco Arnulfo 80b7aee756 Isolation mode: a path of the isolated compound path moves on its own (fixes #2354) 2026-10-16 14:57:22 +07:00
NetterSilverandClaude Haiku 5.5 e510190867 Keep Layers panel selection inside the isolated group
Fixes #2286

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 14:57:21 +07:00
NetterSilverandClaude Haiku 5.5 ee6cd6de55 Keep paragraph styles aligned in Find and Replace with line breaks
Found while testing crates/engine/src/cmd/typemenu.rs:668 (find_replace / edit_runs)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-16 14:57:20 +07:00
bflatastic a64a5a9911 UI: Classic colour scheme (User Interface › Color Scheme)
A second colour scheme next to Modern: the neutral greys and blue accent of
earlier versions, on the same cards, corners and layout. Picked in
Preferences › User Interface › Color Scheme (pref uiColorScheme:
modern|classic); Accent Color is dimmed while Classic is chosen, which has
its own blue.
2026-10-16 14:29:33 +07:00
bflatastic 257217a2e3 UI: restyled interface with a choice of accent colours 2026-10-16 09:00:14 +07:00