No description
  • Rust 98.7%
  • Nix 1.3%
Find a file
2026-05-09 17:18:27 +05:30
src add system tray icon (StatusNotifierItem via ksni) with Open Config / Quit menu and dynamic mute/deafen state 2026-05-07 05:31:26 +05:30
.gitignore phase 0: bootstrap (jj init, deps, module skeleton, tracing) 2026-05-01 14:47:02 +05:30
Cargo.lock add system tray icon (StatusNotifierItem via ksni) with Open Config / Quit menu and dynamic mute/deafen state 2026-05-07 05:31:26 +05:30
Cargo.toml add system tray icon (StatusNotifierItem via ksni) with Open Config / Quit menu and dynamic mute/deafen state 2026-05-07 05:31:26 +05:30
CLAUDE.md phase 0: bootstrap (jj init, deps, module skeleton, tracing) 2026-05-01 14:47:02 +05:30
config.example.toml make wlr-layer-shell layer configurable; default to overlay so the surface stays above fullscreen windows 2026-05-06 22:42:12 +05:30
flake.lock Add nix flake + package 2026-05-09 17:18:27 +05:30
flake.nix Add nix flake + package 2026-05-09 17:18:27 +05:30
package.nix Add nix flake + package 2026-05-09 17:18:27 +05:30
README.md add README with discord credential setup + config reference 2026-05-07 20:05:19 +05:30

discord-overlay

A Wayland-native overlay that shows the members of your current Discord voice channel — avatar, name, mute/deafen badges, and a green ring around the speaker. Renders as a wlr-layer-shell surface, transparent, click-through. Includes a system tray icon (StatusNotifierItem) with Open config / Quit and a dynamic mic glyph that mirrors your own mute/deafen state.

Runs on any compositor that implements wlr-layer-shell (Hyprland, sway, KDE Plasma 6, …). Vanilla GNOME is unsupported. The tray icon needs a panel that speaks SNI — true on KDE, on most Wayland tiling setups via waybar, and on GNOME with the AppIndicator extension.

Setup

1. Register a Discord application

The overlay talks to your local Discord client over its IPC socket and uses OAuth to authorize. You need to register a Discord application to get the credentials.

  1. Go to https://discord.com/developers/applications.
  2. New Application → name it whatever (e.g. discord-overlay).
  3. In the left sidebar pick OAuth2.
  4. Under Redirects, add http://127.0.0.1 and Save Changes. The overlay never actually opens this URL — Discord just requires it to be present and to match what we send during the token exchange.
  5. Copy the Client ID (visible at the top of the OAuth2 page).
  6. Click Reset Secret under Client Secret, then copy the secret. Treat it like a password — don't share it or check it in.

You don't need to submit the app for verification. Discord apps work for the developer-team account (you) without any approved-scopes review, which is exactly what we want.

2. Drop the credentials into config

mkdir -p ~/.config/discord-overlay
cp config.example.toml ~/.config/discord-overlay/config.toml
$EDITOR ~/.config/discord-overlay/config.toml

Paste the Client ID and Client Secret into client_id and client_secret.

3. First run

cargo run --release

On first launch, Discord pops up an Authorize dialog ("This will allow this app to read your voice channels …"). Approve it. The overlay caches the resulting access token at ~/.cache/discord-overlay/token.json (mode 0600), so subsequent launches don't re-prompt.

If you join a voice channel, you should see your channel's members appear in the overlay. Speaking lights up the green ring; muting/deafening yourself updates both the per-row badge and the tray icon.

Config reference

All keys live in ~/.config/discord-overlay/config.toml. See config.example.toml for the same in copy-paste form.

Key Type Default Notes
client_id string required Discord application Client ID.
client_secret string required Discord application Client Secret.
anchor enum "top-left" Where the overlay sits on screen. One of "top-left", "top-right", "bottom-left", "bottom-right".
layer enum "overlay" wlr-layer-shell stacking layer. "overlay" stays above fullscreen windows (and above screen lockers, deliberately); "top" is covered by fullscreen toplevels.
width u32 300 Surface width in logical pixels.
height u32 600 Surface height. Tall enough to fit your largest expected channel; rows past the edge are clipped.
font_size f32 14.0 Name text size in pixels. Row height and the mute/deafen badge size scale with this.

Logging

Tracing reads RUST_LOG. Default is info,discord_overlay=debug. To see voice-state events:

RUST_LOG=discord_overlay=trace cargo run

Token cache

The overlay stores the OAuth access + refresh tokens in ~/.cache/discord-overlay/token.json (mode 0600). To force a fresh authorization:

rm ~/.cache/discord-overlay/token.json

You'll get the Discord consent dialog again on next launch.

Avatar cache

Decoded avatars live at ~/.cache/discord-overlay/avatars/{user_id}_{hash}.png. Safe to wipe at any time; the overlay re-downloads as needed.