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.
- 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.
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.
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.
Small bordered buttons with Minus/Plus icons flank the range slider,
allowing single-step quality adjustments. Disabled at min (1) and
max (100) boundaries.
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.
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.
- 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
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.
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.
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.
- 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
- 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
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.
- 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
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.
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
- 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
- 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
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.
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.
- 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
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.
- 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
- 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
- ToolPill: add box-shadow (0 2px 8px), gradient overlay for glossy depth,
subtle white border for definition
- ToolGalaxy: fix tagline so counter number appears before "tools. Zero cloud
dependency." text instead of being separated
Use real screenshots and sample photos from apps/videos/public/screenshots/
instead of CSS-gradient PhotoPlaceholder components:
- PipelineFlow: landscape photo for thumbnails with object-position variation
- AiMagicReel: portrait photo for bg removal, B&W photo for colorization,
landscape for super resolution and restoration segments
- PrivacyPromise: real portrait/landscape/B&W photos in shield, larger padlock
- OneCommand: real app-full.png screenshot instead of wireframe AppMockup,
increased amber glow to 12%
- CloudVsLocal: real portrait photos for all thumbnails, larger server icons
(36px), amplified shake (5px) and vibrate (3px), escalated red tint overlay
- ShieldIcon: increased stroke width to 3.5px, added gradient fill