-- ───────────────────────────────────────────────────────────────────────────── -- Look and feel -- Tokyo Night Moon -- -- Colours here must stay in sync with quickshell/config/Theme.qml. -- accent #82aaff borders / focus -- bg #222436 base -- -- Performance note: every animation below is event-driven. Nothing uses the -- "loop" style on borderangle/shadowangle/glowangle -- that style forces -- Hyprland to render at full refresh rate forever, even when nothing is -- visible, which is exactly the kind of idle GPU burn to avoid on a 4500x3000 -- display. -- ───────────────────────────────────────────────────────────────────────────── local prefs = require("prefs") hl.config({ general = { gaps_in = prefs.get("gapsIn", 5), gaps_out = prefs.get("gapsOut", 10), border_size = prefs.get("borderSize", 2), col = { -- The prism: blue leads, orchid follows, on a diagonal so the pair -- is visible on both a tall and a wide window. Same two colours as -- the shell's hairline (quickshell/widgets/PrismEdge.qml) and the -- tmux theme this palette came from. active_border = { colors = { "rgba(82aaffee)", "rgba(b172b0ee)" }, angle = 115 }, -- Unfocused windows get no colour at all. The gradient only means -- something if exactly one window on screen is wearing it. -- Follows the colour scheme: a dark neutral is invisible against a -- light desktop. services/ColorScheme.qml applies changes live; -- this is the value a fresh session starts from. inactive_border = prefs.get("colorScheme", "dark") == "light" and "rgba(a8aecb99)" or "rgba(3b426199)", }, resize_on_border = true, -- Enables the per-window "immediate" rule used for games in rules.lua. -- Harmless on its own; tearing only happens where a rule opts in. allow_tearing = true, layout = "dwindle", snap = { enabled = true }, }, decoration = { -- 18 to match the shell's popover radius, so a window and a panel sitting -- next to each other read as the same object family. rounding = prefs.get("windowRounding", 18), rounding_power = 2, active_opacity = 1.0, inactive_opacity = prefs.get("inactiveOpacity", 1.0), blur = { enabled = prefs.get("blurEnabled", true), size = prefs.get("blurSize", 8), passes = prefs.get("blurPasses", 3), -- Required for blur to be affordable. Never turn this off. new_optimizations = true, -- Floating windows skip blurring what's behind tiled ones. Big win. xray = true, ignore_opacity = true, noise = 0.0117, contrast = 0.9, brightness = 0.85, vibrancy = 0.17, vibrancy_darkness = 0.05, popups = true, popups_ignorealpha = 0.2, -- Blurring the special workspace is expensive and rarely seen. special = false, }, shadow = { enabled = prefs.get("shadowEnabled", true), range = prefs.get("shadowRange", 20), render_power = 3, sharp = false, color = "rgba(15161eee)", offset = { 0, 4 }, scale = 1.0, }, -- New in 0.56. Kept deliberately faint: in this direction the gradient -- border is the signature, and a strong halo would compete with it. -- This is just enough to lift the focused window off the wallpaper. glow = { enabled = prefs.get("glowEnabled", true), range = prefs.get("glowRange", 8), render_power = 2, color = "rgba(82aaff33)", color_inactive = "rgba(00000000)", }, -- Off: costs real frame time and reads as smeary on a 60Hz panel. motion_blur = { enabled = false }, }, animations = { enabled = prefs.get("animationsEnabled", true) }, dwindle = { -- Keep the split orientation a window was created with. Closest match -- to how the Forge extension behaved on GNOME. preserve_split = true, smart_resizing = true, }, misc = { force_default_wallpaper = 0, disable_hyprland_logo = true, disable_splash_rendering = true, -- Same setting as Theme.fontFamily in the shell. If only the QML side -- followed the preference, the compositor and the shell would disagree -- about the interface font and nobody would notice until a tooltip -- rendered in a different typeface. font_family = prefs.get("interfaceFont", "Adwaita Sans"), -- Variable refresh rate. 3 = enable only for fullscreen windows whose -- content type is "video" or "game" -- the tag rules.lua applies to -- games. Keeps VRR off the desktop, where it causes visible flicker. vrr = prefs.getInt("vrrPolicy", 3), -- Blur behind the lock screen. session_lock_blur = true, -- Let a crashed lock screen be recovered rather than stranding you. allow_session_lock_restore = true, -- Don't let apps steal focus by shouting; matches GNOME's behaviour. focus_on_activate = false, }, render = { -- Colour management is stable and on by default in 0.56. cm_enabled = true, -- 1 = automatically flip the monitor into HDR for fullscreen content -- that asks for it, and back out afterwards. This is how games get HDR -- without the desktop paying the screencopy cost. See monitors.lua. cm_auto_hdr = prefs.getInt("autoHdr", 1), -- 2 = direct scanout only for windows tagged content = "game" -- (set by the rules in rules.lua). Bypasses compositing for real -- fullscreen games. direct_scanout = prefs.getInt("directScanoutPolicy", 2), }, cursor = { -- 2 = auto. Disables the hardware cursor when tearing, which is what -- keeps the cursor from ghosting in games. no_hardware_cursors = 2, -- Don't let the cursor break VRR on content tagged as a game. no_break_fs_vrr = 2, min_refresh_rate = 48, -- Pull the cursor theme from gsettings so GTK apps and Hyprland agree. sync_gsettings_theme = true, -- Fade the cursor out after 4s of no movement, like GNOME does. inactive_timeout = prefs.get("cursorInactiveTimeout", 4), }, ecosystem = { no_update_news = true, no_donation_nag = true, }, xwayland = { -- Render X11 apps at 1:1 device pixels so they're sharp rather than -- bilinearly upscaled. See the note in README.md about the unavoidable -- sizing tradeoff at 1.5x. force_zero_scaling = true, }, quirks = { -- 2 = report HDR as preferred to gamescope only. Stops gamescope from -- white-screening when it expects HDR to already be live. prefer_hdr = 2, }, }) -- ── Motion ────────────────────────────────────────────────────────────────── -- speed is in deciseconds: speed = 4 means 400ms. Higher = slower. hl.curve("easeOutQuint", { type = "bezier", points = { { 0.23, 1 }, { 0.32, 1 } } }) hl.curve("almostLinear", { type = "bezier", points = { { 0.5, 0.5 }, { 0.75, 1 } } }) hl.curve("quick", { type = "bezier", points = { { 0.15, 0 }, { 0.1, 1 } } }) hl.curve("easy", { type = "spring", mass = 1, stiffness = 238.1191, dampening = 24.21279 }) -- A touch bouncier than "easy"; used for windows appearing. hl.curve("snappy", { type = "spring", mass = 1, stiffness = 320, dampening = 22 }) hl.animation({ leaf = "global", enabled = true, speed = 10, bezier = "default" }) hl.animation({ leaf = "border", enabled = true, speed = 5.39, bezier = "easeOutQuint" }) -- The focus sweep: when a window takes focus, its gradient border rotates into -- place once. Style "once" is load-bearing -- the alternative, "loop", makes -- Hyprland render at full refresh rate forever, even when no border is visible. -- That is exactly the idle GPU cost this config exists to avoid, so: never loop. hl.animation({ leaf = "borderangle", enabled = true, speed = 6, bezier = "easeOutQuint", style = "once" }) hl.animation({ leaf = "windows", enabled = true, speed = 4.79, spring = "easy" }) hl.animation({ leaf = "windowsIn", enabled = true, speed = 4.1, spring = "snappy", style = "popin 90%" }) hl.animation({ leaf = "windowsOut", enabled = true, speed = 1.49, bezier = "almostLinear", style = "popin 90%" }) hl.animation({ leaf = "fade", enabled = true, speed = 3.03, bezier = "quick" }) -- Layer surfaces = the Quickshell bar, dock, popovers and overlays. hl.animation({ leaf = "layers", enabled = true, speed = 3.81, bezier = "easeOutQuint" }) hl.animation({ leaf = "layersIn", enabled = true, speed = 3, bezier = "easeOutQuint", style = "fade" }) hl.animation({ leaf = "layersOut", enabled = true, speed = 2, bezier = "almostLinear", style = "fade" }) -- Workspace switching: horizontal slide, matching Alt+H / Alt+L direction. hl.animation({ leaf = "workspaces", enabled = true, speed = 2.5, bezier = "easeOutQuint", style = "slidefade 15%" }) hl.animation({ leaf = "zoomFactor", enabled = true, speed = 7, bezier = "quick" }) return true