Skip to content

feat: support shape changes on existing nodes (set_shape op) #1

Description

@hugolytics

Observed

Changing the shape: of an existing node via canvas_write_d2 is a no-op — the diff engine returns ops_applied: 0, warnings: [] and the node's Figma shapeType is unchanged.

Repro

  1. Create a node with shape: diamond (e.g. "C2F indexing" { shape: diamond }).
  2. Call canvas_write_d2 with the same full D2, only changing shape: diamond → shape: rounded_rectangle.
  3. Result: ops_applied: 0. Canvas unchanged.

Expected

Shape property changes on existing shape_with_text nodes should be applied — either:

  • emitted by the D2 diff engine as a set_shape op, or
  • exposed as an explicit apply_patch op.

Root cause

  • bridge/d2-diff.js doesn't treat shape: differences on existing nodes as a diff (only create/delete/rename/reparent/edge changes are emitted).
  • plugin/code.js sets shape.shapeType only at node creation (lines ~521, ~1163, ~1395). No handler exists for a post-creation shape mutation.
  • SHAPE_MAP already exists in bridge/d2-vocabulary.js — the D2 keyword ↔ Figma shapeType mapping is in place.

Feasibility

Figma plugin API allows mutating shape.shapeType on an existing ShapeWithTextNode, so this is a pure bridge/plugin-side change. No roundtrip or geometry implications (post-processor can reroute edges if shape bounds shift via canvas_relayout).

Proposed implementation

  1. apply_patch op:
    { type: 'set_shape', node_id, after: 'ROUNDED_RECTANGLE' }
    
    Handler in plugin's ops.forEach that guards node.type === 'SHAPE_WITH_TEXT' and sets node.shapeType = op.after.
  2. d2-diff.js: when an existing node's D2 shape: keyword differs from its current shapeType, emit a set_shape op (map via SHAPE_MAP).
  3. Validator: reject set_shape on non-shape_with_text nodes (SECTION, CONNECTOR, etc.).

Workaround today

Delete the node (omit from target_d2) → re-add with the new shape in a second write. Loses position; must follow with canvas_relayout. Or change the shape manually in FigJam.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions