Skip to content
piny4manPublic

About

Fast GPU-rendered application launcher for Arch Linux and Hyprland.

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Hyprburst

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.

Features

  • Rio terminal engine — rio-vt manages 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+ Lua hl.dsp form)
  • Terminal fallback — hyprburst tui runs the launcher inline in any terminal for SSH / no-GPU sessions

Demo

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.

Project Structure

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

Requirements

  • 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.conf setups can use the shipped hyprlang hyprburst.conf with unified windowrule syntax.
  • 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 tui uses the hosting terminal's font and fallback settings.

Install

From source

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.

From crates.io

cargo install hyprburst

From the AUR

Available 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 hyprburst

The 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).

Usage

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.

Hyprland Setup

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.

On Hyprland 0.55+ Lua configs, the snippet only binds the key. Placement and opacity come from Hyprburst's TOML config.

Lua (hyprburst.lua, Hyprland 0.55+)

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"))

Configure Placement

For current Lua setups, use ~/.config/hyprburst/config.toml:

[window]
placement = "centered" # default; or "fullscreen"
opacity = 0.85

centered 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.

hyprlang (hyprburst.conf, legacy)

# 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, hyprburst

The 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:

{
  "layer": "bottom"
}

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.

Upgrading from 0.4.x

Hard break — hyprburst no longer spawns a terminal. Bare hyprburst now 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: move terminal.class to window.app_id (if you customized it) and delete the rest of [terminal]. The Super+Space bind (bind = SUPER, Space, exec, hyprburst) is unchanged. hyprburst tui still runs inline in the current terminal as a fallback.

Window and font

The launcher window and cell font are configured under [window] and [font] in ~/.config/hyprburst/config.toml.

[window]

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.

[font]

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.

Customizing the look

Two sections cover everything about how hyprburst renders on screen: [layout] controls geometry and [ui] controls per-row decoration.

[layout]

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.

[ui]

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.

Worked example: centered grid with breathing room

[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"

Environment variables

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.

Config

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.toml

Fields

The [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.

[appearance]

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.

Color values

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).

Minimal example

[layout]
padding_horizontal = 0
padding_vertical = 0

[ui]
prompt = "λ "
page_size = 8

[colors]
banner   = "#ff79c6"
selected = "light-cyan"

Validation

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.

History Schema

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
)

Building

cargo build --release

Running

cargo run --release

Press Escape to close.

Performance

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-startup

This 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.

Troubleshooting

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.

License

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.

About

Fast GPU-rendered application launcher for Arch Linux and Hyprland.

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages