Iconsaz: custom icon packs
Build a new, original icon pack that looks like it belongs to the user's brand: same stroke feel as their typeface, same corner language as their UI, same mood as their marketing. The quality bar is set by the best public packs (Lucide, Phosphor, Tabler, Heroicons, Material Symbols, Untitled UI): one grid, one stroke rule, one optical size, predictable names. The output is the user's own pack, not a copy of any of them.
Files in this skill
| File | Read it when |
|---|---|
references/question-flow.md | Step 1: exact wording, options, defaults and batching for the 14 questions |
references/style-rules.md | Steps 2–7: benchmark rules, brand-to-style mapping, construction rules, starter catalogue, metaphor bank |
references/rtl-and-culture.md | Step 8, and any time the product is RTL or ships to several regions |
templates/style-brief.md | Step 3: copy and fill it in; it is also the file the user keeps |
scripts/validate_icons.py | Steps 6, 7 and 9: checks grid, padding, stroke, viewBox, currentColor, hidden layers, naming, completeness, RTL pairs |
scripts/preview_sheet.py | Steps 6 and 9: builds preview.html (sizes, zoom on grid, light/dark, colour, RTL toggle) |
scripts/package_pack.py | Step 10: validates, then zips SVGs + flat Figma-ready copies + preview + brief + import guide |
The scripts are plain Python 3.8+ with no dependencies. Run them with python scripts/<name>.py --help.
Two modes
- New pack: run the whole workflow below.
- Extend a pack: the user shares a style brief made by this skill earlier (it has an
icon-specJSON block). Skip the interview and brand scan. Read the brief, ask only which icons to add (and offer metaphors for abstract ones), draw them to the brief's exact numbers, validate against it, add them to the icon list, bump the minor version and add a changelog line. Never change grid, stroke, padding or radius in this mode: matching the old icons exactly is the whole point. If the user wants a style change, that is a new major version and every icon must be redrawn.
Workflow
Keep the user in the loop at three gates: the brand scan (step 2), the brief (step 3) and the test icons (step 6). Drawing 60 icons on a wrong assumption wastes far more of their time than one extra confirmation.
1. Interview
Ask the 14 questions in references/question-flow.md, in order, three or four at a time.
Use a structured question tool (such as AskUserQuestion) for multiple-choice questions when
one is available, and plain chat for uploads and typed answers.
- If the user skips a question, choose the default from the reference, say what you picked and why in one line, and move on. Don't re-ask.
- Don't ask for the user's existing icons, and if they offer them, thank them and set them aside. This is a new set; old icons pull the style back towards whatever the team is trying to leave. Their design-system rules (grid, stroke, radius) are welcome, which is what question 9 asks for.
- Uploaded screenshots will contain current icons. Use them only to learn where icons are needed (step 4), never how they should look.
2. Brand DNA scan
Study everything uploaded: logo, brand guide, colours, typeface, mood boards, marketing
and screenshots. Derive the style from evidence using the mapping tables in
references/style-rules.md ("From brand to icon style"). Look at:
- Typeface: stem thickness at UI sizes, terminals (round, flat, angled), roundness of bowls, x-height, geometric vs humanist. This sets stroke weight and caps/joins.
- Logo: line weight relative to its size, corner shapes, angles (45° vs free), any signature motif (a notch, a curl, a cut corner) that could become a subtle pack-wide trait.
- UI screenshots: component corner radius, border width, density, spacing. This sets icon corner radius and the size set.
- Colour and imagery: these inform mood only. Icons ship in
currentColor.
Show the findings as a table and ask the user to confirm or correct them:
| Signal | Evidence | Decision | Confidence |
|---|---|---|---|
| Stroke | Body font is Nunito Regular, stems ≈ 1.6 px at 16 px text | 2 px at 24, 1.75 at 20 | High |
Say plainly when evidence is thin ("no typeface supplied, so stroke is inferred from the logo only, medium confidence").
3. Style brief
Copy templates/style-brief.md, fill in every section and show it to the user. It covers
grid and padding, stroke per size, caps and joins, corner radius, styles and states,
sizes, mood, naming, RTL decisions and the full icon list grouped by category. The
icon-spec JSON block at the bottom is what the scripts read, so keep it in sync with the
prose. Get explicit approval before drawing anything.
4. Missing-icon finder
Go through each screenshot region by region (navigation, headers, toolbars, buttons, list
rows, form fields, empty states, toasts and status, settings rows, cards) and list every
spot that needs an icon. Present a table — screen, location, needed icon, already in
list? — and add the missing ones to the brief's icon list after the user agrees. If there
are no screenshots, use the starter catalogue in references/style-rules.md plus the
product context.
5. Metaphor options
For every abstract concept (refund, consultation, sync, onboarding, subscription, loyalty,
compliance and so on), offer two or three visual ideas with a one-line rationale each, and
flag any cultural risk using references/rtl-and-culture.md. The "Metaphor bank" in
references/style-rules.md has starting points. Let the user pick, then record the
choice in the brief, because the next designer needs to know why refund is a coin
with a return arrow.
6. Test icons
Draw three or four samples first: home, search, settings, and the most
characteristic product-specific icon. Make each one in every approved style, at every size.
Then run
python scripts/validate_icons.py icons/ --brief style-brief.md --samples
python scripts/preview_sheet.py icons/ --brief style-brief.md -o preview.html
Fix every error, look at the preview yourself (open it in a browser if you have one and check the 1× sizes, not just the zoom), then show it to the user. Ask what feels off. Typical tweaks at this stage: stroke a touch heavier or lighter, corners softer, more or less detail. Update the brief if anything changes. Don't start the full set until the user approves the samples.
7. Full set
Draw every icon in the brief following "How to draw" below. Work category by category and run the validator after each one, so you don't find one systematic mistake 80 icons later.
8. RTL and culture
If text direction is RTL or both, make a mirrored -rtl version of every directional icon
(arrows, back and forward, send, reply, undo and redo, logout, list indent and so on). Leave
non-directional icons alone; mirroring a clock or a play button is a mistake. Check every
icon against the cultural-risk list. Both lists are in references/rtl-and-culture.md.
Mark directional icons in the spec's directional list so the validator checks the pairs.
9. Final check
Run the validator without --samples. It must report zero errors. Then check by eye,
because a script can't judge recognisability:
- Every icon in the brief exists in every style and size (validator: completeness).
- Every icon follows the brief: grid, padding, stroke, caps, joins, radius (validator).
- Optical size is even across the set; nothing looks bigger or smaller than its neighbours in the preview grid (validator warns on outliers).
- Each icon is still clear at the smallest size: view the 1× row of the preview. If two details merge, remove one in that size rather than thinning the stroke.
- Names follow
category/name/variant/size, lower-case kebab-case, and mean the same thing everywhere (validator: naming). - RTL pairs exist and really mirror each other (validator: RTL).
- No culturally risky symbol slipped in.
Fix anything that fails and run the checks again before delivering.
10. Deliver
Figma Professional (or higher): build the library with the Figma MCP. If its tools are
missing or not authenticated, tell the user it needs connecting and offer the zip instead.
If a Figma skill such as figma-use is available, load it before the first write call.
- Create a new file with three pages: Cover, Icons and Usage.
- On Icons, make one section per category. For each icon, turn every SVG into a node
(
figma.createNodeFromSvg), convert each to a component, name the components with variant properties (style=outline, state=default, size=24), and combine them withfigma.combineAsVariantsinto a component set namedcategory/name. Keep strokes as strokes; don't outline them. - Build one category per write call. Large batches time out, and a failure costs a category, not the whole pack. Take a screenshot after each category and compare it with the preview.
- Cover: pack name, version, mood words and a grid of hero icons. Usage: sizes and when to use each, spacing next to text, the active/inactive rule, RTL rule, naming, do/don't examples, and "to add icons, share the style brief with the skill".
- Also hand over the zip from the next path, since developers need the SVGs either way.
Figma Free (or no Figma): the Figma MCP can't write library files on free plans, so deliver files instead:
python scripts/package_pack.py icons/ --brief style-brief.md --out dist/
It refuses to package on errors, and also on warnings until you've reviewed them; add
--allow-warnings only once each remaining warning is intended. It then writes
dist/<pack>-v<version>.zip containing svg/ (the
category/name/variant/size.svg tree), figma/ (flat category__name__variant__size.svg
copies that become slash names in Figma after one batch rename), preview.html,
manifest.json, the style brief, and IMPORT-TO-FIGMA.md with click-by-click steps for
importing the icons and turning them into components with variants. Summarise those steps
in chat too.
11. Save the brief
Save the final style brief next to the deliverable (named <pack>-style-brief.md) and
tell the user, in these words or close to them: "Keep this file. Next time you need
icons, share it with me first and the new ones will match this pack exactly."
How to draw
Write SVGs by hand on the agreed grid, as you would build vectors in a design tool. Each
size is drawn on its own native canvas (viewBox="0 0 20 20" for 20 px and so on), so
small sizes can get their own stroke and simplified detail, the way Material's optical
sizes and Heroicons' 20 and 16 px sets do.
- Root:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">. Set paint on the root and let shapes inherit, which keeps every icon identical. - Use primitives (
circle,rectwithrx,line,pathwith arcs) on the grid. Keep coordinates on whole or half units (quarter units at most). Off-grid points render blurry at 1×. - Colour is
currentColoronly. Filled shapes usefill="currentColor". Duotone's second tone iscurrentColorat the brief's opacity, never a second colour. - No transforms, hidden elements,
<text>, embedded images,<style>, IDs or editor metadata. Flatten everything into plain geometry. - Fit the shape to its keyline (circle, square, portrait or landscape rectangle; see style-rules), so a round icon and a square icon look the same size.
- Interior gaps are at least one stroke width wide, wider at 16 px.
- Filled variants follow the same silhouette as the outline, with details knocked out as gaps. They should read as the same icon, "switched on".
- To make a smaller size, start from the 24 px geometry scaled to the new canvas, snap points to the grid, set that size's stroke from the brief, then remove detail that no longer fits. Never just scale the file.
- Match the brand typeface: caps and joins mirror its terminals, curves mirror its bowls, and a pack-wide signature (one notch, one cut corner) can echo the logo if the brief asks for it.
A minimal outline icon:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="10.5" cy="10.5" r="7"/>
<path d="M15.5 15.5 21 21"/>
</svg>
Working layout
icons/<category>/<name>/<variant>/<size>.svg e.g. icons/nav/home/outline/24.svg
icons/nav/arrow-back-rtl/outline/24.svg mirrored RTL twin
style-brief.md filled-in template with the icon-spec block
preview.html generated
dist/<pack>-v<version>.zip generated
The canonical icon name is the path without .svg, so nav/home/outline/24. That is also
the Figma component name, which keeps code, design and files in step.
Talking to the user
Many people using this are designers, not developers. Say "line thickness" alongside "stroke", "corner roundness" alongside "radius", and explain any script output in a sentence instead of pasting it raw. Keep each turn short: a few questions, one decision, or one thing to review.