Desktop Resume
Back to Blog

How I Built mtsaga.net: Architecture, Desktop Environment, Terminal & Design System

architecture design-system next-js javascript css service-worker web-development

Introduction

When I set out to build my personal site, I knew I didn’t want a generic portfolio page. I wanted something that showcased not just what I’ve built, but how I think about engineering problems. The result is mtsaga.net — a platform that includes a full Windows 11-style desktop environment, a PowerShell terminal emulator, an interactive file explorer, and a blog — all stitched together by a unified design system.

This post breaks down the architecture, key engineering decisions, and lessons learned building each major feature.


Site Architecture Overview

The site is a hybrid architecture combining multiple technologies:

Layer Technology Purpose
Blog & Pages Jekyll (GitHub Pages) Static content, blog posts, SEO
Desktop UI Next.js + TypeScript Windows 11 environment
Terminal Vanilla JavaScript PowerShell emulator
Explorer Vanilla JavaScript File browser UI
Design System CSS Custom Properties Unified visual language
Deployment GitHub Pages + Cloudflare CDN, SSL, caching

The key decision was not making the entire site a single SPA. Each feature is self-contained — the blog is statically generated by Jekyll for SEO and speed, while the desktop environment is a separate Next.js app under /desktop/. This gives us the best of both worlds: fast, crawlable content and rich interactive experiences.

Why This Hybrid Approach?

  1. SEO: Blog posts need to be statically rendered and crawlable. Jekyll does this perfectly.
  2. Performance: The main site loads in under 1 second. The desktop app only loads when someone navigates to /desktop/.
  3. Independence: Each feature can be developed, tested, and deployed independently.
  4. Simplicity: No complex build orchestration — Jekyll handles the outer shell, Next.js handles the desktop.

The Desktop Environment

The crown jewel of the site is a fully functional Windows 11-style desktop that runs entirely in the browser.

Window Management

The window manager handles:

  • Drag and drop positioning with boundary constraints
  • Resize from all edges and corners
  • Minimize to taskbar with animation
  • Maximize with double-click title bar toggle
  • Z-index stacking with focus management
  • Snap layouts for window tiling

Each window is a React component that maintains its own state (position, size, minimized/maximized). The window manager coordinates z-index ordering so the focused window is always on top.

// Simplified window state management
interface WindowState {
  id: string;
  title: string;
  position: { x: number; y: number };
  size: { width: number; height: number };
  isMinimized: boolean;
  isMaximized: boolean;
  zIndex: number;
}

Virtual File System

The desktop includes a virtual file system that maps to real content on the site:

  • /Desktop/ → Desktop icons and shortcuts
  • /Documents/ → Resume, certifications
  • /Projects/ → Portfolio items
  • /Blog/ → Links to blog posts

This is backed by a JSON data structure that mirrors a real file tree, allowing the Explorer app to navigate it and the Terminal to cd through it.

Start Menu & Taskbar

The taskbar tracks open windows, shows a clock, and provides system tray icons. The Start Menu is a searchable app launcher that filters through available “applications” (About, Resume, Projects, Blog, etc.).

Service Worker & Offline

A custom service worker (serviceworker.js) provides:

  • Cache-first strategy for static assets (images, fonts, CSS)
  • Network-first strategy for HTML pages
  • Offline fallback page when connectivity is lost
  • App manifest for PWA “Add to Home Screen” support
// Cache strategy in serviceworker.js
self.addEventListener('fetch', event => {
  if (event.request.destination === 'image' || 
      event.request.url.includes('/assets/')) {
    event.respondWith(cacheFirst(event.request));
  } else {
    event.respondWith(networkFirst(event.request));
  }
});

Performance Considerations

The desktop app uses Next.js code splitting aggressively. Each “application” (About, Resume, etc.) is a separate chunk that only loads when the window opens. This keeps the initial bundle small despite the complexity of the environment.


The Terminal Emulator

The terminal at /terminal/ is a custom-built PowerShell-style emulator written in vanilla JavaScript — no frameworks, no dependencies.

Command Parser

The parser tokenizes input into command name and arguments, handling:

  • Quoted strings ("hello world")
  • Pipe operators (|)
  • Flag parsing (-Name value, -Recurse)
  • Tab completion with cycling
// Tokenizer approach
function tokenize(input) {
  const tokens = [];
  let current = '';
  let inQuote = false;
  
  for (const char of input) {
    if (char === '"') { inQuote = !inQuote; continue; }
    if (char === ' ' && !inQuote) {
      if (current) tokens.push(current);
      current = '';
      continue;
    }
    current += char;
  }
  if (current) tokens.push(current);
  return tokens;
}

Built-in Commands

The terminal supports a full set of commands:

Command Description
Get-Help Shows available commands
Get-ChildItem / ls Lists directory contents
Set-Location / cd Changes directory
Get-Content / cat Reads file contents
Clear-Host / clear Clears the terminal
Get-Process Shows “running” processes
Get-Certification Lists my certifications
Get-Experience Shows work experience

Each command is a self-contained function that receives parsed arguments and returns formatted output. Output rendering supports tables, colored text, and ASCII art.

Tab Completion

The tab completion engine indexes:

  1. All available command names
  2. Directories/files in the current path (from the virtual FS)
  3. Command-specific parameter names

Pressing Tab cycles through matches. Pressing it again cycles to the next match (PowerShell-style).

Output Rendering

Terminal output isn’t plain text — it’s HTML rendered to look like PowerShell output. This means we can do colored text, tables with alignment, clickable links, and even inline ASCII art, all while maintaining the terminal aesthetic.


The Design System

The design system ensures visual consistency across Jekyll pages, the Next.js desktop, and all interactive features.

CSS Custom Properties

Everything starts with CSS variables defined in :root:

:root {
  --dark-bg: #161B33;
  --section-bg: #1c2948;
  --card-bg: #22305a;
  --fg: #e4e6eb;
  --muted: #8a9bb8;
  --accent: #00aaff;
  --btn-bg: #00aaff;
  --footer-bg: #0f1724;
}

These tokens are shared across every CSS file on the site. When I want to adjust the accent color or background, it’s a single-line change that propagates everywhere.

Typography

The site uses two font families:

  • Orbitron (Google Fonts): For headings, navigation, buttons — gives the “cyber” feel
  • Segoe UI (system): For body text, ensuring readability

The hierarchy is:

  • h1: 2.5–3rem Orbitron
  • h2: 1.8–2rem Orbitron, accent color, bottom border
  • h3: 1.5rem Orbitron
  • Body: 1rem Segoe UI, 1.8 line-height

Component Library

Key reusable components include:

  • Cards (.blog-card, .sidebar-widget): Consistent rounded corners, shadows, hover effects
  • Tags (.blog-tag, .tag-cloud-item): Pill-shaped with hover state transitions
  • Buttons: Accent-colored with glow hover effects
  • Navigation: Sticky header with backdrop blur

Accessibility

The design system follows WCAG 2.1 AA standards:

  • Color contrast ratios are 4.5:1+ for body text
  • Interactive elements have visible focus indicators
  • All images have alt text
  • Semantic HTML structure throughout
  • Keyboard navigable menus and interactive elements

Lessons Learned

1. Start Simple, Then Layer Complexity

The site started as a single index.html. The blog was added next, then the terminal, then the desktop. Each layer was built on a stable foundation. If I’d tried to build everything at once, I’d still be in development.

2. Don’t Over-Abstract Early

I resisted the urge to create a shared component library across Jekyll and Next.js. They share CSS variables, but that’s it. Trying to share React components with a static site generator would have been an unnecessary coupling.

3. Performance Is a Feature

Every interactive feature is lazy-loaded. The desktop doesn’t load until you visit /desktop/. The terminal doesn’t load until you visit /terminal/. The main site stays fast because it’s just HTML and CSS.

4. Build for Fun, Document Later

Most of these features started as “what if I could…” experiments. The design system post and this deep dive came after. Building something that excites you first, then documenting it, produces better results than designing a documentation-first architecture.


What’s Next

Upcoming work on mtsaga.net:

  • Interactive Security Labs — In-browser hash cracking, packet analysis, and AD graph visualization tied to blog posts
  • Search & Topic Graph — Full-text search with a D3.js force-directed graph showing how topics connect (already live)
  • Lab Notebook — A lightweight stream of short updates on what I’m testing and building
  • Enhanced Terminal — More commands, piping between commands, and history persistence

If you have questions about any of these systems, feel free to reach out at mt@mtsaga.net.