zudo-panel-designer docs
GitHub repository

Type to search...

to open search from anywhere

Align & Distribute

The Align panel's 6 align + 2 distribute operations and the selection|panel reference toggle.

The sidebar's Align & Distribute panel (components/align-panel.tsx, between Layers and Properties — see Interface → Right sidebar) aligns or evenly spaces the current multi-selection. The math lives in align-ops.ts, shared as-is by both the panel's buttons and the command palette's Align commands — pressing a button and running the equivalent command are one code path, not two kept in sync by hand.

Align and distribute

Six align buttons (left / center-horizontal / right / top / middle-vertical / bottom) and two distribute buttons (horizontal / vertical) — each an icon button with a hover tooltip naming the operation (e.g. "Align Left", "Distribute Horizontally"). Distribute spaces the eligible layers evenly along the chosen axis, using each layer's own bounding box, not just its center.

Align to: Selection vs Panel

A select below the buttons — labeled Align to — toggles the reference every align/distribute click uses, defaulting to Selection:

  • Selection — aligns/distributes layers relative to their own combined bounding box.

  • Panel — aligns/distributes each layer relative to the panel's own rect (0,0 to panelWidthMm × panelHeightMm), letting a single layer be centered or edge-aligned on the panel.

The minimum eligible-layer count differs by reference, because a Selection-referenced align/distribute needs something within the selection to align against:

OperationSelection referencePanel reference
Align2+ layers1+ layer
Distribute3+ layers (2 layers have no interior gap)1+ layer

Both button groups disable themselves (and every icon button dims) once the current selection drops below the required count for the active reference.

Eligibility

Align/distribute targets are computed the same way the Select tool's layer eligibility already excludes patterns from group operations:

  • Pattern layers are excluded — a pattern layer is a movable x/y/size square (see Tools → Select → Pattern squares), but its cover-default placement would dominate the combined bounds and yank real content toward it, the same reasoning as the marquee/Select-All exclusions elsewhere. It doesn't participate and doesn't count toward the minimum; move/size it via drag, nudge, or the inspector instead.

  • A path layer with no real geometry (no points, and no non-empty extraSubpaths) is excluded too — core's path-bbox math still returns some rect for an empty path (a 0×0 rect at the origin), and counting that as a real target would silently pull the combined bounding box toward (0, 0).

  • Rotated shapes align/distribute by their axis-aligned bounding box (rotatedRectAABB) — the same rotation-aware bbox the renderer and the Select tool's multi-selection chrome use, so what you see selected is exactly what the operation measures against.

  • A path layer's points (and bezier handles) translate as a unit via translatePathLayer; every other layer type moves by patching x/y.

History

Each align/distribute click is one undo entry — or, if the layers are already aligned/distributed (every computed delta is zero), no commit at all. Committing an identical document would still discard the redo stack for zero visual change, so a genuine no-op is skipped entirely rather than writing a phantom history entry.

Also reachable from the command palette

Align and distribute have no keyboard shortcut of their own — they're deliberately chordless, palette-only commands (category Align), reachable via the command palette (Align Left, Align Center (Horizontal), Align Right, Align Top, Align Middle (Vertical), Align Bottom, Distribute Horizontally, Distribute Vertically). A palette-triggered align always uses the Selection reference — the same default the panel starts on — since a palette command has no visible reference toggle of its own to read from.