wntr

arch · hyprland · quickshell · php

the stack

two hand-built websites, a desktop that recolors itself from a video wallpaper, a bar i rebuilt piece by piece, and sixteen desktop apps i wrote because the existing ones weren't mine.

~4klines on the site
~45klines of my own apps
~43klines of shell ui
14apps follow the wallpaper
5.3msaudio latency
0frameworks
the desktop

it started as a normal rice

it began like most people's: a downloaded setup on omarchy (ilyamiro's imperative-dots) with catppuccin pink borders, bouncy animations, and a generator that wrote my config files for me. none of that is what runs now.

day one

a stock rice

someone else's hyprland + quickshell setup. config was spat out of a settings.json through templates and a file watcher, so nothing was really mine to edit.

the gut

generator ripped out

retired the whole template engine and rewrote hyprland as clean hand-written files: animations, rules, binds, monitors, gaming. catppuccin hardcodes gone. ~/.config became a git repo with one focused commit per area.

the look

this site became the design spec

took the design language off this page and pushed it into every app: one font (geist mono, swapped in 515 places in the shell alone), one motion curve, moonlight glow, no bounce.

the color

everything follows the wallpaper

wired a pipeline so a video wallpaper decides the color of the whole system, live, with no restarts.

the bar

the last of ilyamiro, gone

rebuilt the top bar and every popup on it one piece at a time: the music player, weather + calendar, network, the volume mixer, the power center, the lock screen and the app launcher. no polling shell scripts left; it all runs on quickshell's native services.

the core

lua config, lock-screen boot new

moved all of hyprland from hyprlang to lua before hyprlang gets removed, live, without logging out. then got rid of the black disk-password prompt: the tpm unlocks the drive and the pc boots straight into my own lock screen.

now

a different machine

on top of that sit sixteen apps i wrote myself, from a fan + rgb controller, a channel mixer and a photo editor to configurators for my mouse, keyboard, controller and usb hub screen. all of them theme themselves from the wallpaper too.

the design language

one curve
cubic-bezier(.16, 1, .3, 1) is the ease on this website and it's the exact bezier hyprland uses for windows, layers, fades and workspaces. the desktop and the site move the same way.
one font
geist mono nerd font everywhere: hyprland, quickshell, kitty, rofi, fuzzel, mako, swaync, qt, gtk, every app i built.
motion
windows pop in at 92% scale and settle, workspaces slide-fade 15%, zero overshoot. 118 bouncy easings in the shell were replaced by hand. popups unfurl down out of the bar.
american
°f, mph, inhg, miles, 12-hour clocks and sunday-first calendars everywhere.

under the hood new

config in lua
ten lua files with a wntr banner on top of each one. the switch was diffed before and after so nothing changed: 94 binds, every option, 35 animations, 12 workspace rules. lumen and the color pipeline write lua now too, and edits reload on save.
boot to lock screen
the tpm unlocks the drive at boot, so the first thing on screen is my lock screen, which is the login.

wallpaper to whole system color

live wallpaper
my own wallpaper-engine-style picker: a video or image per monitor, or a folder it shuffles through. runs as a systemd service on mpvpaper.
color extraction
it grabs a frame from the video and matugen builds a material-you palette from it.
14 targets
quickshell, hyprland borders (45° gradient), kitty, neovim, cava, swayosd, swaync, rofi, gtk, qt5, qt6, both qt styles, rmpc.
hot reload
a reload script signals every app to repaint in place: kitty and cava get usr1, rmpc and swayosd restart, gtk gets force-flushed. change the wallpaper and the whole desktop recolors in about a second.
past the desktop
my rgb fans, ram and keyboard, my password manager and every app below can follow the same palette.

the top bar, rebuilt

the bar
every pill is plain dark glass tinted from the wallpaper. the old keyboard-layout pill and the battery ui are gone ("this is a pc, not a laptop"). popups anchor under the pill you clicked and unfurl down from a sliver of the bar.
music player
an apple-style controller in the bar: marquee title, drawn glyphs, a scrubber, on native mpris. click it and a live beatprints poster drops down under it: the cover, a palette pulled from the album art that doubles as the scrubber, synced lyrics, and a cava band. the icon row is real controls, the heart prints the poster to a png that drops onto the screen, right-click cycles its theme.
weather
the bar chip is a tiny live sky. the popup is the whole sky: gradient by time of day, sun arc and bloom, a real moon phase, stars and shooting stars, two layers of drifting clouds, mist, particle rain and snow, lightning. glass cards blur the sky behind them: a calendar, moon + daylight, a 24-hour curve you scrub with the mouse, a 5-day forecast (click a day to see its weather in the sky), wind, humidity, pressure and visibility. tuned to a locked ~250 fps on the 240 hz panel with zero hitches.
network
one pill for ethernet, wifi, bluetooth and vpn with hand-drawn glyphs. on ethernet it shows link speed and live up/down throughput. wifi scanning, connect with password, forget. bluetooth devices. a full nymvpn section: connect/disconnect, gateway picker, ad-block.
volume
the pill shows master volume live (scroll to change, middle-click mutes, peak meter on hover). the popup is a mixer wired into fader: master, mic, a personal/stream switch, five channel strips with post-fader meters and pre-gain badges, per-app channel pills, and an output picker.
power center
avatar (right-click to change), user@host and uptime. lock and sleep, hold-to-confirm logout/restart/poweroff. a live system card from rig: cpu/gpu temps, fans, memory with sparklines. display controls from lumen: hdr switch, brightness, night light + kelvin. lights from halo with live zone colors and presets. notification history with do-not-disturb.
lock screen
since the tpm unlocks the drive on its own, this is the first thing the machine shows at boot now. the lock screen is my login, no black password console in front of it. the live video wallpaper keeps playing behind it, hardware-decoded, while the desktop one pauses. idle shows a big glowing clock, date and weather; start typing and the clock slides up for avatar + password pill (it shakes on a wrong password). now playing bottom-left, power bottom-right.
app launcher
alt+tab. split layout: search, a rounded picture (wallpaper, a gif, a video or a random pick from a folder) and tabs for apps / run / files / windows on the left, results on the right. remembers what i launch most.
screenshots
every screenshot drops onto the screen as a physics card: it shrinks out of the region, falls, bounces and tumbles. throw it around, hold and drag it straight into discord, double-click to dismiss.
still there
settings, clipboard manager, focus-time tracker, updater, timer, draw tool, system usage, a desktop pet and the purin boot splash.

tuned for comp games

rig
ryzen 7 7800x3d, rtx 4070 super, asus 1440p 240hz oled on displayport, nzxt kraken elite, lian li uni fans, wooting 60he+, pulsar x2 crazylight on an hm lab 8k hub, beacn mic, govee light bars and a wired powera switch controller.
display path
screen tearing allowed and direct scanout for games, so frames skip the compositor. vrr deliberately off because the games run way past 240 fps.
input + cpu
flat raw mouse accel, hardware cursors, gamemode renices the game and flips the cpu to the performance governor.
audio
pipewire quantum cut from 1024 to 256: 21 ms down to 5.3 ms, mic path included.
roblox
runs natively through sober with hand-picked fflag presets (og / fps / max). ~1.1k fps baseline.
skate. new
modded and offline through the reskate launcher on proton. a forever black screen turned out to be the cpu's tiny amd igpu: the game deadlocked on load just because it could see it, so it's now filtered down to the 4070. it always opens tiled on workspace 6 under the bar, pretty much fullscreen, and i play it on the controller through guise.
spotify
patched liquid lyrics locally to fix a webgl leak that crashed spotify's gpu process and made lyrics lag.
portable
one script packs the entire setup into a tarball, and the installer detects the hardware on a laptop and strips the nvidia and monitor-specific bits.
built from scratch

apps i wrote

each one is its own python program with a custom gui, themed from the wallpaper and set in geist mono. most run as background services. the hardware ones talk to devices directly, with protocols lifted from vendor web drivers.

grain new

7.6k lines

a layered photo editor like pixlr, except it runs entirely on the pc. no account, no ai, nothing uploaded.

  • layers with 13 blend modes and live layer styles: inner and outer glow, outline, drop shadow, bevel
  • every adjustment pixlr has: curves, levels, hue/sat, color balance, exposure, highlights/shadows, vibrance
  • color lookup with 20 built-in looks or any .cube lut
  • filters from blur, grain and clarity to glitches (rgb split, scanlines, slice), fish eye, kaleidoscope, halftone, bloom and dehaze
  • the full toolbox: marquee, lasso, magic wand, crop, brush, clone, bucket, gradient, shapes, editable text, free transform
  • sliders stay live on 24 mp photos: a small proxy renders while you drag, then the exact full-res result lands
  • 80 steps of copy-on-write undo, each one under a millisecond
  • projects save as one .grain file with every layer intact

guise new

3.6k lines

turns a switch controller into an xbox controller. my own xoutput, with rebindable everything.

i built this on a whim for one reason: i wanted to play reskate with a controller. that's it, no other reason. it ended up at 3.6k lines with a daemon, a gui, a cli, gyro and a hidhide clone, and my actual controller doesn't even have gyro or rumble. it supports both anyway.

  • reads the pad straight from the kernel and grabs it so games only see the fake
  • the fake has the exact identity of a real xbox 360 pad, so every game and steam treat it as one
  • zero polling: each output frame goes out the instant the controller reports one
  • press-to-bind remapping; the press you bind with is swallowed so it never reaches the game
  • presets by position or by letter, turbo, stick routing, profiles
  • deadzone, outer and anti-deadzone, response curves and invert, with a live stick preview
  • gyro to stick with calibration, rumble passthrough, joy-con pairs merged into one pad
  • hide mode: a udev rule that hides the real pad from steam and proton entirely (linux hidhide)
  • found a bug in python-evdev's rumble upload along the way, so it does those kernel ioctls by hand
  • background service plus a gui, a cli and an on/off/toggle bind

rig

4.3k lines

replaced coolercontrol. fans, aio, lcd, rgb and system monitoring.

  • background daemon over a unix socket plus a gui and cli; the bar's power center reads it live
  • fan curves smoothed with ema and ramp limits, panic mode at 90°c, pump curve uploaded into the kraken itself
  • pushes live stats or gifs onto the kraken's 640×640 lcd
  • rgb is a software effects engine: 19 effects in numpy rendered at 30 fps and streamed as raw led packets to every device

fader

3.7k lines

beacn's windows mixer, rebuilt for linux on pipewire.

  • five channels (system, game, music, chat, aux) with separate personal and stream mixes
  • a daemon routes every app to its channel and remembers where you put it
  • ramped volume changes, zero crackle, mic latency cut from 21 ms to 5 ms
  • drives the mic's onboard dsp over usb: live eq graph over the mic spectrum, headphone bass/treble, lighting
  • "flex mode" with bouncing studio waves and gradient bars

terrarium

3.8k lines

a small autonomous ai that lives on the pc. he named himself rill.

  • wakes himself up on his own schedule, works on his own interests, journals, then picks when to sleep
  • runs code inside a sandbox with no network and capped cpu and memory
  • has eyes and a body: a little corner window with sprites he draws himself; poke, pet and hug him
  • knows the weather, the tide and the moon phase. holds his messages while i'm in a game

splice

3.9k lines

a premiere-style multi-track video editor for linux.

  • compiles the whole timeline into one ffmpeg filtergraph, exports on the gpu with nvenc
  • keyframes on position, scale, rotation and opacity
  • chroma key, .cube luts, audio denoise and compression
  • smooth playback through background-rendered proxies

halo

2.7k lines

ambilight for my govee bars: the lights follow what's on screen.

  • captures the screen as a tiny gpu video stream so the 240 hz desktop never stutters
  • splits it into zones, smooths with two-stage easing and dithering, streams frames to the lights over the lan
  • drops to 8 hz when the screen is still, restores the lights' own scene on exit
  • survives vpns and power-cycled lights

confidant new

1.5k lines

a private ai that runs entirely on the pc. nothing leaves it.

  • a 30b vision model on the 4070 super through ollama, localhost only, ~34 tokens/s
  • password-locked; every chat and image encrypted with aes-gcm
  • locking wipes the key, the open chats and the clipboard, and unloads the model so its memory goes too
  • paste or drop images, optional web research with a strict query privacy rule, auto-lock when idle

lumen

2.3k lines

monitor control: hdr, brightness, night light, profiles.

  • talks to the oled directly over ddc/ci on i2c
  • smart brightness: drives sdr-in-hdr brightness when hdr is on, because the panel rejects hardware brightness in hdr
  • writes hyprland's newer monitorv2 config so hdr luminance keys actually apply; slider drags apply live

flick

1.9k lines

a config app for my pulsar x2 crazylight.

  • speaks the mouse's hid protocol, read out of pulsar's own web driver
  • dpi stages, polling rate up to 8k, lift-off, debounce, motion sync, angle snap
  • whole-mouse profiles and a backup of the factory settings

hall

1.4k lines

a live view of my wooting 60he+.

  • every key animates to its real travel depth, 0 to 4 mm, at 60 fps
  • keys glow when actuated and ripple on press; a 3-second travel graph
  • measures where each key actually actuates and resets

hmlabs

1.9k lines

puts my own pictures and gifs on the usb hub's little screen.

  • reverse-engineered serial protocol, safe stock flash path only
  • gallery with drag-drop, fill/fit, portrait mode for standing the hub up
  • brightness, slideshow and a live usb power monitor

uwu vault

2.2k lines

an offline password manager.

  • argon2id key derivation into aes-256-gcm with an authenticated header
  • key held in locked memory and wiped on lock; locks on suspend or focus loss
  • built-in 2fa codes, password health audit, passphrase generator

triad wallet

1.8k lines

a fake multichain crypto trading terminal, built purely to look insane.

  • btc, xmr and sol, every number driven by one 40 ms heartbeat
  • "the pit": flickering order books, flying trade tape, whale alerts and liquidation explosions

verse

0.7k lines

discord "listening to spotify" with the live lyric line.

  • official rich presence, no self-botting
  • lyrics from spotify itself through a spicetify bridge, lrclib as backup
  • runs headless as a user service

clipper

medal clone

instant replay without obs.

  • always-on 5 minute replay buffer in ram, encoded on the gpu
  • f9 saves the last 30s, shift+f9 60s, ctrl+f9 15s
  • 1440p at 120 fps, clip browser with thumbnails
this site

the websites

two sites, one engine: this page and a polaroid moodboard for my gf. no framework, no build step, no database: hand-written php and plain javascript, around 4k lines, on cheap shared hosting.

what you're looking at

entrance
an "enter" gate (browsers block sound until you click), then the song fades in over a looping video background with film grain, vignette, pointer parallax and blur-in reveals.
music-reactive
the browser's audio analyser runs a 4096-point fft, split into log-spaced bands from 45 hz to 12 khz. those bars radiate out of the logo's outline like a cava visualizer, and a bass kick detector pulses the glow and flashes the screen on the beat.
the tab title
the name does a wave where each letter pops into superscript, deletes itself, types back out with a cursor, then scrolls the now-playing song as a marquee.
the moodboard
every piece of tape is generated by code: torn edges, frayed paper notes, 10 tape layouts × 10 tape styles, stickers and doodles, all off a seeded random generator so the layout is identical for every visitor.
performance
phones run the effects at half rate, the visualizer pauses when you scroll past it, and reduced-motion is respected.
behind it
every change is versioned with one-click undo, uploads are re-encoded server-side, and the analytics are my own. no google anything.

arch linux · kernel 7.2 · hyprland · made by wntr · updated nov 2026

·