Commit Graph

1223 Commits

Author SHA1 Message Date
bflatastic 4603ebec7a Review: report module beside rasterfx, ids checked without a tree walk, docs trimmed (#1147)
The report module moves to cmd/rasterfx/report.rs (the crate's foo.rs +
foo/ layout instead of #[path]). An object is the document's when its id
is below the document's next id, so building the report no longer walks
the whole document (and its symbols and patterns) on every PDF, SVG,
print and clipboard export. The parity docs say what changed in the
status line and one evidence bullet instead of a separate paragraph.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 18:17:25 +07:00
KnottyDyes 8d881cc0bc PDF export: warn when raster effects render below the requested resolution
The 64 million pixel cap can silently lower raster-effect resolution. Report each original object's id and name with requested and achieved ppi through the existing export warnings, retaining the lowest resolution across its images.

Keep the cap and rendering unchanged, cover capped and uncapped exports, and record the evidence without changing parity scores.
2026-10-11 18:17:25 +07:00
bflatastic 805d30e284 Review: DXF outlineText note and new-art wording in the MCP docs (#1148)
DXF already outlines type unless preserve: editability, so say so next to
the outlineText flag; reword the new-art sentence and point to paint.default.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 18:14:25 +07:00
KnottyDyes 4505ccb20d MCP: drawing tools describe inherited paint and export text options
Omitted paint fields keep the current appearance, so agents can get a black outline when they only set a fill. Document the initial white fill and 1 pt black stroke and recommend explicit paint for outline-free art.

Clarify SVG/SVGZ outlineText versus PDF options.advanced.outlineText and PDF's live-text default, noting DXF also accepts the top-level flag. Descriptions and documentation only; drawing and export behavior are unchanged.
2026-10-11 18:14:23 +07:00
bflatastic c3719b2e79 #1163: MCP render_preview takes an artboard index
render_preview only rendered the first artboard, so an agent couldn't
look at pages 2 and on of a multi-artboard document without switching
to screenshot. It now takes an optional 0-based `artboard` (as
screenshot does) and refuses an index the document doesn't have.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 18:13:26 +07:00
bflatastic 9b12fff215 #1163: Release splits a path of several subpaths into one path each
A path of several subpaths (an SVG `d` with several `M`s, PDF paths, a
path drawn in one go over MCP) is a compound path in Illustrator, and
Object › Compound Path › Release splits it into separate paths. Here
Release only acted on compound path objects, so such a path couldn't be
broken apart. Release now gives each subpath a path of its own, with the
path's paint, in stacking order; the first keeps the path's id. One undo
step, as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 17:58:13 +07:00
bflatastic da735914b6 #1158: Alt-click on a layer's eye or lock isolates that layer
Hide Others, Lock Others and Outline Others left the layer they keep as
it was, so Alt-clicking the eye of a hidden layer hid everything and
Alt-clicking a locked layer's lock left it locked. As Illustrator's
Layers panel does, the layer clicked now shows (unlocks, previews) while
the others hide (lock, outline), in the same undo step.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 17:50:35 +07:00
bflatastic d3c997329d #1111: a blend's spine bends into a curve
The Anchor Point tool drags any segment of a selected blend's spine into
a curve, straight ones too, and Direct Selection reshapes a curved spine
segment as it does a path's (a straight one it leaves, as on paths). Both
run the new `object.blend.spine.reshapeSegment`, which bends the segment
with the same math as `path.reshapeSegment`, now shared as
`SubPath::bend_segment`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 17:49:41 +07:00
bflatastic 1f5073e4d1 #1111: a selected gradient mesh shows its mesh lines and points
Only the Mesh tool drew a gradient mesh's grid, so with the Selection
or Direct Selection tool a selected mesh showed no outline and no
points, and its points couldn't be seen to be clicked. The selection
highlight now draws a gradient mesh's lines and points, as it already
did for mesh envelopes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 17:36:23 +07:00
bflatastic a809f270eb #1151: Preferences › Performance › Linux display server opens the window through Xwayland, where file drops work
winit 0.30 delivers no file drops on native Wayland. The new Linux Display
Server preference (Automatic / X11 (XWayland), shown on Linux only, read at
startup) has winit open the window on X11 when the session is Wayland,
DISPLAY is set and the X11 libraries winit loads are installed (ldconfig
check ported from PhotoCraft); otherwise the window opens on Wayland and
the log says why. README, development notes, parity docs, ROADMAP and the
complete catalogs updated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 17:29:23 +07:00
bflatastic 171c382618 #1103: a marquee selects only the objects whose paths it touches
A marquee drawn wholly inside a filled shape counted as touching it, so
a marquee over a background (the usual way to pick small objects off it
in Outline view) selected the background too. As in Illustrator, the
marquee now needs the path itself: an anchor inside it or a segment
crossing its edges.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 17:16:33 +07:00
bflatastic c7522b7f0c #1152: Offset Path opens on the values it was last applied with
Object › Path › Offset Path (and `ui.menuDialog` for it) opens on the
offset, joins and miter limit of the last time OK was pressed, as in
Illustrator, instead of 10 pt and Miter every time. The values are kept
with the rest of the remembered dialog options.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 17:16:16 +07:00
bflatastic f68f66a579 #1133: Zig Zag's dialog has sliders and radio buttons, as in Illustrator
Effect › Distort & Transform › Zig Zag… lays out its options the way
Illustrator's dialog does: Size and Ridges per segment each have a
slider beside their field, Relative / Absolute are radio buttons under
Size, and Points offers Smooth and Corner as radio buttons instead of a
dropdown. The label reads "Ridges per segment".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 16:46:14 +07:00
bflatastic fbc1c494b2 #1144: Live Corners round corners between curved segments too
A corner is now any anchor that isn't smooth where two sides meet at an
angle, straight or curved, as in Illustrator. The cut meets each side at
its setback measured along the curve, leaves both sides along their
tangents there, and each curved side is trimmed to what the cuts at its
ends leave of it. The largest radius is still the one taking the cut
halfway along the shorter side, measured along the curve. Corners
between straight sides draw exactly as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 16:14:08 +07:00
bflatastic 255fefe71f Render: a shape far beyond any page is left undrawn, never crashing the app
A property test of the importers (import_fuzz) crashed CI with
STATUS_STACK_BUFFER_OVERRUN: a shape with coordinates in the 1e20s from a
mutated file made vello_cpu either panic in flatten_simd on a rayon
worker (rayon then aborts the process, so the engine's panic guard never
sees it) or ask for a 132 GB allocation, which aborts too. A malformed
file could end the app and lose the user's work.

draw_shape now leaves a shape undrawn when its control points, through
the view, aren't finite or reach past 1e10 pixels, or a visible stroke
is that wide (MAX_DEVICE). A document's art stays within 4 million
points, 2.6e9 pixels at the closest zoom, and vello was checked safe
with 90,000 random shapes within 1e9 pixels and 30,000 within 1e12.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 16:13:30 +07:00
bflatastic 423cb18f40 #1139: Shift-click selects several artboards, which move and delete together
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>
2026-10-11 16:04:30 +07:00
Biromedic f4035c98d1 Fix #1141: SVG import keeps a mask whose art is all hidden, so its object stays hidden
Mask art that is all visibility:hidden imports as nothing, and opacity_mask
then returned no mask: the object was drawn whole. An empty mask is what the
file means (black all over); the renderer and the PDF and SVG exports already
draw empty mask art by its clip and invert options.
2026-10-11 16:00:38 +07:00
Biromedic 1726c600d2 Fix #1140: gradient stops blend colour and opacity apart on the canvas, as the exports do
The canvas built its peniko gradients premultiplied (peniko's default), while
Gradient::sample, the PDF export (shading plus SMask) and SVG viewers blend
colour and opacity separately: a transparent white stop into black drew grey
127 halfway instead of 191. Opaque gradients are unchanged.
2026-10-11 16:00:36 +07:00
dotCooCoo d79aa607cc Lint: clippy -D warnings passes for the wasm32 web build
On main, cargo xtask wasm printed two dead-code warnings in
vectorcraft-ui-egui, and this clippy run reported the same two as
errors:

    cargo clippy --target wasm32-unknown-unknown -p vectorcraft-web -- -D warnings

ask_update_changed (dialogs/missing_links.rs) is called only from
tick_link_updates, and is_c_locale (i18n/mod.rs) is called only from
detect_system_lang. Both callers are compiled only for native targets.

Each function now has the same #[cfg(not(target_arch = "wasm32"))]
attribute as its caller. Native builds compile both functions as
before.
2026-10-11 16:00:33 +07:00
mateususa ae9cd2a03c #819: more noise removal never gives more paths
Remove Noise merged each small component into its most common neighbour
in one pass. When a speck was merged into a small region that was itself
merged away later, the region's flood fill skipped the speck's pixels
(already seen), so they stayed behind as a new island of the region's old
label. Higher Noise values merge more regions, so they left more such
islands: on noisy images the path count rose with Noise (70 -> 126 -> 206
paths from Noise 50 to 200 on one test image). denoise now repeats its pass
until one changes nothing; each merge joins two components, so it ends
(with a cap of 64 passes as a backstop). Labels shorter than w x h are left
alone instead of indexed past their end.

Tests: the minimal one-row case, a property test on random blocky noise
(no mergeable region under the minimum is left, and a larger minimum never
leaves more regions), and two noisy images whose path count must not rise
with Noise (both fail without the fix).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 16:00:31 +07:00
bflatastic eeb78520e1 Review: a headless test of the font menu's highlight across a list rebuild (#1116)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 16:00:28 +07:00
Nigel Ihza Firdausy eb189a36c3 fix(fonts): end live preview when filters remove its highlighted row 2026-10-11 16:00:27 +07:00
Nigel Ihza Firdausy 22690c3565 fix(fonts): retain the same highlighted font after list rebuilds 2026-10-11 16:00:27 +07:00
bflatastic 2afd0b659c Icons: the Selection arrow is black and Direct Selection's white in every theme
Icons are drawn in the theme's colour. The Selection tool's filled arrow
therefore came out light in the dark themes and the Direct Selection
tool's hollow one dark, so they looked swapped to anyone who knows the
black Selection and white Direct Selection arrows (reported by a user).
Both arrows now paint a fill in a fixed colour (black, white;
dc-arrow-fill.svg, original) under their outline in the theme's colour.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 15:30:24 +07:00
bflatastic 539759429c #1018: Edit Toolbar opens a drawer beside the toolbar; tools drag in and out
The ••• button at the bottom of the toolbar no longer opens All Tools as a
centred dialog. It opens the All Tools drawer beside the toolbar, next to the
button. Escape or a click outside closes it; a click in the toolbar doesn't.
Tools that are already in the toolbar show dimmed in the drawer.

While the drawer is open the toolbar can be edited, as the public
documentation describes:
- drag a tool from the drawer onto a toolbar button's top or bottom edge
  (left or right edge in two columns) to put it in its own slot there;
- drag it onto a button's middle to add it to that button's group;
- drag a toolbar button into the drawer to take its tool out;
- drag a toolbar button to another place in the toolbar to move its tool.
A line or outline shows where the tool will go, and the dragged tool follows
the pointer. While the drawer is closed the toolbar can't be edited.

The Basic and Advanced toolbars each keep their own edits in
UiState::toolbar_edits, which is saved with the preferences. It is serde
default, so older preferences still load, and a hand-edited file is cleaned
up when it loads. An edit that brings back the default toolbar clears the
saved edits. New UI commands toolbar.addTool {tool, slot?, place?},
toolbar.removeTool {tool, group?}, toolbar.reset and
window.editToolbar {open?} let MCP and the control channel make the same
edits. The drawer also has a Reset button.

The drawer moved from dialogs/all_tools.rs into the new edit_toolbar.rs. It
is tested with headless egui frame tests driven by pointer events (placement,
Escape, click outside, dimming, drag and drop in each direction, the locked
toolbar), along with command, persistence and drop-zone tests. The three new
command labels are translated in every complete catalog, and the error
messages reuse existing translated templates.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 15:30:09 +07:00
bflatastic eb510f4194 Part of #812: Ctrl/Cmd and Alt shape a star while it's dragged
A star's inner radius was always half its outer one while drawing, so
its ratio couldn't be changed. As Illustrator documents for the Star
tool: Ctrl/Cmd during the drag keeps the inner radius where it is while
the outer one follows the pointer (the new ratio stays once the key is
let go, for the rest of the drag and the next stars), and Alt keeps the
star's shoulders straight (each point's sides in line with the next
points', a ratio of cos(2π/n)/cos(π/n); five points or more).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 14:59:05 +07:00
bflatastic 82b22af43c #788: file.place frames an SVG by its viewBox when crop is given
Placing an SVG fitted and centred it by its art's bounds whatever `crop`
said, so art drawn on a shared canvas lost its place and scale, and
`crop: "crop"` and `crop: "bounding"` gave the same result without a
warning. With `crop: "crop"` given, an SVG is now framed and clipped by
its viewBox (its artboard, as File › Open has it), as a PDF is by its
page: `rect` and `at` fit and centre that frame. By default, as
Illustrator places an SVG, and with "bounding", it is still its art's
bounds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 14:58:33 +07:00
bflatastic 8c69173bb7 #1089: an image copied in a browser pastes as the picture, also from its markup
A browser's Copy Image puts the picture on the clipboard with text next
to it. Paste already took the picture when that text was only the
image's address (#597), but some browsers (seen on Fedora with KDE) put
the image's HTML there instead, `<img src="…" class="…" style="…">`,
which isn't an address, so the markup was pasted as type.

names_a_picture also takes markup whose only content is <img> elements
(no text outside its tags) as naming the picture, and Paste then reads
the bitmap. Markup with words in it, and an address alone, still paste
as text.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 13:51:41 +07:00
bflatastic b9aca50c3c #1129: the toolbar's paint buttons fit its width
The Fill/Stroke proxy stayed 36 pt and the Color, Gradient and None
buttons 7.5 pt in both toolbar layouts, so in two columns they sat small
in a wide strip and were hard to hit (in one column too). The proxy is
now 54 pt in two columns, the three buttons 11 pt in one column and
17 pt in two, and in two columns Draw Normal, Draw Behind and Draw
Inside sit side by side, each setting its mode (view.drawMode {mode}),
as Illustrator's two-column toolbar shows them; one column keeps the
button that cycles them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 13:26:24 +07:00
Michael Gieson a75b465419 Selection tools: Alt-drag copies snap to the original they leave behind
The snap targets of a copy were gathered when Alt went down, from the document
as previewed, where the original had already moved with the drag, so the
original was never a target where it stays. Now both target sets (for a move,
and for a copy, which includes the original) are gathered when the drag
begins, and Alt picks between them each frame: for Direct Selection drags by
an anchor and for whole-object moves (the Selection tool's, and Direct
Selection's from a segment or fill).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-11 12:24:46 +07:00
Michael Gieson af98309c01 Direct Selection: Alt during a drag of whole paths turns the copy on and off
Pressing an anchor of paths that are all selected whole now moves them as
objects held by that anchor, so Alt pressed or released during the drag turns
the copy on and off (the original shows or not), as with the Selection tool.
The anchor keeps snapping all along, onto the original only while a copy
leaves it behind. With only some anchors selected the drag still moves just
those.

A committed move drag is now named for what it did in the end (Copy or Move),
for the Selection tool too.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-11 12:24:46 +07:00
Michael Gieson 5dcc64e757 Direct Selection: Alt-drag copies snap by the anchor pressed
Alt-dragging a path by an anchor moved the copy with whole-object snapping
(bounds only, from the press point), so the anchor couldn't land exactly on
another anchor. Now the pressed anchor (its own coordinates, not the pointer's)
snaps as a dragged anchor does: onto other paths' anchors and segments and
Smart Guides, and onto the original the copy leaves behind. The history says
Copy for an Alt-drag.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-11 12:24:46 +07:00
Michael Gieson abfcd0800e Direct Selection: Alt-drag by an anchor copies the whole path
Alt-pressing a segment already picked the whole path and Alt-drag copied it,
but a press on an anchor ignored Alt and only moved the selected anchors. Now
Alt on an anchor picks the whole path too, so Alt-drag duplicates it as the
Selection tool's does.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-11 12:24:46 +07:00
Michael Gieson fe5955e521 Direct Selection: pressing an anchor of a path selected whole keeps all its anchors
A path with all its anchors selected is stored whole (no partial entry), so
pressing one of its anchors looked unselected and replaced the selection with
that anchor alone; the drag then moved just it. Now an anchor of a path
selected whole counts as selected: the press keeps the selection and the drag
moves every anchor. Shift-press still deselects that one anchor.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-11 12:24:46 +07:00
Hiroshi Inukai aa9f0153a4 PDF/.ai import: glyphs spaced each their own way keep their place
Character tightening and optical kerning space each glyph differently, as
Japanese titles often are. The importer evened a line out with one
tracking value (type on a path took none), leaving glyphs up to an eighth
of an em out of place. When the file's font is installed and one value
can't place every glyph, each character now keeps its own tracking,
measured along the baseline (along the path for type on a path).

Glyphs closed up by up to half an em (the proportional widths of CJK
punctuation) also continue their line instead of starting another.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:24:46 +07:00
bflatastic 5e9b7d09a2 Review: a whole number past i64::MAX is past any maximum; ROADMAP (#1091)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:24:46 +07:00
webdevtodayjason aecf88c1c1 Plug-ins: whole-number parameters keep their exact value and stay in range 2026-10-11 12:24:45 +07:00
imachus 2c8b8b0cc1 Type: Proportional Metrics in vertical type — upright glyphs on the font's proportional heights, `vpal` (#966)
The second half of #966. With Proportional Metrics on, a vertical segment is
also shaped top to bottom, with and without `vpal`: the difference gives
each glyph's change of advance down the column and its x and y placement.
An upright glyph (not tate-chu-yoko) in a font with vertical metrics takes
them on top of its cell, so it moves with its shorter cell; a font without
vertical metrics keeps `upright_cell`'s cell, and with the switch off
nothing is shaped twice and the column is as before.

As in horizontal type, Line-end Punctuation Half Width takes nothing more
off the punctuation `vpal` re-spaced and trims the punctuation it leaves
full height as before. Docs: mcp.md, and Proportional Metrics leaves the
missing lists in gaps.md, type-parity.md and target-app-parity.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:24:45 +07:00
Alejandro Londono 8957545c33 #893: merge Shape Builder faces in the planar map
After linesweeper 0.5 (#1028 on main), uniting the faces of a grid of
lines could split the merged strip again even with their corners shared
exactly: a sweep over seven or more faces moved shared vertices by about
1e-6 (within its eps) and the edges between faces no longer cancelled.

Faces cut by open paths now merge like closed shapes' faces already do
(FaceMerger::exact): in the planar map itself. build() is split into
map() (the graph and its faces) and build(); Map::merge traces the
boundary of the picked faces along the map's own edges, dropping the
edges between two picked faces and the loose ends inside them, so no
sweep runs on the result. FaceMerger finds each face again by a point
inside it, checks the area, and keeps the boolean union as a fallback.

Tests: the regression test merges through FaceMerger; a grid test
covers a ring with its hole, cells touching at a corner, a loose end,
and that the map path (not the fallback) produced the result.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:24:44 +07:00
Alejandro Londono cfa36fc55f #893: Shape Builder merges leave no seams on grids of lines
The planar map merged sweep endpoints within eps into one vertex id but
kept each segment's own copy of the coordinates, so faces meeting at a
vertex could disagree on that corner by ~1e-13. Uniting them then failed
to cancel their shared edge, and a merged strip came back as several
touching subpaths whose stroke drew the inner edges as leftover lines.

Pin every edge's ends to its vertex's canonical position, so faces share
their corners bit for bit. Regression test from the reporter's grid.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:24:44 +07:00
Emlembow 7ff0269a1d Fix #867: macOS file dialogs are sheets, and no dialog runs inside the event handler
The crash: rfd's blocking dialog ran -[NSSavePanel runModal] inside
winit's event handler; when a resize of the panel ends, AppKit runs the
closures winit queued meanwhile, and winit's re-entrancy panic fires
inside an Objective-C block, where it can't unwind, so the app aborts.
As PhotoCraft (#673) and PdfCraft (#145) ship it:

- macOS: picks::ask shows an rfd::AsyncFileDialog as a sheet on the
  window (beginSheetModalForWindow returns at once); a waiter thread
  sends the paths and wakes the window. A pick asked outside an entry is
  refused and logged instead of running a modal. Linux keeps its thread
  (#592) and now also wakes the window; Windows is unchanged.
- Nine paths that asked outside an entry now run as entries: Load
  Profile, Swatches and Graphic Styles Other Library, the shortcut
  editor's Import and Export, and the presets dialogs' Export.
- While a dialog is open: the macOS menu bar is inert except Hide, Hide
  Others and Minimize; Quit, Close, Close All and the close button are
  refused; Finder/Dock opens and the IME discard wait; another dialog
  is refused with a status message. The answer re-activates the
  document that asked (by uid) and Save Changes finds its document by
  uid; a frame guard clears a stale picks entry after a recovered panic.
- ui.inspect reports fileDialog.

Squashed onto current main by the maintainer (with main's automation
sandbox wrappers and font-name menus kept).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:14:17 +07:00
bflatastic 525b79a51a #1111: Ctrl+Shift+L, C, R, J and F align paragraphs
The paragraph alignment shortcuts were missing. Cmd/Ctrl+Shift+L, C and
R align the selected type's paragraphs left, centred and right, J
justifies them with the last line aligned left and F justifies all
lines; while the Type tool edits text they act on the paragraphs its
selection touches, through the Paragraph panel's own path. They are UI
commands (type.alignLeft, …), listed in Keyboard Shortcuts, and enabled
while type is selected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 11:58:51 +07:00
bflatastic 558b8b621c #1095: an artboard's name stays at its corner in a rotated view
The name was placed at the top-left corner of the artboard's bounding box
on screen, which a rotated view (Rotate View) turns away from the
artboard's own corner, so the name floated off beside it. It now sits
above the artboard's top-left corner as the view maps it, no wider than
the artboard's on-screen width.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 11:43:11 +07:00
bflatastic c7b46dbb3e Review: palette writing keeps the swatches PaletteFormat::holds names; ROADMAP (#1110)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 11:33:07 +07:00
dotCooCoo 2b93e8a930 Swatches: swatch.library.save counts only the swatches the file holds
swatch.library.save replied with the number of solid colors and
gradients it was asked to save, including the gradients the format
leaves out. For a new document saved as .ase, count was 50 and the file
held 46 colors. The .gpl and .ase writers keep solid colors only, and
the CSS writer leaves freeform gradients out.

count is now the number of swatches written. The new
PaletteFormat::holds returns whether a file of a format keeps a swatch
with a given paint, and swatch.library.save counts the swatches for
which it returns true. The reply has the same fields as before.

Tests: after a freeform gradient is added to a new document's swatches,
the test checks that count has these values: 51 for .vcswatches, 46 for
.gpl and .ase, and 50 for CSS. Each file holds that many swatches.

Docs: docs/mcp.md.
2026-10-11 11:33:07 +07:00
bflatastic 4d52b043cf Review: Lock and Hide › All Artwork Above use Selection::deselect_uneditable; ROADMAP (#1109)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 11:33:07 +07:00
dotCooCoo cd34e4097a Object: Lock and Hide › All Artwork Above deselect the objects they lock or hide
Object › Lock › All Artwork Above and Object › Hide › All Artwork Above
lock or hide the objects that are above the selection in its layer and
overlap it. Such an object can be a group or a sublayer that holds
another selected object. The commands left that object selected, the
key object included. Align then moved the locked object, or aligned
the other selected objects to the hidden key object. object.lock and
object.hide clear the selection, and layer.setProps, which the Layers
panel's eye and lock columns run, deselects what it hides or locks.

Both commands now deselect every selected object that is locked or
hidden after the command, as layer.setProps does, and clear the key
object when it is one of them. Undo selects the objects again and
restores the key object.

Docs: the object.lock.above and object.hide.above params text,
docs/target-app-parity.md.
2026-10-11 11:33:06 +07:00
bflatastic cc6fd8a5dc Review: Align and Distribute share one apply_moves; ROADMAP (#1108)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 11:33:06 +07:00
dotCooCoo a31cdab606 Part of #394: Align and Distribute move pattern tiles when Transform Pattern Tiles is on
object.align, object.distribute and object.distributeSpacing moved
objects without their pattern tiles, whatever General › Transform
Pattern Tiles was set to. They now follow the preference as Move,
Nudge and the Selection tool do: with it on, pattern fills and strokes
move with the art. Each also takes a `patterns` param for one call, as
the transforms do. When the art uses a pattern, the journal records the
choice, and a recorded action plays back with it.

Docs: docs/mcp.md (transformPatternTiles), docs/target-app-parity.md.
2026-10-11 11:33:05 +07:00
bflatastic d10962ac45 Review: one Selection::deselect_uneditable for the hide and lock commands; ROADMAP (#1107)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 11:33:05 +07:00