mirror of
https://github.com/storytold/figcraft.git
synced 2026-10-25 10:56:48 -06:00
Layout grids: Auto line width for columns and rows
Columns and rows can now set their line width to Auto: a width of 0 (or typing the word "Auto" / "自动" in the field) draws a one-pixel hairline down the band's middle, like the square grid, instead of a filled band. - grid_lines: a non-stretched grid with size <= 0 emits a hairline at each band's middle rather than a zero/negative-width rect. - canvas: a degenerate (zero-width or zero-height) grid rect is painted as a 1px line; a filled band is still painted as a rectangle. - number_field: a field whose placeholder is "Auto" also accepts the word "Auto"/"自动", mapping it to 0. - right: the grid size field shows "Auto" and the align menu no longer forces a 60px band on a zero width. - props: document the Auto semantics of LayoutGrid::size. - ROADMAP.md / docs/ui-parity.md: note the change. - layout tests: regression test for the Auto hairline.
This commit is contained in:
+2
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
**Stage: alpha** · next: beta, ~26 points and ~162–292 h away (one Opus 5.5 agent; ~33–67 h wall-clock with 5 agents)
|
||||
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-17 · **Change:** minor (community batch #753: Selection colors, smart-selection spacing, a Present tab; language table re-measured from the catalogs; community fixes from #524 up (55 PRs: `.fig` import fidelity, paste from other apps, the Actions palette, editor fixes, server limits) and a boolean-op crash guard; number variables in the text content picker (#629); frames and sections convert into each other (#719); bounded canvas pan overscan; community fixes from #478 up and a control-channel fix (#589); bounded canvas pan overscan; Typography spacing icons support scrubbing (#373); font scans skip named pipes; system theme on first run; recent files as cards with thumbnails on the home screen; community fixes: lost images reported on loading (#207), SVG import budgets (#190), Leptos code (#223), full screen (#227), server snapshots readable again (#188), owner-only preferences (#200), ruzstd 0.9.1 (#182), layer cycle repair (#205), batch rollback, Direct3D 12 on Windows, plugin metering (#192); vector edit mode regions: hover hatch, selection and drag; SVG/PDF exports refuse over-depth documents (#208); bounded MCP/control framing, connections and queues (#201); plugin log limits (#191); live-session revert guard (#198); attached MCP no longer replays after a lost reply (#194); repeat command recursion fix; the Layout panel's constrain-proportions link scales the other side, #220; core editor leftovers: component playground, auto gap handles, variables inside styles, inner shadows and background blur on groups, command-made text readable on dark pages, a one-step frame/group convert, delays on mouse triggers and manual overlay offsets, wrapped-line alignment; `.fig` export: instance sizes, variables with modes, shared styles, variable-width strokes; starter templates, a Templates tab and Getting started tips on the home screen; your online files; everyday editing partials: number fields, outline options, Hide when publishing, cursors, panel widths, dark pages; sharing with a join code; text box sizes measured against documents re-saved by other software; live sessions per document; .fig export checked by opening written files in other software; a public figcraft-server: open hosting, owner tokens, per-address limits, idle expiry, moderation, install.sh; experimental .fig export; keyboard shortcut parity suite and bindings; Simplified Chinese draft catalog; Latin American Spanish overlay; prototyping tail: gamepad triggers, widgets in prototypes, mode lookups; plugin directory on figcraft-server; Japanese and Korean draft catalogs and CJK UI fonts; plugin widgets and the plugin panel tail; French, German and Brazilian Portuguese draft catalogs; cursor chat and spotlight in live sessions; layers and assets panels behaviour suite and fixes; vector multi-edit and edit tail; dev resources links; extended collections tail; branch version history and finer list merges; headline percentages recomputed from the area table: feature breadth ~84%, core ~94%, mainstream ~50%; text lists, hanging punctuation and decoration styles; comments and version history behaviour suite and fixes; canvas navigation, guides and grids behaviour suite and fixes; export and inspect behaviour suite and fixes; .fig import: editable vector networks and more layer kinds; shapes and vector behaviour suite and fixes; paint and effects behaviour suite and fixes; frames, groups, sections and masks behaviour suite and fixes; styles and variables behaviour suite and fixes; prototyping behaviour suite and fixes; components behaviour suite and fixes; embedded image colour profiles; layers panel keyboard: F2 rename, Shift+F10 context menu, keyboard box selection, 10k-layer QA; per-side stroke weight variables; text behaviour suite: CJK line breaking, metrics, vertical trim; selection and transform behaviour suite and fixes; `.fig` import, best effort; Windows QA pass with eight fixes; auto layout behaviour suite and fixes; Display P3: gamut warning and soft-proof (true P3 blocked upstream); several windows; localization layer with a draft Spanish catalog; hosting figcraft-server: wss in the desktop app, server releases, deployment guide; plugin panels and settings; canvas fixes: boolean hit testing on the result, group drags, frame outlines and slices; code connect; stretch and scatter brushes, pen pressure; text on a path and pattern fills; team libraries on the server and swap library; branches: create, update from main, review and merge; animated GIF fills and TIFF images; Open recent, outlines for the selection and mask outlines: menu breadth 100%; extended collections, variables import/export, gradient stop and variant bindings; feature breadth ~80%; ready ~49%) · **Target:** Figma Design (desktop app 126.10.7)
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-19 · **Change:** minor (community batch #753: Selection colors, smart-selection spacing, a Present tab; language table re-measured from the catalogs; community fixes from #524 up (55 PRs: `.fig` import fidelity, paste from other apps, the Actions palette, editor fixes, server limits) and a boolean-op crash guard; number variables in the text content picker (#629); frames and sections convert into each other (#719); bounded canvas pan overscan; community fixes from #478 up and a control-channel fix (#589); bounded canvas pan overscan; Typography spacing icons support scrubbing (#373); font scans skip named pipes; system theme on first run; recent files as cards with thumbnails on the home screen; community fixes: lost images reported on loading (#207), SVG import budgets (#190), Leptos code (#223), full screen (#227), server snapshots readable again (#188), owner-only preferences (#200), ruzstd 0.9.1 (#182), layer cycle repair (#205), batch rollback, Direct3D 12 on Windows, plugin metering (#192); vector edit mode regions: hover hatch, selection and drag; SVG/PDF exports refuse over-depth documents (#208); bounded MCP/control framing, connections and queues (#201); plugin log limits (#191); live-session revert guard (#198); attached MCP no longer replays after a lost reply (#194); repeat command recursion fix; the Layout panel's constrain-proportions link scales the other side, #220; core editor leftovers: component playground, auto gap handles, variables inside styles, inner shadows and background blur on groups, command-made text readable on dark pages, a one-step frame/group convert, delays on mouse triggers and manual overlay offsets, wrapped-line alignment; `.fig` export: instance sizes, variables with modes, shared styles, variable-width strokes; starter templates, a Templates tab and Getting started tips on the home screen; your online files; everyday editing partials: number fields, outline options, Hide when publishing, cursors, panel widths, dark pages; sharing with a join code; text box sizes measured against documents re-saved by other software; live sessions per document; .fig export checked by opening written files in other software; a public figcraft-server: open hosting, owner tokens, per-address limits, idle expiry, moderation, install.sh; experimental .fig export; keyboard shortcut parity suite and bindings; Simplified Chinese draft catalog; Latin American Spanish overlay; prototyping tail: gamepad triggers, widgets in prototypes, mode lookups; plugin directory on figcraft-server; Japanese and Korean draft catalogs and CJK UI fonts; plugin widgets and the plugin panel tail; French, German and Brazilian Portuguese draft catalogs; cursor chat and spotlight in live sessions; layers and assets panels behaviour suite and fixes; vector multi-edit and edit tail; dev resources links; extended collections tail; branch version history and finer list merges; headline percentages recomputed from the area table: feature breadth ~84%, core ~94%, mainstream ~50%; text lists, hanging punctuation and decoration styles; comments and version history behaviour suite and fixes; canvas navigation, guides and grids behaviour suite and fixes; export and inspect behaviour suite and fixes; .fig import: editable vector networks and more layer kinds; shapes and vector behaviour suite and fixes; paint and effects behaviour suite and fixes; frames, groups, sections and masks behaviour suite and fixes; styles and variables behaviour suite and fixes; prototyping behaviour suite and fixes; components behaviour suite and fixes; embedded image colour profiles; layers panel keyboard: F2 rename, Shift+F10 context menu, keyboard box selection, 10k-layer QA; per-side stroke weight variables; text behaviour suite: CJK line breaking, metrics, vertical trim; selection and transform behaviour suite and fixes; `.fig` import, best effort; Windows QA pass with eight fixes; auto layout behaviour suite and fixes; Display P3: gamut warning and soft-proof (true P3 blocked upstream); several windows; localization layer with a draft Spanish catalog; hosting figcraft-server: wss in the desktop app, server releases, deployment guide; plugin panels and settings; canvas fixes: boolean hit testing on the result, group drags, frame outlines and slices; code connect; stretch and scatter brushes, pen pressure; text on a path and pattern fills; team libraries on the server and swap library; branches: create, update from main, review and merge; animated GIF fills and TIFF images; Open recent, outlines for the selection and mask outlines: menu breadth 100%; extended collections, variables import/export, gradient stop and variant bindings; feature breadth ~80%; ready ~49%) · **Target:** Figma Design (desktop app 126.10.7)
|
||||
|
||||
FigCraft is a clean-room, open-source, pure-Rust reimplementation of the Figma design workflow,
|
||||
native on macOS, Windows, Linux and FreeBSD and in the browser, fully drivable by agents through
|
||||
@@ -316,6 +316,7 @@ Ranked; detail and milestones in [`docs/roadmap.md`](docs/roadmap.md).
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-10-19 | minor | Layout grids: columns and rows can set their line width to Auto (a width of 0, or typing the word “Auto” / “自动” in the field), drawing a one-pixel hairline down each band's middle like the square grid instead of a filled band; the width field shows “Auto” as its placeholder and clears to Auto. The align menu no longer forces a 60 px band on a zero width (it keeps Auto); only stale sub-pixel widths are lifted. Regression test in the layout suite. Numbers unchanged. |
|
||||
| 2026-10-17 | minor | Community batch #753 (10 PRs): Selection colors for mixed selections (#403); smart-selection spacing fields and canvas handles (#402); a Present tab with device and scale controls (#537); adding auto layout to an empty frame keeps its size (#369); `node.set` applies auto layout keys to frames only and warns about font styles a family lacks (#603); canvas images on whole device pixels (#359); Adwaita window controls on Wayland without server decorations (#592, not run on GNOME or KDE by the maintainers); the keyboard shortcuts panel closes on the home screen (#548); macOS paste modifiers in tests (#750); credits column tests (#347). `cargo xtask parity` re-run: 212 / 212 menu items (100%; the catalog gained View ▸ Full screen with #227 on 2026-10-14), 561 commands. Language table re-measured from the catalogs (2,272 entries): the drafts read 95–99% (strings added since 2026-10-12 show English), Indonesian has a draft (99%; it read none), and Russian, Swedish (its command labels from #599), Turkish and Czech are listed with their counts. Per-area parity rows for the day's landings in `docs/gaps.md`, `target-app-parity.md` and the area docs. Numbers unchanged |
|
||||
| 2026-10-17 | minor | Control channel while the window is minimised (M8, #720): a minimised or covered window answers every request that acts on the app's state (edits, `ui.inspect`, `ui.pointer`, `ui.key`, `ui.type`, `ui.set`, `app.quit`…) without drawing, and what needs a drawn frame (`ui.screenshot`, `ui.input`, `window.new`) is an error at once; before, those waited up to 60 s and held up every later request on the connection (an attached agent's `inspect_ui` or window screenshot stalled until the window came back). Measured on Windows 11, minimised: requests ~100 ms each (eframe wakes a minimised window at most ten times a second; ~2 ms on screen), a window screenshot fails in ~100 ms instead of 60 s, idle CPU 0. Numbers unchanged. |
|
||||
| 2026-10-17 | minor | Community fixes from #524 up (batches #727, #728, #733, #735, #736 and #729; 55 PRs) and a crash guard. `.fig` import: explicit instance identity, overrides by key, text style precedence, grid track sizes, slot content, connector labels, skip ink, paragraph options and hanging lists, list start numbers, vertical trim, per-point stroke joins, text on a path, image adjustments and embedded images; large files open within budgets from the file's own size; an import report after opening; imported bytes stay out of the command journal. Files and paste: save a copy as `.fig`; Cmd/Ctrl+V pastes images copied in other apps and layers copied from another design app (`edit.pasteDesignLayers`); paste over and paste properties; clipboard reads on Linux and the BSDs time out after 2 s. Editor: live font preview on hover; Shift+I and Resources open Assets; Shift-drag moves the selection; thin strokes take a nearby double-click; dropped points merge; Flatten keeps open paths; the Actions palette gets tabs, ranked search, a keyboard highlight and recents; the colour picker opens on a new fill or stroke; text strokes follow their alignment; selection highlights after line breaks; a draggable pages/layers divider; variant properties reorder by drag; submenus keep their hover with a safe triangle; menu actions that need a value ask for it; File ▸ Rename edits the name in place. Engine: bad paint indexes, non-finite geometry and pages in copy/cut are refused; a param naming a layer says so when it isn't one; a CLI script is one undo step and resolves `$step`. Server and collaboration: message limits follow `max_file_mb` (client capped at 1 GiB); a damaged generation field no longer drops flushed edits; the web build joins a session from a `#join=` link. Also Swedish command labels, Nix CI through the shared workflow, paint bounds once per render, and a guard that turns a panic inside the boolean-op library into bad input (the stroke draws unclipped). Numbers unchanged. |
|
||||
|
||||
@@ -1189,7 +1189,9 @@ pub enum GridAlign {
|
||||
#[serde(default)]
|
||||
pub struct LayoutGrid {
|
||||
pub kind: GridKind,
|
||||
/// Grid: cell size. Fixed (not stretched) columns/rows: their width/height.
|
||||
/// Grid: cell size. Fixed (not stretched) columns/rows: their width/height. 0 (or Auto) draws
|
||||
/// a one-pixel hairline like the square grid; a positive value draws a band that many
|
||||
/// document units wide.
|
||||
pub size: f64,
|
||||
/// Columns/rows: how many (0: Auto, as many fixed-size ones as fit; a stretched grid has 1).
|
||||
pub count: u32,
|
||||
|
||||
@@ -1047,6 +1047,9 @@ pub fn grid_lines(g: &LayoutGrid, w: f64, h: f64) -> Vec<Rect> {
|
||||
let total = if cols { w } else { h };
|
||||
let gutter = if g.gutter.is_finite() { g.gutter.max(0.0) } else { 0.0 };
|
||||
let offset = if g.offset.is_finite() { g.offset.max(0.0) } else { 0.0 };
|
||||
// Auto width (size 0, a non-stretched grid) draws a one-pixel hairline down the
|
||||
// band's middle, like the square grid; otherwise a filled band of `size`.
|
||||
let auto = g.size <= 0.0 && g.align != GridAlign::Stretch;
|
||||
let count = match g.count {
|
||||
// Auto: as many fixed-size columns (rows) as fit in the room the type leaves them.
|
||||
0 if g.align != GridAlign::Stretch => {
|
||||
@@ -1074,7 +1077,13 @@ pub fn grid_lines(g: &LayoutGrid, w: f64, h: f64) -> Vec<Rect> {
|
||||
};
|
||||
for i in 0..count {
|
||||
let a = start + i as f64 * (size + gutter);
|
||||
out.push(if cols { Rect::new(a, 0.0, a + size, h) } else { Rect::new(0.0, a, w, a + size) });
|
||||
if auto {
|
||||
// A one-pixel hairline down the band's middle (the square grid's lines).
|
||||
let c = a + size / 2.0;
|
||||
out.push(if cols { Rect::new(c, 0.0, c, h) } else { Rect::new(0.0, c, w, c) });
|
||||
} else {
|
||||
out.push(if cols { Rect::new(a, 0.0, a + size, h) } else { Rect::new(0.0, a, w, a + size) });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -447,3 +447,27 @@ fn grid_hostile_values() {
|
||||
assert!(x.is_finite() && y.is_finite() && w.is_finite() && h.is_finite());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn grid_lines_auto_width_columns_rows_hairline() {
|
||||
// Columns with Auto width (size 0, non-stretched) draw one-pixel hairlines at each band's
|
||||
// middle, like the square grid; a set width draws filled bands.
|
||||
let g = LayoutGrid { kind: GridKind::Columns, align: GridAlign::Min, count: 3, size: 0.0, gutter: 10.0, offset: 0.0, ..LayoutGrid::default() };
|
||||
let lines = grid_lines(&g, 300.0, 50.0);
|
||||
assert_eq!(lines.len(), 3, "three hairlines");
|
||||
for r in &lines {
|
||||
assert!((r.x0 - r.x1).abs() < 1e-9 && (r.y0 - r.y1).abs() > 1.0, "a vertical hairline: {r:?}");
|
||||
}
|
||||
// A positive width draws filled bands again.
|
||||
let g = LayoutGrid { kind: GridKind::Columns, align: GridAlign::Min, count: 3, size: 8.0, gutter: 10.0, offset: 0.0, ..LayoutGrid::default() };
|
||||
let lines = grid_lines(&g, 300.0, 50.0);
|
||||
assert!(lines.iter().all(|r| (r.x1 - r.x0).abs() > 1e-9), "a set width draws bands");
|
||||
|
||||
// Rows Auto width: horizontal hairlines.
|
||||
let g = LayoutGrid { kind: GridKind::Rows, align: GridAlign::Min, count: 2, size: 0.0, gutter: 10.0, offset: 0.0, ..LayoutGrid::default() };
|
||||
let lines = grid_lines(&g, 50.0, 200.0);
|
||||
assert_eq!(lines.len(), 2, "two hairlines");
|
||||
for r in &lines {
|
||||
assert!((r.y0 - r.y1).abs() < 1e-9 && (r.x0 - r.x1).abs() > 1.0, "a horizontal hairline: {r:?}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -923,7 +923,12 @@ fn overlays(app: &FigApp, painter: &egui::Painter, t: &Tokens) -> Vec<(NodeId, [
|
||||
let a = w * Point::new(r.x0, r.y0);
|
||||
let b = w * Point::new(r.x1, r.y1);
|
||||
let (sa, sb) = (app.to_screen(a.x, a.y), app.to_screen(b.x, b.y));
|
||||
if g.kind == figcraft_doc::GridKind::Grid {
|
||||
// The square grid and an Auto-width line draw one-pixel hairlines; a filled
|
||||
// band (a column/row with a set width) is painted as a rectangle.
|
||||
if g.kind == figcraft_doc::GridKind::Grid
|
||||
|| (r.x0 - r.x1).abs() < 1e-9
|
||||
|| (r.y0 - r.y1).abs() < 1e-9
|
||||
{
|
||||
painter.line_segment([sa, sb], stroke(col, 1.0));
|
||||
} else {
|
||||
painter.rect_filled(Rect::from_two_pos(sa, sb), CornerRadius::ZERO, col);
|
||||
|
||||
@@ -2069,12 +2069,13 @@ fn grid_settings(app: &mut FigApp, ui: &mut Ui, ids: &[NodeId], list: &[LayoutGr
|
||||
menu_popup(&resp).show(|ui| {
|
||||
for (k, (name, a)) in names.iter().zip(aligns).enumerate() {
|
||||
if menu_check(ui, k == cur, name, "") {
|
||||
// Fixed-size columns need a size of their own.
|
||||
// Keep Auto (size 0); only lift stale sub-pixel sizes (0 < size < 1) to a
|
||||
// sensible band, so a width typed as 0 stays Auto.
|
||||
app.run(
|
||||
"node.set",
|
||||
set(&|x| {
|
||||
x.align = a;
|
||||
if a != GridAlign::Stretch && !(x.size.is_finite() && x.size > 0.0) {
|
||||
if a != GridAlign::Stretch && x.size > 0.0 && x.size < 1.0 {
|
||||
x.size = 60.0;
|
||||
}
|
||||
if a == GridAlign::Stretch {
|
||||
@@ -2099,14 +2100,16 @@ fn grid_settings(app: &mut FigApp, ui: &mut Ui, ids: &[NodeId], list: &[LayoutGr
|
||||
GridAlign::Center => {
|
||||
widgets::sublabels(ui, span, Some(tr("Gutter")));
|
||||
row(ui, 32.0, |ui| {
|
||||
field(app, ui, "size", g.size, &size);
|
||||
let e = crate::variable_ui::number_field_or(app, ui, ids, &format!("layoutGrids/{i}/size"), Id::new(("grid_field", "size", i)), Some(g.size), col, tr("Auto"), Lead::None, "");
|
||||
app.field_run(e, "node.set", |v| set(&|x| x.size = v.max(0.0)));
|
||||
field(app, ui, "gutter", g.gutter, &gutter);
|
||||
});
|
||||
}
|
||||
GridAlign::Min | GridAlign::Max => {
|
||||
widgets::sublabels(ui, span, Some(tr("Offset")));
|
||||
row(ui, 32.0, |ui| {
|
||||
field(app, ui, "size", g.size, &size);
|
||||
let e = crate::variable_ui::number_field_or(app, ui, ids, &format!("layoutGrids/{i}/size"), Id::new(("grid_field", "size", i)), Some(g.size), col, tr("Auto"), Lead::None, "");
|
||||
app.field_run(e, "node.set", |v| set(&|x| x.size = v.max(0.0)));
|
||||
field(app, ui, "offset", g.offset, &offset);
|
||||
});
|
||||
widgets::sublabels(ui, tr("Gutter"), None);
|
||||
|
||||
@@ -259,10 +259,21 @@ fn number_field_impl(
|
||||
};
|
||||
// A relative edit of no single value goes to each layer's own.
|
||||
let set = |v: f64| Edit::All(FieldEdit::Set(v));
|
||||
let typed = |text: &str| match (parse(text, suffix == "%")?, value) {
|
||||
(Typed::Value(v), _) => Some(set(v)),
|
||||
(Typed::Rel(r), Some(cur)) => r.apply(cur).map(set),
|
||||
(Typed::Rel(r), None) => Some(Edit::Each(r)),
|
||||
let typed = |text: &str| {
|
||||
// A field whose placeholder is "Auto" (grid width/count, auto-gap, …) also takes the
|
||||
// word "Auto" (or the Chinese "自动") as input, setting it to 0 — its automatic value.
|
||||
let auto_token: &str = &*tr("Auto");
|
||||
if empty == auto_token {
|
||||
let t = text.trim();
|
||||
if t.eq_ignore_ascii_case("auto") || t == "自动" {
|
||||
return Some(set(0.0));
|
||||
}
|
||||
}
|
||||
match (parse(text, suffix == "%")?, value) {
|
||||
(Typed::Value(v), _) => Some(set(v)),
|
||||
(Typed::Rel(r), Some(cur)) => r.apply(cur).map(set),
|
||||
(Typed::Rel(r), None) => Some(Edit::Each(r)),
|
||||
}
|
||||
};
|
||||
// With the keyboard on the field (Tab) and nothing typed yet, the arrows step it as it is.
|
||||
if editing.is_none()
|
||||
|
||||
+3
-2
@@ -1,6 +1,6 @@
|
||||
# UI and interaction parity
|
||||
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-18 · **Change:** minor (a rename selects the whole name, so typing replaces it; Escape or Enter after a pen path stays on the same vector (#760); IME composition kept on through idle frames of a text edit, candidates at the caret (#747); Selection colors for mixed selections and smart-selection spacing (#753); submenus with a hover delay and a safe triangle; the Actions palette's tabs, ranked search, highlight and recents; menu items that ask for a value; editor fixes from the community batches; fields select their text on focus; Typography spacing icons support scrubbing (#373); CSS colour names in hex fields; the Small caps sample in Type settings drawn from capitals; recent files as cards; vector edit mode: hovering, hatching, selecting and dragging filled regions; home screen: Templates tab, first-run templates and Getting started tips; number fields: scrub rates, arrow steps, arithmetic with brackets, relative edits of mixed values; outline mode's hidden layers and object bounds; Hide when publishing; cursors per tool and modifier; panel widths; dark pages for files made in the dark theme; drag threshold and double-clicks into text in groups; rotation origin on Alt+R and placing with Enter: no documented shortcut missing; keyboard shortcut parity suite and bindings; cursor chat and spotlight in live sessions; layers and assets panels behaviour suite and fixes; vector multi-edit and the vector edit tail; canvas navigation, guides and grids behaviour suite and fixes; shapes and vector behaviour suite and fixes; paint and effects behaviour suite and fixes; frames, groups, sections and masks behaviour suite and fixes; layers panel keyboard: F2 rename, Shift+F10 context menu, F8 box selection; selection and transform behaviour suite and fixes; Display P3: gamut warning and soft-proof (true P3 blocked upstream); several windows; boolean hit testing on the result, group drags, frame outlines and slices; outlines for the selection, mask outlines; arc fields, live boolean editing, shape builder on strokes, one-sided widths) · **Target:** Figma Design UI3 (desktop app 126.10.7)
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-19 · **Change:** minor (a rename selects the whole name, so typing replaces it; Escape or Enter after a pen path stays on the same vector (#760); IME composition kept on through idle frames of a text edit, candidates at the caret (#747); Selection colors for mixed selections and smart-selection spacing (#753); submenus with a hover delay and a safe triangle; the Actions palette's tabs, ranked search, highlight and recents; menu items that ask for a value; editor fixes from the community batches; fields select their text on focus; Typography spacing icons support scrubbing (#373); CSS colour names in hex fields; the Small caps sample in Type settings drawn from capitals; recent files as cards; vector edit mode: hovering, hatching, selecting and dragging filled regions; home screen: Templates tab, first-run templates and Getting started tips; number fields: scrub rates, arrow steps, arithmetic with brackets, relative edits of mixed values; outline mode's hidden layers and object bounds; Hide when publishing; cursors per tool and modifier; panel widths; dark pages for files made in the dark theme; drag threshold and double-clicks into text in groups; rotation origin on Alt+R and placing with Enter: no documented shortcut missing; keyboard shortcut parity suite and bindings; cursor chat and spotlight in live sessions; layers and assets panels behaviour suite and fixes; vector multi-edit and the vector edit tail; canvas navigation, guides and grids behaviour suite and fixes; shapes and vector behaviour suite and fixes; paint and effects behaviour suite and fixes; frames, groups, sections and masks behaviour suite and fixes; layers panel keyboard: F2 rename, Shift+F10 context menu, F8 box selection; selection and transform behaviour suite and fixes; Display P3: gamut warning and soft-proof (true P3 blocked upstream); several windows; boolean hit testing on the result, group drags, frame outlines and slices; outlines for the selection, mask outlines; arc fields, live boolean editing, shape builder on strokes, one-sided widths) · **Target:** Figma Design UI3 (desktop app 126.10.7)
|
||||
|
||||
Fine canvas control is what Figma users feel first: handles, snapping, nudging, modifier keys,
|
||||
drag behaviour, numeric precision. This checklist covers the tools, gestures and panels. Status:
|
||||
@@ -105,7 +105,7 @@ interaction feel not yet compared.
|
||||
| Frames and sections drawn around layers take those fully inside; sections never drop into frames | done | not in auto layout frames |
|
||||
| Resizing a section leaves its contents in place | done | |
|
||||
| Masks: what a mask hides doesn't take clicks; a mask group's box is the mask's | done | |
|
||||
| Layout grids (Ctrl+G) | done | columns, rows and grid; stretch, left, centre, right; Auto count; several per frame; styles; not shown or snapped on a rotated frame; a nested frame's grids snap but only top-level frames draw them |
|
||||
| Layout grids (Ctrl+G) | done | columns, rows and grid; Auto line width (0 draws a one-pixel hairline); stretch, left, centre, right; Auto count; several per frame; styles; not shown or snapped on a rotated frame; a nested frame's grids snap but only top-level frames draw them |
|
||||
| Gamut warnings for Display P3 files | done | colour picker note; View ▸ Soft-proof sRGB stripes what sRGB can't show (the canvas itself is sRGB) |
|
||||
| Gradient and padding/gap handles on the canvas | done | |
|
||||
| Hover outline, selection colours, handle sizes | done | measured from UI3 screenshots |
|
||||
@@ -172,6 +172,7 @@ in the table. `crates/ui-egui/src/shortcut_keys_tests.rs` drives the keys a look
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-10-19 | minor | Layout grids: columns and rows take an Auto line width (0 or “Auto”), drawing a one-pixel hairline down each band's middle; the width field shows “Auto” and typing it clears the width. The align menu keeps a zero width as Auto instead of forcing 60 px. Regression test added. |
|
||||
| 2026-10-18 | minor | A rename (layers double-click, F2, File ▸ Rename, a page) selects the whole name in the frame its field first draws, so the first key replaces the name instead of being appended. Checked in the app on Windows over the control channel |
|
||||
| 2026-10-17 | minor | Escape or Enter while the pen draws ends the path and keeps its vector in edit mode with the pen, so the next path is drawn into the same layer (unconnected); another Escape leaves edit mode (#760). Entering edit mode on a layer that already is a vector no longer records an empty undo step. Numbers unchanged |
|
||||
| 2026-10-17 | minor | Text layers keep the platform IME on for every frame of an edit, not only frames with input (an idle frame turned it off and macOS dropped each composition, #747); the candidate window opens at the caret instead of the canvas corner; keys pressed while composing go to the IME |
|
||||
|
||||
Reference in New Issue
Block a user