Brand and theming

Figures that match the document around them.

Reading _brand.yml inside a Typst block, and compiling a figure for both the light and the dark side of a page.

A compiled figure is an image, so it keeps the colours it was drawn with. The extension binds the document brand ahead of every block, as _typst_render_brand, so a figure can draw itself in the colours of the page instead. Two more bindings, _typst_render_background and _typst_render_foreground, carry the resolved colours. The Reference describes all three.

Brand colours

This page uses the pastel brand shared by these documentation sites. background: auto compiles the block once per colour scheme. The dictionary matches the side being compiled, so the swatches below change with the theme of the page:

#let roles = ("primary", "secondary", "tertiary", "success", "info", "warning", "danger")
#let colours = _typst_render_brand.color
#stack(
  dir: ltr,
  spacing: 4pt,
  ..roles
    .filter(role => role in colours)
    .map(role => rect(width: 1.4cm, height: 1.4cm, radius: 3pt, fill: rgb(colours.at(role)))),
)

#let roles = ("primary", "secondary", "tertiary", "success", "info", "warning", "danger")
#let colours = _typst_render_brand.color
#stack(
  dir: ltr,
  spacing: 4pt,
  ..roles
    .filter(role => rol

#let roles = ("primary", "secondary", "tertiary", "success", "info", "warning", "danger")
#let colours = _typst_render_brand.color
#stack(
  dir: ltr,
  spacing: 4pt,
  ..roles
    .filter(role => rol

Under color are nine semantic roles: foreground, background, primary, secondary, tertiary, success, info, warning, and danger. Under typography are the base and headings families.

A role the brand does not define stops the compilation, so read an uncertain one with a default:

#let accent = _typst_render_brand.color.at("tertiary", default: "#888888")

Light and dark

background and foreground take three shapes: a Typst colour, auto to read the brand, or a map with light and dark keys. auto and a map each carry two values, so the block is compiled twice in HTML output. The page then shows the image that matches its mode:

```{typst}
//| background: auto
//| foreground: auto
#align(center)[#text(size: 14pt)[This box follows the page.]]
```

#align(center)[#text(size: 14pt)[This box follows the page.]]

#align(center)[#text(size: 14pt)[This box follows the page.]]

Switch the theme of this page to see the pair swap.

A block option is one line of //| key: value, so an explicit light and dark pair is written in the document or project YAML instead, where it becomes the default for every block:

extensions:
  typst-render:
    background:
      light: "#FFF6E5"
      dark: "#20232A"
    foreground:
      light: "#20232A"
      dark: "#FFF6E5"

A plotting package

A package that reads _brand.yml takes the dictionary directly. Gribouille is one, from version 0.7.0:

```{typst}
#import "@preview/gribouille:0.7.0": *

#plot(
  data: (x: (1, 2, 3, 4), y: (2, 4, 3, 5), g: ("a", "b", "a", "b")),
  mapping: aes(x: "x", y: "y", colour: "g"),
  layers: (geom-point(size: 5pt),),
  theme: theme-brand(_typst_render_brand),
  width: 8cm,
  height: 5cm,
)
```

The Reference also describes what a brand written for one mode alone does in the other.

Back to top