Table Of Contents
This site doesn’t have a product roadmap. No sprint planning. No backlog grooming. No stakeholders to keep happy. It’s just mine. And that means I get to do whatever I want with it.
This is not a portfolio. It’s a platform diary. A digital garden, but I like digital playground better. I should put it on the homepage now I think of it.
What It Actually Is
Some developer portfolios feel very ‘finished’ — they’re polished and professional, and that’s awesome, but they can sometimes feel a bit static, like a snapshot of a project that’s been put behind glass. I’ve been guilty of that in the past too. But it’s not print design. It’s not “oh, it’s sent to the printer now.” You can change stuff. (for the better or worse.. To each their own and all that—but the point is, it’s alive.)
This one isn’t such a “polished portfolio”.
But the goal is not “making a polished thing”, I purposely want to make it rough and gritty. I’m finding out that’s actually harder.
A portion of the site I at least try to make it smooth and business-y, corporate etc, but this is also where I experiment with features that aren’t 100% production-ready. A place where I probably will switch things around now and then, or just: paint one page blue and the other red, go with entirely different typeface combinations. A spot where I archive things, where I point to interesting things, where I keep notes and later change my mind on those notes .. Where I use features that landed three months ago and still have yellow squares on caniuse. Where I learn by building instead of reading about it. Lofty goals I know, and I basically “just started”
The stack is HTML, CSS, JS, held together with Astro. No Tailwind, no pre-loaded component library, no utility framework. Probably will integrate some Vue, Svelte or React stuff here too since the Astro island architecture easily facilitates it. (I have a demo here where I use a component written in each of those frameworks, on one page, communicating with each other, keeping state and everything.)
I wanted to see how far you can push pure CSS in 2026 before reaching for abstractions. Pretty far, it turns out. (spoiler: I knew that already, you don’t need abstractions)
Pick A Thing and Build Something With It
This is a phrase I’ve stolen from the way real learning happens — the same way route transitions are part of the page experience, and the same way container queries aren’t just a CSS feature, they’re a mental model shift.
You don’t really understand a feature until you’ve built it into something that matters — until you’ve had to debug why it’s not behaving the way you thought it would.
That’s why this site exists. So I can test ideas, push browser features as far as they’ll go, and understand what it really feels like to build with them. Or learn that @function for me may come rather sooner than later to baseline browsers.
The CSS Is The Interesting Part
When I started building this, I made one deliberate decision: I’d write CSS. The real stuff. Especially all the new, powerful things that have been landing in browsers for the past few years and somehow still feel new. This is not a rant “against CSS frameworks” btw. There are definitely good ideas I borrowed from them too.
Over the years I’ve been experimenting with all kinds of these new features in projects or on my codepen account. After a while you know what works, how, and how to implement them best. Colours is a good example. I’ve made so many colour tools it became a running joke amongst colleagues, friends and even family. “playing with colours again” ?
OKLCH colors.
The entire color system is built on OKLCH. Eleven hues, twelve steps each. A perceptually uniform color space that actually behaves predictably — adjust lightness and it looks lighter, not just mathematically lighter. You can’t say that about hex codes.
oklch(0.7 0.18 85) — lightness, chroma, hue. You know what you’re looking at.
color-mix() for everything in between.
Need a surface that’s 3% away from the background? color-mix(in oklch, var(--sys-canvas) 97%, var(--sys-canvas-text) 3%). No more hardcoded halfway values. The mixing happens at runtime, in the right color space.
@scope for the theme system.
The site has a multi-dimensional theming setup. Typography themes on data-typo, color themes on data-colortheme. Scoped with CSS @scope blocks — @scope ([data-typo="editorial"]) and everything inside gets the editorial treatment. No class gymnastics, no specificity battles.
You can stack them. Set one color theme on a section, a different typography theme on another element inside it. They compose freely.
Embracing the Platform, Really
I’m not building on top of the web. I’m building with it — the thing that people like Bramus or Brad (amongst many others, should make a link list - add TODO: make inspiration links list) talk about: let the platform shine, not hide it behind abstractions.
This isn’t XYZ CSS, it’s not utility-first, it’s not a component library. It’s just CSS — modern CSS — being used for things it was designed to do.
You want theming? @scope
You want responsive components? Container queries
You want controlled transitions between states? View Transitions API
You want scroll-based interactivity? animation-timeline
You want state-aware styles without JavaScript? :has()
These aren’t gimmicks — they are the platform doing what it’s meant to do.
Container queries instead of media queries.
For layouts: move away from @media and use container queries instead (still work to do, the habit is strong). The components respond to their container, not the viewport. This is the right mental model. A component shouldn’t care how wide the browser window is — it should adapt to whatever space it’s given.
View transitions between pages.
Those morphing animations when you navigate — blog post images sliding from the listing to the detail page — that’s the View Transitions API. The nav stays anchored. The content transitions. The whole thing feels native.
One of those features where you add it once and then wonder how everything else feels so jarring.
Scroll-driven animations.
The fade-in effect on a few sections use animation-timeline: view() with animation-range. No JavaScript. No IntersectionObserver. Just CSS telling the browser: start this animation when the element enters the viewport, finish it 30% through.
The reading progress indicator (WIP) on blog posts uses animation-timeline: scroll(). One line. No scroll event listener, no requestAnimationFrame.
:has() for state-aware styling.
More useful than I expected. Checkbox focus rings, form states, toggling light/dark scheme based on a radio input’s checked state — all CSS, no JS wiring needed.
calc-size() and interpolate-size.
The <details> elements on the site animate open and closed smoothly. That used to require a JavaScript height hack. Now interpolate-size: allow-keywords on :root and calc-size(auto, size) on the element handles it natively.
It’s brand new. Barely any green on caniuse. I used it anyway. Progressive enhancement baby, some browsers do it nicely, others just resort to the open and close we already had. Some browsers animate smoothly, others fall back gracefully.
@starting-style for entrance animations.
Elements that animate in on first render — no JavaScript, no class toggling on a timeout. Just @starting-style telling the browser where to start the transition from when the element first appears in the DOM.
text-wrap: balance and text-wrap: pretty.
Headings get text-wrap: balance. Paragraphs get text-wrap: pretty. Two lines that fix orphaned words and jagged headline wrapping site-wide. The kind of invisible polish that you only notice when it’s missing.
The Tools Section
I’ve been building CSS toys, small experiments and concept proofs on CodePen for years.
Little experiments. Things that were too useful to stay as a pen but not quite a product.
So I started migrating some of them here. Other stuff I found out and implemented in this site too. There’s lots more. A digital playground is nice but at this point it feels a bit like a digital shed. Some cleanup is definitely needed.
They live under /projects. More are coming.
Where The Ideas Come From
Inspiration Is Everywhere — Not Just Online
For me, ideas don’t really come from reading technical specs or dry documentation—they come from just… looking.
Part of that is digital, obviously. I’ve got this curated ecosystem of RSS feeds, newsletters, and deep-dive technical essays that actually go beyond the hype. But honestly? A huge chunk of it comes from everyday life. I’ll be in the supermarket and see a bottle label with perfect typographic rhythm, or I’ll spot a random poster taped to a telephone pole—I’ve even found myself staring at the way the letters sit together on a cereal box. And yeah, in all those cases, I’m totally that weirdo stopping in the middle of the street to take a photo of it. Good design doesn’t just live in digital spaces, you know?
As for where I actually keep all this stuff, my Pinterest has basically become a visual bookmark system that got a bit out of hand. I have boards for typography experiments and UI details I want to reverse-engineer—I’ve even saved recipes before just because the color combinations were so good.
I’m also a big fan of those long-form articles that go deep on a specific use-case or idea instead of just summarizing the docs. It’s great seeing actual people sharing their knowledge, whether they’re well-known or just some dev writing an explainer on their own blog. You’ve got the staples like Smashing Magazine and CSS-Tricks, obviously, but they’re certainly not the only ones I’m reading.
When I want to see what people are actually building, I’m usually on CodePen. Their weekly Spark newsletter is consistently good, and I find their Challenges are a really useful forcing function when I want to try out a specific bit of code. Then there’s YouTube for the deep dives—everything from math discoveries and new JS syntax to Fireship when I need a quick explainer on something I haven’t touched yet.
The stimulus for great UI is anything that catches your eye and makes you think:
“Wait — how did they do that?”
That curiosity — that’s the real foundation.
It’s less about a single spark and more about just keeping the engine running, if that makes sense. Keep your eyes open.
Or that time when my girlfriend complained she couldn’t find a decent website where she could just print a planning calendar.
Living On The Edge
I visit caniuse.com (opens in a new tab) a lot.
Not to check if something is supported enough to use — but to see how close it is to being everywhere.
I’m one person, building for myself. If something works in the latest two versions of Chrome, Firefox, and Safari, that’s enough for this site. The people visiting developer portfolios usually keep their browsers updated.
For a more structured signal, I use web.dev/baseline (opens in a new tab).
Baseline Newly Available means it just landed in all major engines. Baseline Widely Available means it’s been stable for at least 30 months.
I use both.
interpolate-size — Newly Available. Used it.
@scope — Newly Available. Used it.
calc-size() — Newly Available. Used it.
View Transitions — Widely Available (almost). Used it.
Some things still have a red square. I use those too, on experiments where the fallback is just… less fancy. That’s okay.
The Point of All This
This site is not about demonstrating proficiency. But it is. It’s about understanding the platform by engaging with it. Thinking of an idea and making it happen. The round circle with the logos swirling around my head is a perfect example of it.
It’s about:
-
Building to understand
-
Using real browser features
-
Letting the platform be expressive
-
Embracing capability instead of simulating it
Learn by doing, learn by failing, learn by fixing. The web moves fast. There’s always something new. It can feel overwhelming if you’re trying to read your way through it all.
My approach: pick one thing at a time, and build something with it.
You don’t really understand @scope until you’ve tried to abuse it.
You don’t really get scroll-driven animations until you’ve debugged why yours aren’t firing.
You don’t really understand OKLCH until you start generating a palette and realize the same chroma value behaves wildly different across hues — that 0.18 on blue doesn’t feel anything like 0.18 on yellow — and then you adjust lightness and everything shifts again. That’s the moment it stops being “a color format” and turns into a proper head-scratcher.
This site is where that learning happens. (Bear with me ;) I promise to share these adventures)
It doesn’t have to scale. It doesn’t need to pass an enterprise accessibility audit (actually it does. For myself). It needs to work, but it may even occasionally break here or there as long as it does not “actually break”, and teach me something.
That’s enough.