Editor has no hoop-size mismatch warning — user designing a path that extends beyond the 4x4 hoop (or whatever's set) gets no warning until they try to export and the service rejects it #260

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

Finding

grep -rn 'hoopSize.*warn\|warn.*hoop' src/ returns 0 hits. The editor renders paths on a virtual hoop (per MM_TO_PX etc.), but if a path's bounding box exceeds the hoop's dimensions, there's no visible warning.

src/components/editor/canvasRenderer.ts likely renders the hoop rectangle (per the MM_TO_PX constant and the rendering logic), but doesn't check if paths are inside.

A user who:

  • Sets hoop to 4x4
  • Draws a path that extends from (0,0) to (200, 200) — but the 4x4 hoop is only 100x100 mm
  • The path renders off the hoop
  • The user thinks "well, it's not visible because of the camera zoom"
  • Tries to export
  • The service might fail with "object count exceeds hoop" or similar
  • The user gets a generic error

The polish move is to show a visual warning (a red dashed line outside the hoop, or a yellow border on the offending path) when paths exceed the hoop.

Where

  • Editor canvas: src/components/editor/EditorCanvas.tsx (no hoop-bounds check)
  • No warning: grep -rn 'hoop.*exceeds' src/ returns 0
  • The export: src/lib/easystitch-client.ts:exportPES (might validate, let me check)

Suggested fix shape

  1. Compute the union bounding box of all visible paths:
const pathsBoundingBox = paths
  .filter((p) => p.visible)
  .reduce((bbox, p) => unionBoundingBox(bbox, pathBoundingBox(p.nodes)), null);
  1. Compare to the hoop size (the active machine profile's max hoop):
const hoop = getHoopSizeMm(machineProfile);
const exceedsHoop = pathsBoundingBox && (
  pathsBoundingBox.width > hoop.width ||
  pathsBoundingBox.height > hoop.height
);
  1. Visual warning:
{exceedsHoop && (
  <div className="absolute top-2 right-2 px-3 py-1.5 rounded-lg" style={{ backgroundColor: '#FEF3C7' }}>
    <AlertTriangle size={12} />
    Some paths extend beyond the {hoop.width}×{hoop.height}mm hoop
  </div>
)}
  1. Per-path indicator: render paths that exceed the hoop with a red dashed outline.

  2. Export guard: the export service already validates (per #103); the in-editor warning surfaces the issue earlier.

Severity

Medium. The user finds out at export time, not design time. Power users notice.

Discovered by

Gap analysis (2026-10-02) of editor validation.

  • #103 (closed) — Inline error in export. The downstream validation; the editor's warning is upstream.
  • The hoop size selector (in the workspace's Design Settings) and the editor's path rendering are parallel surfaces.
  • The "MACHINE PROFILE" hint in the workspace's right panel shows {machineDef.maxHoopMm.w}×{machineDef.maxHoopMm.h}mm — the editor's warning mirrors that.
## Finding `grep -rn 'hoopSize.*warn\|warn.*hoop' src/` returns 0 hits. The editor renders paths on a virtual hoop (per `MM_TO_PX` etc.), but if a path's bounding box exceeds the hoop's dimensions, there's no visible warning. `src/components/editor/canvasRenderer.ts` likely renders the hoop rectangle (per the `MM_TO_PX` constant and the rendering logic), but doesn't check if paths are inside. A user who: - Sets hoop to 4x4 - Draws a path that extends from (0,0) to (200, 200) — but the 4x4 hoop is only 100x100 mm - The path renders off the hoop - The user thinks "well, it's not visible because of the camera zoom" - Tries to export - The service might fail with "object count exceeds hoop" or similar - The user gets a generic error The polish move is to show a visual warning (a red dashed line outside the hoop, or a yellow border on the offending path) when paths exceed the hoop. ## Where - Editor canvas: `src/components/editor/EditorCanvas.tsx` (no hoop-bounds check) - No warning: `grep -rn 'hoop.*exceeds' src/` returns 0 - The export: `src/lib/easystitch-client.ts:exportPES` (might validate, let me check) ## Suggested fix shape 1. **Compute the union bounding box of all visible paths**: ```ts const pathsBoundingBox = paths .filter((p) => p.visible) .reduce((bbox, p) => unionBoundingBox(bbox, pathBoundingBox(p.nodes)), null); ``` 2. **Compare to the hoop size** (the active machine profile's max hoop): ```ts const hoop = getHoopSizeMm(machineProfile); const exceedsHoop = pathsBoundingBox && ( pathsBoundingBox.width > hoop.width || pathsBoundingBox.height > hoop.height ); ``` 3. **Visual warning**: ```tsx {exceedsHoop && ( <div className="absolute top-2 right-2 px-3 py-1.5 rounded-lg" style={{ backgroundColor: '#FEF3C7' }}> <AlertTriangle size={12} /> Some paths extend beyond the {hoop.width}×{hoop.height}mm hoop </div> )} ``` 4. **Per-path indicator**: render paths that exceed the hoop with a red dashed outline. 5. **Export guard**: the export service already validates (per #103); the in-editor warning surfaces the issue earlier. ## Severity Medium. The user finds out at export time, not design time. Power users notice. ## Discovered by Gap analysis (2026-10-02) of editor validation. ## Related - #103 (closed) — Inline error in export. The downstream validation; the editor's warning is upstream. - The hoop size selector (in the workspace's Design Settings) and the editor's path rendering are parallel surfaces. - The "MACHINE PROFILE" hint in the workspace's right panel shows `{machineDef.maxHoopMm.w}×{machineDef.maxHoopMm.h}mm` — the editor's warning mirrors that.
Author
Owner

Shipped fix at a91226f (push 324eb2f..a91226f).

Two pieces:

  1. Hoop outline — pages/Editor.tsx now plumbs the user-selected hoop (designHoopSize) into EditorCanvas as a new optional hoopSize prop. When present, the canvas renders a labeled dashed rectangle showing where the selected hoop (4x4 / 5x7 / 6x10 / 8x12) sits inside the larger 400x400mm design canvas. Without this the user had no visual reference for "this is the area that will fit in my machine" until they hit export (#103).

  2. Extends-beyond-hoop warning — the canvas computes per-path bbox vs. hoop bounds in path-units every frame. When one or more visible paths overflow the hoop, it:

    • strokes a red dashed outline around each offending path (so the user can see which paths are the problem), and
    • shows a top-right warning badge: "N path(s) extend beyond the WxHmm hoop".

The badge uses AlertTriangle from lucide-react (the same icon the ServiceHealthBanner uses for visual consistency) and mirrors the dimensions label format used by the EditorHeader hoop selector + the right panel MACHINE PROFILE hint, so the user gets the same value everywhere. Legacy callers that don't wire hoopSize render unchanged (the canvas tolerates undefined).

Three new helpers in canvasRenderer.ts:

  • drawSelectedHoop — outline + dimension label for the selected hoop.
  • drawHoopOverflowIndicator — red dashed rect around an overflowing path's anchor bbox in screen coords.
  • The existing computePathsBoundingBox shape is mirrored inline for the per-frame overflow check; the React-side useMemo on (paths, hoopSize) drives the badge.

Tests: 11 new cases — 4 in canvasRenderer.test.ts (rect math + scale + empty-path no-op) and 7 in EditorCanvas.test.tsx (legacy no-op, hoop outline drawn, no badge when paths fit, badge + outline when a path overflows, pluralization for 2+ paths, sibling paths that fit don't get outlined, invisible overflowing paths don't contribute). Full vitest suite: 1383 passing.

Shipped fix at `a91226f` (push `324eb2f..a91226f`). Two pieces: 1. **Hoop outline** — `pages/Editor.tsx` now plumbs the user-selected hoop (`designHoopSize`) into `EditorCanvas` as a new optional `hoopSize` prop. When present, the canvas renders a labeled dashed rectangle showing where the selected hoop (4x4 / 5x7 / 6x10 / 8x12) sits inside the larger 400x400mm design canvas. Without this the user had no visual reference for "this is the area that will fit in my machine" until they hit export (#103). 2. **Extends-beyond-hoop warning** — the canvas computes per-path bbox vs. hoop bounds in path-units every frame. When one or more visible paths overflow the hoop, it: - strokes a red dashed outline around each offending path (so the user can see which paths are the problem), and - shows a top-right warning badge: "N path(s) extend beyond the WxHmm hoop". The badge uses `AlertTriangle` from lucide-react (the same icon the ServiceHealthBanner uses for visual consistency) and mirrors the dimensions label format used by the EditorHeader hoop selector + the right panel MACHINE PROFILE hint, so the user gets the same value everywhere. Legacy callers that don't wire `hoopSize` render unchanged (the canvas tolerates `undefined`). Three new helpers in `canvasRenderer.ts`: - `drawSelectedHoop` — outline + dimension label for the selected hoop. - `drawHoopOverflowIndicator` — red dashed rect around an overflowing path's anchor bbox in screen coords. - The existing `computePathsBoundingBox` shape is mirrored inline for the per-frame overflow check; the React-side `useMemo` on `(paths, hoopSize)` drives the badge. Tests: 11 new cases — 4 in `canvasRenderer.test.ts` (rect math + scale + empty-path no-op) and 7 in `EditorCanvas.test.tsx` (legacy no-op, hoop outline drawn, no badge when paths fit, badge + outline when a path overflows, pluralization for 2+ paths, sibling paths that fit don't get outlined, invisible overflowing paths don't contribute). Full vitest suite: 1383 passing.
Mark closed this issue 2026-10-04 11:26:45 +00:00
Sign in to join this conversation.
No description provided.