Commit Graph
305 Commits
Author SHA1 Message Date
bflatastic 92c1657334 i18n: Chalk & Charcoal, Graphic Pen, Reticulation and Plastic Wrap in every catalog that has the Sketch filters (#2972, #2967, #2976, #3034)
Also cargo fmt over the four filters.
2026-10-20 03:14:27 +07:00
nrq6993-a11yandCursor cfea906681 G1: Mesh point drags show dX/dY in measurement labels
Honor Measurement Labels while moving gradient-mesh and mesh-envelope
points with the Mesh tool or Direct Selection.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-20 02:48:08 +07:00
nrq6993-a11yandCursor 361ebd29bf G1: Free Distort corner drags show dX/dY measurement labels
Honor Measurement Labels during envelope-style corner drags on the Free Transform tool, matching the Move handle readout.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-20 02:37:03 +07:00
bflatastic 85163a7c82 Tests: the Snap to Glyph test says what it checks (#3124) 2026-10-20 02:23:34 +07:00
bflatastic 88a444ef7b fmt (#3124) 2026-10-20 02:23:34 +07:00
nrq6993-a11yandCursor 0c62d9c02c G4: View › Snap to Glyph snaps new type to live-text guides
Wire the View menu toggle and add glyph baselines and bounds to drawing snap targets so point type placement lines up with existing text when Smart Guides are on.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-20 02:23:34 +07:00
bflatastic cb229ac08c fmt (#3121) 2026-10-20 02:23:33 +07:00
nrq6993-a11yandCursor 88bd9bcd9e G4: Touch Type drag test treats omitted zero dx as no kerning
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-20 02:23:33 +07:00
nrq6993-a11yandCursor 222ec72e28 G4: Touch Type arrow keys nudge the selected character
Keyboard increment (Shift ×10) moves the active glyph through text.touchType, with vertical type remapping like the Type tool.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-20 02:23:33 +07:00
bflatastic b8f9c403a7 Measure: with Measurement Labels off the measured line still draws, only its readout goes (#3128) 2026-10-20 02:23:33 +07:00
nrq6993-a11yandCursor 6ef9f2dd93 G1: Measure tool honors Measurement Labels preference
Hide the preview line and readout when Smart Guides › Measurement Labels is off; options still report the last drag.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-20 02:23:33 +07:00
nrq6993-a11yandCursor fd53416de3 G1: honor Show Measurement Labels on pie, corners, width, and tiling readouts
Tools that showed distance or angle overlays during drags now respect the
Units preference, consistent with shape and selection tools.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-20 02:23:33 +07:00
bflatastic d507a73d09 fmt (#3114) 2026-10-20 02:23:33 +07:00
nrq6993-a11yandCursor 6d713de980 G1: Crop Image honors Smart Guides measurement labels.
Gate the crop size readout on the preference and show it at the pointer while dragging the box.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-20 02:23:33 +07:00
bflatastic 9435c5079d fmt (#3099) 2026-10-20 02:23:33 +07:00
nrq6993-a11yandCursor 1eac4f5b79 G1: Graph tools show W/H measurement labels while dragging plot area
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-20 02:23:33 +07:00
nrq6993-a11yandCursor 99aa4e6a7c G1: hide bounding box while dragging type-on-path brackets.
Match corner-radius and pie-widget drags: the Selection tool reports a transforming drag so the canvas drops the sharp selection box during bracket moves.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-20 02:23:33 +07:00
bflatastic bb32072be9 fmt (#2983) 2026-10-20 01:48:35 +07:00
nrq6993-a11yandCursor 5bf159d5d1 G1: show distance and angle on Pen, Line and Curvature rubber bands
Measurement labels while drawing now match the Measure tool (D, angle, dX/dY) when the preference is on.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-20 01:48:35 +07:00
nrq6993-a11yandCursor d41af02637 G1: Spacing Guides snap bounding-box resizes to equal gaps
Smart Guides spacing now applies when scaling with the Selection and Free Transform tools, not only on moves.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-20 01:48:35 +07:00
bflatastic 819da290f1 Pencil: Alt key toggles to Smooth Tool is kept with the tool's other options, and Georgian has its label (#2685) 2026-10-20 01:30:19 +07:00
bflatastic 303c5f8bca Pencil: Alt key toggles to Smooth Tool starts off, as Pencil Tool Options ships it (#2685) 2026-10-20 01:19:14 +07:00
krinry de985a46e6 Pencil: Alt key toggles to Smooth Tool (#2001) 2026-10-20 01:18:45 +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
bflatastic 7e1095f9b1 Tests: the Type arrow tests drop their debug prints (#3004) 2026-10-19 23:14:09 +07:00
sungjea kimandClaude Opus 5.5 515569470c Anchor Point tool: Shift-drag on an anchor moves it, handles and all
With the Anchor Point tool, a drag from an anchor pulls out smooth handles.
Shift held at the press now moves the anchor instead, its handles keeping
their offsets; Shift kept down during the drag keeps the move at 45° steps
(the constrain angle), released it frees it. A Shift-click that doesn't
move leaves the anchor as it was. A selected blend's spine points follow
the same rule (object.blend.spine.moveAnchor).

The move goes through a new engine command, path.moveAnchor
{id, subpath?, anchor, x, y}, since path.moveAnchors only acts on the
direct-selected anchors and the Anchor Point tool keeps no anchor selection.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 22:19:53 +07:00
sanyamsingh001andCodex c07945b934 fix: keep wrapped Type fallback on grapheme boundaries
Co-authored-by: Codex <noreply@openai.com>
2026-10-19 22:19:53 +07:00
sanyamsingh001andCodex de4c6b1a6d fix: keep Type arrows on grapheme boundaries
Co-authored-by: Codex <noreply@openai.com>
2026-10-19 22:19:53 +07:00
NetterSilverandClaude Haiku 5.5 3eed3be8e6 Stop locked guide objects from blocking marquee selection
Fixes #3036

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 22:19:42 +07:00
dotCooCoo 219253f163 Objects on Path: attach objects to a path and spread them along it
VectorCraft had no Objects on Path. A click with the Objects on Path
tool attaches the selected objects to the path clicked. The tool is in
Edit Toolbar's Modify section and the Blend tool's flyout, and Object ›
Objects on Path › Attach and the context menu with two or more objects
selected choose it. The objects and the path go into an Objects on
Path group with the path at its bottom.

- object.objectsOnPath.attach orders the objects column by column from
  left to right and top to bottom in each column. The first one sits
  on the path's first anchor, the last one sits on the end of an open
  path, and the rest are spread evenly by length; a closed path takes
  them all the way round. Each object's attachment point (Pivot, one
  of nine, default the center of its bounds without strokes) sits on
  the path, and the object is turned to the path there. An object that
  was rotated by an angle other than a multiple of 90° is first turned
  to the nearest multiple of 90°. Rotate tilts every object by that
  many degrees counter-clockwise. Symbol instances are measured by
  their art. Guides, compound paths, type, paths without length and
  graphs are refused with a reason.
- After every edit the objects go back on the path: editing the path
  moves them, an object moved on its own goes back, and objects moved
  into or out of the group in the Layers panel join the end of the
  path or leave it. Scaling, shearing or reflecting the whole group
  keeps each object's scale, shear or reflection, and the objects are
  spread evenly along the transformed path again. Undo takes the path
  and the objects back in one step, and a copied group stays live on
  its own path.
- object.objectsOnPath.options changes Pivot and Rotate, and
  object.objectsOnPath.expand leaves a plain group. Both act on the
  groups that `ids` names, or on the groups of the selection when
  `ids` is not given.
- The native file keeps the group live; SVG, PDF and the other exports
  write plain art. The tool highlights the path under the pointer, has
  a cursor entry, and Escape during a press cancels the click.

Part of #2545

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-19 21:51:32 +07:00
dotCooCoo e6c8ce1759 Live Paint: Live Paint Selection Tool Options set what a click selects and the highlight
Double-clicking the Live Paint Selection tool did nothing, and the tool
always selected faces and edges and highlighted them in red at 4 px.
It now opens Live Paint Selection Tool Options with Select Fills,
Select Strokes, Color and Width, the options the reference app's help
page on selecting objects lists.

- With Select Fills off, a click selects the edge nearest the pointer,
  as Alt-click does. With Select Strokes off, Alt-click selects the
  face under the pointer, as a click does. With both off, a click
  selects no face or edge.
- Color (a layer color or a custom color) and Width (1 to 20 px) set
  the highlight on the face or edge under the pointer.
- The defaults are the earlier behavior: both selections on, red
  (#ff2a2a) and 4 px. The options are tool options (tool.setOption
  {tool: "livePaintSelection"}): they last across tool switches and
  are saved with the preferences.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-19 21:51:31 +07:00
nrq6993-a11yandCursor 49f7f5d7d8 G1: busy cursor during background open, save and export
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-19 00:26:27 +07:00
dotCooCoo 09a6fbe470 Type: a click away from the text being edited ends editing without making new text
While a Type tool edited text, a click on blank canvas ended the
editing and also placed new point type at the click. Area Type and
Type on a Path did the same with a click on a path.

Such a click now only ends the editing. The typing session is
committed, empty point type that a click placed is discarded as before,
and the Type tool in use stays active; the next click makes new type.
The same applies when the editing began with a double-click from a
selection tool. A click on other type still edits it at once, and a
drag that draws an area-type frame still makes the frame.
2026-10-18 23:50:57 +07:00
bflatastic 9938a31c9b Pencil: a stroke that starts and ends on a selected path redraws the section between (Edit Selected Paths, #2850)
path.freehand takes redraw: {id, within}: the stroke's ends are placed on the path, anchors added there, and the section between them replaced by the fitted stroke, the shorter way round a closed subpath; a stroke that doesn't end on the path still draws a new one. The Pencil and Paintbrush send it for a stroke that starts on a selected path's outline away from its ends, within Edit Selected Paths' distance.
2026-10-18 20:12:47 +07:00
AJ Richardson 411f5f7680 prioritize bounding-box handles over mirror axis 2026-10-18 19:02:44 +07:00
AJ Richardson 63cebd392a Add interactive Mirror Repeat axis controls 2026-10-18 19:02:44 +07:00
dotCooCoo 282ed8955b Slices: resizing a slice snaps as drawing one does
Dragging a user slice's edge or corner handle with the Slice Selection
tool never snapped, while drawing a slice with the Slice tool snaps to
the grid, to whole pixels, to the art and to the ruler guides.

The handle drag now gathers its targets when the handle is pressed and
snaps what the handle moves through PointSnap::snap_scale, as the
Selection tool's bounding-box handles do: to the nearest gridline with
Snap to Grid, to whole pixels with Snap to Pixel, to the art and the
artboards with Smart Guides, and with Smart Guides off to the art's
anchors and the ruler guides with Snap to Point. Then a shown, unlocked
ruler guide within 5 px moves the side or corner onto it, as the Slice
tool moves a drawn slice's corner onto a guide. Shift still keeps the
proportions, and Alt still resizes about the center.

Docs: docs/target-app-parity.md.
2026-10-18 12:40:11 +07:00
dotCooCoo 034ef916ad Selection: a Shift-constrained move that snaps stays on its line
A move that Shift kept level, upright or on a diagonal left that line
when it snapped. With View › Snap to Grid on, a level Shift-drag also
moved the selection up or down onto a gridline, and Snap to Pixel,
Smart Guides and Snap to Point moved it off the line in the same way.
Each axis snapped on its own after Shift had constrained the move.

With the Selection tool, and with Group Selection and Direct Selection
moving whole objects, a Shift-constrained move now slides along its
line until it snaps. With Snap to Grid or Snap to Pixel, the move
slides along the line by the shorter of the two distances that put it
on a gridline or a whole pixel on either axis. The bounds line up with
the other objects, or space evenly with them, only on the axes the line
runs along, and the grabbed point stops where the line passes an anchor
or crosses a ruler guide. A level or upright move snaps along its own
axis only. Moves without Shift snap as before.

Docs: docs/target-app-parity.md.
2026-10-18 12:40:10 +07:00
dotCooCoo 2643f57b1f Color: type, gradient, mesh and swatch commands store RGB input as color-managed CMYK in a CMYK document
In a CMYK document, paint.setFill stores an RGB color as CMYK through
the color settings, but the other commands that take a color stored it
as RGB: text.create, text.createInPath, text.setStyle and
text.setRangeStyle colors, a shapeBuilder.merge hex fill,
paint.editGradient stops, freeform gradient points, gradient mesh
points, the Symbol Stainer's color, and swatch.new {colors},
swatch.newGroup, swatch.editGroup and swatch.edit. The Mesh tool sent
the fill as a hex value, so a CMYK fill came in as RGB.

These commands now store such a color through paint::new_color, as
paint.setFill does, and take keepModel to keep RGB (shapeBuilder.merge
inside its fill object). A color the swatch
or gradient already has keeps its model, so stops sent back with a
moved offset keep their colors (the Gradient panel's ramp and the
Gradient tool send keepModel), and a stop that names a process
swatch takes the swatch's color as it is, in paint.setFill gradients
too. Where the app copies an existing color, it keeps the color's
model: the Color panel's sliders for gradient stops and freeform
points, a swatch put on a stop or a point (the stop popover, Alt-click
in the Swatches panel, a drop on the Gradient panel's ramp), the fill
the Mesh tool gives a new point or the Symbol Stainer applies, and the
colors the Color Guide, Color Themes and Recolor Artwork save as
swatches.

swatch.new {color, mode} converted RGB into CMYK before converting it
into mode, so the New Swatch dialog in RGB mode stored #00ff00 as
R101 G176 B62 in a CMYK document. With mode, the color is now
converted once.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-18 12:34:40 +07:00
dotCooCoo 438d27ffbe Selection: a marquee selects an Intertwine group or a repeat only where it meets their art
A marquee measured an Intertwine group and a repeat by their bounding
box. A marquee in the gap between two members of an Intertwine group,
or between two copies of a repeat, selected the object, although a
click there misses and a plain group needs a marquee to meet one of its
members. Direct and Group Selection's marquees also selected the
Intertwine group whole beside the anchor points of its members.

The marquee now touches an Intertwine group by its members, as it
touches a plain group, and it touches a repeat by the copies the repeat
draws, as clicks hit them. Direct and Group Selection's marquees select
the anchor points of an Intertwine group's members, and Group
Selection's E marquee selects the members inside it. Blends, and
envelopes outside Edit Contents, keep their box, as clicks on them do.

Docs: docs/target-app-parity.md.
2026-10-18 12:34:38 +07:00
dotCooCoo 7d56260b47 Shaper: the Lasso, Smart Guides and the anchor tools skip a Shaper Group's original shapes
A Shaper Group keeps its original shapes as its first child, at no
opacity, and clicks do not pick them outside Construction mode. The
Lasso, the Add Anchor Point, Delete Anchor Point, Anchor Point and
Scissors tools still picked their anchor points and segments, also
where the group erased the face, and Smart Guides, Snap to Point and
the transform tools' reference point snapped to them. The Lasso and
the anchor tools also picked art outside the isolated group or object
in isolation mode.

The Lasso and the anchor tools now visit only the art a click can pick:
the isolated object in isolation mode, and a Shaper Group without its
original shapes unless they are isolated (Construction mode). Smart
Guides and Snap to Point leave the original shapes out of their
targets, and Spacing Guides leave out their bounds when a face moves.
The transform tools' reference point snaps to an original shape only
when that shape is selected, or under the pointer in Construction
mode. The Shaper Group test document moves into the shared test
helpers.

Docs: docs/shaper.md, docs/target-app-parity.md.
2026-10-18 12:34:37 +07:00
dotCooCoo 23dd9a1f2a Fix #2054: bounding-box resize handles snap to the grid, pixels, points and ruler guides
A bounding-box handle dragged with the Selection or Free Transform tool
snapped only with Smart Guides on, and then only to the other objects
and the artboards. View > Snap to Grid, Snap to Pixel, Snap to Point
with Smart Guides off and the ruler guides did not move it, while a
move snaps to all of them.

The corner or side a handle moves now snaps as a dragged point does.
With Snap to Grid on it lines up with the nearest gridline, and with
Snap to Pixel on it lines up with whole pixels. With Smart Guides off,
Snap to Point lands it on the other objects' anchors and on ruler
guides within its distance. With Smart Guides and Snap to Point both
on, it lines up with the ruler guides as well as with the other
objects. Shift still keeps the proportions. Without Alt the opposite
side stays put, and with Alt the box still scales about its center.

Docs: docs/target-app-parity.md.
2026-10-18 01:27:14 +07:00
dotCooCoo 8fbd515d6c Shaper: a marquee does not select a Shaper Group by the original shape of an erased face
A Shaper Group keeps its original shapes as a transparent first child.
Clicks skip them outside Construction mode, but a marquee did not: one
drawn over the outline of an original shape whose face the group had
erased selected the group, where nothing is shown. Group Selection's E
marquee selected an original shape that lay inside it, and Direct
Selection's marquee and clicks selected the anchor points of the
original shapes.

The marquee now skips a Shaper Group's original shapes with the same
check clicks use, which moves into shaper_hides, and Direct Selection's
walk over the art it can pick skips them too. In Construction mode, with
the original shapes isolated, the marquee still selects them and Direct
Selection still selects their anchor points.

Docs: docs/shaper.md, docs/target-app-parity.md.
2026-10-18 01:21:28 +07:00
makesomethingshit 85afe7caaf test(blend): preserve Shift reshape after main rebase (#2544) 2026-10-18 01:11:39 +07:00
makesomethingshit 92e33b1579 fix(blend): preserve Anchor Point picking priority (#2544) 2026-10-18 01:11:39 +07:00
makesomethingshit fa9a52bd71 fix(blend): match cursor, Shift radius and hidden-handle cases (#2544) 2026-10-18 01:11:39 +07:00
makesomethingshit 5f70f96a66 style(tools): match rustfmt in rebased spine anchor test (#2544) 2026-10-18 01:11:39 +07:00
makesomethingshit 10ae4cc5a8 fix(blend): align spine anchor picking, Shift drag and handle visibility (#2544)
- Prefer the anchor over a short handle within tolerance, like hit_handle.
- Pick the nearest eligible spine point and handle.
- Constrain Shift handle drags to 45-degree steps round the anchor.
- Hide spine handles with handles_multiple off, in overlays and picking.
2026-10-18 01:11:39 +07:00
makesomethingshit 286a1fb8b3 test(tools): cover blend spine anchor conversion and handle focus (#2544) 2026-10-18 01:11:39 +07:00
makesomethingshit e2b4cef111 fix(blend): route Anchor Point tool through spine anchors and handles (#2544) 2026-10-18 01:11:38 +07:00