Skip to content

Game Overlay

P3DROVFX edited this page Oct 12, 2026 · 1 revision

Game Overlay and Game Mode

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.

Quick start

  1. 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.
  2. 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).
  3. 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).

The widgets

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

Performance HUD

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 with mangohud. 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.

Discord voice

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 the rpc rpc.voice.read rpc.voice.write scopes; 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.

Game detection

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 (the toggle) and Full Game Mode

  • 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_esports button 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 for mpvpaper.
    • FullGameMode.enter() applies the normal Game Mode's Hyprland overrides, waits for any Hyprland config write to finish, and starts scripts/gameMode/swap.sh enter detached (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), runs qs kill -c ii, kills those wallpapers, and starts qs -p …/gameMode.qml.
    • gameMode.qml runs only the overlay, the polkit agent, and a global shortcut lock that runs hyprlock — 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 ii name, so IPC is qs -p ~/.config/quickshell/ii/gameMode.qml ipc call gameMode exit.

Configuration (Config.options.overlay)

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

Under the hood

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

Related pages

← Back to Home

Clone this wiki locally