Case study
berktan.dev
This site. Built to survive a thirty second skim and to hold up when someone opens the source.
- Role
- Design and engineering
- Period
- 2026
Context
A portfolio has to do two jobs that pull in opposite directions. It has to be legible to a recruiter who gives it thirty seconds, and it has to survive an engineer opening the source and looking at how it was actually built.
The constraint I set was that every visual decision had to have a reason I could write down, and every performance shortcut had to be one I could defend rather than one I got away with.
What I did
Next.js App Router with React Server Components by default. Every animated piece is an isolated client leaf, which keeps the interactive surface small and leaves most of the page as plain server-rendered markup.
Scroll and pointer input never passes through React state per frame. Motion values drive transforms directly, and the magnetic dock measures item centres with offsetLeft rather than getBoundingClientRect, so a transformed element can never feed its own displacement back into the next calculation.
The preloader is CSS keyframes rather than Framer Motion. It plays while the page hydrates, which is exactly the moment the main thread cannot afford animation driven by requestAnimationFrame.
External data is sanitised where it enters the app rather than where it is rendered. GitHub repository URLs and Spotify album art both pass through one URL guard in the fetch layer, because a repo homepage is free text its owner controls.
The project feed is fetched on the server from the GitHub API and revalidated hourly, so the page stays static while the content stays current.
What changed
Colour tokens, easing curves, duration bands and spring constants are written down rather than improvised, so a change six months from now has something to be consistent with.
Self-hosted on a home server behind a Cloudflare Tunnel, which turned the dependency tree into a real attack surface rather than a formality and forced the security posture to be deliberate.
Built with
- Next.js
- React
- TypeScript
- Tailwind CSS
- Framer Motion
- Cloudflare Tunnel