Compile one design into launch-ready icon assets and project wiring.
Xcode Asset Catalog · app icons · extension manifests · package icons · PWA icons. One compiler.
English | 한국어
Part of Starter Series — reusable launch tooling, not just clone-templates.
icon-makeris the identity asset companion toshotkit: make the icon set first, then capture/store/social assets from the built product.
- Pre-release — the package is implemented, packable, and available as a
public source repo, but
iconkithas not been published to npm yet. The commands below distinguish local development from post-npm release install paths. - Currently implemented — a provider-neutral delivery icon compiler with a
structured design-intent/source workflow, target constraints, bounded local
brand-evidence discovery, separate direction and artwork approval gates,
direct SVG/PNG handoff, Xcode-ready Apple AppIcon catalogs, and outputs for
apple,browser-extension,expo,electron,vscode,pwa,mcp-connector, andgeneric;.ico/.icnscontainers; preview contact sheets; target autodetection; JSON output; and optional manifest/package patching. - Design intent — one config, many platform outputs. Icon decisions are project intent, so the source of truth lives in
icon-maker.config.jsor the data-onlyicon-maker.config.json; platform file names and manifest wiring are mechanical. - Non-goals — the offline CLI does not own AI logo generation, brand strategy, or illustration. An agent may call an available image-generation provider upstream, but only an approved project-local SVG/PNG crosses into the compiler.
- Redacted — none. The package does not use network calls, credentials, or third-party image services.
npm install
node bin/icon-maker.js --brief --target apple,browser-extension,pwa
node bin/icon-maker.js --placeholder --target auto --dry-run --json
node bin/icon-maker.js --placeholder --target generic --out-dir .tmp-icon-preview --preview --json
rm -rf .tmp-icon-previewThe brief command reports target constraints and existing local brand evidence without writing files. It does not authorize image generation until direction and approval are explicit. The other commands opt into temporary placeholder artwork to test target detection, preview rendering, and the JSON contract.
Install in a consuming repo:
npm i -D iconkitZero-install:
npx iconkit --source ./brand/icon.png --target auto --jsonClaude Code plugin path after the public plugin entry exists:
/plugin marketplace add starter-series/create-starter
/plugin install icon-maker@starter-series
Start with a machine-readable source request:
node bin/icon-maker.js --brief --target apple,browser-extension,pwa --json--brief first resolves technical constraints for the selected targets and
performs a bounded local scan for existing brand assets, guidance documents,
and palette evidence. Discovered evidence must be reviewed; it is not approved
brand intent. If an approved source is already configured in mark.source, the
workflow returns ready-to-compile and skips image generation.
--brief --json returns schemaVersion: 2. Its requestType maps the workflow
to direction-discovery (needs-direction), direction-review
(needs-direction-approval), image-generation
(ready-for-image-generation), or compile (ready-to-compile).
For source acquisition, follow the returned workflow exactly:
needs-directionmeans concept or mood is missing andimageGenerationAllowedisfalse. Never pass this prompt to an image model. If the user is unsure, present exactly three text-only hypotheses, each with a name, what it expresses, visual metaphor, mood, and tradeoff, then wait. Product context and user-confirmed brand evidence ground their meaning; technical constraints only determine whether a direction can ship.needs-direction-approvalmeans concept and mood are complete but not approved. Present the direction and wait for explicit approval or revision.- Rerun with the selected hypothesis fields and
--approve-direction, or store the same complete direction withdesign.approved: truein config. Onlyready-for-image-generationwithnextAction: "generate-image"andimageGenerationAllowed: trueexposes a non-nullimagePrompt; pass only that field to an image model.
Round-trip a selected hypothesis without summarizing or dropping fields:
name becomes --direction-name, metaphor becomes --visual-metaphor, and
the remaining fields use --concept, --expresses, --mood, and --tradeoff,
plus optional --palette and --avoid. Partial input is preserved in the
returned direction; carry the full result forward on the next run or persist
it in config. Omit --approve-direction for the direction-review round trip;
after explicit approval, rerun the same full payload with the flag. The command
below is that approved rerun.
node bin/icon-maker.js --brief \
--target apple,browser-extension,pwa \
--direction-name "Focused signal" \
--concept "clarity emerging from noisy inputs" \
--expresses "calm confidence" \
--visual-metaphor "one bright signal aligned through a field" \
--mood "precise,quiet" \
--tradeoff "abstract rather than literal" \
--palette "#0f172a,#14b8a6" \
--avoid "letters,platform logos" \
--approve-direction --jsonThe CLI remains offline and never calls a model. The agent shows the generated candidate and waits for separate artwork approval. Only after that approval may the provider output be placed inside the project and compiled with a preview:
node bin/icon-maker.js --source ./brand/icon.png \
--target apple,browser-extension,pwa \
--preview --jsonInspect icon-preview.html, then explicitly wire manifests/packages:
node bin/icon-maker.js --source ./brand/icon.png \
--target apple,browser-extension,pwa \
--patch --jsonAfter npm publication, replace node bin/icon-maker.js with npx iconkit.
--source is resolved relative to the target project and must stay inside it.
A square PNG of at least 1024 x 1024 is preferred for image-generated artwork;
native vector SVG is also accepted. Smaller or non-square PNG input produces
structured warnings. --out-dir is also resolved inside the target project;
output may not be redirected outside that boundary.
Compilation without an approved source is an error. --placeholder is the
explicit escape hatch for deterministic temporary artwork and emits a warning.
Expo needs a separate transparent adaptive foreground when the default source has an opaque background:
node bin/icon-maker.js --source ./brand/icon.png \
--adaptive-source ./brand/icon-adaptive.png \
--target expo --preview --jsonCreate a config:
node bin/icon-maker.js --initGenerate icons:
node bin/icon-maker.js --source ./brand/icon.png --target auto --preview
node bin/icon-maker.js --source ./brand/icon.png --target browser-extension --patch
node bin/icon-maker.js --source ./brand/icon.png --adaptive-source ./brand/icon-adaptive.png --target expo --json
node bin/icon-maker.js ../my-app --source ./brand/icon.png --target pwa --out-dir out --json
node bin/icon-maker.js --placeholder --target generic --dry-run --json--json prints one machine-readable object to stdout. If an explicit or
trusted local .js config writes to stdout while loading, icon-maker routes
that config noise to stderr so stdout remains parseable:
{
"ok": true,
"sourceMode": "source",
"targets": ["browser-extension"],
"produced": [
{ "target": "browser-extension", "path": "/abs/app/assets/icons/icon128.png", "format": "png", "size": 128 }
],
"patches": []
}icon-maker.config.js:
module.exports = {
project: {
name: 'My App',
slug: 'my-app',
description: 'What the product does and for whom',
},
placeholder: false,
// Used by --brief when an approved source is not already present:
// design: {
// name: 'Focused signal',
// concept: 'clarity emerging from noisy inputs',
// expresses: 'calm confidence',
// metaphor: 'one bright signal aligned through a field',
// mood: ['precise', 'quiet'],
// tradeoff: 'abstract rather than literal',
// palette: ['#0f172a', '#14b8a6'],
// avoid: ['letters', 'platform logos'],
// approved: false,
// },
mark: {
source: {
default: './brand/icon.png',
adaptiveForeground: './brand/icon-adaptive.png',
},
// Used to flatten transparent artwork for Apple delivery:
background: '#111827',
},
// Required only when Xcode routing is ambiguous or a new set is desired:
// apple: {
// assetCatalog: './MyApp/Assets.xcassets',
// appIconSet: 'AppIcon',
// },
targets: ['auto'],
};For starter-only temporary artwork, opt in explicitly with
placeholder: true and configure mark.glyph, shape, and colors. Placeholder
mode is never selected merely because mark.source is absent.
A config direction authorizes image-generation handoff only when concept and
at least one mood are present and design.approved is true. Keep approval
false until the user accepts that direction. The other hypothesis fields are
preserved under design.name, expresses, metaphor, tradeoff, palette,
and avoid. A configured approved source takes precedence and skips image
generation.
For untrusted target checkouts, prefer icon-maker.config.json. Auto-discovery
loads the JSON form first and refuses to auto-execute a target repo's
icon-maker.config.js unless the path is passed explicitly with --config.
| Target | Outputs |
|---|---|
apple |
detected Xcode App Icon set: RGB iOS 1024 source, complete macOS size matrix, Contents.json |
browser-extension |
assets/icons/icon16.png, icon32.png, icon48.png, icon128.png, icon.svg |
expo |
assets/icon.png, transparent-foreground assets/adaptive-icon.png, assets/icon.svg |
electron |
assets/icon.png, assets/icon.ico, assets/icon.icns, assets/icon.svg |
vscode |
assets/icon.png (256), assets/icon.svg |
pwa |
public/icon-192.png, public/icon-512.png, public/favicon.ico, public/favicon.svg |
mcp-connector |
assets/icon.png (1024), assets/icon-512.png, assets/icon.svg |
generic |
assets/icon.png, assets/icon.svg |
For a one-off vanilla-chat handoff, use --source. When the design path should
remain project intent, point mark.source at it:
module.exports = {
mark: {
source: {
default: './brand/icon.svg',
adaptiveForeground: './brand/icon-adaptive.svg',
},
},
targets: ['expo', 'pwa'],
};SVG outputs preserve an SVG source. A PNG source is embedded in generated SVG
wrappers. PNG/ICO/ICNS and Apple outputs are rasterized through
@resvg/resvg-js into square canvases using contain scaling. Keep the source
inside the target directory. Keep SVG input self-contained: use inline
fills/strokes and avoid remote fonts or external images for portable output.
An exact Markdown-fenced SVG code block is unwrapped automatically. Prose
around the fence is rejected. A source path may not collide with any generated
or preview output path, and output paths or symlinks may not escape the target
directory. When selected targets need different files at the same path, use
--out-dir to isolate them.
Security: the SVG output (e.g.
favicon.svg) preservesmark.sourceafter optional exact Markdown-fence removal; icon-maker does not sanitize it. An SVG can carry<script>or event-handler attributes that execute when the file is opened or served directly in a browser. Only pointmark.sourceat SVGs you author or trust; never feed it an untrusted third-party SVG whose output you then serve.
The apple target emits one App Icon set that Xcode can compile for iOS and
macOS. It reads ASSETCATALOG_COMPILER_APPICON_NAME from project.pbxproj when
that value is unambiguous. Preview-only catalogs are ignored. With exactly one
production asset catalog, icon-maker writes into it; with none, it creates
Assets.xcassets and warns that the catalog may need to be added to Xcode. With
multiple catalogs or App Icon names, it stops instead of guessing:
module.exports = {
apple: {
assetCatalog: './MyApp/Assets.xcassets',
appIconSet: 'AppIcon',
},
targets: ['apple'],
};An explicitly configured catalog must already exist. Existing App Icon sets
that reference files not owned by icon-maker are never overwritten; choose a
new apple.appIconSet instead. Empty Xcode appearance slots and set metadata
are preserved. Imported Apple artwork is flattened onto mark.background, and
Apple PNGs are encoded as RGB without an alpha channel. The current target uses
the broadly compatible Asset Catalog path; layered Icon Composer authoring
remains an upstream design step.
--preview writes icon-preview.html, a local contact sheet for checking tiny
sizes, transparent backgrounds, and platform containers:
node bin/icon-maker.js --source ./brand/icon.png --target auto --preview--patch updates known fields when the matching manifest exists:
manifest.jsonextensionicons- Expo
app.jsonexpo.iconand Android adaptive foreground - Electron / VS Code
package.jsonicon public/manifest.jsonPWAicons
When --patch is requested and a matching manifest is absent, the JSON result
contains a patch-target-missing warning. Generate and review first; patch in a
second command when the assets are accepted.
- Current source checkout:
node /path/to/icon-maker/bin/icon-maker.js <path> --source ./brand/icon.png --target auto --json - Upstream source request:
node /path/to/icon-maker/bin/icon-maker.js <path> --brief --target apple,pwa --json - Published CLI after npm release:
npx iconkit <path> --source ./brand/icon.png --target auto --json - Skill:
skills/create-icons/SKILL.md - Source plugin metadata:
.claude-plugin/plugin.json
There is no MCP server in v1. The reliable surface is an offline CLI with a JSON contract plus a skill that collects and approves direction, presents one generated candidate for artwork approval, and only then invokes the compiler.
npm install
npm run lint
npm test
npm run pack:install-smoke
npm run xcode:smoke # macOS/Xcode only