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

branding-engine

v0.3.0

Published

Generate favicons, marks, wordmarks, social cards, brand sheets, and web tokens from one color and a 1-3 character glyph.

Readme

branding-engine

npm version ci node license: MIT

Generate a consistent brand kit from a compact alphanumeric mark and one accent color. Outputs include favicons, vector and raster marks, wordmark lockups, brand sheets, social cards, manifests, and CSS tokens.

The mark and wordmark use real font outlines. The common website path requires only Node.js; browser rendering is optional.

Example

Illustrative input using a non-production sample palette:

{
  "name": "Severino Labs",
  "identity": {
    "slug": "severino-labs",
    "color": "#6D5EF7",
    "deep": "#352A8A",
    "onColor": "#FFFFFF",
    "glyph": "SL",
    "wordmark": "Severino Labs"
  },
  "portrait": "./studio.jpg",
  "cardPalette": {
    "accent": "#9B8CFF",
    "textSoft": "#E3DEFF",
    "textMuted": "#B7AFE8"
  },
  "cards": [
    {
      "file": "social-card.png",
      "width": 1200,
      "height": 630,
      "photoWidth": 420,
      "eyebrow": "Severino Labs",
      "name": "Brand systems, generated.",
      "tagline": "Marks, wordmarks, sheets, web assets, and social cards from one config.",
      "meta": "Illustrative branding-engine example",
      "url": "github.com/joeseverino/branding-engine"
    }
  ]
}

Generated mark:

Severino Labs generated mark

Generated wordmark:

Severino Labs generated wordmark

Generated brand sheet:

Severino Labs generated brand sheet

Generated social card:

Severino Labs generated social card

The complete input and committed generated output are in examples/severino-labs.

Requirements

  • Node.js 18 or newer
  • sharp, OpenType.js, and the WOFF2 decoder, installed automatically
  • Optional: @playwright/test plus Chromium for brand sheets and social cards

Install:

npm install branding-engine

For a project-local CLI installation:

npm install --save-dev branding-engine
npx branding-engine --help

The package can also be installed globally with npm install --global branding-engine, though project-local installation keeps the version reproducible for collaborators and CI.

For sheets and social cards:

npm install --save-dev @playwright/test
npx playwright install chromium

Glyph Rules

glyph is the compact mark rendered inside the tile.

  • Accepts 1-3 ASCII letters or digits
  • Lowercase letters are normalized to uppercase
  • Spaces, punctuation, symbols, and strings longer than three characters fail
  • Layout dynamically adjusts by character count and caps narrow marks by height

Valid:

A
AC
A3X
7
R2

Invalid:

ABCD
A C
A-C
@

Quick Start: Add Branding to a Website

Use init and generate when a site needs favicons, a manifest, and CSS tokens in its public directory.

npm install --save-dev branding-engine
npx branding-engine init

Edit the generated brand.config.json:

{
  "name": "My Site",
  "accent": "#2563EB",
  "deep": "#173B8F",
  "onColor": "#FFFFFF",
  "glyph": "MS"
}

Then generate the files:

npm run brand

Default output:

public/
├── apple-touch-icon.png
├── brand-tokens.css
├── favicon-32.png
├── favicon-192.png
├── favicon.ico
├── favicon.svg
└── site.webmanifest

The command also prints the <head> links to add to the site.

Website Config Reference

| Field | Required | Description | |---|---:|---| | name | yes | Application name used in site.webmanifest | | accent | yes | Six-digit hex accent, with or without # | | glyph | yes | One to three alphanumeric mark characters | | deep | no | Dark palette shade; derived from accent when omitted | | onColor | no | Glyph color on the accent; defaults to #FFFFFF |

Options:

branding-engine generate --config path/to/brand.config.json --public path/to/public

Generated files are deterministic and intended to be committed with the site.

Astro

Astro serves files from public/ at the site root, so the default generator paths work without customization:

npm install --save-dev branding-engine
npx branding-engine init
npm run brand

In your shared layout, add the generated links and tokens:

<html lang="en">
  <head>
    <link rel="icon" href="/favicon.ico" sizes="any" />
    <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
    <link rel="apple-touch-icon" href="/apple-touch-icon.png" />
    <link rel="manifest" href="/site.webmanifest" />
    <link rel="stylesheet" href="/brand-tokens.css" />
    <meta name="theme-color" content="#2563EB" />
  </head>
  <body><slot /></body>
</html>

To regenerate before every production build, add it to the existing build script:

{
  "scripts": {
    "brand": "branding-engine generate",
    "build": "npm run brand && astro build"
  }
}

Plain HTML or Static Site

If the repository already publishes a public/ directory, use the same default commands as Astro. If the repository root itself is deployed:

npx branding-engine generate --public .

Add the links printed by the command to the page <head>, plus the token stylesheet:

<link rel="stylesheet" href="/brand-tokens.css" />

The generated CSS variables can then be used from any stylesheet:

.button {
  color: var(--brand-on-accent);
  background: var(--brand-accent);
}

Full Brand Kit

Use build for a reusable config-driven kit:

branding-engine build --config ./brand --out ./kits

--config accepts either a brand.json path or a directory containing brand.json. An optional surfaces.json can live beside it.

Minimal brand.json:

{
  "name": "Acme",
  "identity": {
    "slug": "acme",
    "color": "#1E3A8A",
    "glyph": "AC",
    "wordmark": "Acme Corp"
  }
}

Expanded brand.json:

{
  "name": "Acme",
  "font": "./AcmeSans.ttf",
  "weight": 800,
  "wordmarkWeight": 700,
  "identity": {
    "slug": "acme",
    "color": "#1E3A8A",
    "deep": "#14245C",
    "onColor": "#FFFFFF",
    "glyph": "A3C",
    "wordmark": "Acme Corp"
  },
  "portrait": "./portrait.jpg",
  "cardPalette": {
    "accent": "#5B82D6",
    "textSoft": "#DDE6FB",
    "textMuted": "#A9C0E8"
  },
  "cards": [
    {
      "file": "social-card.png",
      "width": 1200,
      "height": 630,
      "photoWidth": 420,
      "eyebrow": "Acme Corp",
      "name": "Acme",
      "tagline": "Built for what comes next.",
      "meta": "Brand systems and engineering",
      "url": "acme.example"
    }
  ]
}

Full Config Reference

| Field | Required | Description | |---|---:|---| | name | no | Human-readable brand name used in logs and fallbacks | | identity | yes | Primary brand identity object | | identity.slug | yes | Output directory name | | identity.color | yes | Six-digit accent color | | identity.glyph | yes | One to three alphanumeric mark characters | | identity.wordmark | no | Text used for wordmark lockups and sheet title | | identity.deep | no | Curated dark shade | | identity.onColor | no | Glyph color on accent | | font | no | Font path relative to brand.json; defaults to bundled Inter | | weight | no | Mark font weight; defaults to 800 | | wordmarkWeight | no | Wordmark font weight; defaults to 700 | | surfaces | no | Inline additional surfaces; surfaces.json takes precedence | | portrait | for cards | JPEG path relative to brand.json | | cardPalette | for cards | Card accent and supporting text colors | | cards | no | Social-card definitions rendered to <out>/cards/ |

Additional surfaces inherit the primary glyph unless they override it:

{
  "support": {
    "color": "#1F4D57",
    "wordmark": "Acme Support"
  },
  "labs": {
    "color": "#7C3AED",
    "glyph": "A3",
    "wordmark": "Acme Labs"
  }
}

One-Off Kit

Create a kit without a config file:

branding-engine kit acme ff5733 AC "Acme Corp"

Three-character example:

branding-engine kit prism 635bff P3X "Prism Works" \
  --only mark,wordmark,web \
  --out ./kits

Syntax:

branding-engine kit <slug> <hex> <glyph> ["Wordmark"] [options]

Figures

Designed, brand-themed graphics for writeup covers, README banners, and OG/social cards, driven by a small JSON spec instead of code. Same headless-Chromium + bundled Inter pipeline as the social cards; for flowcharts and sequence diagrams use Mermaid (the diagram tool) instead.

branding-engine figure cover.figure.json \
  --tokens ./kits/severino-labs/web/tokens.css \
  --out cover.png            # defaults to <spec>.png

A spec is one object. template and its fields are the only required parts; everything else has a default.

| Field | Default | Notes | |---|---|---| | template | — | title, flow, diamond, nodes, or topology | | size | cover (radial topologytopo) | preset (cover 1600×900, wide, topo 1500×1000, og 1200×630, github 1280×640, square) or [w, h] | | theme | light | light or dark | | colors | from --tokens | inline { accent, deep, onAccent, ink, paper } override |

Output renders at 2× the logical size (override with --scale) for crisp text.

title — eyebrow + headline + optional sub-line and footer. The all-purpose cover/banner.

{ "template": "title", "size": "og", "theme": "dark",
  "eyebrow": "Diamond Model", "headline": "Marks & Spencer\nCyberattack",
  "subline": "Identity-based intrusion mapped to MITRE ATT&CK.", "footer": "jseverino.com" }

flow — stacked left-to-right step chains (before/after, pipelines). rows[].anchor highlights one step in the brand accent.

{ "template": "flow", "theme": "light", "rows": [
  { "label": "Before", "steps": ["Browser", "PHP", "MySQL"] },
  { "label": "After", "steps": ["Markdown", "Astro", "Cloudflare"], "anchor": "Cloudflare" } ] }

diamond — the four-vertex model around a center node (top/left/right/bottom + center).

{ "template": "diamond", "theme": "dark", "center": "M&S\n2025",
  "nodes": { "top": "Adversary", "left": "Capability", "right": "Infrastructure", "bottom": "Victim" } }

nodes — a generic graph: layout of row, ring, or grid, a nodes list, and an optional center. \n breaks a line in any label.

topology — network / lab topologies that keep the topology look: a device glyph per node in a ringed circle, a node label, and links that carry a network name or IP. Use this (not flow) when the graphic is devices on a network rather than a boxes-and-arrows pipeline.

layout options, easiest first:

  • star — hub-and-spoke. Each node sets pos: center for the hub, then n/s/e/w/ ne/nw/se/sw. The engine snaps e/w to the hub's exact y and n/s to its exact x, so spoke links are dead straight by construction — no hand-tuned coordinates. The hub's label auto-parks in the first empty diagonal quadrant. Use this for almost every network diagram.
  • row — nodes evenly spaced left→right (pipelines, before/after).
  • ring — nodes evenly around an optional center.
  • free — each node placed by at: [xFraction, yFraction] (0..1 of the canvas) with an optional scale. The escape hatch for arrangements the others can't express.

Omit size and the frame follows the layout: radial star/ring topologies use the 3:2 topo frame (legible on mobile, where width is the constraint); a row becomes a short, wide banner whose height is sized to the node count, so a 2-node diagram fills the frame instead of floating in 16:9. An explicit size always wins.

Each node takes { id, icon, label, role?, at?, scale?, labelPos? }; icon is one of laptop, monitor, server, database, switch, router, cloud, phone; role of anchor or attacker fills the node in the brand accent; labelPos is above/below. Links are { from, to, label?, fromLabel?, toLabel?, style?, dir?, color? } where style is dashed, dir is to/both/none, color: "accent" draws the link (and a bordered label chip) in the brand accent for an attack/overlay path, and fromLabel/toLabel print a small label under each endpoint (e.g. the IP octet beside each host). Omitting links in a row chains the nodes in order.

{ "template": "topology", "layout": "ring", "theme": "light",
  "center": { "id": "s1", "icon": "switch", "label": "s1\nOpen vSwitch", "role": "anchor" },
  "nodes": [
    { "id": "c0", "icon": "server", "label": "c0\nSDN Controller" },
    { "id": "h1", "icon": "monitor", "label": "h1\nVictim" },
    { "id": "h3", "icon": "monitor", "label": "h3\nAttacker", "role": "attacker" },
    { "id": "h2", "icon": "monitor", "label": "h2\nTarget" } ],
  "links": [
    { "from": "c0", "to": "s1", "label": "OpenFlow", "style": "dashed", "dir": "to" },
    { "from": "h1", "to": "s1", "dir": "both" },
    { "from": "h2", "to": "s1", "dir": "both" },
    { "from": "h3", "to": "s1", "dir": "both" } ] }

Stages

Select stages with a comma-separated --only value:

branding-engine build \
  --config ./brand.json \
  --out ./kits \
  --only mark,wordmark,web

| Stage | Browser needed | Output | |---|---:|---| | mark | no | Favicons, vector mark, PNG marks, transparent variants | | wordmark | no | Vector and PNG title-case/all-caps lockups | | web | no | CSS tokens, web manifest, and <head> snippet | | sheet | yes | Brand overview poster, sections, and generated kit README | | cards | yes | Configured social-card PNGs |

Without --only, all stages run.

Output Layout

Each kit is written under <out>/<slug>/:

<out>/<slug>/
├── icons/
├── mark/
├── sheet/
├── web/
└── wordmark/

Social cards are written to <out>/cards/.

Programmatic API

import {
  buildBrand,
  buildKit,
  generateSite,
  markSvg,
  normalizeGlyph,
  wordmarkSvg,
} from 'branding-engine';

await buildKit({
  slug: 'acme',
  hex: '#FF5733',
  glyph: 'a3x',
  wordmark: 'Acme',
  only: 'mark,wordmark,web',
  outDir: 'public/brand',
});

const glyph = normalizeGlyph('a3x'); // "A3X"
const mark = markSvg({ size: 64, bg: '#FF5733', glyph });
const lockup = wordmarkSvg({
  tileHex: '#FF5733',
  text: 'Acme',
  glyph,
});

Main exports:

  • buildBrand(options)
  • buildKit(options)
  • initSite(options)
  • generateSite(options)
  • makeMark(options)
  • makeWordmark(options)
  • makeSheet(options)
  • makeWeb(options)
  • makeCards(options)
  • markSvg(options)
  • wordmarkSvg(options)
  • normalizeGlyph(glyph)
  • renderCard(browser, options)
  • launchBrowser()

Fonts and Glyph Extraction

Bundled Inter caches include uppercase letters and digits for marks, plus uppercase, lowercase, digits, and spaces for wordmarks.

Custom fonts and missing characters are extracted entirely in Node with OpenType.js and a WebAssembly WOFF2 decoder. No Python, fonttools, native binding, or system font utility is required. Supported input formats are TTF, OTF, WOFF, and WOFF2.

Extracted caches are written under .brand-cache/, or the directory specified by BRAND_CACHE_DIR. The installed package is never modified. If a variable font cannot be instantiated at the requested weight, the build exits with the font filename and parser error; use a static font file or another supported variable font.

Errors

The CLI exits nonzero with an actionable message for invalid glyphs, invalid colors, missing configs, unavailable font glyphs, or missing optional browser dependencies.

Example:

Invalid glyph: "ABCD". Expected 1-3 letters or digits, e.g. A, AC, or A3X.

License

MIT. The bundled Inter font includes its own notice under assets/fonts/inter/NOTICE.md.