Editor has no 'align' or 'distribute' operations for paths — user with 5 paths in a design has to manually drag each to align, no Figma-style 'align left' or 'distribute horizontally' #258

Closed
opened 2026-10-04 03:37:35 +00:00 by Mark · 1 comment
Owner

Finding

grep -rn 'align.*path\|path.*align' src/components/editor/ returns 0. The editor has:

  • Move paths (drag)
  • Duplicate
  • Delete
  • Hide/show
  • Fit to view

No:

  • Align left/right/top/bottom/center
  • Distribute horizontally/vertically
  • Group (per the workspace's ContextMenu)

A user with 5 paths they want aligned to the leftmost edge:

  • Reads the bounding box of the leftmost path
  • Manually drags each of the other 4 to that x coordinate
  • Has to read the x in the right panel ("Path 3: x = 12.5 mm")
  • Drags to match

Figma/Illustrator have:

  • Align Left, Center Horizontal, Right
  • Align Top, Center Vertical, Bottom
  • Distribute Horizontal Spacing, Vertical Spacing
  • Tidy (auto-arrange)

These are bulk geometric operations that take 2+ selected paths and snap them into alignment.

Where

  • Editor's path operations: src/components/editor/EditorRightPanel.tsx (per-row actions)
  • No align: grep -rn 'align' src/components/editor/ returns 0
  • Workspace's ContextMenu has Group/Ungroup but no Align (per the snippet I saw)

Suggested fix shape

Add an "Align" section to the editor's right panel (or to the EditorContextMenu per #191):

{selectedPathIds.length >= 2 && (
  <SectionHeader title="Align" isOpen={openSections.align} onToggle={() => toggleSection('align')} />
  {openSections.align && (
    <div className="grid grid-cols-3 gap-1.5">
      <button onClick={() => onAlign('left')} title="Align left">
        <AlignLeft size={14} />
      </button>
      <button onClick={() => onAlign('center-h')} title="Center horizontally">
        <AlignCenterHorizontal size={14} />
      </button>
      <button onClick={() => onAlign('right')} title="Align right">
        <AlignRight size={14} />
      </button>
      <button onClick={() => onAlign('top')} title="Align top">
        <AlignStartHorizontal size={14} />
      </button>
      <button onClick={() => onAlign('center-v')} title="Center vertically">
        <AlignCenterVertical size={14} />
      </button>
      <button onClick={() => onAlign('bottom')} title="Align bottom">
        <AlignEndHorizontal size={14} />
      </button>
    </div>
  )}
)}

onAlign(direction):

  1. Compute the bounding box of all selected paths.
  2. For each selected path, compute its own bounding box.
  3. Snap the path so its left/right/center matches the union's left/right/center.

The operation is a single history push (per the multi-select pattern from #188).

For distribute: equal spacing between the leftmost/rightmost paths' centers.

Severity

Low. The user can drag manually. Power users with many paths notice.

Discovered by

Gap analysis (2026-10-02) of editor path operations.

  • #188 (open) — Multi-select. Same selection infrastructure; align uses the selection.
  • The workspace's ContextMenu has Group/Ungroup but no Align. The editor and workspace are parallel surfaces.
  • Figma/Illustrator/Sketch all have these. They're standard bulk operations.
## Finding `grep -rn 'align.*path\|path.*align' src/components/editor/` returns 0. The editor has: - Move paths (drag) - Duplicate - Delete - Hide/show - Fit to view No: - Align left/right/top/bottom/center - Distribute horizontally/vertically - Group (per the workspace's `ContextMenu`) A user with 5 paths they want aligned to the leftmost edge: - Reads the bounding box of the leftmost path - Manually drags each of the other 4 to that x coordinate - Has to read the x in the right panel ("Path 3: x = 12.5 mm") - Drags to match Figma/Illustrator have: - Align Left, Center Horizontal, Right - Align Top, Center Vertical, Bottom - Distribute Horizontal Spacing, Vertical Spacing - Tidy (auto-arrange) These are bulk geometric operations that take 2+ selected paths and snap them into alignment. ## Where - Editor's path operations: `src/components/editor/EditorRightPanel.tsx` (per-row actions) - No align: `grep -rn 'align' src/components/editor/` returns 0 - Workspace's `ContextMenu` has Group/Ungroup but no Align (per the snippet I saw) ## Suggested fix shape Add an "Align" section to the editor's right panel (or to the EditorContextMenu per #191): ```tsx {selectedPathIds.length >= 2 && ( <SectionHeader title="Align" isOpen={openSections.align} onToggle={() => toggleSection('align')} /> {openSections.align && ( <div className="grid grid-cols-3 gap-1.5"> <button onClick={() => onAlign('left')} title="Align left"> <AlignLeft size={14} /> </button> <button onClick={() => onAlign('center-h')} title="Center horizontally"> <AlignCenterHorizontal size={14} /> </button> <button onClick={() => onAlign('right')} title="Align right"> <AlignRight size={14} /> </button> <button onClick={() => onAlign('top')} title="Align top"> <AlignStartHorizontal size={14} /> </button> <button onClick={() => onAlign('center-v')} title="Center vertically"> <AlignCenterVertical size={14} /> </button> <button onClick={() => onAlign('bottom')} title="Align bottom"> <AlignEndHorizontal size={14} /> </button> </div> )} )} ``` `onAlign(direction)`: 1. Compute the bounding box of all selected paths. 2. For each selected path, compute its own bounding box. 3. Snap the path so its left/right/center matches the union's left/right/center. The operation is a single history push (per the multi-select pattern from #188). For distribute: equal spacing between the leftmost/rightmost paths' centers. ## Severity Low. The user can drag manually. Power users with many paths notice. ## Discovered by Gap analysis (2026-10-02) of editor path operations. ## Related - #188 (open) — Multi-select. Same selection infrastructure; align uses the selection. - The workspace's `ContextMenu` has Group/Ungroup but no Align. The editor and workspace are parallel surfaces. - Figma/Illustrator/Sketch all have these. They're standard bulk operations.
Mark closed this issue 2026-10-04 11:05:47 +00:00
Author
Owner

Shipped fix(#258) at 324eb2f (push 499db84..324eb2f).

Editor Path Properties now has an Align & Distribute section between Transform and Direction & Closure.

  • 6 align ops (left / centerH / right / top / centerV / bottom) snap selected paths to a shared edge or center.
  • 2 distribute ops (horizontal / vertical) space 3+ paths evenly between the extremal pair.
  • Underlay nodes follow the same delta so outlined underlays stay aligned with their visible path.
  • Multi-select fan-out matches #188 / #205 / #209: one setPaths + one history push per click.
  • Buttons disabled when <2 paths selected (align) or <3 paths selected (distribute), matching the no-op the Editor would produce.
  • 18 new geometry tests + 10 new panel tests; 1361 total pass, lint clean.

Replaces the manual-drag-5-paths workflow with a one-click geometric op.

Shipped fix(#258) at 324eb2f (push 499db84..324eb2f). Editor Path Properties now has an Align & Distribute section between Transform and Direction & Closure. - 6 align ops (left / centerH / right / top / centerV / bottom) snap selected paths to a shared edge or center. - 2 distribute ops (horizontal / vertical) space 3+ paths evenly between the extremal pair. - Underlay nodes follow the same delta so outlined underlays stay aligned with their visible path. - Multi-select fan-out matches #188 / #205 / #209: one setPaths + one history push per click. - Buttons disabled when <2 paths selected (align) or <3 paths selected (distribute), matching the no-op the Editor would produce. - 18 new geometry tests + 10 new panel tests; 1361 total pass, lint clean. Replaces the manual-drag-5-paths workflow with a one-click geometric op.
Sign in to join this conversation.
No description provided.