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

brand-artisan

v0.1.0

Published

Turn JSX into brand images (Open Graph, social posts, banners). next/og's engine outside Next: no browser, no Figma, no server.

Readme

BrandArtisan

JSX in, image out. One .tsx file, one image: Open Graph, social posts, banners, carousels.

npm CI license MIT

🇫🇷 Version française : README.fr.md

If you can write a React component, you already know how to make your visuals. BrandArtisan turns JSX into PNGs: Open Graph images for your site, LinkedIn, Facebook and X posts and banners, carousels. No Figma, no browser, no server: your visuals are code, versioned with everything else.

import type { Template } from "brand-artisan";

function render() {
  return (
    <div style={{ display: "flex", width: "100%", height: "100%", background: "#0e1a2b" }}>
      {/* your layout, in flexbox */}
    </div>
  );
}

export default { size: { width: 1200, height: 630 }, title: "Site OG", render } satisfies Template;

Under the hood, it is the next/og engine (Satori + resvg) taken out of its Next wrapper: JSX → SVG → PNG. react only provides the JSX runtime; there is no react-dom and no client-side rendering.

Getting started

Prerequisite: Node.js ≥ 22. Nothing else.

npx create-brand-artisan my-visuals
cd my-visuals
npm run dev      # browsable preview at http://localhost:4000
npm run build    # exports the PNGs to out/

The generated project contains only your brand: guidelines (brands/), visuals (templates/), asset scripts (tools/), fonts (fonts/). The engine lives in node_modules and updates with npm update. A complete example ships with it (Calame, a fictional brand): the first command produces an image before you have written anything.

Writing a visual

A .tsx file under templates/<project>/ = one image. It default-exports a Template (see above); discovery is automatic, there is no registry to edit. In dev, every visual gets its own URL, like Next routes:

http://localhost:4000/                               → lists the projects
http://localhost:4000/calame/og                      → preview page (re-rendered on each refresh)
http://localhost:4000/calame/og?raw                  → the raw PNG
http://localhost:4000/calame/linkedin-carousel?pdf   → a folder's assembled PDF, once built

npm run build exports everything to out/<project>/, ready to upload.

Three Satori rules to know:

  • Any element with several children must be display: flex: the number one cause of render errors.
  • Fonts are explicit: drop <Family>-<weight>.ttf into fonts/ (e.g. Sora-700.ttf), that is all it takes to register one.
  • Images are embedded as data URIs (<img src="data:image/svg+xml;base64,…">), not by file path.

Carousels: a folder of slides, one PDF

A carousel is a subfolder of cards sharing a theme, one .tsx per slide:

templates/calame/linkedin-carousel/
  theme.ts      shared palette and layout (pure TS, not discovered)
  card-1.tsx    one slide = one PNG, and one page of the PDF
  card-2.tsx
  …

npm run build renders each slide to its own PNG, which is what a carousel ad takes (Campaign Manager, one image per card). An organic LinkedIn carousel is another animal: the swipeable carousel of the feed is a document post, and what you upload is a single PDF that LinkedIn paginates into slides. The same images attached directly to a post come out as a mosaic of thumbnails, not a carousel.

npm run pdf -- calame/linkedin-carousel    # → out/calame/linkedin-carousel.pdf

One slide per page, each page at its slide's exact size, in natural order (card-2 before card-10). The command refuses to assemble slides of mixed ratios: LinkedIn takes the whole document's ratio from its first page, so a stray page would come out letterboxed. In dev, a folder's page offers its PDF as soon as it exists, and flags it out of date when a slide is more recent.

One project = one set of guidelines

Each brand is a project: its reference in brands/<project>/ (brand.md: palette, logo, typography; project.md: tone, audience, claims), its visuals in templates/<project>/. brand.md is blocking: no visual without guidelines; this is what keeps humans and AI alike from inventing colors or recomposing a logo by eye.

A separate toolchain (tools/<project>/) generates the assets rendering cannot produce: an SVG logotype traced from the font's glyphs, multi-size favicons, .ico. npm run build does not cover them: each script runs on its own, and writes to out/<project>/brand/.

npx tsx tools/calame/build-logo.ts     # → out/calame/brand/logo/
npx tsx tools/calame/build-favicon.ts  # → out/calame/brand/favicon/

Details: tools/README.md.

With an AI agent

BrandArtisan ships skills that encode each platform's official dimensions, safe zones, and the "nothing outside the guidelines" discipline. They install into whichever agent you use:

npx skills add roslove44/brand-artisan -s "*" -y

-s "*" -y takes the whole set and installs into the agents found on your machine; drop the flags to choose both from a list. The skills CLI knows where Claude Code, Cursor, Copilot and twenty-odd other agents keep theirs. Rerun the command to update; a teammate runs it once to get the same set. Claude Code users can instead add this repository as a plugin marketplace: /plugin marketplace add roslove44/brand-artisan.

These skills read the files you point them at, SVG markup included, and run the project's own commands. import-reference reaches furthest, since its input comes from outside the project: it treats file content as data to measure, never as instructions.

/new-project my-brand        sets up the guidelines (brand.md) through an interview
/import-reference            derives the guidelines from your existing visuals, measured to the pixel
/og-image my-brand           1200×630 Open Graph image
/linkedin-post, /facebook-post, /x-post…    visuals to each platform's specs
/campaign my-brand           multi-platform kit from a single brief
/brand-assets my-brand       generates logo, favicon and their variants

The agent reads your guidelines, asks the missing questions, and produces verifiable .tsx files (npm run typecheck, npm run build). Everything can still be done by hand: AI is an accelerator, not a requirement.

The CLI

brand-artisan dev                       render server at http://localhost:4000
brand-artisan build                     exports templates/ to out/
brand-artisan pdf <folder>              assembles a folder of slides into a PDF (LinkedIn document post)
brand-artisan colors <image> [count]    an image's palette, measured rather than guessed

Commands work from any subfolder of the project. Skills are not part of the engine: they install per agent (see With an AI agent) and npx skills update refreshes them.

The API

import { brand, root, toPng, renderToFile, type Template } from "brand-artisan";

| Export | Role | | --- | --- | | type Template | A visual's contract: { size: { width, height, scale? }, title?, render }. scale: 2 for retina. | | brand(path) | Absolute URL to brands/<path>, ready for readFile. E.g. brand("calame/logo/logo.svg"). | | root(path) | Absolute URL resolved from the project root (the nearest package.json folder). | | toPng(node, size) | JSX → PNG (Buffer). | | renderToFile(node, size & { out }) | Same, but writes out/<out>.png and returns the path. |

Two subpaths for brand tooling: brand-artisan/brandkit (glyph outlines, SVG → PNG, .ico) and brand-artisan/colors (palette and painted-area measurement).

Contributing

Setup, repo commands, test safety net and conventions: CONTRIBUTING.md.

License

MIT, with one exception: the fonts in fonts/ are under the SIL Open Font License 1.1 (fonts/NOTICE.md). Calame, the repository's demonstration brand, is covered by MIT like everything else: it is fictional, and it is there to be a starting point.