A raw breakdown of every decision, every tool, every sleepless iteration that went into building portfolio.vajracognixia.in — from blank file to live production.
Most students build portfolios with templates — drag, drop, publish. I wanted something that proves itself by existing. If I claim to build real things, my portfolio should be a real thing.
The constraint: zero templates, zero frameworks, zero shortcuts. Every pixel, every animation, every API call — hand-written. The portfolio is the project.
As a B.Tech CSE student at LPU and national-level handball player, I wanted both identities to come through. Technical precision of a developer, competitive drive of an athlete.
Started with rough pencil sketches on paper. Decided on a dark monochrome palette — #060d1a background, orange as the only accent, Bebas Neue for display punch. The rule: if it doesn't feel sharp, cut it. Took three complete redesigns before anything felt right.
Semantic skeleton first. Proper landmarks, headings, accessibility. CSS custom properties set up before a single component was built.
No frameworks. Pure CSS — grid, flexbox, keyframe animations, glassmorphism, scroll-snap, noise overlay. Every hover state was a deliberate micro-decision.
IntersectionObserver, GitHub REST API, Web Speech API, EmailJS — all vanilla JS. No React, no Vue. Each feature had to justify its bytes.
Firestore for contact messages. AI assistant via Claude API. Firebase Hosting for custom domain + free SSL — production-grade at zero cost.
Deployed. Shared. Got feedback. Fixed mobile. Added certifications, gallery, testimonials. A portfolio is never finished — it grows with you.
// Live GitHub repo fetcher — runs on page load async function fetchRepos() { const base = 'https://api.github.com/users'; const user = 'Devanshu-Dhyanu'; const res = await fetch(`${base}/${user}/repos?sort=pushed`); const repos = await res.json(); repos.slice(0, 6).forEach(repo => { const card = createCard(repo.name, repo.pushed_at); document.querySelector('#repo-grid').appendChild(card); }); } fetchRepos();
// IntersectionObserver for scroll-triggered reveals const observer = new IntersectionObserver( (entries) => { entries.forEach(entry => { if (entry.isIntersecting) { entry.target.classList.add('visible'); observer.unobserve(entry.target); } }); }, { threshold: 0.15 } ); document.querySelectorAll('.reveal') .forEach(el => observer.observe(el));
// Web Speech API — no library, zero cost function playAudioResume() { const synth = window.speechSynthesis; const text = `Hi, I'm Devanshu Dhyanu — Full Stack Developer at LPU. I build real products, not assignments.`; const utt = new SpeechSynthesisUtterance(text); utt.rate = 0.95; utt.pitch = 1.0; synth.speak(utt); }
{
"hosting": {
"public": ".",
"ignore": ["firebase.json", ".firebaserc"],
"headers": [{
"source": "**/*.@(js|css)",
"headers": [{
"key": "Cache-Control",
"value": "max-age=604800"
}]
}]
}
}
Jumping straight to HTML without a visual plan wastes hours. Even rough paper sketches save massive refactoring later.
Setting up :root variables for everything upfront meant I could retheme the entire site in minutes.
No React, no Vue. Modern Web APIs — IntersectionObserver, SpeechSynthesis, Fetch — cover nearly every portfolio need natively.
Built desktop first, paid the price with hours of broken breakpoints. Mobile first from day one next time — non-negotiable.
Uncompressed images tanked load time. Compressing to WebP and adding lazy loading made a measurable, visible difference.
Waiting for perfect means never launching. Put it live, get real feedback, iterate fast. Done is better than perfect — always.
The portfolio is live, production-ready, and constantly evolving. Come see what it became.