-
Notifications
You must be signed in to change notification settings - Fork 0
Theming
NullOS uses Stylix for system-wide theming, automatically generating color schemes from your wallpaper and applying them across all applications.
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
- Wallpaper Input - You provide a wallpaper image
- Color Extraction - Stylix extracts dominant colors
- Base16 Generation - Creates a 16-color palette
- Application - Applies colors to all configured targets
The simplest way to theme NullOS:
# In variables.nix
stylixImage = wallpapers/your-wallpaper.jpg;Rebuild and your entire system adopts colors from the wallpaper!
-
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 .#yourhostnamePrimary configuration: home/stylix.nix
{ 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
};
};
}Default behavior - Stylix extracts colors:
stylix = {
image = vars.stylixImage;
# Colors auto-generated
};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/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
};Use wallpaper but override specific colors:
stylix = {
image = vars.stylixImage;
override = {
base00 = "000000"; # Force pure black background
base08 = "ff0000"; # Force bright red
};
};stylix.polarity = "dark";stylix.polarity = "light";Let Stylix decide based on wallpaper:
stylix.polarity = "either";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";
};
};stylix.fonts = {
monospace = {
package = pkgs.nerdfonts.override { fonts = [ "FiraCode" ]; };
name = "FiraCode Nerd Font Mono";
};
sansSerif = {
package = pkgs.inter;
name = "Inter";
};
};stylix.fonts.sizes = {
applications = 12;
terminal = 11;
desktop = 10;
popups = 10;
};Control which applications Stylix themes.
Check home/stylix.nix for:
stylix.targets = {
# Application 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;
};If you prefer an app's native theme:
stylix.targets = {
vscode.enable = false;
discord.enable = false;
spotify.enable = false;
};Stylix automatically configures GTK:
gtk = {
enable = true;
theme.name = "Generated-Stylix-Theme";
iconTheme.name = "Papirus-Dark";
};home.packages = [ pkgs.papirus-icon-theme ];
gtk.iconTheme = {
package = pkgs.papirus-icon-theme;
name = "Papirus-Dark";
};Override Stylix for GTK:
stylix.targets.gtk.enable = false;
gtk = {
theme = {
package = pkgs.adw-gtk3;
name = "adw-gtk3-dark";
};
};qt = {
enable = true;
platformTheme.name = "gtk"; # or "qt6ct"
style.name = "adwaita-dark";
};For more control:
stylix.targets.qt.enable = false;
qt = {
enable = true;
platformTheme.name = "qt6ct";
};Then configure with qt6ct GUI tool.
Stylix automatically themes Ghostty:
# In home/ghostty.nix
programs.ghostty = {
enable = true;
# Stylix handles 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
};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)";
};Override Stylix:
general = {
"col.active_border" = "rgba(33ccffee) rgba(00ff99ee) 45deg";
"col.inactive_border" = "rgba(595959aa)";
};Stylix provides colors to Waybar via CSS variables.
/* Access Stylix colors */
* {
background: @base00;
foreground: @base05;
border: @base0D;
}
#workspaces button.active {
background: @base0D;
color: @base00;
}stylix.targets.waybar.enable = false;
# Then manually style in home/waybar/default.nixstylix.cursor = {
package = pkgs.bibata-cursors;
name = "Bibata-Modern-Classic";
size = 24;
};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
stylix.opacity = {
terminal = 0.9;
applications = 1.0;
desktop = 1.0;
popups = 0.95;
};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)$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 ];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)
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.jpgStylix still uses one for color generation.
- Rebuild home-manager:
home-manager switch --flake .- Check target is enabled:
stylix.targets.yourapp.enable = true;- Restart application
Try these fixes:
- Different wallpaper - Some images produce better palettes
- Manual scheme - Use pre-made Base16 scheme
- Adjust polarity - Try "dark" vs "light"
- Override specific colors - Manually set problematic colors
Some apps need additional configuration:
# Force GTK theme
dconf.settings = {
"org/gnome/desktop/interface" = {
gtk-theme = config.gtk.theme.name;
};
};If fonts don't apply:
fc-cache -f # Rebuild font cacheCheck font name:
fc-list | grep -i "jetbrains"- High Contrast Wallpapers - Produce more vibrant themes
- Test Multiple Wallpapers - Find what generates best palette
- Combine Methods - Wallpaper + manual overrides
- Consider Readability - Ensure text is visible
- Match Cursor/Icons - Choose coordinating cursor and icon themes
- Less is More - Don't override too much, trust Stylix
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";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";https://github.com/danth/stylix
https://tinted-theming.github.io/base16-gallery/
- https://coolors.co - Generate palettes
- https://colorhunt.co - Browse palettes
- Customization Guide - General customization
- Hyprland - Window manager theming
- Waybar - Status bar styling
- GTK Configuration - GTK apps theming