npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@bravobit/icon-font-generator

v2.0.0

Published

Generate SVG, TTF, WOFF, WOFF2 and EOT icon fonts from a folder of SVG icons.

Readme

@bravobit/icon-font-generator

Turn a folder of SVG icons into a ready to use icon font.

npm version npm license

Point it at a directory of .svg files and it writes SVG, TTF, WOFF, WOFF2 and EOT fonts. Every icon is reachable both by its code point and by its name, so you can use either content: "\e000" or data-icon="my-icon" in CSS.

Requirements

Node.js 24.14.0 or newer. The package is ESM only.

Installation

npm install --save-dev @bravobit/icon-font-generator

Or run it without installing:

npx @bravobit/icon-font-generator --input icons --output dist --name my-icons

Command line

icon-font-generator --input icons --output dist --name my-icons

| Option | Alt | Description | Default | | ----------- | ---- | -------------------------------------------------------------------------------------- | --------- | | --input | -i | Directory containing the .svg icons. Required. | – | | --output | -o | Directory the font files are written to. Created when it does not exist. Required. | – | | --name | -n | Font family name and output file name. | default | | --type | -t | Format to generate. Repeat the flag to pick several. | all | | --quiet | -q | Suppress progress and warnings; only print the generated paths. | off | | --help | -h | Show the help text. | – | | --version | -v | Show the version. | – |

Relative --input and --output paths resolve against the current working directory; absolute paths are used as given.

Examples

Generate every format:

icon-font-generator -i icons -o dist -n my-icons

Generate only the two formats a modern browser needs:

icon-font-generator -i icons -o dist -n my-icons -t woff2 -t woff

Collect the generated paths in a build script:

files=$(icon-font-generator -i icons -o dist -n my-icons --quiet)

Output formats

| Format | File | Notes | | ------- | -------------- | ------------------------------------------------------------------------ | | svg | <name>.svg | SVG font. The source every other format is built from. | | ttf | <name>.ttf | TrueType. | | woff | <name>.woff | Web Open Font Format. | | woff2 | <name>.woff2 | Web Open Font Format 2. Smallest, and all you need for current browsers. | | eot | <name>.eot | Embedded OpenType, only relevant for legacy Internet Explorer. |

The paths are printed to stdout in the order the formats were requested. Progress, warnings and errors go to stderr, so the output stays usable in a pipeline. Colour is dropped automatically when stderr is not a terminal or when NO_COLOR is set.

Exit codes

| Code | Meaning | | ---- | --------------------------------------------------------------------- | | 0 | The font was generated. | | 1 | The font could not be generated (missing input, unparseable icon, …). | | 2 | The command line was used incorrectly (unknown flag, missing option). |

Node API

import iconFontGenerator from '@bravobit/icon-font-generator';

const paths = await iconFontGenerator({
  input: 'icons',
  output: 'dist',
  name: 'my-icons',
  types: ['woff2', 'woff'],
});

console.log(paths); // ['/abs/path/dist/my-icons.woff2', '/abs/path/dist/my-icons.woff']

| Option | Description | Default | | ------------ | ---------------------------------------------------------------- | ---------------------------------------- | | input | Directory containing the .svg icons. Required. | – | | output | Directory the font files are written to. Required. | – | | name | Font family name and output file name. | 'default' | | types | Formats to generate. | ['svg', 'ttf', 'woff', 'woff2', 'eot'] | | onProgress | Called with progress messages. | – | | onWarning | Called for non-fatal problems, such as non-SVG files in input. | – |

Resolves with the absolute paths of the written files, in the order the formats were requested.

Error handling

Every problem the generator detects itself is thrown as an IconFontGeneratorError with a stable code:

import iconFontGenerator, {isIconFontGeneratorError} from '@bravobit/icon-font-generator';

try {
  await iconFontGenerator({input: 'icons', output: 'dist'});
} catch (error) {
  if (isIconFontGeneratorError(error) && error.code === 'NO_ICONS') {
    // ...
  }
}

| Code | Cause | | ------------------------ | ----------------------------------------------------------- | | INVALID_OPTIONS | Missing or malformed option, or an unknown format. | | INPUT_NOT_FOUND | The input directory does not exist. | | INPUT_NOT_A_DIRECTORY | The input path points at a file. | | INPUT_UNREADABLE | The input directory could not be read. | | NO_ICONS | The input directory contains no .svg files. | | TOO_MANY_ICONS | More icons than fit in the Unicode Private Use Area (6400). | | DUPLICATE_LIGATURE | Two icon names collapse onto the same ligature. | | INVALID_SVG | An icon is empty, unreadable or not an SVG. | | FONT_GENERATION_FAILED | A font encoder rejected the input. | | OUTPUT_NOT_WRITABLE | The output directory or a font file could not be written. |

TypeScript declarations ship with the package; no @types install is needed.

How icons become glyphs

  1. Every .svg file in input is read, sorted by file name and optimised with SVGO. Files are sorted so the code points below are identical on every machine.
  2. Each icon gets the next code point in the Unicode Private Use Area, starting at U+E000.
  3. Each icon also gets a ligature based on its file name, with hyphens replaced by underscores (arrow-left.svg becomes arrow_left).
  4. The glyphs are written into an SVG font, which is converted to the remaining formats.

Consequences worth knowing:

  • Non-SVG files in the input directory are skipped with a warning. Entries whose name starts with a dot are skipped without one, unless they end in .svg.
  • Adding an icon in the middle of the alphabet shifts the code points of the icons after it. Reference icons by their ligature if you want names that survive a rebuild.
  • arrow-left.svg and arrow_left.svg cannot live in the same font, because both produce the ligature arrow_left. This is reported as an error instead of silently dropping one of them.
  • Generated TTF, WOFF, WOFF2 and EOT files embed a build timestamp, so they differ between runs even when the icons did not change. The SVG font is byte-for-byte reproducible.

Using the font

@font-face {
  font-weight: normal;
  font-display: block;
  font-family: 'my-icons';
  src:
    url('my-icons.woff2') format('woff2'),
    url('my-icons.woff') format('woff'),
    url('my-icons.ttf') format('truetype');
}

.icon-font::before {
  display: flex;
  direction: ltr;
  line-height: 1;
  width: inherit;
  height: inherit;
  word-wrap: normal;
  font-size: inherit;
  font-style: normal;
  font-weight: normal;
  white-space: nowrap;
  text-transform: none;
  letter-spacing: normal;
  vertical-align: middle;
  content: attr(data-icon);
  font-family: 'my-icons';
  font-feature-settings: 'liga';
  text-rendering: optimizeLegibility;
  -moz-osx-font-smoothing: grayscale;
  -webkit-font-smoothing: antialiased;
}

Because content reads the data-icon attribute, the icon name goes straight into the HTML:

<div class="icon-font" data-icon="arrow_left"></div>

Add the EOT and SVG sources to the src list as well if you still support Internet Explorer.

Upgrading from 1.x

The generated fonts are unchanged, but the packaging is not:

  • The package is ESM only. const generator = require('@bravobit/icon-font-generator') no longer returns the function. Use import generator from '@bravobit/icon-font-generator', or require('@bravobit/icon-font-generator').default.
  • Node 24.14.0 or newer is required.
  • Failures now exit with a non-zero status. 1.x exited 0 on every error, so pipelines silently passed. Scripts that relied on that need to handle the new exit codes.
  • Errors and progress moved to stderr. stdout only carries the generated file paths.
  • Absolute --input / --output paths now work. 1.x joined them onto the working directory, which created directories such as ./tmp/out for --output /tmp/out.
  • Icons are sorted before code points are assigned, so a rebuild yields the same code points on every platform. On filesystems that do not return directory entries in alphabetical order, the assigned code points may differ from 1.x.
  • Input that used to pass silently now fails: an empty input directory, an unparseable or non-SVG icon, and two icons that collapse onto the same ligature.

All command names, flags, option names, default values and output file names are unchanged.

Development

npm install
npm run build       # bundle src/ to dist/ with tsdown
npm test            # build, then run the test suite
npm run lint        # eslint, including type-aware rules
npm run lint:fix    # eslint --fix
npm run typecheck   # tsc over src/ and test/
npm run check       # build, lint, typecheck and test

src/ is laid out along the pipeline:

src/
  index.ts        public exports
  generator.ts    the pipeline
  options.ts      option validation
  output.ts       writing the files
  icons/          reading, optimising and naming the source icons
  fonts/          one encoder per output format
  cli/            commander wiring, exit codes and stdout/stderr

License

Distributed under the MIT License. See LICENSE for more information.