Skip to content

snes19xx/surface-dots

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

118 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

surface-dots

Personal dotfiles + UI setup for my Surface Laptop 4 (AMD) running Hyprland. Also, please check out my calendar app: Evercal


Table of contents


Screenshots

Desktop Layouts


Lockscreen, Reading Mode, Other system components

Dependencies

Core & System

  • quickshell
  • hyprland
  • hypridle
  • hyprlock
  • hyprshade
  • hyprland-plugins
  • xdg-utils
  • xdg-desktop-portal-hyprland
  • xdg-desktop-portal-kde
  • xdg-desktop-portal-gtk
  • polkit-gnome
  • sddm
  • networkmanager
  • bluez, blueman
  • webkit2gtk-4.1

UI & Theming

  • dunst
  • awww
  • waypaper-git
  • rofi
  • kitty
  • firefox
  • colorreload-gtk-module
  • qt6ct
  • kvantum
  • papirus-icon-theme
  • ttf-nerd-fonts-symbols
  • ttf-iosevka-nerd
  • ttf-google-fonts-git
  • volantes_cursors

Utilities

  • grim, slurp, swappy, grimblast
  • pamixer
  • pulseaudio-utils
  • playerctl
  • brightnessctl
  • libnotify
  • wl-clipboard
  • vdirsyncer
  • khal
  • EverCal
  • xdg-utils
  • curl, jq
  • auto-cpufreq
  • howdy-git (optional)

Caution

Some 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 follow instructions in the FAQs below to reconfigure values accordingl or start an issue if you require further assistance.

Installation

Note

I've pulled the installer down because of the significant changes in hyprland 0.55. The only way to install surface-dots at the moment is manually copying files around. I'll try to update the installer as soon as possible.

Hyprland

Keybindings

Apps

  • SUPER + Q → terminal (kitty)
  • SUPER + E → file manager (thunar)
  • SUPER + R → rofi
  • SUPER + B → firefox
  • SUPER + D → reading mode
  • SUPER + N → night light
  • SUPER + S → my custom ocr app

Window actions

  • SUPER + SPACE → toggle hub on or off
  • SUPER + X → kill active window
  • SUPER + F → toggle floating (simple)
  • SUPER + ALT + F → toggle floating and set size 900x600 + center
  • SUPER + M → fullscreen
  • SUPER + P → pseudotile
  • SUPER + UP → togglesplit
  • SUPER + DOWN → togglesplit

Exit

  • ALT + F4 → Power menu
  • SUPER + ALT + F4 → exit Hyprland

Focus (arrow keys)

  • SUPER + Left/Right → move focus horizontally
  • SUPER + UP/Down → move focus vertically

Workspaces

  • SUPER + 1..0 → workspace 1..10
  • SUPER + SHIFT + 1..0 → move active window to workspace 1..10
  • SUPER + mouse wheel → next/prev workspace
  • SUPER + G → toggle group
  • SUPER+CTRL+LEFT/RIGHT → move across grouped windows

Scratchpad (“special workspace”)

  • SUPER + H → toggle special workspace magic
  • SUPER + SHIFT + S → move active window to special:magic

Mouse (window move/resize)

  • SUPER + LMB → move window
  • SUPER + RMB → resize window

Screenshots

  • Print → Screen snip
  • SUPER + Print or SUPER + O → Capture screen
  • SUPER + SHIFT + Print → Window capture

Shaders

Shaders are integral part of my setup, I find them fun.

  • All shaders are located at ~/.config/hypr/shaders/
  • shaders can be accessed and toggled through rofi start menu (only in taskbar mode)

OR:

# activate with:
hyprctl eval 'hl.config({ decoration = { screen_shader = "/<path to shader.glsl>" } })'

# To turn off the screen shader, set the screen_shader value to an empty string.
hyprctl eval 'hl.config({ decoration = { screen_shader = "" } })'

Reading Mode

A shader-based reading mode to mimic an e-ink reader.

  • Toggle with SUPER + D or ~/.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

Other shaders

  1. main.glslmain shader to improve my display (activates on startup through hyprland exec)
  2. night.glslmy main night-light mode shader (toggle with SUPER + N)
  3. outdoor.glsfor maximum outdoor useability
  4. cinema.glslfor media consumption
  5. amano.glslsimulates Yoshitaka Amano artstyle
  6. art_canvas.glslsmulates physical canvas geometry and pigment density
  7. dither.glslSimulates 4-bit graphics.
  8. fuji_acros.glslsimulates fujifilm acros
  9. crt_mode.glslsimulates a crt monitor
  10. vhs.glslsimulates vhs
  11. gameboy.glslsimulates a gameboy screen
  12. smart_invert.glsleConverts RGB to HSL, inverts the Lightness channel, and converts back
  13. silent_hill.glslPacific Northwest / Silent Hill Shader
  14. greens.glsl – _Retains only green hues and desaturates all other colors to grayscale. _

Desktop Layouts

Two desktop layouts are available depending on how you want the bar positioned.

Use the top bar layout:

qs -c top-bar

Use the taskbar layout:

qs -c task-bar

Both layouts (mostly) reuse the same core components but behave differently depending on mode.

Taskbar Mode Behavior

Taskbar mode has additional desktop components and layout changes:

  • desktop/ScreenBorders.qml
  • dock/Drawer.qml
Default state (no active windows)

When the session starts or when no windows are open:

  • ScreenBorders wrap around the display edges.
  • The taskbar switches to dock mode.
  • The center of the dock contains a quickshell app drawer: dock/Drawer.qml
When a window becomes active

As soon as a window opens:

  • ScreenBorders hide
  • The taskbar switches to workspace mode
    • The taskbar in this state behaves similarly to the regular bar used in top-bar mode, except it appears at the bottom of the screen.
    • The launcher drawer switches to rofi instead of the Quickshell drawer.
Other taskbar-specific changes
  • The rofi (start) menu is wider and contains shaders

  • The Hub media card derives its background colors from album art palette colors, instead of using blurred album artwork.

  • Upcoming events are no longer displayed inside CalendarsWeatherCard.qml and have a dedicated card hub/Events.qml. By default, the next upcoming event is shown until it ends. Multiple events can be added to the list by increasing the loop count in the file.

  • Theme switching also differs between layouts:

    • Taskbar mode: the Hub header has a theme toggle button (dark/light).
    • Topbar mode: right-clicking the Arch glyph launcher icon toggles the theme. Both modes use the same theme script just located at:
    # in top bar mode:
    bash ~/config/quickshell/top-bar/bar/theme-mode.sh dark|light
    # in task bar mode:
    bash ~/config/quickshell/task-bar/utils/theme-mode.sh dark|light
  • Changing colors is generally easier in Taskbar mode, as most styling is handled through the dynamic theme system in lib/ThemeEngine.qml. Some components still use the older theme.js configuration, and a few define their own colors internally, so theme behavior is still not completely unified.

Expand for Topbar/Taskbar components

Workspaces

Clicking a workspace pill runs:

hyprctl dispatch workspace <id>

Updates

Updates are hardcoded for archlinux if you are using a different distro please replace:

// replace this snippet
sh(`
            if [ -e /var/lib/pacman/db.lck ]; then
                cat /tmp/qs_updates_count 2>/dev/null || echo 0
                exit 0
            fi
            n=$(checkupdates 2>/dev/null | wc -l)
            echo "$n" | tee /tmp/qs_updates_count
        `)

with a poller for your distro, for example debian:

// replacement snippet:
sh(`
            # apt list --upgradable does not lock the database, so we skip the lock check
            n=$(apt list --upgradable 2>/dev/null | grep -v 'Listing...' | wc -l)
            echo "$n" | tee /tmp/qs_updates_count
        `)

Clicking the updates pill runs:

kitty -e bash -lc "sudo pacman -Syu"

with this line in Taskbar.qml (line 932) and Bar.qml(line 595):

command: ["kitty", "-e", "bash", "-lc", "sudo pacman -Syu"]

please replace this line with your package manager's update/upgrade command

Date and Clock

  • Pressing the clock emits a requestHubToggle() signal used to open or close the hub.
  • Pressing Esc or clicking outside the hub closes it.

Quickshell Hub

The hub is named 'snes-hub` with

// in HubWindow.qml (line 78 in task-bar and line 68 in top-bar):
WlrLayershell.namespace: "snes-hub"

This is the main control/notification center. The hub is opened by:

  • Clicking the date/clock module in the bar
  • Pressing SUPER + SPACE through a Hyprland keybinding

It is rendered as a wlr-layershell overlay designed to stay out of the way and close quickly. The UI is composed of reusable components so cards can be added, removed, or restyled without rewriting the entire hub.

If you want a lightweight fallback, an earlier AGS version is available in .config/ags/.

EXPAND FOR INDIVIDUAL COMPONENTS

Header

  • Profile icon and username
  • RAM and CPU usage indicators (only in topbar mode)
  • Screenshot button (runs capture script and closes the hub)
  • Power button
  • Theme toggle button (taskbar mode)

Power Options

A compact power grid expands inside the header.

Open it by:

  • Clicking the power button
  • Pressing the p key

Keyboard navigation:

  • Arrow keys / Tab to move
  • Enter to activate
  • Esc to close

Buttons and Sliders

  • Wi-Fi toggle with SSID readout (right-click opens the Wi-Fi module)
  • Bluetooth toggle with connected device status
  • Performance profile button (cycles profiles through auto-cpufreq, right click toggles battery health card)
  • DND toggle (dunst)
  • Volume and brightness sliders (pactl and brightnessctl)

Battery Health

The battery health card shows RAM and CPU usage in Taskbar mode.

Polled using:

upower -i /org/freedesktop/UPower/devices/battery_BAT1

Displayed information:

  • Health (capacity %)
  • Current charge %
  • Charge cycles
  • Energy (full / design)
  • Time remaining (when available)
  • Charging state

NOTE
If your battery device is not battery_BAT1, update the device path in BatteryHealthCard.qml.


Media Card (MPRIS)

The hub includes an MPRIS media card.

  • Appears only when media is playing
  • Clicking it launches the external Now Playing widget and closes the hub
  • Resets its internal state when track metadata changes

Some browser content (like YouTube) can behave inconsistently depending on how the browser exposes MPRIS.

In taskbar mode, the media card uses colors extracted from album art instead of blurred artwork backgrounds.


Now Playing (Flutter)

This is a separate Flutter desktop widget managed through Hyprland window rules.

Behavior:

  • Window resizing is disabled (setResizable(false))
  • Esc closes the widget
  • Theme colors are generated from album artwork using palette_generator

NOTE
You may need to make the now_playing binary executable and change the path to it in MediaCard.qml


Calendar, Weather and Events

The hub includes a calendar and weather card using a JSON-based weather script.

Calendar events are synced from Google Calendar using:

  • vdirsyncer
  • khal

Events are displayed in a dedicated Events card in Taskbar mode instead of inside CalendarsWeatherCard.qml.

The next upcoming event remains visible until it finishes. Multiple events can be configured inside:

hub/Events.qml
Google Calendar sync (vdirsyncer + khal)

Recommended installation method (avoids system Python packaging issues):

sudo pacman -S --needed python-pipx
pipx install "vdirsyncer[google]"

If both a system and pipx version of vdirsyncer exist, remove the system package and ensure ~/.local/bin appears earlier in PATH.

Setup

Create the required directories:

mkdir -p ~/.config/vdirsyncer/status ~/.config/vdirsyncer/tokens
mkdir -p ~/.local/share/vdirsyncer/calendars

Example configuration values:

token_file = "~/.config/vdirsyncer/tokens/google_calendar"
type = "google_calendar"
client_id / client_secret

Calendar files are stored in:

~/.local/share/vdirsyncer/calendars/*

Khal reads .ics files from this location.

Notes

  • The CalDAV API must be enabled in Google Cloud.
  • If OAuth consent is in testing mode, add yourself as a test user.
  • If you receive “token obtained but Not Found”, enable calendars at:

https://calendar.google.com/calendar/syncselect

Sync and test

vdirsyncer discover
vdirsyncer sync
khal list now 7d

Notifications

  • Clicking a notification dismisses it
  • Uses dunst (dunstctl) as the backend
  • Collapsed by default when the media card is active
  • Can be expanded with the expand button

Power menu

Quickshell Power Menu screenshot (Dark) Quickshell Power Menu screenshot (Light)

wlr-layershell power menu overlay (separate from the hub header menu). Toggled with ALT+F4 Run

# in Topbar mode:
quickshell -p ~/.config/quickshell/top-bar/bar/PowerMenu.qml
# in Taskbar mode:
quickshell -p ~/.config/quickshell/task-bar/utils/PowerMenu.qml

Wifi menu

Standalone 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 ~/<pathto>lib/Wifimenu.qml

Warning

You cannot connect to enterprise access points (for now), I haven't had the time to fix it yet

OSDs

Custom on-screen displays for:

  • Volume
  • Brightness
  • Various system modes (Dark, Light, Reading Mode, etc.)

Firefox Customizations

Codex Stellarium

Codex Stellarium preview on Firefox
Get it on Firefox Get Codex Stellarium

Codex Stellarium is an interactive, customizeable astronomy inspired custom new tab/homepage. Replaces the default new tab with an interactive starfield, planetary system, and comet simulator. Contains:

  • Canvas Animations: Interactive comets, planetary orbits, and a parallax starfield.
  • Dynamic Theme: Auto-switches between light and dark modes based on local time or weather conditions.
  • Live Data: Displays current weather (via Open-Meteo API), lunar phase, and sidereal time.
  • Shortcuts: Configurable quick links.
Manual Installation

Note

  • I have a .crx file in the codex-stellarium directory if you want to use it in a chromium-based browser.
  • I also have other custom home/newtab pages in .config/firefox/custom_homes that can be installed with this method

.config/firefox/codex-stellarium Firefox doesn't really want you to use local html as a new tab page, if you want to isntall codex stellarium manually or use your own html as custom new tab:

  • Move config/firefox/defaults/pref/autoconfig.js to Firefox defaults/pref/ (e.g. /usr/lib/firefox/defaults/pref/)
  • Edit config/firefox/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/)

userChrome

/chrome/userChrome.css: A custom stylesheet that overrides the default Firefox interface. (These customizations work in windows or other os as well)

Expand for instructions to install custom usercss:
1. Enable Stylesheets in Firefox
  1. Open Firefox and enter about:config in the URL bar.
  2. Accept the risk warning.
  3. Search for toolkit.legacyUserProfileCustomizations.stylesheets.
  4. Double-click to set the value to true.
2. Locate Your Active Profile
  1. Go to about:profiles.
  2. Find the profile box that states: "This is the profile in use and it cannot be deleted."
  3. Copy the path listed under Root Directory
    (e.g., /home/username/.mozilla/firefox/xxxxxxxx.default-release).
3. Install the Files
  • Copy the userChrome.css into the chrome folder
    (create it if it doesn't exist, or move the chrome folder from this repo)

Themes

GTK:

I use a modified version of Fausto-Korpsvart's Everforest gtk theme. The installer automatically copies it to the required directory for the theme toggle script to use it.

Qt / Kvantum

Kvantum theme files are located in: .config/Kvantum

Additional related configuration files:

  • .config/qt6ct
  • .config/color-schemes

Use Kvantum Manager to install and apply the Kvantum theme.

SDDM

I have two SDDM themes:

  • Stellarium SDDM theme (Astronomy inspired)
  • Pixel SDDM theme (Google Pixel inspired)

The installer installs the themes and writes to conf.d automatically based on your choice. It will however prompt you for password authorization via pkexec.

  • For Manual install:
    • move the contents of sddm/theme folder to /usr/share/sddm/themes/ (create the dir if it doesn't exist yet) and:

      sudo mkdir -p /etc/sddm.conf.d
      echo -e "[Theme]\nCurrent=stellarium" | sudo tee /etc/sddm.conf.d/theme.conf

Utilities

Utilities include the following:

  • crt_gen.py a script to add crt like filters to an image (works best with images that aren't too bright or too dark)
  • figures.py script to generate nice fun mathematical illustrations
  • SR4.icm Color profile for the display of the Surface Laptop 4. Import it in KDE Plasma to get Windows-like color calibration.
  • Fonts I like and use often

Credits & Acknowledgements

Media Sources

  1. Photo by fffunction studio on Unsplash
  2. Photo by Brian McGowan on Unsplash
  3. Photo by Mimicry Hu on Unsplash
  4. Photo by Bailey Zindel on Unsplash
  5. Photo by Jay Yu on Unsplash
  6. Photo by Ben Dutton on Unsplash
  7. Photo by Richard Rhee on Flickr
  8. Photo by Cedric Chambaz on Flickr
  9. Photo by temo Berishvili on Unsplash
  10. Photo by Lucas Pezeta on Unsplash
  11. Photo by Andreas Strandman on Unsplash
  12. Surface default wallpapers are from microsoft
  13. All Rofi pictures were pulled from Pinterest; I don’t know the original owners.

[Reuse Note:]

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.

FAQs

Q: Will this run on a distro other than Arch Linux?
A: I'm not sure about the installer but as long as you have the dependencies I don't see why it wouldn't.

Q: Can I use this setup with another compositor or desktop environment?
A: Yes. Most features, including Quickshell, will work correctly (as long as you're on wayland). Shaders are the only exception. However, some features exclusively rely on hyprland's ipcs, for best experience please use with hyprland

Q: Why use Flutter for the "Now Playing" widget?
A: It was one of my first projects while learning Flutter, which explains the older dependencies. Behind the Material Design frontend, it is just a standard MPRIS controller.

Q: How does the face unlock animation work?
A: It assumes the authentication was successful by default. You may need to adjust the timer in main.qml to get the timing right for a realistic effect. It does properly recognize authentication failures and timeouts.

Q: Why are there multiple app drawers (including the top-bar Rofi drawers)?
A: I am currently experimenting with different designs and layouts. My plan is to write a custom app drawer from scratch in rust with live tiles similar to Windows 10. I want it to feel distinctly native to Linux rather than acting as a cheap copy of the Windows Metro UI.

Q: Why are the desktop layouts two different shells instead of one unified shell with two options?
A: The project originally started as a simple calendar widget for my Google Calendar events. As more components were added over time, it evolved without a strict overall layout plan. Consolidating everything into a single shell would require significant code edits which I don't want to do atm

Q: How do I enable or disable screen borders?
A: (Only in taskbar mode) follow the instruction in shell.qml

Q: Components are misaligned in the hub. How do I fix them?
A: You can correct alignment by adding padding (left, right, up, down), adjusting spacing, or using the translate function. For example, to move weather in CalendarWeather card to the right:

// Right: Weather
      ColumnLayout {
        Layout.alignment: Qt.AlignTop | Qt.AlignRight
        Layout.preferredWidth: 110

        /* increase to move right, decrease (values can be negatives too) to move to the left */
        transform: Translate { x: 5 }  // <--- add this

Q: The taskbar is covering windows at the bottom of the screen. How do I fix this?
A: Decrease the layer exclusive zone in Taskbar.qml or increase the gaps in Hyprland config.

// desktop/Taskbar.qml
    WlrLayershell.exclusiveZone: 47 // <-- change this

Q: Will you make a settings app to configure things instead of requiring file edits?
A: Yes, that is the plan. I do not have a strict timeline yet because there's so much spaghetti code

Q: Can I use the top-bar Rofi on the taskbar, or vice versa?
A: Yes. You just need to edit the path to the launcher script in your Hyprland configuration and update the on-click action within the launcher component for the respective bars.

Q: The theme switcher is not applying my GTK or Qt themes. How do I fix it?
A: First, make sure the script has executable permissions. Next, verify the theme files exist and match the names referenced in the script. Finally, run the script directly from the terminal to check for specific error messages abd fix them one by one.

If you have any other questions, please start an issue. I'd be more than happy to answer it for you.

About

Personal linux dotfiles + UI setup

Topics

Resources

Stars

Watchers

Forks

Contributors