Skip to main content
Back to the garden
·🌿 10 min · Medium read

Why my portfolio has a Garden OS mode

Most developer portfolios are a hero, three project cards, and a contact link. I wanted to ask: what if the portfolio itself was a small product? Here is why I built a fake operating system on top of mine, and the three engineering decisions worth defending.

Garden OSDesignCareerPortfolio

Why a portfolio needs an OS mode

Most developer portfolios are a hero, three project cards, an about paragraph, and a contact link. That format works. It also disappears into the average within ten seconds of landing on the page.

When I rebuilt my portfolio this spring, I asked a different question: what would it feel like if the portfolio itself was a product? Not a brochure. Not a CV. A product the visitor can poke at and discover things in.

The answer is what I now call Garden OS — a hidden second mode of the same site that turns the page into a fake desktop operating system. Same content, different envelope.

The two-mode trick

The site has two top-level experiences, switchable from the nav or the Display Options panel:

  • Website mode — what you'd expect. Linear pages, garden illustrations, Fraunces serif headlines.
  • Garden OS mode — a 1990s-meets-modern OS chrome. Menu bar at the top, draggable windows with macOS traffic-light controls, a desktop wallpaper, snap-to-edge tiling, and a desktop pet that wilts if you don't visit.

Both modes render the same routes internally. About page is About page; project case studies are project case studies. The only thing that changes is the chrome. In OS mode, opening "About" opens a draggable window that loads /about inside an iframe. The window remembers its position via react-rnd. The traffic lights work: red closes, yellow minimises (the window stays mounted so iframe state is preserved), green maximises.

This means all my content stays SEO-friendly. Search engines crawl the regular routes. Visitors who want a portfolio that feels like a small game get one. Visitors who want a portfolio that feels like a portfolio get one. No fork, no duplication.

Three engineering decisions worth defending

Why iframes for the OS-mode windows

The obvious alternative is to render the page content inline inside each window component — call the same React tree twice with different layout. I rejected that because:

  1. The OS chrome is not a layout primitive. It's a container metaphor. The window has its own scroll, its own focus, its own "tab" that should feel separate from the page hosting it.
  2. Iframes get window scope isolation for free. Click into a window's /projects iframe → focus stays in that iframe → keyboard shortcuts for back/forward navigate inside it without nuking the OS state.
  3. Routing-as-iframe means the same /projects/tricomhub URL works in both modes. Bookmarking inside Garden OS mode just opens the route directly in website mode (because the iframe target is the real route).

The trade-off is real: an iframe means a second React mount per window, which is more memory than a single-tree shared render. For a portfolio with at most 5 windows open at once, that's a non-issue.

Why CSS Modules instead of Tailwind

The earlier Once UI scaffold I wiped used Tailwind utility classes everywhere. The Garden OS rebuild went CSS Modules + CSS custom properties. Two reasons:

  1. The OS chrome has very specific custom geometry — traffic lights, glassmorphism panels, snap-preview rectangles, drag-handle chevrons. Half my CSS is bespoke. Authoring those as one-off utility classes inside a className string makes them harder to read than a focused .windowTitleBar { … } rule.
  2. Theme variables travel cleanly across modes. Both website mode and OS mode read the same --color-accent (garden emerald, #00c781). Themes can mutate at runtime via data-theme="dark" on <html> without touching component code.

Tailwind is great for speed; for a site whose entire identity is its look, paying upfront for ownership of the CSS pays back fast.

Why the menubar clock reads the real time

The menu bar in Garden OS shows a live clock, battery, wifi, and cellular indicator — all driven by real browser APIs (Date, navigator.getBattery(), navigator.connection, navigator.onLine).

The temptation was to fake them. A static "12:34 PM" + a hardcoded battery icon would have been a fraction of the code. Fake instruments are the uncanny valley of UI: as soon as you notice they're fake, the whole metaphor breaks. So the clock ticks every second, the battery percentage matches your actual device, and the wifi indicator goes red when you go offline.

Trade-off: my battery code has to handle browsers (Safari) that don't expose getBattery(). Falls back to a 0.85 mock with a comment. That's the price of consistency.

What surprised me

How much of "feeling native" was the animation transitions, not the static rendering. Early versions had perfect window chrome but the open / close / minimise transitions were instant — the whole thing felt jarringly snappy in a way that reads as broken on a desktop OS.

I burned a full session debugging window-drag jitter that turned out to be Framer Motion fighting with react-rnd's transforms. The fix was separating the concerns: opacity-only Framer for entry/exit, CSS class transitions for minimise, no transforms on the wrapper. Once I stopped trying to do everything with one tool, the animations became buttery — and the OS mode finally read as a real OS instead of a costume.

Should you build one for your portfolio?

Probably not. The Garden OS metaphor only earns its keep because this site is also where I keep my digital garden — the long-form notes you're reading right now. The "OS hosts apps" mental model fits a site that hosts both my projects and my writing. For a static freelance brochure, two pages and a CTA still beats a clever idea.

If your portfolio is also where you experiment, where you cultivate, where the tool is the message — then yes, an OS mode is one of the most fun things you can build, and it'll teach you more about animation, state isolation, and visual metaphor than any tutorial.


The Garden OS mode lives under src/components/GardenOS/. The design system is documented under .ai/design-guide/.