The desktop app built eframe without its `links` feature, so egui-winit dropped every
`ctx.open_url` with only a log warning: the update prompt's What's new link and Download
button, the About and Credits links, Terms in Live and the link in the Dev Mode panel did
nothing on click. The feature adds no crate: `webbrowser` is already a dependency of the app.
DeckCraft's desktop app builds eframe with it too.
`links_in_the_interface_open_in_the_browser` fails without the feature.
Co-authored-by: Oleksii Sukholita <oleksii.sukholita@gmail.com>
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>
The merge spliced this branch's submenu sentence into the middle of
main's row. The row is main's again, with the measured first-frame
sentence in place of the old 0.15 s one and #2220's overflow sentence
kept.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adds step-security/harden-runner (audit, pinned to v2.22.4 like
craft-common-actions) as the first step of each job that did not have it,
so every workflow in the org's public repos reports its egress to
StepSecurity. Audit, not block: block-mode allow lists come from each
job's observed traffic.
Typing `5. ` at the start of a plain paragraph starts a numbered list whose first item reads 5 (Figma has no start-number field); the next item goes on with 6. Digits only, 1 to 9999; `0. `, `12a. ` and `2)` stay text (not measured), `1)` works as before. The measured restart rows (plain paragraph, bullet item) are no longer marked silent.
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
The minmax(0, 1fr) rule holds for fixed-size and hug-size children; a
Fill child's own minimum keeps its track at least that big, as before
(not measured).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The paste handler read the system clipboard synchronously (2 s timeout) even
though the paste event already carries that text, and discarded the read's
result. On the desktop, the clipboard bridge delivers `event_text` that it read
while the window thread was free; re-reading from the paste handler blocks that
same window thread - and when the app itself owns the clipboard (a self-paste),
its own data source can only be served by that very thread, so every self-paste
froze the window for the full 2 s read timeout on Linux/Wayland.
Prefer the event's text and only fall back to the synchronous read when the
platform handed over none (chords, image-only clipboard, context-menu paste).
A regression test pins that a paste event carrying text never triggers the
synchronous read.
Submenus of the main menu were not constrained to the window (constrain: false, so they sit
beside their row), so the Object submenu ran past the bottom edge with its lowest commands out of
reach. Menus and submenus are now held within the window's height (moved up, never above the top,
8 pt margins, still beside their row so menu-aim is unchanged), and a panel taller than that
scrolls with the wheel; the keyboard's focus scrolls into view.
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>
* **No blank canvas** when switching back to a document tab or to a page in a file: the image it had when last shown is drawn from the first frame while it renders again
* Images of up to four recently shown files and pages are kept; closing a tab frees its image right away
Refs: #2074
pans_and_edits_get_no_preview_and_build_on_the_kept_image failed in full lib runs with "a pan after a previewed zoom renders strips only: Full". The render kept from the zoom is stale once the global font generation changes (retained.rs prepare: last.fonts == layout_generation()), and the once-per-process system font scan that many other tests start bumps it (fontdb.rs scan_system_fonts -> clear_layout_cache). When that scan landed between the test's zoom and its pan, the pan redrew in full instead of patching. Unrelated to the clock or the threshold. document() now runs scan_system_fonts() first (a concurrent caller waits for the scan), so the generation is settled before any render. Test-only change; the shipped staleness check is intended behaviour.
Stress, full lib binary with 16 test threads: 3 of 6 runs failed before, 0 of 25 after.
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>
* fix(collab-net): never send the server key over plain ws:// to another machine
Publishing a plugin, uploading or sharing with the server's key accepted a
ws:// address for a remote host, so the reusable administrative key went
out in clear text. The key now goes only over wss://, or over ws:// to
this machine (loopback or localhost); browsing without a key is unchanged.
* address review: connect only to loopback addresses for a plain ws://localhost endpoint
The suite has 68 cases with this branch's three (the intro still said
64, and the revision row named totals nobody had counted).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On a fixed-size axis a Fill (1fr) track now splits the free space by its fraction, after gaps and padding, and a fixed-size or hug-size child alone in it asks nothing of the track, so a child bigger than its share overflows into the next track. Measured in Figma web: frame 300 x 200, rows 1fr / 1fr, children 100 x 150 and 100 x 20 give rows 100 / 100 (second child at y 100); with a row gap of 10, rows 95 / 95 (y 105); with the frame height on Hug the rows fit their content, 150 / 20 (frame 170). This replaces the 2026-10-11 rule from the documentation (a track never gets less than its content). Unchanged: a Fill child's own minimum, spanning children, Hug and Fixed tracks, the Hug-axis path.
Three behaviour cases flipped to the measured rule and three added with the measured numbers; the two parity docs are updated.
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
The closing pass moves out of reopen_loops (back to main's body) into close_bridged_loops, run only by remove_segments and delete_vertices when the segment or point count changed. Every loop takes what closing_segment returns against one snapshot, so two fills that shared a deleted border both close through the bridge, as rounding already draws them. The owner map is gone.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove; Fable 5.1 decided; Sonnet 5.5 wrote at medium
Flatten used the vector's network as stored, so a rounded point kept its radius and the box kept the cut-off sharp vertex. It now takes the network as the layer draws it (VectorNetwork::rounded_smoothed through geometry::drawn_network): each rounded point becomes the arc's end points joined by curves, every radius reads 0, and the layer's box is re-fitted to the baked geometry. Shapes' own radii were already baked; a rounded point beside a curved segment keeps today's behaviour.
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
Checking a loop's closing segment against every closing already accepted was quadratic in the
number of open loops. A map from closing segment to the chain that took it first answers it in
one lookup; behaviour is unchanged. A test closes 50 independent chains through their own
segments.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove and wrote
Two regions over one open chain both got the closing segment when rounded, but reopen_loops gave it to the first loop only, so after an unrelated deletion the second region's curved closing segment dropped out of its fill. The pass now takes the segment for every loop that walks the same chain (same segment set); a different chain still can't share it.
closing_segment no longer scans every segment and every loop per call: rounded_smoothed and reopen_loops build one LoopIndex (endpoint pair to segments, and which segments are in a loop) per pass and pass it in.
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
The Vietnamese row said "cấu hình của tệp" (the file's configuration)
for the file's profile. It now says "hồ sơ màu của tệp", the term the
Color profile label uses.
An export setting set to sRGB still writes sRGB files in a Display P3
document, so the note no longer says every exported PNG, JPG and WebP is
tagged Display P3. Follows #1759.
A Pen bridge between two degree-2 points leaves the region alone, and Delete on the point between them then rotated the loop open with the bridge in no loop, so even an unrounded fill ran straight across a curved bridge. reopen_loops now pushes the one segment in no loop that joins an open chain's ends onto the loop's end (winding kept, loop by loop), as connect does. This also covers removing segments and the eraser.
closing_segment is public, derives its own start point, walks strictly (a loop out of walking order is left alone) and gives up when two segments qualify. The render fix stays as the fallback for files already saved in that state.
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
The reporter's file has a corner cut off by a segment drawn first, with the corner point then deleted with Delete. The region's loop is left as the open chain of the other four segments, and the cutting segment, which joins the chain's two ends, is in no loop. The stroke follows the network, so it rounds both ends of that segment; the fill and the selection outline follow the loop.
Cause: VectorNetwork::rounded_smoothed rebuilds each loop by inserting a corner's arcs where the loop arrives at the point, so the point the loop starts at is never cut (in a closed loop it is arrived at last), and the open loop's closing edge ran straight to it. closing_segment now finds the segment joining an open loop's two ends when no loop holds it, and rounding walks it as the loop's last segment, so every corner of the fill and outline matches the stroke. Closed loops and the cases #1991 fixed are untouched.
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
The frame's Swap orientation button and the selection's quick-action buttons (24 pt) still
painted their glyphs at the old 14 pt inset beside Fit to contents' 16 pt; they use
`icon_glyph_rect` now.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove and wrote