A theme controls how a generated pinout looks and behaves around the connectors — colors, fonts, the connector list, symbols, and a few responsive behaviors. The connector diagrams and pin colors themselves are board data and stay the same across themes; a theme restyles the page, the tooltips, and the list.
Themes are bundled with pinout-gen the same way connector types are, and you can add your own.
Set the board's theme in the [board] table of your board config:
[board]
title = "My Board"
image = "board.png"
width = 1920
height = 1080
theme = "midnight"Or override it on the command line (this wins over the board's theme):
pinout-gen board.toml --theme oceanPrecedence is --theme → [board] theme → default. A theme name is resolved from the board's theme_dir (default ./themes, next to the config) first, then from the themes bundled with the package. An unknown name is an error naming both places it looked.
| Theme | Look |
|---|---|
default |
The stock light/dark palette with Roboto. What you get with no theme. |
slate |
Cool blue-gray, Glegoo — a serif face. |
ocean |
Teal and cyan, Lexend. Roomy: larger list text and symbols, and the list always sits below the board. |
terminal |
Green and pixel-monospaced (Geist Pixel), connector list open by default, symbols off. |
midnight |
Indigo/violet, Inter UI with a monospaced pin-label font. Stacks below 720px. |
workbench |
Warm neutrals with an amber accent, Inter. The pinout shows in a permanent panel under the board instead of a tooltip; list open, stacks below 900px. |
Every theme provides both a light and a dark palette. See Light and dark mode for how the page chooses between them.
The generated pinout has no light/dark control of its own — it takes the scheme from its surroundings. On load it decides like this:
- A
?theme=parameter. Openingboard.pinout.html?theme=dark(or?theme=light) pins that scheme and stops the page from following its surroundings. Handy for linking straight to one, or for an iframe you always want dark. - The embedding page, when the pinout is embedded from the same origin. It reads MkDocs Material / Zensical's
data-md-color-scheme(whereslatemeans dark), a genericdata-theme="dark"|"light", or adarkclass on<html>/<body>— and keeps watching, so flipping your docs site's toggle re-colors the embedded pinout live. This needs same-origin access, so it does not apply across origins. - The reader's OS preference (
prefers-color-scheme), when neither applies.
A parent page can also set the scheme at any time by posting to the iframe, which is how a cross-origin embed drives it:
iframe.contentWindow.postMessage({ pinconnectTheme: "dark" }, "*");Send "light" or "dark" to set the scheme — this takes effect immediately and overrides all of the above, including ?theme=. Any other value clears the override and hands control back to the reader's OS preference.
The same board in each bundled theme, light and dark. Every shot has the connector list open and one connector selected, so the list, tooltip and pin-label styling are all visible — default and slate ship with the list collapsed until you press the ☰ button.
| Light | Dark |
|---|---|
![]() |
![]() |
| Light | Dark |
|---|---|
![]() |
![]() |
Ocean sets sidebar_stack_breakpoint = 6000, so the connector list is stacked below the board at any window width. These shots are full-page to show it.
| Light | Dark |
|---|---|
![]() |
![]() |
| Light | Dark |
|---|---|
![]() |
![]() |
| Light | Dark |
|---|---|
![]() |
![]() |
Warm neutrals with an amber accent and Inter. This one demonstrates tooltip_placement = "panel": instead of a floating tooltip, each connector's pinout appears in a permanent box under the board, which shows the hint and credit until a connector is chosen. The list is open by default and stacks below 900px.
| Light | Dark |
|---|---|
![]() |
![]() |
A theme is a TOML file whose name is the theme name (midnight.toml defines midnight). Every field is optional and merges over the built-in defaults, so a theme only states what differs. A minimal theme is just a name:
[theme]
name = "My Theme"name is the display name — what the designer's Theme dropdown shows. It defaults to the file's own name, so it is only worth setting when you want something friendlier than the filename. Boards and --theme always refer to a theme by its filename, not this.
CSS color values (hex, rgb(), rgba(), …). Token names are the generated CSS variables without the leading --. light applies in light mode, dark in dark mode.
| Token | What it colors |
|---|---|
bg |
Page background |
text |
Primary text |
tip-bg |
Tooltip and connector-list background |
tip-border |
Tooltip / list border |
tip-shadow |
Tooltip / list shadow |
hs-hover, hs-stroke, hs-active |
Hotspot hover fill, outline, and pinned fill |
hint-bg, hint-text |
Hint pill background / text |
divider |
Divider lines |
conn-body, conn-cavity, conn-stroke |
Connector housing fill, cavity fill, outlines |
line-color |
Pin lead lines |
label-color |
Pin label text (and connector symbols) |
desc-color |
Connector description text |
type-color |
Connector type / pin-count text |
scroll-thumb, scroll-track |
Themed scrollbar thumb and track |
[colors.light]
bg = "#f8fafc"
text = "#0f172a"
hs-stroke = "rgba(37,99,235,.55)"
conn-body = "#e8edf3"
[colors.dark]
bg = "#0b1220"
text = "#e2e8f0"Setting bg = "transparent" in both palettes lets an embedded pinout take the background of whatever it sits in — an admonition, a card, the page itself — instead of painting its own.
The generated page declares a color-scheme to match the palette it is showing, which is what browsers require before they will let an iframe stay transparent over a host page in the opposite mode.
Names outside this table are not rejected — they are emitted as CSS variables too. Defining my-accent in both palettes gives you var(--my-accent) to use from [extra_css], with light/dark switching handled for you.
Values are checked as they load. A bare hex with no # (bg = "f8f8f8") is not valid CSS — the browser drops the declaration that uses it and paints the element transparent instead — so pinout-gen adds the # for you and prints a warning. A value that is no recognizable color at all (a misspelled gray, say) is left alone but still warned about, since it would silently leave that element unstyled. Both are warnings, not errors: the page is still written. The designer shows the same warnings in its Generate dialog.
Only the tokens in the table above are checked this way. A name outside it may legitimately hold any CSS your [extra_css] wants, so only the missing-# repair applies there.
The UI font, and optionally a separate font for the pin labels in the connector diagrams.
| Key | Meaning |
|---|---|
family |
Font family name |
source |
google (loaded from Google Fonts), bundled (a font file embedded in the output as base64, keeping it self-contained), or system (family is used verbatim as a CSS stack) |
weights |
Weights to request, e.g. "400;500;600" — google only |
file |
Path to the font file relative to the theme, e.g. "inter.woff2" — bundled only |
[font.label] takes the same keys and defaults to [font] when omitted.
[font]
family = "Inter"
source = "google"
weights = "400;500;600"
[font.label]
family = "JetBrains Mono"
source = "google"
weights = "400;500"| Key | Default | Effect |
|---|---|---|
sidebar_default_open |
false |
Start with the connector list shown |
sidebar_max_width |
340 |
Max list width in px; the panel sizes to its content up to this (and 40vw), wrapping only if longer |
sidebar_responsive_stack |
false |
Below the breakpoint, the list moves below the board and animates open/closed |
sidebar_stack_breakpoint |
640 |
Width in px at/under which stacking kicks in |
show_symbols |
true |
Show per-connector symbols; false hides them even if set on the board |
symbol_style_fallback |
false |
Give symbol-less connectors a default icon based on their type's style |
font_scale |
1.0 |
Scale the list / tooltip / bottom-bar text |
symbol_size |
16 |
Connector-symbol icon size in px |
tooltip_box_scale |
1.5 |
Tooltip drawing's long side, as a multiple of the connector's box on the board. 0 pins it to its natural size |
tooltip_min_scale |
0.5 |
Smallest fraction of natural size the drawing may shrink to |
hint_autohide |
0 |
Seconds before the "Click or tap a connector" hint fades out, leaving the PinConnect credit (to make it smaller); the first hover or tap on a connector hides it too. 0 keeps it |
hint_placement |
"overlay" |
Where the hint pill sits: "overlay" floats it over the bottom edge of the board area to make the layout more compact, "below" puts it in flow under the board so it can never cover a connector |
tooltip_placement |
"auto" |
"float" keeps the tooltip beside its connector, "below" always parks it under the board, "auto" parks it below on narrow screens when the board is short enough to leave room and floats otherwise, "panel" replaces the tooltip with a permanent box under the board |
tooltip_below_breakpoint |
768 |
Width in px at/under which "auto" may place tooltips below the board |
tooltip_max_width |
420 |
Tooltip box max width in px; always capped by the viewport width |
tooltip_panel_min_height |
0 |
Floor in px for the "panel" box; it is otherwise exactly as tall as the tallest connector's pinout, so it never scrolls |
fullscreen_button |
true |
Show a fullscreen button beside the list toggle (see below) |
[behavior]
sidebar_default_open = true
sidebar_responsive_stack = true
sidebar_stack_breakpoint = 720
font_scale = 1.1Tooltip sizing. The connector drawing in a tooltip is sized from the connector's box on the board rather than a fixed pixel size, so it shrinks along with the board instead of covering it on a small screen. It tracks the board live — resizing the window or opening the list re-fits the open tooltip. Two bounds keep it sane: it never grows past the drawing's natural size (so wide screens look exactly as they did before), and never shrinks below
tooltip_min_scaleof it (so pin labels stay readable). Raisetooltip_box_scalefor larger tooltips, or set it to0to opt out entirely.
Panel mode. With
tooltip_placement = "panel"there is no floating tooltip: a permanent box sits under the board, beside a full-height connector list on wide screens and between the board and the list when stacked.hint_placementhas no effect in this mode, since the hint lives in the panel.
Fullscreen. The button beside the list toggle puts the pinout into the browser's fullscreen mode, so an embedded pinout gets the whole screen and, on a wide one, the side-by-side layout. Where element fullscreen is not available (iPhone Safari, or an embedding page whose iframe does not allow it; pinout-embed does) it opens the pinout in a new tab instead, which also gives pinch-zoom on phones. The button is removed when neither can work, and
fullscreen_button = falseremoves it always.
Responsive stacking and embedding. When the list stacks below the board, the pinout resizes itself to fit. If you embed it with pinout-embed, the iframe grows and shrinks to match — no fixed-height scrollbars. Use a recent
pinout-embedbuild for this.
A raw-CSS escape hatch appended after the generated variable blocks, for anything the tokens can't express. It is emitted verbatim, so it is a trusted, author-controlled surface — keep board data out of it.
[extra_css]
css = """
.bb { font-style: italic; }
"""- Copy
default.toml(it documents every token) to<name>.toml, and uncomment/override what you want to change. - Put it either in the bundled themes folder (
pinout_gen/pinout_gen/themes/, shipped with the package) or in a board-localtheme_dirnext to your board config (handy for a project- or site-specific theme you don't want to bundle). A board-local theme of the same name overrides a bundled one. - Reference it with
theme = "<name>"(or--theme <name>).
A theme in the bundled folder appears in the designer's Theme selector straight away, with nothing to regenerate: the designer reads the same files the generator does.
A board-local theme is a different matter. The designer has your config text but not your theme_dir, so it cannot load the theme, and it will render with the bundled theme of the same name or fall back to the default. It says so when that happens. Use the command line for those boards, or bundle the theme.
- Because tokens merge over the defaults, start from a couple of overrides (
bg,text, an accent) and add more only as needed. - Pin colors come from the board rather than the theme — a reader sees the same wire colors no matter which theme is applied.
- The designer shows a Theme selector in its toolbar; a custom theme name it doesn't know about is still preserved when you save.











