boards/board.rs: kept this branch's STICKY_TEXT_SIZE export (sticky_font_size is gone) and main's settle_mind_maps export. Docs: main's status line with ours in front, both revision rows.
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
* 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>
release.yml also runs nightly on main with craft-common-actions' dry-run: every release build
except macOS, with nothing signed, pushed or drafted. Breakage that only the release build hits
(riscv64, Flatpak, FreeBSD, packaging) then shows up the next morning instead of on release
day, as it did on 11 Nov 2026.
insert_model cleared the copied start with one set_para_lists call per newline, each scanning the whole text, and set_para_lists also zeroed the level of plain paragraphs. Add TextData::clear_list_starts (one pass, touches only start_offset, no-op when no paragraph has a start) and call it once over the created paragraphs, only when the text has a newline.
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
* M5: Locked layers follow Figma's rules: no nudge, a locked parent's children stay locked (#1560)
Pins Figma's locked-layer behaviour (measured in Figma's web app, 2026-11-10; help center "Lock and unlock layers") in a new lock_behaviour_tests suite. Fixes the divergences: transform.nudge and transform.nudgeSize skip locked layers, object.toggleLock without a value counts a child of a locked parent as locked (so it never locks the child on its own), and the Layers panel padlock on such a child is inert.
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
* Layers panel: a padlock sweep skips the children of a locked layer (#1560)
A padlock drag sweep no longer collects rows with `locked_above`, so
dragging across a locked frame's children leaves their own flags alone
and draws no swept value on them. An eye sweep is unchanged.
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
* M5: Lock/Unlock leaves a locked layer's child alone in a mixed selection (#1560)
With a locked frame's child and an unlocked layer selected, Lock/Unlock set both own flags, so
the child stayed locked once the frame was unlocked. With no explicit `locked` value, the command
now skips a layer whose parent is locked, as its padlock does; an explicit value (scripts) still
sets it.
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>
Co-authored-by: FredApps <FredApps@users.noreply.github.com>
* fix(flatpak): allow release checks and self-update helpers
* test: keep Flatpak permission parsing within strict Clippy rules
* chore: bump version to 0.17.1 for the Flatpak update fix
* pathops: check closed inputs before faces normalises, share the dash allowance across subpaths, index point incidence once
* pathops: leave out move-only subpaths when closing, budget dashes by the fitted pattern, index only join points
Enter copied the item's start (a typed "5. " gives 4) onto the new item, so once a middle item was unlisted the next one restarted at its copied start. Every paragraph an insertion creates now has start_offset 0; the first item keeps its start. Measured in Figma: unlisting "b" in 5. 6. 7. leaves "c" at 1., and the same for a list started with 1.
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 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>
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 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>