Editor has no 'offset' or 'outline' operation on a path — user wanting to create a thicker outline or an inner cutout has to manually duplicate and move the path, no automatic offset #280

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

Finding

grep -rn 'offsetPath\|outlinePath' src/components/editor/ returns 0. The editor has no path offset.

A user with a circular path wanting a thicker ring (e.g., 2mm thick embroidery) wants to:

  • Create an inner circle and an outer circle
  • The two circles form a ring
  • Manually: duplicate the path, scale the duplicate by some amount, manually position

The editor's "scale" tool (per applyPathTransform in geometry.ts) doesn't do per-direction offset. The user can't create a true offset path.

Standard "Offset Path" / "Outline Path" operations in Illustrator:

  • Create a new path at a specified distance from the original (inside or outside)
  • Use the offset to create borders, cutouts, inlays

Where

  • Editor's path operations: src/components/editor/EditorRightPanel.tsx (per-row actions)
  • No offset: grep -rn 'offset' src/components/editor/ returns 0

Suggested fix shape

  1. Algorithm: implement a path offset (perpendicular offset of each node by N mm). For a circle, this is straightforward (a larger/smaller concentric circle). For an arbitrary polyline, the implementation is more complex (corner-handling for offsets at sharp angles).

  2. UI: add an "Offset" button to the Path Properties section:

<button
  onClick={onOffset}
  data-testid="offset-path"
  title="Create an offset path at a specified distance"
>
  <MoveDiagonal2 size={14} /> Offset...
</button>
  1. Modal: a small modal asking for the offset distance (in mm) and direction (inside / outside / both).

  2. History: single undoable action.

  3. Output: creates a new path with the offset geometry. The original is preserved.

Severity

Low. The user can manually duplicate and scale. Power users with production embroidery notice.

Discovered by

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

  • The path operations family: split, merge, mirror, rotate, reverse, close, duplicate, simplify, offset.
  • The auto-digitize flow may produce paths that need a "border" (e.g., the perimeter of a shape filled with stitches).
  • Illustrator's "Offset Path" is the standard reference; it's a key tool for embroidery digitizing.
## Finding `grep -rn 'offsetPath\|outlinePath' src/components/editor/` returns 0. The editor has no path offset. A user with a circular path wanting a thicker ring (e.g., 2mm thick embroidery) wants to: - Create an inner circle and an outer circle - The two circles form a ring - Manually: duplicate the path, scale the duplicate by some amount, manually position The editor's "scale" tool (per `applyPathTransform` in `geometry.ts`) doesn't do per-direction offset. The user can't create a true offset path. Standard "Offset Path" / "Outline Path" operations in Illustrator: - Create a new path at a specified distance from the original (inside or outside) - Use the offset to create borders, cutouts, inlays ## Where - Editor's path operations: `src/components/editor/EditorRightPanel.tsx` (per-row actions) - No offset: `grep -rn 'offset' src/components/editor/` returns 0 ## Suggested fix shape 1. **Algorithm**: implement a path offset (perpendicular offset of each node by N mm). For a circle, this is straightforward (a larger/smaller concentric circle). For an arbitrary polyline, the implementation is more complex (corner-handling for offsets at sharp angles). 2. **UI**: add an "Offset" button to the Path Properties section: ```tsx <button onClick={onOffset} data-testid="offset-path" title="Create an offset path at a specified distance" > <MoveDiagonal2 size={14} /> Offset... </button> ``` 3. **Modal**: a small modal asking for the offset distance (in mm) and direction (inside / outside / both). 4. **History**: single undoable action. 5. **Output**: creates a new path with the offset geometry. The original is preserved. ## Severity Low. The user can manually duplicate and scale. Power users with production embroidery notice. ## Discovered by Gap analysis (2026-10-02) of editor path operations. ## Related - The path operations family: split, merge, mirror, rotate, reverse, close, duplicate, simplify, offset. - The auto-digitize flow may produce paths that need a "border" (e.g., the perimeter of a shape filled with stitches). - Illustrator's "Offset Path" is the standard reference; it's a key tool for embroidery digitizing.
Author
Owner

Shipped at 6ce5b74 on origin/main.

The right panel's Path Properties section now has an Offset Path subsection (below the existing Simplify subsection) with:

  • a distance input (mm, default 2mm — typical embroidery border width)
  • an Outside / Inside side selector
  • an Apply button that creates a new sibling path at the chosen distance; the original is preserved

Implementation notes:

  • The algorithm (geometry.offsetPath) is a standard polyline offset — for each anchor, average the right-hand perpendiculars of the two incident segments and translate by distance * normal * sign. Endpoints of an open polyline get a single perpendicular. Bezier handles translate with their anchors.
  • The Editor's handler (handleOffsetSelectedPath) inserts the new path next to its source, remaps anchor ids to the per-path-id-prefixed convention so a later rename / delete of the source can't collide with the offset copy's anchors, bumps the sequence of every later path so the copy doesn't collide with an existing sequence slot (same convention as the duplicate handler), and promotes selection to the offset copy so the user can immediately drag, color, or further-offset. Undoable via the standard pushHistory snapshot.
  • Side sign convention is right-hand-rule per segment — the user picks the side. For a typical ring traced clockwise in screen coords (y-down), 'outside' grows the ring; CCW-wound rings grow inward. Same UX as Illustrator's dialog.
  • 6 new geometry tests pin the offset math (empty input, zero distance, open + closed paths, side sign convention, bezier handle translation, placeholder id remap, square corner bisectors).
  • 12 panel tests pin the UI contract (gate, defaults, apply forward, side toggle, input disabled states).
  • 6 Editor wiring tests pin setPaths + pushHistory + selection promote + id namespace.
Shipped at 6ce5b74 on origin/main. The right panel's Path Properties section now has an Offset Path subsection (below the existing Simplify subsection) with: - a distance input (mm, default 2mm — typical embroidery border width) - an Outside / Inside side selector - an Apply button that creates a new sibling path at the chosen distance; the original is preserved Implementation notes: - The algorithm (geometry.offsetPath) is a standard polyline offset — for each anchor, average the right-hand perpendiculars of the two incident segments and translate by distance * normal * sign. Endpoints of an open polyline get a single perpendicular. Bezier handles translate with their anchors. - The Editor's handler (handleOffsetSelectedPath) inserts the new path next to its source, remaps anchor ids to the per-path-id-prefixed convention so a later rename / delete of the source can't collide with the offset copy's anchors, bumps the sequence of every later path so the copy doesn't collide with an existing sequence slot (same convention as the duplicate handler), and promotes selection to the offset copy so the user can immediately drag, color, or further-offset. Undoable via the standard pushHistory snapshot. - Side sign convention is right-hand-rule per segment — the user picks the side. For a typical ring traced clockwise in screen coords (y-down), 'outside' grows the ring; CCW-wound rings grow inward. Same UX as Illustrator's dialog. - 6 new geometry tests pin the offset math (empty input, zero distance, open + closed paths, side sign convention, bezier handle translation, placeholder id remap, square corner bisectors). - 12 panel tests pin the UI contract (gate, defaults, apply forward, side toggle, input disabled states). - 6 Editor wiring tests pin setPaths + pushHistory + selection promote + id namespace.
Mark closed this issue 2026-10-04 15:16:43 +00:00
Sign in to join this conversation.
No description provided.