Design & Build · 2026
Personal Portfolio
I rebuilt this site three times before it felt right. Along the way I made it twenty times smaller and found a bug that made the entire page vanish.
- Role
- Design & build
- Timeline
- 2026
- Built with
- HTML · CSS · JavaScript
- Live
- keithnicolosi.com
Three tries to get it right
My first portfolio looked like a hacker movie. Neon green text on black, fake scanlines like an old monitor, a blinking cursor, and a pretend terminal that typed out my name when the page loaded. I was pretty happy with it.
The problem was what it said about me before anyone read a word. It looked like someone who thinks coding is cool, which is true, but it isn't the point. I wanted it to look like someone who makes deliberate choices and can explain why. Those are different impressions, and the second one is much harder to fake.
The second attempt went the other way entirely: cream background, elegant serif headlines, lots of white space. It was probably the best-looking of the three and I scrapped it too. It read like a magazine article about me rather than something built by me: polished, but it could have belonged to anyone.
The third one is this. Knowing what to throw away turned out to be most of the work.
Building it by hand
Most sites today are built on top of large toolkits that handle the heavy lifting for you. I didn't use any. This site is a handful of files (a page of structure, a stylesheet, one script, and a folder of images), with a separate page written for each case study. Nothing gets compiled or processed. What I wrote is exactly what your browser receives.
That wasn't stubbornness. A portfolio is something you edit maybe twice a year, usually in a hurry, right before you need it. Every tool you build on top of is one more thing that can stop working while you weren't looking: versions change, things get deprecated, and suddenly you're spending an evening fixing your build instead of updating your site. I wanted something I could open in five years, change one line, and publish.
The trade-off
Doing it by hand takes longer up front and means repeating myself more than I'd like. In return there's nothing between me and the page, and publishing is a single command. For a site this size that's clearly worth it. For something much bigger it wouldn't be, and knowing where that line sits is the actually useful part.
Making it fast
The finished page is about 74 KB, small enough to appear almost instantly, even on a bad connection. It started out roughly twenty times larger, and nearly all of that was one file: my photo.
The original portrait was 1.34 MB. It was also far larger than it needed to be (roughly five times wider than the space it actually appears in) and saved in a format that reserves room for transparent areas, despite the photo having none. It was carrying instructions for transparency that didn't exist.
Resized to fit its actual slot (with enough extra to stay sharp on high-detail screens) and saved in a more efficient modern format, it came out at 15.5 KB, about 87 times smaller, with no visible difference. An older-format copy sits alongside it for browsers that need one.
The bug that made everything disappear
Sections on this site fade in as you scroll to them. The standard way to build that is to start each section invisible, then have the browser tell you when it scrolls into view so you can fade it in.
There's a trap in that, and it's a bad one: if the "it's now visible" message never arrives, the content never comes back. The page doesn't partially break or look wrong; it renders completely blank. All the text is sitting right there, just permanently invisible.
I hit this for real while testing. In one situation the browser simply never sent those notifications, and the entire site was an empty screen. Everything was technically working; you just couldn't see any of it.
The fix
The first screen no longer waits to be told anything; it checks its own position directly and shows itself. Everything further down still uses the normal approach, but with a timer watching in the background: if no notifications have arrived within a second and a half, it assumes the system isn't working and reveals everything immediately.
The lesson stuck with me more than the fix did. If you hide something on purpose, you need a guaranteed way to bring it back. Otherwise you haven't added a nice effect; you've put a single point of failure in front of your entire page.
A few design details
The background never repeats
Those slow-moving coloured lights behind the page drift on three different timings that don't line up with each other. If they shared a rhythm you'd eventually notice the pattern restarting, and it would start to feel cheap. Mismatched timings mean it effectively never repeats.
The texture is deliberate
Large, soft colour gradients on a dark background tend to show visible stripes rather than blending smoothly, and you've probably noticed it in photos of a sunset sky. Adding a very faint layer of grain breaks those stripes up, and your eye reads it as texture instead.
The trick is that the grain sits underneath the text rather than over the top of it. Over the top, it makes everything slightly fuzzy. Underneath, the background smooths out and the text stays perfectly sharp.
The panels behave like glass
The cards blur whatever is behind them and catch a bit of light along their top edge. That highlight is doing most of the work; real glass catches light that way, and without it the panels just look like flat grey boxes.
Making it work for everyone
Some people get motion sickness from animation, so if you've told your device you prefer reduced motion, this site turns all of it off: the drifting background, the fade-ins, the glow that follows your cursor. Not some of it, all of it.
There's also a skip link for people navigating by keyboard so they don't have to tab through the menu on every page, clear outlines showing where the keyboard focus currently is, and the cursor glow switches off entirely on phones and tablets, where it means nothing and only costs battery.
What I'd do differently
The styling file is getting long, close to a thousand lines. It's still manageable because it's organised in the same order as the page itself, but it's near the limit of what one file should reasonably hold. I've already split these project pages into their own file, and that's the direction I'd keep going.
The bigger one: I'm writing each of these case study pages by hand, and they're largely the same shape. That's exactly the point where building everything from scratch stops paying off, and the honest answer is that a tool to generate them would now be the right call. Which is the whole reason the no-tools rule was worth trying in the first place: you learn where the limits actually are by walking into them.