Commit Graph
716 Commits
Author SHA1 Message Date
FractalEncryptandDevin 985ef69cb7 New Document: units belong to the chosen preset, not the whole tab
Choosing units in Preset Details restyled every preset card in the Recent
and Saved tabs, so switching between inches and millimetres rewrote all the
user's templates at once. The pane's options apply to the selected preset
(helpx, "Create and save custom document presets"), so only the chosen card
follows the chosen units now; the others keep the units their document or
preset was made in, and clicking one brings its units back. The built-in
category tabs still show the chosen units (#2078).

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-11-04 21:38:01 +07:00
dotCooCoo 4db6e7b448 Paint: use the document color model for new gradient defaults 2026-11-03 20:18:34 +07:00
ruchirguitarandClaude Opus 5.5 8850b923ce Fix #4924: Text Tweaker ramps or randomises one character attribute letter by letter
A built-in Type Tools add-on (Object › Plug-ins › Type Tools › Text Tweaker…,
`addon.type.textTweaker`): size, baseline shift, rotation, horizontal or vertical
scale, tracking, leading or stroke weight go from a start value to an end value
along a straight ramp, an ease, a bow, a spike or at random with a seed, set as
the Character panel sets them, while the text stays live. One undo step, a
dialog with Preview, catalog rows in all 26 languages, docs/mcp.md and the
parity docs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 20:07:58 +07:00
dotCooCoo 2a95625b99 Type: step font families with the mouse wheel
Apply wheel steps over the closed family fields in Character, Properties and Control, preserving event order and one undo step per effective notch. Document the supported controls and the application choices. Fixes #5253.
2026-11-03 16:03:40 +07:00
dotCooCoo e8e09af782 Brushes: Calligraphic and Scatter values follow pen tilt, bearing and rotation
Squashed from #5031 onto main.
2026-11-02 14:33:02 +07:00
dotCooCoo cb7df83217 Swatch libraries: Patterns › Geometric Patterns adds a pattern with its swatch
Window › Swatch Libraries and the Swatches panel's library menu get a
Patterns submenu with Geometric Patterns, a built-in library of eleven
black pattern swatches drawn in code (dots, stripes, a checkerboard, a
grid, diamonds, triangles, crosses and a zigzag).

- Clicking a pattern in its library panel adds the pattern and its
  swatch to the document and applies it to the active fill or stroke
  (Alt: the other one), as one undo step. A second click reuses the
  swatch; a different pattern under the same name keeps its name and
  the library's pattern comes in numbered.
- swatch.library.list lists the pattern libraries after the gradient
  libraries (category "patterns"), and swatch.library.add brings a
  pattern swatch's pattern as pasting art painted with it does.
- The library panel draws each pattern tile from the library's pattern.
- "Geometric Patterns" is translated in every catalog.
2026-11-02 12:04:02 +07:00
bflatastic a76d9215da Fix #4923: Find Nearest Swatch matches colours to a library's swatches
Object > Plug-ins > Color Effects > Find Nearest Swatch... picks a
library (the document's swatches, a built-in library, or a library or
colour book the user saved or loaded) and Fill and Stroke, and lists
each colour of the selection with its three closest swatches and their
CIEDE2000 difference. Apply gives each colour its nearest swatch as one
undo step.

- addon.color.nearestSwatch (a query): the closest swatches of a
  library to each colour of the selection's fills and strokes (solid
  colours and gradient stops, inside groups and type), or to a colour
  given, with deltaE; count 1..50.
- addon.color.applyNearestSwatch: recolours those paints (and gradient
  meshes) to their nearest swatch; global and spot swatches link, and a
  library's swatches the colours take are added to the document first
  (as swatch.library.add adds them), so a spot colour stays spot.
- The library picker Image Trace's Document Library uses moves to the
  Swatches panel module and is shared.
- No colour book data ships: only libraries VectorCraft computes or the
  user loads are searched.
2026-11-01 11:09:11 +07:00
bflatastic 84336967aa Fix #4922: Expand Dashes into Paths 2026-11-01 09:08:07 +07:00
bflatastic cd277d5d84 Fix #4917: Sort Objects sorts the selection by one attribute and applies that order to another
Squashed from #5017 onto main.
2026-11-01 08:11:17 +07:00
bflatastic ef80709e16 Fix #4925: Randomize Opacity gives each selected object a random opacity in a range 2026-11-01 08:07:33 +07:00
bflatastic 68391bdde4 Fix #4926: New Symbols from Layers 2026-11-01 02:44:16 +07:00
bflatastic 916b60898a Fix #4927: Save a Timestamped Copy 2026-11-01 02:44:16 +07:00
bflatastic 9e3f8dccec Fix #4950: Path Precision Tools: Divide into Dashes
addon.pathtools.divideDashes cuts the selected paths (or only their
direct-selected segments) into separate open paths of a dash length
measured along the curve, with an optional gap (gap pieces dropped
unless removeGaps is false) and Fit to Corners and Ends; pieces keep
the path's appearance, one undo step, at most 100000 pieces. Geometry
in vectorcraft-pathops; dialog with unit fields and Preview; tests,
sweep cases, catalog rows and docs.
2026-11-01 02:44:16 +07:00
bflatastic 69985f4998 Fix #4928: Arrange Tools: Group Overlapping Objects
addon.arrange.groupOverlapping groups the selected top-level objects
whose visual bounds overlap or touch, chains included (union-find over a
sweep along x, at most 20000 objects), only within one layer or group.
Each group takes its frontmost member's stacking place; one undo step,
all groups made in one pass over the tree. Menu item, tests, sweep case,
catalog rows and docs.
2026-11-01 02:44:15 +07:00
bflatastic 9b407edbbe Docs: ROADMAP progress log for 2026-10-31 2026-10-31 22:22:23 +07:00
bflatastic ca0785573d Add-ons: Arrange Tools — Arrange in Grid, Swap, Replace with Top Object, Set Size of Each, Zoom to Selection
A built-in add-on in Object › Plug-ins › Arrange Tools (#4830, #4831, #4832, #4833, #4834):

- addon.arrange.grid lays the top-level selected objects out in rows and
  columns, a row or a column (stacking order from the back, visual bounds,
  each object centred in its cell), from the selection's top-left or
  centred on the artboard.
- addon.arrange.swap swaps two objects' bounds centres, and with `size`
  their widths and heights.
- addon.arrange.replace puts a copy of the topmost selected object centred
  on each of the others, in its stacking place, kept, stretched or fitted
  in proportion; the replaced objects are deleted unless `keep`.
- addon.arrange.size gives each selected object an exact width and/or
  height about a reference point.
- addon.arrange.zoomSelection (a UI command) fits the active view to the
  selection.

Places and sizes are measured as object.setBounds measures them (its
transform, now also available per object), strokes scale as Scale Strokes
& Effects says, each command is one undo step, and Arrange in Grid,
Replace with Top Object and Set Size of Each open previewed dialogs.
Catalog rows, command sweep cases, docs/mcp.md, parity docs and the
ROADMAP progress log.
2026-10-31 22:22:15 +07:00
aiongg ffad6cc20e docs: tidy wording 2026-10-31 04:25:47 +00:00
aiongg 8ae1f7dae6 docs: tidy agent, contributor and asset docs 2026-10-31 04:17:23 +00:00
nine-codesandClaude Opus 5.5 64b92627c2 Add Bosnian (bs) to the interface languages
bs.tsv: Bosnian (Latin script, Ijekavian) catalog covering every key of
VectorCraft's other catalogs, its wording shared with storytold/craft-i18n
locales/bs/ and the strings craft-i18n lacks translated new. Every bs-*
locale selects it; counts use one/few/other. Locale and plural tests,
localization docs and an attribution entry (AI-assisted, not yet
reviewed by a native speaker).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013Tayw8nmxoLLmKv13jK93z
2026-10-31 01:17:11 +07:00
ashokram-si 7a2fc777f4 Gradient panel: presets to apply, save and delete (G13)
People reuse the same gradients across documents and rebuilt them by
hand. The Gradient panel now has a Presets menu: the presets of the
app's built-in gradient libraries, grouped by library (theme), then
the saved ones. Choosing one gives the gradient behind the active
proxy (or a solid paint) the preset's type, stops, method and dither,
keeping its placement, as one undo step, through paint.editGradient.
The panel menu saves the current gradient as a preset (named in a
dialog) and deletes saved ones; Hide/Show Presets toggles the row.

Saved presets are kept with the preferences, next to the other user
preset lists (width profiles, flattener, perspective). Stops linked to
a document swatch keep their colour, unlinked, since a preset is used
in other documents. Built-in presets can't be deleted; names are
unique.

Commands: gradient.presets.list, .apply, .save and .delete. The menu's
rows are drawn only while in view, as its headings are.

Tests: engine tests for list, apply (fill and stroke, placement kept,
one undo step), save (unique names, unlinked swatch stops) and delete;
panel tests for applying from the menu and saving, deleting and
hiding presets from the panel menu, including scrolling the menu to
the saved presets. Docs: gaps G13, target-app and UI parity, ROADMAP.
2026-10-30 19:50:25 +07:00
wjrichardsandClaude Opus 5.5 dd934dfd4e Linux clipboard: copy text through the core Wayland protocol
Where arboard can't open (GNOME has no data-control protocol, and the Flatpak on a
Wayland session has no X11), Copy and Paste use the compositor's core data-device
protocol on the window's own connection through smithay-clipboard, already in the
build through egui-winit: text only, a copy's text or its SVG markup. A bitmap-only
copy reports that this clipboard carries text only and leaves it as it was.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 17:12:17 +07:00
wjrichardsandClaude Opus 5.5 c988af83b5 Linux clipboard: stop the retry storm
The Flatpak on GNOME has no X11 (fallback-x11 on a Wayland session) and GNOME offers
no data-control protocol, so arboard::Clipboard::new() failed every time. The handle
was kept only on success, so the background Paste check reconnected to the compositor
and logged a warning every 250 ms: 267k warnings in 18 h, the 16 MB log full in 3 h.

- A clipboard that can't be opened is tried again after 1 s, doubling to a minute.
  A Copy or Paste of the user's retries at most once a second.
- The outage is logged once (WARN) and its end once (INFO), across the UI's and the
  background check's handles.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 02:19:33 +07:00
krosk93 7a79935c10 i18n: add Catalan (ca) localization
Squashed from #4453 onto main.
2026-10-29 13:00:44 +07:00
Taha-Mahmoodi e7f2ab9a8e Docs: Pathfinder › Trap ships; Effect › Pathfinder 13/13, Illustrator effects 49/50 2026-10-24 03:09:08 +07:00
Jürg Lehni c28ad99678 Type: OpenType SVG colour fonts draw and export as vector art
Each glyph's SVG document is read by the SVG importer, which the engine registers with the text crate.
2026-10-23 09:07:54 +07:00
Jürg Lehni 9de4b40241 Type: COLR colour fonts draw and export as vector art
Glyphs whose paints documents have no form for (sweep gradients, compositing modes) are drawn as images of the glyph.
2026-10-23 05:14:47 +07:00
Taha-Mahmoodi edca5e9eb0 Docs: the Effect Gallery is shipped; thumbnails and an in-dialog preview area remain (G2 1–2 h, raster effects 85%) 2026-10-23 03:48:07 +07:00
Mirko Kerezovic 5e9df83dd4 Fix #3646: display PDF document title 2026-10-23 01:01:24 +07:00
bflatastic 26b9cf84ad Type: colour emoji fonts with bitmap glyphs draw and export
Squashed from #3561 onto main.
2026-10-23 00:44:31 +07:00
Taha-Mahmoodi 9097c4a564 Docs: G2 lists the 57 filters once and its table estimate matches; ROADMAP records Conté Crayon in its revision history
Review follow-up (CodeRabbit): the two older G2 bullets counting 46 and 49
filters were superseded by Conté Crayon (57/57) and are folded into one
current bullet; the G2 row in the ranked table and the entry's estimate now
both say 4–6 h, as ROADMAP.md and roadmap.md do. ROADMAP.md's revision
history gains its 2026-10-22 row.
2026-10-22 21:34:37 +07:00
Taha-Mahmoodi bd6d076484 Effects: Sketch › Conté Crayon draws the dark areas in a black crayon and the light areas in a white one on textured paper 2026-10-22 21:18:34 +07:00
dwetscherandClaude Opus 5.5 f73a3df974 AF.5: bound hostile Affinity files; fuzz the new import paths
- One budget for the whole read (layers, pixels, characters, table
  cells), shared with embedded documents and charged also when their
  reading fails; the first reading is dropped before the second.
- Tables: at most 65 536 cells; lines and cell formats that don't
  match the grid are left out instead of shifted.
- Paragraph formats matched to runs by binary search; font names
  longer than 256 bytes are dropped.
- Overlays: one work budget per import; encoded originals decoded
  within their layer's size; table cell outlines recoloured too.
- Engine: master page copies capped, each page's master found in
  linear time, line gaps looked up once per font, the working CMYK
  table built once, objects past MAX_COORD left out.
- Embedded content stays with its node; pixel masks under artistic
  text are read whole and include stroke reach; gradient overlays on
  hidden layers are kept.
- Render: contexts and raster effect images stay within
  MAX_RASTER_SIDE per side (vello overflowed near u16::MAX; found by
  the new fuzz target).
- Tests: affinity tests/import_limits.rs, feature samples in
  import_fuzz.rs, shared builders in engine/tests/support/.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 18:24:57 +07:00
dwetscherandClaude Opus 5.5 fd50bd6f84 AF.5: Affinity import — strokes, text decoration, text placement, outline effects, CMYK photos
- Strokes set to None no longer import as black 1px strokes.
- Underline and strikethrough are kept.
- Frame text starts at cap height; lines hanging out of a frame make it taller;
  mixed-alignment artistic text lines up within its longest line; line breaks
  inside a paragraph get no paragraph spacing.
- Table cell text taller than its cell is centred and stays visible.
- Outline effects on stroked shapes are drawn around the stroke.
- CMYK pixel layers go through the document's embedded CMYK profile; without
  one, opaque layers stay CMYK.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 18:24:57 +07:00
bflatastic 74ec2751ed Docs: Photoshop filter count after Fresco and Torn Edges (54/57), one row each 2026-10-22 01:15:10 +07:00
bflatastic 0c9a7a89a0 Docs: Photoshop filter count after Colored Pencil (52/57), one Artistic row 2026-10-22 00:31:30 +07:00
bflatastic 3c6d2b371e Docs: Photoshop filter count after the Artistic batch (51/57) 2026-10-22 00:23:51 +07:00
bflatastic 14f804cdee Type: ruby (ふりがな) for live text
Squashed from #3448 onto main.
2026-10-22 00:10:56 +07:00
bflatastic 2cd7f156fb Add lighting presets to 3D effects
Squashed from #3442 onto main.
2026-10-22 00:01:37 +07:00
Midasdf 32d012f6cc Print: Japanese paper sizes (JIS B4/B5/B6, はがき・封筒・四六判)
The Print dialog's Media list only had Letter/Legal/Tabloid and the ISO A
and B papers, so Japanese papers had to be entered as a custom size, and
"B4"/"B5" were ISO 216 (250 × 353 and 176 × 250 mm) although Japanese
printing uses the JIS sizes (257 × 364 and 182 × 257 mm, JIS X 6310).

Media gains JIS B4, B5 and B6 next to the ISO ones, and はがき
(japanese postcard, 100 × 148 mm), 往復はがき (japanese double postcard,
148 × 200 mm), 封筒 長形3号/長形4号 (japanese envelope #3/#4, 120 × 235
and 90 × 225 mm), 角形2号/角形3号 (kaku #2/#3, 240 × 332 and 216 × 277 mm),
四六判 (yonroku-ban, 127 × 188 mm) and A6, all in millimetres at 72/25.4.
b4 and b5 keep their ISO 216 dimensions so print settings and presets
saved before the Japanese papers existed keep their paper; the dialog
labels say "B4 (ISO)"/"B5 (ISO)" beside "B4 (JIS)"/"B5 (JIS)".

A paper is named by its JSON id or by its dialog label, any case and
spacing ("b5 (jis)", "B5 (JIS)" and "b5jis" all mean the JIS B5), so
agents and the control channel need not know the id spelling; an unknown
name is still refused. Media is written out instead of through the
choice! macro to carry that lookup.

The print.setup/file.print parameter docs and docs/mcp.md list the new
papers; the Print dialog picks them up from Choice::ALL with no UI code
change, and the Japanese labels are translated in ja.tsv (はがき,
往復はがき, 長形3号, 長形4号, 角形2号, 角形3号, 四六判).

Tests: japanese_paper_sizes checks every added size in points, that the
ISO B4/B5 values did not change, name resolution and id/label round
trips, and that each paper prints a PDF page with its own MediaBox size.

Validation: cargo fmt --all -- --check clean; cargo clippy
-p vectorcraft-pdf --all-targets -- -D warnings clean; cargo test
-p vectorcraft-pdf -> 330 passed, 0 failed (328 lib + 2 integration).
2026-10-21 23:32:26 +07:00
nrq6993-a11y 078e67a386 G2: Effect › Sketch › Water Paper raster filter (#2955) 2026-10-21 15:17:04 +07:00
bflatastic 62e8474caa i18n and docs: Note Paper's catalog rows, raster effects 46 of 57 (#2954) 2026-10-20 08:29:26 +07:00
Martin Vlach f664564e97 Effects: Sketch › Bas Relief, Charcoal, Photocopy and Stamp (#2527)
Squashed from #2533 onto #2525 (Smudge Stick, Sponge, Watercolor): both sets in PIXEL_EFFECTS (45), the catalogs and the docs, whose counts now read 45/57.
2026-10-20 06:43:50 +07:00
Martin Vlach 5251246778 Effects: Artistic: Smudge Stick, Sponge and Watercolor (#2435)
Squashed from #2525 (its merges of main dropped).
2026-10-20 06:32:32 +07:00
bflatastic ac83e91c5f Docs: the ROADMAP's 2026-10-19 row, and the rows merges of conflicting PRs left twice
ROADMAP: a progress row and status line for the community PRs of 2026-10-19; the reproducible-bytes and inch-ruler rows appeared twice. gaps.md: G6 held four interleaved versions of its Missing line; it now says what is left (a scripting surface). target-app-parity.md: three copies of the Type evidence bullet, merged into one with every sentence. type-parity.md and ui-parity.md: a row and a shorter copy of it.
2026-10-20 02:41:01 +07:00
Hamza 39b59b5730 Rulers: stop labelling an inch ruler at a sixteenth
Labelling to a hundred and twenty-eighth left the left ruler unreadable: it
spells a label one character per line, 8.5 pt apart, and at zoom 50 the step is
1/64 with labels 56.25 pt apart while "0.015625" needs 61.5 pt. At zoom 100 it
is "0.0078125" in the same space.

The label ladder stops at a sixteenth, as the report says Illustrator's does,
so zooming in past that leaves the labels where they are and only the ticks
between them grow denser -- down to a hundred and twenty-eighth, which is the
32nds, 64ths and 128ths the report expects to appear unlabelled. Every label is
at most the six characters of "0.0625", which fits the 50 pt the ladder leaves.
2026-10-19 23:47:04 +07:00
Hamza 2c6a2ad082 Rulers: an inch is divided in half, not in ten
Zooming in on an inch ruler stepped through 0.2, 0.1 and 0.05 of an inch:
`Unit::ruler_step` picked from one decimal ladder for every unit, and the
rulers divided whatever it returned by ten. A tenth of an inch is not a mark an
inch ruler carries (#2827).

Below an inch the steps are binary fractions now, 1/2 down to 1/128, and
`Unit::ruler_minor` gives the unlabelled ticks between two labels: an eighth of
the step on an inch ruler, so every tick is a binary fraction of an inch and
they stay about as dense as the tenths elsewhere. An inch and wider keeps the
shared ladder, and the metric units, points, pixels and picas keep their
tenths. Ruler-tick snapping follows the ticks that are drawn, which moves an
inch document's Shift-drag of a guide onto the same grid.

`ruler_label` took its decimals from `(-step.log10()).ceil()`, which writes
1/16 as "0.06" and 1/8 as "0.13" -- wrong values, not just rounded ones. It
uses the fewest decimals that write the step exactly, and drops trailing zeros
as `Unit::number` does, so a sixteenth-inch ruler labels the inch `1` rather
than spelling `1.0000` down six lines of the vertical ruler.
2026-10-19 23:47:03 +07:00
Hamza 7bc7025a62 Exports: say that an encrypted PDF still differs, and test the fallback
Two review points on #2880.

The reproducibility claim needed qualifying. PDF encryption draws its AES
initialisation vectors and the file `/ID` from a random seed, which
`SOURCE_DATE_EPOCH` deliberately does not reach, so a PDF exported with a
password never repeats however the variable is set. The docs and the ROADMAP
line say so now.

The byte-identity test passes an explicit `created`, so it never exercised the
clock-or-variable fallback. `pinned_or` takes the environment and the clock as
arguments, and the new test shows the variable is preferred, that a blank,
negative or non-numeric value leaves it to the clock, and that a host with
neither has no date to record. The environment is injected rather than set: a
test that changes this process's environment is `unsafe` under edition 2024 and
would reach every other test running beside it, which is why `cursor_theme`
takes a lookup closure too.
2026-10-19 22:19:51 +07:00
Hamza 1c80b23745 Exports: SOURCE_DATE_EPOCH stands in for the clock, so output repeats
PNG, PDF, EPS, legacy `.ai`, packaged zips and saved `.vectorcraft` files
record the wall-clock time they were made in, so the same commands run twice
gave different bytes although the pixels matched (#2880):

  PDF   /CreationDate and /ModDate   D:20261018155816 vs D:20261018155817
  PNG   the `Creation Time` tEXt entry
  .vectorcraft  one byte of the stored date
  SVG   carries no time, and already repeated

`metadata::output_time` is the time a file records: `SOURCE_DATE_EPOCH` when it
holds a non-negative whole number of seconds, else the clock, as the
reproducible-builds specification defines it. A date a command is given
(`file.new {created}`, a save's `modified`) still wins over the variable, and a
blank, negative or non-numeric value is ignored so that an export is never
refused over the environment.

`metadata::now_unix` keeps the real clock and now has exactly two callers, both
of which must not be pinnable from the environment: the recovery heartbeat, and
the seed PDF encryption draws on.
2026-10-19 00:37:55 +07:00
Davit Matchakhelidze 7cf8dd4764 i18n: Georgian (ka) interface language
Squashed from #2045 (merge commits from main dropped).
2026-10-18 18:09:14 +07:00
bflatastic 52b6543c2e Docs: the ROADMAP's 2026-10-18 row includes the second batch 2026-10-18 13:26:54 +07:00