Commit Graph
1011 Commits
Author SHA1 Message Date
SnapOtter 6e53a14072 fix: wire crop, selection, and transform tool overlays into canvas
- CropOverlay: rendered in its own Layer when crop tool is active,
  cropState auto-initialized when switching to crop tool
- SelectionOverlay: marching ants rendered for active selections,
  selection tool mouse events dispatched through canvas handler
- TransformToolTransformer: rendered when transform tool is active
- Selection tool handlers wired for marquee-rect, marquee-ellipse,
  lasso-free, lasso-poly, and magic-wand tools
- Active selection preview rect shown while dragging
2026-05-07 23:58:50 +08:00
SnapOtter 3bcf06f1ec feat: expand camera RAW support with exiftool-first decode strategy
- Add CR3 (Canon) brand detection in ftyp magic bytes, returning "raw"
  to route through the RAW decode pipeline
- Add magic bytes for Fujifilm RAF, Sigma X3F, and Minolta MRW formats
- Expand RAW_EXTENSIONS set from 6 to 24 formats (CR3, NRW, RAF, PEF,
  3FR, IIQ, SRW, X3F, RWL, GPR, FFF, MRW, MEF, KDC, DCR, ERF, PTX)
- Rewrite decodeRaw() with two-tier strategy: ExifTool embedded JPEG
  extraction (fast path) with ImageMagick+LibRaw fallback (full decode)
- Add ext parameter to decodeToSharpCompat/decodeRaw so temp files use
  the original extension for correct format identification
- Pass fileExt from tool-factory when calling decodeToSharpCompat
- Add JXL, ICO, PSD, EXR, HDR, TGA MIME entries to CONTENT_TYPE_TO_EXT
2026-05-07 23:58:48 +08:00
SnapOtter 1651d4558f fix: use distinct Photoshop-standard icons and grouping for editor toolbar
- Marquee: BoxSelect (dotted rectangle) instead of Square
- Lasso: Lasso icon instead of Pen
- Transform: Maximize2 (corner arrows) instead of Move
- Gradient: Blend instead of ArrowUpRight
- Blur Brush: Droplet (water drop) instead of ScanLine
- Sharpen Brush: Triangle instead of ScanLine
- Smudge: Fingerprint instead of ScanLine
- Burn: Flame instead of Sun (was same as Dodge)
- Sponge: Droplets instead of Sun (was same as Dodge)
- Shape: Hexagon instead of Square (was same as Marquee)
- Reorder groups to match standard Photoshop toolbar layout
- Merge Crop + Eyedropper into one group
- Separate Eraser into its own group
2026-05-07 23:49:47 +08:00
SnapOtter e99bae428a fix: resolve 50+ bugs across editor store, canvas, panels, and tools
- Store: loadImage resets state, applyCrop updates sourceImageSize,
  setTool clears stale cropState, layer ordering preserved across
  layers, rotateCanvas/flipCanvas account for object dimensions,
  trimCanvas implemented, resizeCanvas supports anchor positioning
- Canvas: crop overlay interactive, move tool drag events wired,
  hand tool panning, stage ref effect mount-only, checkerboard
  tracks pan offset, filter cache clearing
- Panels: hslToHex color fix for hue 240-360, adjustments single
  setAdjustment call, curves draggingIndex after sort, history
  panel fresh temporal reads, export transparent setting, canvas
  resize dialog re-sync, hex input respects picker target
- Tools: text tool fixed positioning and event cleanup, shape tool
  deferred addObject, selection mode wired to store, magic wand
  tolerance controlled, eyedropper coordinate transform
- Options: dodge-burn/shape/clone/fill/gradient/pixel-brush use
  proper store actions instead of raw setState
- Added 20+ store actions for tool settings
- Updated tests for corrected rotation/flip/trim behavior
- Excluded e2e-editor from vitest config
2026-05-07 23:47:08 +08:00
SnapOtter d5a03f2a98 chore: add CONTEXT.md to gitignore 2026-05-07 20:56:36 +08:00
SnapOtter 30b14151a4 fix: undo/redo rendering pipeline for canvas
Brush and eraser mouseUp handlers were bumping _historyVersion a second
time (after addObject already bumped it in mouseDown).  This created a
ghost history entry whose objects array held the same reference as the
current state.  On undo, zundo restored that identical reference, so
zustand's Object.is selector equality saw no change and skipped the
canvas re-render -- the stroke stayed visible even though the history
panel moved backward.

Remove the redundant _historyVersion increment from both mouseUp
handlers.  The addObject call in mouseDown already records the correct
pre-stroke snapshot.  mouseUp now only patches lastAction for the
history label without creating a new temporal entry.
2026-05-07 20:36:12 +08:00
SnapOtter fa3085aff9 fix: increment history version on brush/eraser stroke completion for proper undo 2026-05-07 20:26:48 +08:00
SnapOtter a633eff788 fix: wire export shortcut, text tool canvas integration, and undo rendering
1. Export dialog (Ctrl+Shift+S): replaced react-hotkeys-hook handler with
   a capture-phase keydown listener on window so the browser's native
   "Save Page As" dialog is intercepted before it can fire.

2. Text tool: created useTextTool hook that spawns an inline textarea
   overlay on canvas click, commits the text as a Konva Text object on
   blur/Enter, and wired it into the useActiveToolHandlers dispatcher.

3. Undo (Ctrl+Z): removed the 500ms debounce from zundo's handleSet.
   The debounce caused a race where calling undo before the timer fired
   would discard the future-states stack, making undo appear to do
   nothing.  The equality function (keyed on _historyVersion) already
   prevents intermediate states from being recorded, so the debounce
   was redundant.
2026-05-07 20:21:46 +08:00
SnapOtter 79897fcdb0 test: fix brush test assertion for hardness visibility 2026-05-07 19:22:50 +08:00
SnapOtter 8208acfb78 fix: restore missing text options and font loader, wire text tool options bar, fix e2e test selectors 2026-05-07 19:13:36 +08:00
SnapOtter 3cc4ec87d7 fix: resolve 15 critical/high/medium issues from self-review
CRITICAL fixes:
- #14: Render source image on canvas via Konva Image + use-image hook
- #3: Wire move tool handlers (onClick, onDragEnd, onTransformEnd, draggable)
  to all CanvasObjectRenderer shapes
- #4: Implement image object rendering for fill/gradient output
- #2: Show fallback text in histogram panel when no imageData provided
- #1: Forward all args in zundo handleSet debounce wrapper

HIGH fixes:
- #5: Track raw screen cursor position for brush overlay instead of
  using canvas-space coordinates
- #6: Export dialog uses Konva stage.toDataURL via module-level ref
  instead of DOM querySelector for correct export at any zoom/pan
- #7: Add _historyVersion increment to setAdjustment, resetAdjustments,
  toggleFilter, and setFilterParam for undo tracking
- #8: Include lastAction in partialize so history labels display correctly

MEDIUM fixes:
- #10: Move useEditorShortcuts from EditorCanvas to EditorPage with
  save/export callbacks
- #11: Remove _historyVersion increment from updateObject to prevent
  brush strokes from flooding undo history
- #12: Apply Konva filters (Brighten, Contrast, HSL, Blur, Grayscale,
  Sepia, Invert, Pixelate, Emboss, Posterize, Noise, Solarize,
  Threshold, Kaleidoscope) to source image node based on store state
2026-05-07 10:00:12 +08:00
SnapOtter e11e3660d9 test: add editor E2E test specs 2026-05-07 09:29:01 +08:00
SnapOtter 4a96d4b217 test: add editor store and types unit tests (161 tests) 2026-05-07 09:27:47 +08:00
SnapOtter 76501c4fb3 feat: add editor polish (mobile handling, loading states, accessibility)
- Show desktop-recommended message on mobile viewports (<768px)
- Add LoadingOverlay component for canvas loading/progress states
- Add ARIA tablist/tab/aria-selected to right panel tabs
- Add "Open in Editor" link in review panel after tool processing
2026-05-07 09:16:20 +08:00
SnapOtter 791bc2d3ce feat: wire editor options bar, right panel, and canvas rendering 2026-05-07 09:12:03 +08:00
SnapOtter f0941e4aec fix: resolve type errors in selection/crop/transform tools 2026-05-06 23:37:31 +08:00
SnapOtter 0f42ceca83 Merge branch 'worktree-agent-a82b6128' into feat/image-editor
# Conflicts:
#	apps/web/package.json
#	apps/web/src/stores/editor-store.ts
#	apps/web/src/types/editor.ts
#	pnpm-lock.yaml
2026-05-06 23:30:42 +08:00
SnapOtter 01dcfa624b feat: add selection, crop, transform tools and supporting infrastructure for image editor
Implements Agent 2 deliverables for the image editor: move tool with Konva
Transformer and smart guide snapping, rectangular/elliptical marquee and
lasso selection with marching ants animation, magic wand flood fill, crop
tool with darkened overlay and rule-of-thirds grid, free transform with
numeric inputs, context menu with z-ordering and clipboard operations,
rulers with drag-to-create guides, smart alignment guides, and canvas/image
resize dialogs. Also creates the shared editor types and Zustand store with
full layer management, z-ordering, clipboard, guide, and document operations.
2026-05-06 23:29:29 +08:00
SnapOtter 1d59997db5 Merge branch 'worktree-agent-a39efeb4' into feat/image-editor
# Conflicts:
#	apps/web/src/components/editor/editor-right-panel.tsx
2026-05-06 23:29:25 +08:00
SnapOtter 2ae97a6c88 feat: add history panel, keyboard shortcuts, export dialog, and navigator minimap
Implement Agent 7 features for the image editor:
- History panel with undo/redo list, action icons, and state jumping
- 51+ keyboard shortcuts via react-hotkeys-hook (tools, modifiers, clipboard)
- Export dialog with PNG/JPEG/WebP format, quality, resize, clipboard copy
- Navigator minimap with viewport rectangle, drag-to-pan, zoom slider
- Autosave/recovery system with localStorage and recovery banner
- Project save/load (.snapotter JSON format)
- Unsaved changes warning via beforeunload
- Paste from system clipboard support
2026-05-06 23:28:29 +08:00
SnapOtter 7c5bd10e80 Merge branch 'worktree-agent-ac1b61d3' into feat/image-editor 2026-05-06 23:24:55 +08:00
SnapOtter 87bbf2f889 feat: add drawing and shape tools for image editor
Implement 8 tool hooks, 7 options bar components, and 1 fill dialog:

Tools:
- Brush: Konva.Line with smooth strokes, hardness via shadowBlur
- Eraser: brush with globalCompositeOperation destination-out
- Shape: Rectangle, Ellipse, Line, Arrow, Polygon, Star with Shift constraint
- Fill (Paint Bucket): scanline flood fill with tolerance and contiguous mode
- Gradient: linear/radial via drag gesture on offscreen canvas
- Clone Stamp: Alt+click source, paint cloned pixels with aligned mode
- Dodge/Burn/Sponge: per-pixel brightness/saturation manipulation by range
- Pixel Brush: blur (box blur), sharpen (unsharp), smudge (directional blend)

Options bars:
- Brush: size/opacity/hardness sliders
- Shape: type selector, fill/stroke color, stroke width, corner radius, sides
- Fill: tolerance slider, contiguous checkbox
- Gradient: linear/radial toggle, opacity, reverse
- Clone Stamp: size/opacity/hardness, aligned toggle
- Dodge/Burn: tool toggle, range dropdown, exposure/flow sliders
- Pixel Brush: tool toggle, size, strength

Common:
- Fill Dialog: Shift+Backspace modal with foreground/background/color/white/black/50% gray
2026-05-06 23:24:34 +08:00
SnapOtter 6238925c38 Merge branch 'worktree-agent-a87ea474' into feat/image-editor 2026-05-06 23:24:09 +08:00
SnapOtter c4bcb12173 feat: add adjustments, filters, levels, curves, histogram, and effects panels for image editor
Implements Features 17, 18, 35, 36, 41, 42, 43 for the editor:
- SliderRow reusable component (label + range + numeric input)
- AdjustmentsPanel with 8 adjustment sliders (brightness, contrast,
  hue, saturation, luminance, exposure, vibrance, warmth)
- Auto adjustments: Auto Tone, Auto Contrast, Auto Color, Auto Enhance
- Levels section with per-channel control, histogram display, black/white
  point, gamma, and output range sliders
- Curves section with 200x200 interactive graph, cubic spline
  interpolation, per-channel support, and 9 presets
- 12 filter controls: toggle (grayscale, sepia, invert, solarize) and
  slider (blur, sharpen, noise, pixelate, emboss, posterize, threshold,
  kaleidoscope)
- Additional blur types: motion blur, radial blur, surface blur
- Vignette with amount/midpoint/roundness/feather sliders
- Grain with amount/size/roughness sliders
- HistogramPanel with RGB channel overlays and stats (mean, stddev, median)
- Reset All and Apply action buttons
- 150ms debounce on adjustment sliders, 300ms on histogram updates
2026-05-06 23:23:45 +08:00
SnapOtter 7e2a7adbd2 Merge branch 'worktree-agent-af61ea3e' into feat/image-editor 2026-05-06 23:23:24 +08:00
SnapOtter a9547f5944 feat: add color system panel, eyedropper tool, and color swatch components
Color panel with foreground/background swatches, react-colorful picker
popover, HEX/RGB/HSL input modes, recent colors row, swap (X) and reset (D).
Eyedropper tool samples composited pixels via stage.toCanvas() with 1x1/3x3/5x5
sample size options, alt+click for background color.
2026-05-06 23:23:05 +08:00
SnapOtter fedb7bc2e3 feat: add layers panel with blend modes, effects, and drag reorder
Implements the layer management panel for the image editor (Features 16, 40):
- Blend mode dropdown (16 modes) and opacity slider for active layer
- Layer list with visibility/lock toggles, thumbnails, and inline rename
- Pointer-based drag reorder (not HTML5 drag API)
- Right-click context menu: Duplicate, Merge Down, Flatten All, Delete
- Layer effects section: Drop Shadow, Inner Shadow, Outer Glow, Stroke
- Each effect with enable/disable toggle and full parameter controls
- Wired into EditorRightPanel as the "Layers" tab content
2026-05-06 23:22:24 +08:00
SnapOtter 9eae8369bb feat: wire editor route, sidebar, mobile nav, and i18n 2026-05-06 23:14:30 +08:00
SnapOtter 08a2119564 feat: add editor layout components, welcome screen, and editor page
Create the four-zone editor layout shell (toolbar, options bar, status
bar, right panel), welcome screen with drag-and-drop and new document
dialog, and the main editor page with clipboard paste and URL loading.
2026-05-06 23:12:59 +08:00
SnapOtter 155783ca86 feat: add canvas system and utility components for image editor
Create canvas zoom hook with smooth Konva.Tween transitions, icon button
component, cursor management with brush overlay, and editor canvas with
checkerboard background, ResizeObserver sizing, and grid overlay.
2026-05-06 23:08:32 +08:00
SnapOtter eb6f3c33ac feat: add image editor type definitions and zustand store
Add complete type system for the editor (ToolType, CanvasObject, EditorLayer,
EditorState, etc.) and the central Zustand store with zundo undo/redo middleware,
50-entry history limit, 500ms throttle, and O(1) _historyVersion equality checks.
2026-05-06 23:05:33 +08:00
SnapOtter 711ddf8deb chore: add konva, react-konva, and editor dependencies 2026-05-06 23:01:47 +08:00
SnapOtter c9b24ada78 ci: add Trivy container vulnerability scan to release pipeline
Scans the amd64 Docker image for CRITICAL/HIGH CVEs with available fixes
before publishing multi-arch manifests. Results upload to GitHub Security tab
as SARIF. Blocks release if fixable vulnerabilities are found.
2026-05-06 22:39:49 +08:00
SnapOtter 7d081b5081 fix: replace Discord member count badge with static join badge 2026-05-06 22:03:43 +08:00
SnapOtter d705c863e3 Merge feat/transparency-fixer: add PNG Transparency Fixer tool
New AI-powered tool that fixes fake transparent PNGs in one click.
Uses BiRefNet HR-matting (2048x2048) with Sharp defringe post-processing.
2026-05-06 21:57:46 +08:00
SnapOtter 371cd6f485 chore: remove temporary Docker playwright config 2026-05-06 21:57:34 +08:00
SnapOtter dabab32798 Merge fix/121-qr-logo-not-working: QR code logo causes preview to vanish
fix: QR code logo causes preview to vanish and become unrecoverable

The QR code generator's logo feature was broken in production (Docker)
due to three interacting issues:

1. The CSP connect-src directive did not include data:, so the
   qr-code-styling library's internal XHR to convert logo data URLs to
   blobs was silently blocked.

2. crossOrigin: "anonymous" was unnecessarily set on imageOptions for
   data URLs.

3. The logo options used a conditional spread that omitted the image key
   when no logo was set, but the library's deep merge preserved the
   stale data URL.

Closes #121
2026-05-06 21:41:29 +08:00
SnapOtter 8f9ba701be fix: QR code logo causes preview to vanish and become unrecoverable
The QR code generator's logo feature was broken in production (Docker)
due to three interacting issues:

1. The CSP connect-src directive did not include data:, so the
   qr-code-styling library's internal XHR to convert logo data URLs to
   blobs was silently blocked. The library has no onerror handler, so the
   render promise hung forever after the container was already cleared.

2. crossOrigin: "anonymous" was unnecessarily set on imageOptions for
   data URLs, which can cause canvas taint issues.

3. The logo options used a conditional spread that omitted the image key
   when no logo was set. The library's update() deep-merges options, so
   removing the logo preserved the stale data URL and the QR stayed
   broken even after logo removal.

Closes #121
2026-05-06 21:38:12 +08:00
SnapOtter 84e62e6132 refactor: rename tool display name to "PNG Transparency Fixer" 2026-05-06 18:53:37 +08:00
SnapOtter c47ec34021 fix: show tool name instead of bundle name in install prompt, add queued state 2026-05-06 18:47:34 +08:00
SnapOtter c0550fb2cf fix(ci): ignore 3 new Pillow CVEs blocked by ML dependency constraints
Pillow 11.1.0 has CVE-2026-42308, CVE-2026-42310, CVE-2026-42311
(fixed in 12.2.0). Upgrading to Pillow 12.x requires validating
compatibility with rembg, realesrgan, mediapipe, and codeformer.
2026-05-06 10:40:30 +08:00
SnapOtter 75e48f2738 test: add transparency-fixer to GUI AI tools and tools-all E2E tests 2026-05-06 10:39:15 +08:00
SnapOtter eb3d0828cb docs: add transparency-fixer endpoint documentation 2026-05-05 23:24:22 +08:00
SnapOtter 4745e435a4 test: add Playwright E2E tests for transparency-fixer tool 2026-05-05 23:17:24 +08:00
SnapOtter c263834037 test: add integration tests for transparency-fixer tool 2026-05-05 23:14:42 +08:00
SnapOtter 52f355ef8f feat: register transparency-fixer in frontend tool registry 2026-05-05 23:09:15 +08:00
SnapOtter 06d6c0ef1e feat: add transparency-fixer settings component 2026-05-05 23:09:10 +08:00
SnapOtter b1959e977d fix: improve defringe quality and add defensive guards in transparency-fixer 2026-05-05 23:07:14 +08:00
SnapOtter 423711ac42 feat: add transparency-fixer API route with defringe post-processing 2026-05-05 23:03:07 +08:00
SnapOtter d5a808dbc7 feat: register transparency-fixer in shared constants, features, and i18n 2026-05-05 22:58:30 +08:00