A boolean operation's box is the first operand's, and never follows what is drawn

Author: danikobeissiCreated Sep 20, 2026Updated Sep 20, 2026

_booleanOperation creates the BOOLEAN_OPERATION node with the first operand's x, y, width and height, and nothing changes that box afterwards. What is drawn, though, comes from the operands: makeBooleanOperationPath combines each visible child's path through their own transforms, and never reads the node's own size.

So the box and the drawing agree only by chance at the moment the operation is made, and part ways as soon as an operand moves or is resized — and they do not agree even then, since a union of two shapes is larger than the first operand alone. Everything that reads the node's box rather than its path reads the wrong thing: get_node's bounds, an auto-layout parent that places the node by its size, hit-testing and selection handles, and an exported SVG's viewport.

What happens

  • At once. Union a 30 by 30 rectangle at (10, 20) with a 20 by 20 one at (60, 70). The node's box is reported as 30 by 30 at (10, 20); what is drawn spans (10, 20) to (80, 90).
  • Afterwards. Move the first operand 100 up and to the left. The drawing follows it; the box does not move at all, and now lies outside the drawing entirely.
  • In an auto-layout frame. The row places the operation by that box, so it overlaps its neighbours or leaves a gap, by however much the box is wrong.

Reproduction, against OpenPencil's own tools

  1. Open a document and draw two rectangles in one frame: 30 by 30 at (10, 20), and 20 by 20 at (60, 70).
  2. Call boolean_union on the two of them, and read the new node with get_node: its box is the first rectangle's, 30 by 30 at (10, 20), while the canvas draws the union of both.
  3. Move the first operand to (-100, -100) with update_node, and read the node again: its box has not changed, though the drawing has moved with the operand.

What was expected

The node's box holds what it draws, and keeps holding it as the operands change — as a group's box does in Figma, and as the editor's own wrapSelectionInContainer does when it makes a group. The union of the visible operands' boxes is the box available without a path engine; it is exact for a union and holds the drawing for the other three operations.

Where

  • packages/core/src/figma-api/index.ts, _booleanOperation, lines 365-388 at e2de247 (x: first.x, y: first.y, width: first.width, height: first.height).
  • What is drawn instead: packages/core/src/canvas/boolean.ts, makeBooleanOperationPath.
  • The tools that reach it: packages/core/src/tools/vector/boolean.tsboolean_union, boolean_subtract, boolean_intersect, boolean_exclude.