How icons are built
Follow a Vadivam icon from its Figma drawing through path cleanup, 60% corner smoothing, strict SVG validation, and generation into every package.
Every icon starts as one SVG file in the repository’s icons/ folder. That file is the only hand-made part: the cleanup, the smoothed corners, and every package format are generated from it. This keeps all 24px drawings consistent and means a fix to one file reaches React, Vue, the raw SVGs, the icon font, and every other format in the same release.
Pipeline
Draw in Figma
Each icon is a top-level 24×24 frame named after its Lucide name, on a 2px grid. Draw centerline strokes on the frame. Don’t flatten or outline them, and keep corners as plain circular arcs: the smoothing is added in a later step. Before export, each frame is audited for a canonical name, 24×24 size, no background fill or layout guides, stroke-only artwork, a 2px stroke, round caps and joins, and zero rotation. After optimizing, the smoothed artwork is brought back into Figma, so the source file and the Community library always match the published icons.
Export to icons/
Export the frame as SVG into the root icons/ folder, replacing the existing file of the same name.
Normalize
bun run icons:optimizeThis optimizes each SVG in place with SVGO, cleans the path data, smooths every rounded corner at 60%, rewrites the root attributes, and strips stroke and fill attributes from the elements. Running it again changes nothing.
Cleaning the path data undoes what Figma’s export leaves behind, without changing how the icon looks:
-
Strokes that end at the same point are joined into one, preferring the stroke that continues straight on at a junction. With round caps and joins, two strokes meeting at a point render exactly like one stroke turning there, and a joined outline lets smoothing see both sides of each corner.
-
Lone
Mcommands, and stubs shorter than 0.05px hidden under another stroke, are removed. Dots drawn ash.01are kept. -
A straight line split into pieces becomes one line.
-
Horizontal and vertical lines just off the pixel grid are snapped onto it, as described under Pixel grid alignment.
bun run icons:checkThis runs every rule under What every SVG must pass, every Checked rule in the design guide, and confirms the names against the pinned Lucide release.
Review by eye
Compare the icon with circle, square, and its family at 24px and at 1×, against the rules that are not checked automatically: grid alignment, keylines, corner radius, gaps, and weight. To see where the icon sits in the set’s distributions, run:
bun scripts/icon-geometry.mjsBuild
bun run icons:buildEvery package and site asset is generated from the validated icons/ folder, so one drawing reaches every format in the same release. Generated files are never edited by hand; fix the source SVG and build again.
What every SVG must pass
Icon files are treated as untrusted input. bun run icons:optimize and bun run icons:check reject an SVG that breaks any of these rules, before anything is published or deployed:
- Root. The root
<svg>has exactlyxmlns="http://www.w3.org/2000/svg",width="24",height="24",viewBox="0 0 24 24",fill="none",stroke="currentColor",stroke-width="2",stroke-linecap="round", andstroke-linejoin="round". Any other root attribute, such asclass,id, orstyle, is rejected. - Elements. Only
<path>,<circle>,<line>,<polyline>,<polygon>,<rect>, and<ellipse>are allowed. That rules out<a>,<clipPath>,<defs>,<filter>,<foreignObject>,<g>,<image>,<linearGradient>,<mask>,<pattern>,<radialGradient>,<script>,<style>,<symbol>,<text>,<use>, and any other element. Every icon in the set uses only<path>. - Attributes. Each element carries geometry only:
don a path;cx,cy, andron a circle;x1,y1,x2, andy2on a line;pointson a polyline or polygon;x,y,width, andheighton a rect, sincerxandrycan’t carry corner smoothing; andcx,cy,rx, andryon an ellipse. Nofill,stroke,transform,opacity,style,class,id, or event handlers. - Geometry. Every element needs geometry. An icon needs at least one drawable element. Path data must parse. A single path may hold at most 8 closed subpaths. The stroke must stay inside the 1px padding. Every rounded corner between two straight lines must be smoothed. Path data must already be clean: no strokes split where they meet, no stray subpaths, no straight lines in pieces, and no lines just off the pixel grid.
- Fills. Source artwork with a
fillother thannoneis rejected before optimization, so outlined Figma exports never reach the set. - Files. File names must be canonical Lucide names in lowercase kebab-case, with an entry in
metadata/lucide.json.
Because every published icon has passed these checks, Vadivam SVGs carry no scripts, styles, links, external references, or event handlers, and are safe to inline in HTML, email, or user-facing documents.
What gets built
From each validated SVG, bun run icons:build generates:
- Optimized SVG files, per-icon SVG strings, a full SVG sprite, an icon font, and icon-node data in
vadivam. - Components for React, React Native, Vue, Svelte, Solid, Angular, Astro, and Preact, each with a PascalCase name made from the file name.
- The shadcn/ui registry item for every icon.
- The icon data inside the MCP server.
- The website’s search index and the
/icons/<name>.svgfile behind every icon page.
All packages share one version and are published together. See Versions and compatibility.