Fast, private image compression that runs entirely in your browser. No uploads, no servers — your images never leave your device.
slimg decodes and re-encodes images using WebAssembly codecs (jSquash) across a pool of web workers, so you can batch-compress dozens of files in parallel without freezing the UI.
- 100% client-side — all processing happens in your browser via WASM. Nothing is uploaded.
- JPEG, PNG & WebP — decode and encode any combination, or keep the original format.
- Format conversion — turn PNGs into WebP, JPEGs into PNG, and so on.
- Quality control — adjustable quality for JPEG/WebP encoding.
- Lossless PNG optimization — powered by oxipng with selectable optimization levels.
- Resize on the fly — optional max width/height (never upscales).
- Parallel batch processing — a worker pool sized to your CPU keeps compression fast and the page responsive.
- One-click download — grab files individually or export everything as a
.zip. - Drag & drop with instant before/after size and savings summary.
- Internationalized — English, 中文, and 日本語 out of the box.
- React 19 + TypeScript
- jSquash WASM codecs (JPEG, PNG, oxipng, WebP)
- Comlink for ergonomic web worker RPC
- Zustand for state
- client-zip for in-browser zip export
- i18next for localization
- Vite+ toolchain (Vite, Rolldown, Oxlint, Oxfmt)
This project uses the Vite+ toolchain via the global vp CLI.
# install dependencies
vp install
# start the dev server
vp dev
# build for production
vp build
# preview the production build
vp previewPrefer pnpm scripts?
pnpm dev,pnpm build, andpnpm previewwrap the same commands.
- Files dropped into the browser are read as
ArrayBuffers and dispatched to aCodecPool. - The pool spreads jobs across
navigator.hardwareConcurrency - 1web workers, transferring buffers (zero-copy) to each worker. - Each worker lazily loads only the WASM codecs it needs and caches them, so repeated formats pay the init cost only once.
- Decoded
ImageDatais optionally resized, then re-encoded to the target format and handed back to the UI as aBlob.
Because everything is local, slimg works offline and handles sensitive images without ever transmitting them.
src/
├── core/ # worker pool, types, download/zip helpers
├── worker/ # codec worker + per-format encode/decode modules
├── components/ # DropZone, SettingsPanel, TaskList, ...
├── store/ # Zustand task store
└── i18n/ # i18next setup + locale files (en, zh, ja)
Issues and pull requests are welcome. Before submitting, please run:
vp check # format, lint, and type-check
vp test # run tests