← Back to Plugins
Tools

Html To Image

clawnify By clawnify 👁 47 views ▲ 0 votes

OpenClaw plugin — render an HTML string to a PNG file on disk (Satori + resvg, no headless browser). Gives agents an html_to_image tool for status cards, summaries and simple charts.

GitHub

Install

openclaw plugins install @clawnify/html-to-image

Configuration Example

"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 }
  ]
}

README

# @clawnify/html-to-image

> Built and open-sourced by **[clawnify.com](https://clawnify.com)** to benefit the OpenClaw ecosystem. It works with **any OpenClaw agent** — there's nothing Clawnify-specific about it.

An [OpenClaw](https://github.com/openclaw/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](https://github.com/vercel/satori) (HTML/CSS → SVG) and [resvg](https://github.com/thx/resvg-js) (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)

```bash
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.

## Use as a library

```ts
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 }`.

## 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:

```jsonc
"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.
- Text uses the bundled **Inter** (latin). Pass your own `fonts` for other families or scripts.
- Emoji are not painted unless you supply an emoji font or grapheme images.

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

## 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
tools

Comments

Sign in to leave a comment

Loading comments...