Commit Graph

9 Commits

Author SHA1 Message Date
BFlat 476cdd95f1
M4: shape builder tool (Shift+M): merge or remove the regions of overlapping shapes (#39)
The selected shapes' outlines split the canvas into regions, computed as the faces of their
arrangement with linesweeper (curves kept, per-shape fill rules, holes and islands handled) and
cached per document version and selection.

- Engine: shapeBuilder.regions / merge / remove / mode commands, ToolId::ShapeBuilder and
  tool.shapeBuilder (catalog: Tools > Shape builder, Shift+M). Merge makes one vector from the
  picked regions styled like the top-most shape over the first; every shape covering a picked
  region loses that area (becomes a vector, or is deleted when nothing is left). One gesture or
  command is one undo step. Session::tool_key routes Enter (finish) and vector edit keys.
- Pathops: faces() (arrangement faces with their covering inputs) and union_faces().
- UI: region edges on the canvas, hovered/collected regions hatched (danger colour to remove),
  no transform box while building, a toolbar pill with Merge/Remove modes, a hint and Done; shared
  pill/tool-cell/divider/Done helpers; original merge/remove icons drawn in code.
- Tests: pathops faces; engine regions, merge, remove, curves, groups, rotation, pointer
  click/drag/Alt, modes, Escape/Enter, cache, junk parameters and degenerate geometry.
- Docs: ROADMAP, README, docs/mcp.md, docs/control-protocol.md, docs/parity.md.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 05:55:12 +07:00
BFlat a5d5c265fd
M7: performance: retained canvas renders, virtual layers panel, shared text layouts, cargo xtask bench (#35)
Large documents stay interactive: the canvas re-renders only what a pan uncovers or an edit
touches, the layers panel lays out only the rows in view, and per-frame work no longer walks the
whole page.

- Benchmark: `cargo xtask bench [SIZES]` builds synthetic pages (`figcraft_engine::synthetic`:
  screens with an auto layout header, a card group, button instances and shapes/text) at
  1k/10k/50k layers and prints engine/render timings (`figcraft-cli perf --layers 1000,10000`) and
  headless whole-UI frame timings (an ignored ui-egui test).
- Retained canvas rendering (`figcraft_render::Retained`, used by the render worker): views snap
  to whole device pixels, so a pan shifts the previous image in place and renders only the
  uncovered strips; an edit renders only where changed layers were and are
  (`Document::changed_ids` diffs the two versions skipping shared structure; ancestors that paint
  from their children's pixels - booleans, effects, masks - count whole; background blur reach
  and noise are allowed for). Zoom, page, options, font or page-level changes, or large changes,
  render the whole view as before. `ui.inspect` reports `canvas.renderWork`.
- The texture image is converted on the render thread, not the UI thread.
- Layers panel: only visible rows are laid out (stable ids while scrolling); rows are cached per
  document version, page, expanded set and filter.
- Frame labels and layout grids of off-screen top-level frames are skipped; the Prototype tab's
  connection sources are cached per document version.
- Text: the layout cache keys by a cheap fingerprint confirmed by `TextData` equality (no Debug
  formatting per lookup, 32k entries) and hands out shared layouts; a layout generation marks
  renders stale when fonts arrive. Overflowing text is culled by its glyphs, so it no longer
  vanishes while its box is off screen.

Before -> after (release, Windows, 1440x900 view, ms; 10k / 50k layers):
- move one layer, re-render @100%:     7.65 / 6.49  -> 0.18 / 0.81
- move one layer, re-render zoomed out: 11.95 / 24.10 -> 0.16 / 0.77
- pan 40 px @100%:                     7.53 / 6.82  -> 0.69 / 0.81
- pan 40 px zoomed out:                12.07 / 24.30 -> 1.62 / 4.17
- full render @100% / zoomed to fit:   7.78 / 44.22 -> 6.56 / 38.83 (10k @100%, 50k fit)
- UI frame, every screen expanded in layers: 6.16 / 39.07 -> 0.24 / 0.57
- UI frame, scrolling that panel:      6.11 / 40.18 -> 0.43 / 0.40
- UI frame, layers filtered by name:   1.03 / 6.92  -> 0.17 / 0.36
- UI frame, Prototype tab:             0.89 / 6.45  -> 0.18 / 0.80
- UI frame, idle:                      0.31 / 1.43  -> 0.11 / 0.39
Unchanged and within budget: single-layer edits through the engine ~0.01 ms, normalize after a
one-node edit < 0.01 ms, hit test 26 / 93 us. Left: save/load at 50k (~0.7 s each), zoomed-out
renders at 50k (~40 ms).

Tests: retained renders match full renders after pans, moves, recolours, hide/remove/add, undo,
masks, overflowing text, edits under a background blur and an inner-shadow/noise layer, a drop-
shadowed group, and a blur panned in from the view's edge; zoom/page/options/page background
render full; junk views don't panic. Layer-row and prototype-source caches follow edits, undo,
page switches, expansion and the filter. `changed_ids`, the text cache, and the perf CLI.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 05:19:05 +07:00
BFlat 1c6f04bf62
M3: Variables editor with aliases, scopes, and rename/delete for variables, modes and collections (#33)
The Local variables window becomes a table editor: collections in a
sidebar, variables grouped by name with one value column per mode, typed
value cells (colour swatch + hex + alpha, number, string, boolean), alias
chips with a variable picker and detach, double-click rename, context
menus, and an Edit variable window for description and scopes.

New commands: variable.update (name, description, scopes),
variable.duplicate, variable.renameMode, variable.removeMode,
variable.renameCollection, variable.deleteCollection. variable.set
validates aliases (same type, no loops) and stores them by id; addMode
always picks a fresh mode id. Pickers offer only variables scoped to the
property. ui.set {variables} opens the editor on a collection.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 05:12:08 +07:00
BFlat d30ee21566
M1: paint depth: gradient stops on the canvas, colour models, colours on this page (#7)
- Gradient stops on the canvas: drag a stop along the gradient line, click the line to add a
  stop (sampled colour), the selected stop is ringed and shared with the picker; Delete removes
  it (two always stay).
- Colour picker value row: a model dropdown (Hex, RGB, HSL, HSB, CSS) with its fields and the
  alpha field; scrubbing works on the numeric fields.
- "On this page" swatches: the page's most used solid colours (cached per document snapshot);
  swatches set a solid colour or the selected gradient stop.
- New command `paint.documentColors {page?, limit?}`; control channel `ui.set {colorPicker}`.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 02:57:40 +07:00
BFlat 14435acb63
M1: keyboard transforms: arrows reorder auto layout children, Cmd+arrows resize (#6)
- Arrow keys on children of an auto layout frame move them one place along the flow (Left/Up
  earlier, Right/Down later; grids step by a row vertically); selected neighbours move as a
  block and stop at the ends. Free layers still nudge.
- Cmd/Ctrl+arrows resize the selection by the nudge amount (Shift: big nudge), top-left fixed;
  only the changed axis becomes Fixed. New command `transform.nudgeSize {dw, dh, big?}`.
- Control channel `ui.key` arrows with `cmd` resize too.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 02:42:17 +07:00
BFlat 6610966921
M1: layers panel depth: search, shift-click ranges, sticky collapse, reveal selection, Tab rename (#4)
- Search toggle in the Layers header: a live filter that lists matching layers across the page.
- Shift-click selects the visible rows from the anchor to the clicked row (Cmd adds them to the
  selection); Cmd-click toggles.
- The tree reveals a new selection once (expands its ancestors and scrolls its row into view),
  so Collapse layers (Alt+L) and manual collapsing stick.
- Alt-click a disclosure triangle expands or collapses everything inside.
- Tab / Shift+Tab while renaming commits and renames the next / previous layer.
- Control channel: `ui.set {layerFilter, collapseLayers}`.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 02:34:55 +07:00
BFlat 4286a3b74b
M2: auto layout depth: min/max UI, ignore auto layout toggle, text baseline alignment, grid tracks and cells (#3)
- Min/max width/height: the W/H sizing menus add min/max (at the current size) and remove them;
  limit rows edit or add the missing bound. The layout clamps Fixed, Hug and Fill children and
  the frame itself; a hugging text wider than its max width wraps at the max. min > max is kept
  ordered by node.set (the other bound follows); in the layout min wins.
- Ignore auto layout (absolute position): a toggle in the Position section; the child stays
  where it is, can't Fill, shows constraints and follows them when the auto layout frame resizes
  (by hugging, filling or a direct resize).
- Text baseline alignment for horizontal layouts ("Align text baselines"; crossAlign baseline):
  first-line baselines line up, other layers align to the top, nested auto layout frames use
  their first child's baseline. Measure gains text_baseline.
- Grid auto layout: column/row tracks (fixed px, hug, fr fill) via columnTracks / rowTracks or
  layout.setTrack, cells anchored by gridColumn / gridRow with gridColumnSpan / gridRowSpan,
  auto placement in reading order, rows grow to fit, hugging grids size to their tracks.
  Panel: column/row gap, track size rows, a child's cell and spans. Old files load unchanged
  (serde defaults; missing tracks are 1fr).
- Canvas handles: wrapped-row gaps and grid column/row gaps are draggable; a selected grid's
  tracks are outlined.
- The layout section moved from right.rs to layout_panel.rs; inspect reports min/max and a
  grid child's resolved gridCell; docs list the new props.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 02:23:43 +07:00
BFlat 94e689fad6
M4: vector edit mode tools: pen branching, bend, paint bucket, lasso, cut, mirroring, point panel (#2)
- Edit-mode toolbar (Move V, Pen P, Bend hold Cmd, Paint bucket Shift+B, Lasso Q, Cut X, Done)
  replaces the tools while a vector is edited.
- Pen in edit mode continues open ends, branches from any point (vector networks), adds points on
  segments and closes paths into fill regions; dragging pulls out mirrored handles.
- Paint bucket fills or unfills any closed area: faces of the network (half-edge walk, nested
  pieces become holes), with a hatched preview of the area under the pointer.
- Bend tool / Cmd: bend segments, pull handles out of a point, click a smooth point to sharpen it.
- Lasso and marquee point selection, segment selection (shift adds), cut at a segment or a point.
- Per-point handle mirroring (none / angle / angle and length, inferred for existing files),
  Alt-drag breaks it; smooth/sharp points; join and merge selected points (Cmd+J, Shift+Cmd+J).
- Delete opens the path, Shift+Delete heals it; arrows nudge points; Cmd+A selects all points.
- Design panel shows the selected points' position, corner radius and mirroring.
- Every gesture is one undo step; edit mode ends when its layer is undone away.
- Paths that end on their start without a ClosePath (ellipse outlines) stay closed and filled.
- New commands (vector.edit.tool/pen/paint/cut/lasso/mirroring/smooth/position/nudge/connect/...)
  for the CLI, control channel and MCP; docs updated.
- Clippy: simplify a few boolean expressions flagged by the current toolchain.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 02:16:04 +07:00
Brandon Thomas b36fd771ab M0.9: MCP server + figcraft-cli, PDF export, web app, release/CI packaging, vector edit mode, workspace lint cleanup
- crates/mcp: JSON-RPC MCP server (18 tools, resources, prompts), headless and attached backends, end-to-end agent tests
- apps/figcraft-cli: info/export/convert/render/run/commands/mcp/perf
- crates/pdf: vector PDF export via krilla with embedded text; file.exportFramesPdf
- apps/figcraft-web + packaging/{macos,windows,linux,freebsd,web} + release/ci workflows
- engine vectoredit: edit points/handles/bend/add/delete-heal; canvas overlay and edit strip

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 13:31:53 -04:00