Sir Blob's Desktop

My portfolio website, built as a web version of my Arch Linux desktop.

Arch Linux Hyprland SvelteKit TypeScript Tailwind CSS Bun

The site recreates my blomarchy setup in the browser: a Hyprland-style tiling desktop, the Quickshell bar, and kitty terminals you can type into.

Features

  • Tiling windows - every page opens as a window that tiles like Hyprland's dwindle layout, with gradient borders.
  • Quickshell bar - app launcher, workspaces, clock, music player, live Discord status, battery details, a theme picker and a wallpaper picker.
  • Music player - plays a random song from a YouTube playlist, muted until you unmute it, with seek, skip, repeat, volume and a playlist view.
  • Floating windows - Alt + V or the title bar button pops a window out of the tiling layout so it can be dragged and resized.
  • btop - a system monitor window with my real GitHub commit graph, repos as processes and some very scientific CPU and caffeine readings.
  • Image viewer - click any image to open it in an imv window with zoom, pan, rotate, pinch and swipe.
  • Kitty terminals - a real command line with history and tab completion. Try fastfetch, whoami or cowsay.
  • Desktop icons - grouped into pages, terminal scripts and socials (GitHub, LinkedIn, Devpost, Discord).
  • 13 themes - Cerberus, Flats, Tokyo Night, Night Cat, Catppuccin, Arch Linux, Gruvbox, Nord, Kanagawa, Wintry, Rose, Catppuccin Latte and Rose Pine Dawn, each with its own wallpaper.
  • Portfolio - about, portfolio, projects (open source, packages, hackathons, research, organizations), blog with RSS and links with QR codes.
  • Live data - GitHub stars and forks, npm downloads, AniList anime stats and OMDb posters for shows and movies.
  • Mobile friendly - on small screens windows go fullscreen with tabs to switch between them.

Keybinds

Keys Action
Alt + Enter Open a terminal
Alt + Space App launcher
Alt + Q Close window
Alt + F Fullscreen page
Alt + V Float or tile window
Alt + J / K Next / previous window
Alt + 1-9 Switch workspace
Alt + T Next theme

Alt stands in for Super, since browsers can't use it.

Image viewer

Keys Action
Left / Right Previous / next image
+ / - Zoom in / out
0 Fit to window
R / Shift + R Rotate right / left
Esc Close viewer

Terminal commands

Command Does
help list every command
whoami who I am
fastfetch system info
skills skills by category
experience work experience
projects [category] list my projects
contact where to find me
ls / cd <page> browse and open pages
theme [name] list or switch themes
cowsay <text> moo
btop system monitor with my GitHub stats
pacman -S <pkg> install things (not really)

Running

bun install
bun run dev
bun run start

The music player needs ffmpeg installed on the server.

Docker

docker compose up -d --build

The image builds the site with Bun and includes ffmpeg. It reads .env and serves on port 3000; set HOST_PORT to publish it on a different port.

Configuration

Copy .env.example to .env and fill in what you need. Every value is optional.

Variable Used for
DISCORD_TOKEN, DISCORD_USER_ID, DISCORD_GUILD_ID Live Discord status in the bar
OMDB_API_KEY Posters and details for shows and movies

Content

Personal content and config live in content/. Data the tools fetch or generate from it (scraped book details and OMDb details) lives in data/, and downloaded images go in static/. Both are committed so the site never has to call Goodreads or OMDb for saved entries. data/lastfm is the exception: the server fills it at runtime and it stays out of git.

Content editor

A terminal app built with Textual edits the playlist, shows, movies, books, portfolio, projects and themes without touching the JSON by hand. It uses the site's own themes.

bun run content:setup
bun run content

content:setup creates a virtual environment in tools/content/.venv and installs Textual and Pillow. Run it once.

Key Action
1 to 9 Switch between Music, Shows, Movies, Books, Profile, Experience, Leadership, Projects and Themes
a Add (YouTube link, IMDb link or Goodreads link)
e / Enter Edit the selected entry (or change the rating for shows, movies and books)
f Toggle featured on a project
p Preview a theme in the editor
t Switch the editor to the next theme
s Move a book to another shelf, set a show or movie to watched, watching or planning, or make a theme the site default
d Delete
K / J Move a song or entry up or down
u / U Refresh the selected book, or every book, from Goodreads; u also refreshes a show or movie from OMDb
C Download every missing book cover, or every missing show and movie poster and details
r Reload from disk
q Quit

Show and movie titles are looked up on OMDb with OMDB_API_KEY from .env once when added. The details go into data/mediaDetails.json and the poster into static/covers/media, so the site only asks OMDb about titles that have nothing saved; fill in the name field to skip the lookup. Book covers are saved into static/covers/books. Books are scraped from Goodreads once when added: your shelf, rating and series go into content/books.json, and the scraped details into data/bookDetails.json. To check a Goodreads link on its own, run python3 tools/content/goodreads.py <url>.

File Holds
profile.json Name, bio, socials, skills and photos
about.json Hobbies, games, shows, movies and the AniList username
experience.json / leadership.json Work experience and leadership roles
projects/*.json Open source, packages, hackathons, research groups and organizations
music.json YouTube links for the music player
books.json Your books: Goodreads link, shelf, rating and series
wallpapers.json Wallpapers for the picker, written by bun run wallpapers
desktop.json Workspaces, desktop icons, the startup command and the default theme
themes.json Color themes for the site and the content editor
blog/*.md Blog posts
Generated file in data/ Holds
bookDetails.json Title, authors, cover, description, pages and genres scraped from Goodreads
mediaDetails.json Year, genre, runtime, plot and poster path from OMDb

Wallpapers

bun run wallpapers

Converts every image in ~/dotfiles/wallpapers into a compressed JPEG in static/wallpapers/gallery, with a small thumbnail for the picker, and writes the list to content/wallpapers.json. Unchanged wallpapers are skipped, so run it again whenever the dotfiles change. Pass a folder to use a different source, or --force to convert everything again.

Languages
Svelte 45.5%
TypeScript 33%
Python 21%
CSS 0.3%