# abchaudary.me

*A React and Bootstrap experiment, rebuilt twice since, around motion, colour theory and one song.*

- Built with: Next.js, React, TypeScript, Payload CMS, PostgreSQL, GSAP, Three.js, Playwright
- Updated: 2026-09-07T20:55:51.639Z
- live: https://abchaudary.me
- repo: https://github.com/abdullahchaudary/portfoliov2

> abchaudary.me: a React and Bootstrap site, then Next.js with a hand-built CMS, now Next.js and Payload, still carrying the original colour and motion ideas.

## What it is

This is the site you are reading. I have rebuilt it twice: a React and Bootstrap start, a Next.js version carrying a CMS I wrote myself, and now Next.js and Payload on Postgres. The stack has changed three times. The ideas underneath it, motion tied to sound and colour treated as physics rather than palette, have not.

## The constraint that started it

The first build was React on Bootstrap, a relic even by the standards of its own year. What made it worth continuing was one decision made early and never walked back: the site should move, not just display. Every rebuild since has been in service of that, not a departure from it.

## Three decisions from the first build that are still here

### Typefaces chosen for love of terminals, not for trend

The search settled on Press Start 2P, a pixel typeface built for old arcade games, next to Source Code Pro, a terminal monospace. Neither is a default choice for a portfolio. Both are exactly the register of someone who spent a lot of time in terminals and a lot of time in retro games, which is the point: the typography is a biographical fact, not a style decision made in isolation.

### Colour, split into red, green and blue on purpose

Behind the white background and the image cards, the animation pulls those three channels apart rather than treating colour as a fixed palette, because red, green and blue are not a design choice, they are the components white light is made of. Splitting them and letting them recombine is the same event, run visibly, that produces the white the rest of the page sits on.

### The whole experience is built around one song

Blackbird Blackbird's "Blurring Lines" scores the intro and the about section, and the Three.js scene was designed against it, not scored afterward. Sound changes how depth and pacing read even when a visitor never notices the track is playing, so the animation was tuned to move with it in a way that stays subliminal rather than illustrative: nothing on screen hits a beat on cue, but the pacing of both was set by the same clock. The [about page](/about) is where that scene still runs.

## Replacing Django with something smaller

The first version's frontend was served as a static build asset out of Django. Django is the right call on backends built to scale and on IoT projects, work I have shipped it on before, where its ORM, admin and auth earn their weight. A single-owner site with one content type does not need any of that, so the second version replaced it with a small CMS built directly into Next.js server functions instead of carrying a framework sized for a much bigger problem.

That CMS was scoped for more than projects, a blog and a photo section were planned into its schema from the start, but neither shipped. Work got busier than the site did, and a project built to be extended sat still instead, for longer than intended.

## Where the Three.js scene came from

It came from a drive home, not a mood board. The same song was playing again, on a stretch of road that goes through a tunnel with a series of turns, and the thought that produced the scene was about space-time: that it is not a fixed backdrop, it wraps around whatever is moving through it, and what passes through leaves an imprint behind rather than disappearing cleanly. That is what the about page tries to show rather than tell.

## What broke in this rebuild

**The loading screen had to run before React existed.** A React component cannot dismiss an overlay quickly, because it cannot do anything until hydration, and hydration is precisely what the overlay is covering for. It is an inline script in the document head instead, counting in raw DOM, finished before the bundle has parsed.

**Music across tabs needed a lease.** Only the first tab plays. Two tabs open means two audio elements racing, so tabs coordinate over `BroadcastChannel` with a `localStorage` heartbeat as the fallback, and a tab that dies releases its claim rather than holding it forever.

**One CSS minifier bug cost a layout.** Lightning CSS merges duplicate `backdrop-filter` declarations and keeps the last, which left only the `-webkit-` form, which Chromium 151 no longer supports. The blur vanished, and with it the containing block it had been silently providing, so a sidebar's absolutely positioned children jumped to the wrong ancestor. The visible symptom was icons in the wrong place, three components away from the cause.

## What this rebuild finished

The blog and the photography section the second version scoped for and never delivered are both [live](/blog) now. Alongside them: Payload CMS on Postgres, 18 architecture decision records, a generated sitemap, Playwright across nine device profiles, and a machine-readable Markdown twin of every route for crawlers that run no JavaScript. The colour separation, the two typefaces and the song from the first version are still here, carried through three rebuilds rather than replaced by any of them.

## Links

Live: [abchaudary.me](https://abchaudary.me).
