An interactive desktop-style portfolio for a Site Reliability Engineer, built with Astro as a static site. The main page renders an OS-like desktop with launchable app windows, persisted preferences, a command palette, a local music player, and an SRE chaos game.
- Interactive desktop shell with draggable, resizable, minimizable windows.
- Desktop icons, external shortcuts, start menu, taskbar, tray controls, and
Ctrl/Cmd+Kcommand palette. - Server-rendered desktop apps for Welcome, Blog, Work, Projects, About, Certifications, Gallery, Terminal, Calculator, Settings, Trash, White Noise, Music, Snake, and the SRE game.
- Standalone resume download page at
/resumewith client-side PDF generation. - Local music library loaded at build time from
public/music. - Markdown/MDX blog content with local images in
src/assets/blog/, standalone/blogroutes, RSS, and sitemap output. - GitHub Pages deployment through Astro's GitHub Action.
- Node
>=22.12.0 pnpm
The repository includes pnpm-lock.yaml, so use pnpm for installs and
scripts.
Run commands from the repository root.
| Command | Action |
|---|---|
pnpm install |
Install dependencies |
pnpm dev |
Start the Astro dev server |
pnpm build |
Build the static site into dist/ |
pnpm preview |
Preview the production build locally |
pnpm test:e2e |
Run Playwright end-to-end tests |
pnpm test:e2e:ui |
Run Playwright in UI mode |
pnpm astro --help |
Show Astro CLI help |
Use pnpm build as the default verification step after code changes. Use
pnpm test:e2e for desktop shell, window manager, command palette, settings,
music player, game, calculator, gallery, or other interaction changes.
βββ public/
β βββ music/ # Local music files discovered at build time
βββ src/
β βββ assets/
β β βββ blog/ # Blog post images (prefixed with blog post names)
β β βββ fonts/ # Local fonts
β βββ components/
β β βββ apps/ # Server-rendered desktop app bodies and helpers
β β βββ desktop/ # Window manager, icons, command palette, menus
β βββ content/
β β βββ blog/ # Markdown/MDX blog posts (supports Obsidian format)
β βββ data/ # Portfolio data JSON (projects, skills, certifications, etc.)
β βββ layouts/
β βββ pages/
β β βββ blog/ # Standalone blog index and static post pages
β β βββ index.astro # Main desktop entry point
β β βββ resume.astro # Standalone resume download page
β β βββ rss.xml.js # RSS feed
β βββ styles/ # Split CSS modules imported by global.css
β βββ types/ # TypeScript type definitions for data structures
β βββ utils/ # Utility functions (certifications sorting, etc.)
βββ scripts/
β βββ generate-og-image.mjs # Regenerates public/og-image.png
βββ tests/e2e/ # Playwright desktop coverage
βββ .deployment-config.md # Security headers and deployment guide
βββ dist/ # Generated production build output
Do not edit generated files in dist/.
- Add portfolio content to the relevant JSON file in
src/data/.- Update TypeScript interfaces in
src/types/data.tswhen adding new fields.
- Update TypeScript interfaces in
- Add blog articles to
src/content/blog/and keep frontmatter compatible withsrc/content.config.ts. Blog posts support both standard Astro and Obsidian frontmatter formats (all fields optional). - Add blog images to
src/assets/blog/with filenames prefixed by the blog post name (e.g.,aws-graviton-01.png,obsidian-multi-devices-cover.png). - Add local music files to
public/music/; supported files are discovered bysrc/data/music.tsduring the Astro build. - Run
node scripts/generate-og-image.mjswhen regenerating the default Open Graph image atpublic/og-image.png. - When adding a new desktop app, register it in
src/pages/index.astro,src/components/desktop/StartMenu.astro,src/components/desktop/CommandPalette.astro, andsrc/components/desktop/AppIcon.astro.
Site metadata is configured in src/consts.ts.
The project uses TypeScript path aliases for cleaner imports:
@/*βsrc/*@components/*βsrc/components/*@data/*βsrc/data/*@utils/*βsrc/utils/*@app-types/*βsrc/types/*@layouts/*βsrc/layouts/*@styles/*βsrc/styles/*
Example:
import { Project } from '@app-types/data';
import projects from '@data/projects.json';
import { sortCertificationsByStatus } from '@utils/certifications';The site deploys to GitHub Pages from main via
.github/workflows/deploy.yaml, using withastro/action followed by
actions/deploy-pages.