Commit Graph
529 Commits
Author SHA1 Message Date
Drew Dibble 3aede6aca2 Merge remote-tracking branch 'upstream/main' into seam-round-joins
# Conflicts:
#	docs/gaps.md
#	docs/target-app-parity.md
2026-11-12 16:30:37 -07:00
Drew Dibble 1032fb3979 Round seams: Classic Rotate and Revolve tests, Wireframe edge, docs
- a_faces_seam_stays_within_half_its_width_of_the_face checks Rotate
  (Classic)'s branches too: No Shading keeps its paint, a gradient keeps
  the gradient, and Diffuse shades its plane darker at some view.
- classic_revolves_seams_are_round checks each seam's reach as well as
  its join, and covers a gradient.
- The Wireframe edge takes seam_stroke (the same stroke it built by hand).
- Docs: which seams went from miter to round and which already were;
  the white-light difference from the 2026-10-17 comparison is expected,
  not measured; the 3D area rows record the change; the performance note
  says its measurement predates the Classic Rotate and Revolve paths.
2026-11-12 16:28:51 -07:00
73b06e478e UI: icon flyouts resize from their top edge and free top corner (storytold/craft-libs#1094) (#6913)
Pin craft-ui to c4b8405d, which adds a top edge and the canvas-side top
corner to icon-strip flyouts and saves the moved top per group. Accept
its new MoveFlyoutTop docking action, and restore the saved top when a
group returns to its place. A docking regression checks the cursors, an
upward top-edge and free-corner drag with the bottom and icon-column edge
fixed, and the top after reopening and in a saved layout.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Codex <codex@openai.com>
2026-11-12 23:54:17 +01:00
Drew Dibble 05fd55bde1 3D effects: every facet's seam has round joins
Each 3D facet is stroked with a narrow seam of its own paint (0.05 to
0.75 pt; Revolve's is always 0.75 pt) so neighboring facets meet without
an antialiasing hairline. In Extrude & Bevel, Inflate and Rotate under a
white light, and in every face of the 3D (Classic) effects (Extrude &
Bevel, Rotate and Revolve (Classic); shaded, No Shading, gradient and
pattern alike), that seam kept the default Miter Join with its limit
of 10. Revolve's seams and the colored-light seams
were already round. A facet seen almost edge-on is a sharp sliver, and
its mitered seam reached up to ten times its half-width past the facet's
tip: thorns of up to 3.75 pt past the solid, along the tops of type seen
tilted and at every edge-on bevel facet.

#2706 (multiple lights) deliberately kept white-light seam joins as they
were, so that legacy white-light output stayed byte-identical to main
(its comment "Preserve existing white-light paints, alpha composition and
seam joins exactly", and four PNGs compared byte for byte). That kept
the thorns too. This change reverses that one part on purpose: the
paints and alpha composition stay exactly as #2706 left them; only the
join changes.

- Outputs change, the document model doesn't. Exports draw the new
  joins (SVG writes stroke-linejoin="round", PDF and .ai draw round
  joins), and Expand Appearance writes round seams into the document.
  But nothing a document stores selects the join, and the format is
  unchanged, so there is no version gate: an old file drawn now simply
  has no thorns.
- Round joins. Projected facets rarely have right-angle corners (a
  square seen at an angle is a parallelogram with acute corners, and an
  exact 90° corner sits at a √2 limit), and round is what the seams of
  colored lights and Revolve already draw. The cost: where a facet has
  no neighbor (Rotate's plane, every silhouette corner) its convex
  corners are drawn rounded by up to 0.375 pt instead of sharp.
  Alternatives weighed and not taken: a Miter Join with a limit near √2
  at every seam, the composed clip included, which would bevel slivers
  but chamfer most projected corners as well; and seaming only the edges
  facets share, or clipping facets to their union as solid_surface
  does, which would keep every outer corner sharp but means a new
  geometry pass for every 3D effect. Round is the smallest change that
  matches the seams already drawn.
- A seam no longer reaches past its facet by more than half its width,
  so the art's visual bounds shrink by up to 3.375 pt where a thorn
  stood (10 × 0.375 less the 0.375 a round seam still reaches).
  White-light output is no longer byte-identical to #2706's comparison;
  docs/3d-lighting-performance.md says so.

Every seam stroke is made by lighting::seam_stroke. The colored clip in
composed_art already outlined its seam with round joins and is
unchanged. Tests: every seam of Extrude & Bevel, Extrude & Bevel (Classic, each
branch), Rotate (Classic), Inflate and Rotate, under white and colored
light, has round joins and reaches no more than half its width past its
face, at views that make a sliver; Revolve (Classic)'s seams are round
on each surface; a mitered seam fails them, and so does the legacy
white-light Inflate test, which now expects Round.
2026-11-12 15:47:18 -07:00
BFlat 87485971b0 Merge pull request #6959 from dotCooCoo/fix/item-transform-later-raster-effects
Effects: a fill's or stroke's own Transform effect leaves the effects listed after it unscaled
2026-11-13 03:28:16 +07:00
BFlat 813b24b0a5 Merge pull request #6835 from dotCooCoo/feat/blend-canvas-easing-handles
Blend: on-canvas widgets set a selected blend's color shift and easing
2026-11-13 02:47:08 +07:00
BFlat d22d3ced48 Merge pull request #6931 from dotCooCoo/fix/eps-cshow-kshow-restore-font
EPS import: cshow and kshow procedures see the font PLRM gives them
2026-11-13 02:46:10 +07:00
BFlat 036c563635 Merge pull request #6820 from dotCooCoo/feat/brushes-ink-wash-library
Brushes: built-in Ink and Wash library with tapered ink, brush pen and wash brushes
2026-11-13 02:46:00 +07:00
dotCooCoo 85b3740cca Effects: a fill's or stroke's own Transform effect leaves the effects listed after it unscaled
Effects apply in the order they are listed, so an effect listed after a
Transform effect applies to the art the Transform effect made, at its
own values, as an object's later effects do after the object's
Transform effect. With Scale Strokes & Effects on, a fill's or stroke's
own Transform effect scaled the effects listed after it in that fill's
or stroke's list by the mean scale: a 300% Transform turned a 5 pt
Offset Path after it into a 15 pt one, and a Drop Shadow after it took
three times its offset. With Transform Patterns or Scale Strokes &
Effects on, an SVG filter after it also had the origin of its user space
moved.

- The effects after such a Transform effect now keep their values, on
  the transformed art and on each copy, on every fill and stroke a
  live-effect plug-in paints the piece with, and when the copies are
  counted against the effect budget.
- With Transform Objects off, the effects before it keep their values
  too.
- The Transform params text, docs/target-app-parity.md and docs/gaps.md
  describe the rule, and drop the note that listed an object's later
  effects keeping their distances as a shortfall.
2026-11-12 10:59:21 -08:00
dotCooCoo 3e46408ab5 EPS import: cshow and kshow procedures see the font PLRM gives them
In a CID-keyed font whose CIDFont the file only names, a cshow procedure
now runs with the CIDFont as the current font, rootfont gives the
composite font, and the procedure gets each code's last byte. A show in
the CIDFont shows the character of that code, and any other string is a
rangecheck error. The current font is restored after each procedure.

A kshow procedure no longer leaves a font it sets current: the current
font is restored when the procedure completes, for every font, and a
kshow the procedure runs sees the font the procedure set.

In GBT-H and CNS2-H, whose mappings are not read, a byte that starts no
row-and-cell code is a code of its own.

docs/gaps.md dates this G9 work in a bullet of its own.
2026-11-12 09:25:14 -08:00
makesomethingshit 777fb2fa42 Merge upstream/main into fix/6865-ai-oversized-artboard 2026-11-13 02:19:20 +09:00
BFlat 2304b38f19 Merge pull request #6907 from dotCooCoo/feat/art-brush-width-pen-pose
Brushes: Art Brush Options' Width can follow the pen's tilt, bearing and rotation
2026-11-12 23:54:29 +07:00
BFlat e618783377 Merge pull request #6084 from Taha-Mahmoodi/feat/glyph-alternates
Glyphs: alternates keep the word joined (feature values, one-piece shaping, unencoded glyphs)
2026-11-12 23:53:13 +07:00
dotCooCoo 9df4a83f07 Merge main into feat/blend-canvas-easing-handles 2026-11-12 08:46:06 -08:00
dotCooCoo fc1a08edbd Merge main into feat/brushes-ink-wash-library 2026-11-12 08:46:00 -08:00
BFlat 3df161a972 Merge pull request #6903 from dotCooCoo/feat/gradient-repeat
Gradients: repeat or reflect a gradient's stops a set number of times
2026-11-12 23:10:02 +07:00
BFlat a38903aa72 Merge pull request #6900 from dotCooCoo/feat/global-edit-highlight-similar
Global Edit: selecting one object highlights the similar objects before the start
2026-11-12 23:08:32 +07:00
BFlat f43d00aa11 Merge pull request #6902 from dotCooCoo/fix/eps-named-cid-show-operators
EPS import: charpath, cshow, kshow and glyphshow read named CIDFont type by its CMap
2026-11-12 23:08:23 +07:00
makesomethingshit c36f863073 Merge upstream/main into fix/6865-ai-oversized-artboard 2026-11-13 00:44:37 +09:00
dotCooCoo 04fd1b127b Brushes: Art Brush Options' Width can follow the pen's tilt, bearing and rotation
The Width menu now offers Tilt, Bearing and Rotation beside Fixed and
Pressure, each with the second width. Tilt goes from Width with the pen
lying flat to the second width upright; Bearing and Rotation go from
Width at -180 degrees to the second width at 180 degrees, as Scatter
Brush Options' modes do. A stroke drawn without that input is half way
between the two widths. brush.options takes width_mode tilt, bearing
or rotation.
2026-11-12 07:28:26 -08:00
Taha-Mahmoodi 2d62c35d69 Merge remote-tracking branch 'origin/main' into feat/glyph-alternates
# Conflicts:
#	docs/gaps.md
#	docs/roadmap.md
#	docs/target-app-parity.md
2026-11-12 19:55:05 +04:30
BFlat 10ea235ee4 Merge pull request #6659 from ruchirguitar/fix/numfield-short-drag-1326
Numeric fields: a sub-threshold pointer movement keeps its caret (#1326)
2026-11-12 22:21:11 +07:00
Taha-Mahmoodi 7c6f51e8d6 Merge remote-tracking branch 'origin/main' into feat/glyph-alternates 2026-11-12 19:37:53 +04:30
dotCooCoo 8a6361b45f Global Edit: selecting one object highlights the similar objects before the start
With one object that Start Global Edit accepts selected with the Selection
tool, the canvas now highlights the other objects a start would take with the
current Global Edit Options, before Global Edit starts. The outlines are kept
per document revision and options, and none are shown during a drag.

Docs: docs/mcp.md (Global Edit), docs/gaps.md (G5).
2026-11-12 07:04:06 -08:00
BFlat c607814697 Merge pull request #6798 from dotCooCoo/feat/brushes-dry-media-library
Brushes: a built-in Dry Media library of grainy chalk, pencil, crayon and charcoal art brushes
2026-11-12 22:01:26 +07:00
dotCooCoo 6208a8cc3e EPS import: charpath, cshow, kshow and glyphshow read named CIDFont type by its CMap
- `charpath` in a CIDFont only named, over a predefined CMap, adds the
  outlines of the characters its codes stand for, placed as `show` sets
  them, and moves the point as `show` does. It added no outlines.
- `cshow` gives its procedure each code of such type, two bytes for a
  two-byte code, with the code's width. It split two-byte codes into
  single bytes.
- `glyphshow` sets the named character itself. It set the character's
  UTF-8 bytes as Latin-1 letters.
- `kshow` runs its procedure between each two codes of such type, with
  the two codes' values. It didn't run it. The procedure sees the font
  the file set as current, and a font it sets stays current.
- A name that ends in the row-and-cell CMap `H` or `V` splits off the
  CMap only when the file defines the CIDFont of that name (as a
  resource or with `definefont`), or the name has a hyphen and an
  installed face that covers Japanese has it. `Foo-Bold-H` stays a font
  of the whole name.
- In a CMap that can't be read (`GBT-H`), each code moves the point one
  em, along the line or down the column; a tab or carriage return byte
  is a code of its own.
- One parser reads the names of the predefined Unicode CMaps, for EPS
  and legacy `.ai` type.
- Outlines added to a path by `charpath` stop at the path's point limit.
- docs/file-format-parity.md, docs/gaps.md and docs/mcp.md describe type
  in named CIDFonts over the predefined CMaps.
2026-11-12 06:57:48 -08:00
dotCooCoo 91d705e155 Gradients: repeat or reflect a gradient's stops a set number of times
A linear, radial, conic or diamond gradient has a spread: Pad (the
default, as before), Repeat or Reflect, with a count of 1 to 100
(VectorCraft's own limit). Repeat and Reflect run the stops that many
times along the vector (around the turn for a conic) and keep going past
both ends, Reflect running every other run backwards, as SVG's
spreadMethod does.

The Gradient panel has a Spread menu and a Repeats field, and the
Gradient tool marks where the runs meet. paint.setFill and
paint.editGradient take `spread` and `repeats`; bad values are errors.
Presets, swatches, blends, strokes along or across a path, Outline
Stroke and Object › Expand follow the spread; Expand gives each run the
same whole number of objects, and Outline Stroke's mesh keeps the color
on each side of a sharp step between two stops at one offset.

SVG writes and reads spreadMethod: SVG import now reads a repeating or
reflecting gradient as one that repeats or reflects once, instead of
expanding its stops over the shape. CSS writes repeating gradients.
PDF writes a conic's sweep shading over one run. PDF, EPS, legacy .ai
and the .ai editing data write the other kinds with their stops
repeated across the shape: at most 256 runs and 16,384 stops (256 stops
in .ai files), and for a radial or diamond no farther than 65,536 runs
from its center, with a warning past those. PDF import now finds sharp
steps in any axial or radial shading instead of blurring them.

Docs: docs/mcp.md (Spread), docs/target-app-parity.md, docs/gaps.md.
2026-11-12 06:52:38 -08:00
makesomethingshit ec9a9fd3c9 Fix #6865: trust oversized editing artboards with capped PDF pages 2026-11-12 23:44:54 +09:00
ruchirguitar 5b2264bb8f Merge remote-tracking branch 'upstream/main' into fix/numfield-short-drag-1326
# Conflicts:
#	docs/gaps.md
#	docs/ui-parity.md
2026-11-12 19:52:50 +05:30
ruchirguitar be1b946b1e Docs: revision rows for the numeric-field tap tolerance (#1326) 2026-11-12 19:46:23 +05:30
ruchirguitar 3adadd52f4 UI: a tap within 1 pt still selects a numeric field's value (#1326)
Review feedback: with no tolerance, pen or trackpad jitter turned a tap
into a drag and the value was no longer selected. A release within 1 pt
of the press is a tap; anything further keeps the caret.
Regression test: a_tap_with_a_pixel_of_jitter_still_selects_all_on_release.
2026-11-12 19:40:04 +05:30
dotCooCoo ba23477b23 Merge main into feat/brushes-ink-wash-library 2026-11-12 05:50:48 -08:00
dotCooCoo 6e9ffa92cc Merge main into feat/brushes-dry-media-library 2026-11-12 05:31:21 -08:00
Ahmed Gomaa 421fead32b Merge upstream main into file/save-read-only-offers-save-as 2026-11-12 15:24:23 +02:00
Taha-Mahmoodi 2585d819cd Merge remote-tracking branch 'origin/main' into feat/glyph-alternates
# Conflicts:
#	docs/gaps.md
#	docs/target-app-parity.md
2026-11-12 17:42:44 +04:30
Ahmed Gomaa c66335eaa7 Merge upstream main into file/save-read-only-offers-save-as 2026-11-12 13:40:13 +02:00
Taha-Mahmoodi 9624b29dad Merge main into contextual glyph alternates 2026-11-12 15:56:45 +04:30
Taha-Mahmoodi ae2800f159 Merge remote-tracking branch 'origin/main' into fix/import-document-title
# Conflicts:
#	docs/target-app-parity.md
2026-11-12 15:52:02 +04:30
BFlat a8879b9fb8 Merge pull request #6760 from dotCooCoo/feat/brushes-bristle-library
Brushes: built-in Bristle Brushes library with one bristle brush for each tip shape
2026-11-12 18:19:32 +07:00
Taha-Mahmoodi 3eb9e0271c Merge remote-tracking branch 'origin/main' into fix/import-document-title
# Conflicts:
#	docs/file-format-parity.md
#	docs/gaps.md
#	docs/target-app-parity.md
2026-11-12 15:18:59 +04:30
Taha-Mahmoodi 4130ba226d Merge remote-tracking branch 'origin/main' into feat/glyph-alternates
# Conflicts:
#	docs/target-app-parity.md
2026-11-12 15:18:46 +04:30
dotCooCoo 448685b2d7 Merge main into feat/blend-canvas-easing-handles 2026-11-12 02:28:04 -08:00
dotCooCoo 8cd40e8216 Docs: blend widgets show only on a blend with a spine
A blend made without a spine shows neither widget; docs/gaps.md and docs/target-app-parity.md now say so next to the Ramp widget's condition.
2026-11-12 01:30:06 -08:00
BFlat 87c0d5cb5e Merge pull request #6826 from dotCooCoo/feat/3d-classic-rotate
3D (Classic): Rotate (Classic) turns flat art in 3D with the No Shading and Diffuse surfaces
2026-11-12 16:02:41 +07:00
dotCooCoo e7f2601847 Blend: arrow keys step from the widget's shown value; a double-click on a widget leaves the art alone
- After a drag past either end of the range, the first arrow key now
  steps back from the value shown instead of doing nothing.
- With the Selection tool, a plain double-click on a blend widget no
  longer edits or isolates the artwork under it, or leaves isolation.
  Ctrl/Cmd+Shift double-click still releases a guide there.
- docs/mcp.md says the lower widget shows only when the steps follow
  the spine, and the G13 blend easing entry in docs/gaps.md no longer
  lists on-canvas easing handles as missing.
2026-11-12 00:54:15 -08:00
dotCooCoo 0c758f6f06 Merge main into feat/brushes-ink-wash-library 2026-11-12 00:41:01 -08:00
dotCooCoo 682971a154 Merge main into feat/brushes-dry-media-library 2026-11-12 00:40:55 -08:00
dotCooCoo aba45b7249 Merge main into feat/brushes-bristle-library 2026-11-12 00:40:51 -08:00
BFlat dcab893acd Merge pull request #6791 from dotCooCoo/feat/styles-painted-sketched-library
Graphic Styles: a built-in Painted and Sketched library adds watercolor, charcoal and ink styles
2026-11-12 15:13:39 +07:00
Taha-Mahmoodi 5144f22976 Merge main 48e066f47 into glyph alternates #6084 2026-11-12 12:34:54 +04:30