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

@richardmcquiston01/monogram-font-maker

v0.3.1

Published

Framework-agnostic TypeScript library that turns a set of monogram letter SVGs into an installable OTF/TTF font, so laser-template tools don't need every letter imported as a separate image.

Readme

Monogram Font Maker

  • NPM Package: @richardmcquiston01/monogram-font-maker
  • Author: Richard McQuiston
  • Website: https://richardmcquiston.com/

Overview

Framework agnostic TypeScript based NPM package for generating a Font from one or more sets of monogrammed letters. User specifies a single ZIP containing monogram SVG files, or individual SVG files for letters (A-Z). From the files, generate an installable OTF/TTF font where each letter is one of the monogram designs.

The point is to remove the manual, per-letter image import step from laser-template design workflows: build the font once, then just type a letter in your design software (LightBurn, Illustrator, CorelDRAW, Inkscape, ...) the same way you would with any other font. The generated font is also plain OpenType bytes, so it drops straight into browser-based tools — e.g. loading it with the FontFace API in maker-toolkit or maker-template-pro — without a server round trip.

Input format

Monogram letters must be supplied as SVG (<svg viewBox="..."><path d="..."/></svg>), one <path>-based design per letter. SVG was chosen over raster formats (PNG/JPG) because it already carries the clean vector outlines a font glyph needs — no lossy auto-tracing step, and no fidelity loss for laser-ready artwork. Each SVG needs a viewBox (or width/height) so its artwork can be scaled into the font's grid; transform attributes and non-<path> shapes (<circle>, <rect>, text, etc.) aren't resolved yet, so flatten artwork to paths before use. A transform on a painted path or its ancestors is rejected with an error. fill-rule="evenodd" compound paths (counters in A, B, O, ...) are supported as long as their contours don't cross each other. Limits: 1000 entries per ZIP/directory, 5 MiB per SVG, 50 MiB total.

Filenames

Every SVG is matched to a letter purely by its filename, wherever it comes from (a ZIP, a directory, or an explicit file list): the base name (the filename on its own, ignoring any folder path) must be exactly one character followed by .svg — A.svg, b.svg, 1.svg, and so on.

  • The .svg extension is matched case-insensitively (.svg, .SVG, .Svg all work).
  • The letter itself is case-sensitive: A.svg and a.svg produce two different glyphs (A and a), not one glyph used for both cases.
  • Anything that doesn't match this <one character>.svg shape — a README.md, a .gitignore, a folder of source files, a multi-character filename — is silently skipped rather than causing an error.
  • If two different files resolve to the same letter (e.g. two A.svg files in different folders of the same ZIP), that's treated as a mistake worth surfacing: it throws rather than silently picking one. Rename one of them.

Custom filename patterns

If your artwork isn't named <letter>.svg, pass a filenamePattern option to extractLettersFromZip, generateMonogramFontFromZip, loadLettersFromDirectory, loadLettersFromFiles, or writeMonogramFontFromZipFile describing where the letter sits in the filename instead. A pattern is a small template with two placeholder tokens and one wildcard:

| Token | Matches | | ---------- | ------------------------------------- | | {letter} | exactly one character, of any kind | | {number} | exactly one digit (0-9) | | * | any run of characters (e.g. a prefix) |

Everything else in the template is matched literally (case-insensitively), and the template must contain exactly one {letter} or {number} token — that's the character captured for the glyph.

// "butterfly_monogram_A.svg" -> letter "A"
const letters = await extractLettersFromZip(zipBytes, {
  filenamePattern: '*_monogram_{letter}.svg',
});

// "monogram_0.svg" .. "monogram_9.svg" -> digit glyphs "0".."9"
const digits = await extractLettersFromZip(zipBytes, {
  filenamePattern: '*_{number}.svg',
});

{number} isn't strictly necessary — {letter} also matches a digit — but it rejects filenames where that position isn't a digit, which catches a typo (monogram_A.svg sneaking into what should be an all-digits set) instead of silently turning it into a glyph named "A".

ZIP archive structure

extractLettersFromZip and generateMonogramFontFromZip accept a single ZIP archive containing one SVG per letter. There's no required folder layout — every entry in the archive is matched by its own filename (see above), not by its path, so files can sit at the archive root or be nested inside subfolders to any depth. Both of these are valid:

my-monogram.zip
├── A.svg
├── b.svg
└── C.svg
my-monogram.zip
└── MyFontKit/
    ├── letters/
    │   ├── A.svg
    │   └── b.svg
    └── README.txt        ← ignored, doesn't match "<letter>.svg"

An archive with no filename matching the <letter>.svg pattern anywhere in it throws, rather than silently producing an empty font.

Note for the Node-only loadLettersFromDirectory helper: unlike the ZIP reader, it does not recurse into subfolders — it only looks at files directly inside the directory you give it. Keep every letter's SVG flat in one folder when using it:

monogram-svgs/
├── A.svg
├── b.svg
└── C.svg

loadLettersFromFiles skips directory scanning entirely and takes an explicit list of paths; each path's own basename must still match the <letter>.svg pattern.

Output format

Fonts are generated as installable OTF/TTF — the format design software already knows how to install and use, and one that also loads fine as a web font.

Getting Started

Prerequisites

  • Node.js >= 18 (for the Node-only helpers under the ./node subpath; the core API also runs in any modern browser)
  • Monogram artwork as SVGs, one per letter, named A.svg, b.svg, etc. — see Filenames and ZIP archive structure above for the exact rules

Installation

npm install @richardmcquiston01/monogram-font-maker

Usage

The package has two entry points:

  • @richardmcquiston01/monogram-font-maker — the core API. Works in the browser or Node; only touches in-memory strings/bytes.
  • @richardmcquiston01/monogram-font-maker/node — adds filesystem convenience helpers (reading a directory of SVGs, writing the generated font to disk) on top of the core API, which it re-exports.

From an in-memory letter map (browser or Node)

import { generateMonogramFont } from '@richardmcquiston01/monogram-font-maker';

const fontBytes = generateMonogramFont(
  {
    A: '<svg viewBox="0 0 100 100"><path d="M10,90 L50,10 L90,90 Z"/></svg>',
    B: '<svg viewBox="0 0 100 100"><path d="M10,10 ..."/></svg>',
    // ...one entry per letter
  },
  { familyName: 'My Monogram' }
);
// fontBytes is an ArrayBuffer containing a complete OTF/TTF font.

From a single ZIP upload (e.g. a web app file input)

import { generateMonogramFontFromZip } from '@richardmcquiston01/monogram-font-maker';

const zipBytes = await file.arrayBuffer(); // `file` is a File from an <input type="file">
const fontBytes = await generateMonogramFontFromZip(zipBytes, {
  familyName: 'My Monogram',
});

// Use it immediately in the page, no server involved:
const fontFace = new FontFace('My Monogram', fontBytes);
await fontFace.load();
document.fonts.add(fontFace);

From files on disk (Node)

import {
  loadLettersFromDirectory,
  writeMonogramFont,
  writeMonogramFontFromZipFile,
} from '@richardmcquiston01/monogram-font-maker/node';

// One SVG per letter in a directory:
const letters = await loadLettersFromDirectory('./monogram-svgs');
await writeMonogramFont(
  letters,
  { familyName: 'My Monogram' },
  './MyMonogram.otf'
);

// Or straight from a ZIP file on disk:
await writeMonogramFontFromZipFile(
  './monogram-svgs.zip',
  { familyName: 'My Monogram' },
  './MyMonogram.otf'
);

Examples

See test/ for runnable examples of every entry point, including round-tripping a generated font back through opentype.js to confirm the glyphs come out correctly.

Buy Me a Coffee

If this app, code, or repository has helped you or someone you know, please consider donating. I appreciate any help to offset the costs of development and/or AI Credits.

Donate via Stripe, or scan:

Donate via Stripe

License

Apache 2

Copyright

(c)2026 Richard McQuiston. All rights reserved.