* fix: select top-level auto layout frames by their empty area Checked against Figma desktop 126 with real pointer input. The gaps and padding of a top-level frame with auto layout (any direction or grid, filled or not, on the page or in a section) select, highlight, and drag the frame, while clicks on its layers still select those layers. A plain top-level frame's empty area stays background, as #900 recorded; its oracle scenarios only used frames without auto layout. Auto layout frames are hit by their bounds even without a fill, and a press on such a frame's empty area no longer starts a marquee. * feat(canvas): outline auto layout children with dotted lines, as in Figma Hovering a horizontal or vertical auto layout frame outlines its visible direct children, and a single selected layer dots the border of its auto layout parent, in the container's outline color. Grid and plain frames, grandchildren, and multi-selections show none. Line weight and dash were measured from Figma 126 screenshots: 1 px with 1.75 px dashes and 1.25 px gaps in screen space. The editor gains a transforming flag that canvas input sets while layers move, resize, or rotate; the outlines and the padding and gap markers of a selected auto layout frame hide while it is set, as Figma's do. The children outline a selected auto layout frame drew under the pointer now uses the same stroke, and the dash effect is freed after each draw. * fix(canvas): select unfilled frames by their empty area only on a click Live Figma 126, with real pointer input on a top-level card holding an unfilled auto layout row and an unfilled plain frame, with and without auto layout on the card: a click on either frame's empty area selects that frame, while a ⌘-click looks through it to the card. Only top-level auto layout frames now own their empty area in hit testing, so a deep hit no longer stops at a nested unfilled auto layout frame. A click that ends on an open container selects the frame child under the point by its bounds, filled or not, which plain frames did not get before; boards that open by themselves keep their empty area as background. * fix(canvas): select an empty unfilled frame on the page by its bounds Live Figma 126: a click inside an empty frame without a fill selects it, on the page and in a section. The section case already did after the previous commit; on the page the click found nothing, since an unfilled frame without children is not hit. A click that hits nothing now looks for a frame under the point among the scope's children, which skips boards that hold layers, as their empty area stays background. * refactor(scene-graph): read the containers the selection opens in their own helper * fix(canvas): open a selected container, so repeated clicks reach deeper layers In Figma, clicking again at the same point inside a selected frame, component, or instance selects the layer under the pointer, so repeated clicks walk down to a text in a nested component such as shadcn's calendar. The click hit test opened only the ancestors of the selection, so a selected nested container stopped the walk at itself and only a double-click went deeper. A selected container with layers now opens like its ancestors; groups and booleans stay closed, as in Figma. Pressing inside the selection still drags it, and its empty area keeps it selected.
5.6 KiB
| title | description |
|---|---|
| Selection & Manipulation | Selecting, moving, resizing, rotating, duplicating, and organizing nodes in OpenPencil. |
Selection & Manipulation
Select objects to move, resize, rotate, duplicate, and organize them on the canvas.
Selecting
- Click a node to select it (deselects everything else). As in Figma, a click inside a top-level frame selects that frame's direct child, such as a nested frame or a group, rather than the deepest layer; click a top-level frame by its title, anywhere when it is empty, or by its gaps and padding when it has auto layout
- Hover an auto layout frame to see its direct children outlined with dotted lines; while a single layer is selected, the border of its auto layout parent is dotted
- Double-click to go one level deeper, or click again inside a selected frame, component, or instance; once a layer is selected, clicks reach its siblings and cousins directly
- ⌘ + click (Ctrl + click on Windows and Linux) selects the deepest layer under the cursor
- Shift + click to add or remove a node from the current selection
- Marquee drag — drag on empty canvas to draw a selection rectangle; intersecting nodes are selected on release. Started inside a top-level frame without auto layout or a section, it selects that container's layers; from the page, a frame or section that holds layers is selected only when fully enclosed
- ⌘A — select all nodes on the current page
- Click empty canvas — deselect all
Moving
- Drag a selected node to move it (all selected nodes move together)
- Arrow keys — nudge selected nodes by 1 px
- Shift + arrow keys — nudge by 10 px
Resizing
Selected nodes show 8 resize handles (4 corners + 4 edge midpoints). Drag any handle to resize.
- Shift + drag a corner handle to constrain proportions
Moving into and out of frames
A dragged node lands in the frame under the cursor when you release it, however little of it is inside, and leaves its frame as soon as the cursor does. Groups and locked frames never take dropped nodes, and a component set takes back only its own variants; a node inside a group stays in it unless you drop it on a different frame, and the group resizes to fit what it holds. A group whose last node leaves is removed. Pressing inside a selected frame, group, or component set drags it rather than the node under the cursor.
- Shift + drag — lock the move to one axis
- Hold Space while dragging — keep the nodes in their current parents
- ⌃ + drag (Ctrl + drag on Windows and Linux) — turn off snapping; dropped into an auto-layout frame, the node is positioned absolutely
Locked nodes in a selection stay where they are when the rest of it moves.
Rotating
Hover just outside a corner handle to see the rotation cursor. Drag to rotate.
- Shift + drag snaps rotation to 15° increments
Duplicating
- Alt + drag (⌥ + drag on Mac) — duplicate the selected node and move the copy
- ⌘D — duplicate in place; a lone top-level frame's copy, on the page or in a section, goes into the first free space to its right
Duplicates keep their names. Duplicating a main component this way creates an instance of it.
Pasting
⌘V keeps the copied position. Pasted into a selected frame, nodes keep their offset from the frame they were copied from, and are centered along any axis where they don't fit; nodes that would land out of view are centered in it. Use Paste here in the context menu to paste at the cursor.
Deleting
Press Backspace or Delete to remove all selected nodes.
Z-Order
Change the stacking order of nodes within their parent:
- ] — bring to front (top of sibling list)
- [ — send to back (bottom of sibling list)
Visibility & Lock
- ⇧⌘H — toggle visibility. Hidden nodes don't render but stay in the layers panel.
- ⇧⌘L — toggle lock. Locked nodes can't be selected or moved on canvas.
Move to Page
Move selected nodes to a different page via the context menu. The nodes are reparented under the target page's canvas.
Sections
A section takes in the sibling nodes it fully covers when you draw it, move it, or resize it over them.
Keyboard Shortcuts
| Action | Mac | Windows / Linux |
|---|---|---|
| Select all | ⌘A | Ctrl + A |
| Duplicate | ⌘D | Ctrl + D |
| Duplicate + move | ⌥ + drag | Alt + drag |
| Move along one axis | ⇧ + drag | Shift + drag |
| Keep current parent | Space while dragging | Space while dragging |
| Move without snapping | ⌃ + drag | Ctrl + drag |
| Delete | ⌫ / Delete | Backspace / Delete |
| Nudge 1 px | Arrow keys | Arrow keys |
| Nudge 10 px | ⇧ + Arrow keys | Shift + Arrow keys |
| Bring to front | ] | ] |
| Send to back | [ | [ |
| Toggle visibility | ⇧⌘H | Shift + Ctrl + H |
| Toggle lock | ⇧⌘L | Shift + Ctrl + L |
Tips
- Use the Layers & Pages panel to see and reorder nodes when they overlap.
- See Context Menu for additional actions like grouping and component creation.