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

@lyubomir-popov/baseline-nudge-generator

v1.5.0

Published

Automatic font metrics reader that generates baseline grid nudges for CSS typography systems

Readme

@lyubomir-popov/baseline-nudge-generator

Automatic font metrics reader that generates baseline grid nudges for CSS typography. Extracts precise font metrics from webfont files and calculates the exact CSS nudges needed to align text to a baseline grid.

Quick Start

  1. Install the package:

    npm install -g @lyubomir-popov/baseline-nudge-generator
  2. Set up your project (one command does it all):

    baseline-nudges setup
  3. Generate tokens and HTML:

    baseline-nudges generate config/typography-config.json
    baseline-nudges generate config/typography-config.json custom-output
  4. View the result:

    open dist/index.html
    # Or if you specified a custom output directory:
    open custom-output/index.html

What's New in This Version

  • 🎨 Multi-font support: Use multiple font families (sans, serif) with different nudge calculations per element
  • ⚖️ Per-element font styling: Specify fontFamily, fontWeight, and fontStyle for each element
  • 🔧 Fixed critical baseline calculation bug: Corrected lineGap distribution formula for accurate baseline alignment
  • 📏 Improved baseline offset calculation: Now properly distributes lineGap above and below text baseline
  • 🎨 Complete typescale support: Full h1-h6 and paragraph element configuration
  • 🧹 Production-ready code: Removed debug outputs, added ESLint, improved error handling
  • 🔤 Enhanced font name extraction: Robust font name detection from various font formats
  • 📝 Better HTML examples: Improved sample text format and visual presentation

How It Works

The tool uses the corrected baseline calculation formula:

baselineOffsetRem = leadingRem/2 + ascenderRem + (lineGapRem/2)

This ensures that lineGap is properly distributed above and below the text baseline, fixing previous calculation errors that caused misalignment.

Configuration Format

The typography-config.json file defines your typography scale and baseline grid settings. Two formats are supported:

New Multi-Font Format (Recommended)

{
  "baselineUnit": 0.5,
  "fontFiles": [
    {
      "family": "sans",
      "path": "../fonts/IBMPlexSans-Regular.woff"
    },
    {
      "family": "serif",
      "path": "../fonts/IBMPlexSerif-Regular.woff"
    }
  ],
  "elements": [
    {
      "identifier": "h1",
      "fontSize": 5.25,
      "lineHeight": 10,
      "spaceAfter": 3,
      "fontFamily": "sans",
      "fontWeight": 700,
      "fontStyle": "normal"
    },
    {
      "identifier": "p",
      "fontSize": 1,
      "lineHeight": 3,
      "spaceAfter": 3,
      "fontFamily": "serif",
      "fontWeight": 400,
      "fontStyle": "normal"
    }
  ]
}

Legacy Single-Font Format

{
  "baselineUnit": 0.5,
  "fontFile": "../fonts/FiraSans-Regular.ttf",
  "elements": [
    {
      "identifier": "h1",
      "fontSize": 5.25,
      "lineHeight": 10,
      "spaceAfter": 3
    },
    {
      "identifier": "p",
      "fontSize": 1,
      "lineHeight": 3,
      "spaceAfter": 3
    }
  ]
}

Configuration Properties

Multi-Font Format

  • baselineUnit (number): The baseline grid unit in rem. Common values are 0.5rem or 0.25rem.
  • fontFiles (array): Array of font file definitions with family and path properties.
  • elements (array): Array of typography elements to generate.

Legacy Single-Font Format

  • baselineUnit (number): The baseline grid unit in rem. Common values are 0.5rem or 0.25rem.
  • fontFile (string): Relative path to your font file from the config directory.
  • elements (array): Array of typography elements to generate.

Element Properties

Each element in the elements array has these properties:

Required Properties

  • identifier (string): Element identifier or CSS class name (e.g., "h1", "p", "caption", ".heading-large").
  • fontSize (number): Font size in rem units (e.g., 2.5 = 2.5rem).
  • lineHeight (number): Number of baseline units for line height, must be a multiple of 0.25 (e.g., 5 = 5 × 0.5rem = 2.5rem, 5.25 = 5.25 × 0.5rem = 2.625rem).
  • spaceAfter (number): Number of baseline units for space after the element, must be 0 or a multiple of 0.25 (e.g., 0 = no space, 4 = 4 × 0.5rem = 2rem, 4.25 = 4.25 × 0.5rem = 2.125rem). Note: If spaceAfter is set to 0, it will be treated as 0.5 baseline units for spacing purposes. The actual CSS margin-bottom will be adjusted by subtracting the baseline nudge (padding-top) to ensure that nudge + spaceAfter equals an exact multiple of the baseline unit.

Optional Properties (Multi-Font Format Only)

  • fontFamily (string): Font family to use (e.g., "sans", "serif"). Defaults to "sans" if not specified.
  • fontWeight (number): Font weight (100-900). Defaults to 400 if not specified.
  • fontStyle (string): Font style ("normal" or "italic"). Defaults to "normal" if not specified.

Important: Line Height vs Font Size

Key difference:

  • fontSize is specified in rem units (e.g., 2.5 = 2.5rem)
  • lineHeight is specified as number of baseline units (e.g., 5 = 5 × 0.5rem = 2.5rem, 5.5 = 5.5 × 0.5rem = 2.75rem)
  • spaceAfter is specified as number of baseline units (e.g., 4 = 4 × 0.5rem = 2rem, 4.5 = 4.5 × 0.5rem = 2.25rem)

This ensures all line heights and spacing are perfect multiples of your baseline unit (or half-baseline units for finer control), maintaining consistent vertical rhythm throughout your typography system.

Example Calculation

With baselineUnit: 0.5:

  • fontSize: 2.5 = 2.5rem font size
  • lineHeight: 5.5 = 5.5 × 0.5rem = 2.75rem line height
  • spaceAfter: 4.5 = 4.5 × 0.5rem = 2.25rem space after element

Important: The actual CSS margin-bottom will be calculated as spaceAfter - nudgeTop to ensure proper baseline alignment. For example, if the calculated nudge is 0.375rem, the margin-bottom becomes 2.25rem - 0.375rem = 1.875rem, so that the total spacing (padding-top + margin-bottom) aligns perfectly with the baseline grid. Special case: If spaceAfter is 0, it is treated as 0.5 baseline units for spacing, so the margin-bottom is calculated as 0.5 - nudgeTop.

Generated Files

Running baseline-nudges generate config/typography-config.json creates:

dist/tokens.json

Design tokens with calculated nudge values for each typography element:

Multi-Font Format

{
  "baselineUnit": "0.5rem",
  "fontFiles": [
    {
      "family": "sans",
      "path": "../fonts/IBMPlexSans-Regular.woff"
    },
    {
      "family": "serif",
      "path": "../fonts/IBMPlexSerif-Regular.woff"
    }
  ],
  "elements": {
    "h1": {
      "fontSize": "5.25rem",
      "lineHeight": "5rem",
      "fontFamily": "sans",
      "fontWeight": 700,
      "fontStyle": "normal",
      "spaceAfter": "1.5rem",
      "nudgeTop": "0.48065rem"
    },
    "p": {
      "fontSize": "1rem",
      "lineHeight": "1.5rem",
      "fontFamily": "serif",
      "fontWeight": 400,
      "fontStyle": "normal",
      "spaceAfter": "1.5rem",
      "nudgeTop": "0.375rem"
    }
  }
}

Legacy Single-Font Format

{
  "font": "Fira Sans",
  "fontWeight": 400,
  "baselineUnit": "0.5rem",
  "fontFile": "../fonts/FiraSans-Regular.ttf",
  "elements": {
    "h1": {
      "fontSize": "5.25rem",
      "lineHeight": "5rem",
      "fontWeight": 400,
      "spaceAfter": "1.5rem",
      "nudgeTop": "0.19065rem"
    },
    "p": {
      "fontSize": "1rem",
      "lineHeight": "1.5rem",
      "fontWeight": 400,
      "spaceAfter": "1.5rem",
      "nudgeTop": "0.415rem"
    }
  }
}

dist/index.html

Interactive HTML demo with:

  • Baseline grid overlay (red lines)
  • All typography elements with calculated nudges
  • Self-contained with embedded font

dist/fonts/

Copy of your font file for the HTML demo to work offline.

Using the Generated Tokens

Import the tokens into your CSS build process or design system:

Multi-Font Format

const tokens = require("./dist/tokens.json");

// Generate CSS
Object.entries(tokens.elements).forEach(([identifier, element]) => {
  const nudgeTopValue = parseFloat(element.nudgeTop);
  const spaceAfterValue = parseFloat(element.spaceAfter);
  const marginBottom = spaceAfterValue - nudgeTopValue;

  console.log(`
.${identifier} {
  font-size: ${element.fontSize};
  line-height: ${element.lineHeight};
  font-family: ${element.fontFamily ? `'${element.fontFamily}', sans-serif` : 'inherit'};
  font-weight: ${element.fontWeight || 400};
  font-style: ${element.fontStyle || 'normal'};
  padding-top: ${element.nudgeTop};
  margin-bottom: ${marginBottom}rem;
  margin-top: 0;
}
  `);
});

Legacy Single-Font Format

const tokens = require("./dist/tokens.json");

// Generate CSS
Object.entries(tokens.elements).forEach(([identifier, element]) => {
  const nudgeTopValue = parseFloat(element.nudgeTop);
  const spaceAfterValue = parseFloat(element.spaceAfter);
  const marginBottom = spaceAfterValue - nudgeTopValue;

  console.log(`
.${identifier} {
  font-size: ${element.fontSize};
  line-height: ${element.lineHeight};
  font-weight: ${element.fontWeight};
  padding-top: ${element.nudgeTop};
  margin-bottom: ${marginBottom}rem;
  margin-top: 0;
}
  `);
});

Perfect for design systems that need precise typographic alignment with proper baseline grid spacing.

Key Features

  • 🎨 Multi-font support - Use multiple font families (sans, serif) with different nudge calculations per element
  • ⚖️ Per-element font styling - Specify fontFamily, fontWeight, and fontStyle for each element
  • 🔧 Corrected baseline calculation - Fixed critical lineGap distribution bug for accurate alignment
  • 📏 Precise font metrics reading - Extracts exact metrics from TTF, WOFF, and OTF files
  • 🎨 Complete typescale support - Full h1-h6 and paragraph element configuration
  • 🔤 Automatic font name extraction - Robust font name detection from various font formats
  • 🎯 Baseline nudge calculation - Generates precise CSS nudges for baseline grid alignment
  • 📱 Responsive baseline grids - Handles tight line-heights with negative nudge compensation
  • 🎭 Interactive HTML demos - Visual examples with baseline grid overlay
  • 🧹 Production-ready code - Clean, ESLint-compliant codebase without debug outputs
  • 🔄 CLI and API access - Command-line tool and programmatic JavaScript API
  • ⚡ One-command setup - baseline-nudges setup downloads font and creates config automatically

Installation

npm install -g @lyubomir-popov/baseline-nudge-generator

Or for local project use:

npm install --save-dev @lyubomir-popov/baseline-nudge-generator

Using Your Own Font

After running baseline-nudges setup, you can replace the downloaded font:

  1. Replace the font file:

    # Replace with your font file
    cp path/to/your-font.ttf fonts/FiraSans-Regular.ttf
    
    # Or rename your font and update the config
    cp path/to/your-font.ttf fonts/YourFont-Regular.ttf
  2. Update the config file:

    Edit config/typography-config.json and change the fontFile path:

    {
      "baselineUnit": 0.5,
      "fontFile": "../fonts/YourFont-Regular.ttf",
      "elements": [{ "identifier": "h1", "fontSize": 2.5, "lineHeight": 5 }]
    }
  3. Customize your typography scale:

    Edit the elements array to match your design system:

    {
      "elements": [
        {
          "identifier": "h1", // Element identifier or CSS class name
          "fontSize": 3, // Font size in rem
          "lineHeight": 6, // Line height in baseline units (6 × 0.5rem = 3rem)
          "spaceAfter": 5 // Space after in baseline units (5 × 0.5rem = 2.5rem)
        },
        {
          "identifier": "body-text",
          "fontSize": 1,
          "lineHeight": 3,
          "spaceAfter": 3
        }
      ]
    }
  4. Regenerate with your font:

    baseline-nudges generate config/typography-config.json

The font name will be automatically extracted from your font file and used in the generated HTML and tokens.

Fractional Baseline Support

The baseline-nudge-generator now supports fractional line heights and spacing values in multiples of 0.25, effectively quadrupling the resolution of the baseline grid for finer typographic control.

Fractional Values

  • lineHeight: Must be multiples of 0.25 (1.0, 1.25, 1.5, 1.75, 2.0, 2.25, 2.5, 2.75, 3.0, etc.)
  • spaceAfter: Must be 0 or multiples of 0.25 (0, 1.0, 1.25, 1.5, 1.75, 2.0, 2.25, 2.5, 2.75, 3.0, etc.). If set to 0, it is treated as 0.5 baseline units for spacing.

Benefits

  • Doubled Resolution: Baseline grid effectively has 2x resolution
  • More Precise Typography: Allows for finer control over line heights and spacing
  • Maintains Grid Alignment: Still ensures proper baseline grid alignment
  • Backward Compatible: Integer values (multiples of 1.0) still work perfectly

Example Configuration

{
  "baselineUnit": 0.5,
  "fontFiles": [
    {"family": "sans", "path": "fonts/Inter-Regular.woff"}
  ],
  "elements": [
    {
      "identifier": "h1",
      "fontSize": 2.5,
      "lineHeight": 5.5,    // 5.5 × 0.5rem = 2.75rem
      "spaceAfter": 4.5,    // 4.5 × 0.5rem = 2.25rem
      "fontFamily": "sans",
      "fontWeight": 700
    },
    {
      "identifier": "p",
      "fontSize": 1.0,
      "lineHeight": 2.5,    // 2.5 × 0.5rem = 1.25rem
      "spaceAfter": 1.5,    // 1.5 × 0.5rem = 0.75rem
      "fontFamily": "sans",
      "fontWeight": 400
    }
  ]
}

Font Format Support

The tool supports various font formats:

✅ Supported Formats

  • TTF (TrueType) - Recommended for best compatibility
  • WOFF (Web Open Font Format) - Good compatibility
  • OTF (OpenType) - Good compatibility
  • WOFF2 - Supported via automatic decompression to TTF

🔧 WOFF2 Decompression

WOFF2 files are automatically decompressed to TTF format for processing:

# Decompress WOFF2 manually if needed
baseline-nudges decompress-woff2 input.woff2 output.ttf

The setup process automatically downloads Fira Sans in TTF format for maximum compatibility.

JavaScript API

const {
  BaselineNudgeGenerator,
  generateFromConfig,
} = require("@lyubomir-popov/baseline-nudge-generator");

// Generate from config file
const result = await generateFromConfig(
  "./config/typography-config.json",
  "./dist"
);

// Or use the class directly
const generator = new BaselineNudgeGenerator();
const result = await generator.generateFiles(
  "./config/typography-config.json",
  "./dist"
);

CLI Commands

# Setup project with font download
baseline-nudges setup

# Generate tokens and HTML demo
baseline-nudges generate config/typography-config.json

# Generate to specific output directory
baseline-nudges generate config/typography-config.json custom-output/

# Create example configuration (downloads font automatically)
baseline-nudges init

# Create example configuration with custom name
baseline-nudges init my-typography

# Validate configuration file
baseline-nudges validate config/typography-config.json

# Legacy SCSS generation (backward compatibility)
baseline-nudges generate-legacy config/typography-config.json output.scss

# Watch mode for legacy SCSS (automatic regeneration)
baseline-nudges watch config/typography-config.json output.scss

# Show help
baseline-nudges --help

# Show version
baseline-nudges --version

Requirements

  • Node.js 14.0.0 or higher
  • Font file in WOFF2, WOFF, TTF, or OTF format (required)

License

MIT

Contributing

Issues and pull requests are welcome. Please ensure your contributions include tests and documentation.

Related Projects