- 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>
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.
An ellipse kept pie angles in its model, but nothing drew or set them. Now
the Transform and Properties panels show Ellipse Properties with Pie Start
Angle, Pie End Angle and Invert Pie, as in Illustrator, and
object.setLiveShape takes {pieStart, pieEnd, invertPie}. The pie runs
counterclockwise on screen from the start angle (0 at 3 o'clock) to the
end angle and closes through the centre; 0 to 360 is the whole ellipse,
an end of 0 means 360, and Invert Pie swaps the angles to show the other
part. One undo step each; a bad angle is an error. The labels are
translated in every complete language. The on-canvas pie widget is still
to come.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A font library can hold two versions of one family and style (a new
Montserrat-Bold.ttf beside an old montserrat.ttf). The font database kept
only the first one loaded, so type set in the other couldn't be matched
when a PDF or .ai was opened: it came in as outlines. Now every version
loads (the first stays the one family and style resolve to), PDF import
tries the other versions when the glyphs differ, and type set in a version
the family and style alone wouldn't pick names it in CharStyle::font_version
(left out when None, so documents without it are unchanged). Layout,
shaping, the substituted-glyph highlight, Find Font, Package and Document
Info follow it; changing the font clears it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Japanese now translates the status-bar and error messages (`@msg`
templates) like Spanish, French, Italian, Russian and Ukrainian do:
556 rows at the end of ja.tsv, the 498 message literals the test scan
finds plus the 58 that the other catalogs also carry (web start-up,
relinking, export notes, PostScript read errors).
`ja` joins COMPLETE_MESSAGES, so complete_languages_translate_every_message
keeps it complete. The registry comment, docs/development.md and the
ROADMAP line now list Japanese with the other five. The messages
themselves stay English for agents and MCP.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
As in Illustrator, the Pen shows its continue cursor over an end of any
open path, selected or not, and a click there selects the path and draws
on from that end (reversing it from its first end). While drawing, it
shows a join cursor over an end of another open path, and a click joins
the two into one path, in one undo step, which finishes the path.
path.join takes {ids: [a, b], ends: ["first"|"last", "first"|"last"]}
to join the ends asked for (the Pen's join); without them it joins the
selected paths' nearest ends as before. Joining a path with itself, or
anything that isn't a path, is an error.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Object › Crop Image and the image's Crop Image buttons (Control bar,
Properties) now show a crop box on the selected image, as Illustrator
does, instead of cropping straight to the artboard (which did nothing for
an image inside its artboard). The box starts on the image's part over its
artboard; its handles and its inside drag it, always within the image, and
the image outside it is dimmed. The Control bar shows its X/Y/W/H with
Apply and Cancel; Enter applies and Escape cancels, both back to the
Selection tool. Apply runs object.cropImage {rect}, one undo step.
- tools: the Crop Image tool (cropimage.rs), with crop_box shared by the
tool and the Control bar.
- ui: ui.cropImage (enabled with an image selected), the Control bar's
crop fields and buttons, "Apply" translated (es, fr, it, ru, uk, ja,
zh-hans, zh-hant).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
craft-fonts main holds only Noto Sans Arabic so far (the other eleven are in
storytold/craft-fonts#11), and releases pin an older craft-fonts commit, so
say which builds list them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The font scan read only the macOS font folders and the Additional
Fonts Folder, so fonts that apps and font managers register with
CoreText from their own folders were missing from the font menus, and
exports set such type in the fallback font. CoreText's font manager
lists them with the installed fonts.
- `mac_fonts.rs` lists the files of the fonts the font manager has
available (`CTFontManagerCopyAvailableFontURLs`, through
objc2-core-text), keeping only file URLs as `open_documents.rs` does
(#433). The desktop app and `vectorcraft-cli` install it as they
install the DirectWrite lister on Windows, and the scan reads the
files outside the font folders in place.
- The scan leaves out faces with no outlines the font engine draws (no
glyf, CFF, CFF2 or VARC table), on every platform. CoreText lists
Apple's PingFang UI interface font (macOS 27), whose outlines are in
an hvgl table; if the scan cataloged it, PingFang SC would count as
installed, and Chinese characters in fallback text, Japanese kanji
included, would draw blank.
- Tests: the list holds the installed fonts by full path, a font
registered from another folder is listed while it is registered, and
a face without outlines the engine draws isn't cataloged.
The Save Swatch Library dialog lists Swatch Exchange (.ase) as a
format, and swatch.library.save takes format: "ase" or a path ending
in .ase. Each solid color keeps its model (RGB, CMYK, Lab or Gray) and
its type (spot, global or process), and color groups stay groups.
Gradients and patterns are left out, and a tint swatch is written as
the color it shows. Without a path or user: true, the command returns
the file as dataBase64.
A swatch exchange library opens under the name of its file. When Save
Swatch Library or Save Graphic Style Library saves to a file, the save
panel suggests the Name from the dialog as the file name, as a save to
User Defined does, and the web app downloads the file under that name.
A name made only of dots and spaces, such as "...", gives the file name
Library (Library.vcswatches) in place of a hidden file.
palette_io::write returns the file's bytes. A property test writes
generated libraries and reads them back, and an import fuzz test loads
mutated copies of a file the writer wrote.
With View › Snap to Grid on, a selection moved with the Selection, Group
Selection or Direct Selection tool lands on the grid: on each axis,
whichever of its two edges and its centre is nearest a gridline (every
subdivision, 9 pt by default) moves onto it. Snap to Grid takes over from
Smart Guides and Snap to Point while it is on, as it does for drawn points.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Libraries panel was a placeholder: it invited dragging art onto it,
but nothing happened. It now keeps local libraries (no account, no
cloud), as Illustrator's Libraries panel does:
- drag art off the canvas (or a swatch) onto the panel to add it, or use
+ to add the selection's graphic, fill or stroke colour, character
style or paragraph style;
- drag a graphic onto the canvas (or double-click it) to place a copy,
click a colour to paint the selection through the active Fill/Stroke
proxy, click a style to apply it to the selected type;
- the library picker and the panel menu create, rename and delete
libraries; each is a .vclibrary file in a Libraries folder next to the
preferences (session-only in the web app, headless sessions and runs
without preferences).
Engine: library.list/get/setCurrent/create/rename/delete/add/use/
removeItem. A graphic is stored as a native document with a thumbnail:
adding copies as Copy does and placing pastes as Paste does, resources
and swatch-name conflicts included. Using a style adds it to the
document and applies it in one undo step.
Clipboard::to_document gave its layer the id u64::MAX, which made a
saved copy overflow Document::fix_next_id when read back; the layer now
takes an id above the objects', and fix_next_id saturates.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Desktop builds made with CRAFT_FONTS_DIR now load craft-fonts' 12 Arabic families into the document font database. Noto Sans Arabic comes first and is the fallback for Arabic text. Cairo, Tajawal, Almarai, IBM Plex Sans Arabic, Noto Kufi Arabic, Amiri, Alexandria, Fustat, Reem Kufi, Aref Ruqaa and Gulzar can be picked by name from the font menus.
The web build doesn't embed these fonts because they would make the wasm too large. It fetches them from beside the wasm instead:
- crates/text/web-fonts.txt lists each face as startup or background.
- build.rs turns that list into vectorcraft_text::WEB_FONTS, with each face's URL (fonts/<sha16>/<file>) and SRI hash taken from the craft-fonts manifest.
- packaging/web/copy-fonts.sh, a Trunk post_build hook, copies the font files and their OFL licences there.
- apps/vectorcraft-web/src/fonts.rs fetches Noto Sans Arabic before the app starts, so Arabic text never shows as boxes. It loads the other faces in the background and logs `web font …` for any that fail.
Because fonts can now arrive after startup, the Type tool's layout cache also checks the font database's generation, so text lays out again when new fonts arrive.
_headers and .htaccess serve fonts/* as font/ttf and cache it as immutable. packaging/web/README.md and docs/development.md explain the fonts folder, and ROADMAP.md lists the Arabic typefaces under Type. Also adds Ahmed Moussa to contributors/people.toml.
Signed-off-by: Ahmed Moussa <moussa.ahmed95@gmail.com>
The PDF writer defaulted to Convert Text to Outlines, so every glyph of
every page became a path: a text-heavy PDF grew several times larger on
export (a 7-page document went from 27 KB to 226 KB) and its text could
no longer be selected or searched. Illustrator's PDF presets embed font
subsets and keep live text; that is now the default too
(advanced.outlineText: false). Outlining stays available as an option,
fonts that can't be embedded still become outlines with a warning, and
printer's marks (page information) are drawn as shapes as before.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`artboard.setProps {scaleArt: true}` maps the art fully inside a resized
artboard (as Move Artwork with Artboard gathers it) and its artboard guides
from the old rectangle onto the new one, each side by its own ratio, in one
undo step, and returns the ids scaled. Strokes, effects and corners follow
Scale Strokes & Effects and Scale Corners (`strokes`, `corners`), pattern tiles
Transform Pattern Tiles (`patterns`); locked and hidden art follows
`lockedAndHidden` (default: prefs moveLockedWithArtboard). The resolved choices
are journaled, so a replay scales the same objects the same way. A move that
keeps the size scales nothing.
The Artboard tool's `scaleArt` option (saved with `moveArt`) makes handle
drags proportional, as the public help describes, keeps them proportional at
the 1 pt minimum, and leaves the scaled art out of the Smart Guide targets.
Move and Scale Artwork with Artboard are check boxes in the Control bar and
Properties' Edit Artboards; the artboard size fields there and in the
Transform panel pass the option. Translated in the eight catalogs that have
Move Artwork with Artboard. docs/mcp.md and the ROADMAP updated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Designers coming from page layout apps expect Cmd+Shift+B to bold the
text they are editing. Type > Bold and Type > Italic switch the selected
type (or the Type tool's selection) to its family's own Bold or Italic
face, and back to the regular weight or upright face when it already is,
keeping the face's other words (a Narrow face stays Narrow). There is no
fake bold or slant: a family without the face is left as it is and the
status bar says so. While the Type tool edits text, Cmd+Shift+B and
Cmd+Shift+I apply them; elsewhere Cmd+Shift+B still hides the bounding
box. Both can be given other shortcuts in Edit > Keyboard Shortcuts.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Tabs panel's ruler was a fixed strip in the panel, at no relation to
the text on the canvas, so stops couldn't be placed by eye. Above Text
(Position Panel Above Text) floats the panel just above the selected
text, as wide as its ruler needs to put 0 on the text's left edge and
its marks at the canvas zoom: each stop sits over the column it sets.
Floating panel groups keep a width they are given.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Such a file's PDF part is a placeholder page, which was refused. When
the file carries editing data, it now opens from that alone: its
structure as a PDF-compatible file's, its point type made from the text
document, and type it can't make (area type, type on a path) left out
with a note that marks the import as lossy. Without editing data, or
with pages picked or layers off, the placeholder is refused as before;
damaged editing data says so.
The page-order note is no longer given when the page has no type.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The layers reader of the editing copy (operators translated into
PostScript for the interpreter, any file with RGB colours, gradients,
transparency or images falling back to its page) is replaced by a reader
of the whole structure (import/ai): layers and sublayers with their
options, groups, compound paths, clipping groups and layer clipping,
names, hidden and locked objects, RGB, CMYK, grey, named and spot
colours, gradients, transparency, fill rule, overprint, embedded images
with their alpha channel, guides and every artboard, and objects drawn
as their look when they have several fills or strokes, effects or a
brush. Containers: Zstandard, zlib or plain data in EPS and .ai.
The text placement, the comparison with the page and the overwrite guard
stay around it. The page's type takes its text object's place without a
group; the comparison is by lightness, on nothing, without layers that
don't print. Symbols, pattern fills, placed files and unknown operators
make the file come in as its page where they show, and are left out of
layers that don't.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With Line-end Punctuation Half Width, an opening bracket that starts a paragraph now drops the
half-em space before it, as one starting a wrapped line already does (#417): its face starts at
the first-line indent, JLREQ 3.1.5's Figure 71 ① (the principle JIS X 4051 adopts), as decided in
#633. Paragraph-start brackets in documents set with this mojikumi move half an em toward the line
start.
Two mojikumi tests used a bracket at a paragraph's start to test something else (consecutive
brackets, the Japanese–Latin space); they now set it inside the line.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Paragraph panel › Kinsoku Set (with the East Asian options) and `text.setFormat {kinsoku}`, as
decided in #633:
- Hard: today's set, so existing documents don't change; the default, and not saved.
- Soft: as Hard, except that 々, the prolonged sound mark ー (JLREQ cl-10) and small kana (cl-11)
may start a line: JLREQ's level 3 line-breaking rules (Appendix C.3). Half-width forms aren't in
those classes and stay off the line start.
- None: no kinsoku.
The setting reaches every break the composers consider (greedy, every-line and hyphenation
points). Reset Panel returns to Hard.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An Illustrator EPS is a flattened page plus, after %%EOF, an editing copy of
the document; a PDF-compatible .ai carries the same in its private data.
Importing only the page lost layer names, order, visibility, hidden layers
and hidden objects and hidden text.
- eps: read the editing copy (Zstandard %AI24_DataStream, older zlib
%AI9_DataStream) into layers, sublayers, groups, compound paths, clip
groups and hidden objects, run by the existing PostScript interpreter.
Falls back to the page, with a warning, when a shown layer uses an
operator that isn't read or the art differs from the page by over 5%.
- eps: read the text document (ate.rs) to place type on hidden layers and
objects; the page's type is matched to the file's text objects by
position (pieces of a line included) and kept with the nearest one when
none claims it. Area type and type on a path are left out with a note.
- pdf/engine: .ai files go through the same reader.
- engine/cli: a file whose import left things out isn't overwritten unless
asked (acknowledgeLoss, --replace-lossy).
- eps: font names re-encoded with a *<n> suffix resolve to their family.
- i18n: es/it/ru for the new import messages; ROADMAP updated.
Container and text-document formats were inferred from user-owned files; the
Adobe file format specification was not read.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Laser and cutter software skips HATCH entities, so shapes that were only
filled (type, traced art) reached it as nothing. Each filled area is now
written as its outlines (polylines and splines, in the fill's colour)
followed by the solid hatch; R12 keeps writing the outlines alone.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A PDF or PDF-compatible .ai whose ToUnicode map gives some glyphs U+FFFD (as
some files do for the digits of an embedded CID font) imported those glyphs as
type showing the replacement character, so every digit came in as "�".
U+FFFD now counts as no mapping. Such a glyph takes its character from the
embedded font where it can (Adobe's CID tables for CID-keyed CFF, as before,
then the font program's own cmap), and otherwise keeps its outline from the
embedded font, so it looks as the file draws it. The import warns which font
had characters the file doesn't name.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
New from Template... and Save as Template opened their dialog in
~/Documents/VectorCraft Templates. On desktops whose documents folder has
another name (Italian ~/Documenti) or where the folder was never made, the
dialog started in a folder that doesn't exist and showed an error.
- The default Templates folder is now in the user's documents folder: on Linux
and the BSDs the one XDG_DOCUMENTS_DIR names in user-dirs.dirs, elsewhere
~/Documents.
- The folder a dialog starts in is made when missing; where it can't be, the
dialog starts in the nearest folder above it that exists, else home.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The rotate cursor drew an arc with a large triangle under each end, both
pointing straight down and away from the arc, so it didn't read as an arrow.
Each end now has a slim arrowhead pointing on along the arc's tangent, with
the same halo as the other cursors.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>