Most developer portfolios are digital business cards designed to pass an ATS scan. A Next.js template, some placeholder copy, a Vercel deployment. It's efficient. It's also pretty boring. I wanted a site that is itself an engineering project: proof of how I approach architecture and security, not a claim that I can write code.
If you're a developer planning your own build, or a recruiter checking my claims: this is the technical breakdown. No hand-waving, failures included.

The Templated Identity Crisis
Why does every portfolio in a computer science department look exactly the same??
During my first year, I noticed a sea of identical templates. They look polished and deploy in minutes, but they say nothing about the person who supposedly built them. As someone focused on backend systems and security, a landing page is not my natural habitat. The shell is.
The first iteration of this site was a modified Hugo template. It felt like wearing someone else's clothes. I decided to rebuild from scratch with three hard constraints:
- Zero UI libraries. No Radix, no Shadcn, no component libraries. Every element is built from raw HTML and CSS.
- Terminal-first. The site must be navigable via a keyboard-driven terminal overlay.
- Proof of work. Every feature must solve a real engineering problem. (Decorative features that only exist to look good are a waste of everyone's time.)
The Architecture of Tokens
React 19, TypeScript, and Vite form the framework layer. That's all.
I avoided CSS-in-JS and Tailwind in favor of CSS Custom Properties. Everything is driven by design tokens defined in a single authoritative stylesheet: index.css.
(I spent two hours debugging why a logo appeared black before realizing the token was defined in a file I never imported. Lesson in source-of-truth management: learned, slowly.)
Every component references these tokens. When the theme flips, everything updates. No conditional rendering, no React state for colors, no class toggling on forty different elements.
:root {
--bg: #111113;
--text: #f0eee8;
--mint: #a8d8c8;
--lavender: #c4b5e8;
--peach: #f4b8a4;
--sky: #9ec8e8;
}
[data-theme="light"] {
--bg: #f0eee8;
--text: #1a1a1f;
/* ... overrides cascade automatically */
}

The theme toggle uses a radial clip-path wipe that originates from the button's position. It's thirty lines of code that make the transition feel deliberate instead of jarring.
The Terminal Interpreter
The terminal isn't a styled text area. It's a structured command interpreter with a typed pipeline, history management, and SPA navigation support.
(It is also the most-used feature on the site, so the keyboard-first bet paid off.)
Every command handler returns a ProcessResult. I used a template literal type, NAVIGATE:${string}, to trigger SPA navigation. It allowed me to keep the result type as a flat primitive union without refactoring twenty files. Pretty elegant, for a fix that dodged an architecture mess.
type ProcessResult =
| TerminalLine[]
| 'EXIT'
| 'CLEAR'
| `NAVIGATE:${string}`
| Promise<TerminalLine[]>;
// In the navigation handler:
if (typeof result === 'string' && result.startsWith('NAVIGATE:')) {
onExit();
onNavigate(result.slice('NAVIGATE:'.length));
return;
}
The system understands argument context. If you type projects --details and hit Tab, it cycles through project IDs. It is some sort of command registry where every handler returns a typed result.

Client-Side Resume Generation
Most portfolios host a static PDF on a cloud bucket. This creates drift. You update a job title on the site but forget to re-export the resume.
I eliminated this by generating the PDF entirely in the browser using @react-pdf/renderer. The data is pulled from the same TypeScript files that drive the UI. When you click download, the engine lazy-loads, renders the document in memory, and triggers the browser download. No server required.
const handleDownload = async () => {
const [{ pdf }, { ResumePDFDoc }] = await Promise.all([
import('@react-pdf/renderer'),
import('./ResumePDF'),
]);
const blob = await pdf(React.createElement(ResumePDFDoc)).toBlob();
// ... trigger download logic
};
The resume and the website are always in sync. Update a job title in one file, and both the UI and the downloadable PDF reflect it immediately. (Anything else is just a maintenance liability waiting to happen.)
Security Hardening
Security is often an afterthought in frontend development. That is a pretty dangerous assumption.
The project detail page renders GitHub READMEs using react-markdown. The initial implementation used rehype-raw to parse embedded HTML. This was a vulnerability?? Yes. GitHub READMEs are not trusted content. An attacker could inject a malicious script into a README and it would execute on my domain. I removed the plugin entirely. Standard Markdown is sufficient. The rest is just an attack vector.
I also implemented a strict Content Security Policy. No inline scripts are allowed. Even if an XSS payload slips through, the browser will block execution. That's defense-in-depth.
default-src 'self';
script-src 'self';
style-src 'self' 'unsafe-inline' https://fonts.googleapis.com;
font-src 'self' https://fonts.gstatic.com;
img-src 'self' data: https://raw.githubusercontent.com;
connect-src 'self' https://raw.githubusercontent.com https://api.github.com;
(I also wrapped every instance of dangerouslySetInnerHTML in DOMPurify.sanitize() just in case. If the data files are ever compromised, the blast radius is limited.)

Performance & Production Polish
Fast is a feature, not a number you check at the end. Every scroll-reveal animation runs off IntersectionObserver, so nothing animates until it enters the viewport.
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
// Trigger animation logic
}
});
}, { threshold: 0.12, rootMargin: '0px 0px -10% 0px' });
Vite's manualChunks config splits the framework code into a react-vendor chunk, so it caches independently of application code. The site loads like a static document and behaves like an app.
The Engineering Conclusion
A portfolio should be proof of how you think, not a list of skills. This one is mine.
Standard CSS turned out to be more than enough for modern layout. Shipping beats perfection. (I deleted three days of work on a glitch effect because it compromised readability.)
The code should do the talking. Is your site an engineering project, or is it just a template??
I am a CSE student who builds backend systems and cares about how they break.
