30-second start
Pick one. Run it. You're done. The recommended path is first.
Runtime: Node ≥ 20.11 (24 recommended). macOS, Linux, Windows (WSL2 for --fix native deps).
🔵 AI assistant · recommended
Click an install button above. Then paste one of these into chat:
• Make a transparent logo for Forge, a dev-tools brand. Flat vector, warm orange.
• Make a favicon for my app, dark-mode aware.
• Fan this master.png out to iOS + Android + PWA.
• Ingest this screenshot as a mark, vectorize, export everything.
Works in Cursor, Claude Code, VS Code, Windsurf, Codex, Gemini CLI. Zero terminal typing.
🟢 Zero key, zero install
One curl, one npx. Offline fan-out to every platform.
curl -o logo.png \
"https://image.pollinations.ai/prompt/\
minimal+flat+vector+logo\
?model=flux&width=1024&nologo=true"
npx prompt-to-asset export logo.png \
--platforms ios,android,pwa,favicon
Outputs: iOS AppIconSet, Android adaptive, PWA, favicon bundle, visionOS scaffold.
🟣 CLI · free API keys
Best CLI experience: free tokens first, paid keys optional.
npm i -g prompt-to-asset
p2a doctor # check env
p2a doctor --fix # auto-install deps
p2a pick # interactive
Start with Cloudflare Workers AI, NVIDIA NIM, HF Inference, Stable Horde, and free trials. Paid providers remain optional fallbacks.
Free paths at a glance
You don't need a paid API key. Ranked best-first:
Details + quotas: Free paths beyond Pollinations. Run p2a doctor or ask your assistant for asset_doctor() to see what's live right now.
[!TIP] Stuck? Click Install in Cursor or Install in VS Code above, restart the editor, and say: "make a favicon for my app, dark-mode aware."
Highlights
- Free CLI-first generation —
p2a doctor,p2a pick, and the MCP tools rank free API routes before paid models, so developers can generate inside the CLI without enabling billing. - Three execution modes —
inline_svg(host LLM authors SVG),external_prompt_only(paste into any web UI),api(server calls a free or paid provider). Pick what fits. All three can finish on $0. - 60+ models, free-first routing — Cloudflare Workers AI, NVIDIA NIM, HF, Horde, Pollinations, free trials, plus optional paid OpenAI / Ideogram / Recraft / BFL / Gemini. Each rule cites a research source.
- Refuses to do the wrong thing — the
Nevercolumn. No wordmarks past 3 words through a diffusion sampler. No transparent PNG through Imagen. Nonegative_prompton Flux. - Offline platform fan-out — one 1024² master → iOS AppIconSet, Android adaptive + monochrome, PWA 192/512/512-maskable, favicon bundle, visionOS parallax, Flutter launcher. Zero network.
- Validates before shipping — tier-0 checks on every output: dims, alpha presence, checkerboard FFT, safe-zone bbox, ΔE2000 palette drift, WCAG contrast, OCR Levenshtein on wordmarks.
- Sprite sheets + 9-slice — pack PNG frames into TexturePacker-compatible atlases (Phaser, PixiJS, Godot, Unity); emit 9-slice numbers + CSS
border-image+ Android.9.png.
Table of contents
- 30-second start
- Usage — what to say to your assistant
- The three modes — inline_svg · external_prompt_only · api
- The router — which model for which job, and what never
- Free paths beyond Pollinations
- Install
- Models covered — 60+
- MCP tools — 25 tools
- CLI surface
- Brand bundle (
brand.json) - Platform support
- Architecture
- Comparison
- Security
- Research-backed decisions
- Development
- Community · License
Usage
You just talk to your assistant. Example from a new chat:
Make me a transparent logo for a developer-tools company called Forge. Flat vector, two-tone warm orange on neutral.
Behind the scenes:
asset_doctor()— check what modes and providers are live.asset_init_brand({ app_name: "Forge", palette: ["#EA580C", "#F5F5F4"] })if nobrand.jsonexists.asset_enhance_prompt({ brief })returns anAssetSpec: classification, rewritten prompt,modes_available[], optionalsvg_brief, optionalpaste_targets, and arouting_tracepointing at the research file that backed the decision (plusnever_models— why Imagen or DALL·E got rejected).- Assistant offers you
inline_svg/external_prompt_only/api. - If
inline_svg: it writes<svg>inline and callsasset_save_inline_svg→ writesmaster.svg,favicon.ico, apple-touch, AppIconSet, PWA bundle to disk. - If
external_prompt_only: assistant shows the refined prompt and the best paste target (free first). You generate, save, then say "ingest this file" →asset_ingest_external. - If
api: assistant calls the routed provider. Server mattes, vectorizes, exports, validates. - Follow-up: "also fan this out for iOS and Android" →
asset_export_bundlewith the saved master.
Zero CLI typing. The CLI is still first-class for CI, shell scripts, and non-MCP environments — both surfaces hit the same core.
Why this exists
Two facts shape everything here.
Producing production-grade software assets is a routing and post-processing problem, not a prompt-engineering problem.
Imagen 3/4 and Gemini Flash Image can't produce real RGBA PNGs — their VAE is RGB-only, so asking for a transparent background renders the grey-and-white checkerboard as pixels. SDXL can't spell past ~8 characters. Only Recraft emits native SVG. Flux errors on negative_prompt. None of that is visible in the model UI. All of it silently breaks one-shot "prompt → asset" tools.
You may not have an image-model API key. The plugin works anyway.
Every one of the three modes can finish on $0.
The three modes
flowchart LR
A["one-line brief"] --> B["asset_enhance_prompt"]
B --> C{"mode"}
C -->|inline_svg| D["Host LLM emits SVG inline<br/>→ asset_save_inline_svg"]
C -->|external_prompt_only| E["Paste into web UI<br/>→ asset_ingest_external"]
C -->|api| F["Server calls routed provider"]
D --> G["matte · vectorize · validate"]
E --> G
F --> G
G --> H["AssetBundle<br/>ios · android · pwa · favicon · visionos · flutter"]
The host LLM picks the mode, or you do. The server surfaces modes_available so the assistant offers them to you. Free paths first — always.
The router
Router decisions live in data/routing-table.json. Capability matrix in data/model-registry.json. Every rule cites its research source.
The Never column matters. It's why prompt-to-asset refuses to render wordmarks past 3 words in any diffusion sampler, and why asking for a transparent PNG never goes to Imagen.
Free paths beyond Pollinations
Verified 2026-04-26 against public Gemini API pricing:
- Imagen 4 image output is paid API. The pricing table lists Free Tier as "Not available" and prices Fast / Standard / Ultra at $0.02 / $0.04 / $0.06 per image.
- Nano Banana family is paid API.
gemini-3.1-flash-image-preview(Nano Banana 2),gemini-3-pro-image-preview(Nano Banana Pro), andgemini-2.5-flash-image(original Nano Banana) list image output only in the paid tier. Billing must be enabled on the GCP project to use these via API. - Free for text, multimodal understanding, and embeddings. The Gemini text-out models still have
Free of chargeinput + output on the free tier. - Free interactive image generation is also via the AI Studio web UI at aistudio.google.com. Community-observed limit 500–1,000 images/day, dynamic. Use
external_prompt_only+asset_ingest_externalif you want Nano Banana quality without billing. - Free image generation via the Gemini consumer app at gemini.google.com: Basic 20/day, AI Plus 50/day, AI Pro 100/day, Ultra 1,000/day.
- Paid API pricing (per image, standard): Nano Banana (
gemini-2.5-flash-image) $0.039; Nano Banana 2 Flash (gemini-3.1-flash-image-preview) $0.045/0.5K, $0.067/1K, $0.101/2K, $0.151/4K; Nano Banana Pro (gemini-3-pro-image-preview) $0.134/1K-2K, $0.24/4K (+ $0.0011 per input image); Imagen 4 Fast $0.02, Standard $0.04, Ultra $0.06. Batch API is 50% off.
Run
p2a doctor(or ask your assistant forasset_doctor()) to see what's live in your environment right now.
Install
Every command works via npx — no install required.
# Zero install
npx prompt-to-asset doctor # what's live in this shell right now
npx prompt-to-asset doctor --fix # auto-install native deps (brew / cargo / scoop; never sudo)
npx prompt-to-asset pick # interactive route picker
npx prompt-to-asset init --register # scaffold brand.json + register in .cursor / .vscode / .windsurf
# Or global for daily use
npm i -g prompt-to-asset
p2a doctor
# Or per-project for CI
npm i -D prompt-to-asset
Register with your AI assistant
Claude Code
claude mcp add prompt-to-asset -- p2a
Smithery (universal)
npx -y @smithery/cli install prompt-to-asset --client claude
Cursor · VS Code · Windsurf · Codex · Gemini CLI
Use the install buttons at the top of this README, or see docs/install.md for the exact stanza per IDE.
Claude Desktop
Download the .mcpb bundle → double-click → restart.
Once registered, your assistant has the full 24 asset_* tool surface.
Models covered
Paid direct APIs: gpt-image-1, gpt-image-1.5, dall-e-3 (deprecated 2026-05-12), imagen-3, imagen-4, gemini-3-flash-image (Nano Banana), gemini-3-pro-image, sd-1.5, sdxl, sd3-large, playground-v3, flux-schnell, flux-dev, flux-pro, flux-2, flux-kontext-pro, ideogram-3, ideogram-3-turbo, recraft-v3, leonardo-phoenix, leonardo-diffusion-xl, fal-flux-pro, fal-flux-2, fal-sdxl.
Free-tier / zero-key: pollinations-flux, pollinations-turbo, pollinations-kontext, pollinations-sd, horde-sdxl, horde-flux, hf-sdxl, hf-sd3, hf-flux-schnell, hf-flux-dev.
Paste-only surfaces: midjourney-v6, midjourney-v7, firefly-3, krea-image-1. Calling asset_generate_* with mode: "api" against a paste-only primary soft-falls-back to the first API-reachable model in the chain and surfaces a warning. If the whole chain is paste-only, you get an ExternalPromptPlan rather than an error.
Tools are annotated readOnlyHint / idempotentHint so Cursor auto-approves without prompting.
Used by the LLM over Bash when MCP isn't registered yet, and by CI. Every read-only command accepts --json.
p2a # default — MCP stdio server
p2a mcp # same, explicit
p2a export <master.png> # offline platform fan-out
p2a export <master.png> --json
p2a init # interactive brand.json + IDE registration hints
p2a init --register # + auto-write .cursor/mcp.json / .vscode/mcp.json / .windsurf/mcp.json
p2a pick # interactive model picker
p2a doctor # environment inventory
p2a doctor --json # structured output
p2a doctor --data # check data/model-registry.json ↔ data/routing-table.json consistency
p2a doctor --fix # auto-install missing native deps (brew / cargo / scoop; never sudo)
p2a models list # --free | --paid | --paste-only | --rgba | --svg
p2a models inspect <id> # full capability dump
p2a sprite-sheet <dir> # pack frames → PNG + atlas
p2a nine-slice <image> # 9-slice JSON + CSS + engine numbers + .9.png
p2a --help
{
"name": "Halcyon",
"palette": ["#2563eb", "#ffffff"],
"fonts": { "display": { "family": "Inter", "weights": [700, 800] } },
"style_refs": ["https://…/sample1.png", "./refs/style2.png"],
"do_not": ["drop shadows", "heavy gradients"],
"lora": "halcyon-flux-v2",
"sref_code": "--sref 1234567890",
"style_id": "rc_halcyon_01"
}
p2a init writes this for you, detecting the framework and suggesting an assets directory. Once present, every generator reads from it automatically.
brief (text)
↓ asset_capabilities → modes available + free/paid/paste-only bucketing
↓ asset_enhance_prompt → AssetSpec {
↓ routing_trace: { rule_id, reason, research_sources, never_models, fallback_chain },
↓ modes_available,
↓ svg_brief?, (inline_svg)
↓ paste_targets?, (external_prompt_only)
↓ rewritten_prompt, …
↓ }
↓
├─ mode: inline_svg → host LLM emits <svg>; asset_save_inline_svg writes bundle
├─ mode: external_prompt_only → user pastes into web UI; asset_ingest_external runs matte → vectorize → validate
└─ mode: api → provider(model, prompt, params) → matte → vectorize → upscale → export → validate
Content-addressed storage: assets/<hash[0:2]>/<hash>/<variant>.<ext>. The MCP server is synchronous and stateless. prompt_hash and params_hash in every AssetBundle are designed to drop straight into a BullMQ / SQS / Cloudflare Queues jobId for a hosted pipeline. Reference design: docs/research/18-asset-pipeline-tools/18e-production-pipeline-architecture.md.
Design thesis
You own the API keys. The LLM owns everything else.
The only thing that happens in a terminal is installing the package and putting keys in .env. Secrets shouldn't pass through chat. Every other verb — doctor checks, model inspection, platform fan-out, brand scaffolding, sprite sheets, 9-slice configs — is an MCP tool the assistant calls when you ask in natural language.
Comparison
Security
This tool handles API keys for up to 15 providers. Non-negotiables:
- Keys live in env vars only. Never written to disk, never logged, never echoed in MCP responses. Provider error bodies go through
redact()(packages/mcp-server/src/security/redact.ts) before reaching the host LLM. - Path access is allow-listed.
image_path/output_dir/existing_mark_svgresolve through symlinks and reject anything escaping project cwd + configured output dir + cache dir + OS tempdir. Widen withP2A_ALLOWED_PATHS=/path1:/path2. - SVG is XSS-sanitized before any write.
<script>,<foreignObject>,on*=handlers,javascript:URIs, external<image href>/<use href>, CSS@importover the network — all rejected. The check runs unconditionally; SVGO is not required. - Cost guardrail. Set
P2A_MAX_SPEND_USD_PER_RUN=5.00to cap any single tool call. Pre-flight estimate refuses to call if over. Free-tier routes are always $0. - Data integrity at boot.
assertDataIntegrityAtBoot()runs on start. If a routing rule points at a model id not in the registry, the server refuses to boot with a clear error. Check in CI withp2a doctor --data. - No telemetry. No remote calls unless the routed provider explicitly requires one.
Full policy: SECURITY.md.
Research-backed decisions
Every routing rule, dialect switch, safe-zone size, and text ceiling that's implemented is backed by a file under docs/research/. asset_enhance_prompt returns a routing_trace.research_sources array on every call. The angle → code pointer map, plus an honest ledger of what's wired and what's deferred, lives in docs/RESEARCH_MAP.md.
Development
git clone https://github.com/MohamedAbdallah-14/prompt-to-asset.git
cd prompt-to-asset
npm install
npm run build
npm run typecheck
npm run lint
npm test # vitest watch
npm run test:run # vitest run (CI)
npm run smoke # list tools via MCP stdio + correctness assertions
npm run sync # regenerate IDE mirrors from SSOTs
npm run verify # byte-verify mirrors match SSOTs
SSOTs live in skills/*/SKILL.md, rules/*.md, .claude-plugin/, and data/*.json. Don't edit .cursor/, .claude/, .windsurf/ directly — they're regenerated by scripts/sync-mirrors.sh and CI byte-verifies them.
- Contribution flow: CONTRIBUTING.md
- User on-ramp: GETTING_STARTED.md
- Common snags: TROUBLESHOOTING.md
- Release notes: CHANGELOG.md
Community
- Issues + feature requests: GitHub Issues
- Security disclosures: SECURITY.md
- Code of Conduct: CODE_OF_CONDUCT.md
- Star history:
If this repo saved you from hand-crafting another AppIconSet, a star helps it reach other developers fighting the same fight.
Read more
The thinking behind the design, in long-form:
- Why I stopped picking image models and built a router instead — the case for routing across 30+ image models.
- MCP server architecture: what's inside prompt-to-asset — architecture deep-dive.
Cross-posted on Medium and dev.to.
License
MIT © prompt-to-asset contributors.