- A press with a selection tool inside an artboard makes it the active one, as
the Artboard tool's does; before, only the navigator and the Artboards panel
changed it.
- Paste in Place, in Front and in Back take `artboard` (the UI passes the active
one): the objects go where they were on the artboard they were copied from,
on that artboard. Without it, they paste where they were, as before.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Cmd+, is how every Mac app opens its settings. It now opens Preferences on
macOS beside its own Cmd+K, unless a command or one of the user's shortcuts
already has the chord.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The toolbar names its tool groups (Select, Shapes, Draw, Modify...). A new
preference, on by default, turns the names off for a cleaner toolbar: a faint
dash then separates the groups.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Document tabs drew their close box before the title on every platform, the
macOS convention. On Windows, Linux and the web it now comes after the title,
as those platforms' tabs (and Adobe's own apps there) put it; macOS keeps it
before.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- artboard.rearrange takes layout (gridByRow, gridByColumn, row, column;
byColumn stays as an alias of gridByColumn) and order (leftToRight,
rightToLeft); Columns is the row count of a grid by column and is
ignored by row and column. It returns {artboards, rows, columns}.
- A Rearrange All Artboards dialog: Layout and Layout Order toggles drawn
in code (widgets::layout_button, previewing the order), Columns/Rows,
Spacing, Move Artwork with Artboard and the artboard count.
- One click: Rearrange All in the Properties panel (Document section with
several artboards, Edit Artboards' Quick Actions); the Artboards panel's
Rearrange button and menu item now open the dialog too.
- Tests for every layout x order (artboards, art riding along, one undo
step), the dialog, the Properties button; the command sweep covers the
new params. Translations for ja, es, it, ru, fr, zh-hans, zh-hant and
pt-br; ROADMAP updated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The crate README now spells out the provenance the review on
storytold/vectorcraft#667 asks the owner to decide on: no Affinity
software; afread's MIT description re-described without translating
code; every structure confirmed on public files (CRC-32 per entry,
self-typed fields); semantics fitted to Affinity's own thumbnails; how
the sample documents were licensed; read-only.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GQPh8UDgMyARR5Hat9UchC
Conflicts: ROADMAP (main's guides and file-format rows, with the Affinity
items kept); fileio/load.rs (main's physical-size raster documents, kept
visible to the Affinity preview fallback).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GQPh8UDgMyARR5Hat9UchC
Preferences > User Interface > Canvas Color offered Match User Interface
Brightness and White only: with a dark interface the first is a high-contrast
dark canvas around the white page, and White hides where the page ends. Light
Gray, Medium Gray and Dark Gray keep the page's edge in view at a gentler
contrast.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The census behind the limit counted duplicate copies of the same public
files: there are 189 distinct documents, the largest still decoding 3.3
million values.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GQPh8UDgMyARR5Hat9UchC
VectorCraft found fonts only in the system's font folders (and, on Windows,
those font services activate). A new preference names one more folder, read
with its subfolders after the platform's: its fonts are listed in the font
menus and used as if installed, without installing them.
- vectorcraft_text::set_user_font_dirs / user_font_dirs: folders
system_font_dirs adds to every scan (none on wasm).
- prefs fontsFolder (Type > Options > Additional Fonts Folder), trimmed; when
it changes after the first scan, the fonts are scanned again at once, so the
folder's fonts appear (or go) and type in them lays out again.
- The label is translated where Additional Plug-ins Folder is.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#677 lets one image decode take up to 2 GB, so large print sheets open on the
desktop. wasm32 can address only 4 GB and aborts when an allocation fails, so
the web app keeps the decoder's default 512 MB and reports larger images as an
error instead.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With the Artboard tool, the Properties panel showed the active artboard's name,
position and size but no quick way to turn it between portrait and landscape.
It now has a row with:
- Preset: New Document's saved and built-in presets, by category, matched in
either orientation (Custom when none matches); choosing one sizes the
artboard in its current orientation;
- Portrait and Landscape (the New Document toggle): the other one swaps the
artboard's width and height.
The artboard's top-left corner stays put, so no art moves with it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A value takes about 40 bytes in memory however few it took in the file,
and a bool array packs eight in a byte, so a small, highly compressed
doc.dat could declare billions of values and make the import abort on
allocation (review on storytold/vectorcraft#667). The parser now counts
fields and array elements against a 2^24 budget before allocating, and
reserves array storage fallibly, returning Error::Limit either way.
The largest of 333 public documents decodes 3.3 million values.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GQPh8UDgMyARR5Hat9UchC
Conflicts: README and ROADMAP (both sides kept: the French and Russian
interface with the Affinity sentence; the placed-documents bullet with
the Affinity one); place and swatch libraries (upstream's byte sniffing
and comments, with the preview-only refusal kept).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GQPh8UDgMyARR5Hat9UchC
object.cropImage {trim: true} cuts the selected image to the box of its pixels
with any alpha, copying them as they are (no re-render, no resampling) and
placing them where they were. An image with nothing to cut is left as it is
and isn't an error (trimmed: false), so a script can trim every image it
opens. Print-ready PNGs usually carry transparent padding; with this, Fit to
Artwork Bounds can size to the art.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Performance › Animated Zoom (with GPU Performance, which dims it when
off): the Zoom tool dragged sideways zooms about the press (right in,
left out) and held still zooms on (Alt: out); a click still steps. Off,
a drag zooms to the area dragged across, now drawn as a marquee. The
hint bar says which.
- User Interface › Large Tabs: taller document tabs with larger titles.
- User Interface › Scale Cursor Proportional to UI: off, the tool cursors
keep their size whatever the UI Scaling (OS and painted cursors alike).
- File Handling › Display Bitmaps as Anti-aliased Images in Pixel
Preview: off (the default), Pixel Preview samples images nearest-pixel
(`RenderOptions::smooth_images`).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A selection moved with the Selection or Direct Selection tool that lines
up with nothing along an axis lands as far from its neighbour as two
other objects of its row (or column) are apart, or halfway between its
two neighbours, within the snapping tolerance; the equal gaps are marked
with a line and end ticks in the Smart Guides colour. The objects are
taken as wholes on their layers (groups too), and inside a group holding
the selection, its other objects. Off, moves only line up as before.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- The Home screen lists the first six of File > Open Recent Files, each by name
(a click opens it) and folder; one that can't be opened says so in the status
bar. With none, there is no section.
- In New Document, a double-click on a preset card creates the document from
it; a click still only chooses it. The Create buttons no longer overwrite a
create asked for earlier in the frame.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CMYK went to RGB through display sRGB: CMYK -> sRGB (clamped) -> working RGB.
Into a wider space (Wide Gamut RGB, the 1998 primaries) that clipped every
colour sRGB can't hold - CMYK cyan's red channel landed at 99 instead of 0 -
and the black-point compensation setting had no effect (moxcms leaves it
unimplemented). An ICC CMYK profile now converts directly into the RGB
profile: into its primaries with linear curves, where compensation is a
linear remap from the profile's black (found by sending black through the
profile and reading it back), then onto its own curves. The canvas uses the
same conversion into sRGB, so what shows is what an RGB export writes.
Checked against Ghostscript with the same profiles (relative colorimetric,
compensation on and off): exports into Wide Gamut RGB and the sRGB display
agree within 1 level in 255. The built-in CMYK spaces are unchanged (Generic
CMYK compensates in its own model).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A CMYK image with an /SMask, /Mask or colour key was handed to the
interpreter and stored as an RGB PNG, converted with hayro's own bundled
profile (Perceptual) rather than the working CMYK, so it showed 10-30 levels
lighter than other CMYK images and lost its ink amounts. It now keeps its
inks as other CMYK images do (#320), and its alpha becomes a greyscale
opacity mask. PDF export already writes that as a DeviceCMYK image under a
soft mask, so a round trip keeps the inks.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The image decoder can't read a CMYK TIFF with an alpha channel at all
("color type Unknown(0)"); it is now read with the tiff crate, associated
alpha divided back out and the inks converted in the active colour settings.
And a 60 in sheet at 300 ppi (18000 x 6600 px) hit the decoder's 512 MB
default allocation limit; up to 2 GB is now allowed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An image opened as a document took 1 px = 1 pt whatever its pHYs, JFIF or
EXIF resolution said, so a 300 ppi print file opened at four times its
physical size. It now opens the way Place already sizes it (pt_per_px):
at the resolution it declares, 72 ppi when it declares none.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A pinch already zoomed the canvas and a second finger already cancelled the
first finger's press, but dragging two fingers together did nothing: the
canvas only read wheel scrolls, and a touch screen sends touches. The fingers'
movement (egui's multi-touch translation) now scrolls the canvas under either
Zoom with Mouse Wheel setting, and zoom and scroll apply in the same frame, so
a pinch that also slides pans too. Trackpads send scrolls, so nothing counts
twice.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Layout (vectorcraft-text tests_combos): every pair of ligatures under tracking,
the paragraph composer, vertical alignment, Shrink Text to Fit, per-paragraph
attributes and inline graphics, and all six at once. Commands
(vectorcraft-engine tests_textcombos): Auto Size and Shrink Text with inline
art, paragraphs, composer and alignment; editing and undo across them; a save
round trip with everything on.
auto_height lays the text out in a very tall probe frame; with Center, Bottom
or Justify the lines moved down inside it and the frame grew to tens of
thousands of points.
The fit scaled each run's size, leading and baseline shift but not an inline
graphic's own shift (points), so shrunk symbols sat off the cap-height centre.
align_vertically moved lines and glyphs but not TextLayout::inlines, so inline
symbols in a centred or bottom-aligned area stayed where top alignment put them.
The reflow path for non-rectangular frames also kept the previous pass's
inlines, drawing each symbol twice.
Advanced › Create: Fills and/or Strokes, with Stroke (the widest line, px).
With Strokes, each colour's 8-connected parts no wider than the stroke width
(chamfer distance transform) trace as open centre lines instead of filled
outlines: the line is thinned to one pixel (Zhang-Suen with each removal
re-checked, so two-pixel lines survive; staircase corners dropped), its
skeleton becomes runs between ends and junctions (junction pixels merged,
spurs pruned, runs through two-way junctions joined, rings closed), and each
run is simplified and fitted with curves. The stroke width is the line's mean
width (pixels over length). Traced lines get round caps and joins in the
document. Without Fills, wider areas become 1 px stroked outlines.
`imageTrace.make` takes fills, strokes and strokeWidth, and refuses neither
fills nor strokes and a non-positive width.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Color mode's colours now come from a Palette (`palette` in imageTrace.make's
params), shown in the Image Trace panel under Mode:
- Limited: the `colors` best colours (what Color did before; the default).
- Full Tone: median cut until no colour box spans more than 96 (Less) … 8
(More) levels per channel, up to 256 colours, set by `colorDetail` 0-100
(the panel's Colors slider for this palette).
- Automatic: flat art (90% of the pixels in a few tight colours) traces with
exactly its colours, anything else as Full Tone.
- Document Library: the most used (at most `colors`) colours of the
document's swatches or of a swatch library (`library`: "document" or a
library id or name, chosen in the panel's Library list), used as they are;
traced shapes fill with the swatch's own colour, its colour model kept.
The library's colours are looked up at every trace, not saved.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- The Image Trace panel's Advanced options sit under a full-width collapsible
header (widgets::section_toggle, also used by New Document's Advanced
Options); whether it is open is kept with the UI preferences.
- View: Tracing Result, Tracing Result with Outlines, Outlines, Outlines with
Source Image and Source Image, in the panel, the Control bar and the
Properties panel. The view is saved in the Image Trace object's settings
(`trace.view`), kept when it is traced again, set with the new
`imageTrace.setView` command (or `view` on imageTrace.make) and drawn by the
canvas only (RenderOptions::trace_views): exports, printing and Expand keep
the tracing result.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Panels other than Properties, Layers and Libraries live in the dock's icon
column, not as tabs. Dragging one onto the dock lit up the whole dock, tabs
included, and the drop put it back as an icon, so it seemed to vanish. The
drop zone now lights up the icon column for such panels (the whole dock still
for the tabbed ones), and the dropped panel pops out of its icon.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Artboard tool handled Delete/Backspace in Tool::key, but never claimed
the keys through Tool::claims_key. The UI only routes Delete/Backspace to a
tool that claims them, so the keypress went to the Clear shortcut instead
and the artboard stayed. The existing tests called the tool directly and
missed it.
The tool now claims Delete/Backspace while no drag is in progress and more
than one artboard exists. With only one artboard left, the keys stay with
the shortcut.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Other editors export a document with a single layer without a layer group:
the layer's name goes on the root <svg> (id, or data-name) and its art sits
directly inside. Such a file opened as "Layer 1"; now its one layer takes the
root's name. Files whose top-level groups are the layers are unchanged, and an
Inkscape root's generated id (with inkscape:version) isn't taken as a name.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The panel laid out a row (with its thumbnail and several whole-document
lookups) for every open row each frame. A layer of 5,000 groups of 10 paths,
all open, took about 29 s a frame headless. Now the rows shown are listed once
per document change (with their layer colour and dimming worked out on the
way down) and ScrollArea::show_rows lays out only those in view: 0.4 ms a
frame. A row highlighted out of view is scrolled to.
The open rows move from UI state into the document's state
(DocState::layers_open, OpenRows): a document opens with only its top-level
layers open, and native files save the open rows (Document::layers_open,
written only when not the default, at save time like the view, so opening or
closing rows never marks the document modified).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Top-level groups already opened as layers named from data-name, else their
id. Now that also holds when one more id-less group wraps them (a transform
on all the art, or a <switch>'s chosen group), and hidden objects inside a
<switch> are kept (hidden) instead of dropped.
Nested groups stay groups unless something marks them as layers: the SVG
export now writes data-vc-layer="sublayer" on layers inside layers, and
import makes such a group (or an Inkscape layer group) a sublayer of the
layer holding it, in that layer's colour. A marked group anywhere else
stays a group.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Pixel Preview only switched the pixel grid on from 600%: the art was still
rendered for the screen and drawn with linear filtering, so curves and
strokes stayed smooth vectors. Now, while a document pixel is bigger than a
screen pixel, the canvas renders the visible document pixels one per point
(anti-aliased by coverage), uploads them with nearest filtering and places
them over the document rect they cover, turning with a rotated view.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>