fonteditor-core

Parse, write, and convert TTF, WOFF, WOFF2, EOT, SVG, and OTF fonts in Node.js and the browser.

Library
npm
v2.6.3
386stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
48/100Fair
Development Activity20
Maintenance20
Community72
Maturity60
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
70/100Good
Architecture75
Code Quality68
Innovation72
Learning Curve65

fonteditor-core is the parsing and conversion engine behind the FontEditor project, giving JavaScript code direct read/write access to the major sfnt-family font formats: TTF, WOFF, WOFF2, EOT, SVG, and OTF (read-only). It normalizes every format into a single in-memory ttfObject representation, so glyph-level operations — subsetting by unicode range, compound-to-simple glyph flattening, glyph search, sorting, and merging two fonts together — work identically regardless of which format the font was read from or will be written to.

Because WOFF2 uses Brotli compression, the library bundles a WebAssembly build of Google’s own woff2 C++ codec rather than reimplementing the compression in JavaScript, which keeps woff2 encode/decode correct without sacrificing browser compatibility. The package ships dual CommonJS/ESM builds plus hand-authored TypeScript definitions, and is commonly used inside icon-font generators, font subsetting tools, and font preview/editing UIs.

What You Get

  • A single createFont(buffer, {type}) entry point that reads TTF, WOFF, WOFF2, EOT, SVG, or OTF into one normalized glyph object model
  • Format conversion in both directions (ttf2woff, woff2ttf, ttf2eot, eot2ttf, ttf2svg, svg2ttfobject, ttftowoff2, woff2tottf) plus base64 export helpers for each format
  • Glyph-level editing on the loaded font: unicode/name/custom-filter glyph search (find), compound-to-simple glyph flattening, glyph sorting, and merging one font’s glyphs into another
  • A WASM-backed woff2 codec (bundled Google woff2 build) so WOFF2 encode/decode works in both Node.js and the browser without a native binary
  • Hand-maintained TypeScript declarations (index.d.ts) and a dedicated ESM_USAGE.md guide for Vite/Webpack/Next.js/Rollup consumers

Common Use Cases

  • Building an icon-font pipeline that subsets an SVG icon set into a webfont (ttf/woff/woff2/eot) for a design system
  • Converting user-uploaded fonts between formats server-side (e.g. TTF/OTF to WOFF2) for optimized web delivery
  • Powering an in-browser font preview or glyph-editing tool that needs to read arbitrary font uploads and re-export them
  • Merging glyphs from multiple font files into a single custom font, such as combining a base typeface with a supplemental symbol set

Under The Hood

Architecture The Font class (src/ttf/font.js) is the public facade: its read/write methods dispatch to format-specific converters (TTFReader for ttf, otf2ttfobject for otf, eot2ttf+TTFReader for eot, woff2ttf/woff2tottf for woff/woff2, svg2ttfobject for svg) and normalize every input into one internal ttfObject graph. Glyph-level operations are delegated to a separate TTF helper class (src/ttf/ttf.js, ~877 lines) that implements findGlyf, sortGlyf, mergeGlyf, and compound2simple against that same canonical structure, keeping the Font facade thin. Low-level binary I/O is isolated into Reader/Writer classes (src/ttf/reader.js, writer.js) built on DataView, which every format-specific parser and writer builds on. The hardest format, WOFF2, is deliberately kept out of this pure-JS pipeline entirely: it’s a separate Emscripten-compiled WebAssembly module (woff2/index.js wrapping woff2.wasm) that must be explicitly initialized via woff2.init() before use, decoupling the C++ codec’s lifecycle from the rest of the library.

Tech Stack The source is plain ES2015+ JavaScript, transpiled with Babel (@babel/preset-env, @babel/cli) into dual CommonJS (lib/main.js) and ESM (lib/main.esm.js) builds wired through package.json’s exports map; TypeScript consumers get static types from a hand-maintained index.d.ts rather than from compiling TypeScript source. The only runtime dependency is @xmldom/xmldom, used for parsing SVG documents on the SVG-to-glyph path. The WOFF2 codec is a pre-built Emscripten/WASM artifact checked directly into the repo rather than compiled at install time. The demo app runs on webpack 4’s dev server, and the package builds via a plain babel src --out-dir lib step.

Code Quality Testing is unusually thorough for a library this size: three separate mocha suites cover the browser build (test/spec, run via @babel/register), the built Node output (test/node-spec, covering font read/write round-trips, otf/svg conversion, and glyph adjustment), and a dedicated ESM integration test plus a standalone TypeScript example project (test/example) that exercises the published type definitions end-to-end. Errors are raised explicitly (throw new Error('not support font type ...')) rather than swallowed, and a dedicated src/ttf/error.js module centralizes error messages. ESLint is configured project-wide with a husky pre-commit hook running lint-staged. No GitHub Actions CI workflow is present in the repository, so these test suites appear to run only locally/on release rather than being enforced automatically on every push.

API Design The public surface is intentionally small: one createFont(buffer, options) entry point handles every input format via a type discriminator, and font.write()/font.toBase64() mirror that same options shape for output, so the mental model transfers across all six supported formats. The one asymmetry is WOFF2, which requires an explicit async woff2.init() call before first use — a reasonable but easy-to-miss extra step that the README calls out directly. Naming is consistent and guessable (ttf2woff, woff2tottf, svg2ttfobject), and both the README and a dedicated ESM_USAGE.md give copy-pasteable examples for CommonJS, ESM, and TypeScript consumers, keeping the ramp-up cost low despite the format-conversion domain being inherently fiddly.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search