An override can't take its layer off the main component's text path, so an instance text of more than one line, whose main is on a path, stays on that path in the file. The export warned the general instance mismatch for it. It now says exactly that case: "an instance's text of more than one line stays on its main component's text path in the file, as an override can't take it off". FigCraft's own import reads such a layer as plain text. The docs' Left out list names the case.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove and wrote
With the colour picker open on an image fill in Crop mode, a press on the layer closed the picker, and closing it committed the drag as a plain move: the whole layer moved instead of the picture inside it. The picker now treats a crop drag as its own control, as it does the open gradient's handles (#1852), so the press doesn't close it and the drag moves the crop.
A drag whose gesture something else committed under the held button went on calling the engine's preview, whose "no gesture in progress" error reached the canvas as a message. That error is now its own EngineError::NoGesture, which the canvas drops: the drag it belonged to is over, and it says nothing to the user.
Tests: crop_image_tests::crop_from_the_colour_picker_then_a_drag_on_the_image_moves_the_crop_not_the_layer (failed before: the crop didn't move) and a_drag_whose_gesture_was_committed_under_the_button_shows_no_message (failed before: "no gesture in progress").
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove and finished; Sonnet 5.5 wrote at medium (cut off by an API error)
* 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>
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>
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
Text on a path was written as an ordinary text layer under the warning "text on a path was written as plain text", so the path, where the text starts and its side were gone when the file was opened again. It is now written as the format's own layer kind (TEXT_PATH): the first part of its path as a vector network of one open or closed chain with the segment the text starts on marked, the start as that segment's own parameter (textPathStart.tValue, found by inverse arc length) and the side as forward. Vertical alignment is written as top, which is how text on a path draws.
More than one line and paths the format can't hold stay plain text, the parts of a path after the first are left out, and text on a path in an instance but not in its main component (or the other way round) is written as the main has it, each with its own warning. The field numbers come from the schema of 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; Fable 5.2 briefed; Sonnet 5.5 wrote at medium
* 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>
* 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>
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>
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>