Skip to content

Theming

NullString1 edited this page Jan 13, 2026 · 1 revision

Theming with Stylix

NullOS uses Stylix for system-wide theming, automatically generating color schemes from your wallpaper and applying them across all applications.

Overview

Stylix is a NixOS module that provides:

  • Automatic color scheme generation from wallpapers
  • System-wide theme coordination
  • GTK, Qt, terminal, and application theming
  • Font management
  • Cursor theme integration

Benefits:

  • Unified look across all applications
  • Easy theme switching (just change wallpaper)
  • Declarative theming configuration
  • No manual color matching needed

How Stylix Works

  1. Wallpaper Input - You provide a wallpaper image
  2. Color Extraction - Stylix extracts dominant colors
  3. Base16 Generation - Creates a 16-color palette
  4. Application - Applies colors to all configured targets

Basic Configuration

Setting Your Wallpaper

The simplest way to theme NullOS:

# In variables.nix
stylixImage = wallpapers/your-wallpaper.jpg;

Rebuild and your entire system adopts colors from the wallpaper!

Wallpaper Requirements

  • Location: wallpapers/ directory in NullOS root
  • Formats: JPEG, PNG, WebP
  • Best Results: Images with distinct, vibrant colors
  • Resolution: Any (will be scaled appropriately)

Adding a new wallpaper:

cp ~/Downloads/cool-wallpaper.jpg ~/NullOS/wallpapers/

Update variables.nix:

stylixImage = wallpapers/cool-wallpaper.jpg;

Rebuild:

sudo nixos-rebuild switch --flake .#yourhostname

Stylix Configuration File

Primary configuration: home/stylix.nix

Basic Structure

{ config, pkgs, vars, ... }:

{
  stylix = {
    enable = true;
    autoEnable = true;
    
    image = vars.stylixImage;
    
    polarity = "dark";  # or "light"
    
    base16Scheme = {
      # Custom colors (optional)
    };
    
    fonts = {
      # Font configuration
    };
    
    targets = {
      # Enable/disable specific applications
    };
  };
}

Color Schemes

Auto-Generated from Wallpaper

Default behavior - Stylix extracts colors:

stylix = {
  image = vars.stylixImage;
  # Colors auto-generated
};

Using Pre-Made Base16 Schemes

Override auto-generation with a specific scheme:

stylix = {
  base16Scheme = "${pkgs.base16-schemes}/share/themes/gruvbox-dark-medium.yaml";
};

Popular schemes:

  • gruvbox-dark-medium.yaml - Warm, retro
  • nord.yaml - Cool, blue-tinted
  • dracula.yaml - Purple and pink
  • tokyo-night-dark.yaml - Modern dark theme
  • catppuccin-mocha.yaml - Pastel dark
  • solarized-dark.yaml - Classic
  • onedark.yaml - Atom One Dark

Find all available schemes:

ls $(nix-build '<nixpkgs>' -A base16-schemes)/share/themes/

Custom Color Scheme

Define your own Base16 colors:

stylix.base16Scheme = {
  base00 = "1e1e2e";  # Background
  base01 = "181825";  # Lighter background
  base02 = "313244";  # Selection background
  base03 = "45475a";  # Comments, invisible
  base04 = "585b70";  # Dark foreground
  base05 = "cdd6f4";  # Default foreground
  base06 = "f5e0dc";  # Light foreground
  base07 = "b4befe";  # Light background
  base08 = "f38ba8";  # Red
  base09 = "fab387";  # Orange
  base0A = "f9e2af";  # Yellow
  base0B = "a6e3a1";  # Green
  base0C = "94e2d5";  # Cyan
  base0D = "89b4fa";  # Blue
  base0E = "cba6f7";  # Purple
  base0F = "f2cdcd";  # Brown
};

Hybrid: Wallpaper + Manual Colors

Use wallpaper but override specific colors:

stylix = {
  image = vars.stylixImage;
  
  override = {
    base00 = "000000";  # Force pure black background
    base08 = "ff0000";  # Force bright red
  };
};

Polarity (Light/Dark Mode)

Dark Mode (Default)

stylix.polarity = "dark";

Light Mode

stylix.polarity = "light";

Either

Let Stylix decide based on wallpaper:

stylix.polarity = "either";

Fonts

Default Font Configuration

stylix.fonts = {
  monospace = {
    package = pkgs.nerdfonts.override { fonts = [ "JetBrainsMono" ]; };
    name = "JetBrainsMono Nerd Font Mono";
  };
  
  sansSerif = {
    package = pkgs.dejavu_fonts;
    name = "DejaVu Sans";
  };
  
  serif = {
    package = pkgs.dejavu_fonts;
    name = "DejaVu Serif";
  };
  
  emoji = {
    package = pkgs.noto-fonts-emoji;
    name = "Noto Color Emoji";
  };
};

Changing Fonts

stylix.fonts = {
  monospace = {
    package = pkgs.nerdfonts.override { fonts = [ "FiraCode" ]; };
    name = "FiraCode Nerd Font Mono";
  };
  
  sansSerif = {
    package = pkgs.inter;
    name = "Inter";
  };
};

Font Sizes

stylix.fonts.sizes = {
  applications = 12;
  terminal = 11;
  desktop = 10;
  popups = 10;
};

Application Targets

Control which applications Stylix themes.

View Current Targets

Check home/stylix.nix for:

stylix.targets = {
  # Application targets
};

Enabling/Disabling Targets

stylix.targets = {
  # Terminal applications
  alacritty.enable = true;
  kitty.enable = true;
  
  # Browsers
  firefox.enable = true;
  
  # Editors
  vim.enable = true;
  neovim.enable = true;
  vscode.enable = false;  # Keep VSCode's own theme
  
  # Desktop environment
  gtk.enable = true;
  qt.enable = true;
  
  # Window manager
  hyprland.enable = true;
  waybar.enable = true;
  
  # Shells
  zsh.enable = true;
  
  # File managers
  yazi.enable = true;
};

Disable for Specific Applications

If you prefer an app's native theme:

stylix.targets = {
  vscode.enable = false;
  discord.enable = false;
  spotify.enable = false;
};

GTK Theming

GTK Configuration

Stylix automatically configures GTK:

gtk = {
  enable = true;
  theme.name = "Generated-Stylix-Theme";
  iconTheme.name = "Papirus-Dark";
};

Custom GTK Icon Theme

home.packages = [ pkgs.papirus-icon-theme ];

gtk.iconTheme = {
  package = pkgs.papirus-icon-theme;
  name = "Papirus-Dark";
};

Custom GTK Theme

Override Stylix for GTK:

stylix.targets.gtk.enable = false;

gtk = {
  theme = {
    package = pkgs.adw-gtk3;
    name = "adw-gtk3-dark";
  };
};

Qt Theming

Qt Configuration

qt = {
  enable = true;
  platformTheme.name = "gtk";  # or "qt6ct"
  style.name = "adwaita-dark";
};

Using qt6ct

For more control:

stylix.targets.qt.enable = false;

qt = {
  enable = true;
  platformTheme.name = "qt6ct";
};

Then configure with qt6ct GUI tool.


Terminal Theming

Ghostty

Stylix automatically themes Ghostty:

# In home/ghostty.nix
programs.ghostty = {
  enable = true;
  # Stylix handles colors
};

Manual Terminal Colors

Disable Stylix and set manually:

stylix.targets.ghostty.enable = false;

programs.ghostty.settings = {
  background = "1e1e2e";
  foreground = "cdd6f4";
  
  palette = "0=#45475a";
  palette = "1=#f38ba8";
  # ... more colors
};

Hyprland Theming

Border Colors

Stylix sets Hyprland border colors automatically:

# In home/hyprland/hyprland.nix
general = {
  "col.active_border" = "rgba(${config.lib.stylix.colors.base0D}ff)";
  "col.inactive_border" = "rgba(${config.lib.stylix.colors.base03}aa)";
};

Custom Border Colors

Override Stylix:

general = {
  "col.active_border" = "rgba(33ccffee) rgba(00ff99ee) 45deg";
  "col.inactive_border" = "rgba(595959aa)";
};

Waybar Theming

Stylix provides colors to Waybar via CSS variables.

Using Stylix Colors in Waybar

/* Access Stylix colors */
* {
  background: @base00;
  foreground: @base05;
  border: @base0D;
}

#workspaces button.active {
  background: @base0D;
  color: @base00;
}

Custom Waybar Theme

stylix.targets.waybar.enable = false;

# Then manually style in home/waybar/default.nix

Cursor Theme

Default Cursor

stylix.cursor = {
  package = pkgs.bibata-cursors;
  name = "Bibata-Modern-Classic";
  size = 24;
};

Changing Cursor Theme

stylix.cursor = {
  package = pkgs.nordzy-cursor-theme;
  name = "Nordzy-cursors";
  size = 32;
};

Popular cursor themes:

  • pkgs.bibata-cursors - Modern, smooth
  • pkgs.nordzy-cursor-theme - Nordic style
  • pkgs.vanilla-dmz - Classic
  • pkgs.capitaine-cursors - macOS-like

Opacity Settings

Terminal Opacity

stylix.opacity = {
  terminal = 0.9;
  applications = 1.0;
  desktop = 1.0;
  popups = 0.95;
};

Per-Application Opacity

Use Hyprland window rules:

# In home/hyprland/windowrules.nix
windowrulev2 = opacity 0.9 0.9, class:^(ghostty)$
windowrulev2 = opacity 0.85 0.85, class:^(code)$

Advanced Techniques

Multiple Theme Profiles

Create theme variants:

# themes/gruvbox.nix
{
  stylix = {
    base16Scheme = "${pkgs.base16-schemes}/share/themes/gruvbox-dark-medium.yaml";
    polarity = "dark";
  };
}

# themes/nord.nix
{
  stylix = {
    base16Scheme = "${pkgs.base16-schemes}/share/themes/nord.yaml";
    polarity = "dark";
  };
}

Import the one you want:

# In home/stylix.nix
imports = [ ../themes/gruvbox.nix ];

Time-Based Themes

Switch between light/dark based on time:

stylix.polarity = 
  if (builtins.readFile /tmp/current-hour) < "18"
  then "light"
  else "dark";

(Requires external script to update /tmp/current-hour)

Per-Monitor Wallpapers

Use Hyprland's multiple wallpaper support:

# Script to set per-monitor wallpapers
swww img -o DP-1 wallpapers/monitor1.jpg
swww img -o HDMI-A-1 wallpapers/monitor2.jpg

Stylix still uses one for color generation.


Troubleshooting

Colors Not Applying

  1. Rebuild home-manager:
home-manager switch --flake .
  1. Check target is enabled:
stylix.targets.yourapp.enable = true;
  1. Restart application

Ugly Color Scheme

Try these fixes:

  1. Different wallpaper - Some images produce better palettes
  2. Manual scheme - Use pre-made Base16 scheme
  3. Adjust polarity - Try "dark" vs "light"
  4. Override specific colors - Manually set problematic colors

Application Ignoring Theme

Some apps need additional configuration:

# Force GTK theme
dconf.settings = {
  "org/gnome/desktop/interface" = {
    gtk-theme = config.gtk.theme.name;
  };
};

Font Issues

If fonts don't apply:

fc-cache -f  # Rebuild font cache

Check font name:

fc-list | grep -i "jetbrains"

Tips for Great Themes

  1. High Contrast Wallpapers - Produce more vibrant themes
  2. Test Multiple Wallpapers - Find what generates best palette
  3. Combine Methods - Wallpaper + manual overrides
  4. Consider Readability - Ensure text is visible
  5. Match Cursor/Icons - Choose coordinating cursor and icon themes
  6. Less is More - Don't override too much, trust Stylix

Gallery - Theme Showcase

Dark Themes

Gruvbox:

base16Scheme = "${pkgs.base16-schemes}/share/themes/gruvbox-dark-medium.yaml";

Nord:

base16Scheme = "${pkgs.base16-schemes}/share/themes/nord.yaml";

Tokyo Night:

base16Scheme = "${pkgs.base16-schemes}/share/themes/tokyo-night-dark.yaml";

Catppuccin Mocha:

base16Scheme = "${pkgs.base16-schemes}/share/themes/catppuccin-mocha.yaml";

Light Themes

Solarized Light:

base16Scheme = "${pkgs.base16-schemes}/share/themes/solarized-light.yaml";
polarity = "light";

Gruvbox Light:

base16Scheme = "${pkgs.base16-schemes}/share/themes/gruvbox-light-medium.yaml";
polarity = "light";

Resources

Stylix Documentation

https://github.com/danth/stylix

Base16 Gallery

https://tinted-theming.github.io/base16-gallery/

Finding Wallpapers

Color Scheme Tools


Next Steps

Clone this wiki locally