| name | actual-budget-theme-builder |
| description | Build custom CSS themes for Actual Budget (the open-source personal finance app). Use this skill whenever the user wants to create, design, modify, or generate a color theme for Actual Budget — including when they mention "Actual Budget theme", "custom theme for Actual", "actual.css", or want to change the look and feel of their Actual Budget instance. Also trigger when users ask about Actual Budget CSS variables, theming, or color customization. This skill knows the complete set of 223 CSS variables and guides users through a brainstorming-driven design process to produce a valid actual.css file. |
Actual Budget Theme Builder
Build complete, valid custom CSS themes for Actual Budget through a guided design process.
Overview
Actual Budget supports custom themes via CSS files that override --color-* variables inside a single :root { } block. This skill guides the user through designing a theme, then generates a complete actual.css file covering all 223 theme variables — ensuring no elements fall back to the default navy/purple palette.
Before Starting
Read these reference files in this skill's directory:
references/variables.md — Every variable name, what it controls, and which need special handling. This is the authoritative list; any variable you skip will fall back to the default dark theme's navy/purple, creating jarring color mismatches.
references/dark.ts — The built-in dark theme source. Shows how the default theme maps palette colors to each variable, including alias relationships (e.g. buttonBareText = buttonNormalText). Useful as a structural reference when generating your own mappings.
Process
This is a creative design collaboration. Be enthusiastic about the user's vision, offer alternatives when something won't work well technically, and treat this like a design consultation — not a form to fill out.
Step 1: Understand the Vision
Gather the following information, adapting your approach to what the user has already told you. Use ask_user_input for structured questions when helpful. You don't need to ask all of these if the user has already provided direction.
Areas to explore:
- Base mood — What overall aesthetic? Deep black/OLED, warm dark, cool dark, light/airy, cyberpunk/neon, or something specific?
- Inspiration — Any reference images, screenshots, or apps they want to match? If they upload images, analyze them for background darkness levels, card/surface elevation strategy, text hierarchy, accent color, and status color style (vibrant vs muted).
- Accent color — What color for primary actions (buttons, links, selected states)? White, green, blue, purple, orange/gold, or custom?
- Chart palette — For data visualization: vibrant and colorful, muted pastels, or monochrome shades of one color?
- Specific requirements — e.g. "green for income and red for expenses", "match my terminal theme", "high contrast for accessibility"
If the user says "just do it" or gives minimal direction, make tasteful decisions and move forward.
Step 2: Design the Palette
Before writing CSS, establish foundation colors. This prevents making 223 independent color decisions and instead creates a coherent system:
BG_DEEP — Deepest background (page, sidebar)
BG_BASE — Standard surfaces (tables, budget columns)
BG_RAISED — Elevated surfaces (cards, modals, menus, dropdowns)
BG_HOVER — Hover states
BORDER — Standard borders
BORDER_ALT — Subtle/secondary borders
TEXT_PRIMARY — Main text
TEXT_SECONDARY — Secondary text
TEXT_MUTED — Subdued/tertiary text
TEXT_BRIGHT — Emphasized text (white or near-white)
ACCENT — Primary accent (buttons, links, selected states)
ACCENT_HOVER — Accent hover state
POSITIVE — Income / positive values (green family)
NEGATIVE — Expenses / negative values (red family)
WARNING — Warnings (orange family)
For light themes, invert the surface hierarchy: BG_DEEP becomes the lightest/white surface, BG_RAISED is slightly darker/shadowed. Ensure positive/negative colors have enough saturation to read against light backgrounds — pale greens and reds wash out on white.
Step 3: Generate Complete CSS
Cover every variable listed in references/variables.md. Any variable you skip will show the default navy/purple color, which looks broken in an otherwise custom theme.
Map your palette to every variable using these principles:
| Element | Maps to |
|---|
| Page/sidebar backgrounds | BG_DEEP |
| Table background, budget columns | BG_BASE |
| Cards, modals, menus, dropdowns, tooltips | BG_RAISED |
| Hover states | BG_HOVER |
| Category group rows, table headers | BG_RAISED or shade between BASE and RAISED |
| Budget current month header | Background tone or subtle accent-tinted shade |
| Budget other month headers | Neutral BG_BASE shade |
| All borders | BORDER or BORDER_ALT |
| Primary text, table text | TEXT_PRIMARY |
| Headers, labels, secondary text | TEXT_SECONDARY |
| Inactive sidebar, placeholders | TEXT_MUTED |
| Links, accents, selected states | ACCENT |
| Income, positive numbers, to-budget positive | POSITIVE |
| Expense, negative numbers, overbudgeted | NEGATIVE |
| Warnings, underfunded templates | WARNING |
| Notice/success backgrounds | Dark shade of POSITIVE |
| Error backgrounds | Dark shade of NEGATIVE |
| Warning backgrounds | Dark shade of WARNING |
Special handling (see references/variables.md for the full list):
- Positive/negative numbers — Use vivid, saturated shades (e.g.
#22C55E green, #EF4444 red). Pastels look washed-out in budget views where numbers need to pop. This applies to numberPositive, numberNegative, toBudgetPositive, toBudgetNegative, and all noticeText* colors.
- Tooltip variables —
tooltipBackground, tooltipText, tooltipBorder control dropdown menus and popovers too, not just tooltips. Treat as an elevated surface layer.
menuItemBackground — Must be solid, never transparent. Menus render over dark elements and transparent backgrounds cause black bleed-through.
- 3 ghost variables —
menuAutoCompleteTextHover, menuAutoCompleteItemTextHover, noticeTextMenuHover aren't in the dark theme defaults but exist in the source. Include them or autocomplete dropdowns fall back to default colors.
- rgba() values — Required for shadows, hover overlays, and the overlay backdrop. See
references/variables.md Important Notes for the full list.
- Transparent buttons —
buttonMenuBackground and buttonBareBackground should typically be transparent.
buttonPrimaryText — Must contrast with buttonPrimaryBackground. If bg is white/light, text must be dark.
- Segment controls (e.g. "Pre / Normal / Post" in rules) — The selected segment uses
pillBackgroundSelected for its background and buttonBareText for text. Set pillBackgroundSelected to an accent-toned background that contrasts well with buttonBareText. If your accent is dark, the bare text must be light (or vice versa) — otherwise the selected label becomes unreadable.
- Checkboxes — Checked state uses
checkboxBackgroundSelected for the fill and checkboxText for the check mark. Make sure these contrast well — a bright accent for the background with white or dark text works. If both are similar in luminance the check mark disappears.
Chart colors (chartQual1 through chartQual9) — 9 distinct, distinguishable colors for data visualization. Approaches:
- Vibrant: Pick 9 hues evenly spaced around the color wheel, saturated and medium-bright
- Muted: Same hue distribution but desaturated, pastel tones
- Monochrome: 9 shades of a single hue from light to dark
- For accessibility, ensure adjacent colors are distinguishable for color-blind users (vary lightness, not just hue)
Step 4: Output and Iterate
- Save the CSS to
/mnt/user-data/outputs/actual.css
- Present the file to the user
- Explain installation: Settings → Show advanced settings → Experimental features → Enable Custom themes → Settings → Themes → Custom theme → Paste CSS → Apply
- Tell user to test and report back with screenshots of any issues
- If issues arise, ask which elements are wrong, identify the variable, and fix
Common Issues and Fixes
| Problem | Likely variable(s) |
|---|
| Category group rows wrong color | tableRowHeaderBackground, tableRowHeaderText |
| Budget month header wrong | budgetHeaderCurrentMonth, budgetHeaderOtherMonth |
| Dropdowns/menus have black areas | menuItemBackground (must be solid). Also include menuAutoCompleteTextHover and menuAutoCompleteItemTextHover. Check tooltipBackground — some popovers use tooltip vars |
| Dropdowns/menus wrong color | menuBackground, menuItemBackground, menuAutoCompleteBackground |
| Report widgets blend into background | cardBackground, cardBorder — need more contrast vs pageBackground |
| Sidebar links invisible | sidebarItemText, sidebarBudgetName |
| Overbudgeted area wrong | toBudgetNegative, toBudgetPositive, toBudgetZero |
| Forms/inputs wrong color | formInputBackground, formInputBorder, formInputBorderSelected |
| Mobile looks wrong | All mobile* variables |
| Tooltip wrong | tooltipBackground, tooltipBorder, tooltipText |
| Selected filter pill wrong | buttonMenuSelectedBackground, buttonMenuSelectedText |
| Floating bar at bottom wrong | floatingActionBarBackground, floatingActionBarText |
| Notes/markdown area wrong | markdownNormal, markdownDark, markdownLight |
| White button has white text | buttonPrimaryText must contrast with buttonPrimaryBackground |
| Positive/negative numbers hard to read | numberPositive, numberNegative need more saturation. Also check noticeText*, toBudget* variants |
| Secondary button border too harsh | buttonNormalBorder — use subtle gray not bright white |
| Auto-sync green dot invisible | sidebarItemBackgroundPositive — needs a bright green |
| Segment control selected label unreadable | pillBackgroundSelected (bg) and buttonBareText (text) — ensure contrast between them. pillBackgroundSelected should be accent-toned |
| Checkbox check mark invisible | checkboxBackgroundSelected (fill) and checkboxText (mark) — need strong contrast |
Validation Checklist
Before delivering, verify:
Quick Start (for experienced users)
If the user already knows exactly what they want (e.g., "make me an OLED black theme with green accents"), skip the brainstorming and go straight to palette → CSS generation. Read references/variables.md first to ensure complete coverage