The package is set up to ingest any icon set that ships as a folder of SVG files, one per icon, in one or more “variant” subfolders. Adding a new set is a config change plus running the codegen script.
The shape of an icon set
Source SVGs should look like this:
static/svg/<set-name>-<variant>/
<icon-name>-<variant>.svg
<another-icon>-<variant>.svg
... Phosphor uses phosphor-regular/, phosphor-light/, phosphor-fill/. Remix uses remixicons-line/, remixicons-fill/. Each file is a single SVG of one icon, with <svg viewBox="0 0 256 256"> and a few inner shapes.
If your set uses a different viewBox or layout, you’ll need to normalize before running codegen. A small script over the source folder is usually enough.
Step 1 - drop the SVGs in
Put the variant folders under static/svg/<your-set>-<variant>/:
static/svg/materialsymbols-fill/
static/svg/materialsymbols-line/ The folder name matters: it becomes both the variant id and the prefix used by the codegen script when stripping suffixes from filenames.
Step 2 - add an entry to SETS
Open scripts/generate.js and add an entry to the SETS array:
const SETS = [
// ... existing entries
{
name: 'materialsymbols',
variants: {
line: 'static/svg/materialsymbols-line',
fill: 'static/svg/materialsymbols-fill'
},
defaultVariant: 'line',
nameFromFile: (filename, variant) =>
filename.replace('.svg', '').replace(`-${variant}`, ''),
stripSuffix: {}
}
]; The fields:
name- used as the subpath (svelte-animated-icon/materialsymbols) and the directory undersrc/lib/.variants-{ variantId: 'path/from/project/root' }. The script reads SVGs from each.defaultVariant- which variant is selected when the user doesn’t passvariant={…}. Must be one of the keys invariants.nameFromFile(filename, variant)- turns a filename into the icon’s component name. For most sets, this strips the.svgextension and the-<variant>suffix.stripSuffix- extra suffixes to strip during generation. Phosphor uses{ fill: '-fill', light: '' }to handle names likeacorn-fill.svg; Remix needs nothing.
Step 3 - run the codegen
node scripts/generate.js The script:
- Reads SVGs from each variant directory.
- Matches icons by name across variants.
- Strips the
<svg>wrapper and any bounding<rect fill="none">from each. - Writes
src/lib/<name>/icons/<PascalName>.sveltewith the variants embedded and...restforwarded toAnimatedIcon. - Writes
src/lib/<name>/index.ts- the per-library barrel.
Generated components look identical to Phosphor’s. See Icon Components for the shape.
Step 4 - add the subpath to exports
Open package.json and add a new entry under exports:
{
"exports": {
".": { "types": "./dist/index.d.ts", "svelte": "./dist/index.js" },
"./phosphor": { "types": "./dist/phosphor/index.d.ts", "svelte": "./dist/phosphor/index.js" },
"./remix": { "types": "./dist/remix/index.d.ts", "svelte": "./dist/remix/index.js" },
"./flowbite": { "types": "./dist/flowbite/index.d.ts", "svelte": "./dist/flowbite/index.js" },
"./hero": { "types": "./dist/hero/index.d.ts", "svelte": "./dist/hero/index.js" },
"./ion": { "types": "./dist/ion/index.d.ts", "svelte": "./dist/ion/index.js" },
"./materialsymbols": { "types": "./dist/materialsymbols/index.d.ts", "svelte": "./dist/materialsymbols/index.js" }
}
} Now consumers can import { Whatever } from 'svelte-animated-icon/materialsymbols', and the bundler tree-shakes Material Symbols out of any app that doesn’t import it.
Step 5 - verify
Run the dev site:
pnpm dev and visit the library’s landing page (/materialsymbols if you followed the example above). You should see a grid of every generated icon, each animated on hover.
Naming gotchas
PascalCase component names.
nameFromFilereturns the raw stem -name_from_file.svgbecomes the componentName_from_file, notNameFromFile. If your set uses snake_case, convert insidenameFromFile:nameFromFile: (filename, variant) => { const stem = filename.replace('.svg', '').replace(`-${variant}`, ''); return stem .split(/[-_]/) .map((s) => s[0].toUpperCase() + s.slice(1)) .join(''); }Variant suffix collisions. If your icons are named
gear-line.svgandgear-fill.svg, the strip logic handles them. If they’re namedgear.svg(no suffix), the script can’t match them across variants - add a suffix in your source files or changenameFromFile.Component name collisions across sets. Two libraries can ship
Gear(Phosphor does, Remix will). Each lives in its own subpath and namespace, so they don’t collide on disk - only on import in your own file. Alias the import:<script> import { Gear as PhosphorGear } from 'svelte-animated-icon/phosphor'; import { Gear as MaterialGear } from 'svelte-animated-icon/materialsymbols'; </script>
If the icon set doesn’t fit the model
The codegen script handles the common case - variant folders with matching icon names. If your set uses a single folder with no variant split, or ships icons in a different layout, the script will need a tweak. Fork it, change the read step, keep the rest. The output shape is what matters.
See Codegen Pipeline for the full walkthrough.