Commit Graph
101 Commits
Author SHA1 Message Date
samhyunandClaude Fable 5.1 3f896453b6 M8: a test for stacked background blurs drawn in bands; the eight-band wording
From the review of #1496: three background blurs stacked on each other across the band
boundaries draw the same in bands as in one piece (within anti-aliasing), so the bands'
overlap, the reach of the largest blur, is enough, as it is for the desktop's parallel bands;
pinned by a test. The docs and the `MAX_BANDS` comment no longer put the longest frame at "an
eighth of the render": a frame draws at least a band, a part of the render rather than the
whole, and the numbers measured for #1496 are cited instead.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-29 23:08:12 +09:00
samhyunandClaude Fable 5.1 6d8b0e68f0 M8: the browser draws a zoom's full render a band at a time
Once a zoom had paused, the browser drew its full render in one frame. On a heavy page that
frame took seconds, and no input was handled meanwhile: the wheel steps and drags that came
were seen only when it was over.

The renderer's `Retained::begin` hands a full render back as `Steps`, drawn `band_h` rows at a
time with the same `render_band` and `put_band` the desktop's parallel bands use (bands overlap
by what background blurs read and keep their own rows; a blur reaching past a band makes the
bands taller rather than one piece), and `finish` keeps the image as a full render. A render
that is reused or patched is done at once, as before.

The browser's `Inline` worker refines through `Renders::refine_for`, which draws at least a
band a frame, more while they fit in `STEP_MS` (24 ms), and asks for the next frame while bands
remain, so input is handled between them; a view has at most eight bands, so on a page whose
render takes seconds the longest frame is about an eighth of it. A render drawn for the very
request is done once drawn. A pan or an edit meanwhile at the same zoom keeps the render going
and is patched in once it is drawn; a pan too far to patch or an edit the patch can't take draws
it again in steps, the image just drawn showing till then (`Refined::Shown`); a zoom, another
page or file, another size or other render options drop the render for one of the new view,
and what its bands took stands as the measure the next zoom's preview and wait go by. A render
in steps counts as one render (glass keeps the shapes a later render asks for again). The
desktop, with its render thread, is unchanged.

Measured in Chrome on two synthetic pages (20 images and 60 shadowed rectangles, with and
without two background-blur panels) whose full render takes 3.6–4.0 s at a deep zoom: the
longest frame while that render runs went from 3.7–4.0 s to 0.9–1.4 s (blur) and 0.69–0.80 s
(no blur); the bands together take longer than one render (the refined image comes after
6.7–8.1 s and 5.3–5.5 s instead of 3.8–4.1 s), each band rendering its overlap again and
repeating some per-band work, shadows mostly. The zoom steps are as before.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-29 22:37:35 +09: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
BFlat 7c9184b023 docs: rows from the round-4 community PRs (#858, #1409, #1397, #1389, #1143, #1427, #1421) (#1504) 2026-10-29 14:48:37 +07:00
BFlat 8dc3ab5703 Merge pull request #669 from yelintong/feat/flutter-codegen
M7: Flutter code generation
2026-10-29 13:37:49 +07:00
bflatastic 789fa33444 Merge main into #634 2026-10-29 12:25:06 +07:00
bflatastic a81efe5466 Merge main into #669 2026-10-29 11:52:03 +07:00
BFlat 60ea32f171 Merge pull request #1465 from phonedu/mcp-agent-feedback
M12: MCP comment feedback and live change events
2026-10-29 10:51:24 +07:00
bflatastic 0cc380c228 Merge main into #1466 2026-10-29 10:08:11 +07:00
bflatastic 6abddb0f68 Merge main into #1465 2026-10-29 09:55:55 +07:00
bflatastic 170f1fdf32 #1466: gaps and ROADMAP list the Arabic draft as shipped 2026-10-29 09:26:15 +07:00
samhyunandClaude Fable 5.1 3773a60801 M8: the browser's wait after a preview never exceeds the render it may save
With a fixed 120 ms wait, a page whose full renders take 15–100 ms was held coarse for 120 ms
after a key zoom or a page switch, where before it was refined in the next frame. The wait is
now the last full render's time when that is shorter than `SETTLE_MS`: a wait never costs more
than the render it may save, and on a heavy page (seconds a render) it is 120 ms as before.

Also from review: the test that the wait counts from the preview no longer times a preview
render (a margin of a few milliseconds under load); a sleep between the request and the poll
stands in for the render, with the whole settle as margin. `Inline::in_flight` says that a
preview's wait counts.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-28 22:53:07 +09:00
phonedu 8e6b3bf449 M12: MCP comment feedback and live change events
Comments become the task queue for an attached or headless MCP client: comment.prompt returns a bounded Markdown brief, the Comments panel gains Copy for AI, and the MCP server exposes fix_comments, watch_comments, figcraft://comments and wait_for_changes. Mutating comment.* commands append to a bounded in-memory event log; the control channel's events.poll long-polls it without the UI thread, and a successful batch commits its events only if the whole batch lands. No model, network dependency, asset or file-format change.
2026-10-28 21:42:31 +08:00
samhyunandClaude Fable 5.1 8c951810ab M8: a test for same-zoom requests before a zoom refines; the gaps status line
From the review of #1468: a pan or an edit at the new zoom before its full render has run
renders from scratch too, so it shows a preview and restarts the wait instead of running a
blocking full render between it and the next step; once refined, requests at that zoom build
on the kept image and are refined at once. The new test pins both down. The status line of
`docs/gaps.md` now carries the date of the gap 7 entry.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-28 22:29:55 +09:00
samhyunandClaude Fable 5.1 f24a8312f7 M8: the browser refines a zoom only once it has paused
The browser renders on the UI thread. A zoom showed its coarse preview and then, in the very
next frame, ran the full render, so every wheel step of a continuous zoom had a blocking full
render between it and the next: on a heavy page each one took seconds, and the zoom stuttered
for as long as it went on.

The browser's worker (`Inline`) now refines a preview only once no newer request has come for
`SETTLE_MS` (120 ms) after the preview was shown: the zoom has paused. Each wheel step still
shows its preview at once, and the worker asks for a repaint when the wait is over. Pans and
edits have no preview and are refined at once, as before. The desktop has a render thread of
its own and is unchanged. A zoom passing through a scale also no longer spends a full render
there.

The wait counts from the preview being handed over, not from the request: rendering the
preview can itself take longer than the wait (the page is blocked meanwhile, so no newer
request could have come), and counted from the request the full render would follow in the
very next frame, as before.

Measured in Chrome on a synthetic page of 20 images, 60 shadowed rectangles and two
background blurs (a full render takes about 3.7 s, a preview about 250 ms), 20 wheel steps in
and 20 out, 50 ms apart, three runs each: the frame interval's p95 went from 3.7 s to 240 ms,
the frames over 100 ms from 79–80 (one full render per step) to 39–41 (one preview per step),
and the zoom took 10–12 s instead of 141 s. The one full render after the pause still takes as
long as before.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-28 22:10:27 +09:00
hussain-hz 636096fad3 M10: add Arabic draft interface catalog
Translate 2508 interface entries from English, keep count-neutral plurals, and gate the web catalog on Arabic font readiness. Record AI assistance and pending native review.

AI-assisted-by: OpenAI Codex
2026-10-28 15:16:31 +03: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
叶林橦 27d5d99e56 M7: land Flutter code generation on main's code targets
main split `codegen.rs` into `dev/codegen.rs` (the shell: `CodeLang`,
`code_for`, `Ctx`, the shared helpers) and one module per native target
(`css`, `html`, `swift`, `compose`, `arkui`), and added Vue and ArkUI from
other PRs. Flutter arrives as the tenth target, in its own module:
`dev/codegen/flutter.rs`, wired from `codegen.rs` (`CodeLang::Flutter`, `dart`
as an alias, rem left to the web targets), with `flutter_definition` /
`flutter_type` / `flutter_default` beside main's `arkui_definition`.

Every language list in the tree is a union of the two sides now: the
`inspect.code` and `inspect.componentCode` specs, `codeConnect` (parse, import
line, expression, template, path checks, messages), the playground CSS/HTML
assets, the 21 UI catalogues (main added eight after this branch: bn, fi, it,
ka, nl, pl, th, vi, each with Flutter in its own conjunction) and the docs.
Flutter is an extra code target; nothing main gained is dropped.

The reviewer's absolute-child bug (#1382-1403: a child that ignores its auto
layout parent fell through to `Place::Flow`) is fixed in `flutter_children`:
flow and absolute children are split, the absolute ones go in a `Stack` around
the Row/Column at the parent's own box (so their offsets stay the parent's and
the padding moves onto the line instead of insetting them), the line fills that
Stack (`Positioned.fill`, so `Expanded` still has a bounded width), and only
flow children now decide `CrossAxisAlignment.stretch` and `Expanded` — the
absolute child no longer joins the line's spacing or loses its offsets.

`flutter_lifts_a_child_that_ignores_its_auto_layout_parent_out_of_the_line`
covers both kinds of child in one auto-layout frame: a 50×20 flow child and a
30×30 absolute one asking for `fill` on both axes, in a parent with 4 pt
padding. It checks the offset, that the absolute child is out of the Row, that
no `Expanded`/stretch comes from it, and that the padding insets the line only.

ROADMAP and dev-mode-parity keep main's header (2026-10-26) and take this
branch's history row in date order (2026-10-16).

`cargo test`: engine 1391 pass, ui-egui 814 + 8 + 1 pass; fmt and clippy clean.
The one engine failure, `board_tables_tests::a_double_click…`, fails the same
way on a pristine `origin/main` here: this sandbox has no `craft-fonts`
checkout, so its text doesn't wrap and the row can't grow.
2026-10-27 11:30:27 +08:00
aiongg 60c671da66 docs: update source paths for the layout moves 2026-10-26 20:36:51 +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 cac991334d Merge pull request #320 from tylerjenningsw/perf/zoom-preview-cold
perf(canvas): preview cold zoom and page transitions once they run long (M8)
2026-10-27 00:50:49 +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 b8f34b11c1 Merge main into #320 2026-10-26 23:03:01 +07:00
BFlat 63d926876f M10: branches in live sessions (#1367)
Branches of a file in a live session: create, edit, review, update from
main and merge while the file is in a session. The branch stays with its
author and makes ids in their own client space far above the main file's;
merging is one synced edit and one undo step; peers' edits merge against
the branch's own base and conflicts resolve as offline; a view link still
refuses merging; a branch made outside the session that adds layers is
refused with a reason. Branch history entries for creation and updates
from main. Fuzz and junk tests extended to export settings, guides and the
live case. Docs: gap 17, collaboration parity, ROADMAP, mcp, protocol.
2026-10-26 13:57:24 +07:00
BFlat 8d60360173 M11: widgets take text input and a property menu (plugin API 4) (#1365)
* M8: widgets take text input and a property menu

Plugin API 4 (gap 6). A widget's text layer can be an editable field:
a double-click edits it like any text, and when editing ends the value
(cleaned, at most 1,000 characters) goes into the widget's state under
the field's name and its plugin redraws, as one undo step. A widget can
also carry a property menu of up to 8 actions, toggles and colour
choices, shown in a small bar over it while it's selected.

- widget.setText and widget.menu drive the same paths from scripts,
  the CLI and MCP; widget.insert/list also report fields and menu
- descriptions, values and stored menus are validated as untrusted;
  an API 3 plugin drawing a field or menu is refused, older hosts
  refuse API 4 manifests; no new host imports
- SDK reads the new events; the Counter example gains a label field
  and a menu (reset, steps of ten, a colour)
- tests for fields, menus, canvas editing, rollback, forged data and
  live sync; junk sweep extended; labels in every command catalog
- docs: plugins, mcp, gaps, target-app-parity, ROADMAP, roadmap

* M8: widget property menu on egui 0.37

Id::new and Ui::id are deprecated in egui 0.37: the widget bar's area uses Id::unique and its buttons' interaction ids come from ui.scope_id().

* M11: a double-click a board object or a widget field takes, in a function of its own (Sonar)
2026-10-26 13:31:53 +07:00
BFlat d3782fdc43 M12: board templates and tables (#1363)
* M12: board templates and tables

Five built-in board templates (retrospective, brainstorm, weekly planner,
flow chart, kanban board) placed as ordinary board objects in one undo step
(board.template, board.templates) from a toolbar picker with pictures, and
board tables made of auto layout frames (board.table, board.tableEdit; up to
50 x 20), typed into with a double-click and edited by row and column from
the bar over the selection. Docs: boards-parity, gap 24, ROADMAP, mcp.

* M12: board templates picker on egui 0.37

Id::new and Ui::id are deprecated in egui 0.37: the templates picker's area uses Id::unique, its buttons' interaction ids come from ui.scope_id(), and its test reads the board bar's area by Id::unique.
2026-10-26 12:52:39 +07:00
BFlat 4fad29a66e M12: board timer and voting sessions (#1361)
* M12: board timer and voting

A countdown everyone on a board sees (board.timer, board.timerState), synced as its end time or the
time left while paused, and voting sessions (board.vote, board.voteResults): votes per person, on
everything, stickies or the selection; clicks vote, your badge takes a vote back; your own votes
show while it runs, everyone's with a ranked list once it ends. Timer and vote sync as document
properties and ballots as one entry per voter; neither is an undo step. A pill at the top right
of the board, new Timer, Pause and Vote icons, labels and strings in every catalog, docs.

* M12: board timer and voting on egui 0.37

Id::new is deprecated in egui 0.37: the timer and voting area and its memory ids use Id::unique.

* M12: board.vote's start and ballot changes in functions of their own (Sonar)
2026-10-26 12:28:59 +07:00
BFlat 26291aff2c M12: boards dot grid, re-attaching connector ends, curved connectors (#1249)
* M12: boards dot grid, re-attaching connector ends, curved connectors

Board pages draw a dot grid in the canvas render, after the page colour
and under the layers (figcraft_render::Dots), thinned out when zoomed out
and coloured from the theme's ink against the page. A selected connector
shows its ends as handles; dragging one onto an object re-attaches it,
onto empty canvas leaves it free (board.reattach, one undo step, also
over MCP). Connectors can be curved, and elbows go around the objects
they join when the short way would cross them.

* M12: boards dot grid: blending a dot in a function of its own (Sonar)
2026-10-26 11:52:16 +07:00
bflatastic 9c57ba1beb Merge main into #1202 2026-10-26 08:43:07 +07:00
236f3185d6 Migrate FigCraft to egui 0.37 (#1312)
* E21: require release font coverage and stabilize capture deadline tests

* E21: separate capture, IME and field-save regression phases

* M0: correct the migration qualification reference

* M-egui037: document input lifecycle and UI regression contracts

* M0: correct egui 0.37 status docs and stabilize join-code regression

---------

Co-authored-by: Dylan M. Taylor <dylan@dylanmtaylor.com>
Co-authored-by: Codebuff <noreply@codebuff.com>
2026-10-25 15:04:39 -04:00
aiongg 92682728e9 Follow-ups from the #1311 review: link notice clicks, variable scopes, corner tooltip (#1316)
* Prototype player: no clicks reach the prototype behind the link notice

* Selection colors: scopes filter the variable menu; the command binds as variable.bind does

* Style picker: color variables scoped to every selected layer's fill or stroke

* Corner button: named Corner smoothing on polygons and stars

* docs/gaps.md: known gaps from the #1311 review

* cargo fmt

* Style picker: clippy
2026-10-25 01:09:29 -04:00
aiongg ad40507450 Merge #1277 2026-10-25 02:21:19 +00:00
dotCooCoo 811d599960 M4: corner smoothing on polygons and stars
Polygon and star outlines did not use their corner smoothing: the value
was stored, imported and exported, but `shape_path` drew their corners
as plain circular arcs, and the Design panel showed the Corner
smoothing field only for rectangles and frames. Rounded polygon and
star corners now take smoothing the way rectangle corners do. Each
corner keeps a circular arc over the unsmoothed part of its turn and
eases into both edges, and it starts (1 + smoothing) times the plain
corner's length from the vertex. When a smoothed corner does not fit
in half of its shorter edge, smoothing is reduced first, then the
radius, as for rectangles. The Individual corners button opens the
panel for polygons and stars too, with the Corner smoothing row and no
field per corner.
2026-10-24 07:22:36 -07:00
dotCooCoo 29ab17c222 M6: Dev Mode refuses edits from dropped files, the Pages list and the Assets panel
In Dev Mode the menus, shortcuts, clipboard, canvas and layers panel
refuse design edits, but an image or SVG dropped on the canvas was
still imported. The Pages list still added, renamed, reordered,
duplicated and deleted pages. The Assets panel still placed instances,
swapped them on an Alt-drop, applied styles, changed Hide when
publishing, accepted library updates and added, removed or swapped
libraries.

All of these now go through dev_mode_refuses with the command they
would run, and show its note. A dropped document still opens as a file
of its own, and the drop overlay shows the note instead of "Drop to
import". A click in the Pages list still opens a page, and page rows
take no drags in Dev Mode.
2026-10-24 02:57:11 -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 62a3072134 Merge main and the community batch into #1202
# Conflicts:
#	crates/engine/src/component_codegen.rs
#	crates/engine/src/tools.rs
#	crates/ui-egui/locales/fi.toml
#	crates/ui-egui/locales/nl.toml
#	crates/ui-egui/src/dev_mode_tests.rs
#	crates/ui-egui/src/shortcuts.rs
#	docs/dev-mode-parity.md
#	docs/file-format-parity.md
#	docs/ui-parity.md
2026-10-24 09:39:52 +07:00
bflatastic 6063d3e9a9 Merge #1189: M4: vector edit transform box around points of several layers (@marcoarnulfo)
# Conflicts:
#	docs/target-app-parity.md
#	docs/ui-parity.md
2026-10-24 09:15:11 +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 17ed21d128 M6: Dev Mode tail: imports in layer trees, compare with versions, an inspect-only canvas (#538)
Import lines for connected components inside generated layer trees; Compare changes against any saved version; a Dev Mode behaviour suite with an inspect-only canvas (menus, shortcuts, paste and Revert to saved refuse design edits; a drag under way is dropped on entering), Changed in the ready list, statuses only on top-level frames and sections; read-only plugins' panels from the Inspect tab.
2026-10-24 02:56: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
Marco Arnulfo 1f2a8104bf M4: vector edit transform box around points of several layers
With points selected in more than one edited layer the transform box now
wraps them all, in the page's axes since the layers can be turned
differently. Its corners and edges scale them, outside a corner rotates
them and inside drags them; each layer's points are mapped in its own
coordinates and the whole drag is one undo step. A click inside clears
every layer's points.
2026-10-22 23:37:49 +02:00
Nicek 7e28d58b3f feat: 新增 ArkUI 代码生成和代码连接支持
添加 ArkUI 作为新的代码语言支持,包括:
- 代码生成:支持生成 ArkTS 组件代码,包括 `@Component` 结构体、`@Prop` 参数、`@BuilderParam` 构建器等
- 代码连接:支持将组件连接到 ArkTS 代码,包括导入路径和模板配置
- 测试:添加 ArkUI 相关测试用例,验证代码生成和连接功能的正确性
- 更新文档:更新开发模式 parity 文档、文件格式一致性文档等,添加 ArkUI 相关说明
- 更新国际化:在所有支持的语言中添加 ArkUI 选项提示
2026-10-22 20:36:45 +08: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
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
tylerjenningsw f80bdb634d docs: zoom previews for cold transitions (M8)
Refs #295
2026-10-20 16:38:27 -04: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
叶林橦 e4562a0072 M7: Flutter code generation
- Code generation gains a Flutter target (ours; the incumbent generates CSS, iOS and Android only), which makes Dart the seventh language: `language: flutter` (with `dart` as an alias, so `CodeLang::from_id` maps both, `id()` is `flutter` and the label `Flutter`).

- `inspect.code` writes a Dart widget tree for the layer: a `Container` for a box, with its size, padding and a `BoxDecoration` (colour, radius, border, shadows); `Row` / `Column` for auto layout, with `spacing`, `crossAxisAlignment` and `textBaseline`, and `stretch` wherever a child fills the cross axis; `Expanded` for a child that fills the main axis; `Stack` with `Positioned` for free children; `Text` with a `TextStyle` (family, size, weight, style, height, letter spacing, decoration and alignment); `Image.asset` for images; `Opacity` for layer opacity; `SizedBox` for a capped subtree. Colours are `Color(0xAARRGGBB)` and `$` is escaped in string literals, as in Compose.

- `inspect.componentCode` writes a `StatelessWidget` for a component or set: properties become constructor parameters with their defaults, a variant property becomes a Dart enum (lowerCamel members, never a keyword), a boolean a `bool`, a text a `String`, a swap a `Widget` and a slot a `List<Widget>?`. Instances are calls that pass only what they change, and an instance's snippet puts the `import 'package:flutter/material.dart';` line before the call, since Dart's imports come first.

- Code connect takes Flutter too: `codeConnect.set {language: flutter}` stores an import path, a name and a template, and the snippet carries a Dart `import '…';` line. The default template passes named parameters (`Card(size: {size})`), as SwiftUI does, and import paths are checked as Dart imports (letters, digits, `_ . / : -`).

- The Inspect panel's language picker iterates `CodeLang::ALL`, so Flutter appears there and in the Connect to code note; the 13 UI catalogs and the component playground's language list follow.

- Docs: README, ROADMAP, docs/mcp.md, docs/gaps.md, docs/components-parity.md, docs/file-format-parity.md, docs/target-app-parity.md and docs/dev-mode-parity.md.

- Tests: Flutter cases in the codegen, component codegen and inspect behaviour suites.
2026-10-16 18:40:59 +08:00
Skyfuller1303 4ecf6e2f39 M4: preserve vector region fills across .fig import and native rendering
A filled area of a vector network can now carry its own paint stack. A region without paints of its own keeps drawing with the layer's fills, and a region with an explicitly empty list draws nothing, so the two cases stay distinguishable. The canvas, SVG and PDF output, boolean and hit-test geometry, vector editing and region operations all honour the per-region paints and keep them when regions are split, merged or reordered.

The .fig importer resolves the individual paint stacks of a layer's filled areas through its normal paint mapping and hands them to the document builder as private mapper data. Public REST vectorNetwork JSON never consumes that data and its region paints are dropped, so only validated .fig input can set them. Invalid entries are skipped with an import note. Live style and variable links on individual regions and writing region paints in the experimental .fig exporter are not part of this change.
2026-10-16 05:07:05 +02:00
Yarila f8458b70a8 Reduce blank canvas strips during panning with bounded overscan 2026-10-16 00:28:10 +05:00
bflatastic 41d2ef688e Merge #312: perf(canvas): refresh full-viewport previews during zoom (M8) (@tylerjenningsw) 2026-10-15 18:33:29 +07:00