SVG Slimmer
Re-trace logos and icons as compact SVGs, colour by colour, or quantize them to small indexed PNGs. It runs entirely on your own machine, in the browser or as a desktop app: nothing is uploaded, unless you choose AI redraw and give it your own OpenRouter key.
Use it: https://svg-slimmer.jderrick.app
Auto-tracers such as VTracer, and exports from design tools, often produce SVGs made of thousands of short straight segments, plus editor metadata. SVG Slimmer redraws the artwork as long smooth curves, then checks the result against the original pixel by pixel so you can see exactly what changed. A traced logo typically comes out 70–90% smaller with no visible difference.
What it does
- Opens SVGs and bitmaps (PNG, JPEG, WebP). Drop a file anywhere on the page, pick one, or paste SVG code. The desktop app also pastes an SVG copied in Inkscape or Finder; a browser only gets Inkscape's small preview picture, so on the web open or drop the file instead.
- Keeps colours. It finds the palette, traces each colour as a stacked layer (each layer runs under the ones above it, so no gaps open between colours), and snaps to the exact colours an SVG declares.
- Lets you choose the palette. Set the most colours to keep and how similar two colours must be to merge. Click a colour once to lock it in, so it survives however far you reduce; again to leave it out; a third time to hand it back. Each colour shows its share of the artwork.
- Handles AI images and upscales. Blended edge pixels only take one of the colours actually meeting at that edge, so no fringe of a third colour appears. Specks and upscaler halos are removed before tracing, and the background is removed only where it touches the border, so white inside the artwork stays white.
- Balances size against detail. Presets run from Smallest to Finest. "Protect small shapes" keeps eyes, letters and thin lines sharp while big curves are still simplified.
- Shows what changed. A difference view marks changed pixels in red, and a zoom moves both views together. The verdict ignores edges that moved by less than a pixel. A colour score (the average CIE ΔE, and the share of pixels over 5) shows how far the colours themselves moved, which the verdict can't: it sorts both images into the palette first, so a gradient traced as bands looks as good to it as the gradient.
- Keeps gradients, if you ask it to. Keep gradients finds the bands that are really one smooth ramp and fills them with a linear or radial gradient fitted to the original, with a radial sheen over it if it has one. Soft glows inside it become blurred shapes, and a wide, evenly fading halo round the artwork becomes a blurred copy of its outline. Each fit is checked against the bands it replaces, region by region, and the bands stay wherever they're closer. A ticket logo built from gradients and glows comes out 19 KB instead of 102 KB, with its colours 1.8 ΔE off on average instead of 5.1. Where the colour is soft lighting no gradient can follow, as in many AI images, Soft lighting can make it a smooth colour field instead: a coarse grid of colours clipped to the shape, written either as squares blurred together (pure vector) or as a tiny picture the browser enlarges smoothly (smaller, but an image inside the SVG). It is used only where it is clearly closer than the gradient. Glows can grow from see-through holes too, such as bulbs cut out of a ticket. It's slower, and Find smallest doesn't try it.
- Slider ends. Under each slider, what each end does, with a smaller file tag on the end that shrinks the SVG (measured on four test images). Each setting's explanation is behind the (i) by its name: hover it, or click or tap to keep it open.
- AI redraw, if you want it and have an OpenRouter key. An AI model rebuilds the artwork the way a designer would, from simple shapes, gradients, blurs and lettering drawn as outlines, using the palette's measured colours. The app scores its drawing like any trace, and One more round sends the model the original, its best drawing so far and a heat map of the colour difference so it can fix what's wrong. Every round is kept, next to the latest trace, in a row of buttons above the pictures, so you can flick between them and compare sizes and ΔE; One more round builds on the round on show, and changing a setting retraces without losing the rounds. A transparent image is shown to the model over a backdrop its artwork doesn't use, since models see clear pixels as black. Each round stands on its own, so the tenth costs the same as the first. Start from a rough trace also sends a quick trace so the model can read off exact positions: much closer on flat logos and lettering, worse on soft lighting. In testing, GPT-6.1 Sol started from a trace redrew the Creative Australia logo at 2.4 KB and ΔE 1.35, closer than the trace itself (14 KB, ΔE 1.53), for about 10¢; Gemini 4 Argon did best on gradients and glows. It's less exact than tracing on soft-lit AI images, where outlines come out a few pixels off. The key is kept on that device and sent only to OpenRouter, and the image goes to OpenRouter and the model's maker. The SVG that comes back is cleaned of scripts, event handlers and outside links before it's shown, and for a transparent original, of any rectangle painted over the whole picture. Models are told not to blur or texture the whole drawing to imitate a scan.
- Tidies SVGs that are already well traced. Redrawing a good trace, such as one from VTracer, only loses detail, and on busy artwork like pen hatching the curves cost more bytes than the straight lines they replace. Tidy keeps the SVG's own outlines and only merges near-identical colours, joins shapes of one colour into a single path wherever that can't change what's painted over what, and rewrites the path data compactly. Remove the background works here too: it leaves out shapes of the background colour that touch the canvas edge, so white inside the artwork stays. It reads flat SVGs, the kind tracers write; anything with strokes, styles, gradients or other shapes is left to Redraw. A 166 KB VTracer drawing comes out 94 KB with 0.01% of pixels changed.
- Straight lines when they're smaller. Corners at 0 draws every edge as a straight line, like VTracer's polygon mode.
- Keep thin slivers stops speck removal filling the gaps between pen strokes, so sketches don't darken; round specks still go.
- Find smallest tries each detail and smoothing setting, straight lines, stronger colour merging and, for an SVG, Tidy, and keeps the smallest file that stays within the difference you allow.
- Exports the slimmed SVG, or a quantized indexed PNG of the original: the image reduced to the palette, written as a true palette PNG at 1, 2, 4 or 8 bits per pixel, with a transparent background if you removed it.
It works best on flat artwork: logos, icons and illustrations with a handful of solid colours. Gradients and soft shadows are reduced to the nearest solid colour unless Keep gradients is on, and even then a highlight with a hard edge inside a gradient stays as bands and an offset drop shadow is left out. Text is traced as shapes.
How it works
- The source is drawn at the trace size (1024, 2048 or 4096 px on the long side).
- Palette: a histogram of solid pixels only, so blended edge pixels never become colours of their own; similar colours merged; reduced to the colour limit by merging the closest pair (weighted so small, distinct colours survive); refined with k-means; your locked and removed colours applied.
- Quantize: every pixel takes its nearest palette colour. Blended edge pixels are restricted to the colours of the nearest solid pixels around them. The background is flood-filled from the border. A majority filter and speck removal clean the map.
- Trace (Redraw): each colour becomes a mask covering itself and everything above it, traced with Potrace. Small shapes can take a lightly smoothed second trace. A bitmap smaller than the trace size is traced at its own size and the curves scaled up: drawn bigger, its one-pixel jaggies would become steps several pixels high, which Potrace keeps as detail instead of smoothing away. Paths are rewritten as rounded relative commands.
- Compare: original and result are drawn at 2048 px and compared colour by colour, with a one-pixel tolerance (for a bitmap drawn bigger than its own size, half of one of its pixels, since it can't place an edge any closer). The colour score compares the actual colours (CIE Lab), with see-through pixels put over white and over black and the worse one counted.
Keep gradients (core/src/gradient.rs) works between steps 3 and 4. The colour map is split into regions, connected patches of one colour, and two touching regions count as one ramp when the original changes smoothly across their border: no jump and no step, however small, and the change either carries on past the border or is tiny next to the difference between the two colours. A flat edge between two close colours changes all at once, within a pixel or two, so it never joins. Locked colours never join a ramp either. Each ramp is fitted robustly with flat, linear and radial gradients of 2 to 4 stops and a linear gradient with a sheen, and the simplest that is nearly as good as the best is kept. What it leaves over, in blobs round the shapes inside it, is fitted as glows: one colour, one opacity and one blur, a glow per shape. The ramp then becomes one layer, painted under the sharp shapes inside it, with its glows between. Blurred shapes are traced at a fifth of their blur, since finer detail never shows, and their filters reach three blurs past the shape so wide glows aren't squared off. With gradients on, the verdict doesn't count a pixel that crossed a band boundary unless its colour also moved by half the merge distance.
Tidy skips steps 1 to 4: it reads the SVG's paths directly (core/src/tidy.rs), snaps fills within Merge similar colours to the most used of them, joins each path to the latest earlier path of its colour when nothing painted in between overlaps it and it overlaps nothing in that path (by bounding box, so fill rules can't open holes), and writes the data as relative or absolute commands, whichever is shorter, with h/v for level lines. Step 5 still checks the result.
Develop and deploy
The pipeline (palette, quantize, trace, compare) is Rust, in core/, and runs in three places:
- The web app (
index.html) runs it as WebAssembly in a pool of Web Workers, one request per worker, so "Find smallest" tries its settings in parallel and multi-colour logos trace their layers in parallel. Where workers aren't allowed it runs on the page's own thread.
- The command line:
svg-slim in cli/.
- The desktop app in
src-tauri/ (Tauri), which shows the same page in the system's web view and runs the core natively, on every core. It saves through the system's Save dialog.
The page draws images with the browser's canvas and hands the core RGBA pixels, so an SVG looks exactly as it does in a browser. Requests and replies are single binary messages, described in core/src/api.rs; web/core-rt.js packs them.
npm run build # compiles the core to WebAssembly, then writes dist/index.html with it inlined
npm run dev # build, then serve locally with wrangler
npm run deploy # build, then deploy to Cloudflare (needs wrangler login or CLOUDFLARE_API_TOKEN)
Building needs Rust with the wasm32-unknown-unknown target (rustup target add wasm32-unknown-unknown). dist/index.html is a single file and also works opened straight from disk.
Command line
cargo install --path cli
svg-slim logo.png # writes logo.slim.svg with the Balanced preset
svg-slim logo.svg --preset fine -o out.svg
svg-slim logo.png --smallest --target 0.5 --png logo-quantized.png
svg-slim glow.png --gradients # keep gradients, glows and halos
svg-slim ai.png --gradients --field squares # soft lighting as a blurred colour grid (or --field picture)
svg-slim --help
Desktop app
cargo install tauri-cli --version "^2" # once
cargo tauri dev # build the page, then run the app
cargo tauri build # SVG Slimmer.app and a .dmg in target/release/bundle/
SLIMMER_SELFTEST=logo.png target/release/svg-slimmer-app drops the image on the page, runs a trace, Find smallest and the Finest preset through the real UI, prints the timings and each native request, and quits.
Checking the port
The Rust pipeline started as a port of the JavaScript this app used to run, and keeps its arithmetic, JS rounding rules included, so it gives byte-identical SVGs from the same pixels. core/examples/parity.rs checks that against reference data dumped from the JS version: raw pixels, palette, index maps, SVG and difference score for each case.
cargo run --release -p slimmer-core --example parity -- <case dir>...
Credits
Tracing by Potrace by Peter Selinger, ported to Rust (core/src/potrace.rs) from kilobtye's JavaScript port, the potrace-browser package. Potrace is licensed under the GPL, and so is this project.