# NixOS Dynamic Theme Switcher - Implementation Instructions

## Objective
Build a time-based dynamic theme switching system on NixOS that:
1. Extracts color palettes from wallpapers using pywal16 with haishoku backend
2. Generates and applies themes for GTK, Qt/Kvantum, Ghostty, and other applications
3. Switches between light/dark themes based on time of day
4. Integrates with existing wpaperd wallpaper rotation service

## Current System State

### Existing Theming Configuration
**GTK Configuration:**
- Current theme: `catppuccin-macchiato-lavender-compact+rimless`
- Settings location: `~/.config/gtk-3.0/settings.ini`, `~/.config/gtk-4.0/settings.ini`
- Icon theme: `Papirus-Dark`
- Cursor: `Bibata-Modern-Classic`
- Files are symlinked from Nix store via home-manager

**Qt/Kvantum Configuration:**
- Current theme: `catppuccin-macchiato-lavender`
- Location: `~/.config/Kvantum/kvantum.kvconfig`
- Style: kvantum (both Qt5 and Qt6)
- Environment variable: `QT_STYLE_OVERRIDE=kvantum`

**Wallpaper Service:**
- Using wpaperd with home-manager integration
- Wallpapers in: `/home/nate/nixos/shared/modules/services/wallpapers/`
- Organized into `Light/` and `Dark/` subdirectories
- Service configured via `services.wallpaperRotator` module

**Actions Required:**
1. Disable/modify static GTK theme configuration in home.nix
2. Disable/modify static Kvantum theme configuration
3. Integrate with wpaperd to trigger theme changes on wallpaper rotation
4. Remove hardcoded Catppuccin theme packages when pywal themes are working

## Implementation Components

### 3. Install Required Packages

Add to module configuration:
```nix
home.packages = with pkgs; [
  pywal16                      # Color scheme generator with 16-color support
  python3Packages.haishoku     # Recommended backend for pywal16
  wpaperd                      # Already installed via wallpaper service
];
```

**Available pywal16 backends:** modern_colorthief, wal, fast_colorthief, haishoku, colorthief, colorz, okthief, schemer2

### 4. Color Extraction & Theme Generation

#### 4.1 Pywal16 Built-in Templates
**Pywal16 already includes templates for:**
- Ghostty: `ghostty.conf` template (tested and confirmed)
- CSS variables: `colors.css` template
- Waybar: `colors-waybar.css`
- Hyprland: `colors-hyprland.conf`
- Rofi: `colors-rofi-dark.rasi` and `colors-rofi-light.rasi`
- Sway: `colors-sway`
- Mako: `colors-mako`
- Foot, Kitty, Alacritty terminal configs
- Many others (47 templates total)

**Output location:** `~/.cache/wal/` after running `wal -i /path/to/wallpaper`

**Usage:**
```bash
wal -i /path/to/wallpaper --backend haishoku -n
# -n flag skips setting wallpaper (wpaperd handles that)
# --backend haishoku uses the haishoku color extraction
# -l flag for light themes
```

#### 4.2 GTK Theme Generation
**Goal:** Create custom GTK 3.0 and GTK 4.0 CSS themes from pywal colors

**Note:** Pywal16 includes `colors.css` template with CSS variables, but NOT full GTK themes.

**Required files:**
- `~/.config/gtk-3.0/gtk.css` - Custom CSS overlay
- `~/.config/gtk-4.0/gtk.css` - Custom CSS overlay

**Approach:** Create pywal template to generate GTK CSS using colors.json output
- Map pywal colors to GTK color definitions
- Use @define-color for GTK theme variables
- Apply to common widgets

#### 4.3 Qt/Kvantum Theme Generation
**Goal:** Generate Kvantum theme from pywal colors

**Kvantum structure (.kvconfig file):**
- `[General]` section with metadata
- `[GeneralColors]` section with color definitions (window.color, base.color, button.color, etc.)
- `[Hacks]` section with tweaks
- Per-widget sections (PanelButtonCommand, etc.)

**Location:** `~/.config/Kvantum/PywalTheme/PywalTheme.kvconfig`

**Required:** Create pywal template that maps colors.json to .kvconfig format
**Optional:** SVG file can be minimal or omitted for basic themes

**Application:** Use `kvantummanager --set PywalTheme` to activate

### 5. Theme Application Script

**Script: `apply-theme.sh`**

**Parameters:**
- `--light` or `--dark` (theme mode)
- Optional: `--wallpaper-path` (specific wallpaper, otherwise use wpaperd current)

**Script Logic:**

1. **Determine wallpaper source:**
   - If `--wallpaper-path` provided, use it
   - Otherwise, let wpaperd select based on mode (Light/ or Dark/ directory)
   - Use `wpaperctl` to interact with wpaperd if needed

2. **Generate color scheme:**
   ```bash
   if [ "$MODE" = "light" ]; then
       wal -i "$WALLPAPER" --backend haishoku -l -n
   else
       wal -i "$WALLPAPER" --backend haishoku -n
   fi
   ```

3. **Apply GTK theme:**
   ```bash
   # pywal doesn't generate full GTK themes, use custom CSS
   ln -sf ~/.cache/wal/gtk-3.0.css ~/.config/gtk-3.0/gtk.css
   ln -sf ~/.cache/wal/gtk-4.0.css ~/.config/gtk-4.0/gtk.css
   
   gsettings set org.gnome.desktop.interface color-scheme "prefer-$MODE"
   ```

4. **Apply Qt/Kvantum theme:**
   ```bash
   kvantummanager --set PywalTheme
   ```

5. **Reload configurations:**
   - Ghostty: Auto-reloads config on file change (no action needed)
   - GTK apps: Automatically detect gsettings changes
   - Qt apps: May need restart for Kvantum changes
   - Hyprland/Sway: Reload via IPC if using pywal templates

6. **Optional: Update Flatpak:**
   ```bash
   flatpak override --user --filesystem=~/.cache/wal:ro
   ```

### 6. Wallpaper Integration & Time-Based Switching

**Option A: Integrate with wpaperd events (Recommended)**
- Modify wallpaper-rotator module to support Light/Dark subdirectories
- Change wallpaper directory based on time of day
- Trigger theme generation on wallpaper change

**Option B: Independent systemd timer**

**Timer configuration:**
```nix
systemd.user.timers.theme-switcher = {
  Unit.Description = "Dynamic Theme Switcher Timer";
  Timer = {
    OnCalendar = [ "*-*-* 06:00:00" "*-*-* 18:00:00" ];  # 6am light, 6pm dark
    Persistent = true;
  };
  Install.WantedBy = [ "timers.target" ];
};
```

**Service configuration:**
```nix
systemd.user.services.theme-switcher = {
  Unit.Description = "Dynamic Theme Switcher";
  Service = {
    Type = "oneshot";
    ExecStart = "${pkgs.bash}/bin/bash ${./scripts/theme-switcher.sh}";
    Environment = "PATH=${lib.makeBinPath [ pkgs.pywal16 pkgs.coreutils ]}";
  };
};
```

**Script determines light/dark based on current hour:**
```bash
hour=$(date +%H)
if [ $hour -ge 6 ] && [ $hour -lt 18 ]; then
    MODE="light"
    WALLPAPER_DIR="Light"
else
    MODE="dark"
    WALLPAPER_DIR="Dark"
fi
```

### 7. NixOS Module Structure

**Module: `theme_switcher/default.nix`**

```nix
{ config, lib, pkgs, ... }:

let
  cfg = config.services.themeSwitcher;
in
{
  options.services.themeSwitcher = {
    enable = lib.mkEnableOption "dynamic theme switching based on time and wallpapers";
    
    user = lib.mkOption {
      type = lib.types.str;
      description = "Username for theme switching";
    };
    
    wallpaperPath = lib.mkOption {
      type = lib.types.str;
      default = "/home/${cfg.user}/nixos/shared/modules/services/wallpapers";
      description = "Path to wallpaper directories (Light/ and Dark/)";
    };
    
    backend = lib.mkOption {
      type = lib.types.enum [ "haishoku" "modern_colorthief" "fast_colorthief" ];
      default = "haishoku";
      description = "Pywal color extraction backend";
    };
    
    lightTime = lib.mkOption {
      type = lib.types.str;
      default = "06:00:00";
      description = "Time to switch to light theme (HH:MM:SS)";
    };
    
    darkTime = lib.mkOption {
      type = lib.types.str;
      default = "18:00:00";
      description = "Time to switch to dark theme (HH:MM:SS)";
    };
  };
  
  config = lib.mkIf cfg.enable {
    home-manager.users.${cfg.user} = {
      home.packages = with pkgs; [
        pywal16
        python3Packages.haishoku
      ];
      
      # Install theme application scripts
      home.file.".local/bin/apply-theme.sh" = {
        source = ./scripts/apply-theme.sh;
        executable = true;
      };
      
      # Pywal custom templates for GTK and Kvantum
      xdg.configFile."wal/templates/gtk-3.0.css".source = ./templates/gtk-3.0.css;
      xdg.configFile."wal/templates/gtk-4.0.css".source = ./templates/gtk-4.0.css;
      xdg.configFile."wal/templates/kvantum.kvconfig".source = ./templates/kvantum.kvconfig;
      
      # Systemd timer and service
      systemd.user.timers.theme-switcher = { /* ... */ };
      systemd.user.services.theme-switcher = { /* ... */ };
      
      # Keep Qt/GTK enabled but don't set static themes
      qt = {
        enable = true;
        platformTheme.name = "kvantum";
        style.name = "kvantum";
      };
      
      gtk.enable = true;
    };
  };
}
```

**Template files needed:**
- `templates/gtk-3.0.css` - GTK3 theme using pywal variables
- `templates/gtk-4.0.css` - GTK4 theme using pywal variables  
- `templates/kvantum.kvconfig` - Kvantum config using pywal colors

## Testing & Validation

### 8. Test Plan

1. **Test pywal color extraction:**
   ```bash
   # Test with light wallpaper
   wal -i ~/nixos/shared/modules/services/wallpapers/Light/IU-Light.jpg --backend haishoku -l -n
   cat ~/.cache/wal/colors.json  # Verify colors extracted
   
   # Test with dark wallpaper
   wal -i ~/nixos/shared/modules/services/wallpapers/Dark/IU-Dark.jpg --backend haishoku -n
   cat ~/.cache/wal/colors.json  # Verify colors extracted
   ```

2. **Verify pywal template output:**
   ```bash
   ls -la ~/.cache/wal/
   # Should see: colors.json, ghostty.conf, colors.css, and custom templates
   cat ~/.cache/wal/ghostty.conf  # Check ghostty colors
   ```

3. **Manual theme application:**
   ```bash
   ~/.local/bin/apply-theme.sh --light
   # Check: GTK apps, Qt apps, Ghostty colors update
   
   ~/.local/bin/apply-theme.sh --dark
   # Check: Theme switches to dark
   ```

4. **Verify theme files:**
   - `~/.cache/wal/colors.json` - Generated by pywal
   - `~/.cache/wal/gtk-3.0.css` - From custom template
   - `~/.cache/wal/gtk-4.0.css` - From custom template
   - `~/.cache/wal/kvantum.kvconfig` - From custom template
   - `~/.cache/wal/ghostty.conf` - From built-in template

5. **Test Kvantum theme:**
   ```bash
   kvantummanager --set PywalTheme
   # Or check: cat ~/.config/Kvantum/kvantum.kvconfig
   ```

6. **Test systemd automation:**
   ```bash
   systemctl --user start theme-switcher.service
   systemctl --user status theme-switcher.timer
   systemctl --user list-timers | grep theme
   ```

7. **Test with live applications:**
   - Open GTK app (nautilus, gnome-calculator) - verify colors
   - Open Qt app (if available) - verify Kvantum theme
   - Open Ghostty terminal - verify color palette matches wallpaper
   - Check waybar/rofi if using pywal templates for those

## Implementation Steps Summary

### Phase 1: Setup pywal with existing wallpapers
1. Create theme_switcher module with pywal16 package
2. Test color extraction on Light/ and Dark/ wallpapers
3. Verify built-in templates (ghostty.conf, colors.css) generate correctly

### Phase 2: Create custom templates
1. Create `templates/gtk-3.0.css` using pywal variables
2. Create `templates/gtk-4.0.css` using pywal variables
3. Create `templates/kvantum.kvconfig` mapping colors.json to Kvantum format
4. Install templates to `~/.config/wal/templates/`

### Phase 3: Theme application script
1. Write `apply-theme.sh` script that:
   - Runs pywal with appropriate flags (-l for light)
   - Symlinks generated CSS to GTK config directories
   - Copies Kvantum config to `~/.config/Kvantum/PywalTheme/`
   - Runs `kvantummanager --set PywalTheme`
   - Updates gsettings for color-scheme preference

### Phase 4: Time-based automation
1. Create systemd timer for light/dark switching times
2. Create systemd service that calls apply-theme.sh
3. Script determines mode based on current time
4. Selects random wallpaper from Light/ or Dark/ directory

### Phase 5: Integration and cleanup
1. Modify existing home.nix files to disable static themes when module enabled
2. Keep icon themes, cursor themes (not wallpaper-dependent)
3. Test on one host before deploying to all
4. Document wpaperd integration approach for future enhancement

## Key Technical Details

**Pywal template syntax:**
```
{background}    -> #081212
{foreground}    -> #c1c3c3
{color0}        -> #081212
...
{color15}       -> #c1c3c3
{cursor}        -> #c1c3c3
{wallpaper}     -> /path/to/wallpaper.jpg
```

**Template location:** `~/.config/wal/templates/filename.ext`
**Output location:** `~/.cache/wal/filename.ext`

**Ghostty:** Automatically reloads config when files change - no manual reload needed

**GTK:** Changes propagate via gsettings/dconf - running apps update automatically

**Kvantum:** May require app restart to see changes (Qt limitation)

**Wallpaper directories:**
- Light: `/home/nate/nixos/shared/modules/services/wallpapers/Light/`
- Dark: `/home/nate/nixos/shared/modules/services/wallpapers/Dark/`
