July 15, 2026
Rebuilding tahmid.space: Next.js to Astro, and why theme switching drove the decision
How a portfolio's light/dark sync bugs exposed an architectural truth — and what moving the presentation layer to Astro islands + Aceternity UI actually changed.
- astro
- architecture
- design-systems
My portfolio has been through four designs this year. The last rewrite wasn’t about looks — it was about an architecture bug I kept patching and never fixing.
The bug that wouldn’t die
The Next.js version kept theme state in a React context. The <html> class,
the CSS variables, the three.js scene and the toggle each had their own idea
of “current theme”, synchronized by hand. I fixed a first-paint flash, a
patchwork transition, and a canvas that stayed in the old theme when your
pointer was idle — three real bugs, one root cause: JavaScript owned a
piece of state that belongs to the document.
The structural fix
In the Astro rebuild, theme is a data-theme attribute set by a pre-paint
inline script. Every color on the site is a --sys-* CSS variable that
re-resolves from that attribute. The toggle flips the attribute; nothing
else exists. React islands can’t desync because they hold no theme state
at all.
What Astro islands changed
The page is static HTML with eight small hydration points — the Aceternity
components (navbar, hero effects, timeline, carousels, contact form)
hydrate client:visible, so below-fold JavaScript never competes with
first paint. The trusted-collaborations wall — 36 brand icons — renders as
build-time SVG with a pure CSS marquee: zero JavaScript for the section
people scroll past fastest.
Design tokens, Material-style
The other lesson: utility classes without a scale produce “everything
seems small and inconsistent” (my own words to the AI pair-programming
with me). The fix is a token layer with Material Web’s discipline — color
roles with mandatory on- pairs, a five-step typescale, motion tokens —
documented on a live /design page that re-renders when the
theme flips.
More on the RAG pipelines and the Shopify headless work soon — those posts belong here now that this site finally has a blog it can grow into.