Favicon Creator
Generate a complete, cross-device favicon set and wire it into the project's layout so it shows up correctly in every browser, tab, home screen, and pinned shortcut.
The favicon is always rendered as a square with tight rounded corners, with the chosen icon centered inside on a solid background color.
Prerequisites
Requires rsvg-convert and ImageMagick's magick on the system. If either is missing, stop and ask the user to install them (brew install librsvg imagemagick). Do not attempt a workaround.
Step 1 — Gather inputs from the user
Ask each question in order. Wait for an answer before moving on. Do not assume defaults beyond what is specified.
1.1 Icon source
Ask: "What icon do you want to use? You can:
- Name a Lucide icon (e.g.
rocket,sparkles,book-open) — this is the default - Name an icon from a different icon library (and which library)
- Point me to an existing
.svgfile in the repo - Describe the icon you want and I'll generate the SVG"
Resolve the answer:
- Default — Lucide icon by name. If the user names an icon without naming a library, treat it as a Lucide icon. Fetch the exact SVG from lucide.dev for that icon and use it as the source. Lucide icons use
stroke="currentColor"andfill="none". Always setstroke-width="1.5"on the root<svg>element (override whatever value Lucide ships with). Do not redraw, simplify, or recreate the paths — use the exact paths from Lucide. - Other icon library. If the user names a different library (e.g. Heroicons, Phosphor, Tabler, Material Symbols), fetch the exact SVG from that library's official source.
- Existing SVG path. Read the file and confirm the
viewBox/ intrinsic size. If there is noviewBox, derive one fromwidth/height. - Described icon. Generate a minimal SVG matching the description. Keep it geometric and legible at 16×16.
1.2 Background color
Ask: "What background color should the favicon square use? (hex, e.g. #FCF8F2)"
This fills the rounded square and also becomes the page theme-color meta tag value.
1.3 Icon color
Ask: "What color should the icon itself be? (hex, e.g. #22D3EE)"
For Lucide / stroke-based icons, this becomes the stroke color. For filled icons, this becomes the fill color.
Confirm both colors back to the user before generating.
Step 2 — Locate the layout file
Find where favicon <link> tags should live. First, read CLAUDE.md and/or AGENTS.md if they exist — they may declare a convention for where head/meta tags go.
If no convention is declared, check in this order:
- Next.js (app router):
app/layout.tsx/app/layout.jsx— favicons are typically handled via file conventions (app/icon.*,app/apple-icon.*) and/or ametadataexport - Next.js (pages router):
pages/_document.tsx/pages/_app.tsx - Rails:
app/views/layouts/application.html.erb(or.haml,.slim) - Vite/React (Inertia, SPA):
index.htmlorapp/views/layouts/application.html.erb - SvelteKit:
src/app.html - Astro:
src/layouts/*.astroor individual page layouts - Plain HTML:
index.html
If you can't find the layout, grep for rel="icon" or apple-touch-icon across the repo. If still ambiguous, ask the user.
Step 3 — Determine the public asset directory
Always look for a public/ folder first. Most modern frameworks use it, and the four canonical files (favicon.ico, icon.png, icon.svg, apple-touch-icon.png) must always land there if it exists.
If the project also has another conventional asset location (e.g. Next.js app router's app/ directory for file-convention icons), write there in addition — but public/ is always required.
If neither exists, ask the user where assets should go, then ensure a public/ equivalent.
Step 4 — Generate the SVG for browser tabs (rounded square with centered icon)
Write public/icon.svg as a square with tight rounded corners, the background color filling the square, and the source icon centered inside. After writing it, also copy the same file to public/favicon.svg (some browsers and link-preview crawlers look for favicon.svg at the site root by name).
Canvas: 80 × 80. Corner radius: 16 (tight rounded corners — 20% of the canvas).
The inner icon should occupy ~60% of the canvas (safe zone for iOS rounded corner masking). Round offsets to whole pixels.
Stroke-based icon (Lucide, etc.) — keep fill="none" and apply the icon color via stroke. Always use stroke-width="1.5" for Lucide:
<svg width="80" height="80" viewBox="0 0 80 80" xmlns="http://www.w3.org/2000/svg">
<rect width="80" height="80" rx="16" fill="#FCF8F2"/>
<g transform="translate(Xoff Yoff) scale(N)" stroke="#22D3EE" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" fill="none">
<!-- exact Lucide paths here, fill/stroke attributes stripped from individual paths -->
</g>
</svg>
Filled icon — apply the icon color via fill:
<svg width="80" height="80" viewBox="0 0 80 80" xmlns="http://www.w3.org/2000/svg">
<rect width="80" height="80" rx="16" fill="#FCF8F2"/>
<g transform="translate(Xoff Yoff) scale(N)" fill="#22D3EE">
<!-- source paths, individual fill attributes removed -->
</g>
</svg>
Centering math — if the source viewBox is W × H, target inner size T = 48 (60% of 80):
N = T / max(W, H)Xoff = (80 - W * N) / 2Yoff = (80 - H * N) / 2
Step 5 — Generate the raster source SVG
Write a second, scaled-up SVG to /tmp/favicon-source.svg — same composition, but at 512 × 512 with corner radius 102 (~20% of 512). This is the source for all PNGs and the ICO.
<svg width="512" height="512" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg">
<rect width="512" height="512" rx="102" fill="#FCF8F2"/>
<g transform="translate(Xoff Yoff) scale(N)" stroke="#22D3EE" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" fill="none">
<!-- source paths -->
</g>
</svg>
For Lucide, multiply stroke-width by N if needed so it renders proportionally at large sizes, OR keep stroke-width="1.5" outside the transform and apply vector-effect="non-scaling-stroke" on the paths. Simpler: keep the icon's stroke crisp by scaling its stroke-width with N (e.g. stroke-width="${1.5 * N}").
Inner-icon target: T = 308 (~60% of 512). Same offset math as Step 4.
Step 6 — Rasterize all sizes
Run from the project root, with $PUBLIC set to the public directory (usually public):
rsvg-convert -w 512 -h 512 /tmp/favicon-source.svg -o $PUBLIC/icon.png
rsvg-convert -w 192 -h 192 /tmp/favicon-source.svg -o $PUBLIC/icon-192.png
rsvg-convert -w 180 -h 180 /tmp/favicon-source.svg -o $PUBLIC/apple-touch-icon.png
rsvg-convert -w 48 -h 48 /tmp/favicon-source.svg -o /tmp/fav-48.png
rsvg-convert -w 32 -h 32 /tmp/favicon-source.svg -o /tmp/fav-32.png
rsvg-convert -w 16 -h 16 /tmp/favicon-source.svg -o /tmp/fav-16.png
magick /tmp/fav-16.png /tmp/fav-32.png /tmp/fav-48.png $PUBLIC/favicon.ico
This produces, in public/:
favicon.ico— multi-resolution 16/32/48 for Windows/legacyicon.svgandfavicon.svg— the rounded square mark for modern browser tabsicon.png— 512×512 PNGicon-192.png— 192×192 PNG for Androidapple-touch-icon.png— 180×180 PNG for iOS home screen
Step 7 — Wire up the meta tags
Edit the layout file. Inside <head>, ensure these tags exist (add or replace — do not duplicate):
<meta name="theme-color" content="#FCF8F2">
<link rel="icon" href="/favicon.ico" sizes="32x32">
<link rel="icon" href="/icon.svg" type="image/svg+xml">
<link rel="icon" href="/icon-192.png" type="image/png" sizes="192x192">
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
Notes:
theme-coloruses the background color from Step 1.2.favicon.icogetssizes="32x32"(notany) so modern browsers prefer the SVG.- If the project already has a
<meta name="theme-color">or any<link rel="icon">/apple-touch-icon, replace them — don't stack duplicates. - Next.js app router: prefer the file convention. Drop the generated files at
app/icon.svg,app/icon.png,app/apple-icon.png,app/favicon.ico(rename accordingly) and let Next emit the tags. Still write the same four files topublic/as well. Only hand-write<link>tags if the project already does.
Step 8 — Report what changed
Summarize for the user:
- The icon source used (Lucide name, library, file path, or description)
- The background and icon colors
- Which files were written
- Which head tags were added or replaced
- A reminder to hard-refresh the browser (or close and reopen the tab) to bust the favicon cache
Rules
- Do not leave behind a half-generated set. If any step fails, stop and report.
- Do not add a
manifest.jsonunless the project already has one. - Do not commit the changes. This skill only generates assets and edits the layout.
- Do not use emojis in file contents.
- Keep the generated SVGs minimal — no decorative comments, no unused attributes.
- Always preserve the exact Lucide path data when a Lucide icon is requested. Only the stroke width and color may change.