v1.0.0

Dynamic images

$assets.render draws a partial as an image, and returns the URL path of that image. Use it for any image that comes from your page data: a banner for each post, a badge for each tag, or a social card for each page.

layouts/blog/single.hbshbs
{{#var file = 'banners/' + $utils.slug($page.title) + '.png'}}
{{#var banner = await $assets.render('banner', file, { width: 1600, height: 400 })}}
<img src="{{ banner }}" width="1600" height="400" alt=""/>

For a social card on each page, see Open Graph images. It builds on this guide.

Install

bongo draws the image with Satori, and converts the drawing to pixels with resvg. They are optional peer dependencies, so add them to your site:

Shell
bun add -d satori @resvg/resvg-js

SVG output needs only satori. If a package is missing, the build fails and tells you what to install.

Arguments

Handlebars
{{#var url = await $assets.render(template, output, options)}}
  • template — the name of a partial, such as og/card for partials/og/card.hbs.
  • output — optional. The path of the image in public/, such as og/home.png. The extension sets the format. Without output, the image is a PNG with a name from its partial and its content, such as card.3f9a1c2e.png.
  • options.width, options.height — the size in pixels. The defaults are 1200 and 630, the size of a social card.
  • options.args — values for the partial, as the attributes of {{#partial}} are.

The partial gets the $page, $pages, $section, and $tags of the page that calls $assets.render. This is also true when a layout or another partial calls it.

The return value is a URL path, such as /og/home.png. On a site under /blog/, it starts with /blog/. Use $utils.url.abs() to make a full URL.

Without output, the name changes when the image changes. Thus a host can cache these images for a long time, as it does other hashed files.

Formats

Extension Made with Runtimes
.svg Satori Bun, Deno, and Node
.png Satori and resvg Bun, Deno, and Node
.jpg, .jpeg, .webp Satori, resvg, and Bun.Image Bun only

JPEG and WebP use Bun.Image, as image processing does. Thus they need the Bun runtime. Under Deno or Node, they fail the build. Their quality comes from $images.quality.

The template

A render template is a partial with one root element. Satori draws a subset of HTML and CSS, with flexbox layout. See the Satori documentation for the CSS that it supports.

partials/banner.hbshbs
<style>
	@font-face { font-family: Inter; src: url(fonts/inter-700.woff); font-weight: 700 }
</style>
<div style="display: flex; flex-direction: column; justify-content: flex-end; width: 100%; height: 100%; padding: 64px; box-sizing: border-box; background: #ffd23f; font-family: Inter">
	<img src="img/logo.svg" width="120" height="40">
	<div style="margin-top: 16px; font-size: 80px">{{ $page.title }}</div>
	<div style="margin-top: 12px; font-size: 28px">{{ $utils.excerpt($page.summary, 100) }}</div>
</div>
  • Set styles with the style attribute. Classes and stylesheets have no effect.
  • Give a box with padding box-sizing: border-box, or Satori adds the padding to its width.
  • Put an element in place with left and top. Satori does not always obey right and bottom.
  • An inline <svg> needs a width and a height.

Fonts

Declare each font with an @font-face rule, in a <style> element of the template. The src is a path in assets/. bongo reads the rules, then removes the <style> element. A <style> element may hold only @font-face rules.

Satori reads TTF, OTF, and WOFF files, but not WOFF2. bongo uses the first src that is not WOFF2. A template with text must declare one font or more. The font files are not copied to public/.

Images

An <img src> or a CSS url() with a path reads that file from assets/. bongo puts the contents of the file into the drawing. A remote URL stays as it is: Satori gets it when it draws. The cache knows only its URL, so a changed remote image does not make a new drawing.

Dev and cache

bongo build draws all the images. bongo dev draws an image at its first request.

bongo keeps each drawing in node_modules/.cache/bongo/render. The key is a hash of the drawing, the fonts, the images, the size, the format, and the versions of Satori, resvg, and Bun. A rebuild copies unchanged images from the cache. $images.prune also cleans this folder. To clear the cache, delete the folder.

Errors

The build fails with a message that names the cause when:

  • two pages draw different images to the same output;
  • output is a file of the site, or a path outside public/;
  • the template has no root element, or more than one;
  • the template has text, but declares no fonts;
  • a font is WOFF2, or a file is not in assets/;
  • a <style> element holds rules other than @font-face.
Edit this page on GitHub MIT license · bongo v1.0.0

    Type to search page titles and sections.