Convert, compress, resize, and package web-ready image and 3D assets.
Built for websites, e-commerce, and digital products that need lighter assets without losing workflow clarity.
Asset Optimizer is focused on one job: preparing images and 3D models so they are actually ready to publish.
It is not just a generic format converter. The product goal is to help users convert, compress, resize, and package assets so they ship with better performance, better compatibility, and lower file size.
- People building websites
- E-commerce teams managing product images
- Creators preparing assets for digital products
- Developers and designers optimizing images and 3D models for the web
| Topic | Status |
|---|---|
| Stable version | 1.1.0 |
| Product contract | docs/version-1-1-0.md |
| Release lane | docs/release-process.md |
| Runtime / env reference | docs/environment.md |
| Setup / operations | docs/setup.md |
Get a running instance in under 5 minutes:
# 1. Clone the repository
git clone https://github.com/your-username/asset-optimizer.git
cd asset-optimizer
# 2. Start the app
docker compose -f docker-compose.yml up -d
# 3. Verify the API is up
curl http://localhost:8000/health
# 4. Open the web UI
# β http://localhost:5173If you want to understand the environment variables and what they do, see Environment Reference. For host-side setup, dependency details, troubleshooting, and Railway notes, see Setup & Operations.
- Upload one image and get a direct optimized download
- Upload one GLB and get a Draco-compressed optimized download
- Upload multiple files or a folder and get a ZIP package
- Keep batch metadata with
manifest.json - Use AVIF only when the runtime actually supports it
- Preserve folder paths when the browser provides them
- Prevent mixing images and GLB files in the same batch
| Input | Output |
|---|---|
| JPG / JPEG | JPG / JPEG |
| PNG | PNG |
| WEBP | WEBP |
| GLB | GLB (optimized) |
| β | AVIF |
- Single file β direct file download
- Multiple files / folder β ZIP download
- Batch ZIPs include
manifest.json - Partial success is supported, valid files still return when others fail
asset-optimizer/
apps/
web/ # React + TypeScript frontend
api/ # FastAPI backend
docs/
docker-compose.yml
README.md
CLAUDE.md| Layer | Tools |
|---|---|
| Frontend | React 19, TypeScript, Vite |
| Backend | Python, FastAPI, Pillow, pillow-avif-plugin, Node.js, gltf-transform |
| Testing | Vitest, React Testing Library, pytest, Playwright smoke |
| Local infra | Docker Compose, Bun |
| Deploy | Railway |
- Upload one or multiple image files
- Select a full folder from the browser
- Convert between supported formats
- Adjust output quality / compression
- Resize by dimensions
- See original vs optimized size
- Download a single transformed file
- Download batch transformations as a ZIP file
- Single-image before/after comparison
- Batch manifest metadata inside ZIPs
- Partial success in batch processing
- Upload one or multiple
.glbfiles - Apply Draco compression for geometry
- Automatic deduplication, pruning, and quantization
- See file size reduction
- Download optimized GLB directly or as ZIP batch
- Batch manifest metadata inside ZIPs
- Single file β direct download
- Multiple files or folder β ZIP download
- Folder uploads preserve relative paths when available
- Batch ZIPs include
manifest.jsonwith per-file outputs, errors, and summary totals - Partial success is supported: valid files still return even if some files fail
For full setup details (host-side frontend/backend, Docker commands, troubleshooting), see Setup & Operations.
Key references:
| Need | Go to |
|---|---|
| Start both services | docker compose up -d |
Frontend on host (bun) |
Setup: Frontend |
| Backend on host (Python) | Setup: Backend |
| Port conflicts, stale volumes, rebuilds | Setup: Docker Troubleshooting |
Backend testing (pytest) |
Setup: Backend Testing |
| What env vars mean | Environment Reference |
multipart/form-data
Fields:
filesβ one or more image filesoutput_formatβjpg,png,webp,avifqualityβ integer1..100max_widthβ optionalmax_heightβ optionalpathsβ optional ordered JSON array for folder structure preservation
multipart/form-data
Fields:
filesβ one or more.glbfileszip_nameβ optionaloutput_stemβ optional (batch only)pathsβ optional ordered JSON array for folder structure preservation
Applies Draco compression, deduplication, pruning, and quantization.
Returns supported input and output formats.
Returns backend-enforced limits for frontend display.
Returns API health status including GLB runtime availability.
- Max 100 files per request
- Max 50 MB total upload size
- Max 50 megapixels per image
- Max 120 seconds cumulative processing time per request
max_width/max_height:1..10000
- Max 100 files per request
- Max 500 MB total upload size
- Max 100 MB per individual GLB file
- Max 120 seconds cumulative processing time per request
- Presets currently available:
- E-commerce Product
- Hero / Banner
- Thumbnail
- Open Graph
- Batch result UX now includes:
- All / Success / Failed grouped result views
- Richer sorting across name, savings, sizes, format, and dimensions
- Separate skipped-file banner for pre-upload exclusions
- Manifest download and copy-summary actions
- Naming controls now include:
- Single-file prefix/suffix naming without forced renumbering
- Batch/folder basename replacement via sequential
output_stem-N - Custom ZIP naming handled separately from internal output paths
- Format guidance now includes:
- Collapsible format guide with transparency and compatibility hints
- Preset rationale shown next to optimization presets
- Clearer AVIF availability and caution messaging
- Folder uploads filter junk/system files before format validation:
.DS_StoreThumbs.dbdesktop.ini._*- files inside
__MACOSX,.git,.vscode
- If
/api/v1/limitsis unavailable, the frontend falls back silently to defaults.
cd apps/web
bun test
bun run test:watchRun the Python test suite from the API app environment as appropriate for your setup.
- Processing is synchronous in the current product line
- Batch ZIP structure is driven by the optional
pathsfield - Filename collisions in ZIPs are resolved with numeric suffixes
- JPG output composites transparency onto white background
- AVIF support depends on runtime/container support and should be validated in the deployment environment
This project follows Semantic Versioning (MAJOR.MINOR.PATCH). 1.0.0 marks the first stable public baseline for the current product contract.
0.1.0β first functional MVP0.2.0β product/UX foundation0.3.0β pragmatic batch UX improvements0.4.0β frontend quality sprint0.5.0β runtime and operational hardening0.6.0β stronger batch result UX0.7.0β output naming controls and format guidance0.9.0β final stabilization release before stable baseline1.0.0β first stable public-ready baseline
- MVP base functional
- Single + batch transform
- ZIP output
- Single-image comparison
- Friendly errors
- Monorepo + Docker dev
- Presets
- Visible limits
- Junk/system file filtering
- Initial
App.tsxrefactor
manifest.jsoninside ZIP- Partial success for batch/folder uploads
- Improved batch summary
- Large-batch warnings
- Vitest + happy-dom test harness
- First wave of frontend tests
- Contract/constants extraction
- Batch UX polish
- Frontend aligned to
0.4.0
- Runtime AVIF capability detection and honest fallback behavior
/api/v1/capabilitiesendpoint- Enriched
/healthand Docker healthchecks - Structured runtime logging with request ID and timing
- Frontend AVIF availability UX aligned to real backend capabilities
- Operational setup and troubleshooting docs
- Batch result tabs for All / Success / Failed outcomes
- Richer batch sorting across name, savings, original size, optimized size, format, and dimensions
- Inline failed-row errors with clearer visual distinction
- Separate skipped-file banner for pre-upload exclusions
- Manifest actions for JSON download and copyable batch summary
- Single-file naming keeps original basename with optional prefix/suffix
- Batch and folder naming replace basenames entirely with sequential
output_stem-N - ZIP name customization is separated from internal output naming
- Static format guidance catalog explains transparency, compatibility, and best-fit use cases
- Collapsible
FormatGuideUI and preset rationale improve format selection confidence - AVIF guidance and availability messaging are clearer in the transformation settings panel
- Quickstart guide in README for first-run local startup
docs/environment.mdcanonical runtime and environment reference- Expanded
.env.examplewith inline operational comments docs/setup.mdDocker troubleshooting and backend testing sections- GitHub Actions CI with parallel frontend and backend test jobs
- Manual release flow with
scripts/release.sh, annotated tags, and release docs
- Final contract stabilization pass before stable release
- AVIF runtime validation confirmed in Docker target runtime
- API smoke validation plus browser smoke coverage added
- Required status checks activated on
main - Public contract review closed with docs and UX drift corrected
- Stable public baseline declared
- Release flow proven with real tags and pushes
- Core contract frozen in
docs/version-1-0-0.md
v1.0.0 has already been reached.
Use docs/version-1-0-0.md as the source of truth for the stable contract before planning future changes.
- SDD planning artifacts are tracked in Engram and ignored from git (
sdd/is ignored). - Project conventions and deeper planning context also live in
CLAUDE.mdanddocs/monorepo.md.