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

og-image-generator

v0.1.1

Published

Reusable OG image generator with SVG templating, PNG rasterization, and meta tag generation

Downloads

204

Readme

og-image-generator

Generate Open Graph images for link previews on social platforms. Composes an SVG template, rasterizes to a compressed PNG via resvg + sharp, and optionally emits HTML meta tags.

Install

npm install og-image-generator

Quick start

CLI

# Minimal — just a project name
npx og-image-generator generate --name "My Project"

# Full options
npx og-image-generator generate \
  --name "hetzner-cli" \
  --tagline "A modern CLI for Hetzner Cloud" \
  --features Servers Firewalls "Load Balancers" \
  --footer "github.com/hetzner/cli" \
  --preset terminal \
  --accent "#d50c2d" \
  -o og-image.png \
  --svg \
  --meta \
  --image-url "https://hetzner.github.io/cli/og-image.png"

# From a JSON config file
npx og-image-generator generate --config og-image.json

Node.js API

import { generate, generateMetaTags } from "og-image-generator";
import { writeFile } from "node:fs/promises";

const result = await generate({
  name: "My Project",
  tagline: "A fast and reliable tool",
  features: ["TypeScript", "CLI", "Extensible"],
  footer: "github.com/me/my-project",
  style: { preset: "terminal" },
});

await writeFile("og-image.png", result.png);
console.log(`${result.width}x${result.height}, ${result.pngSize} bytes`);

// Generate meta tags for your HTML <head>
const meta = generateMetaTags({
  title: "My Project",
  description: "A fast and reliable tool",
  url: "https://my-project.dev",
  imageUrl: "https://my-project.dev/og-image.png",
});

console.log(meta.html);
// <meta property="og:type" content="website"/>
// <meta property="og:title" content="My Project"/>
// ...

CLI reference

og-image generate / og-image-generator generate

Generate a 1200x630 PNG image.

| Flag | Description | |------|-------------| | --name <name> | Project name displayed in the image (required unless --config) | | --tagline <text> | Short tagline below the project name | | --description <text> | Page description (meta tags only, not rendered in image) | | --features <words...> | Feature keywords shown in a row (e.g. --features Fast Secure) | | --footer <text> | Footer text, typically a URL or version | | --preset <name> | Style preset — sets decorations and colors (see og-image presets) | | --bg <color> | Background hex color (default: #0a0a0a) | | --accent <color> | Accent hex color for the project name (default: #22d3ee) | | --logo-svg <path> | Path to an SVG file to render as the logo | | --font <path> | Path to a custom font file (TTF, OTF, or WOFF2) | | -o, --output <path> | Output PNG path (default: og-image.png) | | --svg | Also write the raw SVG file alongside the PNG | | --meta | Print Open Graph + Twitter Card meta tags to stdout | | --url <url> | Canonical page URL (included in meta tags) | | --image-url <url> | Public URL where the image will be hosted (for og:image) | | --config <path> | Path to a JSON config file (all other flags are ignored) |

og-image presets / og-image-generator presets

List all registered style presets with their descriptions and decoration details.

JSON config file

Instead of CLI flags, you can provide a JSON file with --config:

{
  "name": "hetzner-cli",
  "tagline": "A modern CLI for Hetzner Cloud",
  "description": "Manage Hetzner Cloud resources from your terminal",
  "features": ["Servers", "Firewalls", "Load Balancers", "SSH Keys"],
  "footer": "github.com/hetzner/cli",
  "url": "https://hetzner.github.io/cli",
  "imageUrl": "https://hetzner.github.io/cli/og-image.png",
  "colors": {
    "background": "#0a0a0a",
    "accent": "#d50c2d",
    "dim": "#a1a1aa",
    "text": "#fafafa"
  },
  "style": {
    "preset": "terminal"
  }
}

All fields except name are optional. See the Configuration section for the full schema.

Configuration

OgImageConfig

| Field | Type | Default | Description | |-------|------|---------|-------------| | name | string | (required) | Project name displayed in the image | | tagline | string | — | Short tagline below the name | | description | string | — | Description for meta tags (not rendered in image) | | features | string[] | — | Keywords shown as a horizontal row with \| separators | | footer | string | — | Footer text pinned to the bottom | | url | string | — | Canonical page URL (for meta tags) | | imageUrl | string | — | Public URL where the generated image is hosted (for meta tags) | | logo | LogoConfig | — | Logo configuration (see Logos) | | colors | ColorConfig | (see below) | Color overrides | | font | FontConfig | bundled Inter | Custom font (see Fonts) | | style | StyleConfig | { preset: "minimal" } | Style decorations and preset (see Style & presets) | | width | number | 1200 | Image width in pixels | | height | number | 630 | Image height in pixels |

ColorConfig

| Field | Default | Description | |-------|---------|-------------| | background | #0a0a0a | Background fill | | accent | #22d3ee | Project name and glow highlight | | dim | #a1a1aa | Secondary text (tagline, features, footer) | | text | #fafafa | Primary text and logo text |

FontConfig

| Field | Default | Description | |-------|---------|-------------| | path | bundled Inter Regular | Path to regular weight font file (TTF, OTF, or WOFF2) | | boldPath | bundled Inter Bold | Path to bold weight font file | | family | "Inter" | CSS font-family name (must match the loaded font) |

The bundled Inter font (SIL OFL license) is used by default. To use a custom font, provide the file path — resvg loads fonts from buffers, so any TTF/OTF/WOFF2 file works.

Logos

Three logo modes are supported:

Inline SVG

Embed SVG elements directly:

await generate({
  name: "My App",
  logo: {
    type: "svg-inline",
    content: '<circle cx="50" cy="50" r="50" fill="#22d3ee"/>',
    viewBox: "0 0 100 100",
  },
});

SVG file

Load from a file path. Optionally extract a specific <g> by its id:

await generate({
  name: "My App",
  logo: {
    type: "svg-file",
    path: "./logo.svg",
    selector: "wordmark", // extracts <g id="wordmark">
  },
});

From the CLI: --logo-svg ./logo.svg

Text fallback

Render text as the logo (uses the configured font):

await generate({
  name: "My App",
  logo: { type: "text", text: "MA" },
});

Style & presets

The style field controls decorative overlays and sets a base preset.

StyleConfig

| Field | Type | Default | Description | |-------|------|---------|-------------| | preset | string \| Preset | "minimal" | Base preset (see below) | | scanlines | boolean \| { opacity } | from preset | Horizontal scanline overlay | | cornerBrackets | boolean \| { opacity, strokeWidth } | from preset | Pixel-art corner frame | | radialGlow | boolean \| { opacity, cy, r } | from preset | Radial gradient glow behind logo |

Explicit fields always override the preset. For example, { preset: "terminal", scanlines: false } uses the terminal preset but disables scanlines.

Built-in presets

| Preset | Scanlines | Corner brackets | Radial glow | Description | |--------|-----------|----------------|-------------|-------------| | minimal | off | off | on (0.15) | Clean, modern. Default. | | terminal | on (0.03) | on (0.15, 2px) | on (0.15) | Retro terminal aesthetic |

List them from the CLI:

npx og-image-generator presets

Custom presets

Presets are plain objects that bundle decorations and optional colors. There are three ways to use them:

1. Inline preset object (no registration)

Pass a Preset object directly — works in the Node.js API without any registration:

import { generate, definePreset } from "og-image-generator";

const neon = definePreset({
  name: "neon",
  description: "Vibrant neon glow on dark background",
  colors: {
    background: "#0d0221",
    accent: "#ff00ff",
    dim: "#b967ff",
    text: "#fffce1",
  },
  scanlines: { opacity: 0.04 },
  cornerBrackets: false,
  radialGlow: { opacity: 0.25, cy: "40%", r: "55%" },
});

await generate({
  name: "My Project",
  style: { preset: neon },
});

2. Register for name-based lookup

Register a preset so it can be referenced by string name in JSON config files and the CLI:

import { definePreset, registerPreset } from "og-image-generator";

const corporate = definePreset({
  name: "corporate",
  description: "Clean corporate look with light background",
  colors: {
    background: "#ffffff",
    accent: "#0066cc",
    dim: "#666666",
    text: "#111111",
  },
  scanlines: false,
  cornerBrackets: false,
  radialGlow: { opacity: 0.08 },
});

registerPreset(corporate);

Now usable as:

{ "style": { "preset": "corporate" } }
npx og-image-generator generate --name "Acme Corp" --preset corporate

Note: registerPreset must be called before generate — it modifies the in-process registry. For CLI usage, register presets in a wrapper script that imports the CLI.

3. Preset with per-project overrides

A preset provides defaults, but explicit colors and style fields on the config always take precedence:

await generate({
  name: "My Fork",
  style: { preset: "terminal", scanlines: false },
  colors: { accent: "#ff6600" }, // overrides preset accent
});

Layering order: defaults -> preset colors -> config colors (rightmost wins).

Preset interface

interface Preset {
  name: string;
  description?: string;
  colors?: {
    background?: string;
    accent?: string;
    dim?: string;
    text?: string;
  };
  scanlines?: boolean | { opacity?: number };
  cornerBrackets?: boolean | { opacity?: number; strokeWidth?: number };
  radialGlow?: boolean | { opacity?: number; cy?: string; r?: string };
}

Preset API functions

| Function | Description | |----------|-------------| | definePreset(preset) | Type-safe factory — validates shape, returns the object | | registerPreset(preset) | Register for name-based lookup (CLI, JSON config) | | getPreset(name) | Look up a registered preset by name | | listPresets() | List registered preset names | | listPresetDetails() | List registered presets with full definitions | | resolvePreset(ref) | Resolve a string \| Preset \| undefined to a Preset | | minimal | Built-in minimal preset (exported constant) | | terminal | Built-in terminal preset (exported constant) |

Meta tags

Generate Open Graph and Twitter Card <meta> tags for your HTML <head>:

import { generateMetaTags } from "og-image-generator";

const meta = generateMetaTags({
  title: "My Project",
  description: "A fast and reliable tool",
  url: "https://my-project.dev",
  imageUrl: "https://my-project.dev/og-image.png",
  siteName: "My Project",
  locale: "en_US",
});

// meta.html — ready-to-paste HTML string
// meta.tags — structured array of { tag, attributes } objects

Generated tags

| Tag | Property | |-----|----------| | Open Graph | og:type, og:title, og:description, og:url, og:image, og:image:width, og:image:height, og:image:type | | Open Graph (optional) | og:site_name, og:locale | | Twitter Card | twitter:card, twitter:title, twitter:description, twitter:image |

All attribute values are HTML-escaped. Relative imageUrl values are resolved against url.

From the CLI, add --meta to print meta tags to stdout:

npx og-image-generator generate --name "My Project" --meta --image-url "https://example.com/og.png"

MetaTagsConfig

| Field | Type | Default | Description | |-------|------|---------|-------------| | title | string | (required) | Page title | | description | string | — | Page description | | url | string | — | Canonical page URL | | imageUrl | string | (required) | URL to the OG image | | imageWidth | number | 1200 | Image width | | imageHeight | number | 630 | Image height | | siteName | string | — | Site name | | locale | string | — | Locale (e.g. en_US) |

Node.js API

generate(config): Promise<GenerateResult>

The main entry point. Builds an SVG, rasterizes to PNG via resvg, compresses with sharp, and returns both.

import { generate } from "og-image-generator";

const result = await generate({
  name: "My Project",
  tagline: "A cool tool",
});

// result.svg   — raw SVG string (useful for debugging)
// result.png   — compressed PNG Buffer
// result.pngSize — PNG file size in bytes
// result.width  — 1200
// result.height — 630

buildSvg(config): string

Build just the SVG string without rasterizing. Useful for previewing or debugging templates:

import { buildSvg } from "og-image-generator";

const svg = buildSvg({ name: "Test", style: { preset: "terminal" } });

compressPng(buffer, options?): Promise<Buffer>

Compress a PNG buffer using sharp. Used internally by generate, but exposed for custom pipelines:

import { compressPng } from "og-image-generator";

const compressed = await compressPng(rawPngBuffer, {
  compressionLevel: 9, // 0-9, default: 9
  palette: true,       // palette quantization, default: true
  colors: 256,         // palette colors, default: 256
});

Font utilities

import {
  getBundledFontPaths,
  loadFontBuffers,
  getFontFamily,
} from "og-image-generator";

// Get paths to bundled Inter font files
const paths = getBundledFontPaths();
// { regular: "/path/to/Inter-Regular.woff2", bold: "/path/to/Inter-Bold.woff2" }

// Load font buffers (with optional custom paths)
const buffers = await loadFontBuffers({ path: "./MyFont.woff2" });

// Get font family name
const family = getFontFamily({ family: "Departure Mono" }); // "Departure Mono"
const defaultFamily = getFontFamily(); // "Inter"

SVG utilities

import {
  escapeSvgText,
  truncateText,
  estimateTextWidth,
  maxCharsForWidth,
  extractSvgContent,
} from "og-image-generator";

escapeSvgText('A & B <C>');       // "A &amp; B &lt;C&gt;"
truncateText("Hello World", 6);   // "Hello\u2026"
estimateTextWidth("hello", 16);   // 44 (5 * 16 * 0.55)
maxCharsForWidth(1040, 52);       // 36

// Extract SVG content from a file (optionally by group id)
const logo = await extractSvgContent("./logo.svg", "wordmark");
// { content, viewBox, width, height }

Fonts

The package bundles Inter (Regular + Bold, WOFF2, ~280KB total) under the SIL Open Font License. Inter is used by default for all text rendering.

To use a custom font:

await generate({
  name: "My Project",
  font: {
    path: "./fonts/DepartureMono-Regular.woff2",
    boldPath: "./fonts/DepartureMono-Bold.woff2",
    family: "Departure Mono",
  },
});

From the CLI: --font ./fonts/DepartureMono-Regular.woff2

Note: resvg does not support CSS @font-face — fonts are loaded as binary buffers and passed directly to the renderer. Any TTF, OTF, or WOFF2 file works.

How it works

  1. SVG compositionbuildSvg() assembles an SVG document from the config: background, optional decorations (glow, scanlines, brackets), logo, name, tagline, features, footer
  2. Font loading — Reads font files as buffers (bundled Inter or custom)
  3. Rasterizationresvg renders the SVG to a raw PNG using the font buffers
  4. Compressionsharp applies palette quantization and maximum compression (typically ~20-30KB for flat-color images)
  5. Meta tagsgenerateMetaTags() produces both Open Graph and Twitter Card tags with proper escaping and URL resolution

License

MIT