Back to Portfolio
The home page: the eyebrow "Multidisciplinary creative", the name "Bill Kirtsos" in large condensed capitals and the line "I make things people use, watch, hear, and play.", a slider on the right showing "Code" and "Websites, web apps, and games." above six dots, and below them a wide, darkened photograph of Bill Kirtsos in glasses and a flat cap, chin on his hand, with drums and guitars behind him, a terracotta "See my work" button, an outlined "Get in touch" button and the note "Open to work and relocation".
Open bill.savage.design in a new tab

Personal Portfolio — Explorable Project Map

Overview

I rebuilt my portfolio from the ground up. The old site was a dark neo-brutalist page running a Tailwind CDN script over a JSON grid; this one is a static Astro 5 build with React islands only where interaction demands them. The centrepiece is the work page — a map-style board where 36 projects sit in five territories, one per discipline. The wheel zooms at the cursor, dragging pans with momentum, two fingers pinch, and the filter chips fly the view to a category and dim the rest. Zoom in and pins resolve into cards. Every node is a real link, so each project also builds as its own static page that opens with its dialog already on screen. The home page is a sequence of scroll-driven sections: a pinned hero with a six-slide carousel, an about section whose paragraphs fill letter by letter while an image stack accumulates, a fisheye quick-facts reel, an accordion of skills, and a project reel whose track scrubs sideways as you scroll down — on phones as well as desktops. All content lives in one JSON file. There is no CMS, no database and no server runtime.

Challenges

An explorable map is easy to make disorienting and easy to make inaccessible. It also had to stay a static build — no server — while giving 36 projects real, shareable URLs, and the motion had to hold up on a phone.

Solutions

Every map node is an anchor to a page generated at build time, so the board stays navigable, shareable and crawlable with JavaScript off. Level of detail swaps pins for cards as you zoom, and the filter chips fly the view instead of reloading it. Sections are pinned with GSAP ScrollTrigger and scrubbed by scroll position rather than by a ticker, which keeps them honest on touch devices. The whole site ships as static HTML from Astro, with React mounted on the single component that actually needs it.