Commit Graph
63 Commits
Author SHA1 Message Date
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 9fdd226509 Merge pull request #664 from phonedu/feat/vue-code-target
M6: a Vue code target (single-file components)
2026-10-27 00:48:53 +07:00
bflatastic c16fd68242 Merge main into #840 2026-10-27 00:38:47 +07:00
bflatastic 502098e02a #840: the status lines without the merge's conflict markers 2026-10-27 00:32:35 +07:00
bflatastic 2aae395310 Merge main into #840 2026-10-27 00:31:32 +07:00
bflatastic fd0f4d8b60 Merge main into #664
Main's class_name takes the node kind (#1372); Vue's slot names pass slot.
2026-10-27 00:30:42 +07:00
bflatastic b3016f7089 Merge main into #1152 2026-10-27 00:14:07 +07:00
bflatastic 4176400e09 Merge main into #664
# Conflicts:
#	crates/engine/src/code_connect.rs
#	crates/engine/src/codegen.rs
#	crates/engine/src/component_codegen.rs
#	crates/engine/src/lib.rs
#	crates/engine/src/playground.rs
#	crates/ui-egui/locales/bn.toml
#	crates/ui-egui/locales/cs.toml
#	crates/ui-egui/locales/de.toml
#	crates/ui-egui/locales/en.toml
#	crates/ui-egui/locales/es.toml
#	crates/ui-egui/locales/fi.toml
#	crates/ui-egui/locales/fr.toml
#	crates/ui-egui/locales/id.toml
#	crates/ui-egui/locales/ja.toml
#	crates/ui-egui/locales/ka.toml
#	crates/ui-egui/locales/ko.toml
#	crates/ui-egui/locales/nl.toml
#	crates/ui-egui/locales/pl.toml
#	crates/ui-egui/locales/pt-BR.toml
#	crates/ui-egui/locales/ru.toml
#	crates/ui-egui/locales/sv.toml
#	crates/ui-egui/locales/tr.toml
#	crates/ui-egui/locales/zh-Hans.toml
#	crates/ui-egui/src/dev_mode.rs
#	docs/dev-mode-parity.md
#	docs/gaps.md
#	docs/mcp.md
#	docs/target-app-parity.md
2026-10-26 23:52:51 +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
Ridzzz0Alam a648700fcc M1: Save no longer overwrites changes another app made to the open file (#1330)
With a file open in the desktop app, figcraft-cli could change it on disk;
the next Save (or auto-save) wrote the app's copy over it and said
"Saved", losing the CLI's changes.

Each tab now remembers its file's size and modification time when it
opens, reverts or saves it (the Stamp library files already use), and
Save and auto-save refuse while the file on disk differs, pointing to
Revert to saved or Save as. Scripts pass `file.save {overwrite: true}`.
Save as and saves to an explicit path are unchanged.
2026-10-26 11:04:01 +01:00
bflatastic 07a654959a Merge main into #1021
# Conflicts:
#	docs/file-format-parity.md
2026-10-26 09:12:39 +07:00
dotCooCoo 1bac7367ba Docs: the PNG row's include bounding box applies to any layer from the commands
The Export section offers include bounding box for text layers, and
file.export and export.update take it for any layer.
2026-10-25 17:34:16 -07:00
dotCooCoo 2581b0bfd9 Docs: the PNG row names ignore overlapping layers and include bounding box for text layers
The PNG row of docs/file-format-parity.md listed the export settings as
"contents only" and "include bounding box (the layer's own box)". Since
#1307 the Export section labels the first option Ignore overlapping
layers and shows Include bounding box for text layers. The row now uses
those names, says that ignore overlapping layers is on by default, and
gives include bounding box for text layers, as the help page lists
them. The status line gets the new date and topic, and the revision
history gets a row; the percentages and hours are unchanged.
2026-10-25 15:27:32 -07:00
Jindřich ŠaršonandClaude Opus 5.5 23e3131e90 M6: Sketch import: .sketch files in recent files show their preview
A .sketch file opened from disk joins the recent files, where it had no
picture and a generic icon. FileKind::Sketch reads the preview.png Sketch
saves under previews/ (within the thumbnail caps) and gets the design-file
mark, like .fig. Test: sketch_files_show_their_preview_png.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 12:33:22 +01:00
Jindřich ŠaršonandClaude Opus 5.5 db1bc539b0 M6: Sketch import: offer FigCraft for .sketch on Windows and Linux too
Linux: the shared-mime-info package declares application/x-sketch (a zip,
*.sketch) and the desktop entry and AppStream metadata list it. Windows:
the installer registers a Figcraft.Sketch ProgId under .sketch's
OpenWithProgids and .sketch in figcraft.exe's SupportedTypes, never as
the default. Both hand the path to file.open, as macOS does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 12:25:07 +01:00
Jindřich ŠaršonandClaude Opus 5.5 c80801391f M6: Sketch import: offer FigCraft in Finder's Open With for .sketch
Info.plist declares Sketch's public type identifier (imported, so it is
known on a Mac without Sketch) and lists it as an Alternate, Viewer
document type: Sketch stays the default, FigCraft is offered. The app
already opened .sketch from an open-documents Apple event via file.open.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 12:22:06 +01:00
Jindřich ŠaršonandClaude Opus 5.5 e712b359fc M6: Sketch import: merge main
Conflicts were only in the Change notes of docs/file-format-parity.md and
docs/target-app-parity.md: main's notes kept, the `.sketch` note added.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 12:22:06 +01:00
aiongg 86bcfaddb9 Merge #1305
# Conflicts:
#	docs/file-format-parity.md
2026-10-25 02:21:44 +00:00
dotCooCoo 9c20d06abd M7: with Contents only on, a slice in a frame or group exports only that container
A slice exported every layer of its page that showed in its area, whatever
its Contents only setting said. With Contents only on (the default), a slice
inside a frame or group now exports only that frame or group and the layers
in it. With it off, or for a slice on the page or in a section, the slice
exports everything in its area as before. The Export section's preview of a
slice follows its first export setting in the same way.
2026-10-24 15:53:33 -07:00
dotCooCoo 27fc3cec81 Docs: list each file-format status topic once
The status line of docs/file-format-parity.md repeated eight topics,
from SVG/PDF export depth refusal (#208) to "last major". Each topic is
now listed once, and the boards entry closes its parenthesis.
2026-10-24 10:34:29 -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
dotCooCoo 954f9036da Docs: parity rows for mouse-trigger delays, outline options and missing fonts
Three parity rows still listed work that has landed on main. The
prototyping Triggers row listed delays on mouse enter, leave, down and
up as missing; they landed on 2026-10-13. Canvas & navigation's
remaining work in target-app-parity listed outline mode's Include
hidden layers and Include object bounds, which View > Outlines has.
The file-format Fonts row said missing fonts give warnings only; the
desktop app lists them in the Missing fonts window, and replacing them
is still missing.

Each file gets its status line and a revision-history row. The
percentages and hours are unchanged.
2026-10-24 09:19:45 -07: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 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
BFlat 8167f13a6a M12: Boards: a collaborative whiteboard file kind (#1229)
Board files (File > New board) with sticky notes, shapes with text, connectors that follow what they join (straight or elbow, arrowheads, labels), marker, highlighter and eraser, and stamps; a board toolbar and a contextual bar; the Design panel hidden on boards, Prototype and Dev Mode refused there. Boards are ordinary FigCraft files built from ordinary layers, so saving, undo, export, MCP and live sessions work unchanged. File tabs, recent files and Open files show a pen nib for design files and a note for boards (original icons drawn in code).
2026-10-24 04:18:55 +07:00
BFlat d6e8a6e874 Docs: roadmap entries for the community PRs in #507, #510, #529 and #530 (#587)
Roadmap, milestone and parity rows for the 93 community PRs landed in batches #507, #510, #529 and #530.
2026-10-24 02:02:19 +07: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 70a080af5b .fig export: files Figma imports, with component set properties
Checked by importing synthetic files into the incumbent (Drafts > Import,
black-box) and against a "Save local copy" of a synthetic document.

- Images are named and referenced by the SHA-1 of their bytes. With
  SHA-256 names, any file with an image failed to import ("Internal error
  during import").
- Component sets hold their property definitions, variant properties
  included (stateGroupPropertyValueOrders); each variant has its own copy
  of each definition (parentPropDefId) and its variantPropSpecs, and its
  layers and instances name that copy. Definitions and values also travel
  as varValue; text values carry their lines; layers get componentPropRefs
  next to the parameter consumption map. Before, sets came in without
  variant properties and with their other properties unbound.
- An axis without a maximum size is written as infinite: 0 collapsed
  auto layout frames with only a maximum width.
- Compound weights are spelt the way font families name their faces
  ("SemiBold"; "Semi Bold" in Inter): text in Libre Franklin Semi Bold was
  a missing font there and wasn't drawn.
- The kiwi encoder writes infinite floats.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 12:56:07 -06:00
phonedu a132eb3768 M6: fix Vue bindings, instance guards and slot catalogs
Vue connected templates keep a string's JS quotes inside bound attributes, so `:title={title}` becomes `:title="&quot;Buy&quot;"` rather than a bare identifier; static attributes take plain text. Nested instances no longer lose a boolean `v-if` guard, instance swaps render through `<component :is>`, slot names stay distinct when their idents lowercase alike, slot content CSS reaches the parent stylesheet, and text defaults escape `</script>` in the script block. The five locale catalogs the Vue key rename missed (bn, fi, ka, nl, pl) are updated, and the docs list Leptos/Vue consistently.
2026-10-22 19:52:58 +08:00
Jindřich ŠaršonandClaude Opus 5.5 7cb4168e13 M6: Sketch import: fixes from the PR review
- --no-system-fonts holds for .sketch imports too: the CLI opts the
  process out, so the import's font matching doesn't scan.
- Shared text styles get the installed family and platform tracking
  their linked layers get.
- Each text run writes its letter spacing, line height and font axes,
  neutral when it has none, instead of taking the first run's.
- The unsupported-drop hint and its catalogs list .sketch.
- A test sends damaged .sketch data through file.open and file.import.
- Stack items are matched to their source layers through a map.
- Docs: .sketch is a convert input; the Carbon kit's Sketch 47 edition
  is refused (the 68 and 83 ones open).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 09:03:17 +02:00
phonedu 8787f46205 M6: a Vue code target (single-file components)
Dev Mode generates React, Leptos, SwiftUI and Compose; a Vue project had to translate the HTML
instead. `inspect.code {language: "vue"}` now writes a single-file component: a `<template>`, a
`<script setup>` with `defineProps` and its defaults, and a `<style scoped>`.

A Vue template holds no arbitrary expressions, so what the web targets write as a braced
expression has its own spelling. Text is `{{ prop }}`, and braces in text are escaped; a boolean
property's layer carries `v-if="prop"` rather than a wrapper element; a slot becomes Vue's own
`<slot name="…">` with its fallback content, which takes no prop, and an instance's content in one
is a `<template #name>`. Variants switch on the root's `data-*` attributes, as on the web.

`codeConnect` links a component to its code as a single-file component: a default import, and a
quoted binding, so `:size={size}` gives `:size="Large"` and a component swap passes the component
itself. A value that needs escapes keeps them inside the quotes, where the attribute's own quotes
become `&quot;`.

`inspect.componentCode` kept a second copy of the code-language list, which is how Vue was missed
when `inspect.code` learned it; it now asks `code_connect::language`, the one list, as
`codeConnect` does.

Eleven tests in `vue_codegen_tests` and a `codeConnect` case; the Inspect panel's language picker
picks Vue up from `CodeLang::ALL`, and the language lists in the docs, the Dev Mode hint and its
thirteen catalogs name it.
2026-10-22 14:12:45 +08:00
Jindřich ŠaršonandClaude Opus 5.5 03c5324305 M6: Sketch import: count it in the parity assessment
Figma imports Sketch files from its file browser (desktop app too); the
area table hadn't listed it. Import/export breadth 86% → 87%, file
formats 60% → 61%; headline numbers unchanged after rounding.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 00:27:20 +02:00
Jindřich ŠaršonandClaude Opus 5.5 054d53900f M6: Sketch import: note embedded fonts as waiting for .figcraft font support
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 00:27:20 +02:00
Jindřich ŠaršonandClaude Opus 5.5 de0650e3f7 M6: Sketch import: layout grids come in hidden
Sketch draws an artboard's layout and square grids only while its layout
view is on; they now import hidden (still there, shown with the eye in
the Layout grid section).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 00:27:20 +02:00
Jindřich ŠaršonandClaude Opus 5.5 a8bade1446 M6: Sketch import: alpha masks, Fade, linear gradient geometry
Alpha masks only mask (no drawn copy of their fill); a progressive
opacity (Fade) becomes an alpha mask of its gradient over the layer;
linear gradients run square in pixels as Sketch draws them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 00:27:20 +02:00
Jindřich ŠaršonandClaude Opus 5.5 f02557e8f9 M6: Sketch import: fonts by PostScript name, Sketch's natural line
The font database knows each face's PostScript name; the Sketch import
finds the installed face a file's font names (CourierNewPSMT is Courier
New Regular) and reads the family from the name only when it isn't
installed. Text without a fixed line height takes the line Sketch draws:
ascent and descent rounded to whole pixels, the line gap left out, a
fifth more for classic Mac fonts, the baseline where Sketch puts it
(measured on sketchtool renders of 80 fonts).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 00:27:20 +02:00
Jindřich ŠaršonandClaude Opus 5.5 41ff790d77 M6: Sketch import: variable font axes; no false embedded-font note
Sketch keys a font's variation axes by the tag read as a number; they map
onto the text style's variations (a fontVariations key in the REST
mapping). Font references without font data only name the fonts a
document uses and no longer raise the embedded-font note.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 00:27:20 +02:00
Jindřich ŠaršonandClaude Opus 5.5 c639cc2b76 M6: Sketch import: Sketch 2025 frames, stacks, tints and corners
Groups as frames and graphics, stacks as auto layout (instances laid out
by their stack), corners and per-side borders from the style, pins and
sizing, tints (layeringType, fillColor overrides), text colour and
visibility overrides, blur lists (progressive, glass), inner shadows in
the shadow list, angular gradients starting on the right, text sizing,
and texts an override changed measured again on open.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 00:27:20 +02:00
Jindřich ŠaršonandClaude Opus 5.5 ad78ee94c3 M6: Sketch import: instances, artboards and Apple fonts like Sketch
Compared with Sketch's renders of a Sketch 64 file. Resized instances lay
out their layers the way Sketch does (measured: pins share the change in
proportion, a fixed size keeps its centre's share, and files before format
110 just scale); masters' backgrounds show in instances only when Sketch
includes them; swaps to a missing symbol keep the original; artboards
don't draw a style they carry. Apple's system fonts are found under the
names designs use (SF Pro, SF UI Text and Display, SF Compact), the
optical size follows the text size for named styles too, and imported
text keeps the platform's trak tracking as letter spacing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 00:27:20 +02:00
Jindřich ŠaršonandClaude Opus 5.5 5b9e18317d M6: Sketch import: match Sketch's own rendering
Compared artboard by artboard with Sketch's renders of a real Sketch 50
file (sketchtool, black-box). Shape groups whose children have no
operation are one compound path filled by the group's winding rule (read
from the layer), not a union: rings, map streets and icons keep their
holes. Filled open paths close, as Sketch fills them. Flips apply after
rotation. Text with a fixed line height sits where Sketch's line spacing
behaviour puts it. Edited ovals and rectangles keep their points. Bitmap
colour adjustments become image filters. scale 0 means unscaled. A local
test compares sample files with sketchtool's renders.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 00:27:20 +02:00
Jindřich ŠaršonandClaude Opus 5.5 233c8e9708 M6: Sketch import: local corpus check and docs
FIGCRAFT_SKETCH_SAMPLES runs every .sketch file of a folder through
file.open (opens with linked instances and finite geometry, or is
refused as too old). File format parity gains a .sketch row; CLI, MCP,
roadmap and ROADMAP mention the import.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 00:27:20 +02:00
xiaou61 beb87d8696 M1: describe the fallback the export actually takes (#465)
The warning still said fixed and content-sized tracks were written as equal
tracks, which the export no longer does. It now reports only the tracks whose
size the format can't hold, and only for the tracks an exported grid has.

Co-authored-by: xiaou61 <113765024+xiaou61@users.noreply.github.com>
2026-10-20 11:14:02 +08:00
xiaou61 414aa1b63c M1: write grid track sizes in .fig export (#465)
The import has read `gridColumnsSizing` / `gridRowsSizing` since #630, but the
export wrote only equal tracks and warned about it, so a grid with a fixed
column beside two weighted ones came back equal after a save and reload.

Write the sizing map next to the order map, keyed by the same track ids: fixed
px, fractional fill and content-sized tracks keep their sizes. A track the
format has no name for (negative or out-of-range size, or a document track the
frame doesn't list) keeps its id and reads back equal, with the existing
warning.

Co-authored-by: xiaou61 <113765024+xiaou61@users.noreply.github.com>
2026-10-20 11:04:13 +08:00
Filip Strajnar eae9546878 M6: export as Android Vector Drawable (XML)
ExportFormat::VectorDrawable ("XML", .xml) and ExportSetting.vd_compat
(bestEffort / exact / ignore, stored only when not the default) wire the
figcraft-vectordrawable writer into file.export, file.exportLayers and
export.add/update: a vdCompat param (junk refused), svgIdAttribute writes
android:name, and the results carry the writer's warnings (per file for
export layers). The Export section lists XML with an "Android Vector
Drawable" tooltip and its id attribute and compatibility options, File >
Export... gets an XML preset, and the toasts say when content was changed
or left out. CLI: --format xml / .xml outputs, --vd-compat, warnings as
note: lines. MCP: format xml returns the XML as text plus its warnings.
A .fig export writes XML settings as SVG with a note.

Docs: file-format-parity (row and revision), ui-parity and roadmap
revisions, architecture (the crate), cli and mcp.
2026-10-18 20:39:46 +02:00
BFlat ef535e49b0 M1: REST import keeps slot layers and instances' slot content (#792) (#796)
Fixes #792.

Fixes #792.
2026-10-18 15:52:30 +07:00
bflatastic 68b19422ad M1: REST import reads grid track sizes (#465)
gridColumnsSizing and gridRowsSizing are CSS grid-template strings: px
tracks are fixed, fr tracks fill, auto/min-content/max-content hug,
minmax(_, Nfr) fills and repeat(n, ...) expands; other tracks stay equal
(1fr). Tracks past the axis's own count are left out. Files from .fig
keep reading the tracks from their source.
2026-10-17 22:44:09 +07:00
BFlat c6d6433473 Docs: parity rows for the 2026-10-17 landings (#756)
Brings the progress docs up to date with what landed on 2026-10-17: community batches #727, #728, #733, #735, #736 and #753, plus #729, #745, #746 and #751. Docs only.
2026-10-17 21:56:26 +07:00
bflatastic 64423c58bc M3: .fig and REST imports keep Hug on auto layout and text (#732)
An auto layout frame a .fig records no primary-axis sizing for hugs on
that axis (auto layout sized it by its content before that axis could be
fixed) instead of turning fixed; an instance that records no auto layout
takes its main's; REST frames whose sizing modes are left out hug (the
documented default); text hugs by its resize mode (auto width both axes,
auto height its height) instead of coming in fixed.
2026-10-17 19:27:35 +07:00
bflatastic 6cdfe2ab8e M3: layers inside instances keep their resizing overrides (#731)
A layer inside an instance can now override its resizing (hug, fill or
fixed, with min and max sizes; override group `resizing`) and its size.
They were refused, and imported ones were dropped at the first relayout.
Kept through rebuilds, undo, save, .fig and REST import, .fig export and
detach; reset per group and with Reset all changes. Position, constraints
and absolute or grid placement stay the main's.
2026-10-17 19:27:35 +07:00