Vectorize: Raster to Clean SVG
Turn PNG/JPG bitmaps into faithful, clean SVG vector art. Built for flat/vector-style
art (mascots, logos, illustrations, icons) on Apple Silicon macOS.
When to Use
Use this skill when the user wants to:
- "vectorize" an image, or do "png to svg" / "raster to vector"
- "convert image to svg" or "trace" a bitmap
- Turn a mascot, logo, or illustration into scalable vectors
- Batch-convert a directory of PNG/JPG images to SVG
What It Does
scripts/vectorize.py runs a proven pipeline:
- Engine selection — COLOR art (fills, illustrations, logos) is traced with
vtracer; MONO/line art is traced with potrace (if installed) or vtracer
greyscale as a fallback. Default is
color.
- Optional background removal — two strategies, neither universally correct
(see "Transparency: choosing a strategy" below).
--transparent (safe default) uses
an edge-seeded flood fill; --global-key uses a global color-key. Applied before
tracing, so the SVG has no background shape.
- Vectorize with tuned vtracer params for flat art (stacked, spline).
- Optimize (
svgo --multipass via npx) — roughly 50% smaller. Skipped gracefully
if npx/svgo is unavailable.
- Verify (
cairosvg) — rasterizes the output SVG back to <name>.check.png next
to the SVG so a human can eyeball fidelity. Skipped gracefully if unavailable.
Prerequisites
uv (required) — brew install uv. Used to build the pinned Python 3.12 venv.
npx / svgo (optional) — for the optimize step. Provided by Node; --yes svgo
is fetched on demand. If missing, optimization is skipped with a warning.
potrace (optional) — brew install potrace. Only used in --mode mono for the
crispest line-art tracing. Without it, mono falls back to vtracer greyscale.
cairo (optional, for verification) — brew install cairo. The script auto-adds
Homebrew's lib dir to the loader path so cairosvg finds libcairo on Apple Silicon.
One-Time Setup (auto-bootstrapped)
There is nothing to install by hand beyond the prerequisites above. On first run the
script uses uv to create a cached Python 3.12 virtualenv at .venv/ inside this skill
directory and installs vtracer, pillow, and cairosvg into it. Subsequent runs reuse
that venv and are fast. If the venv ever gets corrupted, delete .venv/ and re-run.
Why a separate venv? vtracer's native wheel segfaults (exit 139) on Python 3.14
on Apple Silicon. It works reliably on Python 3.12. The script manages this itself —
it never relies on the system Python having vtracer.
Usage
# Single file, output alongside the input
python3 scripts/vectorize.py mascot.png
# Single file, custom output dir, with SAFE background removal (edge flood fill)
python3 scripts/vectorize.py mascot.png -o out/ --transparent
# Aggressive background removal (global color-key) -- clears interior gaps
python3 scripts/vectorize.py mascot.png -o out/ --global-key
# Whole directory (globs *.png / *.jpg / *.jpeg)
python3 scripts/vectorize.py ./assets/ -o ./svg/
# Mono / line-art (uses potrace if present, else vtracer greyscale)
python3 scripts/vectorize.py logo_bw.png --mode mono
# Auto-detect color vs mono
python3 scripts/vectorize.py drawing.png --mode auto
# Tuning + skipping optional steps
python3 scripts/vectorize.py mascot.png --filter-speckle 10 --color-precision 8
python3 scripts/vectorize.py mascot.png --no-optimize --no-verify
Parameter Reference
| Flag |
Default |
Meaning |
input |
— |
A single PNG/JPG file or a directory (globs images). |
-o, --outdir DIR |
alongside input |
Where to write .svg (and .check.png). |
--transparent |
off |
Remove background via edge flood fill (safe default). Preserves same-colored interior regions; leaves enclosed background opaque. |
--global-key (alias --transparent-aggressive) |
off |
Remove background via global color-key. Clears enclosed gaps too, but erases interior regions matching the background. |
--mode color|mono|auto |
color |
Engine: color=vtracer, mono=potrace/greyscale, auto=heuristic. |
--filter-speckle N |
6 |
Drop specks smaller than N px. Higher = fewer specks, smaller file. |
--color-precision N |
7 |
Color bits of precision. Higher = more faithful, larger file. |
--no-optimize |
off |
Skip the svgo pass. |
--no-verify |
off |
Skip the cairosvg .check.png render. |
Fixed vtracer params (proven on flat art): colormode=color, hierarchical=stacked,
mode=spline, corner_threshold=60, path_precision=3.
Transparency: choosing a strategy
Background removal has two strategies and neither is universally correct. Pick based
on the artwork, and always eyeball the .check.png afterward.
| Strategy |
Flag |
Removes |
Preserves |
Fails when |
| Edge flood fill (safe default) |
--transparent |
Only background connected to the image border |
Enclosed same-colored regions (e.g. white/cream eye interiors) |
Background is trapped inside the art (gaps between limbs, holes in a logo) — those stay opaque |
| Global color-key (aggressive) |
--global-key |
All pixels near the background color, anywhere |
Nothing color-matching is safe |
An interior region matches the background color — it gets erased, leaving a hole (e.g. cream eye-whites become transparent voids, which look like creepy black holes on a dark page) |
Rule of thumb:
- Start with
--transparent. It never eats interior detail.
- If enclosed gaps must be cleared and no interior region shares the background color,
use
--global-key.
- If the art has cream/white eyes, teeth, or highlights on a light background, avoid
--global-key — it will punch them out. Use --transparent and accept the enclosed
gaps, or hand-edit the SVG.
Troubleshooting
- vtracer segfault / exit 139 (the #1 gotcha). This happens when vtracer runs on
Python 3.14. The script avoids it by pinning a Python 3.12 venv via
uv — never run
the tracing on the system Python directly. If you see a segfault, delete .venv/ and
re-run so the venv rebuilds on 3.12. Confirm uv is installed (brew install uv).
- "uv not found." Install it:
brew install uv (expected at /opt/homebrew/bin/uv).
The bootstrap cannot proceed without it.
- SVG too large. Raise
--filter-speckle (e.g. 10–15) to drop small specks, and make
sure --optimize is on (svgo typically halves the size). Lowering --color-precision
also shrinks output.
- Jagged / blocky output. Raise
--color-precision (e.g. 8) and/or lower
--filter-speckle so fine detail survives.
- Background not removed. Use
--transparent. If a solid background still remains,
the flood-fill threshold may be too low for a noisy/gradient background — raise
FLOODFILL_THRESH in scripts/vectorize.py (default 50). Note the fill is
edge-connected, so same-colored interior regions are intentionally preserved.
- Gaps inside the art stayed opaque.
--transparent only removes background touching
the border. Enclosed background (between limbs, holes in a logo) needs --global-key —
but read the next entry first.
- Interior regions turned into holes / creepy voids. You used
--global-key on art
whose interior (eye-whites, teeth, highlights) matches the background color, so the
color-key erased them; on a dark page they read as black holes. Switch to --transparent
(which preserves interiors), or hand-edit the SVG. See "Transparency: choosing a strategy".
.check.png skipped ("cairosvg unavailable"). Install cairo: brew install cairo.
The script adds Homebrew's lib dir to DYLD_FALLBACK_LIBRARY_PATH automatically; if it
still can't load, confirm brew --prefix/lib contains libcairo.2.dylib.
- svgo skipped. Node/npx isn't on PATH. Install Node, or run with
--no-optimize to
silence the warning. Optimization is optional and never blocks output.
1---2name: vectorize3description: Convert raster images (PNG/JPG) into clean SVG vector art. Use whenever the user wants to vectorize an image, do png to svg, raster to vector, convert image to svg, trace an image, turn a mascot/logo/illustration into vectors, or produce scalable SVG from a bitmap. Handles color art (vtracer) and mono/line art (potrace), with optional background removal, svgo optimization, and a verification render.4---56# Vectorize: Raster to Clean SVG78Turn PNG/JPG bitmaps into faithful, clean SVG vector art. Built for flat/vector-style9art (mascots, logos, illustrations, icons) on Apple Silicon macOS.1011## When to Use1213Use this skill when the user wants to:1415- "vectorize" an image, or do "png to svg" / "raster to vector"16- "convert image to svg" or "trace" a bitmap17- Turn a mascot, logo, or illustration into scalable vectors18- Batch-convert a directory of PNG/JPG images to SVG1920## What It Does2122`scripts/vectorize.py` runs a proven pipeline:23241. **Engine selection** — COLOR art (fills, illustrations, logos) is traced with25 **vtracer**; MONO/line art is traced with **potrace** (if installed) or vtracer26 greyscale as a fallback. Default is `color`.272. **Optional background removal** — two strategies, *neither universally correct*28 (see "Transparency: choosing a strategy" below). `--transparent` (safe default) uses29 an edge-seeded flood fill; `--global-key` uses a global color-key. Applied *before*30 tracing, so the SVG has no background shape.313. **Vectorize** with tuned vtracer params for flat art (stacked, spline).324. **Optimize** (`svgo --multipass` via npx) — roughly 50% smaller. Skipped gracefully33 if npx/svgo is unavailable.345. **Verify** (`cairosvg`) — rasterizes the output SVG back to `<name>.check.png` next35 to the SVG so a human can eyeball fidelity. Skipped gracefully if unavailable.3637## Prerequisites3839- **`uv`** (required) — `brew install uv`. Used to build the pinned Python 3.12 venv.40- **`npx` / `svgo`** (optional) — for the optimize step. Provided by Node; `--yes svgo`41 is fetched on demand. If missing, optimization is skipped with a warning.42- **`potrace`** (optional) — `brew install potrace`. Only used in `--mode mono` for the43 crispest line-art tracing. Without it, mono falls back to vtracer greyscale.44- **`cairo`** (optional, for verification) — `brew install cairo`. The script auto-adds45 Homebrew's lib dir to the loader path so `cairosvg` finds `libcairo` on Apple Silicon.4647## One-Time Setup (auto-bootstrapped)4849There is **nothing to install by hand** beyond the prerequisites above. On first run the50script uses `uv` to create a cached Python 3.12 virtualenv at `.venv/` inside this skill51directory and installs `vtracer`, `pillow`, and `cairosvg` into it. Subsequent runs reuse52that venv and are fast. If the venv ever gets corrupted, delete `.venv/` and re-run.5354**Why a separate venv?** vtracer's native wheel **segfaults (exit 139) on Python 3.14**55on Apple Silicon. It works reliably on **Python 3.12**. The script manages this itself —56it never relies on the system Python having vtracer.5758## Usage5960```bash61# Single file, output alongside the input62python3 scripts/vectorize.py mascot.png6364# Single file, custom output dir, with SAFE background removal (edge flood fill)65python3 scripts/vectorize.py mascot.png -o out/ --transparent6667# Aggressive background removal (global color-key) -- clears interior gaps68python3 scripts/vectorize.py mascot.png -o out/ --global-key6970# Whole directory (globs *.png / *.jpg / *.jpeg)71python3 scripts/vectorize.py ./assets/ -o ./svg/7273# Mono / line-art (uses potrace if present, else vtracer greyscale)74python3 scripts/vectorize.py logo_bw.png --mode mono7576# Auto-detect color vs mono77python3 scripts/vectorize.py drawing.png --mode auto7879# Tuning + skipping optional steps80python3 scripts/vectorize.py mascot.png --filter-speckle 10 --color-precision 881python3 scripts/vectorize.py mascot.png --no-optimize --no-verify82```8384## Parameter Reference8586| Flag | Default | Meaning |87|------|---------|---------|88| `input` | — | A single PNG/JPG file **or** a directory (globs images). |89| `-o, --outdir DIR` | alongside input | Where to write `.svg` (and `.check.png`). |90| `--transparent` | off | Remove background via **edge flood fill** (safe default). Preserves same-colored interior regions; leaves enclosed background opaque. |91| `--global-key` (alias `--transparent-aggressive`) | off | Remove background via **global color-key**. Clears enclosed gaps too, but erases interior regions matching the background. |92| `--mode color\|mono\|auto` | `color` | Engine: color=vtracer, mono=potrace/greyscale, auto=heuristic. |93| `--filter-speckle N` | `6` | Drop specks smaller than N px. **Higher = fewer specks, smaller file.** |94| `--color-precision N` | `7` | Color bits of precision. **Higher = more faithful, larger file.** |95| `--no-optimize` | off | Skip the svgo pass. |96| `--no-verify` | off | Skip the cairosvg `.check.png` render. |9798**Fixed vtracer params (proven on flat art):** `colormode=color`, `hierarchical=stacked`,99`mode=spline`, `corner_threshold=60`, `path_precision=3`.100101## Transparency: choosing a strategy102103Background removal has two strategies and **neither is universally correct**. Pick based104on the artwork, and always eyeball the `.check.png` afterward.105106| Strategy | Flag | Removes | Preserves | Fails when |107|----------|------|---------|-----------|------------|108| **Edge flood fill** (safe default) | `--transparent` | Only background *connected to the image border* | Enclosed same-colored regions (e.g. white/cream eye interiors) | Background is **trapped inside** the art (gaps between limbs, holes in a logo) — those stay opaque |109| **Global color-key** (aggressive) | `--global-key` | *All* pixels near the background color, anywhere | Nothing color-matching is safe | An interior region **matches the background color** — it gets erased, leaving a hole (e.g. cream eye-whites become transparent voids, which look like creepy black holes on a dark page) |110111**Rule of thumb:**112- Start with `--transparent`. It never eats interior detail.113- If enclosed gaps must be cleared **and** no interior region shares the background color,114 use `--global-key`.115- If the art has cream/white eyes, teeth, or highlights on a light background, **avoid116 `--global-key`** — it will punch them out. Use `--transparent` and accept the enclosed117 gaps, or hand-edit the SVG.118119## Troubleshooting120121- **vtracer segfault / exit 139 (the #1 gotcha).** This happens when vtracer runs on122 Python 3.14. The script avoids it by pinning a **Python 3.12** venv via `uv` — never run123 the tracing on the system Python directly. If you see a segfault, delete `.venv/` and124 re-run so the venv rebuilds on 3.12. Confirm `uv` is installed (`brew install uv`).125- **"uv not found."** Install it: `brew install uv` (expected at `/opt/homebrew/bin/uv`).126 The bootstrap cannot proceed without it.127- **SVG too large.** Raise `--filter-speckle` (e.g. 10–15) to drop small specks, and make128 sure `--optimize` is on (svgo typically halves the size). Lowering `--color-precision`129 also shrinks output.130- **Jagged / blocky output.** Raise `--color-precision` (e.g. 8) and/or lower131 `--filter-speckle` so fine detail survives.132- **Background not removed.** Use `--transparent`. If a solid background still remains,133 the flood-fill threshold may be too low for a noisy/gradient background — raise134 `FLOODFILL_THRESH` in `scripts/vectorize.py` (default 50). Note the fill is135 edge-connected, so same-colored *interior* regions are intentionally preserved.136- **Gaps *inside* the art stayed opaque.** `--transparent` only removes background touching137 the border. Enclosed background (between limbs, holes in a logo) needs `--global-key` —138 but read the next entry first.139- **Interior regions turned into holes / creepy voids.** You used `--global-key` on art140 whose interior (eye-whites, teeth, highlights) matches the background color, so the141 color-key erased them; on a dark page they read as black holes. Switch to `--transparent`142 (which preserves interiors), or hand-edit the SVG. See "Transparency: choosing a strategy".143- **`.check.png` skipped ("cairosvg unavailable").** Install cairo: `brew install cairo`.144 The script adds Homebrew's lib dir to `DYLD_FALLBACK_LIBRARY_PATH` automatically; if it145 still can't load, confirm `brew --prefix`/lib contains `libcairo.2.dylib`.146- **svgo skipped.** Node/npx isn't on PATH. Install Node, or run with `--no-optimize` to147 silence the warning. Optimization is optional and never blocks output.