Communitygithub.com

Abhijit-Jha/icon-skill

>- Designs and ships original SVG UI icons, from one custom icon to a consistent set. Icons are drawn on a 24px grid with pro design rules, then linted, optimized, previewed as PNG and emitted as zero-dependency React, Vue, Svelte or HTML-sprite components with accessible defaults. Use when the user needs sidebar icons, nav or navbar icons, dashboard icons, menu, toolbar or settings icons, an icon set, a custom icon or an SVG icon, or says "make an icon for…", "design icons for my app", or wants to replace emoji or placeholder icons, even if they never say SVG. It always draws its own icons instead of installing an icon library, and matches the style of a library the project already uses. Not for logos, brand marks, favicons or app-store artwork, illustrations, raster images, or icon-font setup.

What is icon-skill?

icon-skill is a Claude Code agent skill that >- Designs and ships original SVG UI icons, from one custom icon to a consistent set. Icons are drawn on a 24px grid with pro design rules, then linted, optimized, previewed as PNG and emitted as zero-dependency React, Vue, Svelte or HTML-sprite components with accessible defaults. Use when the user needs sidebar icons, nav or navbar icons, dashboard icons, menu, toolbar or settings icons, an icon set, a custom icon or an SVG icon, or says "make an icon for…", "design icons for my app", or wants to replace emoji or placeholder icons, even if they never say SVG. It always draws its own icons instead of installing an icon library, and matches the style of a library the project already uses. Not for logos, brand marks, favicons or app-store artwork, illustrations, raster images, or icon-font setup.

Works with✓Claude Code~Codex CLI✓Cursor
npx skills add https://github.com/Abhijit-Jha/icon-skill/tree/HEAD/icon-forge

Ask in your favorite AI

Open a new chat with this agent skill pre-loaded.

Documentation

Icon Forge

Draw custom icons that look like they came from one professional set, and ship them with no runtime dependencies. You are done when every icon passes lint, you have looked at the 16/20/24px preview and it reads clearly and consistently on light and dark, and the generated components are wired in with accessible usage.

<skill> below means the folder containing this file (e.g. .claude/skills/icon-forge, .cursor/skills/icon-forge, .agents/skills/icon-forge). Scripts need Node ≥18 and no project dependencies.

When to use / when not

  • Use: a sidebar, navbar, dashboard, settings page, empty state or toolbar needs icons; the user asks for a custom or missing icon; the user wants to replace emoji/placeholder icons or a heavy icon package with a small own set.
  • Don't use: logos and brand marks (trademarks; need a designer), favicons/app icons, illustrations or spot art, photos/raster, animated Lottie. If the user explicitly asks to install a library (e.g. "just use Lucide"), do what they asked; this skill exists for the custom path.

Hard rules (and why)

  1. Draw every icon yourself; add no icon-library dependency. The user chose own icons for bundle size and a unique look. Don't paste path data from Lucide, Heroicons, Material, etc. (license and originality). Use references/glyph-cookbook.md (original drawings) as starting geometry.
  2. If the project already uses an icon library, match its grid, stroke, caps and radius (see scripts/detect.mjs and design-rules §10). New icons must sit next to existing ones without looking foreign.
  3. One set, one style. Same grid, stroke width, caps/joins, radius scale, padding and detail level for every icon. Consistency matters more than any single clever icon.
  4. Presentation attributes live only on the root <svg>, colour is currentColor, and sources contain no ids, styles, classes, transforms or <g>. Otherwise theming, dark mode, the strokeWidth prop and inlining break.
  5. Never claim an icon is good without rendering it and viewing the PNG. Geometry that looks right in code routinely fails at 16px: blobs, closed gaps, off-centre shapes, mismatched weight.
  6. Run the scripts; don't re-implement them. Lint, optimize, preview and codegen are deterministic. Never hand-edit generated files; change icons/src/ and rebuild.
  7. Don't modify the user's dependencies. Preview tooling installs into ~/.cache/icon-forge (--install); SVGO runs via npx if absent. Ask before adding any package to the project.
  8. Accessible by default. Icons are aria-hidden unless labelled; icon-only controls get aria-label; interactive targets ≥44px; meaningful icons ≥3:1 contrast.

Workflow

1. Detect stack and existing style

node <skill>/scripts/detect.mjs .

Note the framework, TypeScript, Tailwind, any icon library (and its style preset), local SVG icons, and the suggested output dir. If an existing set exists, open 2–3 of its SVGs and copy their root numbers. Otherwise use the default: 24 grid, stroke 2, round caps/joins.

2. Plan the list: meaning → metaphor → file name

Write a short table before drawing: label | metaphor (what is drawn) | file name | cookbook start. Example: Projects | kanban board | kanban.svg | kanban. Pick mainstream metaphors (design-rules §7) and one metaphor per meaning. Name files for the object, kebab-case. Ask the user only if a label is ambiguous and the choice changes the UI meaning; otherwise decide and state the choice.

3. Draw on the 24 grid

Create icons/src/<name>.svg with the canonical root (svg-code-rules.md). For each icon:

  • Start from the matching keyline: circle r10, square 18 (x/y 3), portrait 16×20, landscape 20×16. Keylines are stroke centrelines.
  • Keep the stroke's outer edge ≥1 unit from the canvas edge. Use radius 2 on large corners and 1–1.5 on small ones; keep gaps ≥2 units of clear space.
  • Make parts either join exactly or keep a clear gap. Use integer coordinates for 2px strokes. Use as few elements as possible (≤6 is typical).
  • Start from the closest references/glyph-cookbook.md entry, then adapt it. Copy the geometry from <skill>/assets/cookbook/<name>.svg when a glyph fits as-is.
  • Compute repeated geometry (teeth, rays, star points) with a few lines of JS instead of guessing. Draw the whole set first, then refine. Consistency is judged side by side.

4. Lint

node <skill>/scripts/lint.mjs icons/src

Fix every ✖. Treat ⚠ gap, density, scale and bounds as design problems to fix, not noise. Note each ℹ gap and check it in step 6; tight parallel strokes (bars, lines) smudge at 16px unless they sit 4 units apart. Re-run until it shows PASS with no warnings you can't justify. Flags: --grid, --padding, --mode fill, --strict, --json.

5. Optimize

node <skill>/scripts/optimize.mjs icons/src icons/svg

This rounds numbers, runs SVGO (local install or npx svgo@4; falls back to the built-in canonicalizer offline), re-orders root attributes, and prints bytes per icon plus total gzip. Lint the output too: node <skill>/scripts/lint.mjs icons/svg.

6. Preview and LOOK, then iterate

node <skill>/scripts/preview.mjs icons/svg --out icons/preview.png \
  --sidebar "dashboard:Dashboard,kanban:Projects" --active dashboard   # add --install the first time if no PNG engine

View the PNGs with your image-viewing tool, in this order:

  1. icons/[email protected]: the set strip and the sidebar mocks. It is small enough to see at full detail.
  2. icons/[email protected]: every icon at each size, plus the inspect view. It's tall, so crop it if your viewer downscales.
  3. icons/preview.png: true 1× pixels.

Together they show:

  • a 24/16px strip on light and dark;
  • a sidebar mock with an active item and a collapsed rail;
  • per-icon rows at 16/20/24/48;
  • a 4× inspect view with grid, blue keylines and the red 1px padding limit.

Answer the self-review questions in design-rules §12. Typical fixes:

You seeFix
One icon looks lighter/smaller in the stripenlarge to its keyline, or add a frame/axis (open glyphs read light)
One looks heavier/busierremove details; ≤3 bars, ≤6 teeth, ≤2 text lines
A smudge where parts meet at 16pxjoin exactly or open the gap to ≥2 units
Shape hugs one side in the inspect viewre-centre, or nudge 0.5–1 unit for optical balance
Metaphor unclear in the collapsed railchoose a more literal metaphor (step 2)

Repeat steps 3–6 until a second look finds nothing to fix. Usually 1–3 rounds.

7. Generate framework output

node <skill>/scripts/build.mjs icons/svg --out src/components/icons --framework react --lang ts \
  --labels "kanban:Projects,dashboard:Dashboard"

--framework react|vue|svelte|html|all; --lang ts|js; --package @app/icons writes a sideEffects:false package.json. The output is one tree-shakable module per icon, a shared base component (size, color, strokeWidth, absoluteStrokeWidth, title, className), index named exports, and icons.json. HTML gives sprite.svg + usage.html. Details: references/output-formats.md.

Then type-check or build the project if it has a script (npx tsc --noEmit, npm run build) and fix any errors.

8. Wire it in with accessible usage

Use the pattern from references/accessibility-and-usage.md:

  • <nav aria-label>; aria-current="page" plus colour and background for the active item;
  • icon size-5 shrink-0 and decorative;
  • an aria-label on icon-only buttons; logout as a <button>;
  • ≥44px rows; muted colours that still reach 3:1.

Output format

Finish with a short report to the user:

  1. Icons: table label → component → metaphor and the folder paths (icons/src, icons/svg, generated dir).
  2. Checks: lint result (errors/warnings), optimize totals (avg B/icon, gzip total), and the preview path(s) you inspected, plus what you changed after looking.
  3. Usage snippet for their framework, with a11y attributes.
  4. Notes: style decisions (grid/stroke/preset matched), RTL icons to mirror, and anything you couldn't verify.

Example

User: "Need sidebar icons for Dashboard, Projects, Team, Settings in my Next.js + Tailwind app." → detect: React (Next) + TS + Tailwind, no icon library → plan: dashboard/tiles, kanban, users, settings/gear → draw from the cookbook and adapt → lint PASS → optimize: 4 icons, avg ~340 B, ~0.4 KB gzip → preview: Projects looked light, so add bars; re-check → build --framework react into src/components/icons → <DashboardIcon className="size-5 shrink-0" /> in the nav with aria-current.

References

Open when you need to…Read
choose sizes, keylines, radii, gaps, metaphors, or fix a preview problemreferences/design-rules.md
write or debug SVG markup, or understand a lint errorreferences/svg-code-rules.md
start from proven geometry for a common UI icon (56 drawn glyphs)references/glyph-cookbook.md + assets/cookbook/*.svg
generate or hand-adapt React/Vue/Svelte/Angular/HTML output, or reduce bundle sizereferences/output-formats.md
write the usage snippet: nav/sidebar patterns, active state, labels, contrast, RTLreferences/accessibility-and-usage.md
change the shape of generated components (props, class names, a11y defaults)templates/<framework>/, which build.mjs reads; edit there, never in the output
test changes to this skillevals/evals.json

Verification checklist (all must be true before you report done)

  • No icon library added; every icon drawn for this task or adapted from the cookbook.
  • Style matches the project's existing icons (or the default preset) across the whole set.
  • lint.mjs PASS on icons/src and icons/svg; remaining warnings justified in the report.
  • You viewed the preview PNG after your last change; 16px light/dark rows are clean; no icon is heavier, lighter or larger than its siblings.
  • Components generated by build.mjs; project type-check/build passes (when available).
  • Usage: decorative icons hidden, icon-only controls labelled, active state not colour-only, targets ≥44px, contrast ≥3:1.
  • Report includes sizes (avg bytes/icon, gzip total) and preview path.

Related Skills