Repository navigation
Game Overlay
Everything a gamer wants without leaving the game: press Super + G over a fullscreen game and a layer of overlay widgets appears on top of it — a pinned crosshair, an FPS limiter, a performance HUD with frame rate and 1 % lows, a volume mixer, media with synced lyrics, resource monitors, notes, a recorder, a floating image/GIF, and Discord voice (who is talking). Widgets can be pinned so they stay on screen, click-through, even when the overlay is closed. And when you want every megabyte back, Full Game Mode swaps the entire shell for a minimal process that runs only the overlay.
It is modelled on the Xbox Game Bar and Steam overlay — with the difference that it is a normal Wayland layer, so it works over any app, not only games.
-
Super + G toggles the overlay. A taskbar along the edge lists the available widgets (
overlay.buttons); click one to open it, drag it, resize it, and use the pin button to keep it on screen. - Click outside, or press Super + G again, to close. Pinned widgets remain, and you can click them through the overlay (they are the only input regions while it is closed; keyboard focus is on demand so clicking a pinned widget lets you type in it).
- Settings → Overlays & OSD → Game Overlays chooses which widgets exist and configures them; each has its own subsection.
The window is a full-screen Overlay layer with an input mask — the closed state only claims the pinned widgets' rectangles, the open state claims the whole screen with an optional dimming (darkenScreen) and an opening zoom (openingZoomAnimation).
| Widget | What it does |
|---|---|
| Crosshair | A pinned aiming reticle drawn at screen centre, in Valorant's crosshair-code format (crosshair.code; build one at vcrdb.net). Pin it and it stays on top of the game |
| FPS limiter | Type a cap and press apply: it writes fps_limit=<n> into ~/.config/MangoHud/MangoHud.conf and sends MangoHud SIGUSR2, so a running MangoHud game picks it up live. Needs MangoHud |
| Performance HUD | RivaTuner-style metrics: CPU, RAM, one GPU, frame rate, frame time, 1 % / 0.1 % lows, network ping, power, temperatures, session time… as bars, graphs or text — see below |
| Volume mixer | Volume per application and device, without alt-tabbing |
| Media | The current track with a progress slider and synced lyrics with focal blur and a gradient mask; transport buttons |
| Resources | CPU, RAM and swap with history, and your hardware identity; metrics are only sampled while the widget is visible |
| Notes | The same notes as the desktop widgets and the Notes app, in tabs, with optional icon editing; also sketch notes |
| Recorder | Big buttons to take a screenshot or record the screen ([[Screen Capture & Recording |
| Floating image | Any picture or GIF/URL floating above everything, with a scale (a reference sheet, a meme, a map) |
| Discord voice | The people in your voice channel as avatars, speaking ones pulsing; also a bar widget and a popup — see below |
Linux has no system-wide frame counter. MangoHud runs inside each game and writes frame times to a log; the HUD reads that log. So the HUD can show everything except FPS for any app, and FPS for games started with MangoHud.
-
Setup is guided in Settings → Overlays & OSD → Performance HUD: it shows whether MangoHud is installed, whether logging is on, and turns it on for you — it adds a small marked block to your MangoHud config so frame times are logged, leaves your other MangoHud settings alone, and can hide MangoHud's own on-screen HUD so only this one shows. Per-game launch advice: Steam launch option (
mangohud %command%), Steam games from the launcher, Flatpak games (which need MangoHud's Flatpak layer and an override), Minecraft/Prism Launcher's wrapper command, or any command prefixed withmangohud. Old logs are deleted after two days. -
What it measures comes from one helper process (
scripts/perfOverlay/perf_monitor.py) that runs only while the HUD is on screen: CPU usage/frequency/temperature, RAM, GPU usage/memory/clock/power/temperature/fan for the GPU you choose (a discrete GPU that runtime power management suspended is reported "suspended" instead of woken up), frame rate, average, 1 % and 0.1 % lows from a configurable statistics window, jitter and stutters, ping to a target of your choice (default your router, so nothing leaves your network), battery charge and time left, power profile, session time. - Look: Bars, Graph or Text styles; Accent, Container or Monochrome palettes; scale, width, background opacity, optional compositor blur, uppercase, mono numbers, icons, a custom title/footer, custom CPU/GPU names, corner (top/bottom left/right) or free placement with a snap margin, refresh interval (default 1000 ms), and Color the FPS with a target FPS. Turn a block on with its switch and the HUD shrinks around what's on; FPS only shows just the number.
Shows who is in your Discord call, over the game. It talks to your Discord client through two possible backends and tells you which is active:
-
Discord's local RPC socket — for the official client. The bridge (
scripts/discordVoice/discord_voice_bridge.py, standard library only) authorizes with Discord's StreamKit overlay client and therpc rpc.voice.read rpc.voice.writescopes; tokens are never logged. -
Vesktop / Equibop / Vencord — these route voice through arRPC, so for them the shell offers an install of a small companion plugin (
scripts/discordVoice/vencord-companion); "Vesktop" in the popup tells you the companion is running.
Options: avatar size and count, participant background (name / avatar / none) and opacity, layout (column or row), blur, auto-resize, continuous speaking pulse. When Discord is gone the bridge stops after a minute instead of reconnecting every three seconds; a Discord window coming back, or any voice command, restarts it.
Several features (Modes & Routines, the Game Mode toggle, power/graphics policies) need to know "a game is running". GameDetector combines four signals, strongest first: launcher classes (steam_app_*, gamescope, Heroic/Lutris/Bottles, Minecraft/Prism, fullscreen Wine .exe), the desktop entry's "Game" category, your own list (modes.game.extraClasses), and a heuristic — a fullscreen focused window with GPU use above gpuThreshold % (45) for holdSec seconds (20). reason says which fired ("Steam app", "fullscreen + GPU 62 %"), so a false positive can be diagnosed from the trigger chip. There is hysteresis so alt-tabbing to chat doesn't end a gaming mode: gameRunning drops 30 s after the last matching window disappears, gameFocused 5 s after focus leaves. GPU polling (a process per sample on NVIDIA/Intel) runs only while something holds the detector and the heuristic is enabled. See Modes & Routines.
- Game Mode is a Hyprland-side preset (a Mode, or the toggle in the Dashboard): it turns off animations, shadows and blur, zeroes the gaps and rounding, shrinks borders to 1 px, allows tearing and forces windows opaque, so the compositor does less work and presents sooner.
-
Full Game Mode goes further. The
sports_esportsbutton at the end of the overlay taskbar arms ("Close the shell for gaming?", 4 s) and the second click enters it. Why a process swap instead of unloading panels? Measured: turning off the family loader inside the running shell returned only ~200 MB (872 → 678 MB) — singletons live as long as the engine, their daemons keep running, and the allocator keeps what it took. A fresh process running just the overlay sits at ~430–480 MB, with no daemons, compared with 0.9–1.5 GB plus 200–350 MB of helpers for the full shell and ~0.5 GB formpvpaper.-
FullGameMode.enter()applies the normal Game Mode's Hyprland overrides, waits for any Hyprland config write to finish, and startsscripts/gameMode/swap.sh enterdetached (setsid), because it is about to kill the shell that launched it. The script records the command lines of video/Wallpaper-Engine wallpapers (so they restart as they were), runsqs kill -c ii, kills those wallpapers, and startsqs -p …/gameMode.qml. -
gameMode.qmlruns only the overlay, the polkit agent, and a global shortcutlockthat runshyprlock— so Super + L and hypridle still lock the screen (no notifications, by design). -
Leaving — the same button ("Exit game mode") runs
swap.sh exit, or simply restart the shell: on boot the full shell finds the marker$XDG_RUNTIME_DIR/ii-game-mode/active, removes the Hyprland overrides and relaunches the saved wallpapers (recover). Either way you end up in the same place. - The game-mode instance has no
-c iiname, so IPC isqs -p ~/.config/quickshell/ii/gameMode.qml ipc call gameMode exit.
-
| Key | Default | Meaning |
|---|---|---|
buttons |
crosshair, recorder, media, volumeMixer, resources, discordVoice, perfMonitor | Taskbar order/contents (also fpsLimiter, floatingImage, notes) |
openingZoomAnimation, darkenScreen, clickthroughOpacity
|
on, on, 0.8 | Overlay behaviour |
crosshair.code (top-level section) |
0;P;d;1;0l;10;0o;2;1b;0 |
Valorant-format code |
floatingImage.imageSource, scale
|
a sample GIF, 0.5 | The picture |
media.* |
100 %, gradient mask on, slider on, lyric size | Media widget |
discordVoice.* |
8 avatars, 52 px, column… |
Discord voice |
perfMonitor.* |
bars, accent, 280 px, 1000 ms, topLeft… |
Performance HUD |
modes.game.* |
launcher classes on, GPU threshold 45, hold 20 s | Detection |
| Piece | Role |
|---|---|
modules/ii/overlay/ |
Overlay.qml (the layer, input mask, focus), OverlayContent, OverlayTaskbar, OverlayContext (pins, widget catalogue), per-widget folders |
services/GameDetector.qml, services/FullGameMode.qml
|
Detection; process swap |
gameMode.qml, scripts/gameMode/swap.sh
|
The minimal second entry point and the swap |
scripts/perfOverlay/perf_monitor.py, overlay/perfMonitor/PerfSampler.qml
|
HUD samples |
services/DiscordVoice.qml, scripts/discordVoice/
|
Discord bridge and companion |
- Modes & Routines — game conditions and the Game preset
- Screen Capture & Recording
- Media Mode
- Keybinds