openpencil/packages/docs/user-guide/drawing-shapes.md
Danila Poyarkov b0e0b321e9
fix: share Figma's creation and grouping between editor and plugin API (#919)
* fix(core): start new layers with Figma's defaults in the editor and plugin API

The plugin API created bare nodes: frames, components, and shapes without fills, and lines and vectors without strokes, so scripts written for Figma drew nothing. Drawn lines also had a black fill instead of a stroke and were invisible. Both paths now share newLayerDefaults, recorded from Figma desktop 126: frames and components white with frames clipping their content, shapes #D9D9D9, lines and vectors a black 1 px stroke, text black. A stroke a script adds gets the 1 px default weight, and an empty vector has no render bounds.

* fix(core): combine variants as Figma does from the canvas and from scripts

The plugin API and the editor command each built component sets their own way, both with 40 px of padding and a grey fill. Figma's command pads the variants by 20 and outlines the set with a 1 px dashed #8A38F5 stroke; its plugin API wraps them exactly with no fill or stroke. One variantSetProps now places and styles the set for both, with a canvas or script style, and applyVariantProperties derives variant properties for both.

* fix(core): report group children in their container's space in the plugin API

Figma's plugin API places children of groups and booleans relative to the nearest real container and refits a group whenever a script changes one of its children. Ours reported group-relative positions and never refit, so scripts placing layers inside groups landed them in the wrong place. x, y, and relativeTransform now map through the groups around a node, and geometry changes, appendChild, insertChild, and remove refit the surrounding groups. The refit moves to Scene Graph as fitEnclosingGroups, shared by the canvas (with undo) and the plugin API.

* test(core): pass script-style strokes and typed components in parity tests

* test(e2e): expect Figma's default shape grey in the scene freshness spec

* fix(vue): draw lines by length and angle as Figma does

The Line tool sized a line as the box spanned by the drag. With the stroke a new line now gets, that box drew as a rectangle outline. A line now starts at the press point with the drag length as its width, no height, and the drag angle as its rotation, as Figma's Line tool makes it; Shift snaps the angle to 45° steps, as the docs already described, and a click makes a 100 px horizontal line.

* fix(core): give each new layer its own copy of the default paints

The defaults spread each paint shallowly, so every layer shared the colour object of the module-level default and editing one layer's colour in place changed the next new layer. Copy the paints with the Scene Graph copy helpers.

* fix(core): group, ungroup, and combine layers through shared code in the plugin API

The plugin API wrapped layers, ungrouped, made booleans, and made components from layers with its own code. Ungroup moved the children to the top of the stack, booleans were named "Boolean union", and a component made from a frame cloned its children under new ids. These now run through the editor's shared wrap, ungroup, and boolean functions, with the placement and defaults recorded in Figma desktop 126: a group or boolean without an index goes on top, ungrouped children take the group's place, booleans are named after the operation and filled with the default grey, a frame becomes a component in its place with its children, and any other layer is wrapped in a white component named after it. Undoing a wrap in the editor now returns each layer to its own place in the stack.

* fix(core): group, frame, combine, and make components from the canvas as Figma does

Recorded in Figma desktop 126: a container made from the canvas takes the topmost selected layer's place, Frame selection adds no fill and does not clip, a component wrapped around layers is white and takes a single layer's name, and a boolean is filled like its topmost operand, or its base for Subtract, without strokes. The canvas commands and the plugin API now share the wrap parent check, stack ordering, component rules, and boolean paints, and the plugin API's createComponentFromNode converts groups in place as Figma does. Undoing a boolean returns each operand to its own place in the stack.

* refactor(core): reuse translate when centering pasted layers
2026-10-06 12:28:52 +00:00

4.4 KiB

title description
Drawing Shapes Creating rectangles, ellipses, lines, frames, sections, polygons, and stars in OpenPencil.

Drawing Shapes

The bottom toolbar provides tools for creating shapes, frames, and sections. Select a tool, then click and drag on the canvas to draw.

Toolbar Tools

Tool Shortcut Description
Rectangle R Draws a rectangle
Ellipse O Draws an ellipse
Line L Draws a line
Frame F Draws a frame (container for other nodes)
Section S Draws a section (takes in the siblings it fully covers)

Shapes Flyout

The shapes flyout (accessible from the toolbar) includes additional shapes:

  • Polygon — creates a polygon with 3 sides by default (triangle)
  • Star — creates a 5-pointed star with 0.38 inner radius

Polygon and Star have no keyboard shortcut — access them from the shapes flyout in the toolbar.

Constrained Drawing

Hold Shift while dragging to constrain the shape:

  • Rectangle → square (equal width and height)
  • Ellipse → circle
  • Line → snaps to 0°/45°/90° angles

Shape Properties

After drawing a shape, select it to edit its properties in the Design tab of the properties panel.

Fill

Every shape can have a fill. The fill section supports:

  • Solid color — pick via the HSV color picker or type a hex value
  • Gradient — Linear, Radial, Angular, or Diamond with editable gradient stops
  • Image — select an image file as the fill

Stroke

Add an outline to any shape. Stroke properties include:

  • Width — uniform or per-side (Top/Right/Bottom/Left) via the side selector dropdown
  • Color — solid color with opacity
  • Alignment — Inside, Center, or Outside the shape boundary (clip-based rendering matches Figma behavior)
  • Cap style — None, Round, Square, Arrow Lines, Arrow Equilateral (for open paths)
  • Join style — Miter, Bevel, Round
  • Dash pattern — dash-on/dash-off

Corner Radius

Available for rectangles, frames, components, and instances. Click the independent corners toggle to set each corner (top-left, top-right, bottom-left, bottom-right) separately.

Effects

Add visual effects from the Effects section:

  • Drop Shadow — offset, blur radius, spread, color
  • Inner Shadow — same controls, rendered inside the shape
  • Layer Blur — blurs the entire node
  • Background Blur — blurs content behind the node
  • Foreground Blur — blurs content in front

Click + to add an effect. Each effect row is collapsible with inline controls. Toggle the eye icon to enable/disable an effect.

Frames and Sections

Frames are containers. Drag shapes into a frame to make them children, or start drawing inside one: a new shape goes into the frame under the point where you start, except locked frames, and joins the end of an auto-layout flow. Drawing a frame over existing nodes puts the unlocked ones it fully covers inside it. New frames clip their content, as in Figma (turn off Clip content to let children show outside), and frames support auto layout.

Select the Frame tool to browse collapsible presets for phones, tablets, desktops, presentations, watches, paper, social media, Figma Community assets, and archived devices in the Design panel. Choosing a preset creates a named frame centered in the viewport and returns to the Select tool. With an existing frame selected, use its Frame preset dropdown to resize it without changing its name.

Sections are top-level containers that take in the sibling nodes they fully cover when drawn, moved, or resized. They're useful for organizing large canvases into logical areas. Sections display a title pill that you can drag.

Keyboard Shortcuts

Action Mac Windows / Linux
Rectangle tool R R
Ellipse tool O O
Line tool L L
Frame tool F F
Section tool S S
Constrain to square/circle Shift + drag Shift + drag

Tips

  • Sections can only exist at the top level — they can't be nested inside frames.
  • Use frames with auto layout to build responsive layouts.
  • Export individual shapes or groups as images via the properties panel or context menu.