Skip to content

Configuration

Shotty has two config layers: a project-local file and a user-wide fallback. They're designed to do different jobs and don't mix.

The two layers

Project-local: ./shotty.toml

Lives at the root of the project you're working in. Holds the project's render targets — every screenshot you want to keep in sync — plus any defaults that should apply across those targets.

User-wide: ~/.config/shotty/shotty.toml

Lives in your home directory. Holds personal preferences — the font you like, your favourite scale factor — that should apply across every project.

[[shot]] entries here are ignored. Render targets belong to a specific project; we don't want shots from one repo silently running when you're cd'd into another.

Where shotty looks

For each invocation, shotty picks one config in this priority order:

  1. --config PATH — explicit override. Loaded verbatim, shots and all.
  2. ./shotty.toml in the cwd. Loaded verbatim.
  3. ~/.config/shotty/shotty.toml. Loaded with [[shot]] stripped — defaults only.
  4. Built-in defaults. No file.

If layer 2 exists, layer 3 is not consulted — the cwd file wins outright. The two configs aren't merged.

How options resolve

Within whichever config is active, each setting's effective value is chosen top-down:

  1. CLI flag — highest priority, only relevant for ad-hoc shotty "..." invocations.
  2. Per-shot override in the active config.
  3. Top-level default in the active config.
  4. Built-in default.

So shotty --font Hack "ls" uses Hack regardless of what shotty.toml says, but shotty --render-all running over a [[shot]] uses the shot's font if set, else the top-level config default, else Menlo-Regular.

Typical setups

Personal preferences only

~/.config/shotty/shotty.toml:

font = "CascadiaCode-Regular"
font_size = 14
line_height = 1.3

Every ad-hoc shotty "..." invocation anywhere on your machine now picks up this font, unless the cwd has its own shotty.toml (in which case the home file is bypassed entirely).

A project with doc shots

./shotty.toml at the project root:

font = "Menlo-Regular"
snug = true

[[shot]]
output = "docs/images/help.png"
command = ["myapp", "--help"]

[[shot]]
output = "docs/images/build.png"
command = "myapp build 2>&1 | head -20"
width = 100

shotty --render-all regenerates both shots using Menlo-Regular, even if your home config prefers Cascadia. Project consistency wins.

Both at once

You have personal defaults in ~/.config/shotty/shotty.toml, then you cd into a project that has its own shotty.toml. The home file is now bypassed completely. If you want a personal preference to also apply inside the project (e.g. you always want scale = 3), you have to add it to the project's file too.

This is intentional: a maintainer reading the project's config should see the full set of decisions that produce its screenshots, not have to also know about the contributor's personal home config.

Named styles

Loose visual keys at the top level of shotty.toml are one default style. You can also define named styles in [styles.<name>] tables and reference them from individual shots — handy when a project has shots that should look noticeably different from each other (a wide build log, a square code shot, a chromeless embed) without repeating the same flag bundle on every entry.

default_style = "docs"

[styles.docs]
font = "Menlo-Regular"
font_size = 13
snug = true

[styles.code]
font = "CascadiaCode-Regular"
font_size = 14
line_height = 1.3
width = 100

[styles.headless]
shadow = false
title = ""              # empty string hides the title bar text
margin = 0

[[shot]]
output = "docs/images/help.png"
command = ["myapp", "--help"]
                                # uses default_style ("docs")

[[shot]]
output = "docs/images/main.png"
style = "code"
command = "bat -p src/main.swift"

[[shot]]
output = "docs/images/hero.png"
style = "code"                  # base style…
title  = "main.swift"           # …with a per-shot tweak

What's a "style key"

Styles hold visual settings — anything that controls what the screenshot looks like. The keys allowed in a [styles.<name>] table are: width, height, max_height, font, font_size, line_height, margin, scale, snug, shadow, title. Behavior keys (timeout, embed_command) and content keys (title, command, output) don't belong in a style — they're per-shot.

Resolution order with styles

For each visual key, the value used is chosen top-down:

  1. CLI flag (only relevant for ad-hoc commands).
  2. Per-shot key in the [[shot]] table.
  3. Active style's value for that key.
  4. Loose top-level key at the root of the config.
  5. Built-in default.

The "active style" is whichever name is in scope: shot's style = "...", otherwise default_style, otherwise none. The CLI's --style <name> overrides both the per-shot style and the config's default_style, so you can quickly preview every shot with a different style:

shotty --style headless --check       # how does everything look chromeless?

A reference to a style that doesn't exist (in any of the three layers) is an error — typos get caught at startup, not silently fall through.

Bypassing the cascade

--config PATH short-circuits everything. The given file is loaded as-is — including its [[shot]] entries — regardless of cwd or home. Useful for one-off bulk renders against a non-default config:

shotty --config docs/release-shots.toml

See also