kuldeepโœฆ
โ†back to all writing
Mar 2026 ยท 8 min read
deep dive๐Ÿ› ๏ธfrontend physics & window management

Behind MacOS Portfolio: Building a Desktop GUI at 60 FPS in the Browser

Architectural walkthrough of recreating the macOS Sequoia desktop in the browser: GSAP parabolic dock magnification, window collision management, and a Groq-powered Siri AI companion.

Rendering Target

60 FPS Compositor

Interactive Apps

25+ Built-in

AI Companion

Siri (Groq LPU)

Window Engine

GSAP + Zustand

view repository โ†—live demo โ†—#Next.js 16#GSAP 3#Zustand Immer#Tailwind CSS#Groq AI#xterm.js

1. The Audacious Goal: A Real Operating System Experience in the Browser

Most developer portfolios follow a predictable layout: vertical scroll sections with cards and text. I wanted to build something that would challenge the limits of modern browser rendering: a complete macOS Sequoia desktop simulation featuring a realistic boot sequence, an interactive lock screen with session persistence, menu bar controls, a dynamic notch, and 25+ functional applications.

To provide a first-class experience on any device, the system features a dual layout: desktop viewports (>=768px) launch the multi-window desktop with draggable shortcuts and dock magnification, while mobile devices (<768px) seamlessly render an iOS-style home screen with swipeable Control Center and an Assistive Touch quick-action orb.

Building an operating system in the browser requires treating the DOM like a native window compositor.

2. 60 FPS Dock Physics: The Exponential Decay Proximity Curve

The hallmark of macOS is its iconic magnification dock. When the cursor glides across the dock, icons scale smoothly based on proximity. Standard CSS hover pseudo-classes cannot compute neighbor influence in real-time.

In useDock.js, we compute the distance between the cursor and each icon's horizontal center, applying an exponential decay curve to calculate scaling intensity. Transforms are executed via GSAP hardware-accelerated transforms (transform: translate3d and scale), avoiding layout recalculation and paint cycles.

src/module/desktop/dock/hooks/useDock.js
1const animateIcons = (mouseX) => {
2 if (isDockDragging) return;
3 const icons = dock.querySelectorAll(".dock-icon");
4 const { left } = dock.getBoundingClientRect();
5
6 icons.forEach((icon) => {
7 const { left: iconLeft, width } = icon.getBoundingClientRect();
8 const center = iconLeft - left + width / 2;
9 const distance = Math.abs(mouseX - center);
10
11 // Parabolic Gaussian proximity curve
12 const intensity = Math.exp(-(distance ** 2.2) / 12000);
13
14 gsap.to(icon, {
15 scale: 1 + 0.48 * intensity,
16 y: -34 * intensity,
17 duration: 0.24,
18 ease: "power2.out",
19 });
20 });
21};
22
23// Elastic spring reset when cursor leaves dock
24const resetIcons = () => {
25 if (isDockDragging) return;
26 const icons = dock.querySelectorAll(".dock-icon");
27 icons.forEach((icon) =>
28 gsap.to(icon, {
29 scale: 1,
30 y: 0,
31 duration: 0.34,
32 ease: "elastic.out(1, 0.72)",
33 })
34 );
35};

๐Ÿ“Œ Key Engineering Takeaways:

  • โœ“Exponential decay curves provide authentic Apple-like magnification.
  • โœ“Elastic easing curves ensure playful, physics-driven icon recovery.
  • โœ“Purging inline styles during app reordering prevents layout tearing during drag events.

3. Window Management & Dock Collision Detection (windowWrapper.jsx)

Managing multiple overlapping windows requires handling z-index stacking, dragging boundaries, 8-direction resizing, and minimize/maximize animations. We architected a higher-order component (windowWrapper.jsx) paired with a Zustand store enhanced by Immer middleware.

When a window is focused, only its z-index increments (state.nextZIndex++), preventing wasteful re-renders of the entire desktop. When a window is dragged over the dock, checkDockCollision inspects bounding rect overlaps and automatically toggles isDockHiddenByCollision to keep window contents unobstructed.

src/hoc/windowWrapper.jsx
1// Case 3: Window minimizing animation down to dock coordinates
2else if (isOpen && isMinimized && !prevMinimizedRef.current) {
3 lastPosRef.current = {
4 x: gsap.getProperty(el, "x") || 0,
5 y: gsap.getProperty(el, "y") || 0,
6 };
7 const startRect = el.getBoundingClientRect();
8
9 gsap.killTweensOf(el);
10 gsap.to(el, {
11 scale: 0.15,
12 opacity: 0,
13 y: window.innerHeight - 80,
14 x: window.innerWidth / 2 - startRect.width / 2, // animate to bottom dock center
15 duration: 0.35,
16 ease: "power2.inOut",
17 onComplete: () => setShouldRender(false),
18 });
19}
20// Case 4: Window restoring (unminimizing) from dock back to original coordinates
21else if (isOpen && !isMinimized && prevMinimizedRef.current) {
22 gsap.killTweensOf(el);
23 gsap.fromTo(
24 el,
25 { scale: 0.15, opacity: 0, y: window.innerHeight - 80, x: window.innerWidth / 2 - startRect.width / 2 },
26 { scale: 1, opacity: 1, y: lastPosRef.current.y, x: lastPosRef.current.x, duration: 0.38, ease: "back.out(1.1)" }
27 );
28}

4. Voice-Enabled Siri AI Assistant Powered by Groq

A desktop experience wouldn't be complete without Siri. We integrated a multimodal AI assistant capable of speech recognition, conversational intelligence, and text-to-speech feedback.

Incoming audio is transcribed using Groq's high-speed Whisper endpoint (/api/groq/transcribe), then passed to a custom Next.js API route (/api/groq/chat) running llama-3.1-8b-instant. The system prompt equips Siri with contextual awareness of the developer's projects, experience, technical proficiencies, and contact information.

Groq's ultra-low inference latency allows Siri to respond almost instantaneously, mimicking native device assistants.

src/app/api/groq/chat/route.js
1export async function POST(req) {
2 const apiKey = process.env.GROQ_API_KEY;
3 if (!apiKey) {
4 return NextResponse.json({ error: "Groq API Key is missing." }, { status: 500 });
5 }
6
7 const body = await req.json();
8 if (!body.model) {
9 body.model = "llama-3.1-8b-instant";
10 }
11
12 const response = await fetch("https://api.groq.com/openai/v1/chat/completions", {
13 method: "POST",
14 headers: {
15 Authorization: `Bearer ${apiKey}`,
16 "Content-Type": "application/json",
17 },
18 body: JSON.stringify(body),
19 });
20
21 const data = await response.json();
22 return NextResponse.json(data);
23}

5. The 25+ App Ecosystem & Performance Takeaways

To make the desktop feel genuinely alive, we built 25+ interactive applications: an xterm.js terminal emulator with custom commands, dynamic notch with Jamendo music streaming, live weather from wttr.in, OpenStreetMap geolocation, and in-browser PDF resume viewing.

By employing Next.js dynamic code splitting, initial bundle sizes remain under 150kB gzipped. Offloading window coordinates and animations to the GPU compositor thread ensures that even with 5 windows open simultaneously, frame rates never drop below 60 FPS.

๐Ÿ“Œ Key Engineering Takeaways:

  • โœ“Animate purely with transform3d and opacity to keep animations off the main thread.
  • โœ“Zustand with Immer allows surgical state updates without cascading component re-renders.
  • โœ“Pairing voice transcription with Groq LPU inference elevates web portfolios into memorable interactive experiences.

โ€” Kuldeep Rajput โœŒ๏ธ

Software Developer ยท building ambitious full-stack web apps