Commit Graph
1738 Commits
Author SHA1 Message Date
bflatastic 8932347ef8 Merge main into #2139 2026-11-13 23:23:44 +07:00
BFlat ef5a058a22 Merge pull request #2331 from denisg0mes/paste-over-next-to-selection
M1: Paste over selection puts the copies just above the selected layer
2026-11-13 23:21:50 +07:00
BFlat 373696ac88 Merge pull request #2292 from TrevorBrown-dev/feat/jam-native-shapes-1808
M9: .jam import: shapes with text come in as native board shapes (#1808)
2026-11-13 23:16:35 +07:00
bflatastic bbd8d7c661 Merge main into #2331 2026-11-13 23:06:07 +07:00
bflatastic e1647fba6a Merge main into #2139 2026-11-13 23:04:53 +07:00
BFlat c69a45382e Merge pull request #2288 from TrevorBrown-dev/docs/drag-modifiers-measured
Docs: drag modifiers measured in Figma
2026-11-13 23:03:31 +07:00
bflatastic 919df8fd80 Merge main into #2292 2026-11-13 23:00:17 +07:00
BFlat 3511511bfb Merge pull request #2301 from TrevorBrown-dev/feat/fig-export-image-adjustments-2297
M6: .fig export writes image adjustments (#2297)
2026-11-13 22:58:48 +07:00
bflatastic 953383fff8 Merge main into #2331 2026-11-13 22:54:24 +07:00
BFlat c56d5d22ad Merge pull request #2327 from TrevorBrown-dev/fix/mind-map-parent-default
M12: a mind map in a section or frame without a place starts at the view's centre
2026-11-13 22:51:44 +07:00
bflatastic e387b63fbf Merge main into #2292 2026-11-13 22:47:47 +07:00
bflatastic 996b16a75e Merge main into #2288 2026-11-13 22:47:14 +07:00
bflatastic 71e063de9f Merge main into #2139 2026-11-13 22:47:03 +07:00
BFlat 1448a91a54 Merge pull request #2086 from TrevorBrown-dev/fix/snap-threshold-measured
Smart guides: objects snap within 4.5 screen pixels, as measured in Figma
2026-11-13 22:45:56 +07:00
BFlat ec524f6cd3 Merge pull request #2315 from TrevorBrown-dev/fix/css-layered-background-2271
M10: CSS code export writes several fills as one layered background, top first, as Figma does (#2271)
2026-11-13 22:44:32 +07:00
bflatastic c08a7c334b Merge main into #2301 2026-11-13 22:43:19 +07:00
BFlat ce7de19097 Merge pull request #2294 from TrevorBrown-dev/fix/fig-list-start-2273
M6: .fig import: a numbered list keeps its start only where it starts counting (#2273)
2026-11-13 22:41:46 +07:00
bflatastic 35906ea43b Merge main into #2292 2026-11-13 22:41:10 +07:00
BFlat ebc0260017 Merge pull request #2289 from TrevorBrown-dev/feat/sticky-size-menu
M12: Boards: a sticky's text-size menu (Small 16 to Huge 96), remembered for new stickies
2026-11-13 22:39:41 +07:00
bflatastic 9baf13c2a4 Merge main into #2288 2026-11-13 22:39:06 +07:00
BFlat bdf14ae7f0 Merge pull request #2286 from TrevorBrown-dev/fix/icon-buttons-16pt-2238
M8: every 24 pt icon button paints its glyph at 16 pt (#2238)
2026-11-13 22:36:15 +07:00
bflatastic 83a0177310 Merge main into #2139 2026-11-13 22:29:54 +07:00
bflatastic 91d2caf9df Merge main into #2086 2026-11-13 22:29:18 +07:00
BFlat 6fb76233ec Merge pull request #2087 from TrevorBrown-dev/feat/variables-duplicate-group-2084
Variables: Duplicate group copies a group's variables as "<name> 2" in one undo step
2026-11-13 22:27:09 +07:00
BFlat b98f3dd39f Merge pull request #2241 from TrevorBrown-dev/fix/mirror-sharp-point-2110
M4: Vector edit: a mirror mode turns a sharp point smooth (#2110)
2026-11-13 22:24:58 +07:00
Trevor BrownandClaude Sonnet 5.5 0de5559d4e Merge upstream/main into feat/jam-native-shapes-1808
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove; Opus 5.5 briefed; Sonnet 5.5 wrote at medium
2026-11-13 04:44:17 -05:00
Trevor BrownandClaude Sonnet 5.5 15261112b1 Merge upstream/main into fix/fig-list-start-2273
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove; Opus 5.5 briefed; Sonnet 5.5 wrote at medium
2026-11-13 04:43:43 -05:00
Trevor BrownandClaude Sonnet 5.5 9f09f56488 Merge upstream/main into feat/fig-export-image-adjustments-2297
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove; Opus 5.5 briefed; Sonnet 5.5 wrote at medium
2026-11-13 04:43:14 -05:00
Trevor BrownandClaude Sonnet 5.5 fb9df220b1 M6: .fig export writes a page's prototype background (#2326) (#2328)
* M6: .fig export writes a page's prototype background (#2326)

The export writes a page's prototype background as prototypeBackgroundColor (field 141, a plain colour) when it differs from the default, as Figma does for a page whose background was set. The device-settings warning now fires only for the device, rotation, colour, custom size and responsive settings. Measured on a synthetic file saved from Figma's web app.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove; Opus 5.5 briefed; Sonnet 5.5 measured and wrote at medium

* M6: the .fig export writes a prototype background opaque and warns for its opacity, and its tests read the written record (#2326)

The colour is written with alpha 1, as the measured record has it and as the import reads it, and a background that isn't opaque warns that its opacity was left out. The tests now read the written record, and each device setting alone is checked.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove; Fable 5.2 reviewed; Sonnet 5.5 wrote at medium

* M6: the .fig export writes every page's prototype background, so Figma shows the same colour (#2326)

A page at FigCraft's default background used to write no field, so Figma showed its own default instead. Every page now writes its colour, opaque. The test for a default page reads the written record and the import.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove; Opus 5.5 briefed; Sonnet 5.5 wrote at medium

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-13 09:34:55 +01:00
Denis GomesandClaude Opus 5.5 c74bcd0b0e M1: Paste over selection puts the copies just above the selected layer
Shift+Cmd/Ctrl+V pasted into the selected layer's parent at its top-left,
but appended the copies, so they went to the top of the parent's layers
whatever was selected. In an auto layout frame that put them at the end of
the flow, away from the layer they were pasted over.

They now go just above the selected layer, in the copied order: in the
Layers panel the row above it, in an auto layout frame the item after it.
A section pasted over a layer in a frame still goes on the page, on top
of its layers, as before. Paste to replace already kept the replaced
layer's place.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-13 01:41:48 -05:00
Trevor BrownandClaude Sonnet 5.5 e0e57dd42a M12: a mind map in a section or frame without a place is centred on the view
board.mindMap's default x and y came from the view's centre, which is on the page, but x and y are the root's place in its parent: under a section at (1000, 500) the map landed 1000 right and 500 down of the view's centre. The default now takes the centre through the parent's inverse world transform (a parent that can't be inverted gives a non-finite centre, which the coordinate check refuses). Explicit x and y stay parent-local. Tests: two in board_mindmap_tests (a section; a frame turned 30 degrees, with a given place carried through the frame).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove; Opus 5.5 briefed; Sonnet 5.5 wrote at medium
2026-11-13 00:45:11 -05:00
Trevor BrownandClaude Opus 5.5 6ad4e02498 Merge upstream/main into docs/drag-modifiers-measured
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-12 22:18:45 -05:00
Trevor BrownandClaude Sonnet 5.5 3cf7385f3d Docs: keep one Vector edit mode row (main's, plus this PR's mirror clause)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove; Opus 5.5 briefed; Sonnet 5.5 wrote at medium
2026-11-12 22:07:04 -05:00
Trevor BrownandClaude Opus 5.5 7d94fa78e9 Merge upstream/main into fix/mirror-sharp-point-2110
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-12 22:06:21 -05:00
Trevor BrownandClaude Opus 5.5 04d5beed4e Merge upstream/main into feat/jam-native-shapes-1808
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-12 21:35:06 -05:00
Trevor BrownandClaude Opus 5.5 38c68e6714 Merge upstream/main into fix/fig-list-start-2273
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-12 21:17:54 -05:00
Trevor BrownandClaude Opus 5.5 128ffa7cd4 Merge upstream/main into feat/fig-export-image-adjustments-2297
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-12 21:09:11 -05:00
Trevor BrownandClaude Sonnet 5.5 a62435bb11 Merge remote-tracking branch 'upstream/main' into fix/css-layered-background-2271
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove; Opus 5.5 briefed; Sonnet 5.5 wrote at medium
2026-11-12 20:53:31 -05:00
Trevor BrownandClaude Sonnet 5.5 197af01629 Merge upstream/main into fix/snap-threshold-measured
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove; Opus 5.5 briefed; Sonnet 5.5 wrote at medium
2026-11-12 20:42:00 -05:00
Trevor BrownandClaude Sonnet 5.5 7057fbf3a5 Merge upstream/main into feat/variables-duplicate-group-2084
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove; Opus 5.5 briefed; Sonnet 5.5 wrote at medium
2026-11-12 20:41:57 -05:00
Trevor BrownandClaude Sonnet 5.5 e4ef6a62a7 Merge upstream/main into feat/zoom-selection-margin
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove; Opus 5.5 briefed; Sonnet 5.5 wrote at medium
2026-11-12 20:41:24 -05:00
Trevor BrownandClaude Sonnet 5.5 39acc36438 Docs: the interactions measured against Figma on 2026-11-08, case by case (#2111)
* Docs: the interactions measured against Figma on 2026-11-08, case by case

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove; Opus 5.5 briefed; Sonnet 5.5 wrote at low

* Docs: the measured values for snapping, menus and Escape, and what FigCraft did before each fix

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove and wrote

* Docs: the safe triangle unresolved, the Hug notice fixed in #2099, the variant warning not added (#2111 review)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove and wrote

* Docs: partly fixed defined, the test row a match, open questions without repeats, ui-parity's line reworded (#2111 review)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove and wrote

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-13 01:47:38 +01:00
Trevor BrownandClaude Sonnet 5.5 a4e330774b M6: .fig export writes list spacing, hanging punctuation and lists, and vertical trim (#2305) (#2306)
* M6: .fig export writes list spacing, hanging punctuation and lists, and vertical trim (#2305)

The export wrote none of a text's list spacing, hanging punctuation, hanging lists or vertical trim, although the import reads all four. It now writes listSpacing, hangingPunctuation, hangingList and leadingTrim, each only when it differs from its default (as Figma saves them), and an instance override back to the default clears the field. The warning narrows to OpenType features, which the import does not read from a .fig.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove; Fable 5.2 briefed; Sonnet 5.5 wrote at medium

* M6: test that an instance override back to the default clears it (#2305)

Adds a round-trip test for the unset entries: an instance whose text goes back to the defaults must not take the main's list spacing, hanging flags and vertical trim again. Also scopes the comment and the docs row to a design file: a text at the defaults carries none of the four there, and a text style holds none of them.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove; Fable 5.2 briefed; Sonnet 5.5 wrote at medium

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-13 01:46:25 +01:00
Trevor BrownandClaude Sonnet 5.5 a60cb1a6fa M7: the Design panel shows the page's variable modes with nothing selected (#2215) (#2312)
Pages take a variable mode, set from the Page section of the right sidebar once a local collection has more than one mode. With nothing selected the Page section now shows the same Variable modes section the frames have: a row per multi-mode collection, Auto or one of its modes, one undo step per pick (variable.setMode without layers sets the page's mode). The frame's row drawing is shared, not copied.


Model-Effort: Opus 5.5 drove; Fable 5.2 queued; Opus 5.5 briefed; Sonnet 5.5 measured and wrote at medium

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-13 01:45:48 +01:00
Trevor BrownandClaude Sonnet 5.5 8ffa1bfbd1 Docs: one Vector edit mode row after the merges (#2287)
Three parallel merges (#2121, #2195, #1875) each left a copy of the Vector edit mode row with its own additions. They are folded into one row: the Point section Mixed X and Y, Flatten baking a point corner radius, and vector edit Copy, Cut and Paste, in the order of the shared text. Nothing dropped.


Model-Effort: Opus 5.5 drove; Opus 5.5 briefed; Sonnet 5.5 wrote at medium

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-13 01:45:10 +01:00
Trevor BrownandClaude Sonnet 5.5 3d22c606a7 M10: Tailwind mobile merge keeps a max-width both frames share (#2272) (#2296)
inspect.code {language: "tailwind", mobile} dropped every mobile max-width and put the desktop one behind lg:, so a fixed-size layer that is the same size on both frames (a 48 x 48 badge) stretched to the full width below 1024 px. A mobile max-width that equals the desktop one is now kept as a plain class, with no lg: copy. A differing max-width still goes fluid on mobile with the desktop cap behind lg:.

Tests: the issue's two frames (a 1440 and a 390 page, each with a 48 x 48 badge) keep max-w-[48px] unprefixed, and a page-wide banner still gets its lg: cap only. The slashed-names test gave the CTAs frame the same 342 px on both frames, which the new rule rightly keeps, so its desktop frame is now 600 px wide. docs/mcp.md notes the rule.


Model-Effort: Opus 5.5 drove; Fable 5.2 queued; Opus 5.5 briefed; Sonnet 5.5 wrote at medium

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-13 01:44:17 +01:00
Trevor BrownandClaude Sonnet 5.5 2408d0aa81 M8: Tab while renaming moves only the rename and wraps from the last layer, as in Figma (#2311)
* M8: Tab while renaming the last layer wraps to the first, as in Figma

Measured in Figma's web app on 2026-11-12: Tab on the last row of the Layers panel commits the name and opens the first row's rename. FigCraft ended the rename there. Shift+Tab on the first row is unmeasured and unchanged, and Tab still moves the selection with the rename.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove; Fable 5.2 queued; Sonnet 5.5 measured and wrote at medium

* M8: Tab while renaming moves the rename, not the selection, as in Figma

Measured in Figma's web app (second run, 2026-11-12): while renaming, Tab and Shift+Tab open the next or previous row in edit, and the selection stays on the layer first renamed. FigCraft moved the selection to the renamed row. Tab now moves only the rename field.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove; Fable 5.2 queued; Sonnet 5.5 measured and wrote at medium

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-13 01:43:49 +01:00
Trevor BrownandClaude Opus 5.5 477f004400 Merge upstream/main into fix/mirror-sharp-point-2110
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-12 19:39:01 -05:00
Trevor BrownandClaude Sonnet 5.5 9467d2355b M10: CSS code export writes several fills as one layered background, top first, as Figma does (#2271)
inspect.code wrote one `background` per visible fill, so only the last survived. A non-text layer now gets one `background` with every visible fill as a layer, top fill first (a document's fills run bottom to top), joined with ", ". A solid above another fill is `linear-gradient(0deg, c, c)` since CSS allows a plain colour only as the last layer; the bottom solid stays a plain colour (and keeps its variable token); gradients, images and patterns keep their layers. A single fill is unchanged. Text keeps one `color` per fill. Tailwind emits a layered value as one `[background:...]` class. Native targets are unchanged.

Tests: several_fills_are_one_layered_background_top_first, one_solid_fill_stays_a_plain_colour, several_fills_are_one_layered_background_class.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove; Fable 5.2 queued; Opus 5.5 briefed; Sonnet 5.5 measured and wrote at medium
2026-11-12 13:54:12 -05:00
Trevor BrownandClaude Sonnet 5.5 b54df860de M6: .fig export writes image adjustments (#2297)
An image paint's adjustments (exposure, contrast, saturation, temperature, tint, highlights, shadows) were dropped on export with a warning, although the importer already reads them. The export now writes them as the paint's `paintFilter`: seven floats, with saturation as vibrance and the tint's sign flipped to the file's (positive towards magenta). A paint without adjustments gets no `paintFilter`. The warning is gone.

The schema gains `PaintFilterMessage` and `Paint.paintFilter`. A round-trip test turns the importer's fixture around and pins the written values and field numbers. Not checked in other software.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove; Fable 5.2 briefed; Sonnet 5.5 wrote at medium
2026-11-12 07:10:52 -05:00