The Journey
This site is itself an engineering project. Below is how it was actually built — what problem each milestone solved, the applied skillset behind it, and a link to the real commit or code, not a certificate.
Ordered newest → oldest. Every skill tag below was used to ship something you can inspect right now — either live on this site or in the linked commit on GitHub.
- Keyboard Shortcuts Cheat Sheet HUD: Zero-scroll at-a-glance cheat sheet modal bound to
?(Shift+/) featuring 2-column layout for instant page navigation (1–7), theme (0) & date (`) toggles, and master dismiss (Esc). - Web Share API Integration: Native OS share sheet (
navigator.share) with automated clipboard fallback across ATS Resume modal, Command Palette, and CLI. - Dev Terminal History Persistence: Cross-session
localStoragehistory ring buffer (ArrowUp/ArrowDown),Tabautocompletion for commands & subcommands, and developer aliases (ls,whoami,cat,ping,cls,share,history). - Strict CV Standard Alignment: Synchronized ATS Resume Generator with master curriculum vitae standards, dual-column geometry, standard JSON Resume (.json), Markdown (.md), and print-optimized PDF styling.
- Interactive Skill & Domain Radar: 5-axis dynamic canvas competency chart on
about.htmlwith active score nodes and toolstack breakdowns. - Tailored ATS Resume Generator: Recruiter-focused interactive resume builder modal supporting role-based filtering (Master CV, AI/ML, Embedded, Full-Stack) and one-click ATS print/PDF export.
- Interactive Dev Terminal Sandbox: Added
radar,resume,run spark,run gcsbr, andglossaryinteractive commands to#adtTerminal. - PWA v43 Cache Bump: Upgraded Service Worker cache version to
aaradhya-portfolio-v43.
- Synthesized Web Audio Cues: Hardware-accelerated Web Audio API sound synthesizer for interactive UI feedback (clicks, chimes, modal pops) with persistent audio toggle and
Shift+Ashortcut. - Dynamic Reading Time Badges: Client-side word count & reading time calculation engine displaying glassmorphic badges across main content pages.
- Live Result Count & Filter Sync: Real-time filter count status indicators (
Showing N of M) on projects and achievements. - PWA v38 & Automated Verification: Service worker bumped to
aaradhya-portfolio-v38andverify.pyexpanded for site-wide tag balance auditing.
- Spotlight Tour Engine: Interactive step-by-step guided tour traversing all 7 main site pages with hardware-accelerated target highlighting.
- Cross-Page Navigation Sync: Remembers tour progression across page reloads via
localStorage(adt_tour_active/adt_tour_index). - Accessibility & Shortcuts: Full keyboard control (Arrow keys, Escape to close, Shift+T to trigger), mobile swipe dismiss, and
prefers-reduced-motioncompliance.
- Glassmorphism & Gradient Borders: Frosted-glass card finishes with conic-gradient rotating borders on card hovers.
- Typography Hierarchy Upgrade: Preloaded and integrated Playfair Display for elegant hero display headers.
- Interactive Skill Matrix: Animated scroll-triggered skill proficiency bars with gradient fills inside the status card.
- Mobile Bottom Sheet Nav: Upgraded mobile menu drawer to a spring-physics bottom sheet with drag handle & backdrop blur.
- Horizontal Swipe Navigation: Gesture-based swipe left/right page switching with edge indicator toasts.
- PWA v36 Cache Bump: Upgraded Service Worker cache version to
aaradhya-portfolio-v36.
- Staggered Entrance Motion: Cascading staggered animations for cards across Home explore grid, project cards, and achievement grids.
- Typed Hero Subtitle: Character-by-character typewriter animation with a 6-caption random rotation pool.
- Animated Stat Counter: Scroll-triggered count-up animation for portfolio statistics (15+ projects, 4th year, 2 fellowships, 8 roles).
- Enhanced View Transitions: Element-level morphing and circular clip-path theme wipe transition.
- PWA v35 Cache Bump: Upgraded Service Worker cache version to
aaradhya-portfolio-v35.
- iOS Safe Area Insets: Added
viewport-fit=coveracross all 10 site HTML pages and updated CSS withenv(safe-area-inset-*)rules for fixed navigation bars, mobile drawer, floating widgets, and footer. - Touch Gesture Controls: Implemented vertical swipe-down dismiss gestures for lightboxes, search command palette, and release modals, plus horizontal swipe-left close for the mobile navigation drawer.
- Web Haptic Feedback API: Integrated
navigator.vibrate()micro-interactions across theme toggle, button actions, terminal controls, and track filters. - PWA v34 Cache Bump: Upgraded Service Worker cache version to
aaradhya-portfolio-v34for instant asset invalidation.
- Interactive Dev Terminal: Added a retro-futuristic interactive terminal widget (
#adt-terminal) on the Home page with live output handlers for commands likeskills,projects,experience,achievements, andmatrix. - CMDK Quick Filters: Enhanced Command Palette tab filter pills for instant keyboard-first category navigation.
- Cursor Light Trail: Hardware-accelerated mousemove light trail particles with touch and reduced-motion performance guards.
- PWA & Release History Sync: Upgraded Service Worker cache to
aaradhya-portfolio-v33and updated What's New release highlights.
The Problem: As the portfolio expanded into a multi-page progressive web app, reading position tracking was non-uniform and offline state switches went unnotified.
The Solution: Upgraded the Service Worker cache to aaradhya-portfolio-v32 with live network status toasts, introduced a fixed neon reading progress bar (#readProgressBar) optimized via requestAnimationFrame, and added hardware-accelerated 3D perspective card tilt micro-interactions on hover.
- Upgraded service worker cache in
sw.jsand added network online/offline toast notifications. - Integrated scroll reading progress bar across all 10 HTML pages and added card 3D tilt handlers in
script.js.
- Added an interactive "What's New" release notes modal accessible site-wide via Command Palette (
Ctrl+K), site footer link, andShift+Nkeyboard shortcut. - Displays structured major commit highlights with version badges, dates, and direct links to GitHub commit SHAs.
- Persists last viewed version in
localStorageto highlight newly deployed major releases.
- Synchronized achievements track filter state with URL hash (
#track=academic,#track=eca) viahistory.replaceStateand added state restoration on page load. - Added
aria-live="polite"screen reader status region for dynamic filter count announcements. - Upgraded PWA Service Worker cache version to
v31and audited social preview metadata tags (og:image,twitter:card) across all pages.
- Restructured the previously stacked “About / Sign in with Google” info card and “Exclusive Research & Specs” VIP tier card into a responsive two-column grid on index.html, so both gated-access explainers sit at equal visual weight instead of one pushing the other down the page.
- Grid activates at 1000px+ viewport width — below that, both columns stack in their original order. The Master Console section underneath was left untouched, still full-width.
- Verified the
.revealscroll-fade class and[data-access-tier]attribute selectors are structure-agnostic before restructuring, since both cards’ gating and animation logic depends on class/attribute matching, not DOM nesting depth.
- Changed
.nav-linksfromjustify-content: centertoflex-startso the Home/Projects/Achievements/Journey links start right after the ADT logo, instead of centering inside the middle track of the nav’sauto 1fr autogrid. - Confirmed the mobile hamburger-drawer breakpoint hides
.nav-linksentirely (display: none), so the fix is desktop-only and doesn’t touch the drawer layout.
- Grouped every project card on projects.html into three named sections — Projects (highest precedence, renders first), Fuse AIF (fellowship coursework), and Personal Tools & Apps — using
<h2>section headers spanning the full grid width (grid-column: 1/-1) rather than splitting into separate nested grids, so the existing toggle-all, keymap, and scroll-animation JS — all queried against a single flat#projectsGrid details.project-cardlist — needed zero changes. - The BiasAperture card is canonically presented under Projects with dual fellowship and computer vision metadata tags, preserving unique indexing in search while capturing full capstone context.
- Cross-referenced the FuseAIF2026 coursework repo to confirm exact week numbers, then renamed three project cards to match the “Fusemachines Wk N — Topic” title pattern already used by the other fellowship cards: Text-to-SQL Agentic Pipeline → Wk 3, Telco Churn & CLV ML Pipeline → Wk 4, Telco Churn Tree-Based Ensemble Pipeline → Wk 5.
- Propagated the same title changes into the
SEARCH_STATIC_INDEXobject in script.js, so the command-palette search stays consistent with what’s actually rendered on the page instead of surfacing stale titles.
- Split the Gesture-Controlled Self-Balancing Robot card’s body into a 1×2 layout at 900px+ — description list and tags on the left, embedded video on the right — instead of the video stacking full-width beneath the text like every other card.
- Scoped the grid change to a new inner wrapper rather than
.project-card-bodyitself, after confirming the existing single-trackgrid-template-rows: 0fr → 1fropen/close collapse animation on that element would conflict with addinggrid-template-columnsdirectly on the same node.
- Added an Alt+2 shortcut wired to the projects page’s toggle-all button, extending the site’s existing keymap pattern (Alt+4 → achievements, Alt+6 → journey).
- Collapsing all cards via the toggle-all button now scrolls the page to top on all three timeline-style pages — projects, achievements, journey — instead of leaving the viewport wherever the last open card happened to be.
- Replaced the native
<details>element’s instant snap-open/snap-closed toggling with a smooth height transition, using a single-child grid-rows trick (0fr → 1fr) plus a JS-intercepted click that delays removing theopenattribute until the collapse animation finishes. - Opening a card scrolls it into view; closing a card now restores the exact scroll position that was active before the card was opened — true undo, not a re-align to the card’s current top position — captured via
window.scrollYat open-time. - Also rewired the “Expand/Collapse all” button to reuse the same animation helpers instead of toggling
opendirectly and snapping instantly, so the button and per-card clicks share one code path.
- Added an ambient indicator so this timeline reads as a live sequence rather than a static list — a single traveling glow steps through every checkpoint in document order, forever, no pause.
- Went through several shipped-then-replaced iterations first: a per-node rotating arc sweep, then a multi-node trailing "snake," before settling on the simpler model that's actually live now — one card's left-edge accent bar glows at a time, straight loop newest→oldest, with the next card starting its glow mid-fade so consecutive cards crossfade instead of handing off edge-to-edge.
- Timing (0.5s,
cubic-bezier(0.4, 0, 0.2, 1)) was matched to this element's own existing hover-transition values and the site's dominant transition tier, rather than picked arbitrarily.
- Converted the timeline from always-expanded cards to collapsible dropdowns, so scanning the full checkpoint history doesn't mean scrolling past every entry's full detail just to see the sequence.
- Added a color-coded type legend (Security fix, Feature, Bug fix, Infra/CI, Architecture, Repo A, Origin) plus descending serial numbers per node, so each checkpoint's category and place in the sequence are visible before expanding it.
- Added an Alt+6 expand/collapse-all shortcut for scanning the whole history at once, with
aria-expandedkept in sync on every card for screen readers.
- The VIP/Master tier gate only toggled
href/CSS on each project's anchor tag client-side — the real GitHub URL still sat as plaintext in adata-vip-linkattribute for all 13 projects, readable by anyone viewing raw HTML, curling the page, or hitting a search-engine cache, passcode or not. - Moved every project repo URL through the same AES-256-GCM/PBKDF2 pipeline already used for gated page content —
data-payload-link-idreferences now stand in for the rawhref, decrypted at runtime viadecryptHexPayload()only after tier verification passes. - Follow-up pass removed the login vectors that didn't belong on a public tier system in the first place — a UI tab, a keyboard shortcut, and two undocumented trigger sequences — leaving Google Sign-In against an explicit allowlist as the only path to Master tier.
- Built a 3-tier access system (Public / VIP / Master) where locked sections ship zero raw HTML — content is pre-encrypted client-side and only decrypted into memory after a passcode or Google Sign-In check passes, then wiped on logout.
- Key derivation via Web Crypto API PBKDF2 (100,000 iterations, SHA-256) feeding AES-256-GCM; Google Identity Services SDK handles OAuth, with client-side JWT parsing to read email/name/avatar and assign tier.
- The encryption scheme derives its AES key from the tier's own passcode — but Google Sign-In sessions and simulated Master-tier previews weren't consistently passing the correct passcode into the decrypt call, so unlocked content silently failed to decrypt for some auth paths.
- Traced the mismatch to where the decryption key was chosen versus where the tier was actually verified, and rewrote it to derive the key directly from the tier requirement rather than trusting a passed-in value.
- Admin widget that lets me add or remove VIP-tier emails at runtime, no redeploy — persisted to
localStorageand immediately re-checked against every gated block on the page. - Also ships stealth mode: the Master tab and diagnostic console are fully hidden from public visitors (no DOM giveaway of their existence) and only reveal via an authenticated session or a deliberate secret trigger.
- Global search was going stale — a new certificate added to the achievements page wouldn't show up in search anywhere except that page itself, until someone remembered to hand-export the index.
- Wrote a Python/BeautifulSoup script that parses
achievements.html/projects.htmland regenerates the static index automatically, then wired it into a GitHub Actions workflow that runs on every push — including a bot-loop guard and rebase-retry logic to survive concurrent CI writes to the same branch.
- Press
/anywhere on the site to open a unified search across every page, project, and achievement — with type-filter tabs, keyboard-only navigation (arrows + enter), and deep-linking straight to the matched item. - Runs on a merged index: a static snapshot ships on every page (so search works even where there's nothing to scan live), overridden by a live DOM scan on the pages that actually render the content — so same-session edits are searchable before a commit even happens.
- Wired the contact form to send real email without a backend — client-side EmailJS integration so a message actually lands in my inbox rather than going nowhere.
- Validation followed a few weeks later: a regex-anchored email pattern plus per-field required checks, each with a focused input and an inline status message rather than a silent block on submit.
- Nepal runs on the Bikram Sambat calendar day-to-day, so the homepage's hero date toggles between B.S. and A.D. on click or backtick. Ported a BS↔AD conversion table (years 1975–2099 BS) and cross-checked it against a live converter before shipping — this is a genuine calendar-math implementation, not a library call.
- Migrated from a single-page site to six pages sharing one navigation, footer, and JS bundle — nav/footer render from a single source of truth so a link change only happens once, not six times.
- Added structured data (schema.org breadcrumbs and credentials), full OG/Twitter meta per page, a generated
sitemap.xml, and a custom 404 with redirect-to-canonical handling.
- This portfolio didn't start as six pages — it was forked from a single-page CV site (
AaradhyaDTmr.github.io, Repo A) at the point above, and I've kept that original site live and independently maintained since. - Its "last updated" status was calling the unauthenticated
api.github.comcommits endpoint client-side, which hit GitHub's 60 req/hr rate limit during active development and silently showed "unavailable." Ported this repo's own CI pattern across: a new GitHub Actions workflow stamps the triggering commit into a static JSON file on every push, read same-origin instead — with the same bot-loop guard and least-privilegecontents: writescoping as the search-index pipeline above.
- Deferred Google Analytics to an async-injected script instead of a render-blocking tag, added
preconnect/preload-as-style for fonts, and moved layout-dependent JS reads ontorequestAnimationFrameso they don't fight first paint. - Backed by a documented Lighthouse audit on Repo A: 98 Performance / 100 Accessibility / 100 Best Practices / 100 SEO on desktop (78 mobile — EmailJS's third-party script is the flagged, irreducible cost).
- Before the fork, on the original single-page site: added a "Last Updated" status field that fetches the file's most recent commit straight from
api.github.comand renders it client-side — graceful fallback to "Last commit unavailable" on failure rather than a broken UI. - This is the exact code path that later hit GitHub's rate limit during active development — the fix for it is the CI-resilience card above. Same repo, same feature, two commits apart in spirit if not in time.
- Hardened the same day: wrapped the fetch in an
AbortControllerwith a 3-second timeout, so a slow or hanging API call degrades to the fallback message instead of leaving the status field stuck on "Loading…" indefinitely.
- The scroll-progress bar and section-transition animations were built on
clip-path, which most browsers can't hand off to the compositor — every frame was re-triggering paint. Rewrote both ontotransform: translateX()withwill-change: transform, which is compositor-only and doesn't touch layout or paint at all. - Same commit added a
<link rel="preload" as="image">for the hero photo — it's the page's LCP element, so it should stop waiting on the parser to discover it — and finished deferring GA4's script tag to a non-blocking load.
- Switched web-font loading to preload-as-style with a print-media
onloadswap, so fonts load async instead of blocking render — then added@font-facefallbacks (Georgia, Courier New, Arial) with per-fontsize-adjustpercentages tuned to match each web font's actual metrics. - That second part is the one people skip: without matching x-height and character width up front, the fallback-to-webfont swap still shifts every line on the page. Sized correctly, the swap is invisible instead of a layout jump.
- Wired up Google Analytics 4 with custom
gtag('event', …)calls on the CV-download button and both contact-form backends tried at the time (EmailJS, then Formspree) — not just a pageview pixel, but funnel data on the two actions that actually matter on a CV site.
- Added a "Skip to main content" link, wrapped the page in proper landmarks (
nav/main/footerwitharia-labeloraria-labelledbyon every section), and gave the mobile hamburger menu real state —aria-expandedandaria-controlsflip correctly as it opens and closes. - Replaced blanket
:focusoutlines with:focus-visible, so keyboard users still get a visible ring while mouse clicks don't leave one behind — plus explicitaria-labels on every icon-only or ambiguous call-to-action.