Perch
Building modsThemes

Themes

A theme is a package too: a validated set of color and shadow tokens declared in mod.json, selectable under Appearance.

3 min readUpdated Sep 7, 2026

A theme recolors Perch: the island, surfaces, text tiers, accents, rims and shadows. Geometry, radii, spacing and typography stay Perch’s. Themes are declared in mod.json as pure data; a package may ship themes alone, or themes alongside widgets.

{
  "id": "nord-theme",
  "title": "Nord",
  "version": "1.0",
  "api": 3,
  "themes": [
    {
      "id": "nord",
      "label": "Nord",
      "tokens": {
        "island": "#2e3440",
        "surface_recessed": "#3b4252",
        "surface_raised": "#434c5e",
        "text_primary": "#eceff4",
        "text_secondary": "rgba(236, 239, 244, 0.62)",
        "accent": "#88c0d0",
        "accent_warm": "#d08770",
        "live": "#a3be8c",
        "rim": "inset 0 0 0 1px rgba(255, 255, 255, 0.08)"
      }
    }
  ]
}

A package needs no entry file to ship only themes; mod.json with themes is a complete package.

The token card in the default theme

The token card in the midnight theme

The token card in the plum theme

The token card in the high-contrast theme

Fields

FieldRule
id[a-z-], 1 to 24 characters (theme ids are [a-z-]{1,24})
labelthe name in the Appearance picker; defaults to the id
tokensan object of token name to value; any token may be omitted and keeps Perch’s default

Tokens

Colors accept #rgb to #rrggbbaa and rgb(...) / rgba(...). Shadows accept a CSS shadow value (up to 160 characters; digits, letters, #, ( ) , . - % and spaces).

TokenWhat it colors
islandthe notch and panel background
surface_recessedinset surfaces: boxes, buttons, bar tracks
surface_raisedraised surfaces: popups, chips
surface_deepthe deepest inset (the clock dial)
text_primarythe brightest text tier
text_secondarythe second tier (sub, label roles)
text_halfthe half-strength tier
text_tertiarythe faintest tier
accentthe primary accent
accent_warmthe warm accent
livethe green: presence, speaking rings, positive deltas
fillthe generic filled element (bar fills)
trackbar and ring tracks
dangerthe red
hairlinedividers
rimthe inset hairline on border = ui.border.rim (shadow value)
rim_strongthe stronger rim (shadow value)
shadow_islandthe notch’s drop shadow (shadow value)
shadow_floatshadow = ui.shadow.float (shadow value)
shadow_recessshadow = ui.shadow.recess (shadow value)

Any other key fails the load with theme <id>: unknown token '<key>' (colors+shadows only); a value that does not parse fails with theme <id>: bad value for '<key>'. A rejected theme never reaches the picker and cannot take the overlay down.

How themes and widgets meet

Widgets that use role tokens and palette names follow the active theme automatically; hex literals do not. A theme may also remap a mod’s @palette colors wholesale. Exactly one theme is active at a time, chosen under Settings, Appearance; Perch’s own black is the permanent fallback.

Perch ships three themes as builtin packages (midnight, plum, high-contrast): read them for complete token sets.

esc
Type to search
navigate open