Commit Graph
788 Commits
Author SHA1 Message Date
SnapOtter 485a2d72d3 fix: harden SSRF validation with missing IP ranges and safeFetch tests 2026-05-11 21:29:58 +08:00
SnapOtter a85ca54feb refactor: remove redundant trim in URL parser 2026-05-11 21:28:24 +08:00
SnapOtter 4a430abf2f feat: add useUrlImport hook for URL fetch lifecycle 2026-05-11 21:27:43 +08:00
SnapOtter d38101b8ea feat: add POST /api/v1/fetch-urls endpoint for server-side URL import
Accepts { urls: string[] } (1-50), fetches each URL with SSRF protection
via safeFetch, validates as image, saves to workspace, generates WebP
preview for non-browser formats, and returns results with download URLs.
Uses p-queue with concurrency 4 to parallelize fetches.
2026-05-11 21:24:56 +08:00
SnapOtter a2be47bd68 feat: add smart URL parser for bulk import 2026-05-11 21:18:45 +08:00
SnapOtter 488ed95686 feat: add SSRF validation utility for URL fetch 2026-05-11 21:18:23 +08:00
SnapOtter 9466df90e0 fix: extract first frame from multi-image FITS files
ImageMagick outputs numbered files (fits-out-0.png, fits-out-1.png)
for multi-image FITS, but decodeFits expected a single output file.
Added [0] selector to extract only the first frame, matching the
pattern used by DDS and PSD decoders.
2026-05-11 18:13:29 +08:00
SnapOtter 2acf0ea48a fix: fall back to Sharp when CLI decoders are unavailable
DNG and FITS previews showed "Preview not available" because their CLI
decoders (ExifTool/ImageMagick) were not installed. Sharp can read both
formats natively (DNG is TIFF-based, FITS via libvips fitsload).

Added Sharp fallback to the preview endpoint, batch processing, and
tool factory: when decodeToSharpCompat throws, try sharp(buffer).metadata()
before returning 422. If Sharp can read the buffer, processing continues
without the CLI decoder.
2026-05-11 18:00:59 +08:00
SnapOtter 50d1f532d1 fix: block PDF uploads, fix PBM/PGM/PPM batch failures, add tests
- Added isImageFile() filter to all drop handlers (dropzone, collage,
  file-upload-area) so PDFs and non-image files are rejected on drop.
  Previously only the file picker's accept attribute filtered; drag-and-
  drop accepted anything.

- Added ppm, pgm, pbm to CLI_DECODED_FORMATS in file-validation.ts.
  These formats were missing, causing Sharp metadata checks to fail for
  some files during batch validation, which silently dropped them from
  results ("File not found in batch results").

- Added integration tests for PBM, PGM, PPM, TIFF, QOI, JP2, SVGZ
  single-file processing, plus a test confirming PDF is rejected.
2026-05-11 17:33:51 +08:00
SnapOtter a52a3b7e87 fix: generate server-side previews for all non-browser formats
SERVER_PREVIEW_EXTENSIONS was missing TIFF, DDS, DPX, EPS, FITS, JP2,
PBM/PGM/PPM, QOI, SVGZ, CUR, and many RAW variants. The server
already had decoders for all of them but the client never triggered
the preview fetch, so users saw "Preview not available" instead.
2026-05-11 17:25:26 +08:00
SnapOtter 1d7a7188bf fix: replace editor PenTool icon with image-edit icon
Custom SVG showing a landscape image frame with a pencil overlay,
clearly communicating "edit image" instead of the vector pen tool
which read more as Illustrator than Photoshop.
2026-05-11 17:20:14 +08:00
SnapOtter 0f1fd2050b fix: add +/- stepper buttons to quality slider in compress tool
Small bordered buttons with Minus/Plus icons flank the range slider,
allowing single-step quality adjustments. Disabled at min (1) and
max (100) boundaries.
2026-05-11 17:12:24 +08:00
SnapOtter aa614cb53d fix: constrain thumbnail strip to right pane and handle non-previewable formats
The thumbnail strip expanded beyond the right pane because the flex
section lacked min-w-0, causing a page-level horizontal scrollbar.
Added min-w-0 to both mobile and desktop image area sections.

For non-previewable formats (DDS, TIFF, EXR, PSD, RAW, etc.), show a
file info card with format and size instead of passing the blob URL to
an img tag that fails and shows an infinite "Loading preview..." spinner.
Also changed the ImageViewer error state from a misleading spinner to a
static "Preview not available" message.
2026-05-11 17:10:42 +08:00
SnapOtter aec1e91c5a fix: add .avif to all file picker accept strings
AVIF was missing from expandAccept() and every inline accept attribute,
causing the OS file picker to gray out .avif files. Drag-and-drop was
unaffected because it bypasses the accept filter. Added .avif to
dropzone.tsx expandAccept (covers all Dropzone pickers) plus 12 inline
accept strings across tool settings, pages, and file-upload-area.
2026-05-11 16:59:49 +08:00
SnapOtter 72de10b844 fix: clean up files section and add KB/MB unit selector to compress
- Remove duplicate "Files" heading (section header + inline count)
- Space "Show more" and "Clear all" apart on the same row
- Replace bare number input with number + KB/MB dropdown for target
  size, defaulting to KB; MB values are converted to KB for the API
- Hide native number input spin buttons for a cleaner look
2026-05-11 16:54:13 +08:00
SnapOtter 0c8e8c075c fix: remove checkerboard bleed in before-after slider and image viewer
The before-after slider hardcoded a checkerboard background on the
entire "after" overlay, which filled letterbox/pillarbox space around
non-transparent images. Replaced with a neutral bg-muted/30.

In image-viewer, moved the checkerboard from the outer container
(which included padding) to the img element itself, so it only
shows through transparent pixels rather than the surrounding area.
2026-05-11 16:48:51 +08:00
SnapOtter a7a17fbff4 fix: show all uploaded files with format and size in left panel
Replace the single-file pill with a full file list showing name
(truncated), format badge, and size for each file. First 5 files
are visible by default with a "show more" toggle for the rest.
Clicking a file selects it in the viewer. Applies to all tools.
2026-05-11 16:42:24 +08:00
SnapOtter 5b868886ba fix: make target size the primary compression mode
Move Target Size button to the left and default to it on load, since
it is the more useful mode for most users.
2026-05-11 16:33:10 +08:00
SnapOtter 8598808b3c fix: correct repository name casing in clone instructions 2026-05-10 22:41:52 +08:00
SnapOtter 172c0fa772 fix: update tool count to 51, refresh hero copy and login page
- Update stale tool counts (48/49/50) to 51 across all apps, docs, and tests
- Add Meme Generator to landing page bento grid (was missing)
- Add 12 SEO-friendly rotating phrases to hero typing cursor
- Change landing hero subtitle to "Every image tool you need."
- Replace outdated login page copy with branded hero + rotating phrases
2026-05-10 22:18:11 +08:00
SnapOtter 28f919b5d7 fix: add favicon to landing page for Google Search visibility
The landing page had no favicon at all, causing Google to show a
generic globe icon in search results for snapotter.com.
2026-05-10 21:50:56 +08:00
SnapOtter caf351209b fix: upgrade favicons to 48x48 for Google Search visibility
Google requires favicons to be a multiple of 48px. The previous 32x32
favicon.png was being ignored, causing the generic globe icon in search
results. Adds favicon.ico (multi-size), apple-touch-icon, and fixes
og:image to use absolute URLs.
2026-05-10 21:49:56 +08:00
SnapOtter 8aa5d9a5f2 Add new branding SVG files for wordmark in white and default colors
- Created wordmark-white.svg with white text for branding use.
- Created wordmark.svg with dark text for branding use.
2026-05-10 21:25:43 +08:00
SnapOtter 78ca9720e7 fix: sync all workspace package versions to 1.16.0 2026-05-10 20:19:02 +08:00
SnapOtter 86a74ab706 fix: replace hardcoded version in deployment docs with placeholder 2026-05-10 20:17:40 +08:00
SnapOtter 6f1c00711b feat: add version badge to docs navigation bar 2026-05-10 20:15:44 +08:00
SnapOtter f0021a53d3 docs: sync API docs with codebase -- add meme-generator, remove phantom endpoints
- Add meme-generator tool and meme-templates API to OpenAPI spec, VitePress
  docs, and README
- Remove 4 phantom OpenAPI entries (brightness-contrast, saturation,
  color-channels, color-effects) that were consolidated into adjust-colors
- Bump OpenAPI version to 1.16.0, tool count to 51
- llms.txt and llms-full.txt auto-update from OpenAPI at runtime
2026-05-10 14:11:23 +08:00
SnapOtter 68fe02db35 fix: QA sweep -- settings dialog a11y, help button contrast, test expectation fixes
- Add role="dialog" and aria-modal="true" to settings dialog for screen
  reader compatibility and Playwright getByRole('dialog') selectors
- Fix sidebar Help button contrast ratio from 1.18:1 to WCAG AA compliant
  by using text-sidebar-foreground class
- Add explicit tabIndex={0} to search input for keyboard navigation
- Update convert test to expect BMP success (now a supported format)
- Fix watermark-image tiled test MIME type mismatch (webp not png)
- Swap compose test base/overlay so overlay is smaller than base
- Relax find-duplicates perceptual hash grouping assertions
2026-05-09 21:50:46 +08:00
SnapOtter a0556772e8 test: expand coverage across all layers -- 1,268 new tests, fix replace-color div-by-zero
14-agent parallel test expansion covering integration, unit, E2E, E2E-Docker,
cross-format matrix, adversarial, GUI navigation/tools/settings/visual/a11y/perf.

- Integration: expand 23 tool test files with HEIC, stress, batch, edge cases
- Unit: close coverage gaps in image-engine, stores, lib (metadata, auto-enhance,
  connection-store, lazy-with-retry, collage/file-store HEIC preview)
- AI bridge: 141 new tests for dispatcher buffering, crash recovery, OOM/segfault
- Cross-format: 794 parameterized tests (16 formats x 12 tools + no-crash matrix)
- Adversarial: memory stress (50x large file), zero-byte, corrupted headers, unicode
- E2E-Docker: expand 8 spec files with dimension verification, pipeline chains
- GUI E2E: tool UI settings/interactions for all 47 tools, remove all test.skip,
  RBAC per-role verification, visual screenshot naming, cross-browser smoke tests,
  a11y ARIA/focus/contrast, performance budgets, 15-tool stability test
- Fix: replace-color.ts tolerance=0 caused division-by-zero producing NaN pixels

Total: 8,958 tests passing across 202 files. Zero failures, zero skips.
2026-05-09 18:02:58 +08:00
SnapOtter 7b1f09f5d0 fix: CLAHE tile size and alpha channel corruption in image enhancement
CLAHE width/height is tile size in pixels, not tile count. A 3px tile on
a 992x1088 image created ~330x360 independent histogram regions, producing
crosshatch/etching artifacts. Now uses image_dimension/8 (clamped 8-256)
for ~8 tiles per axis. Also strips alpha before enhancement and re-joins
after to prevent CLAHE/normalise/linear from corrupting transparency.
2026-05-09 15:20:55 +08:00
SnapOtter 7f131d99a6 fix: QA sweep -- SSE crash, memory leaks, HEIC Docker decode, TGA detection, lint cleanup
- Fix SSE write-after-end crash in progress.ts (remove callback before ending stream)
- Fix blob URL memory leaks: revoke processedPreviewUrl and old HEIC preview URLs
- Add AbortController to batch fetch in use-tool-processor and use-pipeline-processor
- Fix TGA format misidentified as CUR (extension overrides magic bytes)
- Add libheif-plugin-libde265 to Docker for HEIC/HEIF decode support
- Remove unused imports and state (AppLayout, setSampledColor, useEffect)
- Fix non-null assertions in meme-text-renderer and meme-generator
- Fix confusing void type in meme-templates
- Remove unnecessary useEffect deps in adjustments-panel
- Fix Playwright strict mode violations in 5 E2E tests
2026-05-09 13:55:00 +08:00
SnapOtter ee871dc8ea feat: add Deep Enhance toggle to image enhancement UI
Toggle sends deepEnhance: true in settings to enable AI-powered
noise/artifact cleanup via SCUNet after the Sharp pipeline.
2026-05-09 11:31:36 +08:00
SnapOtter 40522ebe1a feat: add Deep Enhance AI tier to image enhancement
When deepEnhance is true and the upscale-enhance bundle is installed,
runs SCUNet (quality tier) after the Sharp pipeline for noise/artifact
cleanup. Falls back gracefully to Sharp-only if sidecar is unavailable.
2026-05-09 11:29:27 +08:00
SnapOtter bdcfb6647c fix: sync frontend preset multipliers and fix sharpen type error
Add clahe and normalise entries to frontend PRESET_MULTIPLIERS to match
backend. Fix SharpenOptions to use m1 (not flat) per Sharp 0.34 types.
2026-05-09 11:26:49 +08:00
SnapOtter b61be9e438 fix: replace enhancement pipeline with CLAHE + normalise + gamma
CLAHE provides adaptive local contrast, normalise stretches the
histogram, and gamma adjusts exposure perceptually. Replaces the old
modulate/linear pipeline that compounded errors and darkened images.
Preset multipliers now include clahe and normalise entries.

Key fixes beyond the spec:
- maxSlope rounded to integer (Sharp requirement)
- White balance uses linear() instead of recomb() to avoid float-cast
  that breaks CLAHE in the libvips pipeline
- CLAHE tile size adapts to image dimensions (1x1 for tiny images)
- Gamma clamped to Sharp's valid range (1.0-3.0)
- Normalise lower/upper correctly mapped to percentile cutoffs
2026-05-09 11:24:00 +08:00
SnapOtter 96b055093b fix: magic wand tool selection, overlay, and mask consistency
- Replace naive 4-neighbor flood fill with scanline algorithm for performance
- Include alpha channel in color distance calculation
- Render actual mask outline with marching ants instead of bounding rectangle
- Use Konva Shape with batched canvas path for efficient edge rendering
- Add dedicated magicWandContiguous state (was incorrectly sharing fillContiguous)
- Add Contiguous checkbox to magic wand options bar
- Fix invertSelection to use consistent mask values (1 not 255) and expand
  inverted mask to full canvas dimensions instead of staying within old bounds
2026-05-09 00:14:57 +08:00
SnapOtter 05cb7c940f fix: deduplicate tool icons and add missing icon mappings
7 icons were shared by multiple tools, now each tool has a unique icon:
- favicon: Globe -> AppWindow
- smart-crop: Focus -> Crosshair
- noise-removal: Sparkles -> AudioLines
- beautify: Sparkles -> ImagePlus
- red-eye-removal: Eye -> ScanEye
- color-palette: Palette -> Droplets
- transparency-fixer: Wand2 -> ShieldCheck
- pdf-to-image: FileOutput -> BookImage

2 icons were missing from the ICON_MAP (falling back to generic FileImage):
- Scaling (content-aware-resize)
- Laugh (meme-generator)
2026-05-09 00:08:24 +08:00
SnapOtter e22ffa4ec9 fix: editor native layout, UI polish, meme templates auth, pipeline export, install queuing
- Remove editor from AppLayout so it owns the full viewport with no sidebar/padding
- Add back-arrow in menu bar for navigation, restyle menu bar to match native app feel
- Slim left toolbar from 48px to 36px with smaller icons and subtler dividers
- Fix options bar overlapping canvas via shrink-0 and overflow-hidden
- Fix opacity/blend controls clipping in right panel with min-w-0 on flex children
- Add global range slider CSS for consistent thin-track + round-thumb styling
- Make meme template routes public so img tags can load without Bearer auth
- Show pipeline export buttons in default compact view, not just expanded hover
- Queue individual AI feature installs instead of erroring when one is active
2026-05-08 23:30:27 +08:00
SnapOtter e3e5fd5890 Merge branch 'testing/image-editor' into main
Merges all image editor work: RAW decode improvements, expanded format
export (AVIF/TIFF/GIF/JXL/PSD), Photoshop-style menu bar, custom Konva
filters, smart guides, clone stamp, dodge/burn, eyedropper, pixel brush,
selection and transform tool overlays, autosave blob URL persistence,
and 49+ bug fixes across editor canvas and E2E tests.

# Conflicts:
#	apps/api/src/routes/tool-factory.ts
#	apps/api/src/routes/tools/convert.ts
#	apps/web/src/components/editor/common/export-dialog.tsx
#	apps/web/src/components/editor/editor-canvas.tsx
2026-05-08 21:37:52 +08:00
SnapOtter 0dbf300ef2 Merge branch 'feat/remotion-promo-videos'
# Conflicts:
#	pnpm-lock.yaml
2026-05-08 21:29:19 +08:00
SnapOtter 3a02affae3 feat: recover AVIF/TIFF/GIF/JXL/PSD export from orphaned commit
Recovers expanded export format support from orphaned commit 80961c01
and PSD export from b07ecd5. The editor export dialog now supports 7
formats (PNG, JPEG, WebP client-side; AVIF, TIFF, GIF, JXL via server
conversion). PSD export uses ImageMagick on the backend.
2026-05-08 21:06:29 +08:00
SnapOtter 7d7df194bc feat: add pipeline import from JSON file
Add import button to saved pipelines section with file picker,
validation, and error display with auto-dismiss. Section now
always renders with empty state text when no pipelines exist.
2026-05-08 20:59:25 +08:00
SnapOtter e5939f7b5a feat: add pipeline export as JSON file 2026-05-08 20:55:48 +08:00
SnapOtter 321c5da998 fix: menu bar dropdown transparent background, move test to e2e-editor
- Replace bg-popover with bg-card for dropdown backgrounds (popover CSS
  variable is not defined in this project's theme)
- Move menu bar test to tests/e2e-editor/ and adapt for editorPage fixture
- Fix click-outside test to handle welcome screen overlay
2026-05-08 20:47:05 +08:00
SnapOtter 5c64581496 feat: recover Photoshop-style menu bar from orphaned branch
Recovers the editor menu bar (File/Edit/Image/Layer/Select/Filter/View)
from orphaned commit b07ecd5 that was lost during a rebase. Integrates
it into the current editor-page layout with PSD/TGA/EXR/HDR file open
support and new document dialog.
2026-05-08 20:37:26 +08:00
SnapOtter a1a71e507f fix: 8 image editor bugs found during Docker-based E2E testing
- fix WebP export silently producing PNG when background is non-transparent
- fix autosave not converting blob: URLs inside image-type canvas objects
- fix project load not resetting selection/crop/clipboard state
- fix rotateCanvas not updating object rotation attributes
- fix flipCanvas not negating object rotation attributes
- fix line shadow props overridden by effect spread ordering
- fix "outside" stroke position rendering same as "center"
- add missing pencil tool keyboard shortcut (N)
- remove misleading resample dropdown from image resize dialog
- fix E2E autosave tests for production builds (no Vite dynamic imports)
- fix color picker test case sensitivity (CSS uppercase vs DOM text)
- add 4 unit tests for rotation attribute transforms
2026-05-08 20:27:06 +08:00
SnapOtter e7001df047 fix: add ImageData type assertion for barcode reader typecheck 2026-05-08 19:08:38 +08:00
SnapOtter aa773addb4 merge: resolve conflict with main branch in tool-registry.tsx 2026-05-08 18:55:28 +08:00
SnapOtter c57d284232 fix(videos): enhance ambient compositions visibility and atmosphere
- FloatingTools: increase layer opacities (back 0.12, mid 0.22, front 0.35),
  add depth-of-field blur (1px back, 0.5px mid), radial vignette overlay,
  increase X oscillation amplitude from 3px to 8px
- BrandGradient: add center SnapOtter logo with subtle scale pulse, scatter
  faint tool names at 5% opacity for texture, add radial vignette
- FormatUniverse: replace buggy ghost badge duplicates with proper CSS opacity
  trail (3 copies at decreasing opacity: 1.0, 0.3, 0.1), increase logo pulse
  from 3% to 5% scale oscillation, add faint elliptical SVG orbit ring lines
  at 5% opacity behind each ring
2026-05-08 18:48:57 +08:00
SnapOtter f44c1a1d10 fix(videos): speed up The48 montage and fix micro-viz timing
- Reduce per-tool time from 15 to 10 frames (total montage: 480 frames)
- Update total composition duration from 840 to 600 frames in Root.tsx
- Increase micro-visualization from 2 to 4 frames for visibility
- Add varied entry paths: diagonal entries from all 8 directions instead
  of just left/right/top
- Adjust all act timings (grid pulse, category labels, tagline) to match
  the compressed timeline
2026-05-08 18:48:44 +08:00