Skip to content

feat(image-editor): wire Paint Bucket (G) — flood fill#39

Merged
lyfuci merged 1 commit intomainfrom
feat/image-editor-paint-bucket
Apr 24, 2026
Merged

feat(image-editor): wire Paint Bucket (G) — flood fill#39
lyfuci merged 1 commit intomainfrom
feat/image-editor-paint-bucket

Conversation

@lyfuci
Copy link
Copy Markdown
Owner

@lyfuci lyfuci commented Apr 24, 2026

Summary

Promotes the Paint Bucket (G) tool from stub to functional. Click on the
canvas → connected region of similar pixels gets filled with the
foreground color and lands as a new image-shape layer (non-destructive,
undoable).

Implementation

  • New `src/lib/image-editor/flood-fill.ts` — 4-connected scanline flood
    fill on raw `ImageData` with a configurable channel-wise tolerance
    (0–128). `maskToDataUrl` paints the mask with the chosen color and
    serialises to a PNG data URL.
  • `Canvas.tsx` exposes a new `onBucketClick(point)` callback. The fill
    itself runs in `ImageEditor.tsx` because it needs to re-render the
    full editor state at source resolution (not just the cropped preview)
    to operate on the true image.
  • The fill bitmap is stored at SOURCE resolution so exports stay sharp;
    the layer's preview-pixel rect spans the full canvas.
  • `OptionsBar` gains a Bucket variant: FG color picker + tolerance
    slider (default 32).
  • Click on a transparent edge / out-of-bounds → empty mask → toast
    message rather than a phantom layer.
  • Coord math handles an active crop: the click is in cropped-canvas
    preview pixels, so we shift back by the crop origin before scaling
    to source.

Removes `bucket` from `STUB_TOOLS`.

Branched from `main` (independent of #38).

Test plan

  • Open an image, press G — Bucket variant appears in the options bar (color + tolerance).
  • Click a uniform region — fills with FG color, new layer appears in the layer list.
  • Tolerance slider changes the size of the filled region.
  • Cmd+Z undoes the fill.
  • Click an isolated speck → toast "Nothing to fill at that point".
  • Switch FG color, fill again — second layer uses new color.
  • Crop the image, then bucket-fill — fill respects the cropped view (no spillover into hidden pixels).
  • Export PNG — fill is at source resolution (not blurry).
  • Save .json project, reload — bucket layer round-trips.

🤖 Generated with Claude Code

Promotes the Paint Bucket tool from stub to functional. Click anywhere
on the canvas and the connected region of similar pixels gets filled
with the foreground color, dropped as a new image-shape layer (so it's
non-destructive and undoable).

## Implementation

- New \`src/lib/image-editor/flood-fill.ts\` — 4-connected scanline flood
  fill on raw ImageData with a configurable channel-wise tolerance
  (0–128). Returns a Uint8Array mask. \`maskToDataUrl\` paints the mask
  with the chosen color and serialises to a PNG data URL.
- \`Canvas.tsx\` exposes a new \`onBucketClick(point)\` callback. The fill
  itself runs in \`ImageEditor.tsx\` because it needs to re-render the
  full editor state at source resolution (not just the cropped preview)
  to operate on the true image.
- The result lands as an image-shape layer covering the full preview
  canvas, with the bitmap stored at SOURCE resolution so exports stay
  sharp.
- \`OptionsBar\` gains a Bucket variant: FG color picker + tolerance
  slider (0–128, default 32).
- Click on a transparent edge / out-of-bounds → empty mask → toast
  message instead of a phantom layer.
- Coord math handles an active crop: the click is in cropped-canvas
  preview pixels, so we shift back by the crop origin before scaling
  to source.

Removes \`bucket\` from \`STUB_TOOLS\`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@lyfuci lyfuci merged commit 4186148 into main Apr 24, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant