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

@docx-editor.dev/fonts

v2.21.0

Published

Open-licensed substitutes for common Word fonts, packaged for @docx-editor.dev shaped measurement.

Readme

@docx-editor.dev/fonts

Open-licensed substitutes for common Word fonts, packaged for shaped (HarfBuzz) measurement in the docx-editor engine.

| Word font | Substitute | License | | --------------- | ----------------- | ----------------- | | Calibri | Carlito | SIL OFL | | Cambria | Caladea | SIL OFL | | Times New Roman | Liberation Serif | SIL OFL | | Arial | Liberation Sans | SIL OFL | | Courier New | Liberation Mono | SIL OFL | | Century Gothic | TeX Gyre Adventor | GUST Font License |

The first five substitutes target matching advance widths for the glyphs they cover. TeX Gyre Adventor is slightly narrower than Century Gothic; the measured difference stays within 1% in bun run check:font-width-fidelity. Kerning and glyph differences can still change line breaks. For the original glyphs, supply licensed font bytes through loadFonts() from @docx-editor.dev/core/editor.

Packaged faces do not cover every script. Liberation Sans has no Arabic glyphs. The editor keeps native family fallback available for missing glyphs. Exact metrics still depend on the font available for that script.

loadDefaultFonts() and defaultFonts() load the five families Word applies to a document by default. Century Gothic is not one of them and adds about 709 KB, so it is opt-in: pass families: ALL_WORD_DEFAULT_FAMILIES, or use googleFonts(), which serves it from these same packaged bytes only when a document names it.

Usage

Use packagedFonts() to load document fonts on demand. In React, useFonts() keeps the resolver identity stable so rerenders do not rebuild the editor.

import { packagedFonts } from '@docx-editor.dev/fonts';
import { DocxEditor, useFonts } from '@docx-editor.dev/react';

function Editor({ bytes }: { bytes: Uint8Array }) {
  const fonts = useFonts(packagedFonts());
  return <DocxEditor document={bytes} fonts={fonts} />;
}

To add Google Fonts, import its resolver and pass it after packagedFonts():

import { googleFonts } from '@docx-editor.dev/fonts/google';

const fonts = useFonts(packagedFonts(), googleFonts());

Call useFonts() inside a component.

To load all 20 faces of the five default families before opening a document, use defaultFonts(). This loads 7.4 MB and avoids repagination when fonts arrive:

import { createDocxEditor } from '@docx-editor.dev/core/editor';
import { defaultFonts } from '@docx-editor.dev/fonts';

const fonts = await defaultFonts(); // Add families to load a subset.
const editor = createDocxEditor({ document: bytes, fonts });

Relocate packaged fonts in Node or Bun

For a single-file executable, copy the contents of the fonts package's assets/ directory into a dedicated directory. Set DOCX_EDITOR_FONT_ASSET_ROOT before starting the process:

DOCX_EDITOR_FONT_ASSET_ROOT=/opt/my-app/fonts ./my-app

The directory must contain the packaged .ttf and .otf files with their original names. Use an absolute filesystem path or a file: URL. Relative paths, filesystem roots, and non-file URLs are ignored.

The package reads this setting when its module loads. Setting it after importing the package does not relocate the fonts. The setting changes packaged asset locations; it does not register custom fonts or enable a font source. Configure packagedFonts() or defaultFonts() as usual. Browser builds use their bundled asset URLs.

Custom fonts for the editor

Use customFonts() to supply brand fonts or licensed Word fonts to the editor. Put it first so your supplied faces take precedence.

import { customFonts } from '@docx-editor.dev/core/editor';
import { packagedFonts } from '@docx-editor.dev/fonts';
import { googleFonts } from '@docx-editor.dev/fonts/google';
import { DocxEditor, useFonts } from '@docx-editor.dev/react';

function Editor({ bytes }: { bytes: Uint8Array }) {
  const fonts = useFonts(
    customFonts({
      sources: [
        {
          url: '/fonts/AcmeSans-Regular.ttf',
          family: 'Acme Sans',
          weight: 400,
          style: 'normal',
        },
        {
          url: '/fonts/AcmeSans-Bold.ttf',
          family: 'Acme Sans',
          weight: 700,
          style: 'normal',
        },
      ],
      onFailure: (failure) => console.warn(failure.request.family, failure.reason),
    }),
    packagedFonts(),
    googleFonts()
  );
  return <DocxEditor document={bytes} fonts={fonts} />;
}

customFonts() loads all configured faces when the editor resolves its fonts. Creating the resolver does not fetch files. It skips faces supplied by earlier sources, matching the family name without case sensitivity and matching weight and style.

Loaded fonts appear in the picker, including in blank documents. Select a font to apply it to document text.

The helper uses loadFonts for validation and caching. onFailure receives each failed face and defaults to console.warn. Cancellation does not trigger onFailure. Core registers the supplied bytes under private names, without changing fonts elsewhere in your app.

loadFonts() from Core remains the lower-level eager loader. It starts loading every listed source when called and returns validated bytes with a typed failures list.

Font registration

defaultFonts() and packagedFonts() supply font bytes for the editor. Core registers these bytes under private font names. Your app's header and sidebar keep their existing fonts. Native fonts remain available for glyphs missing from the substitutes.

Upgrade from page-wide registration

Before 2.18.0, loaders could register substitutes under public names such as Arial. From 2.18.0, font loaders supply bytes for private editor registration only. If you already pass packagedFonts() or defaultFonts() through the editor's fonts option, keep that configuration.

The packagedFonts option install is deprecated and ignored, including true. Remove it while keeping your other loader options:

- fonts: packagedFonts({ install: true, onFailure })
+ fonts: packagedFonts({ onFailure })

installDefaultFontFaces() is deprecated. It does nothing and resolves to 0, without fetching or registering fonts. Remove its calls and supply packagedFonts() or defaultFonts() through the editor's fonts option instead. defaultFonts() has no install option. loadDefaultFonts() remains bytes-only.

If surrounding app text relied on these public fonts, configure those fonts separately with your app's CSS or font loader. Check the fonts in your app's headers, sidebars, and other text after upgrading.

Importing the package does not fetch fonts. Configure a loader or resolver to enable them.

Font binaries ship as separate files (assets/*.ttf and assets/*.otf) fetched per requested family. Each face's sha256: hash is baked at packaging time (src/manifest.generated.ts) and CI-verified against the shipped bytes.

Google Fonts, on demand

@docx-editor.dev/fonts/google includes a font catalog without bundling its font files. It fetches fonts requested by the document or its default face.

import { googleFonts } from '@docx-editor.dev/fonts/google';
import { DocxEditor, useFonts } from '@docx-editor.dev/react';

function Editor({ bytes }: { bytes: Uint8Array }) {
  const fonts = useFonts(googleFonts());
  return <DocxEditor document={bytes} fonts={fonts} />;
}

The editor requests fonts on load and when edits or font selection introduce new families.

A document that uses Calibri loads Carlito, its metric-compatible substitute. The document's default face also counts as a request. Use allow to restrict the catalog.

Resolution checks these sources in order:

  1. Your substitute mappings, merged over the built-in substitutions.
  2. Packaged assets for Century Gothic, which needs no third-party request.
  3. A direct match in the Google Fonts catalog.

If no source matches, the editor keeps its fallback measurement. It does not infer width-compatible substitutes from the document's PANOSE font classification. Supply your own font bytes when you need a specific face.

Google Fonts requests disclose the requested families to the content delivery network. Use packagedFonts() for packaged assets, or restrict remote requests with googleFonts({ allow: ['Tinos', 'Lato'] }). When composed after another resolver, Google Fonts skips families whose faces are already loaded. A partially loaded family still requires its remaining faces.

Maintain the catalog

The generated catalog pins each face to an immutable google/fonts commit and a sha256: hash. Family names are lookup keys, never URL fragments. The catalog requires regular, bold, italic, and bold-italic static faces that pass validation. When upstream provides only variable fonts, the catalog can pin an earlier commit with static files. The shaper does not support variable font axes.

Run these commands from packages/fonts:

# Download fonts and regenerate the catalog and hashes.
bun run google:catalog

# Download catalog faces and verify their hashes.
bun run google:verify

From the repository root, run bun run check:google-catalog to check the committed catalog offline. CI runs the same check. bun run check:font-width-fidelity compares synthetic text measurements with font subsets embedded in Word PDF exports.

Licenses

The packaged fonts keep their licenses in licenses/. Carlito, Caladea, and Liberation use the SIL Open Font License. TeX Gyre Adventor uses the GUST Font License, which has no SPDX identifier of its own, so package.json names it LicenseRef-GUST-Font-License. Its operative terms are the LaTeX Project Public License 1.3c or, at your option, any later version; the one clause it adds on top asks you to rename a modified font, and says so as a request rather than a legal requirement. licenses/ carries both texts, because the GUST license states its terms by reference to the LPPL. The package code uses Apache-2.0.