---
title: Hyprland
description: Hyprland Lua config layered on Omarchy — bindings ported from niri, master layout, terminal-only blur, monitors, and the omarchy-* helper scripts.
---

[Hyprland](https://hypr.land) is a dynamic tiling Wayland compositor. This config uses Hyprland's Lua configuration and sits on top of [Omarchy](https://omarchy.org), which provides the defaults, theme, menus, and `omarchy-*` commands. The files here only override. Most bindings are ported from the [niri config](/desktop/niri) so the same keys do the same jobs.

:::note
`~/.config/hypr` and the `omarchy-*` scripts are **not** listed in `.chezmoiignore.tmpl`. chezmoi applies them on every role and OS, including `mac` and `server`. They only take effect where Hyprland and Omarchy are installed.
:::

## Files

| Source (repo) | Target | Purpose |
| --- | --- | --- |
| `dot_config/hypr/hyprland.lua` | `~/.config/hypr/hyprland.lua` | Entry point, workspace and window rules |
| `dot_config/hypr/autostart.lua` | `~/.config/hypr/autostart.lua` | Extra autostart (empty) |
| `dot_config/hypr/bindings.lua` | `~/.config/hypr/bindings.lua` | Keybindings |
| `dot_config/hypr/input.lua` | `~/.config/hypr/input.lua` | Key repeat, tablet/touch mapping |
| `dot_config/hypr/looknfeel.lua` | `~/.config/hypr/looknfeel.lua` | Layout, decoration, blur |
| `dot_config/hypr/monitors.lua` | `~/.config/hypr/monitors.lua` | Monitor modes and positions |
| `dot_config/hypr/hyprsunset.conf` | `~/.config/hypr/hyprsunset.conf` | Night-light profile |
| `dot_config/hypr/xdph.conf` | `~/.config/hypr/xdph.conf` | xdg-desktop-portal-hyprland |
| `dot_config/hypr/dot_luarc.json` | `~/.config/hypr/.luarc.json` | Lua language server settings |
| `dot_local/bin/executable_omarchy-*` | `~/.local/bin/omarchy-*` | Helper scripts (see [below](#omarchy-scripts)) |

None are templates. Hyprland and Omarchy are not in `.chezmoidata/packages.yaml`. They come from the Omarchy install.

## Entry point

`hyprland.lua` loads Omarchy, then the personal files, then Omarchy's toggles:

```lua ~/.config/hypr/hyprland.lua
dofile((os.getenv("OMARCHY_PATH") or "/usr/share/omarchy") .. "/default/hypr/bootstrap.lua")
require("default.hypr.omarchy")

require("hypr.monitors")
require("hypr.input")
require("hypr.bindings")
require("hypr.looknfeel")
require("hypr.autostart")

require("default.hypr.toggles")
```

Omarchy's default bindings stay enabled. `omarchy_default_bindings` and `omarchy_preinstalled_bindings` are left commented. `bindings.lua` unbinds each default it replaces.

### Workspace rules

| Workspace | Monitor |
| --- | --- |
| 3 | `desc:Apple Computer Inc StudioDisplay 0x984262A7` (EDID match, survives connector changes) |
| 4 | `eDP-1` |
| 5 | `eDP-1` |

### Window rules

| Class | Rule |
| --- | --- |
| `^brave-www\.tldraw\.com__-Default$` | Workspace 3 |
| `^tldraw-offline$` | Workspace 5, fullscreen |
| `^com\.anthropic\.Claude$`, `^kitty-herdr$` | `special:scratchpad silent` |
| `^com\.fastmail\.Fastmail$` | `special:fastmail silent` |
| `^Beeper$` | `special:beeper silent` |
| `brave-(www\.)?youtube\.com__.*`, title not matching `.*Picture.?in.?[Pp]icture.*` | Float, pin, size 30% × 30% of the monitor, move to `10, monitor_h*0.7-10` (bottom-left corner) |

Scratch residents are placed `silent` so that [`omarchy-toggle-scratch`](#omarchy-toggle-scratch) decides when to reveal them. The YouTube rule matches both `youtube.com` and `www.youtube.com` because Chromium's class changes once a video plays. It excludes the picture-in-picture overlay so Omarchy's own PiP rule still applies. Its size and inset must stay in sync with [`omarchy-pip`](#omarchy-pip).

## Input

`input.lua`:

- `repeat_delay = 250` (Omarchy's value), `repeat_rate = 50` (raised from 40). The file's comments record that 200/50 felt too fast. The typing lag it was meant to fix came from the keyboard's firmware tap-hold handling and was fixed on the keyboard itself.
- Tablet and touch devices are pinned to one output each:

| Device | Output | Extra |
| --- | --- | --- |
| `elan9008:00-04f3:43c7-stylus` (Flow Z13 pen) | `eDP-1` | |
| `elan9008:00-04f3:43c7` (Flow Z13 touchscreen) | `eDP-1` | Taps land on the panel instead of the focused monitor |
| `wacom-intuos-bt-s-pen` | `desc:Apple Computer Inc StudioDisplay 0x984262A7` | `active_area_size = { 152, 85.5 }`, `active_area_position = { 0, 0 }` — a 16:9 band cropped from the 16:10 tablet |

The layout, touchpad, and gesture examples in the file are commented out. Palm rejection is done by a libinput quirks file in `/etc`, which chezmoi does not manage.

## Look and feel

`looknfeel.lua` loads after the Omarchy theme's `hyprland.lua`, so its values override the theme's. The theme sets colors. This file sets everything else. The approach is flat windows by default, with blur only behind terminals.

| Setting | Value |
| --- | --- |
| `general.layout` | `master` (instead of Omarchy's dwindle; per-workspace layouts saved by `omarchy-hyprland-workspace-layout-toggle` still win) |
| `decoration.rounding` | 0 |
| `decoration.blur` | enabled; `size 5`, `passes 2`, `brightness 0.8`, `contrast 1.1`, `vibrancy 0.15`, `noise 0.01`, `new_optimizations`, `popups = false` |
| `decoration.shadow` | disabled |
| `group.groupbar.gradient_rounding` | 0 |
| Workspace animation | disabled (`hl.animation({ leaf = "workspaces", enabled = false })`) |

Blur must be enabled globally before any window can use it, so every window tagged `default-opacity` gets `no_blur = true`, and terminals get it back:

```lua ~/.config/hypr/looknfeel.lua
o.window({ tag = "default-opacity" }, { no_blur = true })
o.window(
  "^(kitty(-.*)?|Alacritty|com\\.mitchellh\\.ghostty|foot|org\\.codeberg\\.dnkl\\.foot|wezterm)$",
  { no_blur = false }
)
```

Omarchy's stock fade (0.985 active / 0.96 inactive) is kept. Terminals get their transparency from kitty's `background_opacity 0.9` (see [kitty](/terminal/kitty)). The comments give the reason for limiting blur: the cyberdream and Spectra themes enabled rounding, blur, and shadow on every window, and that costs frame time on an iGPU driving the laptop panel plus a 5K display.

## Monitors

`monitors.lua`:

| Output | Mode | Position | Scale |
| --- | --- | --- | --- |
| any (fallback) | `preferred` | `auto` | 2 |
| `DP-4` (Apple Studio Display) | `5120x2880@60` | `0x0` | 2 |
| `eDP-1` (laptop) | `2560x1600@180` | `2560x0` | 2 |

`GDK_SCALE=2` is exported. The Studio Display sits left of the laptop panel. At scale 2 its logical width is 2560, so `eDP-1` starts at x = 2560.

## hyprsunset and portal

```ini ~/.config/hypr/hyprsunset.conf
profile {
    time = 07:00
    identity = true
}
```

The identity profile stops hyprsunset from tinting the screen. A commented 20:00 / 4000 K night profile and an `o.launch_on_start("hyprsunset")` hint remain in the file.

```ini ~/.config/hypr/xdph.conf
screencopy {
    allow_token_by_default = true
    custom_picker_binary = hyprland-preview-share-picker
}
```

Screen-share requests get a restore token by default and use `hyprland-preview-share-picker` as the source picker.

## .luarc.json

Configures lua-language-server for the Lua config: the library path is `/usr/share/hypr/stubs`, `checkThirdParty` is off, and `hl` and `o` are declared as globals.

`autostart.lua` contains only a commented `o.launch_on_start` example.

## Keybindings

Every binding defined in `bindings.lua`. Bindings not listed here are Omarchy defaults. The *Replaces* column gives the Omarchy default that was unbound first.

### Windows

| Keys | Action | Replaces |
| --- | --- | --- |
| `SUPER + Q` | Close window | same (made explicit) |
| `SUPER + W` | `omarchy-toggle-layout` — flip workspace layout | close window |
| `SUPER + BACKSPACE` | Focus last window | toggle transparency |
| `SUPER + TAB` | Next window in the active workspace | next workspace |
| `SUPER + SHIFT + TAB` | Previous window in the active workspace | previous workspace |
| `SUPER + H` / `J` / `K` / `L` | Focus left / down / up / right | `J`: toggle split, `K`: keybindings menu, `L`: toggle layout |
| `SUPER + D` | Toggle split (dwindle `togglesplit`) | — |
| `SUPER + SHIFT + H` | `omarchy-smart-move l` — move/merge left; floating: bottom-left corner | — |
| `SUPER + SHIFT + J` | `omarchy-smart-move d` — move/merge down; floating: top-left | — |
| `SUPER + SHIFT + K` | `omarchy-smart-move u` — move/merge up; floating: top-right | — |
| `SUPER + SHIFT + L` | `omarchy-smart-move r` — move/merge right; floating: bottom-right | — |
| `SUPER + SHIFT + T` | `omarchy-pip` — toggle picture-in-picture | — |

`SUPER + TAB` walks a ring built only from the active workspace's mapped windows, ordered by `stable_id`. Grouped windows stay in the ring and hidden ones are skipped. It raises the focused window afterwards. It avoids `cyclenext`, which would pull in a hidden scratchpad. `binds.movefocus_cycles_groupfirst = true` makes `hjkl` focus step through a group's tabs before leaving the group.

### Workspaces and monitors

| Keys | Action | Replaces |
| --- | --- | --- |
| `SUPER + CTRL + J` | Next workspace (`e+1`) | — |
| `SUPER + CTRL + K` | Previous workspace (`e-1`) | Herdr keybindings |
| `ALT + Q` / `W` / `E` / `R` / `T` | Switch to workspace 1 / 2 / 3 / 4 / 5 | — |
| `ALT + SHIFT + Q` / `W` / `E` / `R` / `T` | Move window to workspace 1 / 2 / 3 / 4 / 5 | — |
| `SUPER + CTRL + S` | `omarchy-toggle-scratch scratchpad` | share menu |
| `SUPER + A` | `omarchy-toggle-scratch scratchpad` | — |
| `SUPER + O` | Focus next monitor | pop window out |
| `SUPER + SHIFT + O` | Move window to next monitor | Obsidian |
| `SUPER + CTRL + SHIFT + J` | Move window to next monitor | — |
| `SUPER + CTRL + SHIFT + K` | Move window to previous monitor | — |
| `SUPER + SHIFT + CTRL + ALT + W` | Workspace `name:w` | — |
| `SUPER + SHIFT + CTRL + ALT + H` | Workspace `name:h` | — |
| `SUPER + CTRL + ALT + X` | Workspace `name:x` | — |

Named workspaces replace niri-dynamic-workspaces. `SUPER + ALT + S` (send to scratchpad) keeps its Omarchy default.

### Sizing

| Keys | Action |
| --- | --- |
| `SUPER + R` | `omarchy-cycle-window-size` — next preset size |
| `SUPER + SHIFT + R` | `omarchy-cycle-window-size prev` |
| `ALT + H` | Width −100 px |
| `ALT + L` | Width +100 px |
| `ALT + K` | Height −100 px |
| `ALT + J` | Height +100 px |
| `SUPER + ALT + C` | Fit active column (scrolling layout only) |
| `SUPER + SHIFT + ALT + C` | Fit visible columns (scrolling layout only) |

### Applications

| Keys | Action | Replaces |
| --- | --- | --- |
| `SUPER + CTRL + A` | Claude: `omarchy-launch-or-focus claude "gtk-launch com.anthropic.Claude"` | audio panel |
| `SUPER + CTRL + G` | Gemini: `omarchy-launch-or-focus gemini "gtk-launch gemini-desktop"` | — |
| `SUPER + CTRL + ALT + H` | `omarchy-cycle ai` | — |
| `SUPER + CTRL + ALT + J` | `omarchy-cycle-terminal` | — |
| `SUPER + CTRL + ALT + K` | `omarchy-cycle-browser` | — |
| `SUPER + CTRL + ALT + G` | `omarchy-cycle ghostty` | — |
| `SUPER + CTRL + ALT + O` | `omarchy-cycle obsidian` | — |
| `SUPER + CTRL + ALT + F` | Nautilus: `omarchy-launch-or-focus nautilus "gtk-launch org.gnome.Nautilus"` | — |
| `SUPER + CTRL + ALT + E` | `omarchy-toggle-scratch fastmail` | — |
| `SUPER + CTRL + ALT + M` | `omarchy-toggle-scratch beeper` | — |
| `SUPER + CTRL + ALT + Y` | `omarchy-summon youtube` | web apps cycle |
| `SUPER + SHIFT + Y` | `omarchy-summon youtube` | YouTube desktop entry |
| `SUPER + CTRL + ALT + T` | tldraw offline: `omarchy-launch-or-focus tldraw-offline "gtk-launch tldraw-offline"` | show time |
| `SUPER + CTRL + ALT + W` | tldraw: `omarchy-launch-or-focus tldraw "gtk-launch TLDraw"` | toggle weather |
| `SUPER + CTRL + ALT + SPACE` | Sticky Notes Canvas via `gtk-launch io.github.faridjaff.StickyNotesCanvas` | — |
| `SUPER + SHIFT + G` | Goliath: `kitty --class=kitty-goliath --title=goliath --config ~/.config/kitty/goliath.conf` | Signal |
| `SUPER + SHIFT + F` | `flea --gui` | unbound first (default unnamed) |
| `SUPER + ALT + SHIFT + F` | `flea --gui "$(omarchy-cmd-terminal-cwd)"` — file manager in the terminal's cwd | unbound first (default unnamed) |

The two `flea` bindings and a rule tagging `com.thisisgm.flea.picker` as `+floating-window` sit between `flea --default` / `flea --picker` marker comments. The `flea` tool writes and removes those blocks itself.

### Screenshots, session, menus

| Keys | Action | Replaces |
| --- | --- | --- |
| `SUPER + S` | `omarchy-capture-screenshot region` | toggle scratchpad |
| `SUPER + SHIFT + S` | `omarchy-capture-screenshot windows` | Google Maps |
| `SUPER + SHIFT + ALT + S` | `omarchy-capture-screenshot fullscreen` | — |
| `SUPER + SHIFT + E` | `omarchy-menu toggle system` | Email |
| `SUPER + SHIFT + Q` | `omarchy-menu toggle system` | — |
| `SUPER + F24` | `voxtype record toggle --profile hermes` — dictation | — |
| `SUPER + SHIFT + SPACE` | Emoji picker (`omarchy-shell shell toggle omarchy.emojis`) | toggle top bar |
| `SUPER + P` | Clipboard manager (`omarchy-shell shell toggle omarchy.clipboard`) | pseudo window |
| `ALT + TAB` | ScrollOverview `toggle all` (only when the plugin is loaded) | Omarchy's two `ALT + TAB` binds |

`SUPER + SPACE` (Omarchy menu), `SUPER + ALT + SPACE` (apps menu), and `SUPER + SHIFT + RETURN` (browser) keep their Omarchy defaults.

### ScrollOverview plugin

When `hl.plugin.scrolloverview` is present, `bindings.lua` configures it:

| Option | Value |
| --- | --- |
| `gesture_distance` | 300 |
| `scale` | 0.5 |
| `workspace_gap` | 100 |
| `layout` | `vertical` |
| `wallpaper` | 2 (global and per-workspace) |
| `blur` | true |
| `shadow` | enabled, range 50 |

## omarchy scripts

The scripts live in `dot_local/bin/` as `executable_omarchy-*` and deploy to `~/.local/bin/`. Each one calls the Lua dispatcher first (`hyprctl dispatch "hl.dsp…"`) and falls back to the classic dispatcher name on older Hyprland.

### omarchy-cycle

```sh
omarchy-cycle <app|browser|brave|terminal|ai|ghostty|kitty|kitty-CLASS|webapp|webapp-NAME>
```

Focuses an app's window, cycles to the next one on repeated presses, or launches the app when none is open. Windows are matched on `class` or `initialClass` (case-insensitive) and sorted by workspace, then address. If the focused window is not in the set, focus goes to the first one. Launches use `setsid uwsm-app --`.

| Argument | Matches | Launches when none |
| --- | --- | --- |
| `webapp` | `^(webapp-\|chrome-)` | re-runs as `webapp-youtube` |
| `webapp-NAME` | `webapp-NAME` or `^chrome-.*NAME` | `gtk-launch` on the first `WebApp-NAME*.desktop` or `*NAME*.desktop` in `~/.local/share/applications` |
| `kitty` | `^kitty` | `kitty` |
| `kitty-CLASS` | `^kitty-CLASS$` | `kitty --class kitty-CLASS` (command from the empty `KITTY_CMDS` map, if set) |
| `ghostty` | `ghostty` | `ghostty` |
| `browser` | zen, brave, chromium, google-chrome, firefox, librewolf, vivaldi, microsoft-edge, helium — excluding `chrome-`/`webapp-` web apps | `omarchy-launch-browser` |
| `brave` | `^brave` (Brave Origin and its web apps) | `brave-origin` |
| `terminal` | kitty, alacritty, ghostty, foot, wezterm — excluding `^kitty-herdr$` (the scratchpad terminal) | `omarchy-launch-terminal` |
| `ai` | `claude\|hermes` | `hermes desktop` |
| anything else | `^APP$` | the argument as a command |

Bound to `SUPER + CTRL + ALT + H` (`ai`), `G` (`ghostty`), and `O` (`obsidian`).

### omarchy-cycle-browser / omarchy-cycle-terminal

One-line wrappers: `omarchy-cycle brave` and `omarchy-cycle terminal`. Bound to `SUPER + CTRL + ALT + K` and `SUPER + CTRL + ALT + J`.

### omarchy-cycle-window-size

```sh
omarchy-cycle-window-size [next|prev]
```

Steps the focused window through preset widths `0.333, 0.5, 0.667` of the monitor.

- **Scrolling layout (tiled):** sends `colresize +conf` / `-conf`, so the layout's own preset list is used.
- **Floating:** resizes to the fraction × monitor width and 0.8 × monitor height, then centers. The index is stored per window.
- **Dwindle/master (tiled):** sets `splitratio` to `2 × fraction`, mirrored when the window is on the right or bottom half, clamped to 0.1–1.9. The index is stored per workspace.

Indices are stored in `$XDG_STATE_HOME/omarchy/window-sizes/`. Bound to `SUPER + R` and `SUPER + SHIFT + R`.

### omarchy-pip

```sh
omarchy-pip [toggle|on] [address:0x...]
```

Picture-in-picture for any window. Floats and pins it, resizes it to 30% of the focused monitor on both axes, and places it in the bottom-left corner with a 10 px inset (matching `general:gaps_out`). `toggle` (the default) unpins and re-tiles a window that is already floating and pinned. `on` always applies the fit. Defaults to the active window. The dispatcher is called with `on`/`off` because `set` toggles on Hyprland 0.56. Bound to `SUPER + SHIFT + T`. `omarchy-summon` also calls it.

### omarchy-smart-move

```sh
omarchy-smart-move <l|r|u|d>
```

- **Tiled:** finds the nearest tiled, visible window in that direction that overlaps on the other axis. If that neighbor, or the focused window, is in a group, it runs a group-aware move (`movewindoworgroup`), which merges into or leaves a group. Otherwise it swaps with the neighbor.
- **Floating:** moves the window to a corner of its monitor without resizing, inside the reserved area (the bar) and inset 10 px. Corners go clockwise from bottom-left: `l` bottom-left, `d` top-left, `u` top-right, `r` bottom-right.

Bound to `SUPER + SHIFT + H/J/K/L`.

### omarchy-summon

```sh
omarchy-summon [youtube]
```

The only profile is `youtube`, which matches class `^brave-(www\.)?youtube\.com__.*$` and skips Picture-in-Picture titles. With no window open, it runs `gtk-launch YouTube`, and the window rule in `hyprland.lua` floats and positions it. With a window open, it moves the window to the focused monitor, runs `omarchy-pip on` to refit it (the two panels differ in logical size), and focuses it. Bound to `SUPER + CTRL + ALT + Y` and `SUPER + SHIFT + Y`.

### omarchy-toggle-layout

```sh
omarchy-toggle-layout [width]
```

Runs `omarchy-hyprland-workspace-layout-toggle`, then polls the workspace layout (6 × 50 ms). If it became `scrolling`, it runs `colresize all <width>` (default `0.75`). Dwindle needs no widths. Bound to `SUPER + W`.

### omarchy-toggle-scratch

```sh
omarchy-toggle-scratch [scratchpad|fastmail|beeper]
```

| Profile | Special workspace | Home monitor | Residents (class → launch) |
| --- | --- | --- | --- |
| `scratchpad` | `special:scratchpad` | Apple Studio Display | `com.anthropic.Claude` → `claude-desktop`; `kitty-herdr` → `kitty --class=kitty-herdr --config ~/.config/kitty/herdr.conf` |
| `fastmail` | `special:fastmail` | focused | `com.fastmail.Fastmail` → `gtk-launch fastmail` |
| `beeper` | `special:beeper` | focused | `Beeper` → `gtk-launch beeper` |

If the workspace is visible, the script hides it. If not, it launches any resident with no window there, waits up to 8 s for the first new window, and reveals the workspace on the home monitor (or the focused one if the home monitor is absent). Launching only missing residents avoids duplicate web-app windows. Bound to `SUPER + CTRL + S`, `SUPER + A`, `SUPER + CTRL + ALT + E`, and `SUPER + CTRL + ALT + M`.

## Related

- [niri](/desktop/niri): the original config these bindings mirror.
- [Waybar](/desktop/waybar): the bar used with this setup.
- [kitty](/terminal/kitty): the `herdr` and `goliath` kitty configs launched here.
