Commit Graph
4092 Commits
Author SHA1 Message Date
Trevor BrownandClaude Fable 5.1 abf2eb9b3a M1: the Fill section shows a text's characters' fills, mixed when they differ, and a layer fill edit reaches every character (#1856)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-11-02 01:24:32 -05:00
Trevor BrownandClaude Fable 5.1 b1aa7c2b2a Merge upstream main into fix/control-arrows-pan
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-11-02 01:23:24 -05:00
Trevor BrownandClaude Fable 5.1 0c18e481eb Merge upstream main into fix/svg-import-stretch-and-dash-offset
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-11-02 01:23:24 -05:00
Trevor BrownandClaude Fable 5.1 7e6f88c469 Merge upstream main into fix/field-alt-scrub
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-11-02 01:23:23 -05:00
Trevor BrownandClaude Fable 5.1 3c9d943ff2 Field scrub: the field always senses drags; Alt as the drag begins makes it a scrub until the button is let go
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-11-02 00:42:22 -05:00
samhyunandClaude Opus 5.5 ed2747e9a4 M8: a stroke's square dash ends and brush shapes paint within its bounds
Three ways a stroke painted past the bounds an export and a redraw go
by, with no effects at all:

- A dash's square end stands out along the path as far as the band
  does across it, so its corners reach √2 times as far from the path.
  Round a curve that is past the box grown by the stroke.
- The ink brush's ragged edges reach 0.54 of the weight from the path,
  not 0.5.
- A scatter brush's copies stray by the weight whatever a width profile
  does, but the profile's scale was applied to the stray as well, so a
  thinning profile left them out.

`outline_reach` now counts square dash ends as √2 at least, and
`Brush::reach_factor` takes the profile's scale for the shapes only and
counts the shapes' reach (`Brush::SHAPE_REACH`), which a test checks
every preset against.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 14:21:44 +09:00
samhyunandClaude Opus 5.5 55821565ac M8: a spread round a stroke with corners keeps its whole shadow
A dashed stroke is cut into dashes with corners wherever they fall round
the outline, and a width profile or a brush can give the stroke corners
of its own. A drop shadow's spread mitres those corners out, but a whole
ellipse or a box still counted as growing by exactly its spread, so the
shadow was cut off at the layer's edge (up to 255 levels).

Such a node now gets the room a star does. Whether the outline's own
mitres end on its box is a check of its own, which the stroke's reach
keeps using, so a node with no spread keeps its bounds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 14:21:33 +09:00
f9b5693621 M2: a text keeps a max height or a number of max lines, not both (#1832)
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-11-02 00:02:56 -05:00
8174dd5b74 M4: bulleted lists keep the same bullet at every level of indentation (#1843)
* M4: bulleted lists keep the same bullet at every level of indentation

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* list_markers: the comment says bullets are the same at every level

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-11-02 00:01:29 -05:00
9c3ec8c1d1 M4: typing 1) and a space starts a numbered list, as 1. does (#1842)
* M4: typing 1) and a space starts a numbered list, as 1. does

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* Parity: the Text area row names the list creation characters

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* Parity: the list creation characters without spaces inside the code spans

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-11-02 00:00:19 -05:00
a953a04e33 Shortcuts: Cmd/Ctrl+Shift+Alt+= / - / 0 make the interface larger, smaller and default-sized (#1846)
* Shortcuts: Cmd/Ctrl+Shift+Alt+= / - / 0 make the interface larger, smaller and default-sized

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* Interface size keys: live while editing text too, and the new size draws on the next frame

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* A preference set during a frame repaints this window too, so the interface size applies on the next frame

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* Control channel: a preference changed by a hidden window's command repaints every window

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-11-01 23:59:08 -05:00
f58e022ed7 Shortcuts: Cmd/Ctrl+Alt+arrows rotate a degree at a time, 15 with Shift (#1845)
* Shortcuts: Cmd/Ctrl+Alt+arrows rotate a degree at a time, 15 with Shift

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* The rotate gesture's label in the English catalog

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* Rotate keys: about the selection's rotation origin, not while editing points, Dev Mode refusal on the control path too

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-11-01 23:56:06 -05:00
Trevor BrownandClaude Fable 5.1 15bd733886 Number fields: Alt held over the field scrubs it, as the label does
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-11-01 23:51:07 -05:00
Trevor BrownandClaude Fable 5.1 5050631bcf M5: Hide UI in the presenter: the bars go away and Cmd/Ctrl+\ brings them back (#1820) (#1826)
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-11-01 23:50:03 -05:00
Trevor BrownandClaude Fable 5.1 65bd00f739 M3: Delete on a layer inside an instance hides it instead of being refused (#1834)
* M3: Delete on a layer inside an instance hides it instead of being refused

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* The components structure test: Delete inside an instance hides

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-11-01 23:49:58 -05:00
Trevor BrownandClaude Fable 5.1 2abd8c5f52 M2: Remove all auto layout takes it off a frame and every frame nested in it (#1833)
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-11-01 23:49:53 -05:00
Trevor BrownandClaude Fable 5.1 3b8ded69c0 M4: a link on text is underlined by default, and Underline takes it off (#1841)
* M4: a link on text is underlined by default, and Underline takes it off

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* text.link: only a new link takes the default underline; Underline reads the texts inside a target

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-11-01 23:49:48 -05:00
Trevor BrownandClaude Fable 5.1 fdd27a0b88 Shortcuts: the Layers panel opens with Ctrl+1 as well as Alt+1 on Windows and Linux (#1844)
* Shortcuts: the Layers panel opens with Ctrl+1 as well as Alt+1 on Windows and Linux

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* Parity note: in the browser Ctrl+1 is the browser's tab key

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-11-01 23:49:43 -05:00
김삼현andClaude Opus 5.5 702b0d7894 M8: a whole ellipse drawn backwards keeps its simple stroke in SVG (#1848)
* M8: a whole ellipse drawn backwards keeps its simple stroke in SVG

An ellipse with a sweep of -2π goes all the way round, as the renderer
and the .fig export already read it. The SVG export's simple stroke
checked `sweep >= 2π` only, so such an ellipse's inside or outside
stroke was written as a filled even-odd ring instead of a stroke.

All three places now ask `figcraft_geom::full_sweep`, as the geometry
and the bounds do.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* M8: a backwards whole ellipse's stroke ring in the renderer and .fig export, tested

Review follow-up (#1848): the renderer's stroke ring and the .fig
export's stroke geometry read a sweep of -2π as whole too, now through
`full_sweep`. A test for each checks a backwards ellipse strokes the
same ring as a forward one, and fails if either goes back to checking
positive sweeps only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* M8: the .fig backwards-ellipse test compares the stroke ring itself

Review follow-up (#1848): the test checked only that one stroke path was
written. It now compares the path's commands and winding rule for the
forward and backwards ellipse, and that the ring is even-odd.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 23:49:38 -05:00
김삼현andClaude Opus 5.5 fa8faf216d M8: a whole ellipse starting anywhere stays whole through a .fig file (#1851)
A .fig file (and the REST JSON) holds an ellipse's start and end angles
as 32-bit floats, and FigCraft writes them that way too. For a whole
turn that starts anywhere but zero, end - start comes out a hair short
of 2π as often as not (start 0.3: 6.283185184), which reads as an arc:
the ellipse came back as a pie slice whose centred stroke draws a line
from the centre to the edge.

On import, a sweep within the angles' precision of a turn is now a turn.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 23:49:34 -05:00
AxylumandCédric Legrand dea8d8eb3a fix(cli): M2.1: scope dead-code expectation (#1816)
Co-authored-by: Cédric Legrand <cedric@legrand-tech.fr>
2026-11-01 23:49:30 -05:00
NetterSilverandClaude Haiku 5.5 9a1b33bbfd Reject signed major in plugin manifest api version string (#1853)
Found while testing crates/plugin/src/manifest.rs:70 (api_from_number_or_string, the Api::Text arm)

Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
2026-11-01 23:49:26 -05:00
Trevor BrownandClaude Fable 5.1 ecd900ab37 Control channel: ui.key arrows pan the view when nothing is selected, as the window does
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-11-01 23:47:48 -05:00
dotCooCoo 8b3ded373e Merge main into feat/export-color-profile 2026-11-01 17:05:42 -08:00
michaelgiraldo 86e74a93f5 M9: avoid immutable caching of missing browser assets 2026-11-01 11:54:10 -08:00
michaelgiraldo 6f7814c9d3 M9: document combined browser and collaboration hosting 2026-11-01 11:23:39 -08:00
Cédric Legrand cda326e24e fix(vectordrawable): M2.1: use inclusive range checks 2026-11-01 20:23:24 +01:00
bd920fc7de M8: .fig import: a routed connector takes its line style from the generated record (#1807) (#1813)
* M8: .fig import: a routed connector takes its line style from the generated record (#1807)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* M8: .fig import: a routed connector keeps its own empty paints and dash pattern

CodeRabbit review on #1813: an explicit empty strokePaints (no stroke) or
dashPattern (solid) on the connector no longer takes the generated record's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-11-01 14:12:31 -05:00
김삼현andClaude Opus 5.5 264bcb1c03 M8: an arc's spread shadow and mitred stroke get room for their corners (#1802)
* M8: an arc's spread shadow gets room for its mitred corners

Rectangles, frames and ellipses grow by exactly their spread, so their
layers only make room for the spread itself; other shapes make room for
the mitre at sharp corners (up to four times the spread). An ellipse
with arc data (a pie slice, or a ring cut short) counted as an ellipse,
but its ends meet its sides in sharp corners: a spread of 25 on a slice
of 0.3 rad cut its shadow off at the layer's edge (up to 255 levels).

Only an ellipse that goes all the way round now grows by exactly its
spread. `figcraft_geom::full_sweep` is what `ellipse` already used to
tell a whole ellipse or ring from an arc, so the two agree.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* M8: an arc's mitred stroke gets room for its corners too

Review: `outline_reach` counted every ellipse as an outline whose stroke
mitres end on the grown box, the same mistake as the spread. A thin
slice with a 20-unit mitred stroke and a spread of 10 still had its
shadow cut off (255 levels). It now asks `grows_by_exactly_its_spread`,
which picks the same shapes and leaves arcs out.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 14:12:27 -05:00
김삼현andClaude Opus 5.5 6b2e464361 M8: a scaled node's spread shadow keeps its room in SVG (#1803)
The SVG export blurs a spread drop shadow in a filter whose region is
the silhouette's page bounds grown by the spread's mitre and the blur.
The spread grows the outline in the node's own units, though, and the
transform then scales it: on a star scaled three times, a spread of 10
mitred out to some 97 units while the region only made room for 48, so
SVG viewers cut the shadow's points off. The spread now grows the region
as far across and down as the transform takes a local step of that
length, as the paint bounds already do.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 14:12:23 -05:00
Trevor BrownandClaude Fable 5.1 83c28cf3ae M6: SVG import: a stretched image stays stretched (#1811)
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-11-01 14:12:18 -05:00
Brandon ThomasandClaude Opus 5.5 5fc2840d90 Release 0.14.0
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
v0.14.0
2026-11-01 13:58:36 -05:00
Cédric Legrand c41471d20b build(pathops): M2.1: inherit workspace Rust version 2026-11-01 19:54:54 +01:00
Cédric Legrand e7a599baea style(text): M2.1: clarify font filter precedence 2026-11-01 19:42:52 +01:00
Dylan M. Taylor 7b5f8c3699 docs: sync Craft App Suite list with ArtCraft Launcher 2026-11-01 12:30:08 -05:00
Trevor BrownandClaude Fable 5.1 8bc405edbc SVG import: the dash offset fix alone, with open-path, mixed-subpath and text tests
The stretched-image fix moved to its own PR.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-11-01 12:16:33 -05:00
Trevor BrownandClaude Fable 5.1 4e22873b44 Page opacity test: a scrub on the field is live and one undo step
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-11-01 12:01:33 -05:00
Trevor BrownandClaude Fable 5.1 d72f096186 M8: color-mix(): a none in color() is a missing component too
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-11-01 11:54:35 -05:00
mortezanaeemi-ops ef52759ebc Add files via upload 2026-11-01 16:17:46 +03:30
mortezanaeemi-ops 7f4b295983 Add files via upload 2026-11-01 16:17:10 +03:30
mortezanaeemi-ops c411152b87 Add files via upload 2026-11-01 15:34:41 +03:30
mortezanaeemi-ops 5d4a5082ec Add files via upload 2026-11-01 14:54:48 +03:30
mortezanaeemi-ops 08537cf425 Delete tests.rs 2026-11-01 13:55:16 +03:30
mortezanaeemi-ops f282a30164 Delete map.rs 2026-11-01 13:54:49 +03:30
mortezanaeemi-ops 6969232326 Add files via upload 2026-11-01 13:53:11 +03:30
samhyunandClaude Opus 5.5 8c93d0559f M8: dots quantize their position apart from the view's origin
Review of #1796: quantizing the mark's distance from the view's corner
took in the error of the view's origin converted to pixels, so a mark
one 1/65536 px step short of a half could still cross it. At a step of
24 and a zoom of (75.5 - 2^-17) / 24, a pan by 51 pixels moved the
first mark. The mark's position and the origin are now each quantized
before the one is taken from the other.

The origin rounds its halves down: some 4 x 10^10 pixels out, its error
is exactly half a step, and rounded up it moved the marks again. Past
2^37 pixels the step is finer than f64 and values are used as they
are, so huge ones no longer overflow to infinity and come out as a
mark at the view's corner.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 19:22:29 +09:00
mortezanaeemi-ops a5ebc01d2c Add files via upload 2026-11-01 13:50:48 +03:30
mortezanaeemi-ops dfe703deb2 Add files via upload 2026-11-01 13:46:24 +03:30
Max MittelstädtandGPT-5.6-Luna 3f7f5f38ce Reject overflowing u32 varints
Found while testing crates/format/src/fig/kiwi.rs:190

Co-Authored-By: GPT-5.6-Luna <noreply@openai.com>
Co-Authored-By: GPT-6-Luna <noreply@openai.com>
2026-11-01 10:09:26 +00:00
samhyunandClaude Opus 5.5 12b0bcddcb M8: a test for texture's whole-pixel moves in wide layers
Review of #1795: the tests checked the rounding of grain cells but not
the move texture now adds in whole pixels. Rounded cells with the old
`f32` move still passed them. A pan across a 2,400-pixel-wide striped
layer catches it: past 1,024 pixels, the old move came out a pixel off
for some pixels.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 18:47:09 +09:00