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 🙏

© 2025 – Pkg Stats / Ryan Hefner

unglyph

v0.0.3

Published

Unified font glyph manipulation library with simple API for parsing, creating, and modifying fonts

Readme

unglyph 🔠

npm version npm downloads npm license Contributor Covenant

A unified font glyph manipulation library with simple API for parsing, creating, and modifying fonts.

Built on top of proven font libraries like fontkit and opentype.js, unglyph provides a clean, type-safe interface for font operations while maintaining simplicity and ease of use.

✨ Features

  • 🔍 Font Parsing: Parse TTF, OTF, WOFF, and WOFF2 fonts using fontkit
  • 🔧 Font Creation: Create custom fonts from glyph data using opentype.js
  • 📝 Glyph Management: Comprehensive CRUD operations with batch processing
  • 🎨 SVG Rendering: Render glyphs to SVG with customizable styles
  • 📦 TypeScript: Full TypeScript support with comprehensive type definitions
  • 🏭 Factory Pattern: Consistent factory functions for easy instantiation
  • 🔄 Format Support: Support for major font formats (TTF, OTF, WOFF, WOFF2)
  • 🎯 Simple API: Clean, intuitive API following KISS principles

📥 Installation

# Using npm
npm install unglyph

# Using yarn
yarn add unglyph

# Using pnpm
pnpm add unglyph

🚀 Basic Usage

Font Parsing

import { parseFont, type FontData } from "unglyph";

// Parse font file
const font: FontData = parseFont(fontBuffer);

console.log(`Font: ${font.familyName}`);
console.log(`Format: ${font.format}`);
console.log(`Units per Em: ${font.unitsPerEm}`);

// Access glyph data
const glyphA = font.glyphs.find((g) => g.unicode === 65);
console.log(
  `Glyph A: ${glyphA?.name}, index: ${glyphA?.index}, advanceWidth: ${glyphA?.advanceWidth}`,
);

Font Creation

import {
  createFont,
  createGlyphManager,
  generateFont,
  type FontOptions,
  type FontData,
  type GlyphData,
  type PathCommand,
} from "unglyph";

// Create glyph manager
const manager = createGlyphManager();

// Add custom glyphs
const glyphA: GlyphData = {
  index: 1,
  unicode: 65, // 'A'
  name: "A",
  advanceWidth: 600,
  path: {
    commands: [
      { type: "move", x: 300, y: 0 },
      { type: "line", x: 100, y: 700 },
      { type: "line", x: 500, y: 700 },
      { type: "line", x: 300, y: 0 },
    ] as PathCommand[],
  },
};

manager.add(glyphA);

// Create FontData
const fontOptions: FontOptions = {
  familyName: "MyFont",
  styleName: "Regular",
  unitsPerEm: 1000,
  ascender: 800,
  descender: -200,
};

const fontData: FontData = createFont(manager.list(), fontOptions);

// Generate font file (returns Uint8Array)
const fontBytes = generateFont(fontData, { format: "otf" });
// Save to file
fs.writeFileSync("myfont.otf", fontBytes);

Glyph Management

import { GlyphManager, createGlyphManager } from "unglyph";

// Create manager with initial glyphs
const manager = createGlyphManager(initialGlyphs);

// CRUD operations
manager.add(newGlyph);
const glyph = manager.get(65);
const exists = manager.has(65);
const removed = manager.remove(65);

// Batch operations
manager.addGlyphs([glyph1, glyph2, glyph3]);
manager.batch([
  { type: "add", glyph: newGlyph },
  { type: "update", index: 2, updates: { advanceWidth: 650 } },
  { type: "remove", index: 3 },
]);

// Find operations
const glyphA = manager.findByUnicode("A");
const capitalLetters = manager.find((g) => g.unicode >= 65 && g.unicode <= 90);
const allGlyphs = manager.list();
console.log(`Total glyphs: ${manager.count()}`);

SVG Rendering

import { renderGlyph } from "unglyph";

// Render glyph to SVG
const svg = renderGlyph(glyph, {
  size: 100,
  color: "#2563eb",
  backgroundColor: "white",
  padding: 20,
  strokeColor: "#1e40af",
  strokeWidth: 1,
});

console.log(svg); // Complete SVG string
// Save to file
fs.writeFileSync("glyph.svg", svg);

🔧 Advanced Usage

Font Pipeline Example

import {
  parseFont,
  createGlyphManager,
  createFont,
  generateFont,
  renderGlyph,
  type FontData,
} from "unglyph";

async function processFont(inputBuffer: ArrayBuffer) {
  // 1. Parse existing font
  const originalFont: FontData = parseFont(inputBuffer);

  // 2. Create manager and copy glyphs
  const manager = createGlyphManager(originalFont.glyphs);

  // 3. Modify glyphs (e.g., make all letters bold)
  const modifiedGlyphs = manager.list().map((glyph) => ({
    ...glyph,
    advanceWidth: glyph.advanceWidth * 1.2, // 20% wider for bold
    path: {
      ...glyph.path,
      // Add stroke offset for bold effect
      commands: addBoldOffset(glyph.path.commands),
    },
  }));

  // 4. Create new font data with modifications
  const newFontData: FontData = createFont(modifiedGlyphs, {
    familyName: `${originalFont.familyName} Bold`,
    styleName: "Bold",
    unitsPerEm: 1000,
    ascender: 800,
    descender: -200,
  });

  // 5. Generate font file
  return generateFont(newFontData, { format: "otf" });
}

Custom Font Generation

import { createGlyphManager, createFont, type GlyphData } from "unglyph";

function createIconFont(
  icons: Array<{ name: string; unicode: number; path: string }>,
) {
  const manager = createGlyphManager();

  // Add icons as glyphs
  icons.forEach((icon) => {
    const glyph: GlyphData = {
      index: icon.unicode,
      unicode: icon.unicode,
      name: icon.name,
      advanceWidth: 1000,
      path: {
        commands: parseSVGPath(icon.path), // Convert SVG path to commands
      },
    };
    manager.add(glyph);
  });

  // Create icon font data
  const fontData = createFont(manager.list(), {
    familyName: "Custom Icons",
    styleName: "Regular",
    unitsPerEm: 1000,
    ascender: 850,
    descender: -150,
  });

  // Generate icon font file
  return generateFont(fontData, { format: "otf" });
}

📚 API Reference

Core Functions

parseFont(input: FontInput): FontData

Parse font file and extract glyph information. Returns unified FontData structure.

createFont(glyphs: GlyphData[], options: FontOptions): FontData

Create font data from glyph data array.

generateFont(fontData: FontData, options?: FontGenerateOptions): Uint8Array

Generate font file from FontData. Returns file buffer (OTF, TTF, etc.).

renderGlyph(glyph: GlyphData, options: RenderOptions): string

Render single glyph to SVG string.

createGlyphManager(initialGlyphs?: GlyphData[]): GlyphManager

Create new glyph manager instance.

Classes

GlyphManager

Manage font glyphs with CRUD operations:

  • add(glyph: GlyphData): void - Add glyph
  • get(unicode: string | number): GlyphData | undefined - Get glyph
  • update(unicode, updates): boolean - Update glyph
  • remove(unicode): boolean - Remove glyph
  • list(): GlyphData[] - Get all glyphs
  • findByUnicode(unicode): GlyphData | undefined - Find by Unicode
  • addGlyphs(glyphs: GlyphData[]): void - Batch add
  • batch(operations: GlyphOperation[]): void - Batch operations
  • count(): number - Get glyph count
  • isEmpty(): boolean - Check if empty

Type Definitions

GlyphData

interface GlyphData {
  index: number; // Glyph index in font
  unicode: string | number; // Unicode character or code point
  name?: string; // Optional glyph name
  advanceWidth: number; // Advance width
  leftSideBearing?: number; // Left side bearing
  rightSideBearing?: number; // Right side bearing
  path: PathData; // Path commands
}

FontData

interface FontData {
  familyName?: string; // Font family name
  format?: string; // Font format (TTF, OTF, etc.)
  unitsPerEm?: number; // Units per em
  ascent?: number; // Ascender height
  descent?: number; // Descender depth
  lineGap?: number; // Line gap
  capHeight?: number; // Cap height
  xHeight?: number; // X-height
  glyphs: GlyphData[]; // Array of glyphs
}

FontGenerateOptions

interface FontGenerateOptions {
  format?: "ttf" | "otf" | "woff" | "woff2"; // Export format (default: "otf")
  familyName?: string; // Font family name (uses font's name if not provided)
  styleName?: string; // Style name (default: "Regular")
  unitsPerEm?: number; // Units per em (uses font's value if not provided)
  ascender?: number; // Ascender height (uses font's value if not provided)
  descender?: number; // Descender depth (uses font's value if not provided)
}

FontOptions

interface FontOptions {
  familyName: string; // Font family name
  styleName?: string; // Style name
  unitsPerEm?: number; // Units per em (default: 1000)
  ascender?: number; // Ascender height (default: 800)
  descender?: number; // Descender depth (default: -200)
  weight?: number; // Font weight (100-900)
  italic?: boolean; // Italic style
}

RenderOptions

interface RenderOptions {
  size: number; // Size in pixels
  color?: string; // Fill color
  backgroundColor?: string; // Background color
  padding?: number; // Padding
  strokeColor?: string; // Stroke color
  strokeWidth?: number; // Stroke width
}

🏗️ Architecture

unglyph is built on top of proven font libraries:

  • fontkit: Advanced font parsing with support for multiple font formats
  • opentype.js: Font creation and OpenType/TrueType manipulation
  • undio: Universal I/O handling for various data types

The library provides a unified, type-safe API that abstracts away the complexity of these underlying libraries while maintaining their power and flexibility.

📦 Package Structure

packages/unglyph/
├── src/
│   ├── types.ts          # TypeScript type definitions
│   ├── parser.ts          # Font parsing functionality
│   ├── creator.ts         # Font creation functionality
│   ├── renderer.ts        # SVG rendering functionality
│   ├── manager.ts         # Glyph manager class
│   └── index.ts           # Main exports
├── dist/                  # Built distribution files
├── package.json           # Package configuration
└── README.md              # This file

🔗 Related

  • fontkit - Advanced font engine for Node and browser
  • opentype.js - OpenType and TrueType font parser and writer
  • undio - Universal I/O utility library

📄 License

MIT © By Sages