# Hyprland window manager — Lua config for Hyprland 0.55+ # Home-Manager configType = "lua" generates hyprland.lua using hl.* API. # API reference: https://wiki.hypr.land/Configuring/Start/ { config, lib, ... }: with lib; let cfg = config.desktop.wm.hyprland; p = config.colorScheme.palette; in { options.desktop.wm.hyprland.enable = mkEnableOption "Hyprland window manager"; config = mkIf cfg.enable { wayland.windowManager.hyprland = { configType = "lua"; settings = { # ── Lua local variables (rendered as: local mainMod = "SUPER") ── mainMod = {_var = "SUPER";}; terminal = {_var = "ghostty";}; # ── Config sections (rendered as: hl.config({...})) ── config = { xwayland = {force_zero_scaling = true;}; input = { kb_layout = "de,us"; kb_variant = ""; kb_model = ""; kb_rules = ""; kb_options = "ctrl:nocaps"; follow_mouse = 1; }; general = { gaps_in = 5; gaps_out = 5; border_size = 1; col = { active_border = {colors = ["rgba(9742b5ee)" "rgba(9742b5ee)"]; angle = 45;}; inactive_border = "rgba(${p.base03}aa)"; }; layout = "dwindle"; }; decoration = { shadow = { enabled = true; range = 60; render_power = 3; color = "rgba(${p.base00}66)"; scale = 0.97; }; rounding = 8; blur = { enabled = true; size = 3; passes = 3; }; active_opacity = 0.9; inactive_opacity = 0.5; }; animations = {enabled = true;}; dwindle = { pseudotile = true; preserve_split = true; }; master = {new_status = "master";}; }; # ── Environment variables (rendered as: hl.env("KEY", "VALUE")) ── env = [ { _args = ["XCURSOR_SIZE" "32"]; } { _args = ["HYPRCURSOR_THEME" "Bibata-Modern-Ice"]; } { _args = ["WLR_NO_HARDWARE_CURSORS" "1"]; } { _args = ["GTK_THEME" "Dracula"]; } { _args = ["XDG_CURRENT_DESKTOP" "Hyprland"]; } { _args = ["XDG_SESSION_TYPE" "wayland"]; } { _args = ["XDG_SESSION_DESKTOP" "Hyprland"]; } { _args = ["XKB_DEFAULT_LAYOUT" "de"]; } { _args = ["NIXOS_OZONE_WL" "1"]; } ]; # ── Per-device config (rendered as: hl.device({...})) ── device = [ {name = "epic-mouse-v1"; sensitivity = -0.5;} {name = "zsa-technology-labs-moonlander-mark-i"; kb_layout = "us";} {name = "keychron-keychron-k7"; kb_layout = "us";} ]; }; # ── Complex Lua: curves, animations, binds, window rules, startup ── extraConfig = '' -- Bezier curves hl.curve("myBezier", { type = "bezier", points = { {0.05, 0.9}, {0.1, 1.05} } }) -- Animations hl.animation({ leaf = "windows", enabled = true, speed = 7, bezier = "myBezier" }) hl.animation({ leaf = "windowsOut", enabled = true, speed = 7, bezier = "default", style = "popin 80%" }) hl.animation({ leaf = "border", enabled = true, speed = 10, bezier = "default" }) hl.animation({ leaf = "borderangle", enabled = true, speed = 8, bezier = "default" }) hl.animation({ leaf = "fade", enabled = true, speed = 7, bezier = "default" }) hl.animation({ leaf = "workspaces", enabled = true, speed = 6, bezier = "default" }) -- Keybinds: terminals & editors hl.bind(mainMod .. " + Return", hl.dsp.exec_cmd(terminal .. " nu -c zellij-ps")) hl.bind(mainMod .. " + T", hl.dsp.exec_cmd(terminal .. " -e nu -c 'nitch; exec nu'")) hl.bind(mainMod .. " + Shift + T", hl.dsp.exec_cmd("launch-timer")) hl.bind(mainMod .. " + N", hl.dsp.exec_cmd(terminal .. " -e nvim")) hl.bind(mainMod .. " + Z", hl.dsp.exec_cmd("uwsm app -- zeditor")) -- Keybinds: misc hl.bind(mainMod .. " + O", hl.dsp.exec_cmd("hyprctl dispatch setprop activewindow opaque toggle")) hl.bind(mainMod .. " + B", hl.dsp.exec_cmd("uwsm app -- thunar")) hl.bind(mainMod .. " + Shift + B", hl.dsp.exec_cmd("uwsm app -- vivaldi")) hl.bind(mainMod .. " + Escape", hl.dsp.exec_cmd("uwsm app -- wlogout -p layer-shell")) -- Keybinds: window management hl.bind(mainMod .. " + Space", hl.dsp.window.float({ action = "toggle" })) hl.bind(mainMod .. " + Q", hl.dsp.window.close()) hl.bind(mainMod .. " + M", hl.dsp.exit()) hl.bind(mainMod .. " + F", hl.dsp.window.fullscreen()) hl.bind(mainMod .. " + Shift + V", hl.dsp.window.float({ action = "toggle" })) -- Keybinds: launchers hl.bind(mainMod .. " + D", hl.dsp.exec_cmd('uwsm app -- rofi -show drun -run-command "uwsm app -- {cmd}"')) hl.bind(mainMod .. " + V", hl.dsp.exec_cmd("uwsm app -- cliphist list | rofi -dmenu | cliphist decode | wl-copy")) hl.bind(mainMod .. " + C", hl.dsp.exec_cmd("bash -c 'FILE=/tmp/screenshot_$(date +%s).png; grim -g \"$(slurp)\" \"$FILE\" && ksnip \"$FILE\"'")) hl.bind(mainMod .. " + Shift + S", hl.dsp.exec_cmd("uwsm app -- rofi -show emoji")) hl.bind(mainMod .. " + P", hl.dsp.exec_cmd("uwsm app -- rofi-pass")) hl.bind(mainMod .. " + Shift + P", hl.dsp.window.pseudo()) -- Keybinds: STT push-to-talk hl.bind(mainMod .. " + R", hl.dsp.exec_cmd("stt-ptt start")) hl.bind(mainMod .. " + R", hl.dsp.exec_cmd("stt-ptt stop"), { release = true }) hl.bind(mainMod .. " + S", hl.dsp.exec_cmd("stt-ptt start")) hl.bind(mainMod .. " + S", hl.dsp.exec_cmd("stt-ptt format-stop"), { release = true }) -- Keybinds: focus hl.bind(mainMod .. " + H", hl.dsp.focus({ direction = "left" })) hl.bind(mainMod .. " + L", hl.dsp.focus({ direction = "right" })) hl.bind(mainMod .. " + K", hl.dsp.focus({ direction = "up" })) hl.bind(mainMod .. " + J", hl.dsp.focus({ direction = "down" })) -- Keybinds: workspaces (1-10) for i = 1, 10 do local key = i % 10 hl.bind(mainMod .. " + " .. key, hl.dsp.focus({ workspace = i })) hl.bind(mainMod .. " + Shift + " .. key, hl.dsp.window.move({ workspace = i })) end hl.bind(mainMod .. " + mouse_down", hl.dsp.focus({ workspace = "e+1" })) hl.bind(mainMod .. " + mouse_up", hl.dsp.focus({ workspace = "e-1" })) -- Keybinds: mouse (drag & resize) hl.bind(mainMod .. " + mouse:272", hl.dsp.window.drag(), { mouse = true }) hl.bind(mainMod .. " + mouse:273", hl.dsp.window.resize(), { mouse = true }) -- Window rules: floating dialogs for _, cls in ipairs({ "file_progress", "confirm", "dialog", "download", "notification", "error", "splash", "confirmreset", }) do hl.window_rule({ match = { class = cls }, float = true }) end -- Window rules: title-based floating hl.window_rule({ match = { title = "Open File" }, float = true }) hl.window_rule({ match = { title = "branchdialog" }, float = true }) -- Window rules: audio/video hl.window_rule({ match = { class = "pavucontrol-qt" }, float = true }) hl.window_rule({ match = { class = "pavucontrol" }, float = true }) hl.window_rule({ match = { class = "^espanso$" }, float = true }) -- Window rules: wlogout hl.window_rule({ match = { class = "wlogout" }, fullscreen = true }) hl.window_rule({ match = { title = "wlogout" }, float = true, fullscreen = true }) -- Window rules: mpv hl.window_rule({ match = { class = "mpv" }, float = true, idle_inhibit = "focus", opacity = 1.0 }) -- Window rules: misc floating hl.window_rule({ match = { title = "^Media viewer$" }, float = true }) hl.window_rule({ match = { title = "^Volume Control$" }, float = true }) hl.window_rule({ match = { title = "^Picture-in-Picture$" }, float = true }) -- Window rules: pomodoro (consolidated) hl.window_rule({ match = { title = "^floating-pomodoro$" }, float = true, size = { 250, 50 }, move = { 12, "monitor_h-150" }, pin = true, }) -- Window rules: streamlabs (consolidated) hl.window_rule({ match = { initial_title = ".*streamlabs.com.*" }, float = true, pin = true, size = { 800, 400 }, opacity = 0.5, idle_inhibit = "focus", no_anim = true, decorate = false, no_shadow = true, no_blur = true, }) hl.window_rule({ match = { initial_title = ".*alert-box.*" }, move = { "100%-820", 102 } }) hl.window_rule({ match = { initial_title = ".*chat-box.*" }, move = { "100%-820", 512 } }) -- Window rules: vibe-typer hl.window_rule({ match = { class = "^vibe-typer$", title = "^Recording Indicator$" }, no_blur = true }) -- Window rules: xwayland border hl.window_rule({ match = { xwayland = true }, border_color = "rgb(ffffff)" }) -- Startup commands hl.on("hyprland.start", function() hl.exec_cmd("hyprpanel") hl.exec_cmd("while ! hyprpaper-random; do sleep 0.5; done") hl.exec_cmd("wl-paste --type text --watch cliphist store") hl.exec_cmd("wl-paste --type image --watch cliphist store") hl.exec_cmd("vibetyper") end) ''; }; services.hypridle = { enable = true; settings = { general = { before_sleep_cmd = "hyprlock"; after_sleep_cmd = "hyprctl dispatch dpms on"; inhibit_sleep = 3; }; listener = [ { timeout = 300; on-timeout = "hyprlock"; } { timeout = 420; on-timeout = "hyprctl dispatch dpms off"; on-resume = "hyprctl dispatch dpms on"; } ]; }; }; services.hyprpaper.enable = true; programs.hyprlock = { enable = true; settings = { "$font" = "JetBrainsMono Nerd Font"; "$base" = "rgb(${p.base00})"; "$text" = "rgb(${p.base05})"; "$textAlpha" = "${p.base05}"; "$accentAlpha" = "${p.base0D}"; "$red" = "rgb(${p.base08})"; "$yellow" = "rgb(${p.base0A})"; general = { hide_cursor = true; }; background = { monitor = ""; path = "${config.home.homeDirectory}/.config/hypr/wallpapers/wallhaven-lmmo8r.jpg"; blur_passes = 0; color = "rgb(${p.base00})"; }; label = [ { monitor = ""; text = "$TIME"; color = "$text"; font_size = 90; font_family = "$font"; position = "30, 0"; halign = "left"; valign = "top"; } { monitor = ""; text = ''cmd[update:43200000] echo "$(date +"%A, %d %B %Y")"''; color = "$text"; font_size = 25; font_family = "$font"; position = "30, -150"; halign = "left"; valign = "top"; } ]; input-field = [ { monitor = ""; size = "300, 60"; outline_thickness = 4; dots_size = 0.2; dots_spacing = 0.2; dots_center = true; outer_color = "rgb(${p.base0D})"; inner_color = "rgb(${p.base00})"; font_color = "rgb(${p.base05})"; fade_on_empty = false; placeholder_text = ''󰌾 Logged in as $USER''; hide_input = false; check_color = "rgb(${p.base0D})"; fail_color = "rgb(${p.base08})"; fail_text = ''$FAIL ($ATTEMPTS)''; capslock_color = "rgb(${p.base0A})"; position = "0, -35"; halign = "center"; valign = "center"; } ]; }; }; }; }