Commit Graph
2296 Commits
Author SHA1 Message Date
dotCooCoo 88b587baa6 PDF/SVG export: knockout groups nest no deeper with more elements
A knockout group was written as a chain of soft masks, one inside the
next for each element, so a group of about 200 elements made a PDF that
VectorCraft's own PDF import refused (form nesting past 50) and an SVG
that the web build refused as too deep.

- PDF writes a knockout group as one transparency group with /K true,
  with /I true when the group isolates, and PDF import reads it back as
  a knockout group. An element with several paints is drawn as one
  group inside it, so its own fills and strokes do not knock each other
  out.
- Where an element knocks out less than the area it paints (its opacity
  or mask defines its knockout shape, or it paints translucently), each
  element is drawn through one soft mask of the overlapping elements
  above it. Past 65,536 objects in a group's masks, or 2,048 elements,
  the group is a PDF knockout group, with a warning.
- SVG draws each element through one mask of the overlapping elements
  above it, built from one shared copy of each element's shape, so the
  elements stay siblings. Past 65,536 shapes in a group's masks, or
  2,048 elements, the group is written as a plain group, with a warning.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-11-13 12:21:39 -08:00
BFlat a105e14aef Merge pull request #7220 from dotCooCoo/feat/image-indexed-color
Edit Colors: convert embedded images to indexed color
2026-11-14 02:40:36 +07:00
BFlat 6e54257294 Merge pull request #7225 from dotCooCoo/fix/modal-blocks-canvas-touch
Touch: canvas taps, presses and view navigation are ignored while a modal dialog is open
2026-11-14 02:40:15 +07:00
BFlat 90a9e00fdd Merge pull request #7205 from dotCooCoo/fix/svg-interactivity-hide-script-paths
SVG Interactivity: replies name JavaScript files outside the read roots by file name
2026-11-14 02:40:06 +07:00
BFlat 58dd9e8908 Merge pull request #7230 from dotCooCoo/fix/docinfo-hidden-object-paints
Document Info: hidden objects and objects at an opacity of 0 list no brushes or paints
2026-11-14 02:39:39 +07:00
BFlat 4dc9c5c5d3 Merge pull request #7218 from dotCooCoo/fix/batch-fit-journal-index
Artboards: a batch's Fit to Artwork Bounds step journals the artboard it fits
2026-11-14 02:39:07 +07:00
BFlat e718e975b6 Merge pull request #7104 from dotCooCoo/feat/actions-record-into-selected
Actions: Begin Recording adds steps to the selected action, and a drag moves a step
2026-11-14 01:54:47 +07:00
BFlat ca8e49e9e2 Merge pull request #7158 from dotCooCoo/fix/export-unused-option-warning
Export: warnings name an option the chosen format doesn't read
2026-11-14 01:54:29 +07:00
BFlat 820b82b8d3 Merge pull request #7188 from dotCooCoo/fix/color-gamut-cache-profile
Color: the out-of-gamut warning updates after a profile change
2026-11-14 01:54:13 +07:00
BFlat a8db64db47 Merge pull request #7208 from dotCooCoo/feat/live-paint-selection-cursors
Live Paint Selection: cursor shows a face, an edge or nothing to select
2026-11-14 01:54:04 +07:00
BFlat 5010861362 Merge pull request #7199 from dotCooCoo/fix/close-background-tab-keeps-front
Documents: closing a background tab keeps the document in front
2026-11-14 01:53:56 +07:00
BFlat 9bad58b73e Merge pull request #7215 from dotCooCoo/fix/new-profile-errors-hide-path
New Document profiles: errors name the profile file by its file name outside the read roots
2026-11-14 01:53:47 +07:00
BFlat 1c1bb2f96e Merge pull request #7191 from dotCooCoo/feat/gradient-hue-blend
Gradients: Hue Clockwise and Hue Counterclockwise mix stops around the hue wheel
2026-11-14 01:53:39 +07:00
BFlat 26869d1754 Merge pull request #7197 from dotCooCoo/fix/item-4498
Arrowheads: keep agents to the arrowheads file inside their read roots
2026-11-14 01:53:29 +07:00
dotCooCoo c367e8d0f3 Touch: canvas taps, presses and view navigation are ignored while a modal dialog is open
With Enable Touch Gestures on, a two-finger tap on the canvas undid and a
three-finger tap redid even while a modal dialog was open, and in the Touch
workspace a two-finger tap switched modes behind it. Fingers already down
when a dialog opened could still complete a tap when they lifted, during
the dialog or after it closed.

While a modal is open, from the frame it opens:
- no finger tap runs a command and no multi-finger gesture begins; the
  fingers already down are forgotten, so lifting them later runs nothing
- a primary press does not reach the tool, a middle-button press does not
  start a pan, and a double-click does nothing
- a long touch does not drop the canvas press
- a click in Presentation Mode does not step to the next artboard
- a pinch, wheel turn or trackpad rotation does not move the view, and the
  rest of a wheel turn made under the dialog is dropped after it closes;
  a new wheel turn after the dialog closes moves the view at once

Docs: docs/target-app-parity.md, docs/mcp.md.
2026-11-13 10:16:40 -08:00
dotCooCoo 1da59bfb22 Document Info: hidden and clear objects list no brushes or paints
Brushes, Spot Color Objects, Pattern Objects and Gradient Objects left
out a fill or stroke that was hidden or at an opacity of 0, but still
listed an object that was itself hidden or at an opacity of 0, and the
objects inside such a group or layer. They now leave those out, their
characters' paints and colorized images included. With Selection Only,
an object selected inside a hidden group or layer, or one at an
opacity of 0, is left out too. Objects still counts every object.
2026-11-13 09:54:35 -08:00
BFlat 608830d683 Merge pull request #7162 from dotCooCoo/fix/actions-recording-limit-notice
Actions: script runs and tool edits name a recording limit as they end
2026-11-14 00:52:08 +07:00
BFlat 7553c1f679 Merge pull request #7182 from dotCooCoo/feat/objects-on-path-detach
Objects on Path: Detach takes the chosen object off the path
2026-11-14 00:51:59 +07:00
BFlat 2814e3e53d Merge pull request #7192 from dotCooCoo/feat/context-menu-smooth
Context menu: Smooth… on a selected path opens the Smooth slider
2026-11-14 00:51:29 +07:00
BFlat c7adea5518 Merge pull request #7144 from dotCooCoo/fix/script-line-numbers
Scripts: $.line and $.stack give the line of the file the code is in
2026-11-14 00:51:19 +07:00
BFlat e41ef1ea62 Merge pull request #7148 from dotCooCoo/fix/blend-without-spine-widget
Blend: a blend without a spine shows the Appearance widget
2026-11-14 00:51:09 +07:00
BFlat 3378e390ab Merge pull request #7175 from dotCooCoo/fix/graph-series-group-appearance
Graphs: Appearance commands and graphic styles given a series group edit its marks
2026-11-14 00:51:00 +07:00
BFlat 4f0d3f1eb3 Merge pull request #7111 from dotCooCoo/fix/freehand-tolerance-low-zoom
Pencil: Fidelity keeps its screen size at low zoom
2026-11-14 00:50:47 +07:00
BFlat 637d51df79 Merge pull request #7143 from dotCooCoo/feat/guides-layer-rows
Layers: ruler guide rows have their own eye and lock, and go to the trash
2026-11-14 00:50:35 +07:00
BFlat 211c673ee2 Merge pull request #7186 from dotCooCoo/fix/mcp-window-capture-private-temp
MCP: an old app's window capture goes through a private temporary folder
2026-11-14 00:50:17 +07:00
BFlat 1f67fa13a5 Merge pull request #7190 from dotCooCoo/fix/item-4475
Expand: type reports a gradient only when Fill expands one of its outlines
2026-11-14 00:50:08 +07:00
BFlat c1c06a839a Merge pull request #7183 from dotCooCoo/feat/pdf-long-pages-points-default
PDF: pages longer than 200 in are written at full size in points by default
2026-11-14 00:49:30 +07:00
BFlat 3904a7396c Merge pull request #7120 from dotCooCoo/feat/revolve-graphics
3D and Materials: wrap graphics around the side of Revolve objects
2026-11-14 00:49:21 +07:00
dotCooCoo 81d19f1718 Edit Colors: convert embedded images to indexed color
Edit > Edit Colors > Convert to Indexed Color... (edit.colors.toIndexed)
stores the embedded images in the selection as indexed-color PNGs: a
palette of at most 256 RGB colors, each pixel the index of one. The
dialog previews live and OK is one undo step.

- The palette is chosen as for a PNG-8 export (selective, perceptual,
  adaptive, web, gray, black and white), as evenly spaced levels of red,
  green and blue (uniform), or from the document's swatches. Dithering
  is diffusion, pattern, noise or none, with an amount.
- Pixels under half opacity become one transparent entry; the others
  become opaque in their own color. Linked images, colorized images and
  color glyph images keep their pixels.
- An image that is already an indexed PNG and would show the same pixels
  is left as it is, and no undo step is recorded when no image changes.
- An image of more than 134,217,728 pixels (33,554,432 in the web app)
  is refused, read from its header before decoding.
- With Select All, locked and hidden objects that hold an image that is
  not an indexed PNG yet are counted in notChanged, without converting
  them.
- The quantizer gains quantize_to, which maps pixels to a given palette.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-11-13 09:49:00 -08:00
dotCooCoo d2be559b55 New Document profiles: errors name the profile file by its file name outside the read roots
file.newProfiles.edit and file.newProfiles.reset returned the automation
access check and file system errors with the profile file's whole path,
so a client confined to read roots that leave out the preferences folder
learned where the folder is. The errors now go through naming_in_error,
like other paths the client did not give: whole inside the read roots,
otherwise by file name. docs/mcp.md and the params text say so.
2026-11-13 09:40:38 -08:00
dotCooCoo f5de590dee SVG Interactivity: replies name JavaScript files outside the read roots by file name
With automation read roots in force, svgInteractivity.info and the files
reply of addFile and removeFile returned every linked JavaScript file as
stored, including paths outside the roots. They now name such a file by
its file name alone, as document.json does; a file inside the roots and
a URL are named as they are, and the document keeps every path.

removeFile also unlinks a file outside the roots by that file name. When
the name fits more than one linked file, it returns an error that names
no stored path and unlinks nothing. addFile still treats only the same
text as already linked.

In a frame a request drives, the JavaScript Files dialog lists such a
file by its file name while its selection keeps the file as linked, and
ui.inspect gives the selected file the same way. The person's frames
show full paths.
2026-11-13 09:32:19 -08:00
dotCooCoo 6462060928 Merge main into fix/export-unused-option-warning 2026-11-13 09:15:25 -08:00
dotCooCoo 2e8a90d6e4 Artboards: a batch's Fit to Artwork Bounds step records the batch's artboard
When a Fit to Artwork Bounds step of `command.batch` takes the batch's
`artboard` as its `index`, the batch's journal entry now records that
`index`. Before, the entry kept the step without it, so a replay with the
Artboard tool choosing two or more artboards fitted those instead.

The params text, docs/mcp.md and docs/target-app-parity.md state that the
step uses the Artboard tool's selection only when two or more artboards
are selected, and the active artboard otherwise.
2026-11-13 09:12:29 -08:00
dotCooCoo 0a7bf3a7e2 Live Paint Selection: cursor shows a face, an edge or nothing to select
The Live Paint Selection tool always showed the plain arrow. Its cursor
now says what a click at the pointer selects, by the same rules as the
click (Alt, Select Fills, Select Strokes, locked, hidden and isolated
groups): the arrow with a filled square over a face, with a short line
between two anchor marks over an edge, and with an x where a click
selects no face or edge. From a press to the release the cursor keeps
the look it had at the press. Use Precise Cursors shows the crosshair.

- Cursor: LivePaintSelectFace, LivePaintSelectEdge and
  LivePaintSelectOutside, with cursors.toml entries and drawn glyphs.
- Tests: live_paint_selection_cursor_shows_what_a_click_selects,
  live_paint_selection_shows_the_arrow_with_a_face_edge_or_x_badge, and
  the precise-cursor list.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-11-13 09:10:18 -08:00
dotCooCoo cbde1630a1 Documents: closing a background tab keeps the document in front
file.close {index} on a tab other than the current one made the
document now at the closed index current and reset the tool, so the
document the user was working in went to the back. The current
document now stays current, found by its id as document.move does, and
its tool keeps its state. Closing the current tab still makes its
neighbor current.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-11-13 09:05:44 -08:00
BFlat 60fd4bd644 Merge pull request #7090 from dotCooCoo/feat/pixel-snapping-options
View: Pixel Snapping Options choose whether Snap to Pixel snaps drawing, moving and scaling
2026-11-13 23:58:35 +07:00
BFlat 6a1b4c42de Merge pull request #7040 from dotCooCoo/fix/nested-link-ids
Links: list and manage linked art in symbols, graph designs, patterns and masks by id
2026-11-13 23:58:20 +07:00
BFlat a9613094a9 Merge pull request #7171 from dotCooCoo/fix/ai-export-art-bounds
.ai export: a .ai of the art's bounds carries no editing data
2026-11-13 23:58:07 +07:00
dotCooCoo 67601f748f Merge main into fix/color-gamut-cache-profile 2026-11-13 08:57:25 -08:00
dotCooCoo bed4e9aa4b Merge main into fix/graph-series-group-appearance 2026-11-13 08:50:06 -08:00
BFlat 10c84a909e Merge pull request #7173 from dotCooCoo/fix/assigned-profile-follows-front-document
Color: assigned profiles follow the document in front
2026-11-13 23:45:03 +07:00
dotCooCoo b018a849ab Arrowheads: keep agents to the arrowheads file inside their read roots
Under automation read roots, stroke.arrowheads.list gives `file` as
null for an arrowheads file outside them and names it by its file name
in `error`. stroke.arrowheads.edit and stroke.arrowheads.reload refuse
such a file with the root-check error, naming it by its file name:
edit makes no folder or file and neither opens nor activates the file,
and reload does not read it. Inside the roots, edit opens the file
under the client's roots. The Stroke panel menu is not confined.
2026-11-13 08:42:37 -08:00
dotCooCoo d1c8ff78de Context menu: Smooth… on a selected path opens the Smooth slider
A right-click on a selection that holds a path (a path, a group of
paths, a compound path, or anchors selected with Direct Selection) lists
Smooth…, after Join and Average… and the anchor entries when those are
listed. It opens the slider that Object › Path › Smooth opens, which
previews the result until OK keeps it as one undo step. With nothing,
only type or a group of type selected, Smooth… is not listed.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-11-13 08:35:40 -08:00
dotCooCoo 6b5e596de0 Color: the out-of-gamut warning updates after a profile change
The Color panel and Color Picker cached their out-of-gamut warning and
correction for the last color only. Assigning the document another CMYK
profile, removing it, or changing the working CMYK space in Color
Settings left the old warning showing until the color changed.

The cache entry now also holds the active color settings and the
registered profiles' generation, so the warning is checked again when
either changes. The comments and the color.gamutCheck params text name
the CMYK space actually used: the document's assigned CMYK profile, else
the working CMYK space.
2026-11-13 08:35:13 -08:00
BFlat a2adbf61e6 Merge pull request #7106 from dotCooCoo/feat/custom-toolbar-dock
Toolbars: toolbars made with New Toolbar dock along the window's edges
2026-11-13 23:32:06 +07:00
BFlat 4c072b320c Merge pull request #7136 from dotCooCoo/fix/command-batch-artboards
Artboards: a batch's Fit to Artwork Bounds step fits every selected artboard
2026-11-13 23:31:28 +07:00
dotCooCoo bc7eddeb5d Expand: type reports a gradient only when Fill expands one of its outlines
object.expand.info reported a gradient (and a fill) to expand for any
type whose characters have a gradient fill. Expand outlines type first,
and each outline then holds the run's gradient on its own box, so a
gradient that repeats or reflects in more than 256 runs across every
outline stays a gradient: the dialog enabled options that changed
nothing.

- The query now measures the paths type.createOutlines makes of the
  glyphs, ruby glyphs and underline and strikethrough bars, each with
  its run's paint, and reports a gradient when one of them expands. It
  lays the text out only when a run has a gradient fill, stops at the
  first outline that expands, and does not change the document. Type in
  symbol art, blends and repeats goes through the same check.
- docs/mcp.md says when gradient is false; docs/target-app-parity.md
  gets an evidence line.
2026-11-13 08:27:09 -08:00
dotCooCoo 5f77b65aa2 Gradients: Hue Clockwise and Hue Counterclockwise mix stops around the hue wheel
The Gradient panel's Method menu gets two methods of VectorCraft's own
beside Classic and Perceptual. They mix a linear, radial, conic or
diamond gradient's colors around the hue wheel: hue, saturation and
brightness each change evenly from one stop to the next, and the hue
angle keeps one direction, as the fixed-direction rules of
https://www.w3.org/TR/css-color-4/#hue-interpolation do. Hue Clockwise
lowers the angle (red, magenta, blue), which is clockwise on the color
wheels, and Hue Counterclockwise raises it (red, yellow, green).

Two stops whose hues are less than half a color level apart count as
one hue and keep it, so a color and a tint or shade of it do not turn
the whole wheel. A stop whose RGB numbers are less than half a color
level apart is gray and takes the hue of the stop it mixes with, and
black takes that stop's saturation too.

- `paint.editGradient` and `paint.setFill` take `method: hue-clockwise`
  or `hue-counterclockwise`, in any case, with a space or an underscore
  for the hyphen or without it; other spellings are an error. The native
  file writes `HueClockwise` and `HueCounterclockwise`.
- The canvas and raster exports draw the gradient through stops on its
  curve, within half a color level.
- Reverse turns the method the other way with the stops, and a Reflect
  spread is repeated from the curve's stops, so both keep the colors.
- SVG and PDF write the gradient as an RGB image, CMYK and spot color
  stops included, with the spot warning. EPS writes a shading in process
  colors with a warning for spot stops. A legacy .ai file and the .ai
  editing data get the colors between the stops as stops of their own,
  in process colors, at most 256, with a warning. CSS gets those stops
  too.
- The `method` error names the four values, in every catalog.
- The Method menu is as wide as its longest name in the interface
  language, within the panel.

Docs: docs/mcp.md, docs/plugins.md, docs/target-app-parity.md, ROADMAP.
2026-11-13 08:26:57 -08:00
dotCooCoo d41cf0d053 Merge main into feat/objects-on-path-detach 2026-11-13 08:26:49 -08:00
dotCooCoo c9d85d61db Merge main into feat/actions-record-into-selected 2026-11-13 08:24:12 -08:00