Commit Graph
3786 Commits
Author SHA1 Message Date
vangel76andClaude Opus 5.5 b55d277b49 Fonts: a variable font's default face is named and weighed by its default instance (#2521)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-18 01:09:53 +07:00
Guillem Hermida 2a5dfa6a94 Fix #1876: Artboard Options has X and Y with a reference point
Artboard Options showed Name, Width and Height only: the generic form
hides x and y, which in the shape dialogs are the click position. The
artboard's position could be dragged but not typed.

The dialog now draws its own rows after the form's, in the same grid:
the reference point locator the Transform panel, the Control bar and
Properties share, then X and Y. They show where the reference point
lies, counted from the ruler origin (#1212), as the Transform panel and
the Control bar show an artboard's position. A typed X or Y moves the
artboard so that its reference point lands there, and a new Width or
Height keeps the reference point in place. The fields still hold the
top-left corner in document points, so OK runs artboard.setProps as
before, in one undo step. The shape dialogs keep their x and y hidden.

form::grid_then lets a dialog add rows to the generic grid.
2026-10-18 01:09:52 +07:00
VictorandClaude Opus 5.5 6190525482 G4: Paragraph panel menu › Roman Hanging Punctuation
The Paragraph panel menu's Roman Hanging Punctuation was a disabled stub.

It is now a per-paragraph attribute: in a left-to-right paragraph of point
or area type with it on, the punctuation Optical Margin Alignment hangs
(quotation marks, hyphens, full stops and commas wholly; asterisks,
tildes, ellipses, en and em dashes, colons and semicolons by half) hangs
outside the margin when it starts or ends a line, on the same sides
(left-aligned lines at their left, right-aligned at their right, centered
and justified at both); letters don't hang. With Optical Margin Alignment
on as well, letters hang too. East Asian punctuation keeps hanging only
through burasagari. The layout shares Optical Margin Alignment's hanging
code, given the share of each glyph that hangs.

text.setFormat takes romanHangingPunctuation; it is off by default, saved
only when on, carried by paragraph styles (New and Redefine capture it)
and turned off by Reset Panel. The panel menu item is a checkbox enabled
with type selected.

Docs: docs/mcp.md, docs/type-parity.md, docs/gaps.md.

Closes #2756.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 01:09:34 +07:00
BFlat f7de3d6a01 Merge pull request #2724 from storytold/pr/batch-1017c
i18n and docs: Image Trace warnings in every complete language; ROADMAP for the evening's landings
2026-10-17 20:03:49 +07:00
bflatastic daaeb45565 Docs: the ROADMAP's 2026-10-17 row includes the evening's landings 2026-10-17 20:03:16 +07:00
bflatastic af555713d5 i18n: the Image Trace large-image warnings in every message-complete language (#2700) 2026-10-17 20:03:16 +07:00
BFlat c1c677bc76 Merge pull request #2409 from dotCooCoo/feat/live-rasterize-effect
Effects: Effect › Rasterize draws an object as pixels while its paths stay editable
2026-10-17 20:02:59 +07:00
BFlat a86cb76d52 Merge pull request #2696 from Silvertree2010/fix/2674-pdf-import-lines-with-line-width
Import PDF 0 w strokes as hairlines instead of dropping them
2026-10-17 20:02:28 +07:00
BFlat 2efd084b97 Merge pull request #2697 from dotCooCoo/feat/task-bar-direct-selection
Contextual Task Bar: direct-selected anchors offer Connect, Corner and Smooth
2026-10-17 20:02:17 +07:00
BFlat 665373b699 Merge pull request #2709 from dotCooCoo/fix/reshape-segment-delta-cap
Paths: Reshape Segment, Convert Anchor Point and the Pencil refuse values of 1e9 pt or more
2026-10-17 20:02:02 +07:00
BFlat 4bf8b3314a Merge pull request #2710 from dotCooCoo/feat/variable-font-axes
Character: variable fonts get a slider for each axis
2026-10-17 20:01:48 +07:00
BFlat 0bb793c079 Merge pull request #2702 from andeecollard/fix/trace-auto-color-rare-colours
Image Trace: Auto Color keeps rare but distinct colours
2026-10-17 20:01:33 +07:00
BFlat 68343ab66a Merge pull request #2700 from andeecollard/fix/trace-large-images-warn
Image Trace: large images trace with a warning; anchor limit 8,000,000
2026-10-17 20:01:18 +07:00
BFlat 4e620ced97 Merge pull request #2701 from andeecollard/fix/raster-new-no-panic
Image Trace: Raster::new returns an error for a buffer of the wrong length
2026-10-17 20:01:04 +07:00
BFlat 15f55f5569 Merge pull request #2705 from andeecollard/trace/centreline-graph
Create Strokes: skeleton graph with junction merging
2026-10-17 20:00:49 +07:00
NetterSilverandClaude Haiku 5.5 fe3e8f65a5 Import PDF 0 w strokes as hairlines instead of dropping them
Fixes #2674

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 19:38:50 +07:00
dotCooCoo 5ad04faff3 Contextual Task Bar: direct-selected anchors offer Connect, Corner and Smooth
With anchor points selected with Direct Selection, the Contextual Task
Bar's anchor items were Remove Anchor Points and Cut Path. The
reference app's bar also offers to connect the selected end points and
to convert the selected anchors to corner or smooth.

The bar now offers Remove Anchor Points, Connect, Cut Path, Corner and
Smooth. Connect runs Join (path.join), and Corner and Smooth run
path.convertAnchors with `to` set to corner or smooth. These are the
commands of the Control bar's anchor buttons. "Connect" has a row in
every catalog; "Corner" and "Smooth" use the existing rows.

The reference app's Smooth item, which adjusts a path's curvature, is not
offered, because VectorCraft has no Object > Path > Smooth. Simplify,
which the reference app's bar also offers here, is still offered only
while no anchors are selected.

Docs: docs/target-app-parity.md.
2026-10-17 19:38:48 +07:00
dotCooCoo 80b9753866 Paths: Reshape Segment, Convert Anchor Point and the Pencil refuse values of 1e9 pt or more
path.reshapeSegment refused only a delta that was not finite. It moves
a segment's two handles by the delta divided by 3t(1-t), which is
0.1425 at t 0.05 or 0.95, so a finite delta above about 2.5e307 wrote
infinite handles into the path. object.blend.spine.reshapeSegment
refuses a delta of 1e9 pt or longer.

path.reshapeSegment now refuses a delta of 1e9 pt or longer, with its
"invalid delta" error. Two other path commands took a point with no
bound. path.convertAnchor with x, y at 1e308 put the two handles 2e308
apart, so the path's control box was infinitely wide, and path.freehand
through such points with keepSelected off fitted a path whose bounds
reached infinity. Both now refuse a point whose x or y is 1e9 pt or
more in size, with "x and y must be finite", the error
object.blend.spine.moveAnchor gives for the same bound.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-17 19:38:47 +07:00
dotCooCoo 4712fb2c2f Character: variable fonts get a slider for each axis
VectorCraft listed a variable font's named instances as styles, but
type could not be set between or past them. The reference app's
Character panel has a Variable Font control that adjusts a variable
font's axes, such as Weight, Width and Slant.

Type now keeps Variable Font settings by axis tag
(CharStyle::font_axes, saved as fontAxes only when set). text.setFormat
and text.setRangeStyle take fontAxes: each value is clamped to its
axis's range, a tag the font has no axis for is left out, and null
goes back to the style's own setting. Another font or style clears
them, including one from a character style that does not set them. A
character style captured from type sets them, with {} for none.
text.fontList {family, style} lists a font's axes.

Layout, outlines, the substituted-glyph highlight and PDF export use
the font instanced at the settings, and neighboring runs at different
settings are shaped apart, as runs in different fonts are. SVG export
writes them as font-variation-settings, the wght setting as the weight
and the wdth setting as font-stretch, and embeds the font instanced
there; SVG import reads font-variation-settings back. Legacy .ai export
warns that the settings are left out.

The Character panel shows a Variable Font button for a variable font.
It opens a slider and a field for each axis the font does not hide,
labeled with the font's name for the axis, and screen readers get each
slider under that name. A drag is one undo step. Reset Panel leaves
the settings, as it leaves the font and style.

Missing Glyph Protection now keeps the settings and the font version
on the characters that keep their font; before, it kept only the
family and style. A character style applied or redefined with another
font now clears the old font's version, as text.setStyle does, unless
the style sets one. SVG export with embedded fonts warns when faces of
one weight, style and width share characters, which browsers then draw
in one of the faces.

Docs: docs/mcp.md, docs/target-app-parity.md, docs/type-parity.md.
2026-10-17 19:38:46 +07:00
andeecollardandClaude Opus 5.5 1e06c82800 Image Trace: Auto Color keeps rare but distinct colours
The Automatic palette counts flat art's colours by area (a colour needs
about 1% of the picture, 0.5% at Colors 100) and fits that count with
median cut and area-weighted k-means. A stem, a highlight, or a near
white beside a pale background (within 24 levels, so in one box) was
averaged into a large neighbour; mixed-colour merging and Noise could
then remove what was left.

On the flat route only, after the count is fitted, rare_colours finds
the colours too rare or too close for it and keeps those that are
distinct (at least 2.5 in Oklab x 100 from every palette colour and from
the main colour each stands for), flat (mostly one histogram bin) and
drawn (a 4-connected region of their own unblended pixels of at least 8
pixels, or three of at least 4); a colour lying between two others, as
anti-aliasing mixes them, must also have an inside. At most six, largest
region first. They stay fixed while the other colours are refitted
around them; merge_mixed leaves them alone; denoise_keeping keeps their
regions of 4 pixels or more whatever Noise is (smaller specks still go).
Full Tone, Limited and Automatic's continuous-tone route are unchanged,
and denoise without kept labels is as before.

Methods cited in the code: median cut (Heckbert 1982), k-means (Lloyd
1982), Oklab (Ottosson 2020), salient-colour preservation (Fukuda et al.
2019, doi:10.1117/12.2521607). The rule and its numbers are VectorCraft's
own; Adobe does not document how its palettes are chosen.

Tests (code-drawn): a rare stem or patch over 2-8 flat colours, hard
and anti-aliased at 1x and 2x; near-white highlights on #FFF4E0 kept and
still paths at Noise 16; a 3 px #909090 stem on #808080; scattered
single pixels of the same areas add no colour; denoise_keeping at Noise
0-32.

Measured on 66 synthetic flat logos (22 designs x hard 1x, anti-aliased
1x and 2x; local inputs): every key colour and no spurious one in 66
(was 39); missing key colours 0 (was 43), spurious 0 (was 2), merged
pairs 0 (was 46); rendered dE00 0.348 -> 0.138. Four public-domain scan
crops take the continuous-tone route and are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018tBcdwNhptqtmX32JCGFzB
2026-10-17 19:38:43 +07:00
andeecollardandClaude Opus 5.5 17a602d1dc Image Trace: large images trace with a warning; anchor limit 8,000,000
The public documentation says Image Trace warns about images larger
than 1500 pixels on a side but traces them, only more slowly. VectorCraft
traced them silently, and refused any trace of more than 2,000,000
anchors, which a 4000 x 3000 photo at High Fidelity Photo nearly reaches
(1.9 million on a code-drawn photo) and a noisier one passes.

- imageTrace.make and makeAndExpand return `warnings`: one for an image
  over 1500 px on a side (traced, but more slowly; a lower-fidelity
  preset or a smaller copy is quicker), one for an image over 64 MP
  that was traced from a scaled-down copy. The app shows the first in
  the status bar.
- MAX_TRACE_ANCHORS is 8,000,000 natively (2,000,000 on wasm, where a
  page has at most 4 GB). Measured through imageTrace.make on
  code-drawn photos: about 90 bytes an anchor kept in the document;
  7.9 million anchors kept 685 MB with an 876 MB peak (4000 x 3000,
  Full Tone at Colors 100, Paths 100, Noise 1, 37 s).
- The refusal keeps its translated advice: raise Noise, lower Paths or
  Colors, or pick a lower-fidelity preset.

Tests: a_large_image_traces_with_a_warning (1600 x 40 and 1500 x 8
code-drawn images, make and make-and-expand),
trace_warnings_name_a_large_or_scaled_down_image, a compile-time check
of the limit's range, and a UI test that the status bar shows the note.

Source:
https://helpx.adobe.com/illustrator/using/image-trace-results-optimization.html

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018tBcdwNhptqtmX32JCGFzB
2026-10-17 19:38:18 +07:00
andeecollardandClaude Opus 5.5 a2e2eba2e2 Image Trace: Raster::new returns an error for a buffer of the wrong length
Raster::new checked its RGBA length with assert_eq!, so bytes of the
wrong length (from a file, a plug-in or a control message) would abort
instead of reporting an error. It now returns Result<Raster, TraceError>
and gives TraceError::Decode naming the byte count and the size (the
existing variant, whose text is already translated, instead of a new
message every language would need). The size product is checked for
overflow.

Raster::pixel indexed the bytes directly; it now gives transparent
black outside the raster, or past the end of a raster whose public
fields were set to a size its bytes don't have (which mosaic reads).

The public signature changes: every caller in the workspace was a test
(trace unit tests, Flat Logo tests and the quality harness), updated to
unwrap. No shipped code built a Raster with new; decode, decode_to_fit
and from_fn always make the right length, and trace_within already
refuses a raster whose fields disagree.

Test (code-drawn): a_raster_of_the_wrong_length_is_an_error_not_a_crash
(short, long, empty, zero-width and overflowing sizes; pixel, trace and
mosaic on a raster whose fields disagree).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018tBcdwNhptqtmX32JCGFzB
2026-10-17 19:38:06 +07:00
0594ffe30f M12: build stroke skeleton graphs with junction merging
Place junction clusters at their deepest pixel and prune terminal branches
by significance beyond their maximal discs. Merge overlapping junctions
and split crossings with continuing outer arms, then join degree-two runs.
Bound nodes, branches and simplification work, using checked data access.

Keep whole-blob selection, ink refinement, cap detection and fitting rules.
Test junction degrees, crossings, 24-angle lines, pruning, graph caps and
random-blob determinism. Record improved junction degrees and remaining
spur and extra-junction limitations in the centre-lines measurements.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: OpenAI <noreply@openai.com>
2026-10-17 19:37:31 +07:00
abb7c1351b M12: use exact crop distances and Guo–Hall stroke thinning
Compute exact squared Euclidean distances per blob with separable parabola
lower envelopes. Thin with bounded Guo–Hall active sets and retain diagonal
ends during staircase cleanup. Keep the whole-blob width rule and existing
graph, ink, cap and fitting rules, with checked access in the moved module.

Verify EDT against brute force, active sets against plain rounds, and both
diagonal slopes for length and connectivity. Record the centre-lines rerun
and its remaining limitations without changing feature scores.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: OpenAI <noreply@openai.com>
2026-10-17 19:37:28 +07:00
c9f0ed14f0 M12: add centre-line scenes and baseline quality measurements
Measure Create Strokes on exact code-drawn scenes in aa and hard variants,
including centre/width error, topology, ends, spurs and painted coverage.
Keep the existing allocator report in one ignored test and document the
current baseline without changing tracing behaviour or dependencies.

Co-Authored-By: Codex <noreply@openai.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 19:37:25 +07:00
BFlat 8c10185ef9 Merge pull request #2714 from storytold/fix/2603-library-panels
Fix #2603: a panel per swatch library, with Persistent
2026-10-17 19:25:40 +07:00
BFlat b9ff56e403 Merge pull request #2713 from storytold/fix/2572-outport-threading
Part of #2572: clicking an area type's out port threads its text into a path or a new frame
2026-10-17 19:25:05 +07:00
bflatastic f38f6fafc3 Fix #2603: a panel per swatch library, with Persistent
Each swatch or graphic style library now opens in a panel of its own,
`library:<kind>:<library id>`, in the shared docking system: several can be open
at once, and they float, group as tabs, dock and close like any panel.
Opening a library that is open brings its panel forward; Previous / Next
Library show the neighbouring library in the same panel.

The library panel menu gains Persistent. The panels' view, Show Find Field
and Persistent are kept in the UI preferences (`library_panels`); at startup
the persistent panels reopen where the saved layout had them, a library
loaded from a file read again from its path (a missing file is skipped with
a status-bar note). `ui.libraryPanel {panel, library?, view?, showFind?,
persistent?}` reaches all of it; docs/mcp.md documents the panels.
2026-10-17 19:13:49 +07:00
bflatastic 88567ee46c Part of #2572: clicking an area type's out port threads its text into a path or a new frame 2026-10-17 19:13:22 +07:00
dotCooCoo 04b0be2c9f Merge main into feat/live-rasterize-effect 2026-10-17 04:09:12 -07:00
BFlat f5511df65f Merge pull request #2695 from storytold/fix/2541-plugins-persist
Fix #2541: installed plug-ins stay installed after a restart
2026-10-17 18:04:04 +07:00
bflatastic 2879c206a8 Fix #2541: installed plug-ins stay installed after a restart
Install Plug-in (plugin.install) now keeps the plug-in's module in a
Plug-ins folder next to the preferences, as Illustrator keeps plug-ins in
its Plug-ins folder, and the desktop app and vectorcraft-cli install the
ones there at startup (a module that doesn't load is skipped with a log
record, at most 512 MB are read). Remove Plug-in deletes it from the
folder. The Additional Plug-ins Folder preference is still loaded from
where it is. Confined MCP servers and VECTORCRAFT_NO_PREFS keep nothing,
as with the PDF preset and colour profile stores.

Docs: docs/mcp.md, docs/plugins.md, docs/target-app-parity.md.
2026-10-17 17:49:38 +07:00
BFlat e78116e0a2 Merge pull request #2609 from dotCooCoo/fix/history-labels-translated
i18n: the History panel translates the undo step names the sources write as literals
2026-10-17 17:41:28 +07:00
bflatastic 351612c978 i18n: Dutch, Danish and Indonesian undo-step names for the History panel (#2609) 2026-10-17 17:26:59 +07:00
dotCooCoo 7930a0456b i18n: the History panel translates the undo step names the sources write as literals
The History panel looked up each step's name with tl!, which reads only
a plain catalog row. 95 of the 427 names that the engine, the tools and
the shell give their undo steps had no such row in at least one complete
catalog, and 83 had no row at all (Make Blend, New Guide, Pen, Reshape
Spine and others). A step named after an effect has the effect's menu
name without its ellipsis. For many effects, and for steps such as New
Layer, the catalogs hold that name only with the ellipsis. The panel
listed those steps in English.

Each complete catalog now has a row for every step name, written in the
catalog's own terms: 1,437 rows in the 19 catalogs. The History panel
reads a step's row, or else the row of the same name with an ellipsis,
without the ellipsis, and shows the name as recorded when the catalog
has neither. A new test reads the step names from the sources, as the
tl! and message tests read theirs, and requires a row for each in every
complete catalog.

Docs: docs/target-app-parity.md.
2026-10-17 17:22:15 +07:00
BFlat fdac986bb4 Merge pull request #2686 from storytold/fix/2441-group-select-compound-part
Part of #2441: Group Selection picks and moves one path of a compound path; i18n and docs for the sixth batch
2026-10-17 17:18:26 +07:00
BFlat fcdddadeb8 Merge pull request #2625 from dotCooCoo/fix/puppet-pins-keep-save-clean
Background save: dropped Puppet Warp pins, ended Edit Text and font scans leave the document saved
2026-10-17 17:17:51 +07:00
BFlat 97cd86d461 Merge pull request #2626 from dotCooCoo/feat/artboards-panel-shift-range
Artboards: Shift-click in the Artboards panel selects a range of artboards
2026-10-17 17:17:36 +07:00
BFlat 47b1fa52cb Merge pull request #2628 from dotCooCoo/feat/export-overflow-warning
Export: PDF, EPS, SVG, EMF, WMF and image exports warn about type that doesn't fit its frame
2026-10-17 17:17:22 +07:00
BFlat 21dc3bf565 Merge pull request #2629 from dotCooCoo/fix/exit-isolation-keeps-lock-guides
Guides: Lock Guides keeps guides deselected after Undo, Exit Isolation Mode and Paste
2026-10-17 17:17:08 +07:00
BFlat 6ecf568c5d Merge pull request #2630 from dotCooCoo/fix/issue-2345
Part of #2345: a marquee does not select a clip group by its hidden art
2026-10-17 17:16:50 +07:00
BFlat 7d677eaa13 Merge pull request #2631 from dotCooCoo/feat/lock-variables
Variables: Lock Variables stops variables from being defined, deleted or renamed
2026-10-17 17:16:35 +07:00
BFlat 20a40f5b1b Merge pull request #2632 from MarekSpodBiedry/issue-2260
Layers panel: drop a layer under the last row to move it to the bottom (#2260)
2026-10-17 17:16:18 +07:00
BFlat e3a67119c1 Merge pull request #2633 from dotCooCoo/fix/save-panels-offer-their-file-type
Save: save panels for files other than documents offer the file type they write
2026-10-17 17:16:01 +07:00
BFlat 003ec8f373 Merge pull request #2635 from dotCooCoo/fix/issue-2460
Part of #2460: a huge selection of type, images, symbols or meshes shows its bounds
2026-10-17 17:15:52 +07:00
BFlat 1fd7ab495a Merge pull request #2665 from dotCooCoo/fix/print-tiling-artboard-edge
Print: a Print Tiling origin on an artboard's right or bottom edge is measured from that artboard
2026-10-17 17:15:35 +07:00
BFlat e7e149a8bd Merge pull request #2637 from dotCooCoo/fix/art-on-artboard-edge
Artboards: art centered on an artboard's right or bottom edge is on that artboard
2026-10-17 17:15:19 +07:00
bflatastic 4417c4feb7 Docs: the ROADMAP's 2026-10-17 row includes the sixth batch 2026-10-17 17:13:04 +07:00
dotCooCoo b0e78cf3d8 Background save: dropped Puppet Warp pins, ended Edit Text and font scans leave the document saved
Selecting other art drops Puppet Warp pins, ending Edit Text clears the
flat view, and a font scan lays type out again. None of these makes an
undo step or counts as an edit to save, but each one replaced the
document. A background save that finished afterwards compared the
document with the one it wrote by pointer, so the document stayed
marked modified. Data Recovery also wrote a new copy of a document whose
pins had been dropped.

DocState now records the documents that these changes replaced, and
DocState::same_content counts them as having the same content. The
modified flag, the end of a background save and Data Recovery use it.
After Edit Text ends, an undo state that was the saved one stays the
saved one.
2026-10-17 17:13:03 +07:00
dotCooCoo 1401051603 Artboards: Shift-click in the Artboards panel selects a range of artboards
With the Artboard tool in use, a Shift-click on a row of the Artboards
panel selects the artboards from the last row clicked without Shift to
the clicked row, and the clicked row's artboard becomes the active one.
When the artboard of the last row clicked without Shift is no longer
selected, the range starts from the active artboard, and later
Shift-clicks start from there too. Ctrl/Cmd-click still adds or removes
one artboard, and a plain click selects one. The public Select
artboards page lists Shift-click in the Artboards panel for selecting
several artboards.

A Shift-click used to add or remove one artboard, as Ctrl/Cmd-click
does (#1139).

Docs: docs/target-app-parity.md.
2026-10-17 17:13:03 +07:00