Commit Graph
418 Commits
Author SHA1 Message Date
bflatastic 6bbd92856c Merge main into #2224 2026-11-12 11:24:51 +07:00
BFlat a49817259d Merge pull request #2106 from TrevorBrown-dev/fix/arrow-pan-step-measured
View: the arrow keys pan 64 px, 320 with Shift, as measured in Figma
2026-11-12 11:22:17 +07:00
bflatastic ebca682595 Merge main into #2224 2026-11-12 11:12:04 +07:00
bflatastic 7ecb6f1c03 Merge main into #2094 2026-11-12 11:07:19 +07:00
bflatastic ea7f7a7145 Merge main into #2106 2026-11-12 11:07:09 +07:00
bflatastic 3c0505def6 Merge main into #2094 2026-11-12 10:50:07 +07:00
bflatastic a5b98d9612 Merge main into #2223 2026-11-12 10:11:57 +07:00
bflatastic a905f50211 Merge main into #2224 2026-11-12 10:11:23 +07:00
bflatastic 7901713555 Merge main into #2106 2026-11-12 10:07:38 +07:00
BFlat dc5cdb971e Merge pull request #2276 from TrevorBrown-dev/fix/marquee-rules-as-measured
M5: marquee selection follows Figma's measured rules (gap 4)
2026-11-12 10:05:23 +07:00
BFlat 4531e99e5c Merge pull request #2070 from dotCooCoo/fix/export-color-docs
Export: color profile text states which formats are tagged and that CMYK PDF is DeviceCMYK
2026-11-12 09:56:27 +07:00
bflatastic c1bd18f1f9 Merge main into #2276 2026-11-12 09:31:46 +07:00
bflatastic 190b8b4c80 Merge main into #2094 2026-11-12 09:27:04 +07:00
bflatastic 2c1c3c974a Merge main into #2106 2026-11-12 09:19:47 +07:00
Trevor BrownandClaude Opus 5.5 71723cd428 Merge upstream/main into feat/text-style-font-weight-2174
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-11 20:38:54 -05:00
Trevor BrownandClaude Opus 5.5 132c6e9686 Merge upstream/main into fix/boolean-corner-radius-2222
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-11 20:38:29 -05:00
Trevor BrownandClaude Opus 5.5 20f02bb7c1 M12: Boards: mind maps in the document and engine (#2226, step 1) (#2228)
* M9: Boards: mind maps in the document and engine (#2226)

Part of #2226, step 1 of 4. A mind map node is a board object of its own (BoardItem::MindNode: a frame hugging its text, no box) and a branch is a connector marked `branch`; the tree is read from the branches alone. `board.mindMap` places a first node with three children and `board.mindMapAdd` adds a child or a sibling, each one undo step. The normalize pass (`board::settle_mind_maps`, `figcraft_doc::mind_layout`) lays a touched map out again from its first node: 88 between columns, 48 between siblings, each stack centred on its parent; a branch that no longer joins two layers of its page is removed. Branches are curved, stroke 4, #757575, round caps. Numbers are from a FigJam map saved and decoded. No toolbar entry, shortcuts or import yet.

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

* M12: Mind maps: a map around its own container stays put; a moved branch re-flows its old map (#2226)

A map holding a layer and something inside it is skipped by the settle pass (it never settled). Every touched branch now stirs its old ends, so re-attaching a branch's start re-flows the map it left. Boards without branches return early, a map over MIND_MAX_NODES is left whole, shift skips non-finite moves, and the doc tests share one six-node helper.

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

* M12: Mind maps: FigCraft's own starter texts (#2226)

A new map's starter children read "Idea 1", "Idea 2" and "Idea 3", as the design specified,
instead of the incumbent's wording, which the first commit had copied from the measurement.

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

* M12: Docs: the mind-map revision rows go in the revision history (#2226)

The 2026-11-10 rows sat in ROADMAP.md's Headline numbers table and docs/roadmap.md's Alpha gate
table; each now opens its file's revision history.

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-12 00:47:05 +01:00
Trevor BrownandClaude Sonnet 5.5 604c78466c M5: marquee: a drag from inside a frame takes it whole when it takes another top-level frame, as re-measured
In top-level mode the frame the drag started in is now selected whole (re-measure 2: [F1, F2], R1 not selected); with no other frame taken only the touched shapes are. Test 9 uses the re-measure's literal marquees; docs reworded and docs/mcp.md rewrapped.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove; Fable 5.1 briefed; Sonnet 5.5 wrote at medium
2026-11-11 17:40:52 -05:00
Trevor BrownandClaude Sonnet 5.5 cb52621414 M5: marquee selection follows Figma's measured rules (gap 4)
A plain marquee now selects each top-level layer it touches: a partly covered frame or section gives the layers in it the marquee touches, an enclosed one is selected itself, an empty frame on touch, a rotated shape by its outline. A drag from inside a frame never selects that frame and also takes the top-level layers it touches outside it. Once the marquee selects a frame whole, no frame opens and a partly covered frame comes whole. Measured in Figma's web app, 2026-11-11.

Flipped existing assertions: marquee_selects_what_it_touches, cmd_marquee_selects_nested_layers, a_box_selects_like_a_marquee. Tests: marquee_behaviour_tests.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove; Fable 5.1 briefed; Sonnet 5.5 wrote at medium
2026-11-11 17:13:26 -05:00
Trevor BrownandClaude Opus 5.5 9f51517f23 M8: view.pan's parameter text and the MCP guide give the measured steps
64 screen pixels a step, five times as far with big (320), as the code
and the measurement have it; they still said ten times and 20 / 200.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-11 12:39:56 -05:00
Trevor BrownandClaude Sonnet 5.5 529134b850 M4: a boolean group's corner radius rounds its result (#2222)
A boolean group takes a corner radius (and corner smoothing): the Design panel shows the field for it, `node.set cornerRadius` writes it, and the renderer rounds every sharp corner of the group's result after the fold, convex and concave alike. Layers inside keep their own radius and do not stack with it, a radius larger than the edges allow shrinks to fit while the field keeps the typed value, Flatten bakes the arcs, and a mixed selection reads Mixed. Measured in Figma's web app on 2026-11-10.

The rounded result is cached apart from the fold (keyed by the folded path, radius and smoothing), so scrubbing the radius never redoes the boolean steps. The .fig and REST importers and the .fig exporter now carry the radius and smoothing of a boolean group, and paste properties and radius variables reach it. Docs: ui-parity, target-app-parity, gaps, file-format-parity, ROADMAP, mcp.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove; Fable 5.1 designed; Sonnet 5.5 wrote at medium
2026-11-10 13:36:10 -05:00
Trevor BrownandClaude Sonnet 5.5 ccb33e0bbc M7: Text styles: bind a number variable to the weight (#2174)
A text style takes a Number variable on `fontWeight` (`style.bind`): the style gets the face nearest the number and sets the `wght` axis, so static and variable fonts both follow. A bound weight and a bound face name replace each other, and the weight wins in a file carrying both. The style editor's weight menu offers number variables beside string ones, and a variable bound to a weight is Unitless in the CSS export. A number bound to a line height stays pixels, as the reference tool applies it; a test pins that.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove; Fable 5.1 designed; Sonnet 5.5 wrote at medium
2026-11-10 12:43:24 -05:00
Trevor BrownandClaude Opus 5.5 046238d392 Merge main into feat/wrap-style-paragraph-and-style-1827 (#2135 Developer Mode)
docs/ui-parity.md conflicted on the wrap style and text direction rows: kept this branch's text with #2135's Developer Mode naming.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove and wrote
2026-11-09 00:35:59 -05:00
skylar taylor-barrick 3839fe4a0c Naming: use Developer Mode instead of Figma's Dev Mode (#2135)
Figma holds a US registration for DEV MODE (US 7574348). Display text only: the view.devMode label, Inspect tab, shortcut row, refusal messages, CLI help, docs and all locale catalogs now say Developer Mode. Command ids, preference keys and saved fields are unchanged; "Dev Mode" stays a search alias in the Actions palette. Adds a naming guard test.
2026-11-09 06:24:44 +01:00
Trevor BrownandClaude Sonnet 5.5 136ca4cda7 M4: a wrap style per paragraph and in text styles, overriding the layer's (#1827)
"You can apply a wrap style at three levels: Text layer, Paragraph, Text style". The layer level was done in #1871; this adds the other two, following the per-paragraph text direction (#1830) and the list style in text styles (#1876).

ParaList::wrap (None follows the layer) with para_wrap_style, set_wrap_style (the layer level, clears overrides), set_para_wrap_styles and common_wrap_style; restyle_breaks takes a style per paragraph; ParagraphStyle::wrap_style; text.wrapStyle and node.set wrapStyle with start/end; inspect lineWrapStyles; CSS text-wrap only when the paragraphs agree; the Wrap style control follows the paragraph; a read-only row in the style editor. The .fig mapping is left for a later change.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove; Fable 5.1 briefed; Sonnet 5.5 wrote at medium
2026-11-07 21:13:39 -05:00
dotCooCoo 97f086e091 Docs: the Display P3 export sentence names RGB PDF and says CMYK PDF ends as DeviceCMYK
The colour profile paragraph in docs/mcp.md said SVG and PDF export
Display P3 files converted to sRGB, without the RGB qualifier the export
tool text now carries. It now says SVG and RGB PDF convert to sRGB, and
PDF with `cmyk` converts to sRGB the same way and then to DeviceCMYK.
The comment above the export match in file.rs says the same.
2026-11-07 16:36:59 -08:00
dotCooCoo 297426c595 Export: color profile text states which formats are tagged and that CMYK PDF is DeviceCMYK
The export tool and command descriptions, docs/mcp.md and the file-format
table said PDF is always sRGB, that sRGB JPG is untagged and that every
exported file is tagged with its profile. RGB PDF is sRGB and PDF with cmyk
is DeviceCMYK; JPG embeds an ICC profile for sRGB and Display P3; WebP embeds
one for Display P3 only. The JPG quality (1 to 100, default 90) now has one
row in the format table.
2026-11-06 22:21:51 -08:00
BFlat b64f13ac56 Merge pull request #1759 from dotCooCoo/feat/export-color-profile
Export: each export setting chooses a color profile
2026-11-07 12:54:29 +08:00
BFlat 8d1b183e7d Merge pull request #1913 from tommy1616/feat/traditional-chinese-taiwan
M10: Traditional Chinese (Taiwan) interface draft
2026-11-07 12:52:13 +08:00
BFlat d578f44742 Merge pull request #1878 from TrevorBrown-dev/feat/region-fills
M8: a fill per region: the Fill section and the fill commands edit the regions selected in vector edit mode (#1875)
2026-11-07 12:29:43 +08:00
bflatastic a6f6c42886 Merge remote-tracking branch 'origin/main' into landb/1913 2026-11-07 11:28:35 +07:00
bflatastic 02f5a3520a Merge main into #1759 2026-11-07 11:19:38 +07:00
bflatastic f4f16f1ba1 Merge main into #1913 2026-11-07 10:57:11 +07:00
bflatastic a864c9beac Merge main into #1997 2026-11-07 10:50:56 +07:00
bflatastic 01096b90f1 Merge main into #1997 2026-11-07 10:50:30 +07:00
Trevor BrownandClaude Fable 5.1 13937c70eb Merge upstream/main into feat/region-fills
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-11-06 22:39:44 -05:00
bflatastic 05530b794e Merge main into #2049 2026-11-07 09:42:38 +07:00
Trevor BrownandClaude Fable 5.1 e4b3815439 Merge upstream/main into feat/region-fills
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-11-06 21:40:15 -05:00
bflatastic 3ebd14ad2d Merge main into #1876 2026-11-07 09:10:47 +07:00
bflatastic a632d63602 Merge main into #2049 2026-11-07 09:10:44 +07:00
bflatastic 88f6986bda Merge main into #2049 2026-11-07 08:58:17 +07:00
bflatastic e65c46761a Merge main into #1913 2026-11-07 08:55:12 +07:00
bflatastic 79d6335c90 Merge main into #2047 2026-11-07 08:54:47 +07:00
Trevor Brown 8f1a3a35ff Merge remote-tracking branch 'upstream/main' into feat/region-fills 2026-11-06 20:52:20 -05:00
BFlat 5762212ced Merge pull request #2006 from JonRC/fix/jpeg-quality-srgb-icc
M6: JPG exports take a quality and embed the sRGB profile (#2004)
2026-11-07 09:47:15 +08:00
bflatastic a170ca7e3e Merge main into #1913 2026-11-07 08:45:02 +07:00
bflatastic 7e9a853da6 Merge main into #2047 2026-11-07 08:43:16 +07:00
bflatastic 593a689280 Merge main into #2049 2026-11-07 08:39:43 +07:00
Filip StrajnarandClaude Opus 5.5 7f62fc1416 M5: proto.settings refuses an unknown device and answers the settings (#2027)
`proto.settings` took any string as the device ("Pixel Nonexistent", "iphone 16") and saved it in
the file: the presenter then drew no device frame while its picker showed the name as if it were
one. An unknown colour was already refused with the device's colours, but a typo in the device
went unnoticed, and an agent couldn't read the settings back (`proto.settings {}` answered
`{ok: true}`, and neither `inspect_document` nor `get_node` shows a page's prototype settings).

An unknown name, or a value that isn't a string, is now refused with every name the picker offers
("None", "Custom size" and the devices), and nothing changes. A known name is taken in any case and
with spaces around it, and stored as the picker spells it (`known_device`). Every call answers the
page's settings as they are after it (`settings_json`): device, background, rotation, the colour
shown, the screen as presented (null without a device), the custom size and responsive, beside the
`ok: true` it answered before; `proto.settings {}` reads them.

Test: `proto_present_tests::unknown_devices_are_refused_and_settings_read_back`. Docs: mcp.md,
prototyping-parity.md, ROADMAP.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LvG6E2LxvJ6MuFmiLA6Zqm
2026-11-06 12:44:01 +01:00
Filip StrajnarandClaude Opus 5.5 853e8c6cc4 M8: a minimised window under Wayland answers control requests (#1906)
Under Wayland an app can't tell that its window is minimised (no `minimized`, no `occluded`),
and the compositor stops asking it to draw. eframe keeps running the app's logic for a window
whose redraw is overdue, but `control::background` still left every request for "the window's
frame", which never came: with the window minimised on GNOME or KDE Plasma each control-channel
or attached-MCP request waited and timed out after 60 s ("it was not applied").

`control::background` now treats a window that drew no frame for `NOT_DRAWING_AFTER` (0.2 s)
while a request waited for it as hidden: requests that act on the app's state are answered from
the logic passes, as they are for a window the platform reports minimised. `FigApp::control_waits`
keeps, per window, its pass count and the time the wait began; a frame drawn since starts the
wait again, and a pass is asked for 0.2 s later while a request waits. Screenshots and `ui.input`
still wait for a drawn frame. Measured on GNOME Wayland with the window minimised by its own
button: 0.54 s a request (before: 13.7 s for one, then 60 s timeouts).

Test: `idle_tests::a_window_that_stopped_drawing_answers_from_its_logic_passes`. Docs:
control-protocol.md, mcp.md, hardware-parity.md, target-app-parity.md, ROADMAP.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LvG6E2LxvJ6MuFmiLA6Zqm
2026-11-06 12:27:59 +01:00