Personal dotfiles + UI setup for my Surface Laptop 4 (AMD) running Hyprland. Also, please check out my calendar app: Evercal
- Dependencies
- Hyprland
- Shaders
- Quickshell Bar
- Quickshell Hub (
snes-hub) - Power menu
- Wifi menu
- Pixel sddm theme
- Firefox custom new-tab
- Surface-only features
- Credits & acknowledgements
- Media sources
SDDM: Lock Screen & Login Screen (hyprlock also looks just like this + with media information if playing when locked)
Dark Mode & Light Mode (Hub + Rofi)
Reading mode & Various other apps
|
|
|
Caution
Layout geometry is hardcoded for 3:2 high-resolution display. Deviation in aspect ratio or pixel density will result in misalignment or things looking too big or small. Please reconfigure values accordingly.
Main config is for Hyprland v0.53: ~/.config/hypr/hyprland.conf
Old Config at ~/.config/hypr/hyprland_OLD.conf
Keybindings
SUPER + Q→ terminal (kitty)SUPER + E→ file manager (thunar)SUPER + R→ rofiSUPER + B→ firefoxSUPER + D→ reading modeSUPER + S→ my custom ocr app
SUPER + SPACE→ toggle hub on or offSUPER + X→ kill active windowSUPER + F→ toggle floating (simple)SUPER + ALT + F→ toggle floating and set size900x600+ centerSUPER + M→ fullscreenSUPER + P→ pseudotileSUPER + UP→ togglesplitSUPER + DOWN→ togglesplit
ALT + F4→ Power menuSUPER + ALT + F4→ exit Hyprland
SUPER + Left/Right→ move focus horizontallySUPER + UP/Down→ move focus vertically
SUPER + 1..0→ workspace1..10SUPER + SHIFT + 1..0→ move active window to workspace1..10SUPER + mouse wheel→ next/prev workspaceSUPER + G→ toggle groupSUPER+CTRL+LEFT/RIGHT→ move across grouped windows
SUPER + H→ toggle special workspacemagicSUPER + SHIFT + S→ move active window tospecial:magic
SUPER + LMB→ move windowSUPER + RMB→ resize window
Print→ screenshot script modesSUPER + Print→ modepSUPER + SHIFT + Print→ modesfSUPER + O→ modem
All shaders located at ~/.config/hypr/shaders/ and use hyprshade
activate with:
hyprshade on <shader_name.glsl>
deactivate with:
hyprshade off
A shader-based reading mode to mimic an e-ink reader.
- Toggle with
SUPER + Dor~/.config/hypr/shaders/reading_mode.sh - Automatically disables animations, shadows, and blur
- Custom GLSL shader with e-ink-like color reproduction
- Warm cream paper tone and soft charcoal blacks for reduced contrast
- Fine paper grain -like texture
Ranked from Useful to completely Useless:
main.glsl– my main shader to improve my display (I run it at startup)night.glsl– my main night-light mode shader (script coming soon)outdoor.gls– for maximum outdoor useabilitycinema.glsl– for media consumptionsoft.glsl– soft, muted texturesmatte.glsl– anti-glare, matteIMB5151.glsl– simulates vintage IBM 3278 / 5151 monitorsfuji_acros.glsl– simulates fujifilm acroscrt_mode.glsl– simulates a crt monitor/retro nostalgiavhs.glsl– simulates vhsgameboy.glsl– simulates a gameboy screenclarity_inefficient.glsl– an early version of my main shaderfocus.glsl– party tricknight_vision.glsl– simulates night_vision
The bar uses an Arch glyph icon (top left) as the launcher button:
- Left click: launches rofi, choosing a different launcher script depending on the current theme mode.
- Right click: toggles the bar’s isDarkMode and calls a theme script:
bash ~/config/quickshell/snes-hub/bar/theme-mode.sh dark|lightExpand for Bar components
Clicking a workspace pill runs: - hyprctl dispatch workspace <id>
Updates are shown using a poller, but it won’t run checkupdates while pacman is busy (to avoid lock-related crashes). When the pacman lock file exists, the bar displays the last cached update count instead. Polled with:
if [ -e /var/lib/pacman/db.lck ]; then
cat /tmp/qs_updates_count 2>/dev/null || echo 0
else
checkupdates 2>/dev/null | wc -l | tee /tmp/qs_updates_count
fi
Clicking the updates pill runs:
kitty -e bash -lc "sudo pacman -Syu"- Pressing the clock triggers a requestHubToggle() signal (used to open/close the hub).
- Esc closes the hub (or clicking anywhere outside it).
- Toggled by clicking the date/clock module in the bar or SUPER+SPACE keybinding through hyprland
- The hub window is an overlay (wlr-layershell) and is designed to get out of your way quickly:
- Organized into reusable components, making it straightforward to add/remove cards or re-skin pieces without rewriting the whole hub.
- If you want a lightweight fallback, use the early AGS version in
.config/ags/(works, but fewer features).
Components (click to expand)
- Profile icon,username + RAM/CPU usage chips.
- Screenshot button (runs the capture script and then closes the hub).
- Power button
- Compact power grid that expands (click the power button or press
pkey) inside the header (no extra window): - Keyboard navigation: Arrow keys / Tab to move, Enter to trigger, Esc to close.
- Wi‑Fi toggle + SSID readout (right‑click opens wifi module).
- Bluetooth toggle + connected device status.
- Performance profile button (cycle modes via
auto-cpufreq, right click toggles battery health card). - DND toggle (dunst).
- Volume + brightness sliders (pactl + brightnessctl).
- Polls:
upower -i /org/freedesktop/UPower/devices/battery_BAT1 - Shows: Health (capacity %) + current charge %, Charge cycles, Energy (full / design), Time remaining (to full/empty when available), State (charging/discharging/fully-charged)
[!NOTE] If your battery isn’t
battery_BAT1, swap the device path inBatteryHealthCard.qmlto match your system.s
- The hub includes an MPRIS-powered media card:
- Clicking the media card launches the external now-playing widget and then toggles the hub off.
- It tracks metadata changes and resets its internal timing state when tracks change. It's still finicky with some browser contents like youtube videos
- Only appears when something is playing
- This is a separate Flutter desktop widget (class rules are handled in Hyprland).
- Resizable is disabled (setResizable(false) is used)
- Esc closes the widget
- Generates theme colors from album art using palette_generator
A simple calendar with weather (json based script and events from my google calendar using khal+ vdirsyncer.
Google Calendar sync (vdirsyncer + khal)
Recommended approach (avoids system Python packaging issues):
sudo pacman -S --needed python-pipxpipx install "vdirsyncer[google]"- If you have both a system and pipx vdirsyncer, remove the system one and make sure PATH prefers ~/.local/bin.
Create folders:
mkdir -p ~/.config/vdirsyncer/status ~/.config/vdirsyncer/tokens
mkdir -p ~/.local/share/vdirsyncer/calendarsExample vdirsyncer config uses:
token_file = "~/.config/vdirsyncer/tokens/google_calendar"
type = "google_calendar"
client_id / client_secret from Google Cloud OAuth
~/.local/share/vdirsyncer/calendars/* - Khal reads .ics files from here
- You must enable CalDAV API in Google Cloud (not only the “Google Calendar API”).
- If OAuth consent is in Testing mode, add yourself as a “Test user”.
- If you get “token obtained but Not Found”, enable calendars at: https://calendar.google.com/calendar/syncselect
vdirsyncer discover
vdirsyncer sync
khal list now 7d- Clicking dismisses.
- Uses dunst (
dunstctl) as the notification backend. - Contracted by default when the media player card is active, but can be expanded via the expand button.
- custom OSDs for brightness and volume controls
- custom OSD for various modes (Dark/Light/Reading Mode etc.)
[!NOTE] You may need to update the scripts in .config/hypr/scripts. Please review the contents of audiocontrol.sh and brightnesscontrol.sh. Newer versions of these scripts write cache for osd qmls to read
wlr-layershell power menu overlay (separate from the hub header menu). Toggled with ALT+F4 Run
quickshell -p ~/.config/quickshell/snes-hub/bar/PowerMenu.qmlStandalone network manager applet located at lib/WifiMenu.qml. With both (light/dark) theme.
- Trigger: Right-click the Wi-Fi button in the Hub.
- or run:
quickshell -p ~/.config/quickshell/snes-hub/lib/Wifimenu.qml
Warning
You cannot connect to enterprise access points (for now), I haven't had the time to fix it yet
[Note: I am using qt5, please install qt5 dependencies]
sudo pacman -S qt6-5compat qt6-svg qqc2-desktop-style inter-font ttf-nerd-fonts-symbolsif you don't want windows hello like animation please use main.qml from the old directory
-
To install:
- move the contents of sddm/theme folder to
/usr/share/sddm/themes/(create the dir if it doesn't exist yet) - Set "pixel" as the current theme by creating a config file in
/etc/sddm.conf.d/: - make sure the directory exists:
sudo mkdir -p /etc/sddm.conf.d
- then create the config file:
echo -e "[Theme]\nCurrent=pixel" | sudo tee /etc/sddm.conf.d/theme.conf
- move the contents of sddm/theme folder to
- Custom Firefox start page: https://github.com/snes19xx/custom-firefox-start
- usercss (Also in this repo): https://github.com/snes19xx/firefox-customizations
Firefox doesn't really want you to use local html as a new tab page so
- Move autoconfig.js to Firefox defaults/pref/ (e.g. /usr/lib/firefox/defaults/pref/)
- Edit mozilla.cfg (repo path: .config/firefox/mozilla.cfg) and set your file path
- Move mozilla.cfg to the Firefox install directory root (e.g. /usr/lib/firefox/)
- Everforest-GTK-Theme by Fausto-Korpsvart
- Rofi themes loosely based on @adi1090x's type 7
Pixeldots.qmlin sddm theme based on @mahaveergurjar's Pixeldots- Colors: Modified from https://github.com/sainnhe/everforest
- SVG icons: https://www.svgrepo.com/
- linux-surface project: https://github.com/linux-surface/linux-surface
- Thorium: https://thorium.rocks/ for the background visualizations in firefox custom new tab
- Photo by fffunction studio on Unsplash
- Photo by Brian McGowan on Unsplash
- Photo by Mimicry Hu on Unsplash
- Photo by Bailey Zindel on Unsplash
- Photo by on Jay Yu on Unsplash
- Photo by Ben Dutton on Unsplash
- Photo by Richard Rhee on Flickr
- Photo by Cedric Chambaz on Flickr
[OC]
-
Lucina wallpaper from Fire Emblem Awekening Artbook
-
Final Fantasy X logo: by Yoshitaka Amano
-
Most Monogatari wallpapers are edited from the scans of Monogatari Series 10th Anniversary Illustration Works Art Book
-
crab2,hanekawa3 and crab2.png are form AhogeDesu
-
All Rofi pictures were pulled from Pinterest; I don’t know the original owners.
Feel free to copy/steal whatever you want as long as you cite me and more importantly the listed media sources in the credits/references where applicable.

