Files
website/README.md
T

5.9 KiB

Sir Blob's Desktop

A portfolio website that recreates my Arch Linux desktop (Hyprland, Quickshell bar, kitty terminals) in the browser. Built with SvelteKit 3, Svelte 5 runes and Tailwind CSS 4.

Running

bun install
bun run dev
bun run build
bun run check

How the desktop works

  • The top bar mirrors the blob-shell Quickshell bar: chai menu (app launcher), workspaces 1-9, clock, Discord status and theme picker.
  • Every page (/about, /projects/hackathons, ...) opens as a tiled window, so old resume links still work.
  • Terminals open next to it and tile with the Hyprland dwindle layout.
  • Desktop icons open a page, a terminal running a command, or an external link.
  • On small screens the focused window goes fullscreen and open windows are listed as tabs.

Keybinds

Keys Action
Alt + Enter Open a kitty terminal
Alt + Space App launcher
Alt + Q Close focused window
Alt + F Fullscreen the page window
Alt + J / K Focus next / previous window
Alt + 1-9 Switch workspace
Alt + T Next theme

Alt stands in for Super, which browsers do not receive.

Editing content

Everything you would normally change lives in content/. No code changes needed.

File Contents
content/profile.json name (shown only on the portfolio page), bio, avatar, education, socials (also used by the links page), skills, interests
content/experience.json experience with highlights, tech, awards and links
content/leadership.json leadership roles
content/about.json hobbies, games, shows, movies
content/projects/opensource.json open source projects
content/projects/packages.json published packages
content/projects/hackathons.json hackathon projects, events and awards
content/projects/research.json research roles and projects
content/models.json 3D models (files go in static/models/)
content/desktop.json default theme, workspaces, desktop icons, startup command
content/blog.json blog name, tagline, posts per page
content/blog/*.md blog posts

Projects

Every project in every category uses the same shape. Only name, description, tags and links are required.

{
	"name": "HushMap",
	"description": "What it does.",
	"image": "/hacks/hushmap.png",
	"tags": ["Svelte", "FastAPI"],
	"featured": true,
	"event": { "name": "Bitcamp 2026", "university": "University of Maryland", "location": "College Park, MD", "year": "2026" },
	"awards": [{ "track": "Best UI/UX Hack", "place": "Winner" }],
	"demoMayBeOffline": false,
	"version": "2.2.0",
	"links": { "demo": "https://...", "code": "https://...", "devpost": "https://...", "package": "https://...", "article": "https://..." }
}

Featured projects are listed first.

Desktop icons

Each icon in content/desktop.json has a label, an Iconify icon and one open action:

{ "label": "about", "icon": "mdi:account", "open": { "page": "/about" } }
{ "label": "skills.sh", "icon": "mdi:script-text", "open": { "terminal": "skills" } }
{ "label": "github", "icon": "mdi:github", "open": { "url": "https://github.com/SirBlobby" } }

{ "terminal": "" } opens an empty terminal.

Blog posts

Add a markdown file to content/blog/. The file name is the URL slug.

---
title: My Post Title
author: Sir Blob
date: 2026-01-01
tags: meta, notes
excerpt: One line summary for the list and the RSS feed.
---

Post content in markdown.

The RSS feed is at /blog/rss.xml.

Themes

Themes live in src/lib/theme/themes.ts and use the same keys as a blomarchy colors.toml, so a theme can be copied over from the dotfiles. Each theme can set a wallpaper (from static/wallpapers/) and an activeBorder gradient. The default theme is set in content/desktop.json.

Shipped themes: Flats (default), Retro 82, Tokyo Night, Catppuccin, Arch Linux, Gruvbox, Nord, Kanagawa, Wintry, Rose, Cerberus, Catppuccin Latte, Rose Pine Dawn.

Terminal commands

help, whoami, fastfetch, skills, contact, email, experience, projects [category], ls, cd <page>, theme [name], echo, cowsay, date, clear, exit. Page names (about, hackathons, ...) and social names (github, linkedin, ...) also work as commands. Tab completes commands, pages after cd, themes after theme and categories after projects; when several match it lists them like bash. Up/Down walk history, Ctrl+L clears.

Commands live in src/lib/terminal/commands/.

Code layout

Path Contents
src/lib/content/ typed loader for content/
src/lib/blog/ markdown renderer, frontmatter, highlighting, dates
src/lib/theme/ theme palettes, stylesheet generation, current theme state
src/lib/desktop/ window manager, dwindle tiling, keybinds, desktop actions
src/lib/terminal/ terminal output model and commands
src/lib/site/pages.ts page list used by the terminal and launcher
src/lib/components/shell/ bar, workspaces, clock, theme menu, Discord status
src/lib/server/discord.ts Discord bot and presence lookup
src/lib/components/desktop/ desktop, windows, icons, launcher
src/lib/components/terminal/ kitty terminal
src/lib/components/ui/ shared page pieces
src/routes/ pages

Discord status

The bar shows live Discord presence (status, avatar, guild tag, activities). A discord.js bot starts with the server (src/hooks.server.ts) and the bar polls /api/discord every 30 seconds. Copy .env.example to .env and fill in:

Variable Value
DISCORD_TOKEN bot token, with the Server Members and Presence intents enabled
DISCORD_USER_ID your user id
DISCORD_GUILD_ID a server both you and the bot are in

Variables are declared in src/env.ts. Without them the widget shows your profile name as offline.

Analytics

Umami is loaded in src/app.html.