Merge pull request 'cleanup' (#12) from review-opti into main

Reviewed-on: #12
This commit was merged in pull request #12.
This commit is contained in:
2026-03-12 11:00:23 -05:00
7 changed files with 148 additions and 2173 deletions

View File

@@ -1,167 +0,0 @@
# Docker Build Fix - Simplified Dependency Installation
## Issue
Docker build was failing with:
```
npm error The `npm ci` command can only install with an existing package-lock.json
```
## Root Cause
The original Dockerfile used `npm ci` which requires fully resolved `package-lock.json` files. These lockfiles were missing and stub lockfiles don't work because `npm ci` requires the complete dependency tree.
## Solution Applied
### Simplified Approach
The Dockerfile now uses **`npm install`** instead of `npm ci`. This is simpler and more reliable:
```dockerfile
RUN npm install
```
**Why this works:**
- ✅ No lockfile required
- ✅ Automatically resolves and installs all dependencies
- ✅ Works consistently across all environments
- ✅ No manual lockfile maintenance needed
- ✅ Simpler Dockerfile = easier to maintain
### Trade-offs
| Approach | Speed | Lockfile Required | Deterministic | Maintenance |
|----------|-------|-------------------|---------------|-------------|
| `npm ci` | Fastest | ✅ Yes | ✅ Yes | High |
| **`npm install`** | Fast | ❌ No | ⚠️ By version ranges | **Low** |
**Note:** While `npm install` resolves versions at build time (not 100% deterministic), your `package.json` uses caret ranges (e.g., `^4.19.0`) which only allow minor/patch updates, providing reasonable stability.
### Files Modified
1. **Dockerfile** - Simplified to use `npm install` in all three stages
2. **.dockerignore** - Optimizes build context
3. **backend/package.json** - Updated multer to v2.1.0 (v1.4.5 no longer exists)
### Dependency Updates
- **multer**: `^1.4.5``^2.1.0` (security fixes, v1.x removed from npm)
- **@types/multer**: `^1.4.7``^2.1.0` (matching types)
## How It Works
### Build Flow
1. **Copy package.json** into build stage
2. **Run npm install** - automatically resolves and installs all dependencies
3. **Build the application**
No lockfile generation or validation needed!
## Usage
### Build Docker Image
```bash
docker build -t pnger:latest .
```
The build will:
- Install dependencies from npm registry
- Build frontend and backend
- Create production image with only runtime dependencies
- Complete successfully every time
### Run Container
```bash
docker run -d \
-p 3000:3000 \
-e MAX_FILE_SIZE=10485760 \
--name pnger \
pnger:latest
```
### Unraid Deployment
The Docker image builds cleanly in Unraid without any configuration needed.
## Optional: Add Lockfiles for Deterministic Builds
If you want 100% deterministic builds with locked dependency versions:
```bash
# Generate lockfiles locally
cd frontend && npm install && cd ..
cd backend && npm install && cd ..
# Commit them
git add frontend/package-lock.json backend/package-lock.json
git commit -m "Add lockfiles for deterministic builds"
# Update Dockerfile to use npm ci instead of npm install
```
**Benefits of lockfiles:**
- Guaranteed exact dependency versions
- Slightly faster builds
- Better for production environments
**Drawbacks:**
- Must update lockfiles when changing dependencies
- More complex maintenance
## Build Optimization
The `.dockerignore` file excludes:
- `node_modules/` (prevents copying local dependencies)
- Development files (`.env`, `.vscode/`, etc.)
- Build artifacts
- Documentation and test files
This keeps build context small and fast.
## Verification
Test the complete build:
```bash
# Build image
docker build -t pnger:test .
# Run container
docker run -d -p 3000:3000 --name pnger-test pnger:test
# Check health
curl http://localhost:3000
# View logs
docker logs pnger-test
# Cleanup
docker stop pnger-test && docker rm pnger-test
```
## Technical Details
### Multi-Stage Build
1. **frontend-builder**: Builds Svelte/Vite frontend with all dev dependencies
2. **backend-builder**: Compiles TypeScript backend with all dev dependencies
3. **production**: Combines compiled outputs with production dependencies only (`--omit=dev`)
### Security Features
- Runs as non-root user (`node`)
- Health check endpoint configured
- Minimal production dependencies
- Alpine Linux base (smaller attack surface)
- No unnecessary dev tools in production image
### Multer v2.1.0 Upgrade
Upgraded from v1.4.5 (no longer available) to v2.1.0:
- ✅ Security fixes (CVE-2026-2359 and others)
- ✅ Backward compatible API
- ✅ Better performance
- ✅ Active maintenance
---
**Created**: 2026-03-08
**Branch**: `fix/add-package-lockfiles`
**Status**: Ready to merge
**Issue**: Docker build failing ✅ RESOLVED

View File

@@ -1,86 +1,76 @@
# PNGer Development Instructions
# PNGer Development & Technical Instructions
## Project Overview
PNGer is a single-container web application for PNG editing and resizing, designed for deployment on Unraid with Gitea version control.
## Development Roadmap
### Phase 1: MVP Foundation (Completed ✅)
- [x] Repository setup
- [x] Project structure initialization
- [x] Backend API scaffold
- [x] Frontend scaffold
- [x] Basic upload/download flow
- [x] Dockerfile configuration
- [x] Live preview implementation
- [x] Dark/light mode theming
- [x] Image resize and compression
- [x] Format conversion (PNG, WebP, JPEG)
### Phase 2: Sprint 1 - Enhanced UX (Completed ✅)
- [x] Drag & drop file upload
- [x] Clipboard paste (Ctrl+V)
- [x] Smart presets (8 configurations)
- [x] Keyboard shortcuts (Enter, Ctrl+Enter, ?, Esc)
- [x] Enhanced visual feedback
- [x] Responsive UI improvements
- [x] Theme contrast fixes
### Phase 3: Advanced Features (Upcoming)
- [ ] Batch processing
- [ ] Advanced crop tool with visual selector
- [ ] Watermarking
- [ ] Image filters and effects
- [ ] Undo/redo functionality
- [ ] History/recent files
PNGer is a single-container web application for PNG editing and resizing, designed for deployment on Unraid with Gitea version control. It features a modern Svelte frontend and a high-performance Node.js/Sharp backend.
## Technical Architecture
### Architecture Overview
PNGer uses a multi-layered architecture designed for responsiveness and efficiency:
```mermaid
graph TD
A[User Browser] --> B[Svelte Frontend]
B --> C[Canvas API (Live Preview)]
B --> D[Express API (Backend)]
D --> E[Sharp Image Library]
D --> F[Runtime Environment (Docker)]
```
### Backend (Express + Sharp)
**Endpoints:**
The backend is built with Node.js and TypeScript, using Express for the API and Sharp for high-performance image processing.
**Key Endpoints:**
- `POST /api/transform` - Transform image (resize, crop, compress, convert)
- `GET /api/health` - Health check
**Key Dependencies:**
- express: Web framework
- multer: File upload handling
- sharp: Image processing
- cors: Cross-origin support
- `sharp`: High-performance image processing (handles resizing, cropping, and format conversion).
- `multer`: Middleware for handling `multipart/form-data`, used for file uploads.
- `express`: Web framework for the API.
### Frontend (Svelte + Vite)
**Components:**
- `App.svelte` - Main container with all features
- `lib/api.ts` - API client
- `lib/preview.ts` - Live preview logic using Canvas API
- `lib/theme.ts` - Dark/light theme management
- `lib/presets.ts` - Smart presets configuration
The frontend is a reactive Svelte application that prioritizes real-time feedback and UX.
**Key Features:**
- Drag & drop upload
- Clipboard paste support
- Real-time preview (debounced 300ms)
- Side-by-side comparison
- File size analysis
- 8 smart presets
- Keyboard shortcuts
- Persistent theme preference
**Core Components & Modules:**
- `App.svelte`: Main application container managing state and UI.
- `lib/api.ts`: API client for backend communication.
- `lib/preview.ts`: Client-side preview logic using the Canvas API for instant feedback.
- `lib/theme.ts`: Dark/light theme management with persistent storage.
- `lib/presets.ts`: Configuration for smart image presets.
**Key Dependencies:**
- svelte: Reactive framework
- vite: Build tool
- axios: HTTP client
### Design System (Dark/Light Modes)
### Docker Strategy
The UI uses a modern design system with CSS custom properties for theming:
- **Light Mode**: Clean white background with dark gold (`#b8860b`) accents.
- **Dark Mode**: Deep black (`#0a0a0a`) background with light gold (`#daa520`) accents.
- **Transparencies**: Dark/Light toggling allows users to inspect PNG transparency against different backgrounds.
**Multi-stage Build:**
1. Stage 1: Build frontend (Vite build)
2. Stage 2: Copy frontend + setup backend
3. Final image: Alpine-based Node.js
## Implementation Details
**Image Size Target:** < 150MB
### Live Preview System
Live preview is implemented using a client-side Canvas-based approach to provide instant feedback (< 100ms) without server round-trips.
**How it works:**
1. User uploads an image.
2. The browser loads the image into an HTML5 Canvas.
3. On any parameter change (width, quality, etc.), a debounced (300ms) update applies transformations to the canvas.
4. The canvas content is displayed side-by-side with the original for comparison.
5. File sizes are estimated from the Canvas data URL to provide immediate feedback on optimization savings.
### Docker Strategy & Fixes
PNGer uses a multi-stage Docker build to minimize image size and maximize security.
**Optimization Fixes applied:**
- **Dependency Installation**: Uses `npm install` instead of `npm ci` to handle missing lockfiles gracefully while maintaining stability via caret ranges in `package.json`.
- **Security**: Runs as a non-root `node` user in the final Alpine-based image.
- **Multer Upgrade**: Upgraded to `v2.1.0` for improved security and performance.
## Local Development Setup
@@ -89,7 +79,7 @@ PNGer is a single-container web application for PNG editing and resizing, design
- npm or pnpm
- Docker (optional)
### Initial Setup
### Setup Steps
```bash
# Clone repository
@@ -101,259 +91,44 @@ cd backend
npm install
npm run dev
# Setup frontend (new terminal)
# Setup frontend (separate terminal)
cd frontend
npm install
npm run dev
```
### Development Workflow
1. **Feature Branch**: Create from `main`
2. **Develop**: Make changes with hot-reload
3. **Test**: Manual testing + health checks
4. **Commit**: Descriptive commit messages
5. **Push**: Push to Gitea
6. **Review**: Self-review changes
7. **Merge**: Merge to `main`
### Environment Variables
**Backend (.env):**
```
PORT=3000
NODE_ENV=development
MAX_FILE_SIZE=10485760
CORS_ORIGIN=http://localhost:5173
```
- `PORT`: 3000 (internal)
- `MAX_FILE_SIZE`: 10485760 (10MB default)
- `CORS_ORIGIN`: http://localhost:5173
**Frontend (.env):**
```
VITE_API_URL=http://localhost:3000/api
```
- `VITE_API_URL`: http://localhost:3000/api
## Docker Build & Test
## Development Workflow & Standards
```bash
# Build image
docker build -t pnger:test .
### Workflow
1. **Feature Branch**: Create from `main`.
2. **Develop**: Use hot-reload (`npm run dev`).
3. **Test**: Perform manual testing of image operations and presets.
4. **Commit**: Use `type: description` format (e.g., `feat: add rotation`).
5. **Merge**: Merge into `main` after review.
# Run container
docker run -p 8080:3000 --name pnger-test pnger:test
# Test endpoints
curl http://localhost:8080/api/health
# View logs
docker logs pnger-test
# Stop and remove
docker stop pnger-test && docker rm pnger-test
```
## Unraid Deployment
### Setup Steps
1. **SSH into Unraid**
2. **Navigate to docker configs**: `/mnt/user/appdata/pnger`
3. **Clone repository**:
```bash
git clone https://git.alwisp.com/jason/pnger.git
cd pnger
```
4. **Build and run**:
```bash
docker-compose up -d
```
5. **Access**: http://[unraid-ip]:8080
### Update Process
```bash
cd /mnt/user/appdata/pnger
git pull origin main
docker-compose down
docker-compose build
docker-compose up -d
```
## Code Standards
### JavaScript/TypeScript
- Use ES6+ features
- Async/await for asynchronous operations
- Descriptive variable names
- Comments for complex logic only
- Type safety with TypeScript
### File Organization
- One component per file
- Group related utilities
- Keep components under 300 lines (split if larger)
- Organize by feature when possible
### Commit Messages
- Format: `type: description`
- Types: feat, fix, docs, style, refactor, test, chore
- Example: `feat: add drag and drop upload`
- Be specific and descriptive
## Feature Implementation Notes
### Drag & Drop Upload
- Uses HTML5 Drag and Drop API
- Visual feedback on dragover/dragleave
- File type validation on drop
- Falls back to file input for browser support
### Clipboard Paste
- Listens for paste events on document
- Extracts image from clipboard items
- Supports screenshots and copied images
- Works across all major browsers
### Smart Presets
- 8 predefined configurations:
1. Web Optimized (1920x1080, 80%, WebP)
2. Social Media (1080x1080, 85%, JPEG)
3. Profile Picture (400x400, 90%, PNG)
4. Email Friendly (800x600, 75%, JPEG)
5. Tiny Icon (64x64, 100%, PNG)
6. Retina 2x (2x size, 90%)
7. Icon Small (256x256, 95%, PNG)
8. Icon Large (512x512, 95%, PNG)
- Applies all settings with one click
- Visual icons for easy identification
### Keyboard Shortcuts
- Global document listeners
- Context-aware Enter key (checks focus)
- Help dialog with ? key
- Esc to close dialogs
- Cross-platform support (Ctrl/Cmd)
### Live Preview
- Client-side Canvas API rendering
- Debounced updates (300ms)
- Reactive state management
- Automatic size estimation
- Side-by-side comparison
### Code Standards
- **TypeScript**: Use strict types where possible.
- **Svelte**: Keep components modular and under 300 lines.
- **Async/Await**: Use for all asynchronous operations.
- **Semantic HTML**: Ensure accessibility and proper structure.
## Troubleshooting
### Common Issues
- **Port in use**: `lsof -ti:3000 | xargs kill -9`
- **Sharp issues**: `npm rebuild sharp`
- **Docker Cache**: `docker builder prune` if builds fail unexpectedly.
- **Preview Glitches**: Check browser console for Canvas API errors.
**Port already in use:**
```bash
lsof -ti:3000 | xargs kill -9
```
---
**Sharp installation issues:**
```bash
npm rebuild sharp
```
**Docker build fails:**
- Check Docker daemon is running
- Verify Dockerfile syntax
- Clear Docker cache: `docker builder prune`
**Preview not updating:**
- Check browser console for errors
- Verify Canvas API support
- Clear browser cache
**Drag & drop not working:**
- Check file type validation
- Verify event handlers are attached
- Test with different browsers
## Performance Targets
- Upload handling: < 100ms (for 5MB file)
- Image processing: < 2s (for 10MP image)
- Download generation: < 500ms
- UI response time: < 100ms
- Preview generation: < 500ms (client-side)
- Docker image size: < 150MB
## Security Considerations
- File type validation (image/* only)
- File size limits (10MB default, configurable)
- No persistent storage of user files
- Memory cleanup after processing
- CORS configuration
- Input sanitization
- Error message sanitization (no path disclosure)
## Testing Checklist
### Upload Methods
- [ ] File input (click to browse)
- [ ] Drag & drop
- [ ] Clipboard paste (Ctrl+V)
- [ ] File validation errors
- [ ] Size limit handling
### Image Operations
- [ ] Resize with width only
- [ ] Resize with height only
- [ ] Resize with both dimensions
- [ ] Crop to fit (cover mode)
- [ ] All 9 crop positions
- [ ] Format conversion (PNG, WebP, JPEG)
- [ ] Quality adjustment
### Presets
- [ ] All 8 presets apply correctly
- [ ] Preset values match specifications
- [ ] Visual feedback on selection
### Keyboard Shortcuts
- [ ] Ctrl+V pastes image
- [ ] Enter downloads (not in input)
- [ ] Ctrl+Enter downloads (anywhere)
- [ ] ? shows help dialog
- [ ] Esc closes dialog
### UI/UX
- [ ] Theme toggle works
- [ ] Theme persists on reload
- [ ] Live preview updates
- [ ] File size analysis accurate
- [ ] Error messages clear
- [ ] Loading states visible
- [ ] Responsive on mobile
### Browser Compatibility
- [ ] Chrome/Edge
- [ ] Firefox
- [ ] Safari
- [ ] Mobile browsers
## Next Steps
1. ✅ Create backend folder structure
2. ✅ Create frontend folder structure
3. ✅ Initialize package.json files
4. ✅ Create Dockerfile
5. ✅ Create docker-compose.yml
6. ✅ Implement MVP features
7. ✅ Add drag & drop upload
8. ✅ Add clipboard paste
9. ✅ Add smart presets
10. ✅ Add keyboard shortcuts
11. [ ] Implement batch processing
12. [ ] Add advanced crop tool
13. [ ] Add watermarking
14. [ ] Add filters/effects
## Resources
- [Sharp Documentation](https://sharp.pixelplumbing.com/)
- [Svelte Documentation](https://svelte.dev/docs)
- [Canvas API Reference](https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API)
- [Drag and Drop API](https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API)
- [Clipboard API](https://developer.mozilla.org/en-US/docs/Web/API/Clipboard_API)
**Last Updated**: March 12, 2026

346
README.md
View File

@@ -1,341 +1,49 @@
# PNGer - Modern PNG Editor & Resizer
A sleek, modern PNG editor and resizer with **live preview**, **drag & drop**, **smart presets**, **keyboard shortcuts**, and **dark/light mode theming**. Built with TypeScript and deployed as a single Docker container on Unraid.
A sleek, modern PNG editor and resizer with **live preview**, **drag & drop**, **smart presets**, **keyboard shortcuts**, and **dark/light mode theming**. Built with TypeScript and optimized for deployment as a single Docker container.
## ✨ Features
### 🎨 Modern UI with Dark/Light Mode
- **Dark Mode**: Black background (#0a0a0a) with light gold (#daa520) accents
- **Light Mode**: White background with dark gold (#b8860b) accents
- Perfect for inspecting PNG transparency on different backgrounds
- Persistent theme preference
- Smooth color transitions
- **🎨 Modern UI**: Beautiful dark/light mode for inspecting transparency.
- **⚡ Live Preview**: Instant side-by-side comparison with file size analysis.
- **🚀 Efficiency**: Drag & Drop upload, clipboard paste (`Ctrl+V`), and smart presets.
- **🖼️ Precision**: Control width, height, quality, and crop positions (9 modes).
- **📦 Reliable Deployment**: Multi-stage Docker build optimized for Unraid and Gitea.
### ⚡ Live Preview
- **Real-time preview** of transformations before download
- **Side-by-side comparison** (original vs transformed)
- **File size analysis** showing savings or increase
- **Instant feedback** using client-side Canvas API (< 500ms)
- No server round-trip needed for preview
## 🚀 Quick Start
### 🖼️ Image Operations
- **Resize Operations**: Width, height, and aspect ratio controls
- **Crop to Fit**: Smart cropping with position control (9 positions)
- **Format Conversion**: PNG, WebP, and JPEG output
- **Quality Control**: Adjustable compression settings (10-100%)
- **Fit Modes**: Inside (resize only) or Cover (crop to fill)
### 🚀 Performance & Usability
- **Drag & Drop**: Drag images directly into the app or use file browser
- **Clipboard Paste**: Paste images with Ctrl+V (Cmd+V on Mac)
- **Smart Presets**: Quick access to common configurations:
- 📷 Web Optimized (1920x1080, 80% quality, WebP)
- 📱 Social Media (1080x1080, 85% quality, JPEG)
- 👤 Profile Picture (400x400, 90% quality, PNG)
- 📧 Email Friendly (800x600, 75% quality, JPEG)
- ⭐ Tiny Icon (64x64, 100% quality, PNG)
- 🔍 Retina 2x (2x dimensions, 90% quality)
- 💎 Icon Small (256x256, 95% quality, PNG)
- 🔶 Icon Large (512x512, 95% quality, PNG)
- **Keyboard Shortcuts**: Fast workflow with keyboard controls (see below)
- **Direct Download**: No server-side storage, immediate download
- **Modern UI**: Sleek, responsive TypeScript/Svelte design
- **File Analysis**: Original size, transformed size, savings percentage
- **Debounced Updates**: Smooth preview generation (300ms delay)
- **Visual Feedback**: Loading states, error messages, success indicators
### ⌨️ Keyboard Shortcuts
- **Ctrl+V** (Cmd+V): Paste image from clipboard
- **Enter**: Transform & Download (works when input not focused)
- **Ctrl+Enter** (Cmd+Enter): Transform & Download (works anywhere)
- **?**: Show/hide keyboard shortcuts help
- **Esc**: Close shortcuts dialog
## Tech Stack
- **Frontend**: Svelte 4 + Vite + TypeScript
- **Backend**: Node.js + Express + TypeScript
- **Image Processing**: Sharp (high-performance image library)
- **Preview**: Canvas API (client-side)
- **Container**: Docker (Alpine-based, multi-stage build)
- **Deployment**: Unraid via Docker Compose
## Quick Start
### Unraid Deployment (Recommended)
1. **Clone or pull this repository to your Unraid server:**
### Docker/Unraid Deployment
1. **Clone & Build**:
```bash
cd /mnt/user/appdata
git clone https://git.alwisp.com/jason/pnger.git
cd pnger
```
2. **Build the Docker image:**
```bash
docker build -t pnger:latest .
```
3. **Run via docker-compose:**
2. **Run**:
```bash
docker compose up -d
```
3. **Access**: `http://localhost:8080` (or your Unraid IP)
4. **Access the application:**
- Navigate to `http://[unraid-ip]:8080`
### Local Development
1. **Install & Run Backend**: `cd backend && npm install && npm run dev`
2. **Install & Run Frontend**: `cd frontend && npm install && npm run dev`
3. **Access**: `http://localhost:5173`
### Unraid Environment Variables (Configurable via UI)
## 📚 Documentation
When setting up in Unraid Docker UI, you can configure:
For more detailed information, please refer to:
- **[INSTRUCTIONS.md](./INSTRUCTIONS.md)**: Technical architecture, development setup, code standards, and troubleshooting.
- **[ROADMAP.md](./ROADMAP.md)**: Project history, sprint updates, and future feature plans.
| Variable | Default | Description |
|----------|---------|-------------|
| `HOST_PORT` | `8080` | External port to access the app |
| `MAX_FILE_SIZE` | `10485760` | Max upload size in bytes (10MB default) |
| `MEM_LIMIT` | `512m` | Memory limit for container |
| `CPU_LIMIT` | `1.0` | CPU limit (1.0 = 1 full core) |
| `NODE_ENV` | `production` | Node environment |
## ⌨️ Keyboard Shortcuts
### Unraid Docker Template Example
- `Ctrl+V`: Paste image from clipboard
- `Enter`: Download (when input not focused)
- `?`: Show shortcuts help
- `Esc`: Close dialogs
```xml
<?xml version="1.0"?>
<Container version="2">
<Name>pnger</Name>
<Repository>pnger:latest</Repository>
<Network>bridge</Network>
<Privileged>false</Privileged>
<WebUI>http://[IP]:[PORT:8080]</WebUI>
<Config Name="WebUI Port" Target="3000" Default="8080" Mode="tcp" Description="Port for web interface" Type="Port" Display="always" Required="true" Mask="false">8080</Config>
<Config Name="Max File Size" Target="MAX_FILE_SIZE" Default="10485760" Mode="" Description="Maximum upload file size in bytes" Type="Variable" Display="advanced" Required="false" Mask="false">10485760</Config>
<Config Name="Memory Limit" Target="" Default="512m" Mode="" Description="Container memory limit" Type="Variable" Display="advanced" Required="false" Mask="false">512m</Config>
</Container>
```
---
## Local Development
### Prerequisites
- Node.js 20+
- npm or yarn
### Setup
1. **Install backend dependencies:**
```bash
cd backend
npm install
```
2. **Install frontend dependencies:**
```bash
cd frontend
npm install
```
3. **Run development servers:**
Terminal 1 (Backend):
```bash
cd backend
npm run dev
```
Terminal 2 (Frontend):
```bash
cd frontend
npm run dev
```
4. **Access dev server:**
- Frontend: `http://localhost:5173`
- Backend API: `http://localhost:3000/api`
### Building for Production
```bash
# Backend TypeScript compilation
cd backend
npm run build
# Frontend build
cd frontend
npm run build
```
## Docker Deployment (Manual)
```bash
# Build the image (all dependencies and builds are handled internally)
docker build -t pnger:latest .
# Run the container
docker run -d \
--name pnger \
-p 8080:3000 \
-e MAX_FILE_SIZE=10485760 \
--restart unless-stopped \
pnger:latest
```
## Project Structure
```
pnger/
├── frontend/ # Svelte + TypeScript application
│ ├── src/
│ │ ├── App.svelte # Main UI component (with live preview)
│ │ ├── main.ts # Entry point
│ │ ├── app.css # Design system (dark/light modes)
│ │ └── lib/
│ │ ├── api.ts # API client
│ │ ├── preview.ts # Live preview logic
│ │ ├── theme.ts # Theme management store
│ │ └── presets.ts # Smart presets configuration
│ ├── package.json
│ ├── tsconfig.json
│ └── vite.config.ts
├── backend/ # Express + TypeScript API server
│ ├── src/
│ │ ├── index.ts # Express server
│ │ ├── routes/
│ │ │ └── image.ts # Image transform endpoint
│ │ └── types/
│ │ └── image.ts # TypeScript types
│ ├── package.json
│ └── tsconfig.json
├── Dockerfile # Multi-stage build (frontend + backend)
├── docker-compose.yml # Unraid deployment config
├── ROADMAP.md # Feature roadmap
├── SPRINT1_CHANGES.md # Sprint 1 implementation details
└── UI_UPGRADE_NOTES.md # UI upgrade documentation
```
## How It Works
1. User uploads an image via drag & drop, file browser, or clipboard paste
2. **Live preview** generates instantly using Canvas API
3. User adjusts parameters (width, height, quality, format, etc.) or selects a preset
4. Preview updates in real-time (debounced 300ms)
5. User sees file size comparison and savings
6. When satisfied, user clicks "Transform & Download" or presses Enter
7. Frontend sends image + parameters to backend API
8. Backend processes using Sharp (resize, crop, compress, convert)
9. Processed image returned directly to browser
10. Browser triggers automatic download
11. No files stored on server (stateless operation)
## API Endpoints
### POST /api/transform
Transform an image with resize, crop, and format conversion.
**Request:**
- Method: `POST`
- Content-Type: `multipart/form-data`
- Body:
- `file`: Image file (PNG/JPEG/WebP)
- `width`: Target width (optional)
- `height`: Target height (optional)
- `quality`: Quality 10-100 (optional, default: 80)
- `format`: Output format `png|webp|jpeg` (optional, default: `png`)
- `fit`: Resize mode `inside|cover` (optional, default: `inside`)
- `position`: Crop position when `fit=cover` (optional, default: `center`)
**Response:**
- Content-Type: `image/[format]`
- Body: Transformed image binary
## Configuration
All configuration is handled via environment variables passed through Docker/Unraid:
- `PORT`: Server port (default: `3000`, internal)
- `MAX_FILE_SIZE`: Maximum upload size in bytes (default: `10485760` = 10MB)
- `TEMP_DIR`: Temporary directory for uploads (default: `/app/temp`)
- `NODE_ENV`: Node environment (default: `production`)
## UI Features in Detail
### Dark/Light Mode
- **Toggle Button**: Sun (☀️) / Moon (🌙) icon in header
- **Persistent**: Saved to localStorage
- **System Detection**: Uses OS preference on first visit
- **Smooth Transitions**: Colors fade smoothly (250ms)
- **Use Case**: Compare PNG transparency on black vs white backgrounds
### Live Preview
- **Side-by-Side**: Original image on left, preview on right
- **File Size**: Shows before and after sizes
- **Savings Indicator**: Green for reduction, yellow for increase
- **Instant Updates**: Debounced at 300ms for smooth performance
- **Canvas-Based**: No server load, runs in browser
### Drag & Drop Upload
- **Drop Zone**: Large, responsive drop target with visual feedback
- **Multiple Methods**: Drag & drop, click to browse, or paste from clipboard
- **File Validation**: Instant validation with clear error messages
- **Visual States**: Hover and dragging states for better UX
### Smart Presets
- **8 Pre-configured Options**: Common use cases ready to go
- **One-Click Apply**: Instantly sets all parameters
- **Visual Icons**: Easy identification of each preset
- **Responsive Grid**: Adapts to screen size
### Keyboard Shortcuts
- **Productivity Focused**: Common operations accessible via keyboard
- **Help Dialog**: Press ? to see all shortcuts
- **Context Aware**: Enter works differently based on focus
- **Cross-Platform**: Supports both Ctrl and Cmd modifiers
### Image Analysis
- Original file size displayed
- Preview size estimation
- Savings/increase percentage
- Visual feedback with color coding
## Recent Updates (Sprint 1)
**Drag & Drop Upload** - Drag images directly into the app
**Clipboard Paste** - Paste images with Ctrl+V
**Smart Presets** - 8 quick-access presets for common scenarios
**Keyboard Shortcuts** - Fast workflow with keyboard controls
**Enhanced UX** - Better visual feedback and error handling
**Theme Contrast Fixes** - Improved text visibility in both themes
See [SPRINT1_CHANGES.md](./SPRINT1_CHANGES.md) for detailed implementation notes.
## Roadmap
See [ROADMAP.md](./ROADMAP.md) for planned features including:
- Batch processing
- Advanced crop tool with visual selector
- Watermarking
- Image filters and effects
- And more!
## License
MIT License - See LICENSE file for details
## Repository
https://git.alwisp.com/jason/pnger
## Screenshots
### Light Mode
Clean white interface with dark gold accents, perfect for inspecting dark images
### Dark Mode
Sleek black interface with light gold accents, ideal for viewing light/transparent PNGs
### Live Preview
Side-by-side comparison showing original and transformed image with file size analysis
### Smart Presets
Quick-access buttons for common image optimization scenarios
### Keyboard Shortcuts
Built-in help dialog showing all available shortcuts
**License**: MIT
**Repository**: [https://git.alwisp.com/jason/pnger](https://git.alwisp.com/jason/pnger)

View File

@@ -1,385 +1,62 @@
# PNGer Feature Roadmap
PNGer is evolved through intentional sprints focusing on user experience, performance, and professional-grade features.
## Completed Features ✅
### Core Foundation
-Basic image upload (file picker, drag & drop, clipboard paste)
-Width/height resizing
-Aspect ratio control (inside/cover)
-Crop positioning (9 positions)
-Format conversion (PNG, WebP, JPEG)
- ✅ Quality adjustment (10-100%)
- ✅ Direct download (no server storage)
- ✅ Docker deployment
-**Live Preview** - Real-time side-by-side comparison with file size analysis
-**Dark/Light Mode** - Theme toggle for better PNG transparency inspection
-**Modern UI** - Sleek design with smooth transitions and visual feedback
### Sprint 0: Foundation (MVP)
-**Core Repository Setup**: Project structure and build systems.
-**Basic Image Operations**: Width/height resizing and quality adjustment.
-**Format Support**: Conversion between PNG, WebP, and JPEG.
-**Docker Deployment**: Multi-stage build for Unraid/Docker environments.
-**Stateless Processing**: Direct download from memory; no server storage.
### Sprint 1: Enhanced UX (Completed March 2026)
-**Drag & Drop Upload** - Drag images directly into the app
-**Clipboard Paste** - Paste with Ctrl+V (Cmd+V on Mac)
-**Smart Presets** - 8 quick-access presets:
- Web Optimized (1920x1080, 80%, WebP)
- Social Media (1080x1080, 85%, JPEG)
- Profile Picture (400x400, 90%, PNG)
- Email Friendly (800x600, 75%, JPEG)
- Tiny Icon (64x64, 100%, PNG)
- Retina 2x (2x dimensions, 90%)
- Icon Small (256x256, 95%, PNG)
- Icon Large (512x512, 95%, PNG)
-**Keyboard Shortcuts** - Fast workflow:
- Ctrl+V / Cmd+V: Paste image
- Enter: Transform & Download
- Ctrl+Enter / Cmd+Enter: Transform & Download (anywhere)
- ?: Show shortcuts help
- Esc: Close dialogs
-**Enhanced Visual Feedback** - Better loading states and error messages
-**Theme Contrast Fixes** - Improved text visibility in both themes
### Sprint 1: Enhanced UX & Live Preview (March 2026)
-**Live Preview**: Real-time side-by-side comparison with file size analysis.
-**Modern Design System**: Dark/Light mode toggle with persistent storage.
-**Drag & Drop Upload**: Intuitive drop zone with visual feedback.
- **Clipboard Paste**: Paste images directly with `Ctrl+V`.
- **Smart Presets**: 8 quick-access configurations for common use cases (Social Media, Web, Icons, etc.).
- **Keyboard Shortcuts**: Fast workflow with `Enter`, `?`, and `Esc`.
- **Performance Optimization**: Client-side Canvas rendering for instant feedback.
---
## Sprint 2: Batch Processing & Advanced Operations (Next Priority)
**Focus**: Handle multiple files and add essential image operations
**Effort**: ~12-15 hours | **Impact**: Very High | **Timeline**: Week 1-2
## Future Roadmap 🚀
### 2.1 Batch Processing 🚀 **HIGH VALUE**
**Why**: Process multiple images at once - massive time saver for bulk operations
**Effort**: Medium (6-8 hours) | **Impact**: Very High
### Sprint 2: Batch Processing & Advanced Operations
**Focus**: Efficiency and essential power-user tools.
- [ ] **Batch Processing**: Upload multiple images and process as a single ZIP.
- [ ] **Basic Transformations**: Rotate (90/180/Custom), Flip (H/V), and Grayscale.
- [ ] **Content-Aware Resize**: Smart cropping and aspect ratio enforcement.
- [ ] **Auto-Optimize**: One-click "best quality/size" ratio finder.
- [ ] Upload multiple images (10+ files)
- [ ] Apply same transformations to all
- [ ] Individual preview for each image
- [ ] Download as ZIP file
- [ ] Progress indicator for batch operations
- [ ] Cancel/remove individual files from queue
- [ ] Batch rename with pattern (e.g., `image-{index}.png`)
- [ ] Memory optimization for large batches
### Sprint 3: Polish & Professional Tools
**Focus**: Precision and customization.
- [ ] **Custom Crop Tool**: Visual selector with aspect ratio lock.
- [ ] **Watermarking**: Text and image-based branding.
- [ ] **Image Filters**: Brightness, Contrast, Saturation, and Sharpen.
- [ ] **Format Intelligence**: Suggestions based on image content (e.g., suggesting WebP for large images).
**Implementation Notes**:
- Use JSZip library for ZIP creation
- Process images in parallel (4-6 concurrent)
- Track individual file progress
- Client-side queue management
### 2.2 Essential Image Operations 🎨
**Why**: Basic operations users expect
**Effort**: Low-Medium (4-6 hours) | **Impact**: High
- [ ] **Rotation**: 90°, 180°, 270°, custom angle
- [ ] **Flip**: Horizontal / Vertical
- [ ] **Grayscale**: Quick B&W conversion
- [ ] **Auto-rotate**: Based on EXIF orientation
- [ ] **Trim**: Remove transparent/white borders automatically
**Technical**: All supported natively by Sharp library
### 2.3 Image Optimization ⚡ **HIGH VALUE**
**Why**: One-click file size reduction without quality loss
**Effort**: Low (2-3 hours) | **Impact**: Very High
- [ ] **Auto-Optimize** button - Smart quality/compression
- [ ] **Lossless PNG** optimization (pngquant-style)
- [ ] **Strip EXIF** metadata (privacy + file size)
- [ ] **Progressive JPEG** encoding
- [ ] **Compression comparison** - Show savings for each format
- [ ] **Target file size** - Optimize to hit specific size (e.g., "under 1MB")
**Implementation**: Use Sharp's built-in optimization + custom quality detection
### Sprint 4: Workflow & Automation
**Focus**: Reusability and productivity.
- [ ] **Custom Presets**: Save and export personal transformation pipelines.
- [ ] **Processing History**: Recent files list (localStorage).
- [ ] **Undo/Redo**: History for parameter adjustments.
---
## Sprint 3: User Experience Polish (High Utility)
**Focus**: Make the app faster and more intuitive
**Effort**: ~10-12 hours | **Impact**: High | **Timeline**: Week 3-4
## Priority Matrix
### 3.1 Quick Access Features ⏱️
**Why**: Speed up repetitive tasks
**Effort**: Low (2-3 hours) | **Impact**: Medium-High
- [ ] **Copy to Clipboard** - Copy processed image directly
- [ ] **Recent Files** - Quick access to last 10 processed images (localStorage)
- [ ] **Undo/Redo** - Revert parameter changes
- [ ] **Favorites** - Star frequently used presets
- [ ] **Quick Settings** - Toggle common options in header
### 3.2 Image Analysis & Info 🔍 **HIGH VALUE**
**Why**: Understand your images better
**Effort**: Low (2-3 hours) | **Impact**: Medium-High
- [ ] **Metadata Display**: Dimensions, format, color space, DPI
- [ ] **Color Palette Extraction**: Show dominant colors (5-8)
- [ ] **Transparency Detection**: Warn if converting transparent to JPEG
- [ ] **File Size Projection**: Estimate final size before download
- [ ] **Aspect Ratio Calculator**: Calculate dimensions maintaining ratio
- [ ] **Memory Usage**: Show current memory consumption
### 3.3 Format Intelligence 🧠
**Why**: Help users choose the right format
**Effort**: Low (2-3 hours) | **Impact**: Medium
- [ ] **Format Recommendations**: Suggest best format based on image
- [ ] **Browser Support Detection**: Show WebP/AVIF compatibility
- [ ] **Multi-Format Export**: Generate PNG + WebP + JPEG at once
- [ ] **Responsive Image Sets**: Export multiple sizes for responsive design
### 3.4 UI/UX Improvements
**Effort**: Low-Medium (3-4 hours) | **Impact**: Medium
- [ ] **Mobile Responsive Design**: Better mobile/tablet experience
- [ ] **Toast Notifications**: Non-blocking feedback messages
- [ ] **Drag to Reorder**: Reorder batch queue
- [ ] **Compare Mode**: Slider to compare before/after
- [ ] **Zoom Controls**: Zoom in on preview images
- [ ] **Grid/List Toggle**: Switch preview layout
| Feature | Impact | Effort | Priority |
|---------|--------|--------|----------|
| Batch Processing | Very High | Medium | 1 |
| Auto-Optimize | High | Low | 1 |
| Custom Crop | High | High | 2 |
| Watermarking | Medium | Medium | 3 |
---
## Sprint 4: Advanced Features (Power Users)
**Focus**: Professional-grade tools
**Effort**: ~15-20 hours | **Impact**: Medium-High | **Timeline**: Week 5-6
### 4.1 Custom Crop Tool ✂️
**Why**: Precise control over cropping
**Effort**: High (8-10 hours) | **Impact**: Medium-High
- [ ] **Visual Crop Selector**: Interactive drag handles
- [ ] **Aspect Ratio Lock**: 16:9, 4:3, 1:1, custom
- [ ] **Freeform Cropping**: No ratio constraints
- [ ] **Rule of Thirds Grid**: Photography composition guide
- [ ] **Golden Ratio Grid**: Advanced composition
- [ ] **Zoom for Precision**: Zoom in for pixel-perfect crops
- [ ] **Crop Presets**: Social media sizes (Instagram, Facebook, etc.)
### 4.2 Filters & Effects 🌈
**Why**: Quick image enhancements
**Effort**: Medium (5-6 hours) | **Impact**: Medium
- [ ] **Brightness/Contrast**: Adjust exposure
- [ ] **Saturation**: Boost or reduce colors
- [ ] **Sharpness**: Enhance edges
- [ ] **Blur**: Gaussian blur with radius control
- [ ] **Tint**: Apply color overlay
- [ ] **Vintage Filter**: Sepia tone
- [ ] **Invert Colors**: Negative effect
- [ ] **Filter Presets**: Quick apply common filters
### 4.3 Watermarking 📝
**Why**: Protect and brand images
**Effort**: Medium (4-5 hours) | **Impact**: Medium
- [ ] **Text Watermark**: Custom text with font selection
- [ ] **Image Watermark**: Upload logo overlay
- [ ] **Position Control**: 9 positions + custom X/Y
- [ ] **Opacity**: Adjust transparency (0-100%)
- [ ] **Repeat Pattern**: Tile watermark across image
- [ ] **Batch Watermark**: Apply to all images in batch
---
## Sprint 5: Workflow & Automation (Productivity)
**Focus**: Save time with reusable workflows
**Effort**: ~8-10 hours | **Impact**: Medium | **Timeline**: Week 7+
### 5.1 Custom Presets & Templates
**Why**: Reusable transformation pipelines
**Effort**: Low-Medium (3-4 hours) | **Impact**: Medium
- [ ] **Save Custom Presets**: Create your own quick-access presets
- [ ] **Preset Categories**: Organize by use case
- [ ] **Import/Export Presets**: Share as JSON files
- [ ] **Transformation Chains**: Combine multiple operations
- [ ] **Preset Shortcuts**: Assign keyboard shortcuts (1-9 keys)
- [ ] **Community Presets**: Gallery of user-submitted presets
### 5.2 History & Session Management
**Why**: Track and repeat common tasks
**Effort**: Low (2-3 hours) | **Impact**: Low-Medium
- [ ] **Processing History**: Last 50 transformations
- [ ] **Quick Re-apply**: Reload previous settings
- [ ] **Export History**: Save session as JSON
- [ ] **Clear History**: Privacy button
- [ ] **Session Restore**: Resume after browser close
---
## Future: Extended Format Support (Lower Priority)
**Focus**: Support more file types
**Effort**: Variable | **Impact**: Situational
### Additional Formats
- [ ] **AVIF Support**: Next-gen image format
- [ ] **TIFF Support**: Professional photography
- [ ] **SVG to Raster**: Convert vector to bitmap
- [ ] **ICO Generation**: Create favicons (16, 32, 48, 64, 128, 256px)
- [ ] **PDF to Image**: Extract first page as image
- [ ] **GIF Frame Extraction**: Convert animated GIF to frames
- [ ] **HEIC/HEIF Support**: Apple photo format
---
## Enterprise & API (Optional)
**Focus**: For hosted/managed deployments
**Effort**: High | **Impact**: Situational
### API Access
- [ ] Generate API keys in UI
- [ ] Rate limiting per key
- [ ] Usage statistics dashboard
- [ ] Webhook support for async processing
- [ ] OpenAPI/Swagger documentation
- [ ] SDK libraries (Python, Node.js, PHP)
### User Accounts (Optional)
- [ ] User authentication
- [ ] Per-user quotas
- [ ] Cloud storage integration (S3, MinIO)
- [ ] Saved presets sync
- [ ] Usage analytics
- [ ] Team collaboration features
---
## New High-Value Ideas 💡
### Image Comparison Tool 🔍
**Why**: A/B test different settings
**Effort**: Low-Medium (3-4 hours) | **Impact**: Medium
- [ ] Side-by-side comparison of 2-4 versions
- [ ] Slider reveal to show differences
- [ ] Quality vs file size comparison matrix
- [ ] Export comparison settings for sharing
### Background Removal ✨ **HIGH VALUE**
**Why**: Remove backgrounds automatically
**Effort**: Medium-High (6-8 hours) | **Impact**: Very High
- [ ] AI-powered background removal (using @imgly/background-removal or similar)
- [ ] Replace with solid color
- [ ] Replace with gradient
- [ ] Replace with uploaded image
- [ ] Transparency preservation
- [ ] Edge refinement controls
### Smart Resize 🦾 **HIGH VALUE**
**Why**: Content-aware resizing
**Effort**: Medium (4-5 hours) | **Impact**: High
- [ ] **Content-aware scaling**: Preserve important areas
- [ ] **Face detection**: Protect faces during crop
- [ ] **Center of interest**: Auto-detect focal point
- [ ] **Smart crop suggestions**: AI-suggested crop areas
### Color Adjustments 🎨
**Why**: Fine-tune image colors
**Effort**: Medium (4-5 hours) | **Impact**: Medium
- [ ] **Hue/Saturation/Lightness** sliders
- [ ] **Color temperature** (warm/cool)
- [ ] **Vibrance** (selective saturation)
- [ ] **Color balance** (shadows, midtones, highlights)
- [ ] **White balance correction**
- [ ] **Color grading presets**
### Border & Frame Effects 🖼️
**Why**: Add decorative elements
**Effort**: Low-Medium (3-4 hours) | **Impact**: Low-Medium
- [ ] **Solid borders**: Color and thickness
- [ ] **Padding**: Add transparent/colored space
- [ ] **Rounded corners**: Border radius control
- [ ] **Shadow effects**: Drop shadow with blur
- [ ] **Frame templates**: Decorative frames
- [ ] **Polaroid effect**: Instant camera style
### Image Merge & Collage 🖼️
**Why**: Combine multiple images
**Effort**: High (8-10 hours) | **Impact**: Medium
- [ ] **Side-by-side merge**: Horizontal/vertical
- [ ] **Grid layout**: 2x2, 3x3, custom
- [ ] **Collage templates**: Pre-designed layouts
- [ ] **Spacing control**: Gap between images
- [ ] **Background color**: For gaps
### Conditional Processing 🤖
**Why**: Smart automation based on image properties
**Effort**: Medium (4-5 hours) | **Impact**: Medium
- [ ] **Size-based rules**: Different settings for large vs small images
- [ ] **Format detection**: Auto-convert based on transparency
- [ ] **Quality ranges**: Set min/max quality constraints
- [ ] **Dimension limits**: Enforce max width/height
---
## Technical Debt & Infrastructure
### Code Quality
- [ ] Unit tests (backend) - Vitest/Jest
- [ ] E2E tests (frontend) - Playwright
- [ ] TypeScript strict mode
- [ ] ESLint + Prettier configuration
- [ ] CI/CD pipeline (GitHub Actions or Gitea Actions)
- [ ] Code coverage reporting (>80%)
- [ ] Automated dependency updates (Renovate)
### Performance
- [ ] Image processing queue (for heavy operations)
- [ ] Web Workers for client-side processing
- [ ] Service Worker for offline support
- [ ] Lazy loading for UI components
- [ ] Memory leak detection and fixes
- [ ] Performance monitoring (Lighthouse CI)
### Security
- [ ] Rate limiting (prevent abuse)
- [ ] File type validation (magic bytes check)
- [ ] Max file size enforcement (configurable)
- [ ] CORS configuration hardening
- [ ] CSP headers
- [ ] Input sanitization audit
- [ ] Security headers (HSTS, X-Frame-Options)
- [ ] Dependency vulnerability scanning
### Monitoring & Analytics
- [ ] Prometheus metrics endpoint
- [ ] Error tracking (Sentry integration)
- [ ] Performance monitoring (Real User Monitoring)
- [ ] Usage analytics (privacy-focused, self-hosted)
- [ ] Health check dashboard
---
## Priority Matrix (Updated)
### Immediate Next Steps (Sprint 2)
1. 🚀 **Batch Processing** - Highest utility, medium effort
2.**Auto-Optimize** - Quick win, very high value
3. 🎨 **Basic Operations** - Essential features (rotate, flip, grayscale)
### High Value, Medium Effort (Sprint 3-4)
4. 🔍 **Image Analysis** - Understand images better
5.**Background Removal** - AI-powered, huge demand
6. 🦾 **Smart Resize** - Content-aware scaling
7. ✂️ **Custom Crop Tool** - Professional precision
### Polish & Productivity (Sprint 5+)
8. ⏱️ **Quick Access Features** - Speed up workflow
9. 📝 **Custom Presets** - Reusable workflows
10. 🎨 **Filters & Effects** - Creative options
---
## Community Ideas
Have suggestions? Open an issue on the repository:
- Feature requests
- Bug reports
- Use case discussions
- Performance improvements
**Maintainer**: jason
**Repository**: https://git.alwisp.com/jason/pnger
**Last Updated**: March 8, 2026 (Sprint 1 Complete)
**Project Maintainer**: jason
**Repository**: [jason/pnger](https://git.alwisp.com/jason/pnger)
**Last Strategy Sync**: March 12, 2026

View File

@@ -1,239 +0,0 @@
# Sprint 1 Changes - UX Enhancements
**Branch**: `feature/sprint1-dragdrop-presets-shortcuts`
**Date**: 2026-03-08
**Status**: Ready for Testing
## 🎯 Overview
This sprint focuses on making PNGer significantly more intuitive and powerful with three major feature additions plus a critical bug fix.
---
## ✅ Bug Fix: Preview File Size Calculation
### Problem
- Preview file size was not calculating correctly
- Size didn't update when adjusting quality slider
- Format changes weren't reflected in estimated size
### Solution
- Fixed base64 size estimation algorithm in `preview.ts`
- Properly map format to MIME types (png, jpeg, webp)
- Quality parameter now correctly applied to JPEG and WebP
- Improved padding calculation for accurate byte estimation
### Files Changed
- `frontend/src/lib/preview.ts`
---
## 🆕 Feature 1: Drag & Drop Upload
### What's New
- **Drag & drop zone** with visual feedback
- Hover state shows accent color
- Dragging over triggers highlight animation
- **Clipboard paste support** (Ctrl+V / Cmd+V)
- File info displayed after upload (name + size)
- One-click "Clear File" button
### User Benefits
- No more hunting for file picker
- Instant image upload from screenshots (paste)
- Modern, expected behavior
- Faster workflow
### Technical Implementation
- `dragover`, `dragleave`, `drop` event handlers
- Clipboard paste event listener
- File type validation
- Visual state management with `isDragging` flag
### Files Changed
- `frontend/src/App.svelte` (drag handlers + paste support)
---
## 🎯 Feature 2: Smart Presets
### What's New
8 built-in presets for common use cases:
1. **🖼️ Web Thumbnail** - 300x300, WebP, 75% quality, cover
2. **📱 Social Media** - 1200x630 Open Graph, PNG, 85%, cover
3. **👤 Profile Picture** - 400x400 square, PNG, 85%, cover
4. **📧 Email Friendly** - 600px wide, JPEG, 70%, optimized
5. **⭐ HD Quality** - 1920px wide, PNG, 90%, high-res
6. **🔍 Retina @2x** - Doubles current dimensions, PNG, 85%
7. **🔷 Icon Small** - 64x64, PNG, 100%, cover
8. **🔶 Icon Large** - 256x256, PNG, 100%, cover
### User Benefits
- One-click transformations for common tasks
- No need to remember optimal settings
- Saves time on repetitive operations
- Perfect for non-technical users
### Technical Implementation
- New `presets.ts` module with preset definitions
- `applyPreset()` function with special Retina @2x logic
- 4-column grid layout
- Hover effects with elevation
- Icon + name display
### Files Changed
- `frontend/src/lib/presets.ts` (new file)
- `frontend/src/App.svelte` (preset UI + selection logic)
---
## ⌨️ Feature 3: Keyboard Shortcuts
### What's New
**Shortcuts Available:**
- `Ctrl+V` / `Cmd+V` - Paste image from clipboard
- `Enter` - Transform & Download (when not in input)
- `Ctrl+Enter` / `Cmd+Enter` - Transform & Download (anywhere)
- `?` - Show/hide shortcuts help
- `Esc` - Close shortcuts dialog
**Shortcuts Help Modal:**
- Clean, centered modal
- Keyboard key styling (`<kbd>`)
- Click outside to close
- Fade-in animation
### User Benefits
- Power users can work without mouse
- Faster workflow for repetitive tasks
- Discoverable via `?` key
- Professional touch
### Technical Implementation
- Document-level `keydown` event listener
- Active element detection (skip Enter if input focused)
- Modal overlay with portal pattern
- `onMount` setup and cleanup
### Files Changed
- `frontend/src/App.svelte` (keyboard handlers + modal)
---
## 🎨 UI/UX Improvements
### Additional Polish
- **Shortcuts button** in header (⌨️ icon)
- **Hint text** under download button: "Press Enter to download"
- **Drop zone improvements**: better empty state messaging
- **Preset icons**: visual indicators for each preset type
- **Modal styling**: professional overlay with backdrop blur
- **Responsive kbd tags**: monospace font with shadow effect
---
## 📊 Testing Checklist
### Bug Fix Validation
- [ ] Upload image, adjust quality slider - size updates in real-time
- [ ] Change format PNG → JPEG → WebP - size reflects format
- [ ] Compare preview size with actual downloaded file size
### Drag & Drop
- [ ] Drag image file onto drop zone - uploads successfully
- [ ] Drag non-image file - shows error
- [ ] Hover during drag - shows visual feedback
- [ ] Drop outside zone - no action
### Clipboard Paste
- [ ] Take screenshot, press Ctrl+V - pastes image
- [ ] Copy image from browser, paste - works
- [ ] Paste non-image - no error
### Presets
- [ ] Click "Web Thumbnail" - sets 300x300, WebP, 75%, cover
- [ ] Click "Social Media" - sets 1200x630, PNG, 85%, cover
- [ ] Click "Retina @2x" with 500x500 image - doubles to 1000x1000
- [ ] All 8 presets apply correctly
### Keyboard Shortcuts
- [ ] Press `?` - shows shortcuts modal
- [ ] Press `Esc` in modal - closes modal
- [ ] Press `Enter` with image loaded - downloads
- [ ] Press `Enter` while typing in input - types Enter (doesn't download)
- [ ] Press `Ctrl+Enter` anywhere - downloads
- [ ] Press `Ctrl+V` - pastes from clipboard
### Cross-Browser
- [ ] Chrome/Edge - all features work
- [ ] Firefox - all features work
- [ ] Safari - all features work (Cmd key instead of Ctrl)
---
## 📝 Files Changed Summary
### New Files
1. `frontend/src/lib/presets.ts` - Preset definitions and apply logic
2. `SPRINT1_CHANGES.md` - This document
### Modified Files
1. `frontend/src/lib/preview.ts` - Fixed size calculation bug
2. `frontend/src/App.svelte` - Major update with all 3 features
3. `ROADMAP.md` - Marked Phase 1.1 complete, added sprint plan
---
## 🚀 Performance Notes
- **No performance impact**: All features are client-side
- **Preview debounce**: Still 300ms, works great with presets
- **Modal render**: Only renders when `showShortcuts = true`
- **Drag handlers**: Lightweight event listeners
- **Preset selection**: Instant application (<10ms)
---
## 🔧 Development Notes
### Code Quality
- TypeScript strict types maintained
- Svelte reactivity patterns followed
- Event cleanup in `onMount` return
- CSS animations for smooth UX
- Semantic HTML structure
### Future Enhancements
- [ ] Multi-file batch processing (use drag & drop foundation)
- [ ] Custom preset saving (localStorage)
- [ ] Preset import/export
- [ ] More keyboard shortcuts (arrow keys for presets?)
---
## ✅ Ready for Merge
This branch is ready to merge to `main` once testing is complete.
**Merge Command:**
```bash
git checkout main
git merge feature/sprint1-dragdrop-presets-shortcuts
git push origin main
```
**Deployment:**
No backend changes - just rebuild frontend Docker image.
---
## 💬 Next Sprint Suggestions
After this sprint, consider:
1. **Sprint 2A**: Batch processing (multi-file upload)
2. **Sprint 2B**: Additional transformations (rotate, flip, filters)
3. **Sprint 2C**: Auto-optimize feature
See `ROADMAP.md` for full feature planning.

View File

@@ -1,413 +0,0 @@
# UI Upgrade - Dark Mode & Live Preview
## Overview
This branch introduces a complete UI overhaul with modern design, dark/light mode theming, and real-time live preview functionality.
## What's New
### 🎨 Modern Design System
**Color Themes:**
- **Light Mode**: Clean white background with dark gold (#b8860b) accents
- **Dark Mode**: Deep black (#0a0a0a) background with light gold (#daa520) accents
- Smooth transitions between themes
- System preference detection on first load
**Design Tokens:**
- CSS custom properties for consistent spacing, colors, shadows
- Responsive typography scale
- Smooth animations and transitions
- Modern card-based layout
- Professional shadows and borders
### 🌙 Dark/Light Mode Toggle
- One-click theme switching
- Persistent preference (localStorage)
- Smooth color transitions
- Icon indicators (☀️/🌙)
- Perfect for comparing PNG transparency on different backgrounds
### ⚡ Live Preview
**Instant Visual Feedback:**
- Real-time preview updates as you adjust settings
- Side-by-side comparison (original vs transformed)
- No server round-trip required (client-side Canvas API)
- Debounced updates (300ms) for performance
**Preview Features:**
- Shows exact transformations before download
- File size comparison
- Savings/increase indicator with percentage
- Color-coded feedback (green = savings, yellow = increase)
- Maintains aspect ratio and crop preview
### 📊 Enhanced Information Display
- Original file name and size shown
- Preview file size estimation
- Savings calculation with visual indicators
- Quality slider with percentage display
- Clear visual separation of controls and preview
### 💅 Visual Improvements
**Layout:**
- Two-column grid layout (controls | preview)
- Card-based design with subtle shadows
- Proper spacing and visual hierarchy
- Responsive design (mobile-friendly)
**Interactions:**
- Smooth hover effects on buttons
- Focus states with accent color
- Loading spinners for processing states
- Fade-in animations
- Button transforms on hover
**Typography:**
- System font stack (native look & feel)
- Proper heading hierarchy
- Readable line heights
- Color-coded text (primary, secondary, accent)
## Files Modified
### New Files
1. **`frontend/src/lib/preview.ts`**
- Client-side preview generation using Canvas API
- Image transformation calculations
- File size estimation
- Utility functions (debounce, format bytes, calculate savings)
2. **`frontend/src/lib/theme.ts`**
- Svelte store for theme management
- localStorage persistence
- System preference detection
- Theme toggle functionality
### Updated Files
3. **`frontend/src/app.css`**
- Complete design system rewrite
- CSS custom properties for theming
- Dark mode support via `[data-theme="dark"]`
- Modern component styles (buttons, inputs, cards)
- Utility classes for layout
- Responsive breakpoints
- Custom scrollbar styling
- Animation keyframes
4. **`frontend/src/App.svelte`**
- Complete UI restructuring
- Two-column layout with grid
- Live preview integration
- Theme toggle button
- Enhanced file upload UI
- Clear file button
- Improved error handling display
- Loading states with spinners
- Side-by-side image comparison
- Savings indicator card
## Technical Details
### Preview Implementation
**How it works:**
1. User uploads image
2. Canvas API loads image into memory
3. Transformations applied client-side:
- Resize calculations (aspect ratio aware)
- Crop positioning (9 positions supported)
- Quality adjustment via canvas.toDataURL()
4. Preview updates on parameter change (debounced)
5. File size estimated from base64 data URL
**Performance:**
- Debounced at 300ms to avoid excessive redraws
- Canvas operations run on main thread (future: Web Worker)
- Preview max size limited by browser memory
- No server load for preview generation
### Theme System
**Storage:**
```typescript
localStorage.setItem('theme', 'dark' | 'light')
```
**Application:**
```html
<html data-theme="dark">
<!-- CSS custom properties change based on data-theme -->
</html>
```
**CSS Variables:**
```css
:root { --color-accent: #b8860b; } /* Light mode */
[data-theme="dark"] { --color-accent: #daa520; } /* Dark mode */
```
### Design Tokens
**Spacing Scale:**
- xs: 0.25rem (4px)
- sm: 0.5rem (8px)
- md: 1rem (16px)
- lg: 1.5rem (24px)
- xl: 2rem (32px)
- 2xl: 3rem (48px)
**Color Palette:**
| Light Mode | Dark Mode | Purpose |
|------------|-----------|----------|
| #ffffff | #0a0a0a | Primary BG |
| #f8f9fa | #1a1a1a | Secondary BG |
| #e9ecef | #2a2a2a | Tertiary BG |
| #b8860b | #daa520 | Accent (Gold) |
| #1a1a1a | #e9ecef | Text Primary |
| #6c757d | #adb5bd | Text Secondary |
**Shadows:**
- sm: Subtle card elevation
- md: Button hover states
- lg: Modal/dropdown shadows
- xl: Maximum elevation
## User Experience Improvements
### Before vs After
**Before:**
- Static form with no feedback
- Download to see results
- Trial and error workflow
- Basic styling
- No theme options
**After:**
- ✅ Real-time preview
- ✅ See before download
- ✅ Immediate feedback loop
- ✅ Modern, professional design
- ✅ Dark/light mode for different PNGs
- ✅ File size visibility
- ✅ Savings indicator
### Use Cases Enhanced
1. **Comparing Transparency**
- Toggle dark/light mode to see PNG transparency
- Useful for logos, icons with transparency
2. **Optimizing File Size**
- See file size impact immediately
- Adjust quality until size is acceptable
- Green indicator shows successful optimization
3. **Precise Cropping**
- See crop position in real-time
- Try all 9 positions visually
- No guesswork needed
4. **Format Comparison**
- Compare PNG vs WebP vs JPEG quality
- See size differences instantly
- Make informed format choice
## Browser Compatibility
**Tested On:**
- Chrome 90+
- Firefox 88+
- Safari 14+
- Edge 90+
**Requirements:**
- Canvas API support
- CSS Custom Properties
- localStorage
- ES6 modules
## Performance Metrics
**Preview Generation:**
- Small images (< 1MB): ~50-100ms
- Medium images (1-5MB): ~200-400ms
- Large images (5-10MB): ~500ms-1s
**Memory Usage:**
- Canvas limited by browser (typically 512MB max)
- Preview auto-cleanup on file change
- No memory leaks detected
## Future Enhancements
### Planned (Not in This Branch)
- [ ] Slider comparison (drag to reveal differences)
- [ ] Zoom on preview for detail inspection
- [ ] Web Worker for preview generation
- [ ] Server-side preview option (Sharp accuracy)
- [ ] Multiple preview sizes simultaneously
- [ ] Drag & drop file upload
- [ ] Batch preview mode
## Testing Checklist
### Manual Testing
- [x] Upload PNG image
- [x] Upload JPEG image
- [x] Upload WebP image
- [x] Adjust width only
- [x] Adjust height only
- [x] Adjust both dimensions
- [x] Change quality slider
- [x] Switch between formats
- [x] Toggle fit mode (inside/cover)
- [x] Test all 9 crop positions
- [x] Toggle dark/light mode
- [x] Verify theme persistence (refresh page)
- [x] Clear file and re-upload
- [x] Download transformed image
- [x] Compare downloaded vs preview
- [x] Test on mobile (responsive)
### Edge Cases
- [ ] Very large image (> 10MB)
- [ ] Very small image (< 10KB)
- [ ] Square images
- [ ] Panoramic images (extreme aspect ratios)
- [ ] Images with transparency
- [ ] Animated GIFs (should show first frame)
### Performance
- [ ] Preview updates < 500ms
- [ ] No UI blocking during preview
- [ ] Smooth theme transitions
- [ ] No console errors
- [ ] Memory cleanup verified
## Deployment Notes
### Build Requirements
- No new dependencies added
- Uses existing Svelte + Vite setup
- Compatible with current Docker build
### Breaking Changes
- None - fully backward compatible
- API unchanged
- Old URL parameters still work
### Environment Variables
- No new env vars required
- Theme stored client-side only
## Usage Guide
### For End Users
1. **Upload Image**: Click "Select Image" or use file picker
2. **Adjust Settings**: Use controls on the left
3. **Watch Preview**: See changes in real-time on the right
4. **Toggle Theme**: Click sun/moon button for dark/light mode
5. **Check Savings**: Green box shows file size reduction
6. **Download**: Click "Transform & Download" when satisfied
### For Developers
**Adding a New Control:**
```svelte
<script>
let newParam = defaultValue;
$: if (file) updatePreview(); // Auto-trigger on change
</script>
<div>
<label>New Parameter</label>
<input bind:value={newParam} />
</div>
```
**Extending Theme:**
```css
/* In app.css */
:root {
--color-new-token: #value;
}
[data-theme="dark"] {
--color-new-token: #dark-value;
}
```
## Screenshots (Conceptual)
### Light Mode
```
┌───────────────────────────────────────┐
│ PNGer 🌙 Dark │
│ Modern PNG Editor & Resizer │
├──────────────────┬────────────────────┤
│ Upload & Transform │ Live Preview │
│ │ │
│ [File picker] │ [Original] [Prev] │
│ Width: [ ] │ │
│ Height: [ ] │ ↓ 450KB saved │
│ Quality: 80% │ │
│ Format: PNG │ │
│ [Download Button] │ │
└──────────────────┴────────────────────┘
```
### Dark Mode
```
┌───────────────────────────────────────┐
│ ✨PNGer✨ ☀️ Light │
│ Modern PNG Editor & Resizer │
├──────────────────┬────────────────────┤
│ 💻Upload & Transform│ 🖼Live Preview │
│ (Black BG) │ (Black BG) │
│ Gold accents │ Gold borders │
└──────────────────┴────────────────────┘
```
## Merge Checklist
- [x] All new files created
- [x] All existing files updated
- [x] No console errors
- [x] Dark mode works
- [x] Light mode works
- [x] Theme persists across refreshes
- [x] Preview generates correctly
- [x] File size calculations accurate
- [x] Responsive design tested
- [ ] Ready to merge to main
---
**Branch**: `feature/ui-upgrade-dark-mode-preview`
**Created**: 2026-03-08
**Status**: ✅ Ready for Testing
**Merge Target**: `main`
**Next Steps**:
1. Build and test locally
2. Deploy to staging
3. User acceptance testing
4. Merge to main
5. Deploy to production

View File

@@ -1,366 +0,0 @@
# Live Preview Implementation Guide
## Overview
Live Preview is the #1 priority feature for PNGer. This guide outlines the implementation approach.
## Goals
1. **Instant Feedback**: Show preview within 100ms of parameter change
2. **Accurate Rendering**: Match final output as closely as possible
3. **Performance**: Don't block UI, handle large images efficiently
4. **Progressive**: Show low-quality preview immediately, high-quality after
## Architecture
### Approach: Hybrid Client + Server Preview
```
┌─────────────┐
│ Upload │
│ Image │
└──────┬──────┘
v
┌─────────────────────────────────┐
│ Client-Side Preview (Canvas) │ <-- Instant (< 100ms)
│ - Fast, approximate rendering │
│ - Uses browser native resize │
│ - Good for basic operations │
└─────────┬───────────────────────┘
v
┌─────────────────────────────────┐
│ Server Preview API (Optional) │ <-- Accurate (500ms-2s)
│ - Uses Sharp (same as export) │
│ - Exact output representation │
│ - Debounced to avoid spam │
└─────────────────────────────────┘
```
## Implementation Steps
### Phase 1: Client-Side Preview (Quick Win)
**Files to Modify:**
- `frontend/src/App.svelte`
- `frontend/src/lib/preview.ts` (new)
**Key Features:**
1. Canvas-based image rendering
2. Debounced updates (300ms after parameter change)
3. Show original and preview side-by-side
4. Display file size estimate
**Code Skeleton:**
```typescript
// frontend/src/lib/preview.ts
export async function generateClientPreview(
file: File,
options: TransformOptions
): Promise<string> {
return new Promise((resolve) => {
const img = new Image();
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d')!
img.onload = () => {
// Calculate dimensions
const { width, height } = calculateDimensions(img, options);
canvas.width = width;
canvas.height = height;
// Apply transforms
if (options.fit === 'cover') {
drawCover(ctx, img, width, height, options.position);
} else {
ctx.drawImage(img, 0, 0, width, height);
}
// Apply filters (grayscale, blur, etc.)
applyFilters(ctx, options);
// Convert to data URL
const quality = options.quality / 100;
const dataUrl = canvas.toDataURL(`image/${options.format}`, quality);
resolve(dataUrl);
};
img.src = URL.createObjectURL(file);
});
}
```
**UI Updates:**
```svelte
<!-- App.svelte additions -->
<script lang="ts">
import { generateClientPreview } from './lib/preview';
import { debounce } from './lib/utils';
let previewUrl: string | null = null;
let originalSize: number = 0;
let previewSize: number = 0;
// Debounced preview generation
const updatePreview = debounce(async () => {
if (!file) return;
previewUrl = await generateClientPreview(file, {
width, height, quality, format, fit, position
});
// Calculate sizes
originalSize = file.size;
previewSize = estimateSize(previewUrl);
}, 300);
// Call on any parameter change
$: if (file) updatePreview();
</script>
<!-- Preview Section -->
{#if file && previewUrl}
<div class="preview-container">
<div class="image-comparison">
<div class="original">
<h3>Original</h3>
<img src={URL.createObjectURL(file)} alt="Original" />
<p>{formatFileSize(originalSize)}</p>
</div>
<div class="preview">
<h3>Preview</h3>
<img src={previewUrl} alt="Preview" />
<p>{formatFileSize(previewSize)}</p>
<p class="savings">
{calculateSavings(originalSize, previewSize)}
</p>
</div>
</div>
</div>
{/if}
```
### Phase 2: Server Preview API (Accurate)
**Files to Modify:**
- `backend/src/routes/image.ts`
**New Endpoint:**
```typescript
// POST /api/preview (returns base64 or temp URL)
router.post(
"/preview",
upload.single("file"),
async (req, res): Promise<void> => {
// Same processing as /transform
// But return as base64 data URL or temp storage URL
// Max preview size: 1200px (for performance)
const previewBuffer = await image.toBuffer();
const base64 = previewBuffer.toString('base64');
res.json({
preview: `data:image/${format};base64,${base64}`,
size: previewBuffer.length,
dimensions: { width: metadata.width, height: metadata.height }
});
}
);
```
**Benefits:**
- Exact rendering (uses Sharp like final output)
- Shows actual file size
- Handles complex operations client can't do
**Trade-offs:**
- Slower (network round-trip)
- Server load (mitigate with rate limiting)
### Phase 3: Progressive Loading
**Enhancement**: Show low-quality preview first, then high-quality
```typescript
// Generate two previews:
// 1. Immediate low-res (client-side, 200px max)
// 2. Delayed high-res (server-side, full resolution)
async function generateProgressivePreview() {
// Step 1: Fast low-res
const lowRes = await generateClientPreview(file, {
...options,
width: Math.min(options.width || 200, 200),
height: Math.min(options.height || 200, 200)
});
previewUrl = lowRes; // Show immediately
// Step 2: High-res from server (debounced)
const highRes = await fetchServerPreview(file, options);
previewUrl = highRes; // Replace when ready
}
```
## File Size Estimation
```typescript
function estimateSize(dataUrl: string): number {
// Base64 data URL size (approximate)
const base64Length = dataUrl.split(',')[1].length;
return Math.ceil((base64Length * 3) / 4); // Convert base64 to bytes
}
function formatFileSize(bytes: number): string {
if (bytes < 1024) return `${bytes} B`;
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;
}
function calculateSavings(original: number, preview: number): string {
const diff = original - preview;
const percent = ((diff / original) * 100).toFixed(1);
if (diff > 0) return `${formatFileSize(diff)} saved (${percent}%)`;
if (diff < 0) return `${formatFileSize(-diff)} larger (${Math.abs(Number(percent))}%)`;
return 'Same size';
}
```
## UI/UX Considerations
### Layout Options
**Option A: Side-by-Side**
```
┌──────────────┬──────────────┐
│ Original │ Preview │
│ │ │
│ [Image] │ [Image] │
│ 2.4 MB │ 450 KB │
│ 1920x1080 │ 800x600 │
└──────────────┴──────────────┘
```
**Option B: Slider Compare**
```
┌────────────────────────────┐
│ [<──── Slider ────>] │
│ Original │ Preview │
│ │ │
└────────────────────────────┘
```
**Option C: Tabs**
```
┌─ Original ─┬─ Preview ─────┐
│ │
│ [Image] │
│ │
└─────────────────────────────┘
```
**Recommendation**: Start with Option A (simplest), add Option B later for detail comparison.
## Performance Optimizations
### 1. Debouncing
```typescript
function debounce<T extends (...args: any[]) => any>(
func: T,
wait: number
): (...args: Parameters<T>) => void {
let timeout: ReturnType<typeof setTimeout>;
return (...args: Parameters<T>) => {
clearTimeout(timeout);
timeout = setTimeout(() => func(...args), wait);
};
}
```
### 2. Image Downsampling
- Preview max size: 1200px (retina displays)
- Original size only for final download
- Reduces memory usage and processing time
### 3. Worker Thread (Advanced)
- Offload canvas operations to Web Worker
- Keeps UI responsive during processing
```typescript
// preview.worker.ts
self.onmessage = async (e) => {
const { file, options } = e.data;
const preview = await generatePreview(file, options);
self.postMessage({ preview });
};
```
## Testing Plan
### Unit Tests
- [ ] `calculateDimensions()` with various aspect ratios
- [ ] `formatFileSize()` edge cases
- [ ] `debounce()` timing
### Integration Tests
- [ ] Preview updates on parameter change
- [ ] Preview matches final output (within tolerance)
- [ ] Large image handling (> 10MB)
- [ ] Multiple format conversions
### Manual Tests
- [ ] Mobile responsiveness
- [ ] Slow network simulation
- [ ] Various image formats (PNG, JPEG, WebP)
- [ ] Edge cases (1x1px, 10000x10000px)
## Rollout Strategy
### Step 1: Feature Flag
```typescript
// Enable via environment variable
const ENABLE_PREVIEW = import.meta.env.VITE_ENABLE_PREVIEW === 'true';
```
### Step 2: Beta Testing
- Deploy to staging environment
- Gather user feedback
- Monitor performance metrics
### Step 3: Gradual Rollout
- Enable for 10% of users
- Monitor error rates
- Full rollout if stable
## Success Metrics
- **User Engagement**: Time spent on page increases
- **Conversion**: More downloads completed
- **Performance**: Preview renders in < 500ms (p95)
- **Accuracy**: Preview matches output 95%+ of time
- **Satisfaction**: User feedback positive
## Future Enhancements
- [ ] Before/after slider with drag handle
- [ ] Zoom on preview (inspect details)
- [ ] Multiple preview sizes simultaneously
- [ ] A/B comparison (compare 2-4 settings)
- [ ] Preview history (undo/redo preview)
- [ ] Export preview settings as preset
---
**Estimated Effort**: 2-3 days for Phase 1 (client preview)
**Complexity**: Medium
**Impact**: ⭐⭐⭐⭐⭐ (Highest)
**Next Steps**:
1. Create feature branch `feature/live-preview`
2. Implement client-side preview
3. Add UI components
4. Test thoroughly
5. Merge to main
6. Deploy and monitor