The rulers were only painted. A drag from the top ruler now previews a
horizontal guide and adds it with guide.add where the button is released
on the canvas; the left ruler makes a vertical one. Released anywhere
else, nothing is added. Guides are shown when one is made this way.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The command palette caches its entries per language and plug-in set
(#243), but each entry also shows its shortcut: after editing shortcuts
the palette kept showing the old ones until the language changed. The
cache key now includes the shortcut editor's generation. From #242.
Co-authored-by: WildfootW <wildfootw@wildfoo.tw>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A line that is not a JSON object with a string `method` (an HTTP request
line, other non-JSON text, a JSON array, invalid UTF-8, a line over 4 MiB)
now gets one error reply and the connection is closed, so a browser's
cross-origin fetch can't smuggle a command in its body. Connections are
capped at 16. Same transport as LightCraft (storytold/lightcraft#129) and
FilmCraft (storytold/filmcraft#123).
The Type tool passed `y + 12` to `text.create` for a dragged frame, and
`text.create` puts the frame's top-left at (x, y), so every frame landed
12 pt below the marquee the user dragged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#226, #227 and #243 landed without their ROADMAP lines: Shipped so far now
says DXF Fit and Aligned text span their two points, Effect > Pathfinder
groups several loose objects first, and names are never translated; the
Last updated line counts the 2026-10-07 issue fixes. Scores unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
EPS files the reference app saves (its procsets in the prolog, a binary header with a TIFF
preview) now open as editable art instead of failing with "undefinedresource in Generic". When
their PostScript still can't be read, the palette preview they carry is placed with the usual
warning instead of the file being refused.
Root cause: five interpreter gaps and one preview format. The Generic and Category resource
categories didn't exist, so categories couldn't be made from Generic (now Category holds the
standard categories, defineresource in Category makes new ones, undefineresource is added);
clipsave/cliprestore were unknown (now a clip stack in the graphics state); systemdict's
languagelevel was the operator, not the integer 3; getinterval copied arrays and strings
instead of sharing their storage, so astore into a subarray was lost (arrays and strings are
now views into shared storage, and readstring/readline return the part they fill); and
resourceforall was unknown (now enumerates matching names with * ? \ templates). The preview
is an 8-bit palette TIFF with an alpha sample, which the image crate can't decode: a small
bounds-checked reader handles that layout (either byte order, any strips).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A press only started a selection inside the text being edited; on other
type it waited for the release, which placed the caret at the press and
ignored the drag, so the first drag across a word never selected it.
A press on type now starts editing it there (the same code a click used
on release), so the drag selects at once; a plain click still just
places the caret.
Fixes#245.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
release.yml's comments sent readers to docs/releasing.md, which never
existed: the workflow was ported from a sibling app without its document.
docs/releasing.md now covers how a release is cut (version bump with
cargo xtask version, the release branch, the draft, publishing, test runs
with a version override), what each job builds and how (macOS universal
signing and notarization, Windows x64/x86/arm64 with the PE checks and the
two signing options, Linux packages and the glibc 2.35 floor behind the
ubuntu-22.04 runners, FreeBSD in a VM, the web build, craft-fonts), the
draft release job and the signing secrets. Every detail is checked against
this repository's workflow and packaging scripts. The README links it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
panels::label_or_name and dialogs::shown_names applied the same rule; it
now lives once as i18n::label_or_name (explicit language, testable) and
both delegate to it. zh-hant gains the two normal text style names the
Character and Paragraph Styles panels translate.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Panels passed names to the translating widgets, so a name that happened to
be a catalog key was translated (a font style "Regular", a workspace called
"Layers"). Font styles, pattern names, recent URLs, ICC profiles, saved
width profiles, user and loaded libraries, plug-in effects and their
parameters, Document Info's artboard/style/font/image rows, text-object
contents in Layers, user text styles in brackets, the Artboard tool's
canvas label and the app-bar workspace switcher now show names verbatim;
built-in entries (Working CMYK, (closest), built-in libraries and effects,
[Normal ... Style]) still translate. Formatted tips around a name are
translated as templates only (panels::label_or_name, library_name).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Lists and headings that mix our labels with names no longer send the
names through the catalog, so a preset, printer or plug-in called
"Regular" or "Black" keeps its name in every language.
- dialogs::shown_names / mixed_dropdown: translate only a list's built-in
entries and show the rest with widgets::dropdown_names (same indices).
- Artboard lists (Save for Office, Save for Web, save options) and
plug-in choices: dropdown_names.
- Mixed lists translate only their built-in entries: Recolor's Limit to
Library, Save for Web, Print, Save PDF and Export for Screens presets,
printers (Default Printer, PDF File), colour profiles and flattener
presets (profile_pick, flatten::preset_dropdown), perspective presets,
New Document's preset cards and Size, and the shortcut set.
- Plug-in dialogs and plug-in effects are headed by the plug-in's name as
it is; plug-in parameter labels are not translated.
- The confirm dialog shows its message and detail as given, and the
shared frame no longer translates headings again: each heading is
translated by its spec. File > Revert translates its template before
filling in the document's name.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Follow-ups from the review of #205.
- Names that are user, file or system data are shown as they are: menu
items for recent files, saved views, recent fonts and Type > Font,
user swatch and graphic style libraries, saved perspective presets,
custom workspaces (and Reset <name>) and plug-ins no longer go through
the catalog (menus::shows_a_name). widgets::dropdown_names,
menu_item_name and dim_name are the non-translating forms of the shared
widgets, for the panels and dialogs that list such names.
- The command palette builds its entries (shown label, search text) once
per language and plug-in set instead of translating ~700 labels every
frame while a query is typed.
- The locale probe (reg.exe / defaults) runs on a background thread at
startup instead of on the first frame.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Strings in code stay English and are the lookup keys; `crates/ui-egui/src/i18n`
maps them to display text at render time from one `*.tsv` catalog per language
(`LANGUAGES` registry, `tl!`/`t`/`tr`/`tr_ctx`/`tr_id`/`tn`/`fmt`). Command ids,
menu paths, `ui.menu.list`, the control channel, the CLI, MCP, status messages
and undo labels never see translated text, so agents, scripts and the existing
tests are unaffected (under `cargo test` the UI is always English).
Wired: in-window menus and the macOS native menu (rebuilt on a language change),
dynamic labels (Undo X, Reset X, Last Effect: X as templates), the command
palette (matches English and translated text), dock tabs, panel tooltips, the
toolbar (category names now cut by characters, not bytes), the dialog frame, the
shared widgets, the Preferences dialog, the shortcut editor, the hint and status
bars, the Home screen, and the literals of every panel and dialog.
Preference `interfaceLanguage` (User Interface › Language): `auto` or a code.
`auto` follows `VECTORCRAFT_LOCALE`, `LC_ALL`/`LC_MESSAGES`/`LANG`/`LANGUAGE`,
the macOS preferred languages and, on Windows (which sets no `LANG`), the user
locale from `HKCU\Control Panel\International`. `zh-TW`/`zh-HK`/`zh-MO`/
`zh-Hant-*` resolve to `zh-hant`; Simplified locales stay English until a
`zh-hans` catalog exists.
`zh-hant.tsv` (~2,850 rows) is clean-room, in the vocabulary used in Taiwan;
terms shared with PhotoCraft reuse its wording, vector terms use everyday
vector-drawing vocabulary. Tests: catalog well-formedness (placeholders,
ellipses, command ids, no Simplified characters), locale resolution, and two
coverage tests that fail when a menu string, panel/tool/preference label,
dialog button, hint-bar fragment or `tl!` literal has no row in a language
marked `complete_menus`. `VECTORCRAFT_I18N_DUMP=file cargo test -p
vectorcraft-ui-egui dump_source_strings` lists the strings for translators.
Also: two clippy findings under rustc 1.97 fixed in passing.
Integrated with main (squashed onto it, 42 commits on): the Czech interface
(#213) moves from its Rust table to `i18n/cs.tsv` on the registry (all 556
rows, Czech plural rule, its menu-coverage and glyph tests kept); Find Font's
resolution notes and the canvas context menu's labels are translated and
covered by the catalog tests (`menus::CONTEXT_LABELS`); the glyph test checks
CJK text only when the craft-fonts build input is embedded (#220 moved the
Japanese fonts out of this repository); a language saved by an older version
carries over to `interfaceLanguage`; Windows' locale lookup runs reg.exe by its
full path.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The server answered tools/* and two fixed resources and nothing else, and
resources/templates/list returned an empty array. This adds the rest of the surface a
client can actually use, against 2025-06-18.
- prompts/list and prompts/get: five workflows (poster, icon-set, recolor,
trace-and-style, export-set) with templated arguments. A missing required argument
is -32602 and names itself.
- resources/templates/list, and resources/read for the templates: object/{id},
command/{id}, effect/{id}, swatch/{name}. Reading one thing at a time instead of
vectorcraft://document/json, which on a real document is thousands of lines an agent
pays for again on every change.
- completion/complete for prompt arguments and template variables, ranked prefix
first, capped at 100 with total and hasMore. The values are read live, so a suggested
format, effect id, command id, trace preset, swatch or object id is one the engine
has.
- logging/setLevel and notifications/message. Nothing installed a log::Log before, so
the engine's log::debug! calls went nowhere; this is the sink, silent until asked.
Installing it is vectorcraft-cli's job rather than the library's, so an embedder
that already has a logger keeps it.
docs/mcp.md gains a Protocol section with the capability table and a Not implemented
section: subscriptions, progress, cancellation, sampling, elicitation and Streamable
HTTP all need the transport to interleave reads, which this one does not — handle_line
answers a line with a reply, so it neither reads an incoming cancellation nor can write
progress before the reply it belongs to.
62 tests (50 unit, 12 property/fuzz). protocol_props.rs gained five: prompts survive
junk arguments, completion/complete never panics and always answers at most 100
string values with a consistent hasMore, every template reads or fails cleanly, and
prompts/completions/templates are swept with junk params while asserting the document
comes back byte-identical.
ROADMAP: one bullet under Automation in Shipped so far and the changelog line. The
parity table and the gap list are untouched — MCP is agent automation, so feature
parity does not move.
list_says_how_each_font_resolved expected Source Sans 3 Black to be a
substitute, which holds only while the bundled family is the only Source
Sans 3: on a machine with the full family installed (it ships with many
font packs), Black resolves exactly and the test failed. It now asks for
a style no Source Sans 3 has, so the substitute path is tested anywhere.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The OK/Cancel row was laid out right to left at the full available
width, and a dialog without a maximum width may use the whole window:
the row, and the window with it, spanned the window (Clean Up, Blend
Options, every generic parameter dialog). The row now spans the fields
above it, at least the dialog's minimum width, so a dialog is sized to
its content.
Fixes#238.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The icon panel flyout was placed by its left edge, 262 points left of
the icon column, at a width of 256: a panel whose content is wider
(Separations Preview, Align, Transform, Stroke, Attributes, Gradient)
grew to the right, over the panel icons. It is now pinned by its right
edge, 6 points left of the column, so a wider panel grows towards the
canvas; panels of the usual width sit where they did.
Fixes#236.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
egui counts a press a few pixels outside the canvas as hovering it (its
interaction radius), but the canvas only takes pointer positions inside
its rect, so such a press fell back to the canvas's centre: a click
just below the document tabs or beside the panels selected, typed or
drew in the middle of the view. Presses, and middle-button pans, now
start only on the canvas itself.
Fixes#232.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Conflicts with #214 (fonts by PostScript name): this branch's name index (FaceKeys,
aliases) stays, and #214's `by_postscript_name` (used by PDF import) reads a PostScript
map filled from it, keyed by the same normalized names.
Removed: scanning ~/Library/Application Support/Adobe (CoreSync/plugins/livetype and
Fonts), and the preference that switched it (Type › Include Fonts of Other Design Apps'
Folders). Fonts activated through another vendor's subscription are licensed for use
through that vendor's own sync; reading their files from VectorCraft would go around that
licence, and the project's clean-room rules keep VectorCraft out of other vendors' files.
Fonts the user has installed in the system or user font folders are still found by every
name, as before.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
macOS keeps faces for its own interface under family names that start with
"." (".SF NS", ".LastResort", ".Aqua Kana"…); Mac apps don't list them. Since
the font menus list every installed family (#36), they showed 74 of them on a
stock macOS, at the top of every list.
- FontDb::menu_family_list: family_list without names that start with ".",
cached like it. Only a leading dot hides a family.
- Type › Font, the family dropdowns (Character, Properties), text.fontList and
Refresh Font List's count use it.
- Lookups by name still see every family: documents and fallbacks that name
a hidden family still find it (face, has_family, find_family, families,
text.fontList {family}, Fonts in Document's missing check).
- Test: tests_sysfonts::font_lists_leave_out_hidden_system_families_which_still_resolve
(a temporary font folder); the engine and UI font-list tests compare with
the listed families.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Right-clicking the canvas now opens a context menu, as the reference app
does. The object under the pointer is selected first unless it already is.
The menu then lists what applies to the selection: Undo and Redo, Cut, Copy,
Paste, Isolate Selected Group or Exit Isolation Mode, Group and Ungroup,
Join and Average, Make or Release Clipping Mask and Compound Path, Make
Guides, the Transform, Arrange and Select submenus, and Export Selection.
On empty canvas it lists Paste, the zoom commands, the ruler, grid and guide
toggles and Select All. Commands that can't run now are left out (Undo and
Redo stay, greyed out), and a press on the canvas only closes the menu. Agents list the same menu with the
`ui.contextMenu.list` control method.
Root cause: the canvas ignored the secondary button except in the toolbar's
tool flyouts; there was no context menu at all. The menu reuses the menu
bar's items, rendering and dispatch; Object > Transform and Arrange are now
shared lists.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>