Commit Graph
10704 Commits
Author SHA1 Message Date
dotCooCoo afdaa47cd5 SVG import: a clip path made of text clips by the text
A <text> in a <clipPath> was dropped with a warning, so a clip path made
only of text had no content and the art it clipped was hidden. The
clipPath content model in CSS Masking Module Level 1 lists text and use
(https://www.w3.org/TR/css-masking-1/#ClipPathElement).

The importer now clips by the text's glyph outlines, together with any
shapes in the same clip path, and keeps clipPathUnits, the transforms,
clip-rule, visibility, the conditional processing attributes and a clip
path on the text. A <use> in a clip path that shows a text clips the
same way, placed by the <use>; a clip path on the <use> applies in the
<use>'s user space, and a reference goes to the first element with the
id. When the clip path holds only one visible text, with no clip path
of its own and no even-odd clip rule, the clipping path of the clip
group is the text object with no fill or stroke, the same structure
Make Clipping Mask produces for type. A text or a <use> with an id in a
clip path can still be shown by a <use> outside it. Each text's
outlines are laid out once, however many elements use the clip path.

A transform set by a style rule or a style attribute on a text now
places it, as it does a shape. Before, only the transform attribute was
read, inside and outside clip paths.
2026-11-11 01:04:34 -08:00
BFlat 9f44e37274 Merge pull request #6522 from dotCooCoo/fix/thumbnail-render-options
Render: node renders and thumbnails follow the supersample and precise options
2026-11-11 13:21:40 +07:00
BFlat 663f3434d7 Merge pull request #6523 from dotCooCoo/fix/render-document-composite-fonts
Render: type in a document's own composite font draws in its definition
2026-11-11 13:17:10 +07:00
BFlat 99cbdf9b73 Merge pull request #6520 from dotCooCoo/fix/break-link-selects-only-selectable-art
Symbols: Break Link selects no art inside a hidden or locked group
2026-11-11 13:05:00 +07:00
BFlat 0695db3ec0 Merge pull request #6519 from dotCooCoo/feat/reshape-focal-points
Reshape: a click sets a focal point and a drag moves every focal point
2026-11-11 12:53:37 +07:00
dotCooCoo 5452b516f6 Render: type in a document's own composite font draws in its definition
Raster renders, ink renders, thumbnails and node renders now lend the
document's composite fonts to the font database while they draw, as the
PDF, SVG and EPS writers already do. A document that is not in front, a
document read from a file (library thumbnails, save previews) and a
placed document's art drew such type in the fallback font or in another
definition of that name.
2026-11-10 21:39:36 -08:00
dotCooCoo eaaf1155a8 Render: node renders and thumbnails follow the supersample and precise options
render_node_with and render_node_thumbnail_with ignored RenderOptions::supersample
and RenderOptions::precise, so the Asset Export tiles, which ask for both, were drawn
with the canvas's shape-by-shape edges and the fast render mode instead of the export's
look. A node render now supersamples Art Optimized edges as a page render does, and
picks the quality render mode when precise is set, for the art's offscreen groups too.
2026-11-10 21:35:47 -08:00
BFlat b34c652a60 Merge pull request #6514 from ruchirguitar/fix/5820-general-units-for-unitless-files
#5820: files that record no units open in Preferences › Units › General
2026-11-11 12:35:44 +07:00
BFlat 10f6f4ffb2 Merge pull request #6518 from dotCooCoo/fix/char-style-basic-names
Character Styles: the style dialogs' fields have accessible names
2026-11-11 12:31:01 +07:00
BFlat ac33652fe3 Merge pull request #6516 from dotCooCoo/fix/menu-scroll-wrap
Menus: a scrolling list keeps each label on one line
2026-11-11 12:26:41 +07:00
dotCooCoo d069e0e4be Symbols: Break Link selects no art inside a hidden or locked group
Break Link to Symbol on a selected group selected the art of every
instance it expanded that was itself shown and unlocked, including art in
a hidden or locked group inside the selection. The art now goes into the
selection only when it and every group and layer holding it are shown and
unlocked, the check Select All uses (select::is_selectable).
2026-11-10 21:08:57 -08:00
BFlat 22ec820569 Merge pull request #6513 from dotCooCoo/fix/break-link-keeps-hidden-locked
Symbols: Break Link keeps a hidden or locked instance's art hidden or locked
2026-11-11 12:00:47 +07:00
dotCooCoo c676051641 Character Styles: the style dialogs' fields have accessible names
The text fields and menus of the Basic Character Formats, Advanced
Character Formats, Character Color and OpenType Features sections, and
the Style Name field of Character Style Options, are now named by the
label beside them, so screen readers announce them. This covers both
Character Style Options and New Character Style, which share the
sections. The New Character Style UI test runs with the accessibility
check on again, and a new test opens every section of both dialogs and
checks that no input is unnamed.
2026-11-10 20:53:24 -08:00
BFlat acc6acfdb2 Merge pull request #6266 from Silvertree2010/fix/h13526-graph-csv-round-trip-drops-a-bla
Keep blank value row in single-column graph CSV round trip
2026-11-11 11:52:07 +07:00
BFlat 3e780a8026 Merge pull request #6512 from dotCooCoo/fix/native-open-pdf-preference-one-pass
Native files: open reads the PDF preference in the same pass as the document
2026-11-11 11:51:57 +07:00
ruchirguitar 52918add2d #5820: keep ruler units the EPS program header gives when the editing data has none 2026-11-11 10:12:00 +05:30
BFlat bc814012d9 Merge pull request #6511 from dotCooCoo/feat/artboard-color-labels
Artboards: an artboard's guide label colors its own guides
2026-11-11 11:27:16 +07:00
ruchirguitar f5daa27a2f #5820: files that record no units open in Preferences › Units › General
A PDF, an EPS or .ai without ruler units, a raster image, a metafile, an
Affinity file or an importer plug-in's document opened (and reverted) in
points whatever the General unit was. They now open in the General unit,
as the reference app opens files that record no unit. Native, SVG and DXF
files and a .ai or EPS with %AI5_RulerUnits keep their own units. Only the
displayed units change, not the art.
2026-11-11 09:56:19 +05:30
dotCooCoo 549391a50d Menus: a scrolling list keeps each label on one line
A popup measures its list on the first frame, when the scroll area does
not yet show its bar. When the bar then appeared, its column took its
width from the items, and the widest label wrapped onto two lines:
Distort & Transform in the Add New Effect menu, and Black and White Logo
in the Image Trace presets, in short windows.

menu_scroll now lays the items out at least as wide as on the popup's
first frame, so the bar's column widens the popup instead. That width
is kept until the popup closes and is never wider than the window has
room for. The items are laid out in the same child Ui on every frame,
so their ids do not change when the width does.
2026-11-10 20:23:42 -08:00
dotCooCoo bd39674469 Reshape: a click sets a focal point and a drag moves every focal point
A click with the Reshape tool on an anchor of a selected path makes it
the focal point, and a click on a segment adds an anchor there that
becomes the focal point. Shift-click adds an anchor or a point on a
segment to the focal points, or removes an anchor that is one already.
Each focal point shows a filled anchor square in a larger hollow one.
A drag from a focal point moves all of them; a drag from another point
moves that point alone, and Shift only keeps the drag's angle.

path.reshape takes the other focal points as focal: [[subpath,
anchor]...]. Anchors that are not direct-selected stay in place, and so
do the ends of an open path unless they are focal points. A selected
anchor between two focal points moves by the whole drag, and one
between a focal point and an anchor that stays takes u² (3 - 2u) of
the drag, as before. A closed subpath with every anchor selected moves
whole: a Reshape drag on a fully selected closed path, and path.reshape
without radius on a closed path selected whole or not selected, move
the whole path instead of a local area. With radius, only the grabbed
point's subpath changes, with the falloff as before.

- An anchor added on a segment of a partly selected path is selected,
  and the selected anchors and segments after it keep their points.
- A focal pair that names no anchor is refused ("`focal` names [0, 7],
  which is not an anchor of the path"), and so is focal with radius.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-11-10 20:18:23 -08:00
NetterSilverandClaude Haiku 5.5 aaf27e1ec6 Keep blank value row in single-column graph CSV round trip
Found while testing crates/engine/src/cmd/graph/data.rs:51 (parse_csv); written by crates/doc/src/graph.rs:497 (GraphSpec::to_csv)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-11 04:16:30 +00:00
dotCooCoo 2faadd28f4 Symbols: Break Link keeps a hidden or locked instance's art hidden or locked
Break Link to Symbol on a selected group, and Delete Symbol with its
instances expanded, turned a hidden or locked instance into visible,
unlocked art. The art now keeps the instance's hidden and locked state,
as Object > Expand does, and Break Link leaves hidden or locked art out of
the selection.
2026-11-10 20:09:28 -08:00
BFlat 726d2b6e13 Merge pull request #6508 from jmverges/fix/3179-warps-of-type-as-mesh
.ai import: warps of type open as mesh envelopes on their saved grid
2026-11-11 10:48:16 +07:00
BFlat 98fe060bb0 Merge pull request #6499 from dotCooCoo/feat/script-console
Scripts: Window › Script Console shows script output, errors and run reports
2026-11-11 10:48:06 +07:00
dotCooCoo 8002598d64 Native files: open reads the PDF preference in the same pass as the document
Opening a native file read its JSON twice: once for the document and once
more for the saved pdfCompatible preference. The format crate now takes
the preference from craft-vectorcraft-format's
Contents::read_with_pdf_preference (craft-libs#562), so a file is read in
one pass.

That method refuses a pdfCompatible that is not a boolean, which main
opens by skipping the value and falling back to whether the file carries
a PDF. Such a file, or one with any other data error, is read again with
Contents::read and scanned for the preference as before, so the files
that open today still open with the same result.

The craft-vectorcraft-format pin moves to 1b34eba41e, the craft-libs
revision craft-update already uses.
2026-11-10 19:42:29 -08:00
dotCooCoo 29437fed48 Merge main into feat/artboard-color-labels 2026-11-10 19:38:12 -08:00
dotCooCoo beef32b8a3 Artboards: an artboard's guide label colors its own guides
Each artboard can carry a guide label: one of the layer colors or a
custom RGB. Guides that belong to an artboard draw in its label color,
and guides without an artboard, or on an artboard without a label, keep
the guide color from the preferences. Selected guides still draw in the
selection color.

- Artboard Options has a Guide Label row (None, the layer colors with
  swatches, or Custom with a color swatch).
- artboard.new and artboard.setProps take guideLabel: null, a layer
  color's name, or #rrggbb. Any other value is an error. The inspect
  summary lists guideLabel when one is set.
- The native format saves the label and skips it when unset; a preset
  index outside the layer colors reads as no label.
- artboard.setProps no longer adds an undo step when nothing changes.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-11-10 19:37:17 -08:00
BFlat add0fcbe03 Merge pull request #6503 from dotCooCoo/fix/fx-menu-flicker
Menus: a long menu stays in one place instead of jumping between two places
2026-11-11 10:29:19 +07:00
BFlat aaa2ea51a8 Merge pull request #6493 from dotCooCoo/fix/pattern-options-null-docs
Docs: pattern.options keeps a pattern's current values for omitted params
2026-11-11 10:09:23 +07:00
jmvergesandClaude Opus 5.5 d85a967fb7 docs: envelope grid orientation and retry budget for warps of type
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-11 03:06:48 +00:00
jmvergesandClaude Opus 5.5 d0c99cba4b .ai import: a warp of type's second try leaves checks for the envelopes after it
A warp of type may now spend up to four checks (its warp and its saved
grid, each with and without strokes). A try after the first is only
made while more checks are left than there are envelopes of type and
warped text objects still to come, so one envelope's retries don't use
up the checks of the others.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-11 03:06:24 +00:00
jmvergesandClaude Opus 5.5 198bb6dffd .ai import: an envelope's grid reads its way round from every row and column
Summing only the end rows and columns let a grid symmetric about its
middle (a mesh bent halfway round) read by rounding, so it came out
turned or not depending on where it sat on the page. Every row and
column is now summed, a sum shorter than 1% of its parts (or than the
grid's reach) counts as no direction and falls back to the first row or
column, and the same comparison decides both cases.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-11 03:06:24 +00:00
jmvergesandClaude Opus 5.5 8820a15e20 docs: warps of type as mesh envelopes on their saved grid
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-11 03:06:24 +00:00
jmvergesandClaude Opus 5.5 37e3c0215a .ai import: type in an envelope may map from its bounds with strokes
With Distort Appearance, an envelope's contents map from the box the
file measured for them: their bounds with their strokes or without
them. For type, the size the file saves for that box is often out of
date, so it can't say which. Envelopes of type are now checked both
ways: as before, and mapping from their bounds with their strokes.
Whichever draws as the drawn art opens live.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-11 03:06:13 +00:00
jmvergesandClaude Opus 5.5 7504a0e2e4 .ai import: an envelope mesh bent far round reads the way it runs
An envelope's mesh is turned upright by which way its rows and columns
run. That was read from the first row alone, so a warp bent past halfway
(its end columns leaning more than 45 degrees) read as turned round and
mapped its contents across instead of along. Read it from the first and
last rows and columns added up instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-11 03:06:13 +00:00
jmvergesandClaude Opus 5.5 8f3f6a82d7 .ai import: a warp of type opens as a mesh envelope on its saved grid
A warp of type whose own warp doesn't draw as its drawn art is checked
again as a mesh envelope on the grid the editing data saves for it, its
points and handles as saved. Where that draws as the drawn art, it opens
live in its place: the type stays editable in that shape, and the warp's
style and bend are lost.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-11 03:06:13 +00:00
BFlat 858b63082f Merge pull request #6500 from jmverges/fix/6472-ai-type-stroke-join
.ai import: stroked type keeps its cap, join and miter limit
2026-11-11 10:01:10 +07:00
BFlat ec89f3f26e Merge pull request #6501 from dotCooCoo/feat/prefs-export-import
Preferences: export and import preferences as a JSON file
2026-11-11 10:01:01 +07:00
dotCooCoo e4830a0e2c Docs: the Script Console note shows only after dropped or cut lines
The panel's note and the doc comment on ui.copyScriptConsole now say the
count of dropped and cut lines appears only when there are any, and the
returned lines count leaves that line out.
2026-11-10 18:51:13 -08:00
dotCooCoo 6643991710 Docs: ui.copyScriptConsole adds the count line only after dropped or cut lines
A copy of every Script Console line starts with the count of dropped and
cut lines only when there are any, and the returned lines count leaves
that line out. The end-line text is described without a code span that
ends in a space.
2026-11-10 18:30:11 -08:00
dotCooCoo ef07aecd96 Menus: a long menu stays in one place instead of jumping between two places
A scrolling menu list took its height from its own top down to the
window's bottom bars. egui picks a popup's side from its size on the
previous frame and moves a popup that does not fit back into the
window, so the list's height changed with where the popup was drawn.
In a short window the Add New Effect menu and other long menus moved
between two places while open, and a menu that did not fit crept a
few points per frame.

The list now takes its height from the room below and above the
button, row or point it opens from: below while that side leaves the
120 pt minimum, otherwise on the side with more room. A submenu
measures down from its row's top or up from its row's bottom. The
change is in menu_scroll, so it applies to every menu built on it.
2026-11-10 18:29:20 -08:00
dotCooCoo d399b17605 Docs: pattern.options accepts a null width or height as omitted
The width and height check in pattern.options applies only to values
that are not null; null keeps the current value.
2026-11-10 18:27:23 -08:00
BFlat 4c2b8df865 Merge pull request #6498 from dotCooCoo/fix/smart-guides-snap
Smart Guides: tools do not snap to Smart Guides while Pixel Preview is on
2026-11-11 09:26:08 +07:00
jmvergesandClaude Opus 5.5 83245cfe54 .ai import: stroked type keeps its cap, join and miter limit (#6472)
The text document reader set a type stroke's paint and weight but never
its cap, join or miter limit, so every stroked text object imported from
a .ai or EPS editing copy drew with a miter join at a limit of 10. Type
the file strokes with round joins, or with a miter limit of 4 or less,
drew long spikes at its sharp corners.

Keys 61, 62 and 64 of a run's character attributes (the run, its
character style, then the document defaults) are now read as the
stroke's cap (0 butt, 1 round, 2 projecting), join (0 miter, 1 round,
2 bevel) and miter limit, as PostScript numbers caps and joins. In the
users' files the page strokes type with exactly these settings. Other
values keep the defaults, a miter limit is capped at 500, and type
without a stroke keeps the defaults.

- ate.rs: Style reads the three keys and char_style passes them on,
  with a unit test over defaults, character styles, run overrides,
  hostile values and unstroked type.
- tests_native.rs: an imported story with round, bevel, default and
  unstroked runs.
- docs/file-format-parity.md: revision row, status line, one line on
  the mapping.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-11 02:20:38 +00:00
dotCooCoo d426c70a92 Preferences: export and import preferences as a JSON file
Part of #6435. An optional VectorCraft feature: the Preferences dialog's
Export Preferences... saves the applied preferences to a JSON file (the
web build downloads it), and Import Preferences... applies such a file and
shows the imported values. They run the new commands prefs.export {path?}
and prefs.import {path | data}.

The file holds every preference prefs.list lists and the eyedropper,
perspectiveWidget, pathfinder and glyphSnap groups, without the four
folder preferences and saved presets. prefs.import reads at most 1 MB and
checks every value first: another format, a newer version, an unknown
preference, a bad value or a folder preference is an error, and nothing
changes. It keeps the open document's units, records no undo step, and is
refused as a command.batch step. prefs.set now rejects a group value that
is not an object.
2026-11-10 18:11:01 -08:00
BFlat af66951c41 Merge pull request #6496 from dotCooCoo/feat/ruler-artboard-guides
Guides: an option makes Cmd/Ctrl ruler drags artboard guides
2026-11-11 09:04:35 +07:00
BFlat d2b1fe74cf Merge pull request #6495 from dotCooCoo/fix/canvas-redraws-on-plugin-change
Canvas: installing or removing a plug-in draws its effects again
2026-11-11 08:58:49 +07:00
dotCooCoo e60b0c3aa6 Docs: pattern.options rejects a bad width or height while sizeTileToArt is on
With sizeTileToArt on, pattern.options ignores width and height for sizing but
still rejects a value that is not a positive number, such as width 0, and
changes nothing.
2026-11-10 17:57:41 -08:00
BFlat 69d36e961d Merge pull request #6494 from dotCooCoo/feat/dimension-horizontal-vertical
Dimension tool: linear dimensions measure horizontally, vertically or aligned
2026-11-11 08:50:56 +07:00
dotCooCoo 4060480ef1 Smart Guides: tools do not snap to Smart Guides while Pixel Preview is on
With View > Pixel Preview on, the tools still snapped to Smart Guides
and showed their guides; only the Object Highlighting outline was
hidden. Work with Smart Guides says Smart Guides cannot be used while
Snap to Grid or Pixel Preview is on.

ViewInfo has a pixel_preview field, and Session::with_tool_cx turns
Smart Guides (and Snap to Glyph, which needs them) off in the tools'
context while it is set. VectorcraftApp::view_info passes View > Pixel
Preview. View > Smart Guides keeps its setting.

Docs: docs/target-app-parity.md.
2026-11-10 17:43:29 -08:00