222 lines
12 KiB
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,
|
|
})
|