Commit Graph
682 Commits
Author SHA1 Message Date
BFlat e1137877ac Merge pull request #6424 from Messhias/feat/g5-style-lib-game-hud
G5: built-in Game HUD graphic style library
2026-11-10 22:19:35 +07:00
BFlat a991ec8dd6 Merge pull request #6432 from ruchirguitar/fix/3565-direct-select-type-path
Direct Selection shows and drags type on a path's direction handles (#3565)
2026-11-10 22:11:14 +07:00
Fabio William Conceição 710e14a33a G5: built-in Game HUD graphic style library 2026-11-10 14:26:37 +00:00
ruchirguitar 74ae6fdd05 #3565: Direct Selection shows and drags type on a path's direction handles
Direct Selection showed and dragged the anchors of type on a path's path
(#3980) but not their direction handles: handle_anchors read only a
path's own data, and the canvas draws only a path's handles.

- text.setPathHandle moves a handle of type on a path's path, in
  document space, as path.setHandle moves a path's; the brackets keep
  their fractions and the text reflows. One undo step.
- Direct Selection draws the handles of selected type on a path and
  drags them with it (Alt: one side, Shift: 45 degree steps).
2026-11-10 19:35:29 +05:30
Julius van der Vaart 5b7325483a Merge branch 'main' of github.com:storytold/vectorcraft into 5421-line-arrowhead
# Conflicts:
#	docs/target-app-parity.md
2026-11-10 09:50:32 +01:00
Julius van der Vaart 8508c9c620 Merge branch 'main' of github.com:storytold/vectorcraft into 5421-line-arrowhead 2026-11-10 09:13:56 +01:00
dotCooCoo 7b44ef5737 Merge main into feat/script-run 2026-11-09 23:43:37 -08:00
dotCooCoo 860149a981 Merge main into feat/text-glyph-bounds 2026-11-09 22:03:17 -08:00
dotCooCoo cc03fade6e Scripts: the growth budget counts every art store, with CLI and source fuzz tests
A document a script opens now counts the art in its graph designs and in
the original of the pattern being edited toward the growth allowance.
`Document::art_roots` and `art_roots_mut` list every tree of a document's
art; `any_node`, `edit_nodes_where` and the script's object count use them.

`script.run` checks the depth of `args` without recursion before it copies
or writes them out, so `args` nested 10,000 levels deep is refused with the
place it went past 64 levels instead of overflowing the stack.

New tests: graph-design art and the growth allowance, `args` nested 10,000
levels deep from a script (a RangeError) and from a caller, `run --cmd
script.run` on the command line with a report and with a thrown error, and
a property test that sends arbitrary source through `script.run`.
2026-11-09 22:00:04 -08:00
dotCooCoo 156613941a Type: glyph bounds take in underline and strikethrough bars
With Measure Type by Glyph Bounds on, point type is measured by its
glyph outlines and its underline and strikethrough bars, as the canvas
draws them. A typed W or H gives what is drawn that size, and underlined
or struck-through spaces are measured by their bars instead of the em
box.

The texts now say that each point type object selected as an object
(not inside a selected group) is measured this way, that moved type
snaps by its ink box, and which Arrange Tools commands follow the
option: Swap Objects, Replace with Top Object, Set Size of Each and
Sort Objects. Arrange in Grid and Group Overlapping Objects keep
measuring visual bounds.
2026-11-09 21:53:22 -08:00
Julius van der Vaart 89482ba940 Stroke: Line Arrow's arms match the line at 100 % only from 0.25 pt (#5421) 2026-11-10 06:48:16 +01:00
Julius van der Vaart c8d7f2cce0 Stroke: Line Arrow's arms take the head's weight, at least 0.25 pt (#5421) 2026-11-10 06:42:19 +01:00
Julius van der Vaart fe487d8226 Merge branch 'main' of github.com:storytold/vectorcraft into 5421-line-arrowhead
# Conflicts:
#	docs/target-app-parity.md
2026-11-10 06:17:42 +01:00
dotCooCoo a1949095c6 Type: an option fits a text object's bounds to its glyph outlines
Measure Type by Glyph Bounds (`typeGlyphBounds`, off by default) is in
Preferences > Type > Glyph Bounds and the Transform panel menu. With it
on, the bounding box, the Transform, Control bar and Properties X, Y, W
and H, `object.setBounds`, the transform tools' reference point and the
Arrange commands measure point type selected on its own by the ink of
its glyphs instead of its em box. A typed W or H scales the live type
until its ink has that size.

- The engine caches each type object's ink in text space with its
  layout bounds; the cache is not saved.
- Use Preview Bounds adds the characters' strokes, and type with
  geometry effects is measured as drawn. Skewed type is measured by its
  outlines.
- Type that draws nothing, area type, type on a path and type inside a
  selected group are measured as before. Align and Distribute keep
  following Align to Glyph Bounds.

Docs: docs/mcp.md, docs/control-protocol.md, docs/target-app-parity.md,
object.setBounds params text.
2026-11-09 21:07:55 -08:00
dotCooCoo 0a7b48503e Merge main into feat/script-run 2026-11-09 20:30:53 -08:00
dotCooCoo 1bf6d2e793 Transform: a butt-capped curve with a handle on its end point stops at that end
With Use Preview Bounds on, a curve piece that bends more tightly than
half the stroke weight after the last split had its box grown by half
the weight on every side. A handle on an end point makes the curve's
first or last control difference zero, so such a curve always reached
that fallback and measured past its butt end: a vertical 2 pt curve
from (50,10) to (50,60) with its first handle on (50,10) measured
Rect(49, 9, 51, 60) instead of Rect(49, 10, 51, 60).

The fallback now measures the piece from the directions its tangent can
take, the nonzero control differences, when they all lie within a
quarter turn of their sum. Pieces whose tangent turns further are still
grown on every side.
2026-11-09 19:47:04 -08:00
Julius van der Vaart b6e49fa4c0 Merge branch 'main' of github.com:storytold/vectorcraft into 5421-line-arrowhead
# Conflicts:
#	docs/target-app-parity.md
2026-11-10 04:40:09 +01:00
dotCooCoo 16da351e5d Merge main into feat/script-run 2026-11-09 19:29:33 -08:00
BFlat 695721f9df Merge pull request #6380 from dotCooCoo/fix/preview-bounds-butt-line
Transform: butt-capped lines measure to their end points with Use Preview Bounds
2026-11-10 09:59:06 +07:00
dotCooCoo dd55adb701 Merge main into feat/script-run 2026-11-09 18:39:42 -08:00
dotCooCoo 2c0d09e079 Scripts: File › Scripts › Other Script… runs JavaScript files
File › Scripts › Other Script… picks a .js or .jsx file, shows a warning
that can be turned off in Preferences › General, and runs the script
against the open documents through the `vc` object. The new
`script.run` and `script.stop` commands run and stop a script over MCP.

- A run is one transaction. Each document it changed gets one undo step
  named Run Script. An uncaught error, a limit or a stop puts every
  document, the paint, the clipboard, menu state and preferences back.
- A command that fails inside a run, or whose result is too large to
  reach the script, is undone and throws an error the script can catch.
- Files a command wrote stay on disk and the report names them, also
  when the run is stopped from the quit question.
- While a script runs, other commands that change anything fail with a
  busy error; MCP reports it as JSON-RPC error -32003.
- In the app the run advances one slice per frame with a Stop button in
  the status bar. A run that adds a great many objects asks whether to
  continue; Stop and Escape end it.
- Commands that change state outside the documents, such as prefs.*,
  plugin.* and file.place.queue, are refused to scripts.

Docs: docs/mcp.md, docs/gaps.md, docs/roadmap.md,
docs/target-app-parity.md.
2026-11-09 18:35:41 -08:00
dotCooCoo bed632cc65 Transform: butt-capped lines measure to their end points with Use Preview Bounds
With Use Preview Bounds on, the visual box of a butt-capped stroke on an
open path grew by half the stroke weight past each end of the path, where
a butt cap paints nothing. A 2 pt vertical line set to H: 10 mm in the
Transform panel drew about 9.3 mm long.

The box of an open subpath with butt caps no longer reaches past its
ends. A straight segment's box comes from the four corners of its stroked
rectangle, and a curve's box comes from the stroke at its ends and where
its tangent is square to an axis. Bevel joins, and miter joins the limit
bevels, are measured by the stroked corners, and round joins by the arc
they paint outside the turn, instead of half the weight all round. Round
and projecting caps, arrowheads, closed paths and miter tips measure as
before. Two cases can still measure larger than the stroke paints: a
curve that bends more tightly than half the weight, and a butt-dashed
path whose first or last dash is a gap, which is measured to the path's
ends.

A horizontal or vertical butt line now measures one stroke weight less
along its length in W or H, and Align places it by its end points. A
slanted line's box shrinks by less: the stroke's corners still reach
past the end points across the line. object.setBounds measures as drawn,
after each scale it tries, a butt-capped open path with a segment at a
slant, symbol instances' art included.
2026-11-09 18:16:48 -08:00
dotCooCoo 7ff3d25697 Part of #5632: Convert to Grayscale stores an image with one gray channel
Edit Colors > Convert to Grayscale wrote the new image as an RGBA PNG, so
a PDF wrote it as DeviceRGB, in a CMYK document too. The image is now
stored as a gray PNG, with alpha only when some pixel is not opaque. Adjust
Colors with mode gray and convert does the same.

An RGB image whose pixels are already neutral now converts, and an image
already stored as gray with no visible change is left as it is.
2026-11-09 16:15:12 -08:00
Julius van der Vaart 7d73882d3a Stroke: Line Arrow arrowhead (#5421)
Add Line Arrow, a 41st generated arrowhead: two arms as thick as the line
(at 100 % scale) meeting at right angles in a sharp tip, cut square at their
ends. It is saved by the new name `LineArrow`, appended so existing names
stay stable, and listed third in the arrowhead menus after Arrow (open).

Its arms spread four weights either side of the line, twice as wide as the
other heads, so Arrowhead now states its own reach and half width. Visual
bounds and clicks on the canvas (head_reach, head_contains) use them instead
of one fixed 4.6 x 2 box; every other head keeps the sizes it had.

Tests: the outline test checks each head against its own reach and half
width; a new test checks the line arrow's tip, corners, open middle and arm
thickness; outset_covers_arrowheads checks that the wider head grows the
outset; the saved-name list includes LineArrow.
2026-11-09 20:47:31 +01:00
adambelis 585621a661 Blend: the spine keeps only the subpath it samples
Spine stored a full clone of the blend's PathData but only ever read its
first subpath. Store that SubPath instead, which drops the extra
allocation and makes the field's purpose clear. Document the field and
the two cases where Spine::new returns None.
2026-11-09 10:06:49 +01:00
dotCooCoo f29c75a231 Plug-ins: hit tests re-evaluate live art when a swatch or color group changes
A painted live effect's pieces name swatches, so a kept evaluation could outlive a swatch that was renamed or removed and answer a click with art the document no longer draws. The kept evaluation now holds the document's swatches and color groups and is stale when they change.
2026-11-08 19:13:37 -08:00
BFlat c5c1913f48 Merge pull request #6265 from dotCooCoo/feat/plugin-effect-paint
Plug-ins: live effects at API level 2 can paint the pieces they return
2026-11-09 10:50:46 +08:00
dotCooCoo bd5ea2a1bf Merge main into feat/plugin-effect-paint 2026-11-08 17:59:33 -08:00
dotCooCoo c603030252 Merge main into feat/visibility-variables-drive-locked-art 2026-11-08 17:31:05 -08:00
dotCooCoo 3ccc919936 Merge main into feat/visibility-variables-drive-locked-art 2026-11-08 17:30:32 -08:00
dotCooCoo d6a91b6142 Merge main into feat/plugin-effect-paint 2026-11-08 17:26:35 -08:00
BFlat 636ffe78ce Merge pull request #5070 from dotCooCoo/feat/kinsoku-shori-type
Paragraph: Kinsoku Shori Type chooses Push In First, Push Out First or Push Out Only
2026-11-09 09:22:52 +08:00
dotCooCoo 3ea13d88d3 Merge main into feat/kinsoku-shori-type
# Conflicts:
#	crates/engine/src/cmd/panelcmds.rs
2026-11-08 16:47:29 -08:00
dotCooCoo 0ce616da4b Merge main into feat/kinsoku-shori-type
# Conflicts:
#	crates/engine/src/cmd/panelcmds.rs
#	crates/text/src/layout/breaking.rs
#	crates/ui-egui/src/panels/paragraph.rs
#	docs/target-app-parity.md
2026-11-08 16:13:35 -08:00
dotCooCoo e2bac253f1 Merge main into fix/fitted-gradient-turns-with-transform 2026-11-08 15:56:12 -08:00
BFlat d83bb6c0b8 Merge pull request #5058 from dotCooCoo/feat/character-anti-aliasing-method-r
Character: Anti-aliasing Method sets how a type object's edges are drawn as pixels
2026-11-09 07:47:57 +08:00
BFlat 165810aa6c Merge pull request #6104 from dotCooCoo/fix/graph-series-object-opacity
Graphs: a series keeps the object opacity and blend modes set on one of its marks
2026-11-09 07:47:29 +08:00
BFlat 0cb2d5dbd8 Merge pull request #5030 from dotCooCoo/fix/issue-3748-r
Fix #3748: in isolation mode, art outside a clip group's mask can be selected and dragged
2026-11-09 07:46:54 +08:00
dotCooCoo 83f1333d1c Effects: a Transform effect that flattens the object leaves a fitted gradient fitted with its options on
With Scale Strokes & Effects or Transform Patterns on, the path and each copy are moved by Node::transform, which fixed a fitted gradient to its fit before a scale of 0 flattened it to one color. Scaling::keep_fit_when_flat keeps the gradient fitted under a map that flattens the object (node::flattens, the gate fixes_fit already used), and the Transform effect's path transforms set it.

docs/target-app-parity.md also says that the Gradient tool still shows a fitted gradient's vector at its unturned fit.
2026-11-08 15:38:07 -08:00
dotCooCoo da7194030f Merge main into feat/plugin-effect-paint 2026-11-08 15:01:41 -08:00
bflatastic 8e45313501 Blend: the spine's ends are its exact end points 2026-11-09 05:06:28 +07:00
dotCooCoo f88815abd9 Merge main into fix/graph-series-object-opacity 2026-11-08 14:02:59 -08:00
bflatastic d58000b5df Objects on Path: the stretched-group test allows the spine's rounding 2026-11-09 04:52:48 +07:00
bflatastic 863023d7de Blend: a vanished spine tangent takes the curve's direction nearby; the unreachable copy after the loop goes 2026-11-09 04:45:17 +07:00
adambelisandCraft Bot 2709a5191f M2.1: blend Align-to-Path smooth on curved spines
Spine::at_length computed tangents from flattened polyline chords, which
are piecewise constant and jump discretely between chords on curved
spines. Steps oriented to the spine with Align to Path stuttered at
large step counts.

Fix: store the original PathData in Spine and compute the tangent from
the original cubic at the true arc-length position via ParamCurveDeriv,
proportionally mapping flattened arc-length s onto each segment's curve
arclength using anchor_length values, instead of using piecewise-constant
chord directions.

Updated segment-selection condition in Spine::at_length to skip segments
whose flattened end is not greater than start before checking whether s is
within the segment. Preserve the existing final-segment fallback so
at_length(0.0) selects a nonzero segment and uses its tangent.

Added zero-derivative fallback tangent for blend-step sampling to keep
Align to Path from passing a zero tangent to atan2.

Added missing docstrings for Spine::new and Spine::length to satisfy
docstring coverage requirements.

Co-authored-by: Craft Bot <bot@storytold.dev>
2026-11-09 04:42:48 +07:00
adambelisandCraft Bot cb5300415a M2.1: blend Align-to-Path smooth on curved spines
Spine::at_length computed tangents from flattened polyline chords, which
are piecewise constant and jump discretely between chords on curved
spines. Steps oriented to the spine with Align to Path stuttered at
large step counts.

Fix: store the original PathData in Spine and compute the tangent from
the original cubic at the true arc-length position via ParamCurveDeriv,
proportionally mapping flattened arc-length s onto each segment's curve
arclength using anchor_length values, instead of using piecewise-constant
chord directions.

Updated segment-selection condition in Spine::at_length to skip segments
whose flattened end is not greater than start before checking whether s is
within the segment. Preserve the existing final-segment fallback so
at_length(0.0) selects a nonzero segment and uses its tangent.

Added missing docstrings for Spine::new and Spine::length to satisfy
docstring coverage requirements.

Co-authored-by: Craft Bot <bot@storytold.dev>
2026-11-09 04:42:48 +07:00
adambelisandCraft Bot b8d23e280b M2.1: blend Align-to-Path smooth on curved spines
Spine::at_length computed tangents from flattened polyline chords, which
are piecewise constant and jump discretely between chords on curved
spines. Steps oriented to the spine with Align to Path stuttered at
large step counts.

Fix: store the original PathData in Spine and compute the tangent from
the original cubic at the true arc-length position via ParamCurveDeriv,
proportionally mapping flattened arc-length s onto each segment's curve
arclength using anchor_length values, instead of using piecewise-constant
chord directions.

Added missing docstrings for Spine::new and Spine::length to satisfy
docstring coverage requirements.

Co-authored-by: Craft Bot <bot@storytold.dev>
2026-11-09 04:42:48 +07:00
adambelisandCraft Bot 5589049a47 M2.1: blend Align-to-Path smooth on curved spines
Spine::at_length computed tangents from flattened polyline chords, which
are piecewise constant and jump discretely between chords on curved
spines. Steps oriented to the spine with Align to Path stuttered at
large step counts.

Fix: store the original PathData in Spine and compute the tangent from
the original cubic at the true arc-length position via ParamCurveDeriv,
proportionally mapping flattened arc-length s onto each segment's curve
arclength using anchor_length values, instead of using piecewise-constant
chord directions.

Reviewed-by: craft-house-rules

Co-authored-by: Craft Bot <bot@storytold.dev>
2026-11-09 04:42:48 +07:00
Adam Belis 4851736364 M2.x: blend Align-to-Path smooth on curved spines
Spine::at_length computed tangents from flattened polyline chords, which
are piecewise constant and jump discretely between chords on curved
spines. Steps oriented to the spine with Align to Path stuttered at
large step counts.

Store the original PathData in Spine and compute the tangent from the
original cubic at the true arc-length position via ParamCurveDeriv,
instead of flattened chord directions.

Adds a regression test walking 200 samples along a curved spine and
asserting each tangent step stays under 0.1 radians.
2026-11-09 04:42:48 +07:00
dotCooCoo d8ff63f5d0 Merge main into feat/character-anti-aliasing-method-r 2026-11-08 13:24:43 -08:00