Commit Graph
100 Commits
Author SHA1 Message Date
bflatasticandClaude Opus 5.5 199a464140 #964: start again when the first frame never reaches the screen
With High Performance chosen on a hybrid laptop, the window's first
frame never reached the screen: no error, no panic, the app stayed in
the background without a window and the log stopped after "rendering
with". The start-up recovery of #502 only saw failures.

A watch thread now gives the first frame 20 seconds from the app's
creation (after the files named at the start opened). When the second
frame hasn't begun by then, so the first was never presented, the app
starts again without that adapter, as it does after a graphics failure,
and this process ends. A window minimized at the start isn't counted.
When the hung processor was chosen in Preferences, the status bar's
note after the restart points to Automatic.

docs/development.md explains it and how to recover from a Graphics
Processor choice that doesn't work; ROADMAP Last updated.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 23:38:58 +07:00
BFlat 45516a6a96 Merge pull request #761 from fahrim/mcp-variables
Variables (data merge): text/visibility variables, datasets, panel
2026-10-10 23:35:20 +07:00
bflatasticandClaude Opus 5.5 d0015a496b variables: Window › Variables opens the panel
As Window's other panel items do, and as the reference's Window menu has
it, Window › Variables is the panel itself instead of a submenu of
eighteen commands. The panel menu gains Make Text Dynamic, Make
Visibility Dynamic, Unbind Variable and Delete Variable beside the
bottom bar's buttons, which share one reading of what the selection
allows; every command stays in the command palette. The labels only
the submenu used leave the catalogs.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 23:34:21 +07:00
bflatasticandClaude Opus 5.5 2e07f887bf docs: Variables in the ROADMAP's last-updated list (#761)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 23:34:21 +07:00
bflatasticandClaude Opus 5.5 500e19680d variables: review fixes for the panel, dialogs and translations
- Dataset and variable names are the user's: the panel's Data Set dropdown and
  the dialogs' name dropdowns show them as they are instead of translating
  them; the dialog's Kind dropdown shows translated kind names.
- Choosing the empty option in a dialog dropdown picked the first name.
- The panel reads the art once per frame for every row's italics, the dialog
  no longer clones the document's variables every frame, and slices are
  matched instead of indexed.
- "No document" and "Define a variable first" go through tl!, and the dialog
  headings Variable Options / Edit Data Set, Text and Visibility have rows in
  every complete catalog; the unused "{name} · {kind} · {count}" row is gone.
- German rows for every Variables string (the catalog predates this branch).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 23:34:21 +07:00
bflatasticandClaude Opus 5.5 b3fa281282 variables: review fixes for hidden objects, namespaces and agent params
- A visibility variable could hide an object but never show it again: dataset
  application, capture and binding refused any object that wasn't visible
  (`is_editable`), so a row that hid an object left it hidden for good and a
  capture after hiding it in the Layers panel didn't record it. They now use
  `Document::variable_target`, which ignores the object's own visibility
  (locked art and art on hidden or locked layers are still skipped).
- Renaming a variable renamed the active dataset when the two shared a name,
  leaving it pointing at a dataset that doesn't exist.
- `variable.delete` and `dataset.delete` without `names` act on the
  highlighted variable and the active dataset, so Window > Variables > Delete
  Variable / Delete Data Set no longer fail with "missing `names`".
- `ids` is checked like other commands' explicit targets (a non-list no longer
  falls back to the selection, bad ids are errors), names are trimmed and
  capped at 255 characters, and the bind checks are shared by Bind and Make
  Dynamic.
- Make Dynamic's fallback name no longer becomes " 2" for unnamed art.
- `dataset.list` reads the art once for every row's drift check, and
  `Variables::prune` looks names up in a set.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 23:34:21 +07:00
BFlat e3874e89e7 Merge pull request #981 from storytold/feat/distort-effects
Part of gap 2: Effect › Distort (Diffuse Glow, Glass, Ocean Ripple)
2026-10-10 23:24:59 +07:00
bflatasticandClaude Opus 5.5 8a0cd9dbf6 Part of gap 2: Effect › Distort (Diffuse Glow, Glass, Ocean Ripple)
Three raster effects on the pixel-filter pipeline
(vectorcraft_effects::pixel::distort), under a new Effect › Distort
submenu between Blur and Pixelate in the Raster Effects section (the
vector Distort & Transform stays its own submenu):

- Diffuse Glow (graininess 0..10, default 6; glowAmount 0..20, 10;
  clearAmount 0..20, 15): the highlights, softened over 2 points, glow
  white from the brightness Clear Amount leaves clear; white grain as
  dense as Graininess says is sprinkled over the object, thicker in the
  glow. Transparency stays as it was.
- Glass (distortion 0..20, 5; smoothness 1..15, 3; texture Blocks,
  Canvas, Frosted or Tiny Lens, default Frosted; scaling % 50..200, 100;
  invert): the object seen through a glass surface; each pixel takes the
  colour the surface's slope bends it to, sampled between pixels. Slopes
  are taken over a span Smoothness widens. The surfaces are made in code
  (Canvas is Texturizer's weave); Load Texture is left out.
- Ocean Ripple (rippleSize 1..15, 9; rippleMagnitude 0..20, 9): smooth
  noise ripples about Ripple Size + 2 points across shift the object by
  up to 0.03 x magnitude x their size.

The shifts are capped, so the effects' outsets and reaches are exact,
and every surface lies in document space around the object's centre:
the same at any zoom or resolution, moving with the object, identical
on every redraw.

Catalogue rows with parameter docs, menu entries, the Texture dropdown,
translations (and German's missing Canvas), tests (parameters and
clamping, outsets, each texture and Invert, the ripples' reach, the glow
and its grain, resolution and move invariance, canvas, multithreaded,
PDF and SVG, the command sweep with junk parameters, the menu) and
ROADMAP.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 23:23:36 +07:00
BFlat f147eb58c7 Merge pull request #974 from IHAGI-c/fix/graph-tick-marks
Graph Type: tick mark length and count per axis, category tick marks, axis label prefix and suffix
2026-10-10 23:07:36 +07:00
bflatasticandClaude Opus 5.5 3a48de555e Review: translate the tick mark lengths; ROADMAP
Short and Full Width, the Graph Type dialog's new Length choices, in the
complete catalogs (None was there). The Value Axis dropdown keeps the
one that landed with #971. ROADMAP Last updated.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 22:49:15 +07:00
BFlat 6794385731 Merge pull request #971 from IHAGI-c/fix/graph-value-axes
Graph Type: value axis on the left, right or both sides; separate scales
2026-10-10 22:35:33 +07:00
bflatasticandClaude Opus 5.5 bea68002e9 Review: Graph Type's Value Axis is a dropdown
The generic Graph Type dialog showed `valueAxis` as a text field. It now
lists On Left Side, On Right Side and On Both Sides, translated in the
complete catalogs, with a test that the choices match the command's
params and that OK moves the axis. ROADMAP Last updated.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 21:48:51 +07:00
BFlat 2b000d828e Merge pull request #934 from dwetscher/feat/i18n-german
German interface language (de)
2026-10-10 21:28:40 +07:00
bflatasticandClaude Opus 5.5 a644c818c9 Review: German for the features landed since the catalog was written
Pixelate, Texture and Video raster effects, Libraries groups, search,
import and export, Update Changed Links, System Title Bar, Scatter, Art
and Pattern Brush Options with Colorization, and the PSD messages, in
the catalog's own conventions. ROADMAP Last updated.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 21:28:15 +07:00
BFlat 58bb72ffc6 Merge pull request #969 from rafi612/system-title-bar
Compact app bar: 32 pt bar, PhotoCraft search icon, no app menu + System title bar option
2026-10-10 21:26:34 +07:00
bflatasticandClaude Opus 5.5 6315086f96 Review: System Title Bar only where it applies, docs, title repaint
- Preferences hides System Title Bar on macOS and the web, where it did
  nothing (it fell through to the plain checkbox row), and lists it with
  the window options instead of under Language.
- The next-launch note reuses "Applies the next time VectorCraft starts."
  instead of a second wording in every catalog.
- A new window title asks for one more frame: AppKit lays the title bar
  out again for it, and the next frame centres the window buttons (#968).
- The menu bar drops the bold branch for the VectorCraft menu it no
  longer shows; theme is imported where the tests use it.
- Docs: Language is Preferences › User Interface › Language (VectorCraft
  › Language on macOS); the control protocol describes System Title Bar;
  ROADMAP Last updated.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 21:15:21 +07:00
BFlat 9f659195c3 Merge pull request #972 from storytold/fix/968-traffic-lights
#968: centre the macOS window buttons on the app bar
2026-10-10 20:56:34 +07:00
bflatasticandClaude Opus 5.5 258d61ced0 #968: centre the macOS window buttons on the app bar
AppKit places close, minimize and zoom in a standard title bar, shorter
than the 44-point app bar they sit over, so they rode high on it. They
are now moved to the middle of the bar, inset from its left as far as
from its top, with the title bar container made as tall as the bar so
they stay clickable. AppKit lays the title bar out again on resize and
when leaving full screen, so the placement runs every frame and sets a
frame only when it is out of place. The app bar keeps the room the
buttons take, measured, instead of a fixed 78 points.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 20:56:18 +07:00
BFlat 5ff1b97376 Merge pull request #970 from storytold/fix/962-inner-glow-source
#962: Inner Glow's Source is a Center/Edge dropdown
2026-10-10 20:45:36 +07:00
bflatasticandClaude Opus 5.5 9216c47204 #962: Inner Glow's Source is a Center/Edge dropdown
The effect dialog showed Inner Glow's `source` as a text field, so the
only way to pick Center was to type the parameter value. It now lists
Center and Edge like the other fields that pick one of a few values.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 20:32:47 +07:00
BFlat 4eaf5e7b50 Merge pull request #967 from storytold/feat/link-watch
Links: Update Links applies while a document is open (from #956)
2026-10-10 20:20:24 +07:00
bflatasticandClaude Opus 5.5 068a934f6a Links: one watch for changed linked files
The link watch checks the active document's linked files every two
seconds and as the window comes back to the front, so the separate check
on focus that #925 added (missing_links::after_focus and its asked-files
set) goes: with both, a change was acted on twice. The watch also
walks the document's links only when a look is due, not every frame, and
wakes the app every two seconds only while the document has links. The
doc comments of status and links::groups are back on their functions.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 20:19:27 +07:00
BFlat f81c0f51d7 Merge pull request #959 from IHAGI-c/fix/graph-combine-types
Graph Type: combine graph types, one type per series
2026-10-10 20:09:10 +07:00
BFlat 11c3a99bfb Merge pull request #960 from storytold/feat/texture-effects
Part of gap 2: Effect › Texture (Craquelure, Grain, Mosaic Tiles, Patchwork, Stained Glass, Texturizer)
2026-10-10 19:44:02 +07:00
bflatasticandClaude Opus 5.5 30ba774e6f Part of gap 2: Effect › Texture (Craquelure, Grain, Mosaic Tiles, Patchwork, Stained Glass, Texturizer)
Six raster effects on the pixel-filter pipeline
(vectorcraft_effects::pixel::texture), under a new Effect › Texture
submenu between Sharpen and Video in the Raster Effects section:

- Craquelure (crackSpacing pt 2..100, default 15; crackDepth 0..10, 6;
  crackBrightness 0..10, 9): the object on relief plaster that cracks into
  plates about Crack Spacing apart (a Voronoi network over jittered points)
  and along the quarter, half and three-quarter contours of its softened
  tones. Depth sets how dark and wide the cracks are and how high the
  plates' bevels and the tones stand (lit from the top left); Brightness
  how brightly the surface is lit.
- Grain (intensity 0..100, 40; contrast 0..100, 50 = unchanged; grainType
  Regular, Soft, Sprinkles, Clumped, Contrasty, Enlarged, Stippled,
  Horizontal, Vertical, Speckle; default Regular): coloured 1-point grains,
  smooth ones, clumps, 2-point grains, streaks along rows or columns, dark
  specks; Sprinkles and Stippled use the background colour, white.
- Mosaic Tiles (tileSize pt 2..100, 12; groutWidth 1..15, 3; lightenGrout
  0..10, 9): irregular tiles bevelled at their edges, with sunken grout half
  a point wide per step, lightened as Lighten Grout says.
- Patchwork (squareSize pt 0..10, 4; relief 0..25, 8): squares filled with
  the colour around their centres, raised to heights that follow the
  highlights and shadows, a little more or less at random.
- Stained Glass (cellSize pt 2..50, 10; borderThickness 1..20, 4;
  lightIntensity 0..10, 3): single-coloured panes leaded in the foreground
  colour (black, half a point per step), lit from behind at the object's
  centre and fading out towards its corners (PixelSpace gains `extent`).
- Texturizer (texture Brick, Burlap, Canvas, Sandstone, default Canvas;
  scaling % 50..200, 100; relief 0..50, 4; lightDirection Bottom, Bottom
  Left, Left, Top Left, Top, Top Right, Right, Bottom Right, default Top;
  invert): the object on a surface in relief. The four surfaces are height
  fields generated in code (bricks in stretcher bond, plain weaves coarse
  and fine, octaves of smooth noise); no image files. Load Texture is left
  out.

Every pattern lies in document space around the object's centre, so the
result is the same at any zoom or raster resolution, moves with the object
and is identical on every redraw (hash noise of cell indices); slopes are
taken in document units. Work per pixel is bounded (a 5 x 5 cell search,
four or five height samples, box blurs); parameters are clamped to their
ranges and finite-checked. The Pixelate helpers (Place, the cell search,
the softened colours) are shared, Mezzotint uses the shared smooth noise,
and the effect dialogs' dropdowns translate their labels in an "effect"
context where the plain word means something else (Soft, Horizontal and
Vertical are type settings in Japanese and Chinese).

Catalogue rows with parameter docs, outsets and reaches, menu entries,
dropdowns (Grain Type, Texture, Light Direction), translations, tests
(parameters and clamping, cracks and contours, ten distinct grains, tiles
and grout, squares in relief, leaded panes and the centre light, the
textures lit and inverted, the same at twice the resolution and when
moved, canvas, multithreaded, PDF and SVG, the command sweep with junk
parameters, the dialogs and the menu) and ROADMAP.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 19:31:47 +07:00
BFlat 32a688d68b Merge pull request #953 from crqch/fix-contributor-links
Fix contributor links
2026-10-10 18:50:11 +07:00
BFlat 5d07d646a9 Merge pull request #950 from seldoms/i18n/chinese-translations
i18n: wrap hardcoded UI strings for Chinese localization
2026-10-10 18:40:44 +07:00
bflatasticandClaude Opus 5.5 22443d8711 Keep CJK UI fallback fonts to ui_fonts
The app already finds an installed font for CJK (and other) characters
the UI fonts lack, the first time a frame paints one (ui_fonts): reading
a system CJK font at every startup duplicated that, cost a font file's
read and memory for interfaces that never show CJK, and broke its test.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 18:36:15 +07:00
BFlat d428de6caa Merge pull request #952 from storytold/fix/949-artboard-label-width
Fix #949: artboard names fit their artboard when zoomed out
2026-10-10 18:25:02 +07:00
bflatasticandClaude Opus 5.5 6a13088840 Fix #949: artboard names fit their artboard when zoomed out
Artboard names are drawn at a fixed screen size above each artboard, so
zoomed out, where artboards shrink on screen, the names ran past them
and over their neighbours. A name is now no wider than its artboard on
screen, ending in an ellipsis when longer, and an artboard narrower
than 24 px shows none.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 18:24:50 +07:00
BFlat 18c9d27c8d Merge pull request #947 from IHAGI-c/fix/graph-blank-values
Graph Data: blank cells are left out, not drawn as zero; quoted numbers are labels
2026-10-10 18:16:26 +07:00
BFlat 3b32ea9626 Merge pull request #946 from rschuerer/fix/861-draw-non-native-art
Part of #861: draw non-native art in .ai editing data from its PDF
2026-10-10 18:13:52 +07:00
bflatasticandClaude Opus 5.5 42b198e3cb Graph data: constants after the imports
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 17:59:47 +07:00
bflatasticandClaude Opus 5.5 1446b4f5dc Keep the doc comment of unreadable on unreadable
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 17:58:55 +07:00
BFlat 7d6be31711 Merge pull request #948 from storytold/feat/brush-options-scatter-art-pattern
Part of gap 5: Scatter, Art and Pattern Brush Options
2026-10-10 17:57:25 +07:00
bflatasticandClaude Opus 5.5 2bc6c66c94 Part of gap 5: Scatter, Art and Pattern Brush Options
Double-clicking a Scatter, Art or Pattern brush in the Brushes panel (or the
panel menu's Brush Options...) now opens its options dialog, as Calligraphic
and Bristle brushes already did. OK runs brush.options and every stroke
painted with the brush redraws.

- Scatter Brush Options: Name; Size (10-1000 %), Spacing (10-10000 %),
  Scatter (-1000-1000 %) and Rotation (-180-180 deg), each Fixed (the first
  value), Random (between the two values) or Pressure (the first value at
  the lightest pen pressure, the second at the heaviest); Rotation relative
  to Page or Path. Scatter brushes now keep these modes (`modes`); brushes
  saved before keep their look (Random where the two values differ).
- Art Brush Options: Name; Width (1-1000 %); Scale Proportionately, Stretch
  to Fit Stroke Length or Stretch Between Guides with the guides' Start and
  End (% of the art length); the four Directions; Flip Along and Across.
- Pattern Brush Options: Name; Scale (1-10000 %), Spacing (0-10000 %); the
  five tiles (Outer Corner, Side, Inner Corner, Start, End) drawn with their
  art or None; Flip Along and Across; Stretch to fit, Add space to fit or
  Approximate path.
- All three: Colorization (None, Tints, Tints and Shades, Hue Shift with its
  Key Color picked from the art's colours, the most used one by default) and
  a live preview of a stroke painted with the edited brush.

Brush definitions from files and commands are now kept within these ranges
(Brush::sanitize, also for Calligraphic and Bristle values); unknown modes,
directions, fits or colorization methods are refused. The brush.options and
ui.brushOptions docs list the new params and fields. Tests: the brush model
(modes, pressure, sanitizing, art colours), engine params reaching the
brush and strokes redrawing, junk params in command_sweep, and headless
dialog tests for each dialog.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 17:48:05 +07:00
BFlat 5b198f3c00 Merge pull request #941 from IHAGI-c/fix/graph-line-options
Graph Type: Edge-to-Edge Lines for line graphs; radar follows Mark and Connect Data Points
2026-10-10 17:32:01 +07:00
bflatasticandClaude Opus 5.5 471c47f96a Graph Type: Edge-to-Edge Lines start off, as the reference app's do
New line graphs put their points at the centres of their categories, the
option's default in the reference app; graphs saved before the option
existed were drawn edge to edge and keep it (a field default of its own).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 17:31:33 +07:00
BFlat 7241726e56 Merge pull request #940 from IHAGI-c/fix/graph-axis-override
Graph Type: Override Calculated Values uses the exact value-axis range
2026-10-10 17:23:59 +07:00
BFlat 3bdaa45607 Merge pull request #945 from storytold/docs/readme-status-1010
Docs: README status for 2026-10-10
2026-10-10 17:22:12 +07:00
bflatasticandClaude Opus 5.5 b4c89f7301 Docs: README status for 2026-10-10 (PSD and PSB open and place)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 17:21:50 +07:00
BFlat 20c1a1621e Merge pull request #944 from storytold/fix/938-corner-widgets-multi
Fix #938: Live Corner widgets on every selected path
2026-10-10 17:20:05 +07:00
bflatasticandClaude Opus 5.5 d57134a308 Fix #938: Live Corner widgets on every selected path
The corner widgets only showed when the selection was exactly one path.
Now every selected path that has them shows its widgets: live rectangles
and polygons with the Selection tool, any path with Direct Selection,
each with its own corners (all of a path selected whole, the
Direct-Selected ones otherwise). Dragging any widget rounds every shown
corner of every path in one step, Alt-click cycles their kind, and the
red limit outline covers them all; a double-click opens Corners for the
path it was on. Each widget is drawn in its own layer's colour.

object.setLiveShape takes items: [{id, corners?}], several objects each
with its own corners, which the drag sends.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 17:19:52 +07:00
BFlat 9449c92136 Merge pull request #943 from storytold/feat/926-library-groups
Fix #926: the Libraries panel's search, groups and library export/import
2026-10-10 17:18:20 +07:00
bflatasticandClaude Opus 5.5 d62ecfe33a Fix #926: the Libraries panel's search, groups and library export/import
Search: a search field at the top of the Libraries panel filters the
current library's colours, character and paragraph styles and graphics
by name, ignoring case; groups without a match are hidden, groups with
one open, and a search nothing matches says so ("No results").

Groups: items can be put in user-named groups, kept in the library file
(`groups: [{name, items: [{kind, item}]}]`, left out when there are
none, so files written before groups load as they are). New commands:
library.createGroup {library?, name?, items?}, library.renameGroup
{library?, group, name}, library.deleteGroup {library?, group} (its
items stay, ungrouped) and library.moveItem {library?, kind, item,
group?}. An item is in one group at most; deleting an item takes it out
of its group. The panel shows each group as a collapsible section with
its item count after the ungrouped items (rename and delete on its
context menu), each item's context menu has Move to Group (No Group,
the groups, New Group...), and a New Group button sits in the footer.
library.get lists the groups, library.list counts them. The generic
command dialog takes fixed params in `__params` for this.

Export / import: library.export {library?, path?} writes a library
(colours, styles, graphics with art and thumbnails, groups) as a
.vclibrary file, the JSON the library folder keeps (without a path:
{data}); library.import {path | data | dataBase64, name?} adds one as a
new library, made current, numbered on a name clash ("Brand (2)").
The panel menu has Import Library... and Export Library..., through the
app's file dialogs (the web downloads, and picks through File > Open,
which now lists Libraries files). Imported and folder files are made
safe: at most 10,000 items of a kind and 1,000 groups, names clipped and
made unique, sizes finite, thumbnails kept only when their PNG header
says at most 1024 px a side, group entries naming missing items or
unknown kinds dropped; a file over 512 MB or that isn't a library is an
error. Paths go through the engine's file helpers (automation roots).
The importer is fuzzed (import_fuzz: garbage and mutated libraries).

Also fixed: the third graphic added to a library got the second's id
(`graphic-2` twice).

Docs: the commands' params docs, docs/mcp.md, ROADMAP.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 17:17:01 +07:00
BFlat c738400ebb Merge pull request #942 from storytold/feat/video-effects
Part of gap 2: Effect › Video (De-Interlace, NTSC Colors)
2026-10-10 17:06:09 +07:00
bflatasticandClaude Opus 5.5 c71af3079c Part of gap 2: Effect › Video (De-Interlace, NTSC Colors)
Adds the Video group to the raster effects, after Sharpen:

- De-Interlace…: Eliminate Odd or Even Fields, Create New Fields by
  Duplication or Interpolation. The fields are the rows of the document's
  raster grid (Document Raster Effects Settings › Resolution, carried to
  the filters as PixelSpace::line) counted from the top of the page, so
  the result is the same at any zoom and moves with the page. A line
  taken out copies the line above (the one below at the top), or takes
  the average of the two.
- NTSC Colors (no options, applied at once): colours a composite
  television signal can't carry, with luma plus chroma past 110 % of white
  or luma minus chroma below -20 % in YIQ, have their chroma cut to fit,
  keeping their luma. Saturated yellow, cyan and pure red lose some
  saturation; legal colours stay as they are.

Catalogue rows with parameter docs, dialog dropdowns, menu, translations,
tests (effects, canvas, command sweep junk, menu) and ROADMAP.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 17:05:56 +07:00
BFlat 7fb2c47006 Merge pull request #939 from storytold/fix/811-identify-unnamed-glyphs
Fix #811: unnamed glyphs of an installed font stay in their type
2026-10-10 16:46:54 +07:00
bflatasticandClaude Opus 5.5 a61aa93c1c Fix #811: unnamed glyphs of an installed font stay in their type
In a PDF (or the PDF part of an .ai file), a glyph of a subset font that
no ToUnicode map, CID table or character map of the font program names
was drawn as outlines, so one text object came in split: "RADA" as the
type "ADA" plus the R's outline.

Such a glyph is now looked for in the installed face of the font's name:
the first character (of those single-byte fonts encode: ASCII, Latin-1,
Latin Extended-A, punctuation, the euro and trade mark signs, fi and fl)
whose glyph draws the same outline, point for point within 2/1000 em,
names it. A subset carries the font's own outlines, so an installed copy
of the same font finds every glyph. Other versions of the font, empty
glyphs and glyphs that are no character still keep their outlines, with
the warning as before. Results are cached per glyph.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 16:46:39 +07:00
BFlat 552945f4e7 Merge pull request #936 from storytold/fix/927-direct-marquee-type
Part of #927: Direct Selection marquees take the type they touch
2026-10-10 16:19:59 +07:00
bflatasticandClaude Opus 5.5 7bf002af2b Part of #927: Direct Selection marquees take the type they touch
A Direct Selection (or Group Selection) marquee only gathered the
anchors of paths, so type, images, symbols and other objects without
anchors to pick were never selected by it. They are now selected whole
when the marquee touches them, as with the Selection tool, next to the
path anchors it holds; locked and hidden objects stay out.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 16:19:44 +07:00
BFlat 3da4080b5e Merge pull request #935 from storytold/fix/918-place-psd
Fix #918: PSD and PSB files open and place as their merged image
2026-10-10 16:09:58 +07:00
bflatasticandClaude Opus 5.5 0eb4ce5e98 Fix #918: PSD and PSB files open and place as their merged image
File › Place and File › Open read PSD and PSB files: the merged image
every such document carries after its layers, which is what a linked PSD
shows. A placed PSD links like any image, so the Links panel updates and
relinks it, and it is sized by its ResolutionInfo resource.

The reader is written from the public file format specification. It
reads Bitmap, Grayscale, Duotone, Indexed, RGB, CMYK (through the colour
settings' CMYK) and Lab, at 1, 8, 16 and 32 bits per channel (32-bit
values are linear), raw, PackBits or zipped with or without prediction.
A document with transparency stores its merged image on white with the
alpha in the first extra channel. It comes back with straight colours,
also for 16- and 32-bit files, which say so in their Lr16/Lr32 block.
Multichannel files are refused with a message. The file is untrusted:
every read is bounds-checked and the image's size is checked against
the decode budget before anything is allocated.

PSB is a read-only format of its own, so exports never write a PSD under
a .psb name. The desktop packaging still doesn't associate either
extension with VectorCraft (UNASSOCIATED_EXTS): they belong to raster
editors. Layers (import options) are left for later.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 16:09:41 +07:00
BFlat be51213f0d Merge pull request #929 from haranishi/fix/eps-gradient-stop-cap
EPS import: bound the stitched-gradient builder
2026-10-10 16:06:43 +07:00
BFlat fe2d2ca173 Merge pull request #933 from storytold/fix/921-properties-gradient
Fix #921: the Properties panel's Gradient section with Type and Draw
2026-10-10 15:51:05 +07:00
bflatasticandClaude Opus 5.5 b3ed7df2a4 Fix #921: the Properties panel's Gradient section with Type and Draw
With the Gradient tool active, the Properties panel shows a Gradient
section: the type buttons (Linear, Radial, Freeform) and, for a
freeform gradient, Draw: Points or Lines as radio buttons. The Gradient
panel and the Properties panel share the type row and the draw mode
change.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 15:50:23 +07:00
BFlat 93fb184939 Merge pull request #932 from storytold/fix/924-tab-leader-typing
Fix #924: the Tabs panel's Leader and Align On keep what is typed
2026-10-10 15:50:20 +07:00
bflatasticandClaude Opus 5.5 2ef32bb1a2 Fix #924: the Tabs panel's Leader and Align On keep what is typed
Both fields read their text from the tab stop again every frame, so each
keystroke was lost before Enter or a click away could apply it: the
field seemed to clear itself while typing. They now use the panels' text
field, which keeps the text being typed until it is committed. The
leader keeps spaces (". " for spaced dots), up to eight characters.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 15:49:49 +07:00
BFlat 5ccbbcca3f Merge pull request #931 from storytold/fix/925-links-on-focus
Fix #925: linked files changed in another app update when the window comes back
2026-10-10 15:49:46 +07:00
bflatasticandClaude Opus 5.5 11beb8fff1 Fix #925: linked files changed in another app update when the window comes back
Preferences › File Handling › Update Links only acted when a document
opened, so a linked image edited in another app while VectorCraft stayed
open kept its old pixels until Update Link in the Links panel, even with
Automatically chosen.

When the window comes back to the front, the active document's links
are now checked. With Automatically, changed files are read again; with
Ask When Modified, they are offered for update, once per change of a
file (keyed by path, size and modification time, since two saves can
share a time); with Manually, the Links panel shows them as modified.
Nothing is asked while a dialog is open.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 15:49:08 +07:00
BFlat 04eb5e52c8 Merge pull request #930 from storytold/feat/pixelate-effects
Part of gap 2: Effect › Pixelate (Color Halftone, Crystallize, Mezzotint, Pointillize)
2026-10-10 15:47:10 +07:00
bflatasticandClaude Opus 5.5 9bad0a24ca Part of gap 2: Effect › Pixelate (Color Halftone, Crystallize, Mezzotint, Pointillize)
Four Photoshop-style raster effects on the pixel-filter pipeline
(vectorcraft_effects::pixel::pixelate), under a new Effect › Pixelate
submenu between Blur and Sharpen in the Raster Effects section:

- Color Halftone (maxRadius 4..127, default 8; channel1..channel4 screen
  angles -360..360, defaults 108/162/90/45): each colour channel is
  screened at its angle in square cells sized so a dot of Max. Radius
  fills one; each cell's dot covers the share of the cell that is the
  channel's coverage-weighted mean there (white stays white, black
  black). RGB documents screen R, G, B (channels 1 to 3); CMYK documents
  screen C, M, Y, K inks (channels 1 to 4), also when they are drawn ink
  plane by ink plane (the K plane uses channel 4).
- Crystallize (cellSize 3..300, default 10): every pixel takes the
  colour at the nearest of one jittered point per cell (exact Voronoi
  over a 5 x 5 neighbourhood, pruned by distance).
- Mezzotint (type: Fine/Medium/Grainy/Coarse Dots, Short/Medium/Long
  Lines, Short/Medium/Long Strokes; default Fine Dots; a dropdown in the
  dialog): each channel is turned fully on or off against its own random
  threshold pattern, so the object becomes pure colours.
- Pointillize (cellSize 3..300, default 5): one dot of random size per
  cell at a jittered point, coloured by the softened object there and as
  opaque as the object at its centre, stacked in random order over a
  white canvas where the object is.

Lengths are in points (Scale Strokes & Effects scales them) and every
pattern lies in document space around the object's centre, so the
result is the same at any zoom or raster resolution, moves with the
object, and is identical on every redraw (hash noise of the pattern's
cell indices, no state). Work per pixel is bounded whatever the
parameters, which are clamped to their ranges and finite-checked; the
halftone's cell grid is capped by the raster's size and a screen finer
than 3 pixels leaves the image as it is (its average). PixelSpace gains
`channels` so the renderer tells the filters what the channels hold.

Catalogue rows with parameter docs, outsets and reaches for cropping,
menu entries, dialog labels (Max. Radius, Channel 1-4, Cell Size), the
Mezzotint Type dropdown, translations, and tests: parameters and
clamping, tone and coverage, CMYK inks, polygon crystals, pure-colour
mezzotints with ten distinct patterns, dots on a white canvas, the same
result at twice the resolution and when moved, the canvas, PDF and SVG
through the engine, the command sweep with junk parameters, the dialogs
and the menu.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 15:42:24 +07:00
BFlat 2d6014583a Merge pull request #923 from callmeBalloch/fix/artboard-artwork-movement
Fix artwork movement when editing artboard X/Y coordinates
2026-10-10 15:29:47 +07:00
bflatasticandClaude Opus 5.5 f3f5e38bb6 ROADMAP: the #922 note joins the Last updated list
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 15:06:59 +07:00
BFlat e1599a16aa Merge pull request #799 from vbasky/feat/graph-series-palette
Colour graph series through Group Selection
2026-10-10 14:37:23 +07:00
bflatasticandClaude Opus 5.5 f21f8a89ce Graph series: find series art in one pass and ignore indices past the series
Painting looked up each selected object's graph by walking up through
parent_of, a search of the whole document per level, so a fill or stroke
change on a large selection grew with the square of the document. The
series art of every graph is now mapped in one pass, and documents with
no graph skip the lookup.

A series index comes from the file: one past the graph's series grew the
graph's series paints to that length. Such a group is no longer taken
for a series.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 14:33:41 +07:00
BFlat dd61dfa146 Merge pull request #920 from storytold/feat/885-transform-effect-dialog
Part of #885: the Transform effect's dialog takes Transform Each's controls
2026-10-10 14:32:55 +07:00
bflatasticandClaude Opus 5.5 20e5a746bd Part of #885: the Transform effect's dialog takes Transform Each's controls
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 <[email protected]>
2026-10-10 14:32:10 +07:00
BFlat da73a46137 Merge pull request #919 from storytold/feat/832-automation-roots
Fix #832: --automation-read-root and --automation-write-root confine the MCP server's files
2026-10-10 14:28:11 +07:00
bflatasticandClaude Opus 5.5 9f875050ef Fix #832: --automation-read-root and --automation-write-root confine the MCP server's files
vectorcraft-cli mcp and vectorcraft --control take the flags PhotoCraft
takes. While roots are in force, every path a command reads (open, place,
relink, SVG image links, library and profile loads, plug-ins, preset
imports, font searches) must lie inside the read root and every path it
writes (save, export, package, Export for Screens and for Web, print to
file, captures, library saves) inside the write root. Paths are made
absolute, links are followed (a missing file's nearest folder's), and the
result is compared by whole components, ignoring case on Windows; `..`
below a missing folder, dangling links and device names are refused. A
root left out grants none of its access; without the flags nothing
changes.

The checks live in one place, vectorcraft_engine::file_access, consulted
by the engine's file helpers and the app's file services. The headless
server confines its whole process; the app confines control requests,
the frames carrying input they inject and the background saves they
start, leaving the person at the keyboard and the app's own folders
alone. The screenshot tool now has the backend write its file.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 14:27:24 +07:00
BFlat ab69087d68 Merge pull request #915 from Messhias/feat/394-display-print-size
Part of #394: Display Print Size at 100% Zoom drives Actual Size
2026-10-10 14:26:31 +07:00
bflatasticandClaude Opus 5.5 77e2a30c6d Part of #394: Actual Size shows print size whatever the display scaling
Display Print Size at 100% Zoom divided an assumed 96 pixels per inch by
the display's scale factor, so on a scaled display (150%, Retina) a
document inch came out a fraction of an inch. Nothing measures the
screen's real density, so an inch is now 96 screen points, the reference
density display scaling is set against, at any scale factor. The unused
screen_ppi and pixels_per_point fields go.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 14:25:50 +07:00
BFlat 90818cae40 Merge pull request #910 from Messhias/feat/394-font-names-in-english
Part of #394: Show Font Names in English labels the font menus
2026-10-10 14:25:15 +07:00
BFlat 3ab2af0744 Merge pull request #917 from storytold/fix/909-profile-preview-scale
Fix #909: a Width tool profile's preview fits the Profile menu
2026-10-10 13:53:54 +07:00
bflatasticandClaude Opus 5.5 8d2a3f48a1 Fix #909: a Width tool profile's preview fits the Profile menu
The Profile menu's preview drew a stroke's width profile assuming its
widths stay within the stroke weight. A profile made with the Width tool
can be many times wider, so its silhouette spilled over the Stroke panel.
It is now scaled to the preview by its widest point and clipped to it.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 13:52:41 +07:00
BFlat 71003386ac Merge pull request #916 from storytold/fix/900-segmented-field
Fix #900: spinner fields read as one box in three parts
2026-10-10 13:32:13 +07:00
BFlat bd439727dd Merge pull request #914 from storytold/feat/812-tool-options
Part of #812: polygon properties, Flare Tool Options, more tool double-clicks
2026-10-10 13:23:32 +07:00
BFlat 809c4266a4 Merge pull request #913 from storytold/fix/901-shift-click-target
Fix #901: Shift-click a target circle in the Layers panel to add or remove it
2026-10-10 13:15:31 +07:00
BFlat 994e821f53 Merge pull request #912 from storytold/fix/903-reselect-after-deselect
Fix #903: Reselect repeats a Same command after Deselect
2026-10-10 13:15:17 +07:00
bflatasticandClaude Opus 5.5 2543da7cf0 Fix #900: spinner fields read as one box in three parts
A number field with a spinner and a preset list (stroke weight, font
size, leading…) was three boxes side by side: the field came out a
point taller than the spinner and the chevron, and each joint had two
borders. The field is now exactly as tall as the other controls of a
row, with its text centred, and the three parts share their borders.
num_field draws its box with the panel text fields' code instead of a
copy of it.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 13:13:41 +07:00
bflatasticandClaude Opus 5.5 990d869897 Part of #812: more tools open their options on a double-click
Double-clicking a tool's button (or tool.options {tool}) now also opens:
- Artboard tool: Artboard Options of the active artboard (the Artboard
  tool's while it is in use, else the window's);
- the graph tools: Graph Type for the selected graph (an error without
  one), the dialog Object > Graph > Type opens;
- the Symbolism tools: Symbolism Tools Options with the brush the eight
  tools share (Diameter, Intensity, Symbol Set Density);
- Magic Wand: the Magic Wand panel.

The Object > Graph dialogs' opener is shared with the toolbar. The new
labels are translated in the eight complete catalogs.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 13:00:21 +07:00
bflatasticandClaude Opus 5.5 ae27d899b8 Part of #812: Flare Tool Options last and open from the toolbar
The Flare tool keeps its options (Center: Diameter, Opacity, Brightness;
Halo: Growth, Fuzziness; Rays: on/off, Number, Longest, Fuzziness; Rings:
on/off, Path, Number, Largest, Direction) as persistent tool options,
saved with the preferences. The next flare dragged out uses them (the drag
still sets the centre and diameter, and Up/Down the ray count), a click
with the tool opens them filled in, and double-clicking the tool (or
tool.options {tool: "flare"}) opens them to edit: OK keeps them and draws
nothing. Before, the click dialog was the generic parameter form with
fixed defaults and the drag always used the command's defaults.

The new Flare Tool Options dialog lays the four groups out in two
columns; Rays and Rings have their checkboxes, and every value is kept
within its range. Its labels are translated in the eight complete
catalogs.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 13:00:21 +07:00
bflatasticandClaude Opus 5.5 7c0ce8a382 Part of #812: polygon properties in the Properties and Transform panels
A selected live polygon now shows Illustrator's Polygon Properties in the
Transform panel and the Properties panel's Transform section: side count,
angle, corner type and radius, radius, side length and Make Sides Equal
(enabled once an uneven scale has made its sides differ). Before, only the
side count and corner radius were there.

object.setLiveShape takes polygonAngle (degrees counterclockwise),
polygonRadius and sideLength (points, centre to vertex / side) and
makeSidesEqual, which drops the uneven scale and shear and keeps the
polygon's centre, angle and mean radius. Each call is one undo step; a
radius or length that isn't a number above 0 is an error. A star stays a
plain path, as in Illustrator.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 13:00:21 +07:00
BFlat 5305b80308 Merge pull request #899 from vbasky/credit/vbasky-name
Credit vbasky by real and display name
2026-10-10 12:56:25 +07:00
bflatasticandClaude Opus 5.5 980cc4fe44 Fix #901: Shift-click a target circle in the Layers panel to add or remove it
Clicking an object's target circle in the Layers panel always replaced
the selection, so several objects couldn't be picked there. Shift-click
now adds the object (a layer: its art) to the selection, or takes it out
when it is selected already, as in Illustrator; nothing stays targeted
then. layer.target takes add: true for it.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 12:55:38 +07:00
bflatasticandClaude Opus 5.5 6917984329 Fix #903: Reselect repeats a Same command after Deselect
Select › Reselect repeated the last selection command, but a Select Same
command needs a selected object to compare with, so after Deselect it
failed with "nothing selected". Reselect now remembers the objects that
were selected when the command ran and, with nothing selected, takes the
reference from those still in the document.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 12:55:37 +07:00
BFlat ba2fc64d89 Merge pull request #906 from storytold/feat/852-pressure-brushes
Part of #852: Brush Options for Calligraphic and Bristle brushes, pen pressure
2026-10-10 12:38:10 +07:00
bflatasticandClaude Opus 5.5 5cf9233d26 Part of #852: Brush Options for Calligraphic and Bristle brushes, pen pressure
Double-clicking a brush in the Brushes panel (or the panel menu's Brush
Options…) opens its options. Calligraphic Brush Options: Angle,
Roundness and Size, each Fixed, Random or Pressure with its Variation,
over live previews of the nib and of a stroke. Bristle Brush Options:
Shape and the bristle sliders. OK runs brush.options; strokes painted
with the brush update.

The Paintbrush records the pen pressure along a stroke (path.freehand
takes [x, y, pressure] points), and a Calligraphic brush with Pressure
variation changes its nib along the stroke, from the value less the
variation at the lightest pressure to the value plus it at the heaviest.
Brushes saved before keep their Random variation. Pen pressure doesn't
reach the app on macOS yet (winit 0.30 reports none there).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 12:15:18 +07:00
BFlat db23e80ec4 Merge pull request #897 from storytold/fix/886-shift-anchor-guides
Fix #886: Smart Guides keep working on a Shift-constrained anchor drag
2026-10-10 12:00:28 +07:00
BFlat da010c33a1 Merge pull request #896 from storytold/fix/888-smooth-wheel-zoom
Fix #888: wheel notches zoom in a glide with Zoom with Mouse Wheel
2026-10-10 12:00:22 +07:00
bflatasticandClaude Opus 5.5 e47d542680 Fix #886: Smart Guides keep working on a Shift-constrained anchor drag
Dragging anchors with Direct Selection snapped to points, paths and
Smart Guides, but with Shift held the move kept its 45° angle and
snapped to nothing. The grabbed anchor now slides along the constrained
line onto the anchors, paths and alignment lines that cross it, as the
drawing tools' Shift does (counted from General › Constrain Angle).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 11:49:56 +07:00
bflatasticandClaude Opus 5.5 d8759492df Fix #888: wheel notches zoom in a glide with Zoom with Mouse Wheel
With General › Zoom with Mouse Wheel, each wheel notch's zoom was
applied on the frame it arrived, so the view jumped a step per notch
while scrolling glides over a few frames. A mouse wheel's notches now
glide in (what is left shrinks by e every 50 ms), ending at the same
zoom; a trackpad's fine steps still apply at once.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 11:49:54 +07:00
BFlat 6ba5e0585e Merge pull request #895 from storytold/fix/867-macos-dialog-thread
Fix #867: macOS file dialogs no longer run inside the window's event handler
2026-10-10 11:49:20 +07:00
BFlat 4c1e16d791 Merge pull request #894 from storytold/fix/890-artboard-edge-art
Fix #890: artboard art includes art flush with its right or bottom edge
2026-10-10 11:49:13 +07:00
bflatasticandClaude Opus 5.5 dd8f144770 Fix #867: macOS file dialogs no longer run inside the window's event handler
On macOS the Open and Save panels ran modally on the UI thread, inside
the window's event handler. Resizing the panel delivered window events
to that handler again, and the app crashed when the mouse was released.
They now open from a thread of their own, as on Linux (#592): rfd runs
the panel on the main thread from the run loop, outside the handler, and
the app picks the answer up when it comes.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 11:30:33 +07:00
bflatasticandClaude Opus 5.5 6c131431ed Fix #890: artboard art includes art flush with its right or bottom edge
The art that goes with an artboard (Duplicate Artboard and Copy/Cut with
art, the Artboard tool's Move/Copy Artwork with Artboard, and moving an
artboard by its X and Y) was found with a half-open containment test, so
an object whose right or bottom edge lay exactly on the artboard's was
left behind. Its edges now count as inside.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 11:30:32 +07:00
BFlat 8ae59bf6b7 Merge pull request #892 from storytold/fix/787-precise-export
Fix #787: raster exports keep translucent edges over opaque art opaque
2026-10-10 11:29:36 +07:00
BFlat b47f611e18 Merge pull request #891 from storytold/fix/798-curvature-any-path
Fix #798: the Curvature tool edits any selected path
2026-10-10 11:29:31 +07:00
BFlat 02d02f660f Merge pull request #889 from storytold/pr/roadmap-batch-2026-10-10
Docs: ROADMAP for the 2026-10-10 fixes; Other Library lists color books
2026-10-10 11:12:50 +07:00
bflatasticandClaude Opus 5.5 4099ebf3c9 Fix #787: raster exports keep translucent edges over opaque art opaque
The renderer composited in 8-bit integers, so where a partly transparent
anti-aliased edge crossed opaque art (or a background colour) the result
came out at alpha 254 on some pixels, and PNG, TIFF and WebP files were
written with an alpha channel. Raster exports (and Save for Web) now
composite in floating point (vello_cpu's f32 pipeline, enabled as a
feature), offscreen groups, masks and patterns included; the canvas keeps
the faster 8-bit path.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 11:12:13 +07:00