| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
Created by Charis Tsevis.
Current version: 0.4.2
Designers and illustrators rarely draw one icon at a time. You fill a page with forty sketches, or lay a whole set out on a single artboard, or scan a sheet of marks made with a brush. The artwork is finished — but it is all in one file, and it is useless that way.
What you actually need is forty separate assets: each one cropped to its own drawing, sitting on a consistent canvas so they line up in a grid, exported in whatever formats the project wants, and named something you can find again in six months. Producing that by hand means selecting, cropping, centring, exporting and typing a filename forty times over — an afternoon of mechanical work where the only real skill involved is patience, and where the results are never quite consistent.
Shapearator does that pass for you. Give it the sheet; it finds every individual mark or object, separates it, centres it on a shared canvas, writes out each format you asked for, and records what it did. A page of sketches becomes an organized, reusable asset library in one run.
The naming is the part that usually surprises people. Rather than icon_001.png, icon_002.png, a local vision model can look at each extracted icon and name it for what it is — lightbulb.png, heart.png, magnifier.png — and record tags and a confidence score alongside it. That turns the output from a numbered pile into something searchable.
All of it runs on your own machine. The vision models are local, the endpoints are hard-restricted to localhost, and your artwork is never uploaded anywhere. Shapearator is a local-first Python app with a desktop GUI and a full CLI: it reads PNG and SVG sheets, exports PNG, JPG, TIFF and SVG, and drives either Ollama or llama.cpp — whichever you already run — for naming.
| Best for | |
|---|---|
| GUI (main.py) | visual workflows, live preview, browsing results |
| CLI (shapearator.py) | automation, scripting, repeatable batches |
| MacShapearator | a native macOS app that bundles this engine |
Everything except live preview, the results browser and the appearance toggle is available from the CLI.
Requires Python 3.10+.
git clone https://github.com/tsevis/shapearator.git
cd shapearator
pip install -r requirements.txtTwo external tools must be on your PATH:
brew install inkscape potrace # macOSinkscape measures and rasterizes vector artwork; potrace traces monochrome bitmaps into vector paths. ./run.sh installs the Python dependencies automatically the first time it cannot import them.
Optional, and only for semantic naming — install either, or both:
./run.sh # GUI
python main.py # GUI, directly
python shapearator.py sheet.png --output-dir exports
python shapearator.py sheet.svg --output-dir exports --formats png svgInk is separated from paper using both luminance and colour distance, so coloured marks on coloured paper are found as reliably as black on white. Nearby marks are merged into one icon, which is what lets a multi-stroke drawing stay a single asset. Three settings drive it:
| Setting | Raise it to | Lower it to |
|---|---|---|
| padding | leave more air around each icon | crop tighter |
| min-area | ignore more dust and specks | keep smaller marks |
| merge-gap | reconnect strokes that sit further apart | split touching icons |
Four presets cover the usual cases: Balanced, Tiny Details, Loose Sketches, Bold Shapes.
Shapearator reads the artwork's own structure first.
Grouped artwork is taken as authored. If the sheet is one <g> per icon — how most vector icon sets are built — each group becomes one icon exactly as drawn. A drum kit made of nineteen separate paths stays one icon. No detection tuning is involved, and the settings above have no effect.
Wrapper layers are seen through. A sheet exported from Illustrator or Figma with all its artwork inside a single Layer_1 behaves like a flat one, including when that layer carries a transform.
Loose shapes still cluster visually. A hand-drawn sheet, where one icon is several disconnected strokes, is grouped the same way a PNG is — the settings above apply to that case.
Each extracted icon carries the definitions it actually references — gradients, clip paths, masks, filters, patterns, markers and <use>/<symbol> targets — resolved transitively, so a gradient inheriting stops from another gradient brings both. Definitions the icon does not use are left out. Document <style> rules are copied whole, since deciding which CSS applies would mean reimplementing the cascade.
SVG input is the highest-fidelity route. Raster-to-SVG depends on content: monochrome shapes are traced to real vector paths, while colour artwork is embedded as a bitmap inside the SVG.
Canvas scaling has three modes: keep each icon at its original size, scale everything by the factor that fits the largest icon (the default, which keeps relative sizes truthful), or fit each icon individually.
exports/
png/ jpg/ tiff/ svg/
metadata/
.shapearator-manifest.json
A run is staged inside the output folder and moved into place only after extraction, naming and metadata have all succeeded. If anything fails, the staged work is discarded and the previous export is left exactly as it was.
.shapearator-manifest.json records every file the last run wrote, and it is the only thing a later run will delete:
Files you add yourself are never tracked and never removed. Delete the manifest and Shapearator forgets the folder, reverting to add-only behaviour.
Each icon gets a JSON sidecar, and the same payload is embedded in exported SVGs: source bounds and size, canvas size, exported paths, vector mode, dominant colour and palette, plus the semantic label, tags and confidence when a model named it.
Metadata is written to be published. Exports get zipped and handed to other people, so nothing in them describes the machine that made them: source_file is the sheet's name, formats are relative to the export folder (which also keeps them valid after the folder moves), and any recorded error text has the home directory replaced with ~.
Shapearator treats Ollama and llama.cpp as interchangeable. Both satisfy one vision-client contract, so behaviour is consistent whichever you use.
| Ollama | llama.cpp | |
|---|---|---|
| Interface | native /api/generate | OpenAI-compatible /v1/chat/completions |
| Default endpoint | http://127.0.0.1:11434 | http://127.0.0.1:8080 |
| Models | ollama pull | GGUF weights + mmproj |
| Server | always-on daemon | the app can launch llama-server for you |
Which to pick? Ollama is the simplest: run the daemon, pull a vision model, done. Choose llama.cpp to run a specific GGUF — including newer models like Qwen3-VL that have no standard Ollama vision tag — or if you prefer one self-contained weights file. Shapearator can download the GGUF and mmproj and start the server for you.
The backend is checked before anything is exported. If it is not ready the run stops without writing a file, rather than quietly producing icon_001… names. Pass --allow-unnamed (or answer the GUI prompt) to export with generic filenames instead.
Either way the metadata records what actually happened. model_used is filled in only for an icon a model really named, and every icon carries a naming_status of named, failed, or not_requested with a reason when it failed. One icon whose labeling call fails is not fatal: it keeps its generic name, and the run finishes with a warning and a named/failed count.
Naming works with any format selection, including SVG alone — an icon with no bitmap gets one rendered internally for labeling and discarded afterwards.
Geometry extraction needs no model. For naming, Shapearator can fetch one:
python shapearator.py --setup # the default model for your backend
python shapearator.py --setup-all # every recommended modelIn the GUI a setup dialog appears the first time you launch with no vision model available. Recommended models, in preference order: Qwen3-VL, Qwen2.5-VL 3B, MiniCPM-V, moondream2, LLaVA, and SmolVLM 500M for a fast smoke test.
python shapearator.py INPUT --output-dir OUTPUT [options]Output — --formats png jpg tiff svg, --output-width, --output-height, --canvas-mode {original,uniform_to_largest,individual_fit}, --bitmap-export-mode {keep_background,transparent_preserve_interior}
Detection — --detection-preset {Balanced,Tiny Details,Loose Sketches,Bold Shapes}, --padding, --min-area, --merge-gap
Naming — --provider {geometry,ollama,llamacpp,directory}, --semantic-naming / --no-semantic-naming, --allow-unnamed, --ollama-url, --ollama-model, --llamacpp-url, --llamacpp-model
Setup and config — --setup, --setup-all, --use-config, --save-config
# Fine detail, three formats
python shapearator.py sheet.png --output-dir exports \
--detection-preset "Tiny Details" --formats png jpg svg
# Semantic naming with Ollama
python shapearator.py sheet.png --output-dir exports \
--provider ollama --ollama-model qwen2.5vl:3b --semantic-naming
# Semantic naming with llama.cpp
# llama-server -hf ggml-org/Qwen2.5-VL-3B-Instruct-GGUF --port 8080
python shapearator.py sheet.png --output-dir exports \
--provider llamacpp --llamacpp-model qwen2.5-vl --semantic-naming
# Load saved defaults and persist the resolved settings
python shapearator.py sheet.svg --use-config --save-config --output-dir exportsconfig/settings.json holds provider selection, naming, formats, canvas size and mode, detection values, and the last input/output paths. The GUI writes it continuously; the CLI reads it with --use-config and writes it with --save-config.
Loading is schema-aware. Unknown keys are ignored and invalid values fall back to their defaults one field at a time, so a config written by a newer version — or edited by hand — never blocks startup and never costs you your other settings.
pytest -q # 289 tests, fully offline
pytest --cov=services --cov-report=term-missing
ruff check services testsThe suite mocks every network call and subprocess, so it needs neither a model backend nor Inkscape.
| Path | Role |
|---|---|
| shapearator.py | CLI entry point |
| main.py | GUI entry point |
| services/ | the engine: detection, export, naming, settings |
| gui/ | tkinter/ttk desktop interface |
| tests/ | pytest suite |
| docs/ | sample sheets and screenshots |
FILE_STRUCTURE.md describes every module; MANUAL.md is the end-user guide.
| Symptom | Fix |
|---|---|
| Required binary 'inkscape' was not found | brew install inkscape |
| Required binary 'potrace' was not found | brew install potrace |
| Semantic naming is enabled but the backend is not ready | start the backend, run --setup, use --no-semantic-naming, or --allow-unnamed |
| ... requires a local endpoint | point the URL at localhost, 127.0.0.1 or ::1 |
| llama.cpp model list is empty | start llama-server with a vision model and its --mmproj, then refresh |
| Some icons kept generic names | the run reports how many failed; see naming_error in each metadata file |
| Small marks disappear | lower min-area, or use the Tiny Details preset |
| One icon split into several | raise merge-gap, or use Loose Sketches |
| Icons inconsistent in scale | use uniform_to_largest |
MIT — see LICENSE. Created by Charis Tsevis.
inkscape and potrace are required external tools, invoked as separate programs rather than linked in; they keep their own licenses (both GPL-2.0-or-later).
| Back | FazBrowse Home | New Git URL |