From svg-icon-gen
Generate, edit, animate, and optimize custom SVG icons from scratch. Use this skill whenever the user asks to create icons, needs SVG icons for a UI, mentions "icon", "SVG", "add an icon", "make me an icon", wants to convert a logo/image to SVG, or is building any frontend where icons would improve the experience — even if they don't explicitly ask for icons. Also triggers when editing existing SVG icons (changing style, weight, converting outline to filled), animating icons, or optimizing SVG paths. Covers all icon styles (outline, filled, duotone), React components, inline SVG, accessibility, dark mode, icon sets, and UI style matching.
How this skill is triggered — by the user, by Claude, or both
Slash command
/svg-icon-gen:svg-icon-genThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Generate, edit, convert, animate, and optimize production-quality SVG icons from scratch. Icons are built from learned geometric patterns — not copied from any library.
Generate, edit, convert, animate, and optimize production-quality SVG icons from scratch. Icons are built from learned geometric patterns — not copied from any library.
Before writing any icon, read references/icon-patterns.md to learn the construction patterns. That file is the foundation — it teaches how icons are geometrically built so you can create ANY icon from scratch.
Every icon request falls into one of these scenarios. Identify which one before doing anything:
The user describes what they want in words. Proceed to Phase 2.
The user uploads an image (logo, boceto, screenshot). This requires PRECISION — logos are brand assets where fidelity matters more than simplification. Follow these steps strictly:
Step 1 — Describe before you trace: Before writing ANY SVG code, describe in text EXACTLY what you see. Be specific:
CRITICAL — Do NOT assume shapes based on what you think the letter/icon "should" look like. Describe ONLY what you actually see in the image. Common mistakes:
How to verify your description: After describing, ask yourself: "If someone who has never seen this image read my description, could they draw it accurately?" If not, add more detail about the specific parts that are unusual or could be misinterpreted.
Example: "I see two thick diagonal strokes forming an inverted V (like a letter A without the crossbar). At the top, the strokes overlap and cross each other — they do NOT taper to a sharp point; instead each stroke maintains its full width through the crossing zone, and the right stroke passes in front. Each stroke is ~3-4 units wide throughout its length. The bottom ends are rounded like capsules (semicircular). The left stroke has a lighter blue gradient, the right stroke is darker blue."
Step 2 — Map to a coordinate grid: Choose an appropriate viewBox (24x24 for icons, larger for detailed logos) and map key points:
Step 3 — Construct path by path: Build each shape individually. For each path:
L for straight edges, A for rounded caps, C for organic curvesZA radius radius 0 0 1 x y to create semicircular capsStep 4 — Preserve colors and gradients:
For logos, NEVER use currentColor. Instead:
<linearGradient> or <radialGradient> in <defs><path> elements with their own fillsStep 5 — Mental comparison before delivering: Before showing the result, mentally compare point by point:
If something doesn't match, fix it BEFORE showing to the user. Then ask: "Does this capture your logo accurately? Want me to adjust proportions, colors, or any details?"
The user has an SVG and wants changes. See Editing Existing SVGs.
The user needs multiple icons. See Icon Sets & Consistency.
You notice a UI the user is building could benefit from icons (buttons without icons, empty nav items, plain text links that could use visual anchors). Suggest it:
Do NOT generate an icon until you know these three things:
Ask or infer: how does the user want the icon delivered?
<svg><path d="..."/></svg> — for HTML, direct embeddingconst Icon = ({ size, color, className }) => (...) — for JSX projectsAdaptive rule: If the user's code is visible in the conversation and uses JSX → deliver React. If it's HTML → deliver inline SVG. If unclear → ask. If the user has expressed a preference before (like <svg><path/></svg>), remember and use that.
Investigate before generating. Follow this decision tree:
If the user's UI code is visible → analyze it directly:
border-radius values → sharp (geometric icons) vs rounded (friendly icons)If no UI code is visible → ask with clear options:
If the user doesn't know → help them discover it:
| Style | Best for | Look |
|---|---|---|
| Outline | Nav bars, toolbars, settings, minimal UIs | Stroke-based, no fill, clean |
| Filled | Active states, CTAs, mobile tap targets, emphasis | Solid shapes, high contrast |
| Duotone | Dashboards, feature sections, marketing, empty states | Two-tone depth, visual hierarchy |
If not specified → recommend based on UI context. Common pattern: outline for inactive states + filled for active.
If the project seems to have or could have a dark theme, ask:
currentColor, or create specific variants if needed."If the user says yes → ensure icons use currentColor so they inherit the text color of whatever theme is active. For duotone icons, ensure the opacity layer has enough contrast on both light and dark backgrounds.
If the user doesn't know or doesn't care → default to currentColor (works for both).
Read references/icon-patterns.md before generating. Then apply these rules:
ViewBox & Sizing:
viewBox="0 0 {size} {size}", never hardcode width/height in the SVGPath Construction:
Pixel Hinting: At small sizes (16px), strokes that land between pixels look blurry. Rules:
Outline (inline SVG):
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path d="..."/>
</svg>
Filled (inline SVG):
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
<path d="..." fill-rule="evenodd" clip-rule="evenodd"/>
</svg>
Duotone (inline SVG):
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true">
<path d="..." fill="currentColor" opacity="0.2"/>
<path d="..." fill="currentColor"/>
</svg>
React Component:
const IconName = ({ size = 24, color = "currentColor", className = "", ...props }) => (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width={size}
height={size}
fill="none"
stroke={color}
strokeWidth={2}
strokeLinecap="round"
strokeLinejoin="round"
className={className}
aria-hidden="true"
{...props}
>
<path d="..." />
</svg>
);
export default IconName;
Adjust fill/stroke attributes per style. Always spread ...props. Always provide defaults.
Use gradients for logos, brand icons, and any conversion where the original has color transitions. NEVER default to currentColor for logos.
Linear Gradient template:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true">
<defs>
<linearGradient id="grad-1" x1="0" y1="0" x2="1" y2="1">
<stop offset="0%" stop-color="#LIGHTER_COLOR"/>
<stop offset="100%" stop-color="#DARKER_COLOR"/>
</linearGradient>
</defs>
<path d="..." fill="url(#grad-1)"/>
</svg>
Radial Gradient template:
<defs>
<radialGradient id="grad-r" cx="50%" cy="50%" r="50%">
<stop offset="0%" stop-color="#CENTER_COLOR"/>
<stop offset="100%" stop-color="#EDGE_COLOR"/>
</radialGradient>
</defs>
Gradient direction mapping:
x1="0" y1="0" x2="1" y2="1"x1="0" y1="0" x2="0" y2="1"x1="0" y1="0" x2="1" y2="0"x1/y1/x2/y2 for custom anglesWhen to use gradients vs currentColor:
currentColor (adapts to theme)Multiple gradient elements: When an image has different colored sections (e.g., a logo with a lighter left half and darker right half), use separate <path> elements each with their own gradient defined in <defs>. Use unique IDs for each gradient.
Decorative (icon next to text label):
aria-hidden="true" focusable="false"
Meaningful (icon IS the label, like an icon-only button):
role="img" aria-label="Close dialog" focusable="false"
<title>Close dialog</title>
Rule: if there's text next to it → decorative. If it stands alone → meaningful. When in doubt, ask.
When the user provides an existing SVG and wants modifications:
fill-rule="evenodd" for paths with holes.fill="none", add stroke="currentColor" with appropriate width.stroke-width and may need to re-scale the icon if thicker strokes overflow the viewBoxA) to sharp corners, or adjust existing arc radiiAlways show before/after and confirm with the user.
When generating multiple icons (for a sidebar, toolbar, feature grid, etc.):
Define these ONCE for the entire set and apply to every icon:
When generating more icons later for the same project:
When asked for a full set:
For basic SVG animations (fade, rotate, pulse, draw-in):
/* Spin — for loaders */
@keyframes spin { to { transform: rotate(360deg); } }
.icon-spin { animation: spin 1s linear infinite; }
/* Pulse — for notifications */
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } }
.icon-pulse { animation: pulse 2s ease-in-out infinite; }
/* Fade in */
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
.icon-fade { animation: fadeIn 0.3s ease-in; }
<path d="..." stroke-dasharray="100" stroke-dashoffset="100">
<animate attributeName="stroke-dashoffset" to="0" dur="0.6s" fill="freeze"/>
</path>
Only offer animations when:
Keep animations subtle — they enhance, never distract.
SVG paths can be unnecessarily verbose. Apply optimization intelligently:
L that could be a single polyline)Before optimizing, evaluate: "Will this change be visible at the rendered size?" If yes → don't optimize, or ask the user first. If no → optimize silently.
If unsure, ask: "I can optimize this path to be ~40% shorter, but there might be very subtle changes in curve smoothness. Want me to go ahead, or keep the current version?"
Before delivering ANY icon, verify:
currentColor (unless user specified fixed colors)M x y → Move to (start new subpath)
L x y → Line to
H x → Horizontal line
V y → Vertical line
C x1 y1 x2 y2 x y → Cubic bézier
S x2 y2 x y → Smooth cubic bézier
Q x1 y1 x y → Quadratic bézier
T x y → Smooth quadratic bézier
A rx ry rot large-arc sweep x y → Arc
Z → Close path
Lowercase = relative coordinates (offset from current point)
Provides a checklist for code reviews covering functionality, security, performance, maintainability, tests, and quality. Use for pull requests, audits, team standards, and developer training.
npx claudepluginhub dmian0/svg-icon-gen-plugin --plugin svg-icon-gen