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 <noreply@anthropic.com>
The Curvature tool only edited the path it was drawing. It now edits any
selected path, whatever drew it, keeping its shape except where edited:
a click on a point makes it the current (direct-selected) point and a
drag moves it, re-curving only its two segments (the neighbours keep
their handle directions); Alt-click or double-click toggles it smooth or
corner and Delete removes it; a click on a segment adds a smooth point
without changing the shape, and a drag moves it in the same undo step.
With an end of an open path current, clicks go on from it (the old
segments keep their shape) and a click on the other end closes it.
The edits go through a new path.curvatureEdit command (move, insert,
extend, close), path.convertAnchor and path.removeAnchor, one undo step
each. The tool now claims Delete/Backspace while it has a point to
remove, so the key no longer deletes the whole path.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The ROADMAP's last-updated line names this batch's fixes and the two
community PRs that didn't add themselves (#792, #765); the platforms
paragraph says Windows starts on Direct3D 12 and loads no Vulkan driver
unless asked (#806); the guides row has ruler guides with Smart Guides
on and the hover labels (#812). Window › Swatch Libraries › Other
Library's description lists .acb color books (#831).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With Smart Guides on, hovering the Selection tool near an object's centre
or one of its anchors now labels it ("center", "anchor"), as
Illustrator does, and a press there grabs the object by that point, so
the point follows the pointer and snaps.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A raster effect painted below its object (Drop Shadow, Outer Glow) is
written as an image under the object's vector art. The image was
rendered over nothing and placed with Normal blending, so a Screen glow
or a Multiply shadow came out as Normal in the PDF. Each image is now
composited with its effects' blend mode, one image per mode when an
object's shadows and glows use several.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Drawing with Smart Guides on ignored the ruler guides: only with Smart
Guides off did Snap to Point use them (a vertical guide seemed to work
when it lay on the artboard's centre line, which Smart Guides follow).
With Snap to Point on, the ruler guides now pull drawn and dragged
points with Smart Guides on too, also while a point slides along a
construction guide or Shift's angle, as in Illustrator.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A run (vectorcraft-cli run, the MCP command_batch tool) had no way to use
an id an earlier step returned. A parameter string that is exactly
$N.path or $last.path now takes that value from step N's result
(0-based), e.g. {"id":"$1.id"}; $$ starts a literal $, and a
reference to nothing fails the step. Objects given to a command are now
used as given: an ids element or id that isn't an object id (or an
unresolved reference) fails instead of the command acting on the
selection. text.setRangeStyle styles the selected type object when no
id is given, as text.setStyle does.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Opening a file that fails (File › Open, Open Recent, the Home screen, a
drop, the Finder or the command line) only set the status bar's
message, which is easily missed: it looked as if nothing happened. A
dialog now says "Can't open “name”." with the reason, as well. An
agent's file.open {path} still just answers with the error.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Color books such as the Pantone books a user owns (.acb) couldn't be
opened. They are now read (never written), from public descriptions of
the format: their RGB, CMYK or Lab colors, named with the book's prefix
and suffix ("PANTONE 185 C"), as spot colors unless the book marks
them as process colors, leaving out the pages' unnamed padding. They
open from Window › Swatch Libraries › Other Library…, File › Open and
the user library folder like .ase files.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
While a group or layer was isolated, clicks, hovers and drags still
reached the art outside it, and that art drew as usual. Now only the
isolated container's contents hit: the art around it is locked and
clicks pass through it. On the canvas it draws at half opacity, above
the group as well as below, each run of it as one dimmed layer.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With type selected, the Properties panel's Paragraph section had only
Align Left, Center and Right. It now has the Paragraph panel's seven
alignments (the justified ones too), its Hyphenate checkbox and a "…"
button that opens the Paragraph panel, as Illustrator's does.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Align to Key Object and Align to Artboard worked only from the Align
panel's own buttons: the Control bar's and the Properties panel's align
buttons always aligned to the selection (one object to the artboard).
They are now one set of buttons that follow Align To (and the key
object), and the Properties panel's Align section gets the "…" button
that opens the Align panel for Distribute and Align To.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
In the gradient stop popover (and the Color panel), clicking a recent
colour replaced the whole gradient with that colour, while the sliders,
spectrum and Black and White chips recoloured the selected stop. The
recent colours now go through the Color panel's target like the chips.
The Swatches panel's recent colours still paint the fill or stroke, as
its swatches do.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Opened from a stop on the Gradient tool's annotator, the colour popover
appeared just below and right of the stop, over the very art whose
colour it changes. It now opens beside the selected art, on the first
side with room for it (right, left, below, above), and beside the stop
only when there is none.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With Rotate View, each ruler measured document x (or y) along a line
that crossed both axes: its ticks covered only a short stretch and the
numbers bunched up. Each ruler now measures along its own edge in the
canvas's coordinates turned with the view, so it is ticked over its
whole length at every angle, and reads x and y as before at 0°.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The dialog's W and H fields send decimal numbers (300.0) and the settings
wanted a whole u32, so the preview failed with "invalid type: floating
point". Pixel sizes now take any number and round it to whole pixels;
negative, huge and non-numeric sizes are still refused.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With the Artboard tool, the active artboard's name was drawn twice: by
the canvas, as for every artboard, and by the tool, in blue and a little
higher. The canvas now leaves that one to the tool, which draws it where
the canvas names the others.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Before deciding to use the layers of an Illustrator file, the import
drew them again for each text object made from the file's text
document, to see whether the page draws it. When the layers differ from
the page by more than the check allows even with every such object
gone (taking one out only changes what is drawn in its box), the
layers aren't used whatever is taken out: that weighing is now
skipped.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Gaussian Blur and Feather drew through a filter layer whose blur works on
a coarser grid tied to the canvas: the blurred art moved by up to about
a pixel, and its steps showed, as the view moved by parts of a pixel
(scrolling, zooming about the pointer). They now blur the content's own
pixels on the CPU, as the Photoshop-style effects already do: the same
look wherever the view is, cached while only the view moves.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Raw app.quit closed the window and answered null at once, so a client
couldn't tell that a save prompt was waiting. It now runs the menu's
Quit: {"pending": "saveChanges"} while a modified document is asked
about, as file.close and file.closeAll answer and the protocol
documentation says; otherwise null, and the window closes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The effect versions of Offset Path, Zig Zag and Roughen showed Joins and
Points as free text fields. They now pick Miter, Round or Bevel and
Smooth or Corner, as Object > Path > Offset Path does. A size's
Relative / Absolute (Roughen, Zig Zag, Tweak) is a pair of radio
buttons, and the effect dialogs' other on/off options are checkboxes
that show when they are off too (they were invisible unchecked).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Illustrator EPS and .ai type is made whole from the file's text
document, shown or hidden: point type, area type (a story in several
frames as threaded type that flows when the file opens) and type on a
path, with its fonts, size, leading, tracking, scaling, baseline shift,
fill and stroke colours (grey, RGB or CMYK), alignment, indents and
paragraph spacing. The page's drawing of that type, often in pieces, is
left out; where the text document can't say, type that shows still
comes from the page.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The output multiplied the glow's colour by its opacity a second time, so outside the shape (where
the glow sets the opacity) it darkened as it faded and showed as a grey rim over a light
background. The test now checks that the fading glow keeps the edge's colour.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The edge filter read `y * w + x` for x = w (the next row's first pixel)
and y = h at the raster's right and bottom edges; it now reads
transparency there, as the module documents. A test checks a solid square
glows alike on every side. Formatted with rustfmt, and the test uses
as_chunks for clippy 1.99.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The report kept a placed document's LINKED FILES and FONTS inside its parent's list. Each document
now gets its own sections, the packaged one first and unchanged (no Document: line), then each
placed document's, headed by its file. Drops a debug_assert and an unneeded mut, runs rustfmt, and
documents the nested packaging in docs/mcp.md and the ROADMAP.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
package.rs: the collector takes main's font lookup (fonts found by any of their names, in the
version the type names, a missing style shown in its closest one, files named by packaged_name).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add Fonts adds only files a folder search found.
- macOS declares .suit as the extension of a font suitcase
(com.apple.font-suitcase), and the font scan reads a suitcase
whatever its name. A search considered only suitcases without an
extension. It now also considers files whose extension is .suit, in
any letter case, and reads one only when it is a suitcase font.
- Add Fonts copies at most 256 MB a file. A search also read larger
font files, and a search that found one for a font could end before
it found a smaller copy. A search now skips font files over 256 MB.
Docs: docs/mcp.md.
A folder search reads at most 8 MB of each font file. The suitcase
reader reads a suitcase font's resource fork whole, up to 256 MB.
Before this change, the search applied its limit to each font only
after that read. One search thread could read 256 MB from a single
suitcase and hold a copy of its fonts as well. The search now reads a
suitcase font only when its resource fork is 8 MB or less. The font
scan still reads each suitcase font's resource fork whole, up to
256 MB.
Docs: docs/mcp.md.
When a document opens with fonts that aren't available, fonts used
only in its symbols included, VectorCraft lists them in a Missing
Fonts dialog after the missing linked file questions, one document at
a time, with Find Fonts and Close. Find Fonts opens Type › Find Font
on the first missing font of the layers' type, to replace it. After
Find Fonts or Close the dialog doesn't open again for that open; when
another dialog replaces it, it opens again once that dialog closes.
Search Fonts Folder (the Fonts folder File › Package writes next to
the document) and Find in Folder… search a folder and its subfolders
for the fonts' files, and Add Fonts copies the files the user chooses
into a Fonts folder next to the preferences. The desktop app and
vectorcraft-cli read that folder with the system's font folders. Type
› Find Font has a Find in Folder… button too when fonts the document
uses are missing. The web app shows no dialog; a status message says
how many fonts aren't available.
- text.missingFonts lists each missing family and style once,
whatever version the document's type names, and leaves out CSS
generic families such as sans-serif. text.findFontFiles searches a
folder on up to 8 threads and returns at once; text.findFontFiles {}
reports the search, and {stop: true} stops it. A search reads only
what the font scan reads of font files (their table directories and
name, fvar and OS/2 tables) and, on macOS, of suitcase fonts, and
lists a file for a font only when the file makes the font resolve
exactly. It does not enter app packages, the Program Files and
ProgramData folders, the system's folders at the root of a volume,
the Shared and Public folders in Users, a home folder's Library,
AppData, Applications, snap and dot folders, a Library folder's app
data folders or the folders the environment names for apps, and it
skips other hidden folders and does not follow links below the
picked folder. It ends after 60 s by default, after 10,000,000
entries listed, with more than 1,000,000 folders waiting, after
10,000 font files read or 1,000 kept, or once every font has a file;
Stop and Close end it too.
- text.addFontFiles copies only files the last search found. Of
those, it copies only regular .ttf, .otf, .ttc, .otc, .woff and
.woff2 files and suitcase fonts with their resource fork, at most
256 MB a file and 1 GB in all. It never replaces a file: a file with
the same contents is kept, and when another file has that name, the
copy gets a number (Name 2.otf). The fonts are then scanned again,
and type set in them redraws.
- ui.missingFontsDialog and ui.findFontsInFolder open the dialog for
agents; docs/control-protocol.md lists its fields.
- File › Package gives a font file whose name has no font extension
the extension that matches its data (.ttf, .otf or .ttc).
- vectorcraft-text adds set_app_font_dir, which system_font_dirs
reads, WantedFonts, which reads a font file's names as the font scan
does, is_font_file and is_suitcase. #762 split its face reader, which
now takes read budgets: file_face_names_within tries the suitcase
reader first, and reader_face_names_within applies the budgets to
each font. vectorcraft-format adds write_new_with.
Docs: docs/mcp.md, docs/control-protocol.md, ROADMAP.
The PDF part of an .ai stands in for the editable document, whose art crossing
the artboard edge isn't clipped, so it keeps opening whole and editable (#646).
Plain PDFs still get the clip to the crop box. path_count is back to counting
every path: no clipping paths appear in the .ai cases it counts.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A clip to the page box is dropped as redundant (by hayro, and by
push_clip_path), so art a file hides outside the page - a mock-up backdrop
thousands of points across, say - came in unclipped: it showed, and it sized
Fit to Artwork Bounds and CropTo::Bounding to metres. Viewers show a page
through its crop box, so each object reaching past it now keeps its own clip
to it, with a warning. Art inside the page is unchanged (no clip groups).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A letterhead saved by Illustrator 28 without PDF compatibility wouldn't
open: "its editing data can't be read (it ends inside a layer)". Its
layer starts with a /ForeignObject (non-native art: the content of a
placed PDF), whose /Data entry is the PDF as ASCII85 in comment lines.
ASCII85 includes `_`, so about one line in 85 starts with `%_`, which
the lexer reads as hidden tokens; a `(` in such a line opened a string
that swallowed the dictionary's end, the rest of the art and the
layer's LB.
The reader now skips to the data's `~>` after `/Data ,` in a
/ForeignObject, as it already did for a /Binary dictionary's ASCII85,
and leaves the non-native art out with a note (nothing draws its PDF
from the editing data yet).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ZwZjADUZP4VzvrFGpiZch
- Fit to Artwork Bounds fits the art exports draw: hidden objects and
layers, guides and template layers don't count, and the bounds stop at
a layer's clip.
- The comparison with the page catches an object one draws that the
other doesn't (pixels whose neighbours all differ, away from type), a
light colour against white, and, for an EPS whose page is its art's
box, art the layers print outside it.
- textAs: outlines opens a .ai whose type shows from its PDF part, which
has the outlines.
- document.open takes editingData: false to open an Illustrator EPS or
.ai as its page or PDF part only, for print pipelines.
Part of #637.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The styles were stored on the text and written to SVG's text-decoration,
but the type was drawn without the lines. vectorcraft_text::decorations
now gives each underlined or struck-through stretch of a run on a line
its bar, placed and sized from the font's own underline and strikeout
metrics (with fallbacks for fonts that have none). The canvas, Create
Outlines, PDF export (outlined and real text) and SVG's outlined text
draw them in the run's paint.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
hyphenation_exceptions_override_the_pattern failed when the round-trip
test set the process-wide list at the same moment: words missing from the
thread's override fell through to the shared store.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
swatch.library.copyToUser {library} copies a library loaded from
another folder into the user library folder of the desktop app. A
.vcswatches, .gpl or .ase file is copied as it is; the swatches of a
document and a library loaded from the data or dataBase64 parameter are
written as a .vcswatches file. The copy gets a name that no file in the
folder has, and when a file with the same extension and bytes is
already there, that file is used. The library is then listed as User
Defined only. Until the app quits, commands given its loaded id use the
copy, unless another library is loaded under that id. Without a user
library folder (the web and headless sessions) the command is disabled.
A file with the same extension and bytes as a User Defined library
opens as that User Defined library. The unchanged original of a copied
.ase file is one such file. Graphic style libraries open the same way.