The real problem was not building a portfolio
The easy version of a portfolio is a neat page with a photograph, a short introduction and a grid of projects. That would have worked, but it would not have felt like me. I wanted the site to carry some of the things I enjoy outside a job description: old computers, science fiction, strange signals, space, hidden details and the pleasure of exploring a system before fully understanding it.
The obvious danger was building something memorable that made the useful information harder to reach. Recruiters often need a credible answer in a minute. Other visitors may want to wander through project histories, technical writing and experiments. Trying to satisfy both groups inside one interface produced an early design that was neither simple nor immersive.
The solution was to stop asking one page to do two opposite jobs. The entrance makes the conflict explicit: choose Reality for the plain record or Illusion for the interactive world. A third Profile view later became the compact professional middle ground. These are not separate identities; they are different reading modes over the same work.
This article is intentionally public-safe. It explains the engineering decisions and lessons without exposing customer data, proprietary prompts, internal identifiers, operational commands or confidential decision thresholds.
- ENTRANCEAsk the visitor how they want to read
- REALITYPlain HTML, direct facts and fast scanning
- PROFILEA concise modern professional overview
- ILLUSIONProjects and writing inside ROY/OS
- CONTENTKeep every view grounded in shared data
From a picture of a desktop to an actual interface
The Illusion side began as a visual idea: a worn retro-future workstation floating somewhere between a personal computer and a spacecraft console. A flat mock-up would have been much easier, but it would also have failed the moment someone tried to use it. The windows therefore had to be real. They can be opened, focused, dragged, resized, minimised, maximised and restored from the taskbar.
Most of the appearance is ordinary HTML and CSS. Borders, title bars, icons, scanlines, shadows, buttons and panels are browser elements rather than pieces baked into one screenshot. React holds the interaction state: which apps are open, their position and size, the focused window, the selected project, the tuned radio frequency and the chosen display theme. A shared window component keeps those behaviours consistent instead of reimplementing them for every app.
That decision made the site more work at the beginning but much easier to extend. Work, Writing, Help, Archive, Radio, NAVCOM, Terminal and CRT Control all feel like parts of the same machine because they use the same small set of interface rules. The wallpaper provides atmosphere; the browser still provides the controls.
The first major challenge: freedom on desktop, constraints on mobile
A draggable desktop assumes space. A phone has almost none. Simply scaling the interface down produced tiny controls, unreachable taskbar items and windows that could open partly outside the viewport. The desktop metaphor had to bend without becoming a separate mobile application.
On smaller screens, CSS changes the geometry: windows use the available viewport, multi-column layouts collapse, the taskbar stays reachable and horizontal indexes become scrollable. The entrance uses separately composed landscape, tablet and phone artwork rather than hoping one crop will work everywhere. Touch targets and native scrolling remain more important than preserving every desktop proportion.
The compromise is intentional. Mobile still looks like ROY/OS, but it behaves more like a sequence of focused panels. The lesson was that responsive design is not shrinking a composition; it is deciding which parts of the metaphor are essential when space disappears.
The second challenge: the same facts kept drifting apart
As the site grew, the same project could appear in Reality, Profile, the Work app and the Writing app. Editing copied text in several components was fast once and expensive forever. Titles, dates and summaries began to risk disagreeing, and adding an article required remembering every place that linked to it.
I moved editable professional content into typed objects under one content directory. Each project file now contains its card and its long-form article together. The shared index supplies every interface, while the article route and sitemap are generated from the article ID. A change to one summary can therefore flow to multiple views without introducing a CMS or database.
This was one of the least visible improvements and one of the most valuable. The website became easier to maintain precisely because less of the presentation knew where the words came from.
const bundle = {
project: { blogId: "making-this-website", /* card */ },
writing: { id: "making-this-website", /* article */ },
};
The third challenge: playful features still obey browser rules
The radio looked like a decorative feature until it had to behave like one. Modern browsers do not allow a website to begin playing audio without a visitor action, so the power control is real rather than theatrical. Closing the radio stops playback; minimising it does not. The visible stations use local ambient audio or small browser-generated synthesiser loops, which avoids depending on a streaming service.
The hidden 100.1 MHz transmission became a useful design test. It ties the tuner, taskbar readout, unlock state and signal-decoder app together, but none of those pieces should block the portfolio itself. The easter egg rewards curiosity while the normal experience remains complete without discovering it.
The same principle shaped the fake terminal and navigation computer. They create the feeling of a larger world, but they never connect to a real shell or pretend to be production tools. The fiction stays safely inside the browser.
The build that worked on my Mac and failed in the cloud
The site uses Next-style routing with Vinext and Vite, then runs through Cloudflare Workers. That kept the runtime small, but it exposed a classic deployment problem: a local macOS and ARM installation is not the same environment as a Linux x64 cloud build.
At one point the dependency setup was narrowed too aggressively to the local architecture. The site built on the development machine while Cloudflare could not find the Linux native binding it needed. The fix was not to delete the lockfile or keep retrying the deployment. It was to remove the Mac-only architecture restriction, keep the dependency tree reproducible and let the cloud install the correct optional package for its platform.
That failure changed the maintenance guide. Runtime versions are now explicit, the lockfile is treated as a contract and the verification flow checks the production build before a release. A green local screen is useful evidence, but it is not proof that another operating system can build the same commit.
Making a strange site legible to ordinary systems
An interactive desktop is a poor surface for search engines, link previews and people who simply want to share one article. Every technical post therefore also has a normal server-rendered URL with its own title, description, canonical link, dates and structured article data. The desktop reader remains the themed experience; the public article page is the durable document.
The site also includes a sitemap, robots instructions, social metadata, a text-first résumé and an llms.txt overview. Accessibility work is less glamorous but equally structural: semantic controls, visible focus, useful alternative text, pressed states for toggles and layouts that remain readable without the decorative effects.
This was the recurring tension throughout the project. The visual concept could be unusual, but navigation, reading and sharing should not require unusual knowledge.
How it was actually made
The website was built iteratively rather than from one perfect design file. I started with the entrance and the two-world idea, implemented the core pages, then repeatedly used the site as a visitor would. Each pass exposed a different class of problem: duplicated content, weak mobile composition, windows that needed clearer state, articles trapped inside the desktop, build assumptions that only held locally and documentation that existed in my head.
AI-assisted development helped with exploration, implementation and review, especially when comparing alternatives or checking a change across many routes. It did not remove the important decisions. I still had to decide what the site was trying to say, reject features that distracted from it, inspect the generated interface and keep claims and project details public-safe.
The final workflow is deliberately boring: edit shared content, run type and lint checks, build the production target, render representative routes, review the diff and then let the main branch deploy through Cloudflare. The imaginative part sits on top of a routine release process.
What I would keep and what I would change
I would keep the central choice. Reality and Illusion give the site a reason to exist beyond collecting links, and the plain route prevents the creative direction from becoming a usability tax. I would also keep the decision to build the interface from real controls. It made responsiveness and accessibility harder, but it preserved the difference between scenery and software.
I would begin with the shared content model earlier. Presentation changed quickly during the first iterations; facts changed more slowly. Separating them from the start would have removed repeated edits and made experiments safer.
The project taught me that personality and maintainability are not opposites. The trick is deciding where each belongs. The outside can be a strange computer in space. Underneath, the content should have one source, controls should behave predictably, tests should catch broken routes and deployment should be boring.