Files
Panama/config/dot/hypr/README.md
T

14 KiB
Raw Blame History

Panama :: Hyprland

A Hyprland desktop built to reproduce the GNOME + Forge setup it replaces, so that muscle memory transfers unchanged.

The one thing to know first

Hyprland 0.55 replaced hyprlang with Lua. hyprland.conf still loads on 0.56 as a legacy fallback and is removed in 0.57. Everything here is Lua.

The authoritative option reference for the installed build is on disk:

File What it is
/usr/share/hypr/stubs/hl.meta.lua Generated type stub — the exact option list for this build
/usr/share/hypr/hyprland.lua Upstream example config

Wire the stub into your editor with .luarc.json in this directory for autocomplete.

The Hypr ecosystem tools did NOT move to Lua. hyprlock.conf, hypridle.conf, hyprpaper.conf and hyprtoolkit.conf are still hyprlang. Don't "fix" them.

Layout

File Contents
hyprland.lua Entry point. Each require() is its own error scope
env.lua Environment. Note the uwsm caveat below
monitors.lua DP-2 geometry, scaling, and the HDR decision
looks.lua Colours, blur, glow, shadows, animations, VRR, scanout
input.lua Keyboard/mouse. Click-to-focus, like GNOME
rules.lua Window rules, gaming rules, layer rules for the shell
keybinds.lua The full keymap
autostart.lua Session startup
overrides.lua Per-machine escape hatch, loaded last
hyprlock.conf / hypridle.conf / hyprpaper.conf / hyprtoolkit.conf Ecosystem tools (hyprlang)

Validate any change without leaving your session:

Hyprland --verify-config

The look

Tokyo Night Moon, with two accents that come from the tmux theme:

Token Value Role
accent #82aaff Carries every state meaning — focused, active, on
accentSecondary #b172b0 Never used alone; only the far end of a gradient

The signature is the prism: the two accents meeting. It appears in exactly four places, and nowhere else —

  1. A one-pixel hairline along the top edge of every glass surface (the bar, dock, popovers), running blue on the left to orchid on the right and fading out before the corners. See quickshell/widgets/PrismEdge.qml.
  2. The focused window's border — general.col.active_border, blue→orchid at 115°. Unfocused windows get no colour at all, because the gradient only means something if one window on screen is wearing it.
  3. The active workspace pill in the bar.
  4. Slider fills.

The restraint is the point. The pink stops being special the moment it's used as a flat fill, so it never is.

Typography

Adwaita Sans for everything the user reads as text — no monospace in the UI. A monospaced clock or percentage reads as terminal output pasted into a panel, which is the opposite of the intent.

The Nerd Font is still used, but only to draw icon glyphs — it is the pragmatic alternative to freedesktop symbolic icons, which ship with a hardcoded #2e3436 fill that Qt (unlike GTK) will not recolour. Where a themed freedesktop icon is wanted instead, quickshell/widgets/ThemedIcon.qml paints a palette colour through the icon's alpha.

Anything whose digits change in place — the clock, the vitals percentages, the recording timer, the selection readout — sets font.features: Theme.tabularFigures. Tabular figures share one advance width, so the text stops twitching as numbers tick without reaching for a monospaced face.

Window rounding is 18, matching the shell's popover radius, so a window and a panel next to each other read as the same family of object.

On animated gradient borders: Hyprland can rotate the border gradient continuously with borderangle + style = "loop". Don't. The wiki is explicit that it forces a full-refresh-rate repaint forever, even when no border is visible — at 4500×3000 that is pure idle GPU burn. This config uses style = "once", so the gradient sweeps into place when a window takes focus and then costs nothing.

Session: use the uwsm one

Log in as "Hyprland (uwsm-managed)", not plain "Hyprland".

xdg-desktop-portal-hyprland's systemd unit requires graphical-session.target, and Fedora ships no hyprland-session.target. Without uwsm that target never activates and screen sharing in OBS, Sunshine and Zoom silently fails.

The uwsm environment gotcha

hl.env() in env.lua exports into the compositor's environment, not the systemd user manager. Anything started as a user unit — vicinae.service, hyprpaper.service, hyprpolkitagent.service, hypridle.service — and every app those launch will not see it.

That is why ~/.config/uwsm/env and ~/.config/uwsm/env-hyprland exist and duplicate the important variables. Keep them in sync with env.lua; env.lua remains the fallback for the plain session.

HDR — read this before turning it on

GNOME ran this panel in bt2100/HDR. This config deliberately does not.

On Hyprland 0.56.x, cm = "hdr" currently breaks screencopy: grim screenshots come back empty, and OBS/Sunshine capture and hyprlock's blurred background go with them. Root cause is still open upstream.

So the desktop runs SDR at 10-bit (cm = "auto") and HDR is handed to fullscreen games only, via render.cm_auto_hdr = 1 in looks.lua. Games get HDR; screenshots keep working.

To try full-time HDR anyway, overrides.lua has the block and the ordered list of workarounds to reach for when things break.

Keymap

The mental model is unchanged from Forge:

  • SUPER acts on windows
  • ALT acts on workspaces
  • SUPER + CTRL changes layout structure

Windows

Key Action
SUPER + H/J/K/L (or arrows) Focus
SUPER + SHIFT + H/J/K/L Move window
SUPER + CTRL + H/J/K/L Swap window
SUPER + SHIFT + Y/O · B/M Wider · narrower
SUPER + SHIFT + I/U · P/N Taller · shorter
SUPER + [ / ] / = Shrink / expand / reset split
SUPER + Q Close
SUPER + U Fullscreen
SUPER + CTRL + C Toggle float
SUPER + CTRL + SHIFT + C Pin (nearest thing to Forge's "always float")
SUPER + CTRL + G / Z / V Toggle split / preselect right / preselect down
SUPER + Tab / SHIFT + Tab Cycle windows
SUPER + SHIFT + grave Last window
SUPER + X / SUPER + SHIFT + X Restore scratchpad / minimise to scratchpad

Workspaces (dynamic, like GNOME)

Key Action
ALT + H / ALT + L Previous / next workspace
ALT + SHIFT + H/L Move window to previous / next
ALT + 1..9, ALT + 0 Jump to workspace
ALT + SHIFT + 1..9 Send window to workspace
SUPER + scroll Change workspace

Launcher and shell

Key Action
SUPER + A / R / Space Launcher (vicinae) — all three, pick your favourite
SUPER + SHIFT + R Fallback launcher (wofi) if the shell is broken
SUPER + V Clipboard history
SUPER + . Emoji picker
SUPER + S Quick settings
SUPER + I Panama Settings
SUPER + SHIFT + F Start or reveal focus session
SUPER + B Notification centre
SUPER + grave Workspace overview
Print Screenshot / record picker
SHIFT / ALT + Print Screenshot screen / window immediately
SUPER + SHIFT + S Screen Intelligence — read text and codes from a selection
SUPER + SHIFT + P Colour picker
CTRL + ALT + L Lock (SUPER+L is "focus right")
CTRL + ALT + Delete Power menu

Apps

SUPER + T terminal · N neovim · W browser · F files · C calculator · E mail · I Panama Settings · CTRL + SHIFT + Esc system monitor. GNOME Settings remains searchable in Vicinae for hardware and account panels.

Calendar and notifications

Click the clock to open the two-column Daybook on Agenda. The month grid, today's schedule, Up Next, weather, and conditional media controls stay visible together. Its right pane has three first-class pages:

  • Agenda — the selected day's calendar.
  • Ongoing — Focus, Caffeine, recording, screen sharing, camera, and microphone activity, visible until each state ends.
  • Notifications — grouped history, Do Not Disturb, and clear actions.

SUPER + B opens Notifications directly. Switching pages preserves the selected date and visible month. Brief completed events such as screenshots and device changes remain in Signal Glass instead of accumulating in Ongoing.

Calendar data comes from Evolution Data Server, so the Google, iCloud, Nextcloud, and local calendars already configured for GNOME remain the source of truth. Panama never stores account credentials. Use GNOME Calendar or Online Accounts to add and manage accounts, and click an event in Daybook to hand off editing and full detail to GNOME Calendar.

The right side of the bar shows a small calendar capsule only from 15 minutes before a timed event until 5 minutes after it starts. It displays relative time (12m or Now); the event title is available on hover but otherwise stays out of the bar. All-day events never trigger the capsule.

Control Center

Click the right-side status cluster or press SUPER + S for Panama's Control Center. It is attached directly beneath the bar and keeps Wi-Fi, Bluetooth, Caffeine, Night Light, Focus, audio input/output, user, settings, and power in one place. Home and Phone continue the same surface rather than opening extra dashboard windows.

Home shows the first four configured Home Assistant favourites as direct controls and expands to the complete configured list. Panama reads the current GNOME Home Assistant extension configuration and its Secret Service token as a compatibility fallback, so the existing setup works without copying a secret. The preferred private configuration lives in the gitignored config/bash/env file:

export PANAMA_HOME_ASSISTANT_URL=https://home.example.test
export PANAMA_HOME_ASSISTANT_TOKEN=replace-with-a-long-lived-token
export PANAMA_HOME_ASSISTANT_ENTITIES=light.kitchen,light.living_room

The helper reads that file directly. No shell restart is required after editing it; close and reopen Control Center to refresh. If Home Assistant is offline, the last known values stay visible with a stale-state label and Retry action.

Phone uses KDE Connect for the capabilities the paired iPhone actually advertises: Send File, Send Clipboard, and Ring. The device remains visible while iOS suspends KDE Connect, but actions stay disabled until it reconnects. No battery percentage is invented when iOS reports none, and BlueBubbles remains the messaging experience. Active file sends appear in Daybook's Ongoing page; successful sends become a quiet recent exchange.

Screen Intelligence

SUPER + SHIFT + S opens the capture picker directly in Selection + Read mode. Read is also available beside Screenshot and Record under Print, and works on a whole display, a window, or a region. Tesseract recognizes English text locally; ZBar recognizes QR codes and barcodes. The result sheet can copy text, search it, translate it, or open a detected web address. No pixels leave the workstation unless one of those explicit network actions is selected.

Deliberate deviations from GNOME

These are the places a 1:1 port was impossible, and what was done instead:

  • Per-edge resize. Forge resized one named edge; Hyprland resizes along an axis and lets the layout pick the edge. The eight Forge keys collapse to four behaviours, keeping the horizontal/vertical and grow/shrink pairing.
  • Overview on SUPER + grave, not a bare SUPER tap. Tap-detection on a modifier misfires when you're quick with SUPER combos.
  • Lock on CTRL + ALT + L. SUPER + L is "focus right" in this keymap.
  • SUPER + grave was Forge's "cycle windows of same app", which Hyprland has no equivalent for. "Last window" moved to SUPER + SHIFT + grave.
  • gnome-control-center is launched with XDG_CURRENT_DESKTOP=GNOME, because it hard-refuses to start otherwise. Panels backed by system services work; panels backed by GNOME Shell (Displays, Keyboard Shortcuts, Multitasking, Appearance) are inert — Hyprland owns those now.

Gaming

content = "game" on the window rules in rules.lua is the keystone — it is what misc.vrr = 3, render.direct_scanout = 2 and cursor.no_break_fs_vrr = 2 key off. Games additionally get blur, animation, shadow and dim disabled, plus immediate for tearing.

Tearing only takes effect when the game is fullscreen and the only thing on screen — no bar, no notifications.

Do not install a notification daemon

mako, dunst and SwayNotificationCenter all register Name=org.freedesktop.Notifications for D-Bus activation. Installing any of them creates a startup race against Quickshell's notification server, and whoever wins keeps the name. If one gets installed as a dependency, systemctl --user mask <name>.service.

Troubleshooting

Nothing autostarts — check systemctl --user status hyprland-session.target and systemctl --user show-environment | grep WAYLAND_DISPLAY. An empty environment means uwsm didn't export it and units with ConditionEnvironment=WAYLAND_DISPLAY silently skip.

Screen sharing missingbusctl --user list | grep impl.portal should show xdg-desktop-portal-hyprland.

Qt apps look wrongQT_QPA_PLATFORMTHEME must be gtk3. It is a single value, not a list: Qt splits on : and uses only the first token.

Wrong GPU / won't startAQ_DRM_DEVICES points at /dev/dri/amd-dgpu, created by config/copy/etc/udev/rules.d/99-panama-gpu.rules. Both env.lua and uwsm/env-hyprland guard on the symlink existing, so a missing rule degrades to "let aquamarine choose" rather than failing to start.