From fc90078333c77f85af38513734efcf9ffb38903f Mon Sep 17 00:00:00 2001 From: Trevor Brown Date: Fri, 13 Nov 2026 00:36:40 -0500 Subject: [PATCH] Docs: Tidy up keeps the first layer and the other axis for a row or a column, not a grid The row's opening said the first layer and the other axis are always kept, but a grid centres each layer in its column and can move it on both axes. The claim is now limited to rows and columns; the order and sizes are kept for all three. Co-Authored-By: Claude Opus 5.5 Model-Effort: Opus 5.5 drove and wrote --- docs/ui-parity.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ui-parity.md b/docs/ui-parity.md index af1fdb89b..77686fb2b 100644 --- a/docs/ui-parity.md +++ b/docs/ui-parity.md @@ -83,7 +83,7 @@ interaction feel only partly compared: the interactions measured so far, case by | Locked layers | done | selectable from the layers panel; no handles, not dragged with the rest of a selection | | Edit ▸ Set default properties: new layers take the selected layer's properties | done | from a shape (any layer but text): new rectangles, ellipses, polygons and stars drawn or clicked with their tools take its fills, strokes and their settings, effects, opacity, blend and corners; from a text layer: new text from the Text tool takes its fills and font (#2028). Silent in the help center on frames, lines and arrows: they keep their own look, as do layers made by commands; the defaults last for the session | | Smart selection spacing | partial | with layers in a row, a column or an aligned grid selected, the Layout section shows horizontal and vertical spacing ("Mixed" until set; typed, scrubbed, fractional and negative) and pink handles in the gaps on the canvas drag them, one undo step, Escape cancels (`arrange.spacing`; sizes, parents and offsets within each track kept; at most 2,000 layers; flow children, locked layers and layers inside instances left out). A ring at each layer's centre drags it to another place in a regular row, column or complete top-left-aligned grid: the others close up and make room around it with the gaps kept, and with Cmd/Ctrl held the two layers swap places instead, previewed live while dragging (`selection_reorder_tests`; no ring on a layer under 16 px on screen). Not covered: reordering irregular grids, and several marked layers moved together. Checked by its author on macOS and in the app on Windows (#402) | -| Tidy up | partial | measured in Figma's web app on 2026-11-12 (a row, a column, a 2 x 3 grid of unequal sizes and its transpose, and many runs on the gap, the unavailable cases among them): the order, the sizes and the other axis are kept and the first layer stays. A row (one group of layers whose Y ranges overlap, side by side) evens its horizontal gaps and a column its vertical gaps to one gap: the most common existing gap (the smaller of two equally common ones), else the mean rounded to a whole number, half up (30, 40, 30 gives 30; 80, 20, 45 gives 48; 10, 10, 50, 90 gives 10; 10, 25 gives 18; 10, 25, 30 gives 22). Layers of a row may overlap along X, and overlapping layers in a chain count as a row (the first and third needn't touch): the negative gap counts in the mean (50 px squares at X 0, 60, 105, 170, gaps 10, -5, 15, give X 0, 57, 114, 171; squares at X 0, 40, 80, 150 give 0, 40, 80, 120). Measured in Figma's web app on 2026-11-13: a negative gap is raised so no layer reaches the one two places before it, floor(-w / 2) + 1 for the narrowest interior layer's width w, so 10, 20 and 30 wide interior layers among 100s give -4, -9 and -14 (X 0, 96, 102, 198, 294, 390 for widths 100, 10, 100 x4), while six 100 wide layers keep the most common gap, -40; only those widths were measured, and an explicit `spacing` is not raised. A grid (two or more rows and columns, one layer in every cell) is packed along the axis with more groups: a column is as wide as its widest layer around the middle of where its layers were, the first column stays, each layer is centred in its column to a whole pixel with Snap to pixel grid on, and every column is stacked from the selection's top; a grid with more rows than columns is the mirror image (centred rows, laid out left to right). The vertical gap reads 51 or 52 in Figma's own runs (mean 51.67), so FigCraft's positions along a stack can differ by a pixel there. Unavailable, as measured, for fewer than three layers, for layers that all overlap each other (one row and one column), for a diagonal and for an irregular layout: a greyed-out row with a tip in the Design panel's menu, the command moving nothing and adding no undo step. Not measured, FigCraft's choices: a 2 x 2 grid packed as columns; layers in an auto layout flow being unavailable (the frame places them; the measurement could not tell this from an irregular layout); the 2,000 layer cap; rotated layers counting by their box; gaps a pixel apart being different gaps; an explicit `spacing` setting the gap and taking two layers; no rounding with Snap to pixel grid off. Tests: tidy_tests | +| Tidy up | partial | measured in Figma's web app on 2026-11-12 (a row, a column, a 2 x 3 grid of unequal sizes and its transpose, and many runs on the gap, the unavailable cases among them): the order and the sizes are kept; in a row or a column the first layer also stays and the other axis is untouched (a grid can move a layer on both axes, as below). A row (one group of layers whose Y ranges overlap, side by side) evens its horizontal gaps and a column its vertical gaps to one gap: the most common existing gap (the smaller of two equally common ones), else the mean rounded to a whole number, half up (30, 40, 30 gives 30; 80, 20, 45 gives 48; 10, 10, 50, 90 gives 10; 10, 25 gives 18; 10, 25, 30 gives 22). Layers of a row may overlap along X, and overlapping layers in a chain count as a row (the first and third needn't touch): the negative gap counts in the mean (50 px squares at X 0, 60, 105, 170, gaps 10, -5, 15, give X 0, 57, 114, 171; squares at X 0, 40, 80, 150 give 0, 40, 80, 120). Measured in Figma's web app on 2026-11-13: a negative gap is raised so no layer reaches the one two places before it, floor(-w / 2) + 1 for the narrowest interior layer's width w, so 10, 20 and 30 wide interior layers among 100s give -4, -9 and -14 (X 0, 96, 102, 198, 294, 390 for widths 100, 10, 100 x4), while six layers 100 wide keep the most common gap, -40; only those widths were measured, and an explicit `spacing` is not raised. A grid (two or more rows and columns, one layer in every cell) is packed along the axis with more groups: a column is as wide as its widest layer around the middle of where its layers were, the first column stays, each layer is centred in its column to a whole pixel with Snap to pixel grid on, and every column is stacked from the selection's top; a grid with more rows than columns is the mirror image (centred rows, laid out left to right). The vertical gap reads 51 or 52 in Figma's own runs (mean 51.67), so FigCraft's positions along a stack can differ by a pixel there. Unavailable, as measured, for fewer than three layers, for layers that all overlap each other (one row and one column), for a diagonal and for an irregular layout: a greyed-out row with a tip in the Design panel's menu, the command moving nothing and adding no undo step. Not measured, FigCraft's choices: a 2 x 2 grid packed as columns; layers in an auto layout flow being unavailable (the frame places them; the measurement could not tell this from an irregular layout); the 2,000 layer cap; rotated layers counting by their box; gaps a pixel apart being different gaps; an explicit `spacing` setting the gap and taking two layers; no rounding with Snap to pixel grid off. Tests: tidy_tests | | Selection colors | partial | the Design panel shows the section from two paint groups (paints sharing a style, a variable and a value count as one group), or from one when a selected layer has children (a frame, group, component or instance), and lists their solid and gradient paints (children and text ranges included; hidden paints, masks, images, patterns and boolean operands left out; styles and variables listed apart): editing a colour changes every matching fill and stroke in one undo step, a row selects the layers that use it or applies a color style or color variable of the document, and a row linked to a style or variable detaches it, keeping the color (`selection.colors`, `selection.setPaint`, `selection.applyColorStyle`, `selection.bindColorVariable`, `selection.detachColor`, `selection.selectColor`). A row's Styles menu also offers enabled libraries' published color styles and Create style (`selection.createColorStyle`); no library variables and no new variable from a row (#403) | | Keyboard box selection | done | Alt+Space on macOS, Ctrl+Space on Windows and Linux, or F8 (`select.area`): a box around the selection or in the middle of the view; arrows move it, Cmd/Ctrl+arrows or Shift+arrows size it (Shift with Cmd/Ctrl: farther), Enter selects like a marquee (Shift+Enter toggles, Cmd/Ctrl+Enter nested), Escape closes; Tab while the box shows, or the chord again, switches to pick select: a pink outline on the first selected layer (the page's top layer with nothing selected), Tab and Shift+Tab move it between sibling layers in Layers order, Enter into a frame's top child, Shift+Enter out to the parent, Space selects it, Escape or a press on the canvas ends it; `ui.key` takes the same keys (#1836) | | Selection colors | partial | the Design panel shows the section from two paint groups (paints sharing a style, a variable and a value count as one group), or from one when a selected layer has children (a frame, group, component or instance; a layer without children shows it only with two paint groups, such as a red fill and a blue stroke; one paint group, however many layers share it, hides it), counting the selected layers' own fills and strokes and their descendants' (measured in Figma's web app, 2026-11-09, #2188, on frames, groups and rectangles only; the rule for components and instances is not measured), and lists their solid and gradient paints (children and text ranges included; hidden paints, masks, images, patterns and boolean operands left out; styles and variables listed apart): editing a colour changes every matching fill and stroke in one undo step, a row selects the layers that use it or applies a color style or color variable of the document, and a row linked to a style or variable detaches it, keeping the color (`selection.colors`, `selection.setPaint`, `selection.applyColorStyle`, `selection.bindColorVariable`, `selection.detachColor`, `selection.selectColor`). A row's Styles menu also lists each enabled library's published color styles under the library's name (a library that can't be read offers none), and a linked row's menu switches it to another style; a library style is copied in, linked and read-only, in the same undo step (`selection.applyColorStyle` with `library`). Create style on an ordinary row asks for a name (the next free "Color n" first) and makes a style of the row's whole paint, gradients, opacity, blend mode and variables bound to gradient stops included, linked to every fill and stroke the row stands for in one undo step; a name in use keeps the window open (`selection.createColorStyle`). Text ranges with fills of their own take the style's value, without a link. No library variables from there, and no new variable from a row (#403) |