Skip to content

Make a theme

A theme is the easiest add-on to make: two small JSON files and no code. This guide makes Lagoon, a teal-and-sand theme, from an empty folder to running on your server.

1. Pick what to change

A theme only sets the tokens it wants to change; everything else keeps Budvo's colors. Most themes change the accent, and many also tint the surfaces. Here's every token with Budvo's own values:

TokenUsed forLight defaultDark default
bgPage background#f7f7f5#0a0b0d
surfaceCards, panels and the sidebar#ffffff#111316
surface-2Inputs, hovered rows and areas inside cards#f1f1ee#16191d
surface-3Stronger fills: selected items, pressed states, tracks#e9e9e5#1d2126
lineHairline borders and dividersrgb(15 17 20 / 0.08)rgb(255 255 255 / 0.07)
line-strongBorders that need to be seen, like inputsrgb(15 17 20 / 0.14)rgb(255 255 255 / 0.13)
fgMain text and numbers#0e0f11#eceef0
fg-2Secondary text#3b3f45#c3c7cd
mutedLabels and captions#6b7079#8a9099
faintPlaceholders, disabled text and hints#9a9fa7#5c626b
accentButtons, links, focus rings and highlightsoklch(0.6 0.105 184)oklch(0.8 0.11 182)
accent-softTinted backgrounds behind accent content (translucent)oklch(0.6 0.105 184 / 0.1)oklch(0.8 0.11 182 / 0.12)
accent-fgText and icons on the accent color#ffffff#06201d
positiveMoney in, on track, paidoklch(0.58 0.13 155)oklch(0.78 0.14 155)
negativeOverdue, over budget, debtoklch(0.58 0.17 25)oklch(0.72 0.16 25)
warningDue soon, needs a lookoklch(0.72 0.14 75)oklch(0.83 0.13 80)
glowSoft light behind highlights (translucent)oklch(0.8 0.09 184 / 0.35)oklch(0.55 0.1 184 / 0.28)

A good start is the four accent tokens in both modes: accent, accent-soft, accent-fg and glow. Change surfaces once the accent feels right.

2. Make the folder

text
theme-lagoon/  manifest.json  theme.json

manifest.json:

json
{  "$schema": "https://budvo.nulldaily.com/schemas/addon-manifest-v1.json",  "manifest": 1,  "id": "theme-lagoon",  "name": "Lagoon",  "version": "1.0.0",  "kind": "theme",  "runtime": "theme@1",  "publisher": "You",  "summary": "Warm sand in the light, deep teal water in the dark.",  "compat": { "budvo": ">=0.2.0 <1.0.0" },  "entry": "theme.json",  "permissions": [],  "tags": ["teal", "warm"]}

3. Set the accent in both modes

Write colors in oklch(lightness chroma hue): keeping the hue and changing the lightness gives you a matching family of colors, which is exactly what light and dark mode need.

json
{  "light": {    "accent": "oklch(0.55 0.11 200)",    "accent-soft": "oklch(0.55 0.11 200 / 0.1)",    "accent-fg": "#ffffff",    "glow": "oklch(0.8 0.08 200 / 0.35)"  },  "dark": {    "accent": "oklch(0.78 0.11 195)",    "accent-soft": "oklch(0.78 0.11 195 / 0.13)",    "accent-fg": "#04191c",    "glow": "oklch(0.5 0.1 200 / 0.3)"  }}
  • accent is buttons, links, focus rings and progress bars. In dark mode make it lighter and a touch less saturated than in light mode.
  • accent-soft is the same color at 10 to 14% opacity, for tinted backgrounds.
  • accent-fg is text on the accent: white on a mid-tone light-mode accent, and a very dark, slightly tinted color on a bright dark-mode accent.
  • glow is a soft light behind highlights: lighter in light mode, deeper and more saturated in dark mode, always translucent.

Only colors are allowed: #rgb, #rrggbb, #rrggbbaa, rgb(...) and oklch(...).

4. Tint the surfaces (optional)

Surfaces are where a theme gets its mood. Keep them in lightness order, each a small step from the last: bg, then surface, surface-2 and surface-3.

json
{  "light": {    "bg": "#f8f5ef",    "surface-2": "#f2eee6",    "surface-3": "#e9e3d8"  },  "dark": {    "bg": "#061214",    "surface": "#0b1a1d",    "surface-2": "#102226",    "surface-3": "#162b30",    "line": "rgb(160 235 240 / 0.08)",    "line-strong": "rgb(160 235 240 / 0.14)"  }}

Merge these into the accent tokens from step 3, so each mode is one object.

5. Check contrast, especially in dark mode

Dark themes go wrong in predictable ways. A few rules keep yours readable:

  • Not pure black, not pure white. Use a near-black with a hint of your hue for bg (like #061214) and an off-white for fg (like #e8f0f0). Pure black and white vibrate against each other.
  • Aim for these contrast ratios against surface: 7:1 or more for fg, 4.5:1 for fg-2 and muted, and 3:1 for faint. Check accent-fg on accent at 4.5:1 too.
  • Step the surfaces gently. Each surface a few percent lighter than the one below it. Big jumps make cards look like holes.
  • Use translucent lines. rgb(255 255 255 / 0.07) style lines adapt to whatever surface they sit on. A tint of your hue works nicely.
  • Lower the chroma. Saturated colors glow on dark backgrounds. Keep the hue, raise the lightness and lower the chroma a little compared with light mode.
  • Leave money colors alone. positive, negative and warning mean income, overdue and due soon everywhere in Budvo. If you do change them, keep them green, red and amber and check their contrast.
  • Debt mode wins. While debt mode is on, Budvo's red theme replaces your accent. Nothing to do; just don't be surprised.

Your browser's developer tools show the contrast ratio of any text, and WebAIM's checker works with hex colors.

6. Preview and check it

Try colors in the playground on the Runtimes page, then check the files:

terminal
npx budvo-addon validate theme-lagoon

To see it on your own dashboard, sideload the folder, press Rescan and pick the theme.

7. Share it

When you're happy with it, send it in to be listed on the marketplace. The catalog draws a light and dark swatch icon from your tokens, so a theme doesn't need an icon of its own.