figcraft/docs/ui-parity.md

35 KiB
Raw Permalink Blame History

UI and interaction parity

Last reviewed: 2026-10-10 · Last updated: 2026-10-13 · Change: minor (session restore: windows and tabs come back as they were left; 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: done (built and checked against Figma's documented behaviour or by eye), partial, missing. Nothing here has been compared tool by tool against the running Figma yet; that pass is the main remaining work (40–60 h, gaps #4).

Summary (estimated): UI/UX fidelity ~58%. Layout and look of UI3 compared side by side (~65%); interaction feel not yet compared.

Window and panels

Item Status Notes
UI3 layout: tab strip as title bar, icon rail, file header, pages + layers, floating bottom toolbar with flyouts, Design / Prototype / Inspect panels done frameless window on Windows/Linux with drawn buttons
Light and dark themes done colours from theme::Tokens; a file or a page made while the dark theme shows gets a #1E1E1E page (#F5F5F5 in the light theme), its own from then on: changing the theme repaints no page and opened files keep theirs; the file the app opens with takes the theme once it is known; the CLI, MCP and exports have no theme and keep #F5F5F5; text drawn with the Text tool is white on a dark page and black on a light one (so is text a command makes in the app without naming a fill; headless sessions keep black) (theme_pages_tests, dark_page_text_tests)
Minimize UI (Cmd+\) done
Resizable panels done each panel's edge drags its width (left 200–480, right 240–480, 240 by default; a double-click on the edge or View ▸ Panels ▸ Reset panel widths puts the default back); the widths are each window's own, the main window's are kept in the preferences when a drag ends and come back at the next start, a new window opens with those of the window it comes from; Minimize UI hides the panels and brings them back as they were; the view keeps its centre and zoom while a panel is resized; in a window too small for them the panels give way so the canvas keeps 160 px (the left one first), down to the smallest window (800×500) (panel_width_tests). Not compared with Figma's widths; no snap points
Actions palette (Cmd+K, Cmd+/) done commands; no assets search parity
Context menus done canvas and layers; Shift+F10 opens them from the keyboard (at the focused layer row or below the canvas selection) and the menu takes the keyboard; the Menu key isn't delivered by the windowing layer (egui 0.36 has no key for it)
Home screen: Recents, Online and Templates done (ours) The sidebar switches between the three (ui.set {homeSection}). Online: your online files (see the collaboration checklist). Recents: new file, open, join with a code, open and recent files, a Getting started card (six tips with their shortcuts from the keymap; its close button is remembered in the preferences and Help ▸ Getting started brings it back) and, while there are no recent files, four templates to start from. Templates: the eight starter templates as cards (thumbnail rendered from the document, cached per theme; name, description, kind and size), a search field and a kind filter, an empty state; Tab reaches every card and Enter opens it; cards and tabs are named for screen readers. A first run opens here. No Community files or drafts folder
Main menu from the logo done generated from catalog.rs; popups sized to content
Keyboard shortcuts panel done docked, tabbed by group like the documentation, searchable, per-platform keycaps; held keys, gestures and presentation keys listed beside the bindings; a label too long for its column ends with "…" and shows in full on hover
Several windows partial File ▸ New window, Open in new window on a tab, a tab dragged off the strip; each window comes back at the next start where it was, with its size, state, panels and tabs (session restore, next row). A screen-reader tree in windows other than the main one is blocked upstream: eframe 0.36 gives only the main window an accessibility adapter, so while a screen reader runs files stay tabs of the main window (restored ones too)
Session restore done (ours) The app comes back the way it was left. Kept with the preferences, written whenever it changes (at once, then at most once a second, never while nothing changes; a crash or a forced quit has it too): each window's place, size, maximized or full-screen state and screen, its side panels' tabs and widths, its tabs in order with the one in front, and per tab the saved file's path or, for one of your online files, its server and id (never a token), the page shown and the view (one view per file, not per page). At the next start the windows and tabs open again; a window whose screen is gone or that no screen shows enough of to grab moves onto a screen (its own if it is still there, else the nearest) and is never larger than it; files that are gone are skipped with one message ("2 files couldn't be reopened") and stay in Open recent; an online file is joined again as its owner and takes its place among the tabs when it arrives (one whose server can't be reached is skipped with a message saying so, and stays under Home ▸ Online); a file or invite link the app was started with opens in addition, in front. Documents never saved aren't part of it: unsaved work comes back from the recovery copies after a crash, and a normal quit keeps none. Preferences ▸ Reopen windows and tabs from last time (pref.restoreSession, on by default) and the --fresh flag start without it. If the last run never got through restoring (a mark written before and cleared once the windows have settled), this run starts on the home screen without restoring, and the home screen offers Restore last session (session.restore) instead. A first run is still the home screen. Holding Shift at start isn't read (the flag is the way); the browser keeps no preferences, so nothing is restored there
Multiplayer avatars, Share button missing waits for multiplayer
Blend mode menus: the layer's (Design panel) and each paint's (colour picker) done Pass through and Normal are distinct (Normal isolates a group's or frame's children); paints have no pass-through; plus darker drawn exactly on the canvas

Layers and Assets panels

Item Status Notes
Rows: click, Shift-click range, Cmd/Ctrl-click toggle; the selection follows on the canvas and a canvas selection is revealed done layers_behaviour_tests
Expand and collapse: Alt-click opens or closes everything inside; Collapse layers (Alt+L) keeps the way to the selection open done Alt-click pinned (the documentation is silent)
Drag to reorder and into frames, groups and auto layout: insertion line, spring-loaded open, several layers together, Escape cancels done several layers dropped together land together (they split apart before); instances and a layer's own children refuse drops
Eye and padlock: click, or drag across rows to set several in one step; layers in a locked frame show a faint padlock done the toggles no longer vanish under the pointer (clicks on them could miss)
Rename: double click, F2 / Cmd+R, Tab to the next row; several layers open Rename layers (match, regular expressions, current name and number codes, start value, preview) done numbered in stacking order, pinned
Find layers (filter by name) done not covered by the documentation
Pages: add, rename, drag to reorder, duplicate ("Copy of"), delete, dividers (a blank page named with a hyphen) done
Assets panel: folders from page, frames and slash names (fold away), search, thumbnails, drag onto the canvas or into frames and auto layout, Alt-drop swap, enabled libraries done
Hide when publishing from the Assets panel's context menu done a right-click on one of this file's components (also Libraries ▸ Hide when publishing for the selection, component.hideWhenPublishing {ids?, on?}): the model's sign of it is the name, so hiding puts a . before the name and showing takes the leading . and _ away (one undo step, saved and synced like a rename; a variant or a layer inside hides its whole component or set); a hidden component shows a crossed eye on its tile and a dimmer name, the menu item its check mark; the next publish leaves it out and brings it back when shown again (hide_publishing_tests). Library components (read-only here) have no such menu

Selection and transform

Item Status Notes
Click, Shift-click, marquee, Shift-marquee toggle done a marquee selects what it touches; from a top-level frame's background, the layers inside it; locked and hidden layers are skipped (selection_behaviour_tests)
Deep select (Cmd/Ctrl-click, Cmd/Ctrl-marquee) done
Select layer menu (every layer under the click) done
Enter / Shift+Enter (children / parent), Tab / Shift+Tab (siblings) done Tab renames the next layer while renaming
Resize handles: Shift keeps proportions, Alt from centre, constraints-aware done Alt shrinks too; past an edge flips (several layers mirror); groups and mixed rotations scale each layer along its own axes, keeping rotation and flip (no skew: children turned off a right angle are approximate); Cmd/Ctrl ignores a frame's constraints (transform_behaviour_tests)
Rotate just outside a corner; Shift in 15° steps done rotated handle box when layers share a rotation
Flip, rotate 90° done
Rotation origin (Alt+R) done a handle at the selection's centre to drag (snaps to the box's corners, edge middles and centre), double-click puts it back, Escape or Alt+R hides it; the corner handles, the rotation field, Rotate 90°/180° and transform.rotate turn about it; it follows the layers and lasts as long as the selection, not saved (the documentation doesn't say; pinned)
Enter with a shape or frame tool chosen done places what a click makes (100×100, lines 100 long, sections 400×300) in the middle of the view, selected (tool.place); from the toolbar, Enter on the chosen tool. No crosshair to move with the arrows first
Alt-drag duplicate done
Drag threshold; double-click into groups and text done a press moves or resizes only once the pointer has travelled 3 px on screen, so a click or double-click made with an unsteady hand drags nothing; a double-click goes one level into a group and the next one edits the text under it, wherever on the text it lands, with all of it selected (a double-click in the text being edited selects the word) (double_click_tests); Enter on a selected text does the same (all of it selected, typing replaces it) and Escape leaves editing with the layer still selected (text_enter_tests)
Scale tool (K): handles about an anchor, live factor, panel done
Nudge 1 / Shift 10 (preference), Cmd+arrows resize done arrows reorder auto layout children
Smart guides: edges, centres, equal spacing (between two layers or continuing a row's gap, labelled), spacing labels, parent, layout grid, ruler guides done red, snap.rs; thresholds not yet compared with Figma's
Ctrl to suspend snapping while dragging (macOS) done Control on macOS (Cmd keeps working), Ctrl elsewhere; moving, resizing and drawing
Measure (Alt hover, Cmd+Alt nested, Shift+Alt padding/gaps) done labels never overlap
Pixel grid snapping, pixel preview, 2x preview done moves, resizes and new shapes land on whole pixels; the pixel grid shows from 400% (view_behaviour_tests)
Numeric fields: arithmetic, scrubbing by dragging the label, mixed values done one field widget for every panel (widgets::number_field). Scrubbing the label: a step a point (1 px; 1% of opacity, 1° of rotation), ten with Shift, a tenth with Alt, each stretch at the rate held while it was dragged, one undo step when let go; past the edge of the screen it goes on where the platform reports the mouse's own motion (desktop), otherwise it stops there. Arrow keys: Up/Down step a pixel field by the small nudge and Shift by the big nudge (the preferences), other fields by their own step and ten of it; they work while typing (from what is typed) and with the keyboard on the field. Typing: + - * /, brackets, units (px, °, %, x, ms), a decimal comma; +10, *2, /4 are relative to the value, and 50%, +10%, -10% too in a field that isn't a percentage. Enter, Tab or a click elsewhere commits (Tab and Shift+Tab move to the next and previous control), Escape restores; a field left as it was commits nothing (no undo step, and a rounded display isn't written back). Mixed values show "Mixed": a number sets them all, a relative edit or an arrow key goes to each layer from its own value in one undo step, for X, Y, W, H, rotation, opacity, corner radius and stroke weight (elsewhere +10 on Mixed sets 10 and *2 does nothing) (field_tests). Left: scrubbing a Mixed field (nothing happens), x2-style suffix edits, the pointer isn't wrapped to the other side of the screen; rates not compared with Figma's
Transform box at small sizes done a press inside a layer smaller than its handles moves it, the nearest handle wins, handles answer just outside and are hidden under 16 px on screen; cursors follow each handle and the box's rotation
Locked layers done selectable from the layers panel; no handles, not dragged with the rest of a selection
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

Tools

Tool Status Notes
Move, hand (Space), zoom (hold Z, Alt out, drag area) done
Frame (presets panel, swap orientation), section, slice done
Rectangle, ellipse (arc handles and Design panel arc fields), polygon, star, line, arrow; Shift/Alt done Alt draws lines from the centre too (shapes_behaviour_tests)
Corner radius handles (inside each corner of a rectangle or frame, a polygon's or star's top point; Alt: one corner), star ratio handle; Count and Ratio fields done handles hide under 48 px on screen; no count handle on the canvas (the Count field instead); corner smoothing rounds rectangles and frames only
Pen: vector networks, branch, close, bend; pencil done pen pressure on Windows and from browser styluses only; outside edit mode the Pen closes on its first point, connects to its other points and continues a selected open path from an end point (vector_multi_behaviour_tests)
Vector edit mode: bend, paint bucket, lasso, cut, eraser, transform box, point snapping, mirroring done paint bucket drags across areas; cut drags divide a shape into layers; delete and heal follows the curve; rounded points are drawn; Shift-click deselects a point at a corner of the box (vector_behaviour_tests); several vectors edited at once, Shift-click handles to drag them together, a cap and join per point, rounded points beside curves (vector_multi_behaviour_tests). Not yet: the transform box around points of several layers
Shape builder (Shift+M) on fills, strokes and open paths; variable width (Shift+W), one side with Alt done
Boolean groups: clicked where the result is, double-click or Cmd/Ctrl-click into operands, live results while dragging or editing points, per-operand operations done
Text: point, auto height, fixed; caret, words, lines, IME done carets step over whole emoji and accented letters; CJK words by script run (no dictionary); vertical trim in Type settings; no spell check
Eyedropper (I) done picks the colour seen under the pointer (opaque) into the selection's fill and the recent colours, one undo step (fx_behaviour_tests)
Comment (C), Shift+C to show/hide done local only
Text on a path (Figma Draw) done put on from the Design panel or text.onPath, not by clicking a path with the Text tool; the path is edited by resizing only
Stretch and scatter brushes (Figma Draw) done eight presets drawn in code; the Pencil's brush is set by tool.pencilBrush, not from the toolbar
Image crop handles done

Canvas

Item Status Notes
Pan/zoom: wheel, pinch, Space-drag, Shift+0/1/2, Cmd+0, +/- done Shift-wheel pans sideways, pinch and the zoom tool keep the point under the pointer; zoom steps, limits (2%–25,600%) and frame order pinned where the documentation is silent (view_behaviour_tests)
Rulers and guides (drag out, move, remove; rotated frames; frame guides) done guides belong to the page or a top-level frame (a frame moved into another keeps its guides but they stop applying); a click selects one for Delete, the arrows or the context menu's Remove guide; Alt-drag drops a copy; Alt while dragging measures to the layers in the frame it crosses; ruler numbering checked by eye only
Frame labels (rotated, right-to-left), size badge done
Outline mode done Outlines, outlines for the selection, mask outlines, frame outlines; shapes are clicked on their outlines, reaching layers behind; View ▸ Outlines ▸ Include hidden layers (view.outlinesHiddenLayers) outlines hidden layers too and Include object bounds (view.outlinesObjectBounds) draws the box of every layer whose outline isn't its box (groups, text, ellipses, vectors); what either draws can be clicked there (a hidden layer on its outline, a group on its box) and nothing else can; both are view settings like the other outline flags (per file, off in a new one, checked in the menu); the lines are light on a dark page (outline_options_tests). The main menu now shows a check mark beside every View toggle that is on
Slices shown on the canvas (View ▸ Slices) done dashed rectangles
Dragging a layer inside a group keeps it in the group done frames and auto layout take other drops
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
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
Cursors per tool and modifier done the engine names a cursor for every tool, modifier and hover target (tool.overlay.cursor, tabled in cursor_tests) and the UI shows the system's or draws its own at the pointer (cursors.rs, cursors_tests; original glyphs from lines and the code-drawn icons). Arrow for Move and Scale; two-headed arrows on the handles that follow the handle and the box's rotation; outside a corner a curved rotate arrow turned to that corner, turning with the pointer while rotating; crosshair for the frame, section, slice, shape, pencil and Text tools; the I-beam over a text with the Text tool and over the text being edited; the pen as a cross with what a click does beside it (nothing: a new point; a ring: closes, connects to or goes on from a point; a plus: adds a point on a segment, also Alt in vector edit mode; a curve: bends, the Bend tool or Cmd/Ctrl); open and closed hand for the Hand tool, Space and the middle button; zoom in and out (Alt) while Z is held; eyedropper; comment pin; the copy cursor with Alt over a selected layer and while Alt-dragging; not-allowed while a drag resizes, rotates or moves a layer inside an instance (it is undone on release) and over a layers row that takes no drop. Ruler guides and gradient, crop and padding handles keep their own cursors (the tool's used to replace them). ui.inspect reports cursor. Left: no cursor for removing a point with the pen (the pen doesn't remove points); the drawn cursors follow the pointer a frame behind the system's; not compared with Figma's side by side
Multiplayer cursors, cursor chat, spotlight partial in live sessions: named cursors, chat bubbles that fade, / to chat, spotlight from your avatar's menu with a banner; no audio or reactions

Keyboard shortcuts

One keymap (figcraft_engine::keymap) drives the menus, the canvas, the shortcuts panel, the control channel and MCP key. crates/engine/src/shortcut_parity_tests.rs holds one row per shortcut in the public documentation (the help centre's feature articles: keyboard layouts, text properties, alignment, frames, components, prototypes, plugins, keyboard navigation…), with the macOS and Windows/Linux keys, what does it here and a note in our words, and checks every row on both platforms; rows the documentation is silent on pin today's keys, so every default binding is in the table. crates/ui-egui/src/shortcut_keys_tests.rs drives the keys a lookup can't prove.

Count Notes
Documented shortcuts (rows) 129 each with macOS and Windows/Linux keys
Bound as documented 128 (110 before this suite) 108 keymap bindings, 14 held keys, gestures and presentation keys, 6 vector edit tool keys
Bound on other keys (documented conflict) 1 Run last plugin: the documentation also gives Ctrl+Alt+P to pixel preview on Windows; the plugin takes Ctrl+Alt+Shift+P there
Missing 0 moving the rotation origin (Alt+R, transform.rotationOrigin) and placing an object with Enter after choosing its tool (tool.place) were the last two
Documented keys a platform keeps 2 Ctrl+Space (Windows/Linux keyboard box selection) switches some CJK input methods; F6 goes to a browser's address bar in the web build
Undocumented bindings pinned 48 of which Cmd/Ctrl+W, Cmd/Ctrl+N and Ctrl+Tab are taken by browsers (web build) and Ctrl+Alt+T / Ctrl+Alt+L by some Linux desktops
  • Newly bound: A for the Frame tool, Shift+' for the pixel grid (Cmd+' kept: the articles disagree), Alt+Cmd+\ / Ctrl+Alt+\ for others' cursors (view.multiplayerCursors, new), Ctrl+F6 to the toolbar on Windows/Linux, Shift+Cmd+U to link text (Cmd+K kept), Cmd/Ctrl+] and [ to nest list items while editing (text.listIndent / text.listOutdent, new), Cmd/Ctrl+Backspace to ungroup, Alt+Space / Ctrl+Space for the keyboard box selection (F8 kept) with Cmd/Ctrl+arrows drawing it out, Ctrl+Shift+A / Ctrl+Alt+Shift+A to suggest auto layout, Ctrl+Alt+Cmd+K / Ctrl+Alt+Shift+K to go to the main component, the arrows panning the view when nothing is selected (view.pan, new), Control suspending snapping on macOS, and Space, N, C and F while presenting. The paint bucket's tooltip shows Shift+B (B still works).
  • Where the documentation disagrees with itself (noted per row): pixel grid (Shift+' or Cmd+'), letter spacing (Alt or Cmd with < >; Cmd would be the font size keys, Alt bound), Windows remove fill (Alt+/ or Alt+,; Alt+, is letter spacing), the Layers panel on Windows (Alt+1 or Ctrl+1), send to back / bring to front (one table shows only the bracket).
  • Platform keys: macOS rows use Cmd and Option, Windows/Linux rows Ctrl and Alt (tested: no macOS glyph on Windows/Linux keycaps, no "Ctrl"/"Alt" words on macOS); no default binding uses a chord the system keeps (Cmd+H/M/Q/Tab/Space, Ctrl+Space and the screenshot keys on macOS; Alt+Space/Tab/F4, Ctrl+Esc, Ctrl+Alt+Delete and Linux workspace and terminal-switch keys).
  • Keyboard layouts: keys follow the character typed, named as on a US keyboard. Characters egui has no key for (ü, ж) arrive as the key at that position (egui's fallback); a symbol another layout types with Shift (/ is Shift+7 on a German keyboard) now counts without the Shift. Not done: per-layout tables like the documentation's (a German Shift+' types " and reaches Shift+2).

Accessibility (ours vs Figma's)

Item Status Notes
Screen-reader names, roles, values, states (AccessKit) done on desktop browser: eframe doesn't send the tree yet
Keyboard navigation: F6 regions, Tab within, focus ring done
Layers panel from the keyboard: arrows, F2 / Cmd+R rename (the row gets the keyboard back), Shift+F10 context menu; 10k-layer lists done revealing a layer, expanding, collapsing and arrow keys timed in cargo xtask bench
Reduced motion done system setting or preference
WCAG AA contrast of secondary and accent text done
Tested with VoiceOver, NVDA, Narrator, Orca missing human QA

Revision history

Date Change Summary
2026-10-13 minor Session restore: the windows and tabs open when the app was left open again at the next start: each window's place, size, maximized or full-screen state, screen, panels and tabs in order with the one in front; per tab the file (or your online file, joined again as its owner), its page and view. Written with the preferences as it changes; windows off every screen move onto one; files that are gone get one message; a crash during restoring starts the next run without it and offers it on the home screen; Preferences ▸ Reopen windows and tabs from last time, --fresh, session.restore, pref.restoreSession; window.list reports each window's rectangle and state. Several windows: positions are restored; the screen-reader tree in other windows stays blocked upstream
2026-10-13 minor Home screen: a Templates tab (eight starter templates as cards with thumbnails, search and a kind filter; click or Enter opens a new document) replaces the Community placeholder, the Drafts placeholder is removed, Recents offers four templates while there are no recent files and shows a Getting started card (closable; Help ▸ Getting started brings it back), File ▸ New from template…, and a first run opens on the home screen
2026-10-12 minor Everyday editing partials: number fields (scrub a step a point, ×10 with Shift, ×0.1 with Alt, on past the screen edge where the platform reports it; arrow keys by the nudge preferences, opacity and rotation by 1 and 10; brackets and units in arithmetic; 50% relative outside percentage fields; Tab commits and moves on; an untouched field commits nothing; relative edits and arrow keys on Mixed go to each layer in one undo step) done; outline mode's Include hidden layers and Include object bounds, drawn and clickable, done; Hide when publishing from the Assets panel done (the name's leading .); cursors per tool and modifier done (a table in the engine, drawn rotate, pen, eyedropper and comment cursors, not-allowed on refused edits; guides and handles keep their cursors); resizable panels done (limits, double-click reset, kept per window and in the preferences, the canvas keeps its room in a small window); a file or page made in the dark theme has a #1E1E1E page (the light theme and sessions without an interface: #F5F5F5) and text drawn on a dark page is white; Enter on a text selects all of it (test added). Menu items: View ▸ Outlines ▸ Include hidden layers / Include object bounds, View ▸ Panels ▸ Reset panel widths, Libraries ▸ Hide when publishing
2026-10-12 minor Drag threshold and double-clicks: the second press of a double-click began a move or resize that was never finished, so double-clicking text inside a group often didn't start editing (from the middle of the text) or dragged and resized it when the hand moved a pixel or two; a move or resize now starts only after 3 px of travel on screen and a double-click drops the press's gesture first
2026-10-12 minor Rotation origin and placing with Enter: Alt+R shows a rotation origin handle to drag (snapping to the box's corners, edge middles and centre; double-click resets; Escape hides; kept while the selection lasts, not saved), which the corner handles, the rotation field, Rotate 90°/180° and transform.rotate turn about (transform.rotationOrigin, transform.setRotationOrigin); Enter with a shape or frame tool chosen, on the canvas or the toolbar's tool, places a click-sized one in the middle of the view (tool.place). Documented shortcuts: 128 bound, 0 missing. The keyboard box selection's toast and screen-reader text name Cmd/Ctrl+arrows too; the shortcuts panel cuts a label that doesn't fit before its keycaps with "…" (measured in the font it's drawn in; long labels ran into the keycaps) and shows it in full on hover
2026-10-12 minor Keyboard shortcut parity suite and bindings: a table of the 129 documented shortcuts per platform (126 bound, 1 moved for a documented conflict, 2 missing, 2 kept by a platform) plus 48 pinned undocumented bindings; 16 rows newly bound (see Keyboard shortcuts); Ctrl to suspend snapping on macOS done; keyboard box selection on Alt+Space / Ctrl+Space
2026-10-12 minor Multiplayer cursors, cursor chat and spotlight: missing → partial (live sessions: chat bubbles at the pointer that fade, / to chat, spotlight from your avatar's menu with a banner to stop or follow again)
2026-10-12 minor Layers and Assets panels behaviour suite and fixes: several layers dropped together land together, Collapse layers keeps the selection's rows open, dragging across eyes or padlocks sets several layers in one step, the toggles stay under the pointer, Rename layers dialog for several layers, pages dragged to reorder, dividers, "Copy of" duplicates, Assets folders by page, frame and slash names
2026-10-12 minor Vector multi-edit and the vector edit tail, with a behaviour suite written from the public documentation (5 tests, about 30 table rows and steps, and a junk-parameter sweep of every vector command in multi-edit mode): several vector layers are edited at once (Enter, double-click or vector.edit.begin {ids}; a press on another layer's point, handle or segment makes it the active layer; Shift-click, marquee and lasso select across layers; dragging, the arrows, Delete, delete and heal, mirroring, smoothing, corner radius and point caps and joins reach every layer's selected points in one undo step; the pen, bend, paint bucket, cut and eraser work in the active layer); several Bezier handles are selected with Shift-click and dragged together (vector.edit.moveHandles); a sharp point next to a curved segment rounds (the curve is cut where the arc meets it and keeps its shape); a point can have its own stroke cap and join (vector.edit.strokeCap, vector.edit.strokeJoin, the Point section of the Design panel; canvas, PNG, SVG and PDF, outline stroke); the Pen outside edit mode connects to one of its own points and ends the path, and continues a selected open path from an end point. Left: corner smoothing beyond rectangles, the transform box around points of several layers, per-point caps and joins on dashed, variable-width and brush strokes
2026-10-11 minor Canvas navigation, rulers, guides, layout grids, outline mode and measuring behaviour suite and fixes: the pixel grid shows from 400% (it waited for 800%); guides belong to the page or a top-level frame; a guide can be selected, deleted, nudged and removed from the context menu, Alt-dragged into a copy, and measured from with Alt while dragging; Auto column and row counts; layout grids hidden on rotated frames; outline mode clicks reach layers behind. Outline mode back to partial (two documented options missing)
2026-10-11 minor Shapes and vector behaviour suite and fixes: corner radius and star ratio handles on the canvas, Count and Ratio fields, Alt draws lines from the centre, paint bucket and cut drags, delete and heal along the curve, rounded vector points drawn, Shift-click deselects a point at a box corner, the miter field shows degrees, individual corners only for rectangles and frames
2026-10-11 minor Paint and effects behaviour suite: the blend menu's Normal sets Normal (it set pass-through), a blend menu for each paint in the colour picker, the eyedropper's rules covered by tests
2026-10-11 minor Frames, groups, sections and masks: drawing a frame or section around layers takes them, sections stay out of frames, section resizing leaves contents in place, masked-out areas don't take clicks, a mask group's box follows the mask, X/Y of layers in groups are measured in the frame
2026-10-11 minor Layers panel keyboard: F2 renames (also from a row with the keyboard, which gets it back), Shift+F10 opens the context menu at the focused row or below the canvas selection, F8 draws a selection box the arrows move and size; stroke weights bind to variables side by side
2026-10-11 minor Selection and transform behaviour suite and fixes: Alt shrinks, groups and mixed rotations scale each layer along its own axes, several layers flip together, whole-pixel resizes, small layers move from inside, locked layers stay put, marquees from a top-level frame's background, equal spacing snapping, Cmd/Ctrl ignores constraints while resizing a frame
2026-10-11 minor Gamut warnings: the colour picker flags Display P3 colours outside sRGB; View ▸ Soft-proof sRGB stripes them on the canvas
2026-10-11 minor Several windows: File ▸ New window, Open in new window on a tab, a tab dragged off the strip; each window has its own tabs and panels and asks about unsaved changes when it closes
2026-10-11 minor Canvas fixes: boolean groups clicked where their result is, a layer dragged inside a group stays in it, View ▸ Frame outlines and View ▸ Slices draw
2026-10-11 minor Outline mode done: outlines for the selection (the selected layers draw as outlines, the rest normally) and mask outlines
2026-10-11 minor Design panel arc fields, live boolean editing (operands on the canvas, live results, per-operand operations), shape builder on strokes and open paths, one-sided widths (Alt-drag a width handle)
2026-10-10 major Created from the ROADMAP's look-and-feel and interaction items, the keymap and the canvas code