Dotfiles/desktopenvs/hyprlua/hypr/hyprland.lua

222 lines
12 KiB
Lua

-- =============================================================================
-- hyprland.lua — Root Hyprland Lua configuration entry point
--
-- This is the top-level config file loaded by Hyprland when the Lua backend
-- is active. It is intentionally kept thin: device-specific settings (monitors,
-- keybinds, environment variables, input, window rules, autostart programs) all
-- live in the usr/ subdirectory so they can be deployed per-machine without
-- touching this shared file.
--
-- Reference: https://wiki.hypr.land/Configuring/Start/
-- Device-specific files live in ~/.config/hypr/usr/ (deployed from hypr/usr/).
-- =============================================================================
-- Pull in per-device configuration modules.
-- monitors is loaded from the Lua search path root (monitors.lua, managed by
-- hyprmoncfg); the remaining modules live in usr/ and are per-machine overrides.
-- They are loaded in this specific order so that later modules can safely
-- depend on earlier ones (e.g., binds may reference programs launched by
-- autostart; input-device-exceptions builds on the global input baseline).
require("usr.monitors") -- monitor layout, resolution, scale (managed by hyprmoncfg)
require("usr.envvars") -- environment variables injected into every child process
require("usr.input") -- keyboard layout, mouse sensitivity, touchpad behaviour
require("usr.binds") -- all keybindings and mouse button bindings
require("usr.windowrules") -- per-app float/pin/opacity/tag/size rules
require("usr.autostart") -- programs launched once when the compositor starts
--------------------
---- MY PROGRAMS ---
--------------------
-- Convenience variables naming the preferred application for each role.
-- These are referenced by keybind definitions in usr/binds.lua so that
-- changing the preferred terminal, editor, etc. requires only a single edit here.
local terminal = "kitty" -- GPU-accelerated terminal emulator
local fileManager = "thunar" -- GTK file manager (Xfce/GNOME ecosystem)
local editor = "kitty nvim" -- Neovim inside kitty; avoids a separate GUI wrapper
local menu = "vicinae toggle" -- vicinae is the custom app-launcher; toggle shows/hides it
---------------------
---- LOOK & FEEL ----
---------------------
-- hl.config() is the Lua API equivalent of Hyprland's declarative keyword blocks.
-- All visual and layout settings for the compositor are collected here so the full
-- theming picture is visible in one place rather than spread across multiple files.
hl.config({
general = {
-- Inner gap between tiled windows (px).
-- Kept small (3 px) so screen real-estate is not wasted on multi-monitor setups.
gaps_in = 3,
-- Outer gap between the outermost windows and the monitor edge (px).
-- Slightly larger than gaps_in (6 px) to give the desktop a "framed" look,
-- ensuring windows never touch the absolute screen edge.
gaps_out = 6,
-- Border width around every window (px). 4 px is thick enough to show the
-- animated gradient colour clearly at 1.5x HiDPI scaling.
border_size = 4,
col = {
-- Active window border: an animated gradient cycling through red hues at 35 degrees.
-- Five colour stops alternating between #E40046 and #f50505 create a slow pulsing
-- effect. The angle = 35 rotates the gradient continuously (see borderangle animation).
active_border = { colors = { "rgb(E40046)", "rgb(f50505)", "rgb(E40046)", "rgb(f50505)", "rgb(E40046)" }, angle = 35 },
-- Inactive border: deep electric blue (#5018dd). Blue recedes visually relative to
-- the hot red active border, making focus immediately obvious without being distracting.
inactive_border = "rgb(5018dd)",
},
-- Disable resize-by-grabbing the window border. This prevents accidental resizes
-- when the cursor clips the edge during fast workspace switching or window dragging.
resize_on_border = false,
-- Tearing introduces screen-tear artefacts in exchange for lower latency.
-- Disabled here for a clean image; enable per-window via windowrules for games.
allow_tearing = false,
-- Default tiling algorithm. Dwindle splits the remaining space in half each time
-- a new window opens, producing a predictable Fibonacci spiral layout that keeps
-- all windows visible without needing manual arrangement.
layout = "dwindle",
},
group = {
-- Window groups stack multiple windows into one tiled slot with a tab bar.
-- These colours keep the group tabs visually consistent with the main border theme.
col = {
-- Active tab in a window group: accent red to match the active window border.
border_active = "rgb(E40046)",
-- Inactive tabs fade to dark blue to de-emphasise them.
border_inactive = "rgb(5018dd)",
-- "Locked" groups cannot be accidentally moved between workspaces.
-- A slightly different red (#f50505) distinguishes them from ordinary active groups.
border_locked_active = "rgb(f50505)",
border_locked_inactive = "rgb(5018dd)",
},
groupbar = {
-- Agave NerdFont provides both monospace text and NerdFont icon glyphs,
-- letting the bar display icons without requiring a separate symbol font.
font_family = "Agave NerdFont",
font_size = 20, -- px; large enough to be readable at 1.5x HiDPI scale
height = 25, -- px; matches indicator_height for a full-height flat pill
-- round_only_edges = false: every tab gets the same border-radius, not just
-- the first and last, giving a uniform pill row rather than a single rounded strip.
round_only_edges = false,
-- indicator_height = height (25 px): the selected-tab indicator fills the entire
-- bar height instead of being a thin underline, making the active tab unmissable.
indicator_height = 25,
-- stacked = false: tabs appear side-by-side horizontally (breadcrumb style),
-- not vertically stacked. Horizontal layout conserves vertical screen space.
stacked = false,
-- Tab label text colour: accent red, consistent with the active border colour.
text_color = "rgb(E40046)",
-- priority = 3 ensures the groupbar is rendered above regular window decorations
-- (shadows, rounded corners) so it is never visually clipped.
priority = 3,
-- Rounded corners on the groupbar container (13 px radius). The value is chosen
-- to complement the 20 px window rounding without looking disproportionate.
rounding = 13,
col = {
-- Active tab fill: solid accent red, clearly selected.
active = "rgb(E40046)",
-- Inactive tab fill: blue background recedes visually.
inactive = "rgb(5018dd)",
-- Locked-group tab colours mirror the border locked colours for consistency.
locked_active = "rgb(E40046)",
locked_inactive = "rgb(5018dd)",
},
},
},
decoration = {
-- Window corner radius (px). 20 px gives a modern "card" look that matches
-- the GTK cyberqueer theme's rounded widgets.
rounding = 20,
-- Focused window: fully opaque (1.0) so content is crisp and readable.
active_opacity = 1,
-- Unfocused windows: 80% opacity hints at the depth/focus hierarchy and lets
-- the wallpaper or background windows bleed through subtly without obscuring content.
inactive_opacity = 0.8,
blur = {
-- Gaussian blur applied behind transparent/translucent surfaces (terminals,
-- unfocused windows). This creates the "frosted glass" depth effect.
enabled = true,
size = 3, -- blur kernel radius in pixels; small = tight, localised blur halo
passes = 3, -- number of successive blur passes; more = smoother but higher GPU cost
-- vibrancy boosts colour saturation of the blurred background so the wallpaper
-- colours stay vivid even when blurred under a translucent surface.
vibrancy = 0.1696,
},
},
animations = {
-- Master switch for all compositor animations.
-- Individual animation types are configured below in the animations section.
enabled = true,
},
dwindle = {
-- preserve_split = true: when a split window is closed and then reopened,
-- Hyprland restores the previous split direction instead of always defaulting
-- to horizontal. This prevents the layout from constantly collapsing and re-splitting.
preserve_split = true,
-- Windows in the special (scratchpad) workspace are scaled down to 95% so they
-- visually "float" above the regular workspace content when toggled in.
special_scale_factor = 0.95,
},
master = {
-- New windows claim the master (largest) pane rather than being added as a slave,
-- so the most recently launched app always gets the most prominent position.
new_status = "master",
-- Same 95% scratchpad scale as dwindle, for visual consistency.
special_scale_factor = 0.95,
},
misc = {
-- force_default_wallpaper = 0 disables Hyprland's built-in anime wallpaper so
-- hyprpaper (or any other wallpaper daemon) has exclusive control of the background.
force_default_wallpaper = 0,
-- Remove the Hyprland logo / splash animation that plays on startup.
-- The custom wallpaper is shown instead from the first frame.
disable_hyprland_logo = true,
},
})
-----------------
---- ANIMATIONS --
-----------------
-- Define a custom cubic Bezier easing curve named "myBezier".
-- Control points P1 = {0.05, 0.9} and P2 = {0.1, 1.05} produce a slight overshoot
-- (spring-like bounce) at the end of the motion — windows "pop" snappily into their
-- final position rather than gliding to a dead stop. This gives the DE an energetic feel.
hl.curve("myBezier", { type = "bezier", points = { {0.05, 0.9}, {0.1, 1.05} } })
-- Window open and resize animation uses the custom spring curve.
-- speed = 7 (Hyprland internal units; higher = faster) keeps the open feeling snappy.
hl.animation({ leaf = "windows", enabled = true, speed = 7, bezier = "myBezier" })
-- Window close animation: "popin 80%" shrinks the window to 80% of its original size
-- while it fades out, giving a quick snappy dismiss effect rather than a slow full collapse.
hl.animation({ leaf = "windowsOut", enabled = true, speed = 7, bezier = "default", style = "popin 80%" })
-- Border colour crossfade when focus changes (active red <-> inactive blue).
-- speed = 10 makes this almost instantaneous so focus changes feel immediate.
hl.animation({ leaf = "border", enabled = true, speed = 10, bezier = "default" })
-- Animated gradient angle for the active border (the rotating multi-stop red gradient).
-- speed = 8 produces a slow, ambient-pulse sweep rather than a distracting fast spin.
hl.animation({ leaf = "borderangle", enabled = true, speed = 8, bezier = "default" })
-- Opacity crossfade when a window gains or loses focus (1.0 <-> 0.8 transition).
hl.animation({ leaf = "fade", enabled = true, speed = 7, bezier = "default" })
-- Special (scratchpad) workspace entrance/exit animation.
-- "slidevert" makes it drop in from the top / slide back up, distinguishing it clearly
-- from regular workspace transitions which use horizontal slides by default.
hl.animation({ leaf = "specialWorkspace", enabled = true, speed = 10, bezier = "default", style = "slidevert" })
--------------
---- DEVICE ---
--------------
-- Per-device input override for a specific mouse identified by its kernel event name.
-- Only fields that differ from the global input settings need to be listed here.
-- sensitivity = -0.5 (valid range -1 to 1) reduces pointer speed for this mouse model
-- without touching the global sensitivity, allowing different mice to have different feels.
hl.device({
name = "epic-mouse-v1",
sensitivity = -0.5,
})