withicons
AGENTS.md3 starsChanged 28 days agoMITView on GitHub
This file is for coding agents (Claude Code, Cursor, Codex, Copilot) that change this repo. If you only need to use the icons in another project, read skills/with-icons/SKILL.md instead. 1,000 icons x 34 styles = 34,000 icons (current numbers; generators read them from data), all generated from 1,000 hand-authored skeletons (plus hand-drawn per-style overrides in forge/hand/), plus one optional animation spec and 20-30 colour palettes per icon, and a separate set of up to 50 live icons (content you set:…
- Commits and pushes
We split this AGENTS.md into the rules it gives an agent
4 rules. About 0 are common, 2 are distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈2
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 92
Originality: never copy path data from Lucide, Feather, Heroicons, Tabler, Phosphor, Material, Font Awesome or any other set.
- Very specific: line 103
Counts are data: never hard-code "500 icons" / "12 styles" in generators.
- Very specific: line 121
Never run npm publish, scripts/deploy.mjs without --dry-run, AWS mutations, or git push unless the user asks.
- Distinctive: line 125
When several agents work at once, each owns specific files.
≈ “Common” is an estimate: at least 1 in 5 of the 36,368 AGENTS.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
AGENTS.md: working on the with icons repository
This file is for coding agents (Claude Code, Cursor, Codex, Copilot) that change this repo. If you only need to
use the icons in another project, read skills/with-icons/SKILL.md instead.
What this repo is
1,000 icons x 34 styles = 34,000 icons (current numbers; generators read them from data), all generated from 1,000 hand-authored skeletons (plus hand-drawn per-style overrides in forge/hand/), plus one optional animation spec and 20-30 colour palettes per icon, and a separate set of up to 50 live icons (content you set: dates, times, counts, labels) whose generators every style renders.
forge/icons/<name>.json the ONLY hand-drawn input: one skeleton per icon (paths + plates, fills, cutouts, aliases, synonyms, tags)
forge/manifest.json icon list + categories
forge/motion/<name>.json hand-authored animation spec per icon (loop, hover, alt presets, swaps); contract: forge/MOTION.md
forge/palettes/<name>.json 20-30 colour palettes picked per icon (ten roles: ink c1-c4 tint accent shadow shine edge);
contract: forge/PALETTES.md; ships as @withicons/core/palettes/* (+ palette-map.js)
forge/styles/<style>.mjs one deterministic renderer per style, in this order everywhere (STYLE_ORDER in forge/lib/emit-core.mjs):
line solid duo gloss engrave blueprint sketch | palette styles: glass kawaii sticker pixel retro
| studio styles: luxe bauhaus skeuo (site group "Studio"; role-named vars --with-<style>-<role>)
| storybook styles: anime gothic pastel coquette plush (site group "Storybook"; role-named vars)
| rich styles (run 12, gradients allowed, role-named vars): clay bento suite dock liquid chrome soft3d brutal
| holiday styles (run 13, rich): utsav rangoli halloween christmas lunar valentine (site group "Holidays");
glass is rich too (soft frosted glass with gradients); duo has an accent detail + opt-in gradient.
Site groups (site/js/site.js GROUPS): Essentials, Product & brand, 3D & glass, Playful, Artistic, Holidays
(palette colours are var(--with-<style>-<role>, #hex), ink stays currentColor)
forge/hand/<style>/<icon>.mjs hand-drawn override of one icon in one style (replaces the generated drawing);
contract: forge/HAND.md; validate with node forge/tools/hand.mjs check <style> <icon>
forge/dynamic/<name>.mjs live icon generators: params -> skeleton, rendered by every style (forge/DYNAMIC.md);
ships as @withicons/dynamic (emit-dynamic) and site/vendor/dynamic/dynamic.js (live.html)
forge/loaders/<name>.mjs animated loaders (50: common / creative / festival): parts = skeletons + CSS keyframe motion, drawn by
every style; _morphs.mjs = icon morph presets; contract: forge/LOADERS.md; compiler forge/lib/loader-compile.mjs;
ships as @withicons/loaders (emit-loaders) + site/loaders.html (Loader Studio) + MCP get_loader
forge/kernel/** geometry + boolean ops shared by renderers
forge/lib/load.mjs loads/prepares skeletons
forge/lib/emit-*.mjs one emitter per package -> packages/*/dist (generated, gitignored); emit-motion -> packages/motion
emit-core also exports the shared helpers: STYLE_ORDER, flattenVars, countText, paletteDoc, motionDoc
forge/tools/site-data.mjs site data (site/data/meta.js, style-<name>.js); build.mjs calls its build(ctx)
forge/tools/site-seo.mjs generated pages: site/icons/*.html, categories/, styles/, sitemap, robots, llms*.txt, icons.json, og/
forge/build.mjs renders everything once, runs every emitter, then site-data + site-seo
packages/* npm packages @withicons/{core,core-plus,soft3d,holiday,react,vue,svelte,angular,solid,web,web-plus,classes,classes-plus,static,static-plus,search,mcp,motion,dynamic,loaders} + CLI `withicons`
companions (jsDelivr: 150 MB per package): the newest styles' core files (svg, nodes) and class files
live in core-plus / classes-plus / web-plus / static-plus, the styles in STYLE_PACKAGE in their own packages (@withicons/soft3d,
@withicons/holiday: dist/ + dist/classes/); core and classes keep the older styles, except the class files of CLASSES_PLUS_STYLES (glass, skeuo, gothic: classes-plus). Every package stays under 145 MB (scripts/package-budget.mjs). Build every CDN URL with cdnPkg/cdnDir/cdnSvgUrl
(forge/lib/emit-core.mjs), never with a hard-coded core@ or classes@ path per style
site/ zero-build static website (vanilla HTML/CSS/JS), deployed to withicons.com
skills/with-icons/ the agent skill for USERS of the library (reference/icons.md is generated)
infra/ AWS CloudFormation (S3 + CloudFront + Lambda API + OIDC role + budget)
scripts/ deploy.mjs, publish.mjs, skill-sync.mjs
docs/ LAUNCH.md (launch plan), COSTS.md (AWS cost model)Commands
npm ci # Node 22+
node forge/build.mjs # full build (packages + site), ~1-2 min
node forge/build.mjs react vue # only some emitters (site data/SEO still regenerate)
node forge/tools/check.mjs # lint all skeletons + render every style (exit 1 on hard errors)
node forge/tools/check.mjs home lock # just these icons
node forge/tools/check-motion.mjs [names] # validate forge/motion/*.json against forge/MOTION.md
node forge/tools/check-palettes.mjs [names] [--quiet] # validate forge/palettes/*.json against forge/PALETTES.md
node forge/tools/preview.mjs --styles line,solid --icons home,lock --size 56 --small --out .preview/<agent>-x.png # add --dark for palette styles
node forge/tools/serve.mjs # http://localhost:4321 (site/)
npm test --workspaces --if-present # package tests (incl. packages/search)
node forge/tools/check-loaders.mjs [names] [--styles a,b] # validate loader specs, compile every style, size, determinism
node forge/tools/preview-loaders.mjs --loaders spinner,orbit --styles line,glass --frames 8 # frame strips (motion on a PNG)
node forge/lib/emit-loaders.mjs [--styles line,glass] # @withicons/loaders + site loader files only (~2 min); --styles redraws just those (+ line) and leaves package.json, README and MCP data alone
node scripts/skill-sync.mjs [--check] # regenerate the skill's icons.md, palette + motion tables, counts, site/skill/SKILL.md
node scripts/deploy.mjs --dry-run # deploy plan; never run without --dry-run unless asked
node scripts/publish.mjs --dry-run # npm pack check (warns if v<version> is already tagged elsewhere); never publish unless askedLook at your output. For any drawing or renderer change, render a preview PNG and inspect it at 56px and at
real 16/24px (--small), on light and --dark.
Rules
- Read
forge/CONTRACT.mdbefore touching icons or styles. Grid, keylines, plates, fills/cutouts, renderer contract. Reuse the shared parts inforge/PARTS.mdexactly. - Adding a style touches more than its renderer:
STYLE_ORDER/PALETTE_STYLES/RICH_STYLES(+STYLE_PACKAGEwhen it ships in a package of its own) in forge/lib/emit-core.mjs, the site lists (ORDER,GROUPS,INFO,ROOTS,NAV_STYLE,NEW_STYLESin site/js/site.js;WORDSin style-picker.js;HEX/STYLE_SAYin live.js;ORDER/GROUPS/HEX/SAYin library.js;ORDER/HEX/CLABELin editor.js), its colour trio +-onin site/css/tokens.css (light and dark) and library.css, forge/tools/site-seo.mjs, forge/tools/site-pages/lib.mjs (ORDER,STYLE_COLOR), its site group inGROUPS(site/js/site.js, read by forge/tools/style-groups.mjs), the picker rows in site/css/icon-page.css, site/css/live.css +SB_GROUPSin forge/tools/site-dynamic.mjs (STYLE_SAY), the home packs (FOLLOW/WASHLINE/SHOWCASEin forge/tools/site-data.mjs),STYLES_3Din packages/motion/src/meta.js when its motion should play in 3D, an allowance in forge/tools/livegate-thresholds.json (node forge/tools/check-dynamic.mjs --calibrate --style <name>), a "Free … icons" lander (forge/tools/site-alternatives/free-more.mjs, gated byhasStyle) and the search words (packages/search/src/engine.mjsSTYLE_WORDS+STYLE_PHRASES+ test). Counts and copy are data-driven; never hard-code "15". - Originality: never copy path data from Lucide, Feather, Heroicons, Tabler, Phosphor, Material, Font Awesome or any other set.
- Deterministic: same input, byte-identical output. Use the kernel
rng(seed), neverMath.random()or dates. - Colour: renderers paint
currentColor. Only the palette styles may add colours, and only asvar(--with-<style>-<role>, #hex)(no defs, ids, gradients, filters, masks, text or images; rich styles may add gradients, see below). Standalone.svgoutputs flatten the variables (flattenVars); inline outputs keep them. - Rich styles (glass and the AI / Product / Trend groups) may also use gradients, and only as one
<defs>node of linear/radial gradients whose ids arewg-<style>-<icon>-<n>and whose stop colours are role variables (var(--with-<style>-<role>, #hex)), so palettes recolour the gradients too. Still no filters, masks, text or images. Inline outputs (packages, the site viauniqIdsin forge/tools/site-pages/lib.mjs) make the ids unique per instance; standalone.svgflattens the variables. Heavy styles load on demand on icon pages and style hubs. - Counts are data: never hard-code "500 icons" / "12 styles" in generators; use
countText(ctx)/ctx.styles.length. - Palettes: per-icon palettes live only in
forge/palettes/<name>.jsonand set colour roles, never style variables; each style maps roles to its own--with-*variables (palette-map), so one palette recolours every multi-colour style. - Motion: animations live only in
forge/motion/<name>.json(closed preset vocabulary,forge/MOTION.md) and ship in@withicons/motion; icons never depend on it. - Generated files are not edited by hand:
packages/*/dist,site/data/*,site/icons/*.html,site/categories/,site/styles/,site/og/,sitemap.xml,llms*.txt,icons.json,skills/with-icons/reference/icons.md,site/skill/SKILL.md,packages/motion/dist,site/vendor/motion/*,site/data/motion.js,packages/cli/src/skill-data.mjs,packages/mcp/src/data-inline.mjs,packages/loaders/dist,packages/loaders/{package.json,README.md},packages/mcp/src/loaders-data.mjs,site/data/loaders.js,site/vendor/loaders/*,site/loaders/svg/*,skills/with-icons/reference/loaders.md(the table). Change the generator and rebuild. - Names: kebab-case canonical names.
aliases(3-15) are what people guess. An alias may not equal another icon's name.synonymsare extra search words. Renaming an icon is a breaking change: keep the old name as an alias. - Brand: the product is with icons (lowercase wordmark), domain withicons.com, "Powered by Evergrow".
The old names egopenicons / Evergrow Open Icons /
eg-prefixes are retired, so never reintroduce them. Public identifiers: npm@withicons/*, element<with-icon>, classeswith with-<name>, CSS vars--with-*. - Site: zero build, relative links (works from
file://and S3),.htmlURLs, every page works without JS for reading. Design contract:site/DESIGN.md. - Previews go to
.preview/<agent-name>-*.png(gitignored). Temporary files go to.tmp/. - Never run
npm publish,scripts/deploy.mjswithout--dry-run, AWS mutations, orgit pushunless the user asks.
Ownership (parallel agents)
When several agents work at once, each owns specific files. Do not edit files you do not own. Ask the coordinator instead.
| area | owner | files |
| icon skeletons | icon authors (per batch, see forge/.claims/) | forge/icons/<name>.json |
| animation specs | motion authors (per icon) | forge/motion/<name>.json |
| colour palettes | palette authors (per icon) | forge/palettes/<name>.json |
| motion package | motion owner | forge/lib/emit-motion.mjs, packages/motion/** |
| style renderers | one agent per style | forge/styles/<style>.mjs, forge/styles/_<style>-*.mjs |
| packages | packages owner | forge/build.mjs, forge/lib/emit-*.mjs (not emit-motion), packages/** (not motion), forge/tools/site-data.mjs, forge/tools/site-integrations.mjs |
| site brand + home (D1) | D1 | site/fonts/**, css/tokens.css, css/chrome.css, js/site.js, index.html, home css/js, 404.html, site/brand/** |
| library + generated pages (D2) | D2 | icons.html, library css/js, forge/tools/site-seo.mjs and all it generates |
| content pages (D3) | D3 | guides/**, developers.html, ai.html, about.html, license.html, faq.html, pages css/js |
| launch, infra, CI, skill | launch owner | infra/**, scripts/**, .github/**, docs/LAUNCH.md, docs/COSTS.md, skills/**, site/skill/SKILL.md, AGENTS.md, CONTRIBUTING.md, CODE_OF_CONDUCT.md, SECURITY.md, LICENSE, CHANGELOG.md, .cursor/rules/** |
| frozen | nobody | forge/kernel/**, forge/lib/load.mjs, forge/tools/check.mjs, forge/tools/check-motion.mjs, forge/manifest.json, forge/CONTRACT.md, forge/MOTION.md (lead only) |
Deploy and release (maintainers)
- Site: push to
mainand.github/workflows/deploy-site.ymlrunsscripts/deploy.mjswith an OIDC role. It uploads changed files with per-class Cache-Control, updates the API Lambda (packages/mcp/dist/lambda.mjs, which must be a self-contained bundle wrapped byinfra/lambda/index.mjs), and invalidates changed paths. - npm: bump the root version (
withiconsVersion;v0.1.0is already tagged, so the next release is 0.2.0), build, then tagvX.Y.Z..github/workflows/release.ymlpublishes all packages in lockstep,@withicons/motionincluded (Trusted Publishing + provenance;scripts/publish.mjsfails if one is missing). Seedocs/LAUNCH.md. - The API Lambda must never answer with HTTP 403: CloudFront maps origin 403s to the site's
/404.html.
Where files are headingNew AGENTS.md files have more rules about keeping secrets out of the code, and fewer about code style.
Of the AGENTS.md files we read, the 28,693 first seen in the last six months, against the older ones: the kind of rule that gained most share, and the kind that lost most. About files like this in general, not this one, and an estimate, since a kind is a pattern in the words.
In this repository2 other files it gives its agents.
- .cursor/rules/with-icons.mdcCursor rule
- with-iconsSkill
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

