A .ai file with placed files opened from its PDF part (no guides, no sublayers,
no hidden objects), because the editing-data reader stopped at them.
- Lexer: a placed file's preview section is one token (it was skipped).
- Reader: %AI5_BeginPlace ... ~ becomes a linked image with the file's path,
showing the preview the data keeps of it (premultiplied ARGB, capped at
MAX_PIXELS, its rows checked against the bytes there), in its place: the
matrix takes the file's pixels from the canvas, where they start at the point
of art space's origin. A placed file without a preview, a path or a matrix
still makes the file open from its PDF part.
- The open result lists one warning saying linked pictures show the
low-resolution preview until their files are found (rows in the catalogs).
- Engine: a link nothing is known of whose image shows a preview is read where
it is found as the document opens, into the image's bounds, and isn't
reported as modified.
- Tests: lexer, reader (hand-written data), engine open with the link missing
and found, fuzz tokens.
- Docs: file-format-parity, target-app-parity, gaps, ROADMAP.
Add a Korean catalog (crates/ui-egui/src/i18n/ko.tsv, 4,151 rows) covering
every menu string, every tl! literal and the status and error messages, and
register `ko` in i18n::LANGUAGES (plural_none; every ko-* locale resolves).
- tests: korean_reads_as_korean, ko locale tags, ko in KEEPS_MENU_NAMES and
COMPLETE_MESSAGES; is_cjk covers Hangul so the bundled-font glyph check
leaves Hangul to installed fonts, as it does CJK without craft-fonts.
- Hangul is drawn with an installed system font on the desktop; the web
build still needs a Korean UI face in craft-fonts.
- docs: localization-parity (Korean row, 12-language score 54% -> 63%,
60-100 h), ROADMAP, README, development.md, gaps.md G16,
target-app-parity.
Clean-room: written from the meaning of the English strings in ordinary
Korean vocabulary; no other product's Korean localisation was used.
AI-drafted; native-speaker review welcome.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Overnight doc conflicts were resolved by keeping both sides, which left two or three copies of
some milestone and parity rows (M1–M3, M5–M7, M14; six area rows; one type row). Each is now one
row with every note. The 2026-10-12 progress row takes the 30 PRs landed since and the Film
Grain row that #1282 added separately.
Add the Hungarian catalog (4,524 rows): every menu string, every `tl!`
literal, the contextual and `@id` rows, the plurals and the status and
error messages, written from the meaning of the English labels in
general Hungarian vector-illustration vocabulary. Conventions are in the
header of `hu.tsv`.
- Register `hu` ("Magyar") in `i18n::LANGUAGES` as a complete language
with `plural_none` (a count takes the singular); every `hu-*` locale
resolves to it.
- Tests: Hungarian joins the menu-label, menu-string, `tl!`-literal and
message coverage checks; `hungarian_reads_as_hungarian` pins the core
vocabulary, the plural, the `file.close` override and a nested
message; ő ű Ő Ű are checked in the bundled UI fonts.
- README, ROADMAP, docs/development.md and docs/localization-parity.md
list Hungarian.
Localize native/web file filters, diagnostic labels, numbered presets
and contributor tooltips with English fallback and Czech plural forms.
Fix gradient adjective agreement and disambiguate Japanese printer marks
in PDF/Print choices and summaries. Keep file extensions and names intact.
Add Czech catalog rows and regression coverage; update localization evidence.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add deterministic document-space grain, highlight controls and a live
dialog with preview, cancel, undo and appearance editing. Preserve
coverage, support existing native and raster export paths, translate
new labels and update parity documentation.
Validate the tonal curve, stationarity, subpixel strength, zoom filtering
and tile seams. Full cargo xtask ci passes all seven gates.
With Smart Guides on, a selection moved by the Selection tool only lined
its bounds up with the other art: grabbed by an anchor and dropped near
another object's anchor, it could stop a fraction of a point beside it
where an edge lined up instead. When the grabbed point comes within the
snapping tolerance of an anchor or a centre, it now lands on it, as
Smart Guides' anchor snapping does.
With anchor points selected by Direct Selection, the Align buttons moved
the whole path, so two points couldn't be lined up. As in Illustrator,
they now align the selected points: to the points' own bounds (Align To
Selection) or to the artboard. A path selected whole still aligns as an
object.
wgpu's default DX12 shader compiler loads whichever dxcompiler.dll the
DLL search path finds first; VectorCraft ships none, so it was another
program's, and one without its dxil.dll warns that the DXIL is unsigned.
wgpu takes the warning for a compile error, the device is lost before
the first frame, and the app falls back to OpenGL. FXC (d3dcompiler_47,
part of Windows) compiles everything the window needs, as LightCraft
does since its #484; WGPU_DX12_COMPILER still picks another.
Make Compound Path kept each path's direction under the non-zero fill
rule, so a shape drawn inside or across another, running the same way,
left the overlap filled instead of making a hole. The paths in front of
the backmost one now run against it, so where they overlap it they cut
holes, as users expect from a compound path.
Releases pinned craft-fonts at its first commit, with the Japanese fonts
only. The pin moves to its current main, as PdfCraft, LightCraft and
WordCraft have moved theirs: desktop builds embed Noto Sans Thai, Noto
Sans Arabic and Noto Sans CJK SC too (the web build still embeds only
the UI font and fetches Thai and Arabic beside the wasm). Packages
already copy every embedded font's licence.
The Thai loanword test no longer assumes the bundled fonts' widths: it
checks that no line ends inside โปรแกรม, whichever Thai font sets it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ctrl/Alt+arrows and double-click treated a run of Thai (Lao, Khmer,
Myanmar) without spaces as one word, and stopped at a word's tone and
vowel marks, which didn't count as part of a word. They now stop at the
word boundaries the line segmenter finds in those scripts (shared with
line breaking, so no more data ships), and combining marks count as
part of a word, also for combining accents in other scripts.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The web build has no installed fonts, so Thai there showed as empty
boxes. With a craft-fonts checkout that has Noto Sans Thai, its Thai
font joins the document font database after the Arabic ones (the
fallback for Thai where no Thai font is installed) and the web build
fetches it before the app starts, as it does Noto Sans Arabic.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The font menu's script filter offered Japanese and Latin only, so Thai
fonts had to be found by name among every installed family. It now has
Thai too: the families whose character map has Thai. Latin lists the
families with neither Japanese nor Thai.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
These scripts don't separate words with spaces, and lines only broke at
spaces, hyphens and CJK characters, so a Thai paragraph in area type ran
on to the next space (or was cut wherever it overflowed). Each
paragraph's glyphs now carry the word ends ICU4X's line segmenter finds
in text of those scripts (its dictionaries on the desktop, its far
smaller LSTM models on the web), and a line may break after them as
after a space. Other text keeps its own breaks, and clusters (a
consonant with its vowel and tone marks) still never split.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Type tool's Left and Right arrows and Delete moved one code point at
a time, so the caret could stop between a Thai consonant and its vowel
or tone marks (or inside an accented letter or emoji sequence), where
typing or deleting splits the cluster. They now step over extended
grapheme clusters. Backspace still takes back one character at a time,
as Thai typists expect for a mistyped tone mark.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Thai typed in a font without Thai glyphs (Source Sans 3, a Latin font)
took the first loaded face that had them, or the first installed file
that did, in path order: on one Windows machine a display face (Kanit)
rather than Leelawadee UI. Characters of Thai, Lao, Khmer and Myanmar
now try fonts made for their script first, installed ones loaded on
demand (Leelawadee UI, Tahoma, Thonburi, Sukhumvit Set, Noto Sans Thai,
the TLWG fonts for Thai), then the fallback as before. Latin beside
them keeps the font chosen.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An agent driving VectorCraft over the confined MCP server had no way to
see which files it was given, so it guessed names. `file.list {path}`
lists a folder's files (with their sizes) and folders by name, held to
the automation read root like every read; links are listed as links and
not followed. At most 5000 entries, with `truncated` saying when there
were more.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An agent's build over MCP left one undo step per batch step (about 280
for one job). `command_batch` takes `atomic: true` (and an optional
`label` naming the step) to make the whole batch one undo step. It runs
the batch in an undo group, opened and closed by the new commands
`edit.undoGroup.begin {label?}` and `edit.undoGroup.end {cancel?}`, so
every backend (headless or the connected app) supports it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The report module moves to cmd/rasterfx/report.rs (the crate's foo.rs +
foo/ layout instead of #[path]). An object is the document's when its id
is below the document's next id, so building the report no longer walks
the whole document (and its symbols and patterns) on every PDF, SVG,
print and clipboard export. The parity docs say what changed in the
status line and one evidence bullet instead of a separate paragraph.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
DXF already outlines type unless preserve: editability, so say so next to
the outlineText flag; reword the new-art sentence and point to paint.default.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
render_preview only rendered the first artboard, so an agent couldn't
look at pages 2 and on of a multi-artboard document without switching
to screenshot. It now takes an optional 0-based `artboard` (as
screenshot does) and refuses an index the document doesn't have.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A path of several subpaths (an SVG `d` with several `M`s, PDF paths, a
path drawn in one go over MCP) is a compound path in Illustrator, and
Object › Compound Path › Release splits it into separate paths. Here
Release only acted on compound path objects, so such a path couldn't be
broken apart. Release now gives each subpath a path of its own, with the
path's paint, in stacking order; the first keeps the path's id. One undo
step, as before.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Hide Others, Lock Others and Outline Others left the layer they keep as
it was, so Alt-clicking the eye of a hidden layer hid everything and
Alt-clicking a locked layer's lock left it locked. As Illustrator's
Layers panel does, the layer clicked now shows (unlocks, previews) while
the others hide (lock, outline), in the same undo step.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Anchor Point tool drags any segment of a selected blend's spine into
a curve, straight ones too, and Direct Selection reshapes a curved spine
segment as it does a path's (a straight one it leaves, as on paths). Both
run the new `object.blend.spine.reshapeSegment`, which bends the segment
with the same math as `path.reshapeSegment`, now shared as
`SubPath::bend_segment`.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Only the Mesh tool drew a gradient mesh's grid, so with the Selection
or Direct Selection tool a selected mesh showed no outline and no
points, and its points couldn't be seen to be clicked. The selection
highlight now draws a gradient mesh's lines and points, as it already
did for mesh envelopes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
winit 0.30 delivers no file drops on native Wayland. The new Linux Display
Server preference (Automatic / X11 (XWayland), shown on Linux only, read at
startup) has winit open the window on X11 when the session is Wayland,
DISPLAY is set and the X11 libraries winit loads are installed (ldconfig
check ported from PhotoCraft); otherwise the window opens on Wayland and
the log says why. README, development notes, parity docs, ROADMAP and the
complete catalogs updated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A marquee drawn wholly inside a filled shape counted as touching it, so
a marquee over a background (the usual way to pick small objects off it
in Outline view) selected the background too. As in Illustrator, the
marquee now needs the path itself: an anchor inside it or a segment
crossing its edges.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Object › Path › Offset Path (and `ui.menuDialog` for it) opens on the
offset, joins and miter limit of the last time OK was pressed, as in
Illustrator, instead of 10 pt and Miter every time. The values are kept
with the rest of the remembered dialog options.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Effect › Distort & Transform › Zig Zag… lays out its options the way
Illustrator's dialog does: Size and Ridges per segment each have a
slider beside their field, Relative / Absolute are radio buttons under
Size, and Points offers Smooth and Corner as radio buttons instead of a
dropdown. The label reads "Ridges per segment".
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A corner is now any anchor that isn't smooth where two sides meet at an
angle, straight or curved, as in Illustrator. The cut meets each side at
its setback measured along the curve, leaves both sides along their
tangents there, and each curved side is trimmed to what the cuts at its
ends leave of it. The largest radius is still the one taking the cut
halfway along the shorter side, measured along the curve. Corners
between straight sides draw exactly as before.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A property test of the importers (import_fuzz) crashed CI with
STATUS_STACK_BUFFER_OVERRUN: a shape with coordinates in the 1e20s from a
mutated file made vello_cpu either panic in flatten_simd on a rayon
worker (rayon then aborts the process, so the engine's panic guard never
sees it) or ask for a 132 GB allocation, which aborts too. A malformed
file could end the app and lose the user's work.
draw_shape now leaves a shape undrawn when its control points, through
the view, aren't finite or reach past 1e10 pixels, or a visible stroke
is that wide (MAX_DEVICE). A document's art stays within 4 million
points, 2.6e9 pixels at the closest zoom, and vello was checked safe
with 90,000 random shapes within 1e9 pixels and 30,000 within 1e12.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Artboard tool and the Artboards panel only ever had one artboard
selected, so Shift-clicking another didn't add it. As in Illustrator:
- Artboard tool: Shift-click adds an artboard to the selection (it
becomes active) or takes one out; a plain click on a selected one keeps
the selection, so a drag moves them all (Alt copies them all, the
copies becoming the selection), and Delete removes them all, one
artboard always staying. The other selected artboards show dashed
bounds; `selected` is a tool option.
- Artboards panel: with the Artboard tool, Shift- or Ctrl/Cmd-click on a
row adds or removes it, every selected row is highlighted, and Delete
Artboard removes them all.
- `artboard.move` and `artboard.delete` take `indices` besides `index`:
several artboards in one undo step, each with its art (an object moved
once where artboards overlap).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>