Commit Graph
139 Commits
Author SHA1 Message Date
BFlat a492cca415 M6: .fig import resolves library text styles linked by asset key and orders restated override rows by level (#1234) (#1515)
Style links that name a library style by its asset key and version resolve to the file's copy of the style, as variable links already did. The linked text style beats the copies of its values below the row that links it; rows above that one still win. Override rows that restate a nested level (overrideLevel) apply at that level instead of in wire order.
2026-10-29 17:28:55 +07:00
BFlat 07681afebe M6: .fig import keeps the file's saved line breaks while the text is unedited (#1236) (#1519)
* M6: .fig import keeps the file's saved line breaks while the text and its box are unedited (#1236)

The line breaker already keeps trailing spaces and the last glyph's letter spacing out of the fit test and doesn't round box widths; imported text wrapped a word early or mid-word because local fonts measure slightly differently from the file's. The import keeps the saved line starts (derivedTextData) on the text with the box width and a stable key of its layout content; layout follows them while both match and no line overflows its box by more than 3% (+1 px).

* M6: local check that imported text wraps at the line breaks its file saved (#1236)

Runs only when FIGCRAFT_FIG_SAMPLES names a folder of .fig files: each fixed-width text with saved breaks wraps there once imported, or falls back by the overflow slack; prints the counts.
2026-10-29 17:04:29 +07:00
bflatastic a2fb40e3ef Merge main into #1397 2026-10-29 13:39:34 +07:00
bflatastic 789fa33444 Merge main into #634 2026-10-29 12:25:06 +07:00
bflatastic 676681302a #1397: import generated_record now that the .fig mapper modules name their imports 2026-10-29 12:07:34 +07:00
bflatastic 7e90148fd7 Merge main into #1397
# Conflicts:
#	ROADMAP.md
#	contributors/people.toml
#	crates/format/src/fig/map/layer.rs
#	docs/file-format-parity.md
#	docs/gaps.md
2026-10-29 12:01:19 +07:00
bflatastic 7c413dfe0a Merge main into #1486 2026-10-29 09:32:05 +07:00
Filip StrajnarandClaude Opus 5.5 652bf35b19 M1: page ruler guides survive save and reopen (#1476)
A page kept its ruler guides in `NodeKind::Page`, and since frame guides
(#70) every layer also has its own `guides` field. Both are written as
`guides`, and on reading the layer's own field takes the key, so:

- a reopened page's guides landed in the layer field and were not drawn;
- saving that page wrote `guides` twice (the page kind's list, always
  written, then the layer's), and the file no longer opened ("duplicate
  field `guides`").

Every layer, pages included, now keeps its guides in the one layer field;
the key in the file is unchanged, so existing files open with their guides.
The field reads every `guides` list a layer has, so files already saved
with the key twice open again with both lists, in file order. This also
covers collab `Create` payloads from older peers.

Regressions: JSON round trips of page and frame guides, a page with two
lists, a bad list still refused (doc); save, reopen, save, reopen through
`.figcraft` and a document.json with the key twice (format). Checked in the
app over the control channel: guides drawn after two save/reopen cycles, and
a file with the key twice opens with all its guides.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LvG6Dyzof21BCrUsByhx2w
2026-10-28 22:47:24 +01:00
Filip StrajnarandClaude Opus 5.5 3009d19fde M6: .fig embedded images are copied once per blob, not once per hash (#1059)
Images carried inside a `.fig` message (`image.dataBlob` indexing the
message's `blobs`) were copied out before the message is dropped, one copy
per image hash. Nothing stops a file from pointing many hashes at one
blob: 100 hashes on a 250 MB blob made 25 GB of copies, an out-of-memory
abort from a small file.

The walk now records each hash's blob index, and `embedded_copies` makes
one shared copy per blob for every hash that names it, so the copies are
bounded by the message's own size. Each resolved image is still copied
once on its way into the document, where images are kept by content hash.

Regression: fifty hashes on one blob share one copy; a hash naming a
missing blob is left out.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LvG6Dyzof21BCrUsByhx2w
2026-10-28 22:45:45 +01:00
Dylan M. Taylor 4268bd859f refactor(fig): split mapping and lint test helpers 2026-10-28 16:00:36 +00:00
Dylan M. Taylor c618e402fa refactor(format): replace wildcard imports 2026-10-28 16:00:36 +00:00
Skyfuller1303 faa96926f4 M4: keep stroked whole-shape merges and bound region paints per file
Merging every region of one stroked shape is a no-op again: only fill
parts count, so a vector with several painted regions still merges.

The region paint import budget now covers the whole file instead of
resetting for each layer, so instances of a main with large region paint
stacks cannot multiply the work.
2026-10-28 11:59:53 +01:00
Skyfuller1303 c785e96b1c Merge remote-tracking branch 'origin/main' into feat/fig-vector-region-fills
# Conflicts:
#	crates/format/src/fig/export.rs
#	crates/format/src/fig/map.rs
2026-10-28 10:12:00 +01:00
Skyfuller1303 219a9ea0b1 M4: require FILL styles for vector region fill links 2026-10-28 09:29:22 +01:00
Filip Strajnar 4ea2d29754 M6: preserve FigJam fallback outlines and sticky bodies 2026-10-27 18:47:27 +01:00
StrajnarFilip 01bc4741a1 M6: retain generated FigJam vectors and outer text fallbacks (#1341) 2026-10-26 22:56:23 +01:00
Filip Strajnar 4e650a1c01 M6: preserve FigJam sticky and shape content on import (#1341) 2026-10-26 21:52:09 +01:00
aiongg c9d6b356fc refactor(format): move fig/map test files to fig/map/ 2026-10-26 20:36:51 +00:00
aiongg 064e6be65f refactor(format): split fig/export.rs into export/ 2026-10-26 20:36:50 +00:00
Skyfuller1303 7f707ecca3 M4: preserve inherited region paints and linked fill styles 2026-10-26 21:33:56 +01:00
aiongg 450675919f refactor(format): split fig/map.rs into map/ 2026-10-26 20:17:49 +00:00
aiongg 47ee566f3d refactor(format): move crates/format/src/fig/mod.rs to crates/format/src/fig.rs 2026-10-26 20:17:47 +00:00
Skyfuller1303 a4076caaf4 Merge main and preserve vector region paints through path operations
Retain regional paint stacks and coordinate frames through simplify, offset, flatten, bucket normalization and Shape Builder. Preserve legacy fill semantics and synchronize importer warning catalogs. Verified with cargo xtask ci on Windows and Ubuntu/WSL, native UI screenshots, and CLI round-trip/export checks.
2026-10-26 19:50:00 +01:00
BFlat cac54fd552 Merge pull request #840 from StrajnarFilip/feat/vector-drawable-export
M6: export as Android Vector Drawable (XML)
2026-10-27 01:06:21 +07:00
BFlat 29c89f7d5b Merge pull request #650 from JimKnoxx/overlay-anchor-trigger
M5: overlay positions relative to the layer that opens them
2026-10-27 00:49:52 +07:00
bflatastic c16fd68242 Merge main into #840 2026-10-27 00:38:47 +07:00
bflatastic b3016f7089 Merge main into #1152 2026-10-27 00:14:07 +07:00
bflatastic 632f2cef4b Merge main into #840
# Conflicts:
#	docs/roadmap.md
2026-10-27 00:12:27 +07:00
bflatastic de826e14cf Merge main into #650
# Conflicts:
#	crates/ui-egui/locales/es.toml
#	crates/ui-egui/locales/pl.toml
#	docs/prototyping-parity.md
2026-10-26 23:24:22 +07:00
bflatastic e469cc8135 Merge main into #840
# Conflicts:
#	apps/figcraft-cli/src/files.rs
#	apps/figcraft-cli/src/main.rs
#	crates/engine/src/cmd/file.rs
#	crates/engine/src/lib.rs
#	crates/ui-egui/locales/en.toml
#	crates/ui-egui/locales/es.toml
#	crates/ui-egui/src/export_panel.rs
#	crates/ui-egui/src/export_preview_tests.rs
#	docs/file-format-parity.md
#	docs/mcp.md
#	docs/roadmap.md
#	docs/ui-parity.md
2026-10-26 23:23:07 +07:00
bflatastic 153250fedf Merge main into #1152 2026-10-26 23:00:18 +07:00
Muamer MustaficandCursor b6d3e002df M4: truncated text fills its last line, keeps truncating when resized, and auto height takes max lines (#1375, #1376, #1377)
- The last line shown runs on into the word wrapped after it, so the ellipsis
  fills the line ("Lorem consec…") instead of following the last whole word.
- An explicit height (node.set, transform.resize, a resize handle, fixed
  sizing) on truncating text keeps it truncating (TextData::fix_size).
- Max lines on auto-height text hugs up to that many lines and ends in an
  ellipsis; text.maxLines keeps auto height, Type settings show it as
  truncating, .fig export writes textTruncation and import keeps auto height.
- node.get reports maxLines; text.fit measures every line.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-26 13:14:51 +01:00
bflatastic 07a654959a Merge main into #1021
# Conflicts:
#	docs/file-format-parity.md
2026-10-26 09:12:39 +07:00
BFlat c853432360 Merge pull request #989 from Ridzzz0Alam/fix/981-fig-layer-cap
Large `.fig` files keep their layers and their library links (#981)
2026-10-26 08:32:26 +07:00
BFlat c5b914ead0 Merge pull request #951 from Hamza0101/fix/fig-note-counts
fig import: a note says how much of the file it covers (#467)
2026-10-26 08:32:09 +07:00
Jindřich ŠaršonandClaude Opus 5.5 87db9522b4 M6: Sketch import: merge main (Boards M12 and community fixes)
Conflicts resolved keeping both sides: `.sketch` stays in `is_document`
(now via `OsStr::to_str`); ROADMAP and the parity, roadmap and
file-format docs keep main's headers and rows with the `.sketch` notes
and history rows added.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 19:13:03 +02:00
NetterSilverandClaude Opus 5.5 a80df8ed18 Count scalar kiwi fields against the decoded-value budget (#1188)
Fixes #1057

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 05:26:06 -04:00
JimKnoxxandClaude Opus 5.5 545cd630fd M5: overlay positions relative to the layer that opens them
From the Figma forum request "Set overlay position relative to element,
not to page": an open overlay action takes anchor: screen (default) |
triggerInside | triggerOutside. With a trigger anchor the position preset
is measured on the layer that opens the overlay instead of the screen.
Outside puts top presets above it and bottom presets below it with the
edges lined up (a dropdown is Bottom left + Outside); Center centres it
on that layer. Manual is unchanged.

The interaction editor gets Relative to (Whole screen / Trigger layer)
and Inside / Outside. The player, the command (and so MCP and the
control channel) carry it; the command's params doc lists it. Figma has
no such setting, so .fig export writes it as a manual offset. Old files
and JSON without anchor read as screen and write unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 09:19:33 +02:00
BFlat e3e39bbc4d M6: Dev Mode measurements kept on the canvas, a read-only layers panel (#1248)
* M6: Dev Mode measurements kept on the canvas, a read-only layers panel

Measurements placed between two layers, along a side or to the layer
around one (devMode.addMeasurement / removeMeasurement / measurements),
stored on the layer they start from (saved, synced, undoable; old files
open without them), drawn in Dev Mode as labelled redlines that follow
the layers and listed, placed and removed in the Inspect tab. In Dev Mode
the layers panel only selects and expands.

* M6: Dev Mode measurements: explicit imports, a measurement row of its own (Sonar)
2026-10-24 13:33:26 +07:00
bflatastic b6489aba3b #989: .fig pages keep room for their top-level layers past large library copies 2026-10-24 13:02:25 +07:00
bflatastic 9b78ff8c4a #989: explicit imports, the .fig test helper named main_component 2026-10-24 13:02:24 +07:00
bflatastic a3509895d4 Merge main into #989 2026-10-24 12:54:02 +07:00
bflatastic 61855d362b Merge main into #951 2026-10-24 12:54:01 +07:00
bflatastic 8dcba0684b Batch r2-1 review: .fig export grid sizing in helpers; instance layers clear inherited track sizes
auto_layout's grid branch moves to grid_layout and grid_sizing (SonarCloud cognitive complexity).
unset() clears gridColumnsSizing and gridRowsSizing, so an instance layer with equal tracks no
longer reads back its main layer's track sizes.
2026-10-24 10:31:08 +07:00
bflatastic bd80829a27 Batch r2-1 review: a paint keeps its own opacity through unbind and rebind
color_alpha is the part of a solid paint's opacity that is its typed colour's alpha, not a flag:
binding a colour variable takes only that part out, unbinding puts the variable's alpha back in,
and REST import records it. A 50% paint bound to a 50% variable stays at 25% bound or not.
2026-10-24 10:30:49 +07:00
bflatastic 9fb88b6668 Merge #904: M1: write grid track sizes in .fig export (#465) (@xiaou61)
# Conflicts:
#	docs/file-format-parity.md
2026-10-24 09:24:04 +07:00
RicardoandClaude Opus 5.5 c19b7d0799 .fig export: a property name used with two types in a set writes both definitions
The set wrote one definition per name, so a variant whose property of
that name had another type named a definition the file didn't hold
(CodeRabbit review on #1152).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 12:00:22 -06:00
RicardoandClaude Opus 5.5 4c6c4d9667 .fig export: warn when a set's variants disagree on a property default
The format keeps one default per property of a set; the first variant's
is written (CodeRabbit review on #1152).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 20:46:12 -06:00
RicardoandClaude Opus 5.5 19d6c17b6d .fig export: grid track sizes
Grids wrote their tracks as equal ones, with a warning. Track sizes
(fixed px, hug, fill shares) are now written as gridColumnsSizing /
gridRowsSizing, the fields the import already reads.

Checked on a synthetic grid in the incumbent (fixed 320/140/112/34/34 px
columns): written as equal tracks it came in with five equal columns and
its layers overflowing their cells; now its columns keep their sizes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 20:43:55 -06:00
RicardoandClaude Opus 5.5 2c044f6b80 .fig export: an override that clears a maximum size writes it as infinite
Like an unset axis, a cleared maximum was written as 0 and could
collapse the layer (CodeRabbit review on #1152).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 13:16:16 -06:00