958 Commits
Author SHA1 Message Date
BFlat 12e9b409ed M12: a connector end on any part of an object with Cmd/Ctrl (#1733) 2026-10-31 10:27:56 +07:00
BFlat e2f04b33e0 M11: a tap on a plugin panel's button keeps what was typed in its fields (#1732) 2026-10-31 10:13:01 +07:00
BFlat 6b28ef57dc M4: Dash cap setting for Dash and Custom strokes (#1728) 2026-10-31 09:41:39 +07:00
BFlat 87254913af M3: library analytics list how each style and variable is used (#1730)
* M3: library analytics list how each style and variable is used

A file reports how many of its layers use each of a team library's styles and
variables, and Show usage lists them by a Type choice with their layers and
files. Layers in instances count for their component. Also ignores plugins/target.

* M3: the style analytics test waits for the instance report too
2026-10-31 09:13:08 +07:00
BFlat 57a51af8bb M5: the Controller menu names each button as PlayStation and Switch controllers do (#1726) 2026-10-31 08:41:40 +07:00
BFlat 1c5c9e04c3 M11: widgets draw lines and SVG pictures (plugin API 6) (#1727)
A widget description can have a line, 100 long and black and 1 thick unless told
otherwise, and an SVG that comes in as locked layers, scaled to fit a size and
within the widget's 256 layers. The Counter example uses both.
2026-10-31 08:13:08 +07:00
BFlat 59c7624569 M12: a connector end dropped along a side of a shape attaches to that side (#1708) (#1714) 2026-10-31 07:57:03 +07:00
BFlat bdb6a05976 M8: regression tests for one-sided strokes on rounded shapes and XML-forbidden characters in SVG (#1351, #1124) (#1719)
Both reports were checked by running them and are already fixed on main. Pins a rounded rectangle or frame stroking only the side asked for in every alignment, and SVG font families and ids leaving out characters XML forbids.
2026-10-31 07:41:40 +07:00
BFlat 3837b08a71 M8: a damaged image is refused with a reason instead of showing as an empty box (#1724)
* M8: a damaged image is refused with a reason instead of showing as an empty box (#1474)

* M8: replacing an image refuses a damaged file too
2026-10-31 07:22:44 +07:00
BFlat 943c20f934 M1: images copied elsewhere paste on the desktop and in the browser (#492) (#1723)
The desktop shell swallows a plain Cmd/Ctrl+V, press and release, and sends an
image paste event; FigCraft ignored it and waited for a release that no longer
comes. The browser's paste event gives eframe only text, so the page now reads
the image from it, under the same limits.
2026-10-31 07:07:09 +07:00
BFlat 2e92d36af0 M6: SwiftUI and Compose code name a bound variable by its code syntax (#1716)
Bound variables with an iOS or Android code syntax are named in generated SwiftUI and Compose in place of their value: paints, stroke weight, sizes, corner radius, gaps, padding, opacity and text. A variable with none for the platform keeps the value.
2026-10-31 06:49:41 +07:00
BFlat 920aafb805 M1: the colour picker's Image tab has a placeholder, a preview and takes a dropped file (#1682) (#1713)
Choosing Image shows a checkered placeholder and Upload from computer instead of a dialog at once; an image paint shows its asset preview. A file dropped on the open picker replaces the image, keeping the fill mode, crop, position and adjustments (image.replace, one undo step; paths capped as image.place's). The browser's file picker reaches the tab too. Also fixes a race in library_detach_tests.
2026-10-31 06:32:59 +07:00
BFlat 1ea19482d3 M1: the Frame tool's Phone presets have the iPhone 17 family (#1691) (#1720)
iPhone 17, 17 Pro, 17 Pro Max and Air, at the sizes the prototype device list uses; a test keeps presets named like a device at its size.
2026-10-31 06:13:47 +07:00
BFlat 477b83560b Merge pull request #1721 from WiktorKluczny/perf/fallback-fonts-one-face
M8: text reads only the fallback fonts it draws with
2026-10-31 05:51:19 +07:00
BFlat f0ceb46dcb M8: Show in folder works in the Flatpak build and selects the file on Linux (#1701) (#1711)
* M8: Show in folder works in the Flatpak build and selects the file on Linux (#1701)

* M8: Show in folder's fallback path is tested on Linux
2026-10-31 05:44:29 +07:00
bflatastic 71a625896b Merge main into #1721 2026-10-31 05:31:25 +07:00
BFlat 87e42a14f2 M4: a dashed line starts and ends with a half-length dash (#1718) 2026-10-31 05:28:15 +07:00
BFlat 71323ee780 M8: search fields in the left panels keep their text in the middle (#1703) (#1709) 2026-10-31 05:10:48 +07:00
BFlat b462a48346 M12: a connector's path can be reshaped by dragging its path handles (#1710) (#1717) 2026-10-31 04:53:36 +07:00
BFlat 4bcfd5247f M12: boards have 16 more shapes, in grid pickers (#1705)
* M12: boards have 16 more shapes, in grid pickers

* M12: a board shape's id and name sit in one table
2026-10-31 04:27:12 +07:00
BFlat 2d784c363d M3: library analytics count insertions and show them over time (#1704)
Gap 10: a file counts the library instances it places, creates, pastes or duplicates and reports them like its detaches. The server counts what a file's totals grow past their highest in the current week and keeps a year of weeks (actions.json). library.usage {days} and Show usage give insertions and detachments over the past 30 days, 90 days or year. New variants are appended; an older server refuses them and Show usage says so.
2026-10-31 04:13:14 +07:00
BFlat 12d36a9913 M4: a stroke's Custom style takes a dash pattern as a comma-separated list (#1681) (#1712) 2026-10-31 03:56:43 +07:00
BFlat 437d052396 M8: a control request can set its own timeout, up to 10 minutes (#1696) (#1706)
A request line can carry timeoutMs beside id and method, capped at 600,000 ms; without it the wait stays 60 s and older apps ignore the field. figcraft-cli mcp --attach PORT --timeout SECONDS sends it with every request and reads the answers that much longer. A timeout's message says how long the request waited.
2026-10-31 03:41:56 +07:00
BFlat fd8d49fc95 M11: a widget opens its plugin's panel (plugin API 5) (#1684)
* M11: a widget opens its plugin's panel (plugin API 5)

Gap 6: a widget callback's ui_show opens the plugin's panel and keeps the module loaded; the panel's callbacks get the widget's id and state and redraw it in the same undo step. Older plugins' ui_show from a widget still opens nothing. The Counter example sets its count from a panel.

* M11: open_panel takes its opener as one value
2026-10-31 03:24:32 +07:00
BFlat 9dafa22a20 M8: the Menu key opens the context menu; stale parity rows on reorder rings and shortcut counts corrected (#1677) 2026-10-31 03:07:14 +07:00
BFlat 760aece238 M5: an Open link action can open in place of the prototype, with Open in new tab off (#1685) 2026-10-31 02:37:54 +07:00
BFlat bbd1188c81 M3: a collection of this file can be extended (#1679)
Gap 14: variable.extendCollection and Extend collection on a collection's row in the Variables editor. Extensions follow edits of the collection they extend at once (normalising keeps them in step whenever variables change), extensions extend again, and a loop of extensions from a hostile file comes apart into plain collections.
2026-10-31 02:21:53 +07:00
BFlat f152ca995f Merge pull request #1697 from saimskywalker/issue-1095-roots-refuse-network
M8: commands confined to automation roots reach no server (#1095)
2026-10-31 02:10:56 +07:00
BFlat b377c70a8c M4: the eyedropper with Cmd/Ctrl+Shift makes a colour style or variable (#1674)
* M4: the eyedropper with Cmd/Ctrl+Shift makes a colour style or variable of what it picks

* M4: the Create from color window's collection picker is its own function
2026-10-31 02:09:08 +07:00
BFlat 54a0c6954b M9: a live session's welcome sends the document compressed to clients that read it (#1665) (#1693) 2026-10-31 01:51:12 +07:00
saimskywalker e6059b3543 M8: confined library checks say they were refused (#1095)
library.check refused nothing while automation roots confined it: it
counted libraries it never asked about and remembered them as yours. It
now refuses before remembering any. library.updates and library.list
answered a refused check with the team library cached earlier, as if the
server had nothing newer; the refusal now reaches them instead of
falling back like an offline server. The MCP and control protocol docs
say that a root on a network share still reaches that file server.
2026-10-31 02:43:50 +08:00
BFlat b6499a295c M8: a control request that times out says whether it was applied (#1673) (#1692)
The UI starts a request through its gate (a new Running state) just before running it and never runs one the transport already cancelled. At the timeout the reply says it was dropped and not applied, or that it is still running and will take effect; a reply that just made it is delivered. Only screenshots and input blame the window.
2026-10-31 01:37:09 +07:00
BFlat 9f4d1ce75b M12: board votes say who voted for what, and earlier votes' results are kept (#1666)
* M12: an ended vote's results say who voted for each object

* M12: a board keeps earlier votes' results, listed in Results and deleted one at a time

* M12: the vote Results popover is drawn by small helpers, and its stepper, rows and Clear are tested
2026-10-31 01:19:03 +07:00
saimskywalker ef4c0aacfd M8: commands confined to automation roots reach no server (#1095)
The roots confined files only: a confined agent could still publish the
open document to any server, host it on the network or join a session.
The engine reaches the network only through the live link, which now
refuses a call made while the roots confine it (hosting, joining,
publishing, sharing, team libraries, plugin directories), and skips the
background team library checks. The MCP and control protocol docs say so.
2026-10-31 02:05:29 +08:00
BFlat e97961ba66 M12: stamps stick to the objects they land on, which are highlighted first (#1671)
* M12: stamps stick to the objects they land on

A stamp sticks to the topmost object under its centre (BoardItem::Stamp gains an optional on, left out when empty so older files open with stamps on nothing) and the board's normalize pass carries it when that object moves or turns, once when both move together. A stamp dragged onto another object sticks to that one, off everything to nothing; one whose object is deleted stays where it is. Gap 24.

* M12: the object a stamp will stick to is highlighted

While the stamp tool is over an object, or a stamp is dragged over one, the object it will stick to is outlined with the canvas's hover outline (Overlay::stamp_target, found by the same stamp_target as board.stamp and settle_stamps). A drag no longer drops what it moves into the auto layout of a sticky, shape with text or table: board objects take no drops; a stamp already inside its sticky moves with it once. Builds on #1671. Gap 24.
2026-10-31 00:25:38 +07:00
bflatastic 497e2d020f Merge main into #1678 2026-10-30 23:51:41 +07:00
BFlat 958b9b8c44 Merge pull request #1676 from nine-codes/claude/sharp-feynman-me8n1o
M10: Bosnian catalog covers main's new paste strings
2026-10-30 23:46:50 +07:00
BFlat 170b9f9066 Merge pull request #1675 from MarekSpodBiedry/issue-1664
Live join: a large Welcome still downloading is not given up on at the idle timeout (#1664)
2026-10-30 23:44:38 +07:00
Patrick Wozniak d015436b13 M9: team links the list no longer hands out are removed at startup; a team link is made before the list changes 2026-10-30 17:39:36 +01:00
BFlat be6a7af25f M3: team library analytics count detached instances (#1668)
* M3: team library analytics count detached instances

Detaching an instance of a library component counts it in the file (libraries.detached, saved with it, capped). The background library check reports the counts after its fetch (ReportDetached); the server keeps them per file beside the file's usage report in usage.json (same caps) and answers Detached with them. Show usage and library.usage list detaches per component and per file (detached, detachesKnown). The new request and reply variants are appended, so every older library message keeps its bytes; an older server refuses the new requests, which the app ignores. Gap 10.

* M3: the detach test waits for the instance count too (the two arrive in separate reports)
2026-10-30 23:29:18 +07:00
Claude 3f867cc4fc Merge main into the Bosnian catalog follow-up
Main merged #1652 (the Bosnian catalog) and added more strings; ROADMAP keeps main's rows with the count updated, and bs.toml translates the two new strings (a pasted table's size limit, connector labels without a snapshot), so it covers all 1,906 UI strings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013Tayw8nmxoLLmKv13jK93z
2026-10-30 16:18:27 +00:00
Patrick Wozniak 2d23f95673 M9: Home ▸ Online shows the server's team list, and its files open by links without a secret (desktop and browser) 2026-10-30 17:10:12 +01:00
BFlat b3ca228a75 M5: skipping the Open link notice by command is saved at once (#1667)
proto.linkNotice from the Actions palette, the control channel or MCP changed the preference in memory only until the app next saved its preferences. It now sets Session::prefs_unsaved, which the app saves at the end of the frame like installed plugins and live-session tokens; the notice's own Don't show this again goes the same way. Gap 15.
2026-10-30 23:05:57 +07:00
BFlat 7e9d6ce8c5 M12: line ends, dashes, weight and any colour on a board connector's bar (#1596) (#1632)
The bar over a selected connector adds start and end point menus with every line end, a line style menu (solid or dashed, weights 1 to 6) and a colour wheel opening the colour picker, beside the board colours and line type; every control names itself on hover. UI only, through board.setStyle and the stroke's dashes and weight.
2026-10-30 22:50:20 +07:00
MarekSpodBiedry 0ebe626062 Live join: a large Welcome still downloading is not given up on at the idle timeout (#1664) 2026-10-30 16:38:36 +01:00
Claude 34cd65a711 M10: Bosnian catalog covers main's new paste strings
Four strings main added since the last merge (pasted design layers and
their missing images, image fills and shared styles not in the file) get
Bosnian translations, so the catalog covers all 1,905 UI strings again;
the counts in ROADMAP.md and the localization parity doc follow.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013Tayw8nmxoLLmKv13jK93z
2026-10-30 15:34:04 +00:00
BFlat 4f5a25cc82 M12: spreadsheet cells paste onto a board as a table (#1663) 2026-10-30 22:32:44 +07:00
BFlat ddda495a6f M6: a long frame name stays on one line in the Export button and Dev Mode's header (#1650) (#1661) 2026-10-30 22:12:49 +07:00
BFlat db725dc73f M8: the Design panel and the selection overlays stop going over a large selection every frame (#1571) (#1660) 2026-10-30 21:58:41 +07:00
BFlat 9b1812432f M6: plugin panels show images (#1639)
* M6: plugin panels show images

An image control in a plugin panel carries a picture as base64 (at most 256 KB; panel specs up to 1 MB), drawn at its size up to a field's width and named by its label, which shows instead when the picture can't be decoded or is over 4,096 px on a side. Images can't be clicked or be command parameters. Panel and form captions no longer wrap.

* Render worker: in_flight counts the watchdog's late preview

The watchdog that previews a render running past PREVIEW_AFTER_MS could pass its still-rendering check, lose the race to the full render, and then hand over its preview and wake the UI after Worker::in_flight had gone false. An idle test that had settled then saw a 0 ns repaint whose cause egui reports a frame late (CI on #1639: 'asked for a repaint in 0ns: [app/files.rs:211]', the autosave tick of the previous frame). The watchdog now marks itself busy from before that check until it has handed over and woken (or skipped), and in_flight counts it; the full render's done markers are SeqCst so the watchdog sees a finished render before in_flight can read idle.

* Docs: drop a status item the merge listed twice
2026-10-30 21:26:15 +07:00