Skip to content

Theme format

A .peltontheme file is a zip archive. At its root sits a manifest.json, everything else it references (token files, CSS, icon SVGs, a preview image) lives alongside it inside the same archive.

manifest.json

Only manifestVersion, name, and base are required, everything else has a sensible default or is simply omitted.

Field Type Required Notes
manifestVersion number yes Must be 1. A container declaring a newer version than Pelton understands is refused outright, this is a hard format check, not a warning.
name string yes Display name shown in the theme list.
base string yes "light" or "dark". Sets which built-in tokens a theme doesn't override fall back to.
id string no Lowercase slug (a-z0-9-), used as the theme's folder-safe identifier. Auto-derived from name if omitted.
author string no Shown in the theme list and the import preview.
version string no Your own version string for the theme, free-form.
description string no Shown in the import preview and the gallery.
homepage string no Link shown in the theme list, if set.
license string no Shown in the theme list, if set.
pelton object no {"min": "...", "max": "..."}, an app-version range the theme was made for. Being outside this range only shows a warning banner on import, it never blocks installation.
tokens array or object no Either a list of token-file paths (merged in order, later files win) or a single inline {token: value} object for a one-file theme. See Tokens.
css array of strings no CSS file paths, concatenated in this exact order into one injected stylesheet.
preview string no Path to a screenshot image, shown in the theme list and the gallery.
icons object no Maps an icon name to an SVG file path. See Icons.

Tokens

Only the tokens below can be overridden. Spacing and density tokens are deliberately not themeable, they're a separate setting, and a theme overriding them would mess with it and break layouts.

Group Tokens
Surfaces surface-base, surface-raised, surface-overlay, surface-sunken, surface-hover, selection-bg, selection-bg-strong
Text text-primary, text-secondary, text-tertiary, text-inverse, link
Borders border-subtle, border-default, border-strong, hairline
Accent accent, accent-fg
Semantic success, success-bg, warning, warning-bg, danger, danger-bg
Radii radius-control, radius-card, radius-none
Fonts font-ui, font-mono
Type sizes fz-meta, fz-label, fz-list, fz-body, fz-heading, fz-title
Font weights fw-regular, fw-medium, fw-semibold, fw-bold
Elevation shadow-overlay

A token value can be anything a CSS custom property normally holds, colors, color-mix(), font stacks, sizes, shadows, up to 300 characters. It can't contain ; { } < > @ \, control characters, or url(...), this keeps a token value from escaping into a CSS rule or fetching something.

CSS

Anything the token list doesn't cover can go in a theme's CSS files, there's no allowlist for CSS the way there is for tokens. They're concatenated in the order listed under css and injected after Pelton's own stylesheet, so they win on specificity without !important.

CSS can technically reach spacing too, but overriding it messes with the user's own density setting, so it's best left alone, see Create a theme for the full reasoning.

A url() inside your CSS that points outside the theme file itself (a remote font, a remote image) is flagged: on import, Pelton shows an explicit warning and defaults to blocking it, the user can choose to allow it, but nothing loads silently.

Icons

icons maps a Tabler icon name (the name Pelton uses internally, lowercase and kebab-case, with the Icon prefix dropped) to an SVG file path in your container. Draw icons with currentColor so they follow the surrounding text color rather than a fixed one.

Every icon SVG is sanitized before use: no <script>, no event-handler attributes (onclick= and friends), no javascript: links, no <iframe>, <foreignObject>, <embed>, <object>, <use>, or <animate> elements, no href/xlink:href, no url() or @import, and no DOCTYPE/ENTITY declarations. Anything else valid in plain SVG markup is fine.

Size limits

Limit Value
Container file (compressed) 20 MB
Any single file 10 MB
All CSS files combined 1 MB
One icon SVG 256 KB
One bundled asset (font, image), inlined 5 MB
Number of files in the archive 512
One token value 300 characters

A complete example

manifest.json, based on Pelton's bundled Nord theme, keeps only metadata and points at a separate token file:

{
  "manifestVersion": 1,
  "id": "nord",
  "name": "Nord",
  "author": "Pelton",
  "version": "1.0",
  "description": "Cool arctic dark palette based on Nord by Sven Greb.",
  "license": "MIT",
  "base": "dark",
  "tokens": ["tokens/colors.json"]
}

tokens/colors.json, a plain {token: value} object:

{
  "surface-base": "#2e3440",
  "surface-raised": "#3b4252",
  "surface-overlay": "#434c5e",
  "surface-sunken": "#272c36",
  "surface-hover": "#404a5c",
  "text-primary": "#eceff4",
  "text-secondary": "#d8dee9",
  "text-tertiary": "#8b95a7",
  "border-subtle": "rgba(216, 222, 233, 0.1)",
  "border-default": "rgba(216, 222, 233, 0.16)",
  "border-strong": "rgba(216, 222, 233, 0.28)",
  "success": "#a3be8c",
  "success-bg": "color-mix(in srgb, #a3be8c 16%, transparent)",
  "warning": "#ebcb8b",
  "warning-bg": "color-mix(in srgb, #ebcb8b 16%, transparent)",
  "danger": "#bf616a",
  "danger-bg": "color-mix(in srgb, #bf616a 16%, transparent)"
}

tokens also accepts a single inline object instead of a file list, the engine supports it, but keeping colors in their own file is easier to maintain and is what every example on this site uses. See Create a theme for the full folder layout, including where CSS files fit in.

Need help?

See Support.