A fast application launcher for Arch Linux + Hyprland, written in Rust.
Hyprburst opens its own GPU-rendered window with a semi-transparent blurred background. Rio's embeddable terminal engine manages the launcher's PTY and VT grid, while Hyprburst keeps ownership of its Wayland surface and OpenGL renderer. It displays apps in a grid with icons, uses hybrid fuzzy/prefix search with recency+frequency scoring, and tracks launch history in SQLite for smart ranking.
- Rio terminal engine —
rio-vtmanages PTY lifecycle, VT parsing, resize, input, and terminal grid state - Native GPU window — winit + OpenGL paints Rio's grid while owning the Wayland surface for proper blur/transparency
- Modern aesthetic — Clean monospace, subtle accent colors, custom ASCII art banners
- Fast — <50ms startup, instant search results as you type
- Smart ranking — Results ranked by recency (exponential decay) + frequency (launch count)
- Icon grid — Apps displayed with monochrome Nerd Font glyphs matched by category (browser, terminal, editor, etc.)
- SQLite history — Tracks launch history for smarter results and usage stats
- TOML config — Customizable window, font, colors, banner, and layout at
~/.config/hyprburst/config.toml - Hyprland native — Launches apps via
hyprctl dispatch(auto-detects the 0.55+ Luahl.dspform) - Terminal fallback —
hyprburst tuiruns the launcher inline in any terminal for SSH / no-GPU sessions
Screenshots and a short screen capture live here. Hyprburst is a floating overlay, so a still of the grid plus a few-second recording of type-to-filter and launch convey it best. Drop assets under
docs/(e.g.docs/demo.gif,docs/grid.png) and link them in this section.
hyprburst/
├── src/
│ ├── main.rs # Entry point: Rio default, native/TUI fallbacks, bench modes
│ ├── lib.rs # Module tree (domain / view / gpu / tui / system / bench)
│ ├── bench.rs # Footprint probes for `--measure` / `--bench-startup`
│ ├── domain/ # Frontend-agnostic state + data (no rendering)
│ │ ├── launcher_core.rs # Launcher state machine
│ │ ├── config.rs # TOML config, XDG paths, optional Swatches theme
│ │ ├── search.rs # Hybrid fuzzy/prefix ranking
│ │ ├── history.rs # SQLite-backed launch history
│ │ ├── icon.rs # Nerd Font glyph mapping by keyword (browser, editor, ...)
│ │ └── desktop.rs # .desktop file discovery and parsing
│ ├── view/ # Shared ratatui-buffer painting (both frontends)
│ │ ├── render.rs # render_core: paints the launcher into a Buffer
│ │ └── layout.rs # Pure layout geometry (list + grid modes)
│ ├── gpu/ # Native window/renderer and Rio VT adapter
│ │ ├── window.rs # winit + glutin + glow cell renderer; frontend routing
│ │ ├── rio.rs # rio-vt PTY, terminal grid, input, resize, and snapshots
│ │ ├── grid.rs # Cell metrics, glyph atlas, grid geometry
│ │ └── font.rs # Cell-font resolution (path / $HYPRBURST_FONT / family / Nerd Font)
│ ├── tui/ # Crossterm/ratatui fallback frontend (`hyprburst tui`)
│ │ ├── launcher.rs # Launcher widget + crossterm key mapping
│ │ ├── app.rs # TUI application state and event loop
│ │ ├── input.rs # Keyboard input handling and event polling
│ │ ├── terminal.rs # Terminal lifecycle (raw mode, panic restore)
│ │ └── effects.rs # Fade-in animation via tachyonfx (TUI only)
│ └── system/
│ └── hyprland.rs # hyprctl dispatch (legacy + 0.55+ Lua `hl.dsp` forms)
├── packaging/
│ ├── hyprburst.conf # Legacy hyprlang drop-in: static windowrules + bind
│ └── hyprburst.lua # Hyprland 0.55+ Lua bind; placement lives in TOML
├── .github/workflows/
│ └── ci.yml # Pull request CI: fmt, clippy, tests
├── Cargo.toml
└── Cargo.lock
- OS — Linux with Hyprland (a Wayland session). Hyprburst opens its own GPU window and dispatches launches through
hyprctl, so it expects a running Hyprland session. - OpenGL — the launcher window is rendered with OpenGL via your GPU driver (Mesa or vendor). Virtually every Hyprland-capable machine already has this.
- Hyprland 0.55+ recommended — use the Lua bind snippet and configure placement/opacity in
~/.config/hyprburst/config.toml. Legacy Hyprland 0.48–0.54 /hyprland.confsetups can use the shipped hyprlanghyprburst.confwith unifiedwindowrulesyntax. - Nerd Font (optional) — hyprburst renders entry icons as Nerd Font glyphs. Both GPU frontends keep your requested text font and use an installed Nerd Font for missing icons (a Mono variant preferred). Icons fit within the text cell; when no font provides an icon, a generic four-tile app symbol appears instead.
hyprburst tuiuses the hosting terminal's font and fallback settings.
Build and install the hyprburst binary into ~/.cargo/bin (make sure it's on your PATH):
git clone https://github.com/piny4man/hyprburst
cd hyprburst
cargo install --path .To build without installing, use cargo build --release — the binary lands at target/release/hyprburst.
cargo install hyprburstAvailable once the AUR package is published. The package name is
hyprburst. Once live, install it with your preferred AUR helper:
paru -S hyprburst # or: yay -S hyprburstThe PKGBUILD lives at packaging/aur/ — it builds the published crate from source and installs the binary, both Hyprland snippets, and the example config. See its README to build or publish it yourself.
After installing, add the matching Hyprland snippet (see Hyprland Setup).
Hyprburst exposes a single binary with a tiny command surface. Run hyprburst help for the same summary.
| Command | What it does |
|---|---|
hyprburst |
Opens the default Rio-backed launcher window. rio-vt owns the PTY/grid and Hyprburst owns the Wayland/OpenGL window — this is what the Super+Space Hyprland bind invokes. |
hyprburst tui |
Runs the launcher inline in the current terminal (crossterm), with no window. The fallback for SSH / no-GPU sessions, and handy for testing the UI from a shell. |
hyprburst native |
Opens the direct in-process launcher without a PTY. Retained as a fallback and comparison path. |
hyprburst help (-h, --help) |
Prints the usage summary and exits. |
hyprburst --measure |
Measures the default Rio-backed frontend to its first PTY-backed frame. |
hyprburst native --measure |
Measures the direct in-process fallback to its first frame. |
hyprburst --bench-startup |
Times the cold startup path (config load + app init), prints peak RSS, and exits without opening the UI. See Performance. |
Inside the launcher: type to filter, arrow keys (or PageUp/PageDown) to move, Enter to launch the selected app, click an app to launch it directly, or press Escape to close.
See Rio Prototype Findings for the architecture, measurements, limitations, and promotion decision.
When opening an app from its .desktop file, Hyprburst removes freedesktop launch target placeholders such as %f, %F, %u, and %U. That matches normal app-launcher behavior for launches without a selected file or URL, so apps such as Inkscape start normally instead of receiving a literal placeholder argument.
Hyprburst opens its own Wayland window with app-id hyprburst; it does not run inside a terminal. Install one small Hyprland snippet, then customize behavior in ~/.config/hyprburst/config.toml.
Pick the snippet matching your Hyprland config format. Hyprland loads hyprland.lua if present, otherwise hyprland.conf; the two formats cannot be mixed.
- Lua (Hyprland 0.55+ with
hyprland.lua):packaging/hyprburst.lua - hyprlang (legacy Hyprland 0.48–0.54, or any
hyprland.confsetup):packaging/hyprburst.conf
On Hyprland 0.55+ Lua configs, the snippet only binds the key. Placement and opacity come from Hyprburst's TOML config.
install -Dm644 packaging/hyprburst.lua ~/.config/hypr/hyprburst.lua
# then add to ~/.config/hypr/hyprland.lua:
# dofile(os.getenv("HOME") .. "/.config/hypr/hyprburst.lua")hl.bind("SUPER + Space", hl.dsp.exec_cmd("hyprburst"))For current Lua setups, use ~/.config/hyprburst/config.toml:
[window]
placement = "centered" # default; or "fullscreen"
opacity = 0.85centered is the default and uses [window] width and [window] height, keeping your normal Hyprland border and rounding. Set placement = "fullscreen" for a full-monitor overlay, which drops the border and rounded corners.
Hyprburst translates those settings into launch-time Lua rules:
| Placement | Hyprland behavior |
|---|---|
centered |
float, pin, stay_focused, size = { window.width, window.height }, center = true |
fullscreen |
float, pin, stay_focused, size = { "monitor_w", "monitor_h" }, move = { 0, 0 }, border_size = 0, rounding = 0, opacity = "... override" |
Hyprburst is still a normal Wayland window. pin and focus rules keep it above normal app windows, but layer-shell surfaces such as top-layer Waybar can still draw above it.
# Drop the config next to hyprland.conf and source it.
install -Dm644 packaging/hyprburst.conf ~/.config/hypr/hyprburst.conf
echo 'source = ~/.config/hypr/hyprburst.conf' >> ~/.config/hypr/hyprland.conf# Requires Hyprland 0.48-0.54 (unified `windowrule`; `windowrulev2` is deprecated).
windowrule = match:class ^(hyprburst)$, float on
windowrule = match:class ^(hyprburst)$, pin on
windowrule = match:class ^(hyprburst)$, size 640 720
windowrule = match:class ^(hyprburst)$, center 1
windowrule = match:class ^(hyprburst)$, opacity 0.9 0.9
windowrule = match:class ^(hyprburst)$, stay_focused on
windowrule = match:class ^(hyprburst)$, dim_around on
bind = SUPER, Space, exec, hyprburstThe legacy hyprlang file keeps static rules because old hyprlang configs cannot use the Lua hl.dsp.exec_cmd("hyprburst", rules) launch-time rule path. These rules center the window; for a full-monitor overlay, swap size 640 720 + center 1 for size (monitor_w) (monitor_h), move 0 0, border_size 0, and rounding 0. On current Hyprland Lua configs, prefer the minimal Lua bind plus TOML placement above.
If Waybar renders above hyprburst, set Waybar's own config to "layer": "bottom" and restart Waybar:
Waybar is a layer-shell surface, so a normal window cannot draw above it while Waybar remains on the top layer.
Hyprburst fades in on open. Escape closes the overlay.
Hard break — hyprburst no longer spawns a terminal. Bare
hyprburstnow opens its own GPU window instead of re-execing into a resolved terminal emulator. The[terminal]config section (preferred,class,flags) and the terminal-resolution logic are gone; a config that still contains[terminal]is rejected with a migration hint on stderr. To migrate: moveterminal.classtowindow.app_id(if you customized it) and delete the rest of[terminal]. TheSuper+Spacebind (bind = SUPER, Space, exec, hyprburst) is unchanged.hyprburst tuistill runs inline in the current terminal as a fallback.
The launcher window and cell font are configured under [window] and [font] in ~/.config/hyprburst/config.toml.
| Key | Type | Default | Notes |
|---|---|---|---|
window.app_id |
string | "hyprburst" |
Wayland app-id. Change only if you know why; legacy hyprlang rules must match it. |
window.placement |
string | "centered" |
"centered" for a centered floating window (keeps your Hyprland border/rounding), "fullscreen" for a full-monitor overlay (drops border and rounded corners). |
window.width |
integer | 640 |
Centered window width. Must be >= 1. |
window.height |
integer | 720 |
Centered window height. Must be >= 1. |
window.transparent |
bool | true |
Keep transparent for Hyprland blur. Set false for an opaque colors.background. |
window.opacity |
float | 0.85 |
Single opacity knob. On Lua Hyprland it is sent as compositor opacity with override; hyprburst also uses it for the transparent background panel. |
| Key | Type | Default | Notes |
|---|---|---|---|
font.path |
string | unset | Explicit .ttf/.otf path for the primary text font. Wins over $HYPRBURST_FONT, [font] family, and fontconfig; missing icons still use fallback fonts. |
font.family |
string | unset | fontconfig family used after path and $HYPRBURST_FONT. A shared Swatches theme fills this when unset. Ignored by hyprburst tui (the hosting terminal owns that font). |
font.size |
float | 20.0 |
Logical font height in pixels (before DPI scaling). The cell size is derived from the font's metrics at this size. Bump it up if text looks too small. |
Two sections cover everything about how hyprburst renders on screen: [layout] controls geometry and [ui] controls per-row decoration.
| Key | Type | Default | Notes |
|---|---|---|---|
layout.mode |
string | "list" |
"list" for one entry per row, "grid" for column-aware navigation. |
layout.min_column_width |
integer | 20 |
Grid-mode only. Cells narrower than this collapse to fewer columns. Must be >= 1. |
layout.padding_horizontal |
integer | 4 |
Extra columns of whitespace on the left and right. Capped at 32; oversized values warn and fall back. |
layout.padding_vertical |
integer | 2 |
Extra rows of whitespace above and below. Capped at 32. |
layout.center_banner |
bool | false |
Horizontally center the banner inside the available width. |
layout.separator |
bool | false |
Draw a thin rule between banner/search and the result list. |
| Key | Type | Default | Notes |
|---|---|---|---|
ui.show_banner |
bool | false |
Draw the banner above the prompt. Hidden by default; set to true to show it. |
ui.banner |
string | built-in ASCII "hyprburst" | Banner content, used when show_banner = true. Multi-line TOML string ("""..."""). An empty string also hides the banner. |
ui.prompt |
string | "> " |
Printed before the search cursor. |
ui.page_size |
integer | 10 |
Entries per page (PageUp/PageDown step). Must be >= 1. |
ui.show_icons |
bool | true |
Draw an icon before each app. GPU frontends use font fallback or a generic app symbol when the text font lacks Nerd glyphs. |
ui.selected_marker |
string | "> " |
Prefix drawn on the selected row. Empty string falls back to the default. |
ui.cursor_char |
string | "█" |
Single-character cursor glyph after the prompt. Non-single-grapheme values fall back to the default. |
ui.show_cursor |
bool | true |
Draw the cursor glyph at all. |
[layout]
mode = "grid"
min_column_width = 28
padding_horizontal = 6
padding_vertical = 2
center_banner = true
separator = true
[ui]
prompt = "λ "
selected_marker = "▶ "
cursor_char = "▏"
show_icons = true
[colors]
banner = "#ff79c6"
prompt = "light-cyan"
selected = "#ffb86c"Hyprburst reads $HYPRBURST_FONT, an optional path to a .ttf/.otf to use as the window's cell font (it overrides [font] family and fc-match, and is itself overridden by [font] path). The window launcher uses $HYPRBURST_CHILD internally to avoid relaunch loops when applying Hyprland Lua launch rules. Everything else lives in ~/.config/hyprburst/config.toml. App launches are dispatched through hyprctl, which auto-detects the Hyprland dispatch form; set HYPRBURST_DISPATCH=lua|legacy to force it if detection ever misfires.
Default location: $XDG_CONFIG_HOME/hyprburst/config.toml, falling back to ~/.config/hyprburst/config.toml. No config file is required — hyprburst ships with sensible defaults and an invalid config is reported on stderr before falling back to them.
A fully-commented template lives at config.example.toml. Copy it and uncomment the fields you want to change:
mkdir -p ~/.config/hyprburst
cp config.example.toml ~/.config/hyprburst/config.tomlThe [window] and [font] sections are documented in Window and font; [ui] and [layout] in Customizing the look. Shared Swatches themes are opt-in under [appearance]; [colors] still controls per-app overrides.
| Key | Type | Default | Notes |
|---|---|---|---|
appearance.theme_file |
string | unset | Path to a Swatches v1 theme. Relative paths resolve against this config file's directory; ~/ expands to $HOME. Loaded once at launch — reopen to apply edits. No theme means today's built-in defaults. |
The six semantic roles map as: background → colors.background, foreground → colors.foreground, accent → colors.prompt and colors.banner, muted → colors.empty, selection_background → colors.selected_bg, selection_foreground → colors.selected, font.family → font.family. Explicit [colors] / [font] fields always win, even when they equal an old default.
A missing or invalid theme_file is reported on stderr and ignored. Hyprburst still launches, keeping valid app overrides and built-in values for everything else. The Rio parent and its TUI child each load this file independently, so they pick the same theme. External hyprburst tui applies the resolved foreground to ordinary text and background to the entire launcher area, while preserving selection/accent colors. It does not apply the theme family—the hosting terminal owns its fonts. Rio's internal child leaves base colors at ANSI defaults so its GPU parent owns the base palette and transparent background panel, just like the native frontend.
Without a shared theme (or if it fails to load), the external TUI uses the built-in palette plus explicit overrides. This intentionally replaces its previous reliance on terminal defaults for ordinary text and blank areas. To retain terminal-owned base colors, set [colors] foreground = "reset" and background = "reset". Each reset independently means the hosting terminal's corresponding default, including when explicitly used for selection colors; it does not inherit the theme's base color. External terminals own opacity/transparency; [window] settings apply only to GPU windows.
The remaining section controls colors:
| Key | Type | Default | Notes |
|---|---|---|---|
colors.banner |
color | #c6a0f6 |
ASCII banner color. |
colors.prompt |
color | #8aadf4 |
Prompt + cursor color. |
colors.selected |
color | #f2d5ff |
Text of the highlighted entry. |
colors.selected_bg |
color | #3a2e5a |
Highlight bar drawn behind the selected row. |
colors.empty |
color | #9a8cb5 |
"No matches" message color. |
colors.background |
color | #1a1b26 |
GPU window background/dimming panel; base background throughout the external TUI. |
colors.foreground |
color | #c8cce0 |
Base color for ordinary launcher text in every frontend. |
Each color accepts either a named color (case-insensitive, dashes/underscores ignored) or a 6-digit hex string like #ff79c6.
Named colors: black, red, green, yellow, blue, magenta, cyan, white, gray/grey, darkgray/darkgrey, light-red, light-green, light-yellow, light-blue, light-magenta, light-cyan, reset (terminal default).
[layout]
padding_horizontal = 0
padding_vertical = 0
[ui]
prompt = "λ "
page_size = 8
[colors]
banner = "#ff79c6"
selected = "light-cyan"Unknown top-level keys, unknown keys in any section, malformed hex (#fff, #xyzxyz), unknown color names, and ui.page_size = 0 are all rejected with a message naming the offending field. On any error hyprburst prints the reason to stderr and starts with the built-in defaults. A missing or invalid [appearance] theme_file is a warning, not a hard error: the launcher stays available and explicit [colors] / [font] overrides are kept.
Launch history is stored in SQLite:
launches (
id INTEGER PRIMARY KEY,
desktop_id TEXT NOT NULL UNIQUE,
app_name TEXT NOT NULL,
launch_count INTEGER NOT NULL DEFAULT 1,
last_used TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
first_used TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
)cargo build --releasecargo run --releasePress Escape to close.
Hyprburst is tuned for instant launch. The release profile enables lto = "thin", codegen-units = 1, strip = "symbols", and panic = "abort" (see Cargo.toml) to minimize binary size and cold-start latency. Use the startup benchmark to catch discovery, config, or history regressions, and hyprburst --measure to capture window time-to-first-frame.
Measure startup end-to-end on your machine:
cargo build --release
./target/release/hyprburst --bench-startupThis times the complete cold path — config load, .desktop discovery, history open — and prints peak resident-set size. On a reference Arch + Hyprland machine the output is:
hyprburst startup: ~4ms
hyprburst peak RSS: ~5 MB
Both well under the <50ms startup budget and minimal-memory goal.
CI asserts the same path stays under a 250ms ceiling via tests/bench_startup.rs — generous headroom over the ~50ms local goal so shared CI runners don't flake. If the test ever does flake, it will be moved behind #[ignore] and run via cargo test -- --ignored as an opt-in lane.
Compare first presentation with hyprburst --measure (Rio default) and hyprburst native --measure (direct fallback). Reference results are recorded in Rio Prototype Findings.
Icons look generic. Both GPU frontends use a four-tile app symbol when no resolved font provides the requested icon. Install a Nerd Font such as JetBrainsMono Nerd Font and reopen hyprburst to get application-specific icons; your configured text family can stay unchanged. Set ui.show_icons = false to hide icons entirely. If icons show as tofu squares (□) in hyprburst tui, configure a Nerd Font or font fallback in the hosting terminal; a shared theme family does not control its font.
Text is too small. Raise [font] size (default 20.0).
The window doesn't open / hyprburst exits with a font or display error. It needs a Wayland session with OpenGL. From an SSH or no-GPU session, run hyprburst tui instead (inline crossterm UI). If it can't find a font, set [font] path.
The launcher opens in the wrong place / isn't fullscreen. On Hyprland 0.55+ Lua configs, install the minimal packaging/hyprburst.lua bind and set [window] placement in ~/.config/hyprburst/config.toml. Use "fullscreen" for the full-monitor overlay or "centered" for a centered floating window. Legacy hyprlang users still rely on static rules in packaging/hyprburst.conf.
Waybar (or another bar) renders on top of hyprburst. Waybar is a layer-shell surface on the top layer, which a normal floating window can't cover. Set Waybar's config to "layer": "bottom" and restart it — details in Hyprland Setup.
Background blur / transparency doesn't show. Keep [window] transparent = true (the default) and set Hyprland's decoration:blur:enabled = true globally. [window] opacity controls both Hyprland compositor opacity on Lua setups and the panel hyprburst paints inside its transparent surface.
The launcher looks too see-through / the blur washes out the text. Raise [window] opacity (default 0.85) toward 1.0 to dim more of the blur behind the launcher; 1.0 makes the background panel fully opaque.
Super+Space does nothing. Confirm the bind sources/loads correctly (bind = SUPER, Space, exec, hyprburst, or the Lua hl.bind(...)) and that hyprburst is on the PATH Hyprland sees.
My config isn't taking effect. An invalid config is rejected and hyprburst falls back to built-in defaults, printing the reason to stderr. Run hyprburst tui from a shell to see the message, then fix the named field. Theme edits apply on the next launch, not live. A bad appearance.theme_file prints a warning and is ignored. Note: the [terminal] section was removed in 0.5 and now errors — see Upgrading from 0.4.x. Unknown keys are hard errors. See Validation.
Hyprburst is licensed under the GNU General Public License v3.0 or later (GPL-3.0-or-later). See LICENSE.
Official releases are controlled by the project owner. See MAINTAINERS.md for crates.io, AUR, and release ownership policy.
{ "layer": "bottom" }