iconsmaker
One SVG in. Every platform icon bundle out.
iconsmaker reads a single source SVG and a small TOML config file and generates
deployment-ready icon assets for macOS, Windows, and Linux — including packaging
variants for Snap, Flatpak, and AppImage — in a single command.
Why iconsmaker
Most icon generators target macOS, Windows, and web favicons — and they almost
always start from a raster (PNG) image. You can press them into service for
Linux, but that's where it falls apart: you're left manually producing a spread
of exact sizes, applying strict reverse-DNS file names, reorganizing everything
into the freedesktop hicolor directory tree, and then hand-writing the
.desktop entry, the AppStream metainfo.xml, and a separate icon variant for
each packaging format (Snap, Flatpak, AppImage). The requirements are finite but
scattered across specs, and looking them all up and assembling them by hand for
every project is a slow, error-prone chore.
iconsmaker automates the whole thing from a single 1024 × 1024 SVG. One
command renders every required size, applies the platform shaping (like the macOS
squircle) automatically, names and files each asset exactly where each platform
expects it, and generates the accompanying metadata — producing every permutation
for macOS, Windows, and Linux (including Snap/Flatpak/AppImage) with no manual
resizing, renaming, or reorganizing. And because the source is vector rather than
a raster image, small sizes stay crisp instead of turning to mush.
What it generates
| Platform | Output | Notes |
|---|---|---|
| macOS | dist/macos/AppName.icns |
7 ICNS elements (16 – 1024 px), Apple squircle mask applied |
| Windows | dist/windows/AppName.ico |
7 sizes (16 – 256 px), PNG + BMP per ICO spec |
| Linux | dist/linux/hicolor/ |
9 PNG sizes + scalable SVG + optional symbolic SVG |
| Linux | dist/linux/<id>.desktop |
freedesktop Desktop Entry |
| Linux | dist/linux/<id>.metainfo.xml |
AppStream MetaInfo for GNOME Software / Discover |
| Snap | dist/snap/snap/gui/ |
256 × 256 store icon + desktop file |
| Flatpak | dist/flatpak/app/share/ |
Full hicolor tree + metadata under the Flatpak prefix |
| AppImage | dist/appimage/<Name>.AppDir/ |
Top-level icon, .DirIcon, inner hicolor tree |
Installation
Prebuilt native installers are published to GitHub Releases for each tagged version.
macOS
Or download iconsmaker-<version>-universal-apple-darwin.tar.gz from the release
and place iconsmaker on your PATH — it's a universal binary that runs natively
on both Apple Silicon and Intel Macs.
Linux
x86_64 (amd64) and arm64 (aarch64) packages are published — pick the one
matching uname -m.
# Debian / Ubuntu
# Fedora / RHEL / openSUSE
Both packages install the binary to /usr/bin/iconsmaker and the man page to
/usr/share/man/man1.
Windows
winget install ideocentric.iconsmaker
winget picks the right build for your CPU automatically. To install by hand,
download and run iconsmaker-<version>-x86_64.msi or iconsmaker-<version>-arm64.msi
(installs to Program Files and adds itself to PATH).
From source
Requires a Rust 1.85+ toolchain. For full prerequisites, per-platform notes, and how to build a universal macOS binary or the installers, see BUILDING.md.
Documentation / man page
On macOS and Linux the package installs a man page:
On Windows the MSI installs iconsmaker.html alongside the binary. On any
platform you can also print the man page directly:
|
See packaging/ for how the installers are built.
Prerequisites
Choose one:
Docker (recommended — no Rust toolchain needed)
Docker 20.10+
Cargo (native build)
Rust 1.85+ (edition 2024)
Full build instructions and per-platform prerequisites are in BUILDING.md.
Quick start
Via Docker
# 1. Clone and build the image once
# 2. Run against any project
Via Cargo
# From your project directory
Two ways to run
iconsmaker can be driven by a config file or entirely by flags, and the two
compose — flags override the config file.
Config mode (IDE / toolchain): keep an icons.toml in your project and run it
as part of your build. If --config is omitted, ./icons.toml is used when
present.
Flag mode (web / CI backend): pass everything on the command line — ideal when
a UI collects the parameters and forwards them. Select platforms with
--macos --windows --linux (or --all):
Passing any platform/packaging flag switches selection to the CLI, so a lone
--macos builds only macOS (it does not also pick up platforms from the config).
Required fields depend on the platforms you select
Requirements form a grid. iconsmaker reports every missing field at once, naming
the selected target that needs it, why, and how to supply it (both flag and
config form). Hard = blocks; Soft = warns (and becomes an error under
--strict).
| Field | macOS | Windows | Linux | Packaging* |
|---|---|---|---|---|
input SVG (-i / [input] svg) |
Hard | Hard | Hard | Hard |
--name |
Hard | Hard | Hard | Hard |
--id (reverse-DNS) |
Hard | — | Hard | Hard |
--exec |
— | — | Hard | Hard |
--comment, --description, --categories, --metadata-license, --license, --developer-name |
— | — | Soft | Soft |
* Packaging (--snap / --flatpak / --appimage) requires --linux and
inherits all Linux requirements.
Format lints (Soft): a non-reverse-DNS --id and unregistered --categories
values are flagged as warnings.
Every flag mirrors a config key (e.g. --metadata-license ⇄ [app] metadata_license); run iconsmaker --help for the full list.
Recommended project layout
Place your icon assets in an icons/ subdirectory of your project:
myproject/
├── icons/
│ ├── master.svg ← your 1024 × 1024 source artwork (required)
│ ├── symbolic.svg ← monochrome tray/panel variant (optional)
│ └── icons.toml ← configuration
├── dist/ ← generated output (add to .gitignore)
└── ... (project source)
The dist/ directory is entirely generated — never commit it.
Preparing your artwork
Base SVG (master.svg)
| Property | Requirement |
|---|---|
| Format | SVG 1.1 |
| Viewbox | Square — 1024 1024 strongly recommended |
| Text | Must be converted to outlines. The renderer has no font loader; text elements that reference font families will not render. Export "text as paths" / "outline text" from your vector editor. |
| Embedded images | Self-contained raster elements (base64 <image>) are supported. External file references (xlink:href="file.png") are not. |
| Filters | The resvg engine supports a useful subset of SVG filters: feGaussianBlur, feOffset, feFlood, feComposite, feMerge, feBlend, feColorMatrix, and feSpecularLighting. Complex filter chains (e.g. feConvolveMatrix) may be ignored. |
| Size | Keep under 2 MB. Highly complex paths slow down rasterization. |
What NOT to include in the master SVG
- Drop shadows — macOS and Linux add their own at the system level.
- Rounded corners / squircle clipping — the tool applies Apple's squircle mask automatically for macOS.
- Platform-specific layering or gloss — the
[effects]section handles depth shading.
Design the artwork as a flat square. The tool handles all platform shaping.
Symbolic SVG (symbolic.svg)
Used on Linux for system trays, notification areas, and high-contrast modes.
- Single colour — use
#363636orcurrentColor - Designed on a 16 × 16 grid (simplified silhouette of the full icon)
- No fills outside the silhouette; no gradients
- Place in
hicolor/symbolic/apps/automatically whensymbolic_svgis set
Apple squircle shape
The macOS squircle mask is generated analytically at every icon size — there
is no shape file to supply or reference. Its roundness is controlled by the
squircle_power value in the [effects] section (default 5.0, macOS-like).
See the [effects] reference below.
icons.toml reference
Create this file in your icons/ directory.
All fields in [app] are used for metadata generation (.desktop, metainfo.xml).
# ── Application identity ───────────────────────────────────────────────────────
[]
# Reverse-DNS identifier — used as the filename stem for every asset and as the
# Flatpak / Snap / D-Bus application ID. Must be consistent across all files.
= "com.example.MyApp"
= "My App"
= "My Application Type" # e.g. "Audio Editor", "Image Viewer"
= "One-line summary" # .desktop Comment=, AppStream <summary>
= "myapp %F" # .desktop Exec= — shell command to launch
# freedesktop.org menu categories:
# https://specifications.freedesktop.org/menu-spec/latest/apa.html
= ["Category", "SubCategory"]
= ["keyword1", "keyword2"]
# Must match your window's WM_CLASS so docks/taskbars group windows correctly.
= "myapp"
= ["application/x-myapp"] # Leave empty if no file associations
= "GPL-3.0-or-later" # SPDX identifier for your app
= "CC0-1.0" # License for the metadata itself
= "Longer paragraph for store listings."
= "https://example.com"
= "Your Name or Studio"
# ── Input assets ──────────────────────────────────────────────────────────────
[]
= "icons/master.svg" # Path relative to the working directory
# The macOS squircle mask is generated analytically — no shape file needed.
# Tune its roundness via [effects] squircle_power below.
# Monochrome SVG for Linux trays (optional):
# symbolic_svg = "icons/symbolic.svg"
# ── Output location ───────────────────────────────────────────────────────────
[]
= "dist"
# ── Platform targets ──────────────────────────────────────────────────────────
[]
= true
= true
= true
# ── Linux PNG sizes ───────────────────────────────────────────────────────────
[]
# Standard freedesktop hicolor sizes. 48 is the minimum required; keep all of
# these for full desktop-environment compatibility.
= [16, 22, 24, 32, 48, 64, 128, 256, 512]
# ── Visual effects (macOS) ────────────────────────────────────────────────────
[]
# SDF bevel: simulates overhead lighting on the squircle boundary.
# Rim highlight on top, subtle shadow on bottom. Applied before masking.
= true
= 0.35 # 0.0 = flat, 1.0 = maximum. 0.35 is a natural default.
= 0.12 # Gaussian blur on the lighting maps.
# 0.00 = no smoothing (may show staircase artifacts)
# 0.12 = default (smooth without losing edge definition)
# 0.30 = very soft
# ── Packaging formats ─────────────────────────────────────────────────────────
[]
= false # Generates dist/snap/snap/gui/
= false # Generates dist/flatpak/app/share/
= false # Generates dist/appimage/<Name>.AppDir/
= false # (reserved — not yet implemented)
Running
Docker
# Run from your project root, mounting it as /workspace:
# With verbose output:
# Using the included docker-compose.yml (from the iconsmaker directory):
PROJECT_DIR=/path/to/myproject \
Cargo
# From your project directory:
# Or if iconsmaker is installed on PATH:
Output reference
After a successful run with all platforms enabled:
dist/
├── macos/
│ └── MyApp.icns macOS icon bundle
├── windows/
│ └── MyApp.ico Windows icon (multi-size)
├── linux/
│ ├── com.example.MyApp.desktop freedesktop Desktop Entry
│ ├── com.example.MyApp.metainfo.xml AppStream MetaInfo
│ └── hicolor/
│ ├── 16x16/apps/com.example.MyApp.png
│ ├── 22x22/apps/ ...
│ ├── 24x24/apps/ ...
│ ├── 32x32/apps/ ...
│ ├── 48x48/apps/ ...
│ ├── 64x64/apps/ ...
│ ├── 128x128/apps/ ...
│ ├── 256x256/apps/ ...
│ ├── 512x512/apps/ ...
│ └── scalable/apps/com.example.MyApp.svg
├── snap/
│ └── snap/gui/
│ ├── icon.png 256 × 256 Snap Store icon
│ └── com.example.MyApp.desktop
├── flatpak/
│ └── app/share/
│ ├── applications/com.example.MyApp.desktop
│ ├── metainfo/com.example.MyApp.metainfo.xml
│ └── icons/hicolor/ ... (full hicolor tree)
└── appimage/
└── MyApp.AppDir/
├── com.example.MyApp.png top-level icon
├── .DirIcon -> ... symlink (Linux only)
├── com.example.MyApp.desktop
└── usr/share/ ...
Installing Linux assets (tarball / manual)
# Icons
# Desktop integration
# Validate
Visual effects
The [effects] section applies a depth treatment to macOS icons only,
simulating overhead lighting on the squircle boundary.
gloss_strength controls how strong the lighting contrast is
depth_blur controls how smoothly the lighting fades across the edge band
The bevel band is fixed at 7 % of the icon's shorter dimension — about 72 px at 1024 px, 18 px at 256 px. Edge pixels facing the light source (upper-left) are brightened via Screen blend; pixels facing away are darkened via Multiply.
Tuning guide:
gloss_strength |
Effect |
|---|---|
0.15 |
Barely perceptible — suitable for very dark or very light icons |
0.35 |
Default — natural overhead light on a physical surface |
0.55 |
Dramatic — similar to an app icon under strong directional lighting |
depth_blur |
Effect |
|---|---|
0.00 |
Raw edge sampling — may show subtle pixel-level staircase |
0.12 |
Default — artifacts smoothed, edge still defined |
0.25 |
Soft — good for icons with gradients near the squircle boundary |
Set squircle_depth = false for a completely flat icon (no lighting).
Build system integration
CMake
Add icon generation as a custom target that runs before the app bundle step.
# Find the tool (adjust if using Docker or a specific install path)
find_program(ICONSMAKER_BIN iconsmaker
HINTS "$ENV{HOME}/.cargo/bin" "/usr/local/bin"
)
set(ICON_CONFIG "${CMAKE_SOURCE_DIR}/icons/icons.toml")
set(ICON_SVG "${CMAKE_SOURCE_DIR}/icons/master.svg")
set(ICON_ICNS "${CMAKE_SOURCE_DIR}/dist/macos/${PROJECT_NAME}.icns")
set(ICON_ICO "${CMAKE_SOURCE_DIR}/dist/windows/${PROJECT_NAME}.ico")
if(ICONSMAKER_BIN)
add_custom_command(
OUTPUT "${ICON_ICNS}" "${ICON_ICO}"
COMMAND "${ICONSMAKER_BIN}" --config "${ICON_CONFIG}"
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
DEPENDS "${ICON_SVG}" "${ICON_CONFIG}"
COMMENT "Generating platform icon bundles"
VERBATIM
)
add_custom_target(icons DEPENDS "${ICON_ICNS}" "${ICON_ICO}")
else()
message(STATUS "iconsmaker not found — skipping icon generation")
endif()
Via Docker (no local install needed)
add_custom_command(
OUTPUT "${ICON_ICNS}" "${ICON_ICO}"
COMMAND docker run --rm
-v "${CMAKE_SOURCE_DIR}:/workspace"
iconsmaker:latest
--config icons/icons.toml
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
DEPENDS "${ICON_SVG}" "${ICON_CONFIG}"
COMMENT "Generating platform icon bundles via Docker"
VERBATIM
)
add_custom_target(icons DEPENDS "${ICON_ICNS}" "${ICON_ICO}")
Then in your app bundle target:
add_dependencies(MyApp icons)
Makefile
ICONSMAKER ?=
: :
:
Adding iconsmaker to a new project
Follow these steps for each new application:
1 — Prepare artwork
- Design your icon in a vector editor (Figma, Affinity Designer, Inkscape, Sketch).
- Canvas size: 1024 × 1024 px square.
- Export as SVG with text converted to outlines (no font dependencies).
- Do not add rounded corners, drop shadows, or gloss — the tool handles these.
- Save as
icons/master.svgin your project.
2 — Create icons/icons.toml
Start from the template in the icons.toml reference section above.
At minimum, fill in:
[]
= "com.yourname.YourApp" # unique reverse-DNS ID
= "Your App"
= "One-line description"
= "yourapp"
[]
= "icons/master.svg"
3 — Run and inspect
Open dist/macos/YourApp.icns in Preview (macOS) and dist/linux/hicolor/256x256/apps/ in
your file manager to visually check the output.
4 — Tune effects
If the depth bevel is too strong or too subtle, adjust in icons.toml:
[]
= 0.35 # reduce for subtle, increase for dramatic
= 0.12
Re-run to see the change immediately.
5 — Validate Linux metadata
Fix any validation errors before shipping.
6 — Wire into your build system
See Build system integration above. Add dist/ to your project's .gitignore.
7 — Per-packaging-format setup
Enable packaging formats in icons.toml as needed and follow the platform's
own guide for referencing the generated assets:
| Format | Generated assets location | Reference |
|---|---|---|
| Snap | dist/snap/snap/gui/ |
Copy to your snap source tree |
| Flatpak | dist/flatpak/app/share/ |
Copy under your Flatpak module prefix |
| AppImage | dist/appimage/YourApp.AppDir/ |
Merge into your AppDir before appimagetool |
.deb |
dist/linux/hicolor/ + .desktop |
List in debian/<pkg>.install |
SVG design reference
Colour palette guidance
| Element | Use |
|---|---|
| Background fill | Avoid pure black (#000) — use near-black like #1a1a1a for depth |
| Primary colour | Should read clearly at 16 × 16 px — test at small sizes |
| High-contrast content | Avoid very similar colours next to each other; they merge at small sizes |
Testing at small sizes
The most common mistake in icon design is content that looks fine at 512 px but is unreadable at 16 px. Check your 16 × 16 and 22 × 22 PNG outputs. Simplify the SVG or increase contrast if small sizes look muddy.
resvg filter support
The following SVG filter primitives are supported:
feBlend, feColorMatrix, feComposite, feFlood, feGaussianBlur,
feImage, feMerge, feOffset, feSpecularLighting, feTurbulence (basic).
Not supported: feConvolveMatrix, feDiffuseLighting (partial), feMorphology,
feDisplacementMap. Unsupported primitives are silently ignored.
Further reading
- Linux Application Icon Asset Guide —
freedesktop hicolor layout, per-desktop styling (GNOME/KDE/Xfce/…), and the
Snap / Flatpak / AppImage /
.debicon requirements.
Bundled assets
iconsmaker ships as a single self-contained binary with no external asset
files. The macOS squircle mask is generated analytically at runtime from the
[effects] squircle_power value — there is no bundled shape SVG to install or
reference.
A sample source icon is included at icons/master.svg so you can try a build
immediately after cloning:
# assets appear under dist/
License
iconsmaker is free software licensed under the GNU General Public License
v3.0 or later (GPL-3.0-or-later).
Acknowledgments
Claude (Anthropic) was used extensively in the design and implementation of this package — architecture, the Rust code, the packaging/installer pipeline, and this documentation.