feat: MaskEditor UI component (#532)#550
Draft
shaoster wants to merge 11 commits into
Draft
Conversation
…r panels, and Storybook stories Complete UI skeleton for #532 — all 6 tools (prefill, brush, polygon, flood, grabcut, snap) render with correct layout and inspector panels; canvas functionality and ML wiring are stubs pending next iteration. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Brush/eraser paint to alpha channel via pointer events. Flood fill uses scanline BFS seeded from source image pixel color. Polygon tool tracks vertices on overlay canvas and fills on double-click. GrabCut rect dragged on overlay canvas. Undo/redo wired with ImageData refs (counts in reducer, snapshots in component refs). Mask canvas shows at 0.55 opacity over source image; commit strips RGB channels to output RGBA PNG. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…sh tool - Brush tool removed from toolbar and state (scope deferred per user request) - Polygon: Close path button + Enter key commit, Insert here + I key, Smooth ×3, Apply simplify (Douglas-Peucker), Delete vertex + Backspace/Delete; all use polygon_vertices_set action - Flood: Commit fill button wires to tool_applied dispatch - GrabCut: R resets rect; F/G switch hint mode when grabcut is active; Cmd+Enter runs refine - Snap: S snaps selected vertex, Shift+S snaps all, [ ] adjust radius - Global: P/G/F/C/S switch tools; Cmd+Z undo, Cmd+Shift+Z / Cmd+Y redo - Canvas ops (fillPolygon, floodFill, smoothPolygon, simplifyPolygon) extracted to maskEditorCanvasOps.ts so MaskEditor.tsx can call them directly for keyboard/button handlers Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
… WASM GrabCut: loadOpenCV() singleton, builds RGB cv.Mat from source image, GrabCut mask from existing mask canvas alpha channel, runs cv.grabCut() with user rect + iterations, writes GC_FGD/GC_PR_FGD pixels back to mask canvas. Uses GC_INIT_WITH_RECT on first run, GC_EVAL when mask already has foreground pixels painted. Contour snap: Canny/Sobel/Scharr edge map computed from grayscale source, then each target vertex searches within snapRadius for the strongest edge pixel above the threshold. Snap vertex (S) operates on selected vertex only; Snap all (Shift+S) operates on all polygon vertices. srcCanvasRef lifted to MaskEditor so both GrabCut and snap can access source pixels without going through React state. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add hintsCanvasRef (third canvas) for GC FG/BG scribble painting - Pass hintsCanvas to runGrabCut so hint strokes are respected as GC_FGD/GC_BGD pins - Fix grabcut hint mode routing: overlay receives pointer events for rect drag, hints canvas receives events in FG/BG modes - Fix snap tool: redraw polygon overlay in snap mode so snapped positions are visible - Add click-to-select vertex in snap mode on overlay canvas - Add ←/→ arrow key cycling through vertices in snap mode - Show "draw a polygon first" empty state in snap inspector when no vertices - Update snap inspector Run section: show vertex count, disable buttons when no polygon Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Close path (⏎ / button) now sets polygonClosed=true, keeping all vertices intact and switching from "add vertex on click" to "select vertex on click". A separate "Apply to mask · ⏎" button (shown when closed) fills the polygon and clears vertices. "Reopen path" restores add-vertex mode. - Add polygonClosed: boolean to state with polygon_closed / polygon_reopened actions - polygon_vertices_set always resets polygonClosed to false - Canvas blocks vertex adds when polygonClosed; click-on-empty-space is a no-op - Inspector shows Close/Reopen toggle + Apply button; ⏎ shortcut label updates accordingly Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace three separate overlay effects (polygon, grabcut, clear-on-switch) with a single composite effect that always draws polygon vertices on top of any grabcut rect. Vertices are now visible regardless of active tool. - Rename drawGrabCutOverlay → drawGrabCutRect (no longer owns clearRect) - Composite effect: clear → draw polygon (if any) → draw grabcut rect (if grabcut tool) - GrabCut live-drag handler composites the same way during pointer move - drawPolygonOverlay gains `closed` param: squares when open, circles when closed - Preview edge-to-cursor suppressed when path is closed (no new vertices) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add Spinner component to MaskEditorShared (CSS animation, no deps) - Add loading prop to ActionButton: swaps icon for spinner, disables click - GrabCut "Refine mask" and snap "Snap v / Snap all" buttons now show spinner while assistStatus=loading - Fix polygon onLeave: redraw overlay without hover preview line so the dashed edge-to-cursor doesn't stick after cursor exits Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Polygon overlay visibility: - Two-pass edge drawing: 3.5px black shadow + 1.5px accent, readable on any background - Vertex handles: white fill + accent ring + dark shadow drop — visible on both dark and orange backgrounds - Preview line to cursor also two-pass Enter key race (Scenario B): - Enter in polygon mode ONLY closes path (polygonClosed=false → polygon_closed) - Pressing Enter when already closed is a no-op; apply requires the button - Remove "· ⏎" label from "Apply to mask" button and keyboard hint OpenCV WASM loading: - isCvReady() exported from maskEditorCv.ts; WASM prefetch starts on module load - Canvas shows "opencv.js loading…" pill with spinner when grabcut/snap tool is active and WASM hasn't resolved yet - Once loaded, indicator disappears automatically Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Each mutating operation (polygon vertex add/move/delete, flood fill, hints stroke, grabcut run, snap) now snapshots mask canvas + hints canvas + polygon vertices + polygonClosed into a single UndoEntry before acting, so a single Ctrl-Z reverses the whole operation. Also separates Close path (Enter / button) from Apply to mask — Enter only closes the polygon, never fills it. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Paints alpha=0 circles on the mask canvas to erase foreground. Each stroke start snapshots the mask into undo history, so individual strokes are reversible. Radius adjustable via inspector slider or [ / ] keys. Also fixes: unused `closed` param in drawPolygonOverlay now correctly controls whether the last edge closes back to the first vertex. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Owner
Author
Checkpoint — session summaryWhat landed in this session (both commits pushed)
Known state / what to continue next
Files changedWhat remains (out of scope for #532 or follow-up)
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
onCommitoutputs RGBA PNG blob with RGB zeroed, alpha = foreground maskPolygon tool — click to add vertices, drag to move, right-click to delete, double-click / Enter / Close path button to fill and commit; Insert here (I), Smooth ×3, Apply simplify (Douglas-Peucker)
Flood fill — scanline BFS seeded from click position, RGB Euclidean tolerance against source image; 4-way/8-way connectivity; add/subtract modes
GrabCut — drag rect on overlay canvas; hint mode switching (R/F/G keys); Run GrabCut stubbed pending cv.grabCut() wiring
Contour snap — inspector controls wired; snap execution stubbed pending cv.Canny() wiring
Keyboard shortcuts — P/G/F/C/S switch tools; Enter finishes polygon; Backspace/Delete removes selected vertex; I inserts midpoint vertex; Cmd+Z/Shift+Cmd+Z undo/redo; Cmd+Enter runs GrabCut; [ ] adjust snap radius; R resets grabcut rect; F/G toggle grabcut hint mode when grabcut is active
Storybook — 7 stories (Gallery + 6 per-image launchers) pre-seeded with real pottery images stored in web/public/stories/
Out of scope (follow-up issues)
Test plan
Closes #532
Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com
🤖 Generated with Claude Code