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:
| Token | Used for | Light default | Dark default |
|---|---|---|---|
bg | Page background | #f7f7f5 | #0a0b0d |
surface | Cards, panels and the sidebar | #ffffff | #111316 |
surface-2 | Inputs, hovered rows and areas inside cards | #f1f1ee | #16191d |
surface-3 | Stronger fills: selected items, pressed states, tracks | #e9e9e5 | #1d2126 |
line | Hairline borders and dividers | rgb(15 17 20 / 0.08) | rgb(255 255 255 / 0.07) |
line-strong | Borders that need to be seen, like inputs | rgb(15 17 20 / 0.14) | rgb(255 255 255 / 0.13) |
fg | Main text and numbers | #0e0f11 | #eceef0 |
fg-2 | Secondary text | #3b3f45 | #c3c7cd |
muted | Labels and captions | #6b7079 | #8a9099 |
faint | Placeholders, disabled text and hints | #9a9fa7 | #5c626b |
accent | Buttons, links, focus rings and highlights | oklch(0.6 0.105 184) | oklch(0.8 0.11 182) |
accent-soft | Tinted backgrounds behind accent content (translucent) | oklch(0.6 0.105 184 / 0.1) | oklch(0.8 0.11 182 / 0.12) |
accent-fg | Text and icons on the accent color | #ffffff | #06201d |
positive | Money in, on track, paid | oklch(0.58 0.13 155) | oklch(0.78 0.14 155) |
negative | Overdue, over budget, debt | oklch(0.58 0.17 25) | oklch(0.72 0.16 25) |
warning | Due soon, needs a look | oklch(0.72 0.14 75) | oklch(0.83 0.13 80) |
glow | Soft 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
theme-lagoon/ manifest.json theme.jsonmanifest.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.
{ "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)" }}accentis buttons, links, focus rings and progress bars. In dark mode make it lighter and a touch less saturated than in light mode.accent-softis the same color at 10 to 14% opacity, for tinted backgrounds.accent-fgis 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.glowis 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.
{ "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 forfg(like#e8f0f0). Pure black and white vibrate against each other. - Aim for these contrast ratios against
surface: 7:1 or more forfg, 4.5:1 forfg-2andmuted, and 3:1 forfaint. Checkaccent-fgonaccentat 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,negativeandwarningmean 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:
npx budvo-addon validate theme-lagoonTo 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.