Added max-w-4xl container constraint to ConversionHistory component to match
the FileConverter component width, creating a more consistent and aligned layout.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Fixed bug where conversion success toast was always showing "all conversions failed"
even when conversions succeeded. The issue was that the completion message was checking
the local jobs array (which still had status: 'pending') instead of tracking actual
conversion results.
Now using local successCount and failureCount variables that are incremented during
the conversion loop to accurately reflect conversion outcomes.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Settings features:
**Quality Preferences:**
- Default quality preset (High Quality, Balanced, Small File, Web Optimized)
**Behavior Preferences:**
- Auto-start conversion when files are selected
- Show/hide conversion history
- Clear history on reset
**Default Output Formats:**
- Set default format for video conversions (MP4, WebM, AVI, MOV)
- Set default format for audio conversions (MP3, WAV, OGG, AAC)
- Set default format for image conversions (WebP, PNG, JPG, GIF)
Implementation:
- Created settings storage system with localStorage
- SettingsModal component with categorized settings
- Settings button in app header
- Real-time settings updates across components
- Custom event system for settings synchronization
- Reset to defaults functionality
- Professional UI with checkboxes and selects
User experience:
- Settings persist across sessions
- Changes apply immediately
- Clear categorization (Quality, Behavior, Formats)
- Easy reset to defaults with confirmation
- Conditional history display based on settings
- Clean modal interface
Technical features:
- Type-safe settings interface
- Event-driven updates
- Graceful fallback to defaults
- Error handling for localStorage
- Platform-aware functionality
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Format presets included:
**Video Presets:**
- YouTube Video (1080p, H.264, optimized)
- Instagram Video (Square format, 1:1)
- Twitter Video (720p, small file)
- Web Optimized (Streaming, low bitrate)
**Audio Presets:**
- Podcast (MP3, voice optimized, 128k)
- High Quality Music (MP3, 320k)
- Audiobook (Mono, 64k, small size)
**Image Presets:**
- Web Thumbnail (JPG, 800px width)
- HD Image (PNG, lossless, high quality)
- Social Media (JPG, 1200px, optimized)
- Web Optimized (WebP, small size)
Implementation:
- Created formatPresets.ts with 11 predefined presets
- FormatPresets component with responsive grid layout
- One-click preset application
- Automatically configures format and options
- Toast notification on preset selection
- Visual feedback with ring highlight
- Organized by category (video/audio/image)
- Emoji icons for visual appeal
User experience:
- Quick access to common conversion scenarios
- No need to manually configure complex settings
- Preset descriptions explain use case
- Disabled during active conversion
- Clear visual indication of selected preset
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Error recovery features:
- **Retry button**: Appears on failed conversions
- **Smart retry logic**: Re-attempts conversion with same settings
- **State management**: Properly resets job state before retry
- **Progress tracking**: Shows progress during retry attempt
- **Toast notifications**: Informs user of retry success/failure
- **History updates**: Successful retries added to history
- **Visual feedback**: RefreshCw icon with clear button label
Implementation:
- Added onRetry prop to ConversionPreview component
- Implemented handleRetry function in FileConverter
- Reuses existing conversion logic for consistency
- Maintains all conversion options during retry
- Updates job status through proper state flow:
error → loading → processing → completed/error
User experience:
- One-click retry for failed conversions
- No need to re-upload file or reconfigure settings
- Clear visual indication when retry is in progress
- Helpful error messages if retry also fails
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Mobile optimizations:
- **Header**: Reduced padding on mobile (px-3), smaller text sizes
- **Main content**: Optimized padding (px-3 sm:px-4) and spacing
- **Format selector**: Added downward arrow for mobile flow
- **Conversion progress**: Time indicators stack vertically on mobile
- **Page layout**: Responsive spacing throughout (space-y-6 sm:space-y-8)
- **Footer**: Smaller text and reduced margins on mobile
Key improvements:
- Better use of screen space on small devices
- Improved touch targets and readability
- Consistent responsive breakpoints (sm:, md:)
- Vertical arrow (↓) on mobile, horizontal (→) on desktop
- All text scales appropriately for mobile screens
Tested on:
- Mobile viewport (< 640px)
- Tablet viewport (640px - 768px)
- Desktop viewport (> 768px)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Features:
- Created ConversionHistory component showing recent conversions
- Displays input/output formats, file sizes, and timestamps
- Relative time display (e.g., "5 minutes ago", "2 hours ago")
- Clear all history functionality with confirmation
- Individual history item removal
- Real-time updates when new conversions complete
- Custom event system for same-page updates
- Storage event listener for cross-tab synchronization
- Empty state with helpful messaging
- Clean, organized card-based layout
- Responsive design with proper spacing
Technical improvements:
- Enhanced history storage to dispatch custom events
- History component auto-refreshes on new conversions
- Maintains up to 10 most recent conversions
- Integrated seamlessly into main page layout
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Major improvements:
- Updated FileUpload component to support multiple file selection
- Added drag-and-drop for multiple files
- Individual file removal
- "Add More Files" button when files are selected
- Modified FileConverter to handle batch conversions
- Sequential conversion of multiple files
- Progress tracking for each file individually
- All files share same output format and settings
- Added batch download functionality
- Single file: direct download
- Multiple files: ZIP archive download
- Uses jszip library for ZIP creation
- Enhanced UI/UX
- Show count of selected files in convert button
- Display all conversion jobs with individual previews
- "Download All" button for completed conversions
- Conversion status messages show success/failure counts
Dependencies added:
- jszip@3.10.1 for ZIP file creation
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
The correct ImageMagick WASM API is:
image.write(format, callback)
Where the format is passed as the first argument and the callback
receives the encoded data. This should produce valid WebP with
correct RIFF headers.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
The correct API pattern is:
1. Set image.format = outputFormatEnum first
2. Then call image.write(callback) with the format already set
This ensures the image is written in the correct format with proper
headers (RIFF for WebP, etc.)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Changed from image.write((data) => data) callback pattern to
image.write(outputFormatEnum) which correctly writes the image data
in the specified format. This should now produce valid WebP files
with proper RIFF headers (52 19 46 46 magic bytes).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
The previous implementation was producing invalid image data with
wrong magic bytes (d0 e5 67 00 instead of 52 49 46 46 for WebP).
Root cause: Incorrect usage of ImageMagick write API.
Changes:
- Set image.format BEFORE writing (tells ImageMagick the output format)
- Simplified write() call to: image.write((data) => data)
- This returns the correctly formatted image data
The proper pattern is:
1. Set image.format = outputFormatEnum
2. Apply transformations (quality, resize)
3. Call image.write() which returns the encoded data
This should now produce valid WebP files with correct RIFF header
(52 49 46 46) and allow the preview to display properly.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Added detailed logging at every step of the image conversion and preview:
ImageMagick Service:
- Log input and output sizes
- Log applied quality settings
- Verify result is not empty before creating blob
- Log created blob size and MIME type
- Fail early if conversion produces empty result
Preview Component:
- Log blob details (size, type, URL)
- Add onError handler to img tag with detailed error info
- Add onLoad handler to confirm successful loading
- Console logs will help identify:
- Is the blob empty?
- Is the MIME type correct?
- Is the object URL valid?
- What error occurs when loading?
TypeScript Fix:
- Changed result type to `Uint8Array | undefined`
- Allows proper checking before blob creation
This will help diagnose why the preview image appears broken
despite successful conversion.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Added comprehensive logging to diagnose the WASM loading issue:
- Log the WASM URL being fetched
- Log fetch response (status, content-type, content-length)
- Log actual WASM file size after fetching
- Verify the buffer is not empty before initialization
- Pass ArrayBuffer directly to initializeImageMagick
- Better error messages with context
This will help identify why the WASM file appears empty:
- Is the fetch failing? (wrong path, 404, CORS)
- Is the response empty? (server issue)
- Is the content-type wrong? (misconfigured server)
The logs will appear in the browser console when converting images.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
The previous approach tried to load the WASM file from a CDN or node_modules,
which resulted in an empty buffer error. This fix copies the WASM file to the
public directory so it can be served alongside the static export.
Changes:
- Copy magick.wasm (16MB) to public/wasm/ directory
- Update wasmLoader.ts to initialize with '/wasm/magick.wasm' URL
- Initialize ImageMagick only once in loadImageMagick()
- Remove redundant initialization from imagemagickService.ts
- WASM file is now served from static assets in production
This ensures:
- WASM file is accessible at runtime
- Proper initialization before image conversions
- No "empty buffer" compilation errors
- Works in both dev and production (static export)
The 16MB WASM file includes the full ImageMagick library with all
image format support and processing capabilities.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
The initializeImageMagick() function requires a URL argument pointing
to the WASM file. Without it, the library won't properly load and
conversions may fail.
Changes:
- Add initializeImageMagick() call with CDN URL
- Use jsDelivr CDN for magick.wasm file
- Matches the installed package version (0.0.30)
This ensures ImageMagick WASM is properly initialized before performing
image conversions, preventing potential runtime errors.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Previously, the ImageMagick service was just a placeholder that returned
the input data unchanged. This caused PNG to WebP conversions to have
the same file size.
Changes:
- Properly implement ImageMagick.read() with conversion logic
- Apply imageQuality option to control compression
- Apply imageWidth/imageHeight options with aspect ratio preservation
- Use correct MagickFormat enum values for output formats
- Fix write() method signature (format comes before callback)
- Remove unnecessary initializeImageMagick() call
Image conversion now properly applies:
- Quality settings (1-100%)
- Resolution/resize options
- Format-specific compression
This fixes the issue where quality settings had no effect on output
file size. Users will now see proper file size reduction when using
lower quality settings or converting to compressed formats like WebP.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This major update adds powerful format-specific controls, quality presets,
file metadata display, and enhanced progress feedback to significantly
improve the user experience.
New Components:
- ConversionOptionsPanel: Format-specific controls with collapsible advanced options
- Video options: codec selection (H.264, H.265, VP8, VP9), bitrate, resolution, FPS
- Audio options: codec selection, bitrate, sample rate, channels
- Image options: quality slider, width/height controls
- Quality Presets: One-click presets (High Quality, Balanced, Small File, Web Optimized)
- FileInfo: Displays file metadata including size, duration, dimensions
- Slider: Reusable slider component for quality/bitrate controls
- Select: Reusable dropdown component for codec/format selection
Enhanced Features:
- ConversionPreview improvements:
- Real-time elapsed time display
- Estimated time remaining calculation
- File size comparison (input vs output with % reduction/increase)
- Better visual status indicators with icons
- Enhanced loading states with detailed progress
- FileConverter integration:
- Passes conversion options to converter services
- Manages conversion options state
- Resets options on file reset
UI/UX Improvements:
- Format-specific option panels that adapt to selected output format
- Visual preset buttons with icons and descriptions
- Collapsible advanced options to reduce clutter
- Better progress feedback with time estimates
- File size comparison badges showing compression results
- Smooth animations and transitions (existing animations already in place)
- Responsive design for all new components
Technical Details:
- Options are properly typed and integrated with ConversionOptions interface
- All components support disabled states during conversion
- Preview component calculates speed and estimates remaining time
- Metadata extraction for video/audio/image files using browser APIs
- Proper cleanup of object URLs and timers
User Benefits:
- Power users can fine-tune codec, bitrate, resolution settings
- Beginners can use quality presets with confidence
- Better understanding of conversion progress and file size impact
- Informed decisions with file metadata display
- Professional-grade control over output quality
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Install docx (v9.5.1) and mammoth (v1.11.0) packages
- Create docxService.ts with full DOCX read/write functionality:
- Extract text, HTML, and Markdown from DOCX files using mammoth
- Generate DOCX files from Markdown with proper heading levels (H1-H3)
- Generate DOCX files from HTML and plain text
- Automatic paragraph formatting and spacing
- Integrate DOCX conversions into pandocService.ts
- Update README with DOCX support documentation
- Add DOCX libraries to tech stack section
Supported DOCX conversions:
- DOCX → Text/HTML/Markdown
- Markdown/HTML/Text → DOCX
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add jsPDF for PDF generation from text/Markdown/HTML
- Add PDF.js for PDF text extraction (read PDFs)
- Support PDF → Text/Markdown conversions
- Support Markdown/HTML/Text → PDF conversions
- Implement page-by-page PDF text extraction
- Automatic pagination and formatting for generated PDFs
Supported PDF operations:
- Extract text from PDF files (all pages)
- Convert PDF to Markdown or plain text
- Create formatted PDFs from Markdown, HTML, or plain text
- Automatic text wrapping and page breaks
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add marked for Markdown to HTML conversion with GFM support
- Add turndown for HTML to Markdown conversion
- Add DOMPurify for HTML sanitization (security)
- Support Markdown ↔ HTML ↔ Plain Text conversions
- Add styled HTML output with responsive design
- Use client-side only DOMPurify to fix SSR issues
Supported conversions:
- Markdown → HTML (with code syntax, tables, blockquotes)
- HTML → Markdown (clean formatting preservation)
- Markdown/HTML → Plain Text (strip formatting)
- Plain Text → HTML/Markdown (basic formatting)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Switch from VP9 to VP8 codec for WebM (less memory-intensive)
- Add realtime encoding deadline and fast CPU preset
- Add ultrafast preset for x264 encoding
- Set explicit bitrates to control memory usage
- Use libvorbis instead of libopus for better compatibility
This fixes "memory access out of bounds" errors during video conversion
in browser environments with limited WASM memory.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add multi-stage Dockerfile for static build
- Add nginx configuration with COOP/COEP headers for FFmpeg.wasm
- Add .dockerignore for optimized builds
- Enable SharedArrayBuffer support via security headers
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add Next.js 16 with Turbopack and React 19
- Add Tailwind CSS 4 with OKLCH color system
- Implement FFmpeg.wasm for video/audio conversion
- Implement ImageMagick WASM for image conversion
- Add file upload with drag-and-drop
- Add format selector with fuzzy search
- Add conversion preview and download
- Add conversion history with localStorage
- Add dark/light theme support
- Support 22+ file formats across video, audio, and images
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>