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

@clawnify/html-to-image

v0.3.1

Published

OpenClaw plugin — render an HTML string to a PNG file on disk (Satori + resvg, no headless browser). Lets agents turn HTML/CSS into images (status cards, summaries, simple charts) they can attach to any channel.

Readme

@clawnify/html-to-image

Built and open-sourced by clawnify.com to benefit the OpenClaw ecosystem. It works with any OpenClaw agent — there's nothing Clawnify-specific about it.

An OpenClaw plugin that renders an HTML string to a PNG file on disk — no headless browser. It gives agents a native html_to_image tool so they can turn HTML/CSS into images (status cards, summaries, simple charts, receipts) and then attach them to any message, email, or channel.

Rendering is done in-process with Satori (HTML/CSS → SVG) and resvg (SVG → PNG). No Chromium, no network, no runtime service to call.

What it does

html_to_image({ html, width?, height?, scale?, background?, path? }) → { path, width, height, bytes }

The tool writes a PNG to disk and returns its absolute path. What happens next is up to the agent — send it, upload it, or reference it. The plugin has no opinion about delivery, which keeps it usable anywhere.

Install (as an OpenClaw plugin)

openclaw plugins install @clawnify/html-to-image --pin
openclaw plugins list | grep html-to-image     # → enabled

The gateway loads it at startup and the html_to_image tool becomes available to agents.

Bundled skill

Installing the plugin also publishes an html-to-image skill (to ~/.openclaw/plugin-skills/html-to-image/). Agents read it on demand — before building anything more than a single styled box — and it carries the flexbox-CSS rules plus copy-paste card / leaderboard / receipt examples. This is where agents learn how to write HTML that Satori accepts, so the always-loaded tool description stays short.

openclaw skills list | grep html-to-image      # → ✓ ready

Use as a library

import { htmlToImage } from "@clawnify/html-to-image";

const { path, width, height } = await htmlToImage(
  `<div style="display:flex;padding:48px;background:#0f172a;color:#fff;font-family:Inter;font-size:48px">
     Deploy succeeded ✓
   </div>`,
  { width: 1200, outputPath: "/tmp/card.png" }, // omit outputPath to get just the buffer
);

Returns { buffer, path?, width, height, overflow, warnings }.

Overflow detection

Satori silently clips anything larger than the image — it doesn't error — which is an easy way to ship a card with a cut-off heading. So every render measures each element's box against the canvas and reports it:

This measures against the image only. Content truncated inside the layout — a narrow column or a fixed-width cell that still fits the image — is not reported: Satori exposes no reliable way to tell that apart from ordinary overlap (an overlapping avatar stack looks the same to a geometry check), so guessing it produces false positives. Keep columns wide by design instead.

"overflow": {
  "horizontal": true,        // content is wider than the image (clipped on the right)
  "vertical": false,         // taller than a FIXED height (always false when height is auto)
  "contentWidth": 1420,      // widest edge actually laid out (CSS px)
  "contentHeight": 480,
  "canvasWidth": 1200,
  "canvasHeight": null,      // null = auto-height
  "clipped": [               // offending nodes, most-overflowing first (capped)
    { "type": "div", "text": "A very long heading…", "right": 1420, "bottom": 96 }
  ]
}

The html_to_image tool returns overflow: false when everything fits, or the report above when something is clipped — so an agent can notice and re-render wider/taller. Since auto-height can never clip vertically, the simplest way to avoid overflow is to omit height and only constrain width.

Options

| Option | Default | Notes | |---|---|---| | width | 1200 | CSS pixels. Height auto-derives from content unless height is set. | | height | (auto) | Fixed height in CSS pixels. Omit to size to content. | | scale | 2 | Output pixel-density multiplier (2 = retina-crisp). | | background | (transparent) | Color painted behind the HTML, e.g. "#ffffff". | | path / outputPath | (temp file) | Where to write the PNG. Tool defaults to a fresh file under the OS temp dir. | | fonts | Inter 400/700 | Replace the bundled default typeface (library only). |

Writing HTML that renders

Satori supports a flexbox subset of CSS — think Open Graph image, not a full web page:

  • Use display: flex for layout (no grid, no float, no position: absolute for flow).
  • Every element containing text or children should set display: flex.
  • Use inline styles. No stylesheets, no <style> cascade, no class-based CSS.
  • No JavaScript runs, and remote <img src="https://…"> is not fetched — embed images as data: URIs.
  • Write raw characters, not HTML entities&amp; renders literally as &amp;, not &.
  • Text uses the bundled Inter (Latin). Satori paints glyphs only from the fonts you give it — it never falls back to the OS — so emoji render as blank boxes (the tool returns a warnings note), the same on every machine. Draw icons with CSS, or pass a fonts array with an emoji font. Non-Latin scripts likewise need their own fonts.

If a layout looks wrong, it's almost always a missing display: flex on a container.

The two mistakes that silently produce a garbage PNG (a CSS dump, or unstyled text) rather than an error are now caught up front: passing a <style> block or a raw CSS stylesheet as the html throws with a message telling you to inline the styles. Satori's own cryptic "explicit display: flex" layout error is also rewritten to say which element needs the display. So a bad render fails loud instead of shipping something broken.

How it works

  1. satori-html parses your HTML string into the node tree Satori expects.
  2. satori lays it out and emits an SVG, embedding glyphs as vector paths.
  3. resvg rasterizes that SVG to PNG at your chosen scale.

Because glyphs are embedded as paths, the rasterizer needs no fonts of its own — the output is deterministic across machines.

License

MIT