← Notes


3 min read

How this portfolio works

A talking intro video, a 3D mini-me you can ask questions out loud, narrated demo videos, and hosting that uses about 70 MB of RAM. Here is what is behind each piece.

A portfolio for an AI engineer should show AI, not just list it. So this site has a few moving parts that are unusual for a personal page. Here's what each one is and how it's built.

The stack

The site is Next.js 15 with the App Router, TypeScript and Tailwind CSS, with Motion for animation and Lenis for smooth scrolling. All of the content (projects, roles, skills, certifications) lives in a single data file. The page, the mascot's knowledge and the AI-crawler summary are all generated from that one file, so they can never disagree with each other.

The talking intro

Press Meet me on the portrait and the photo comes alive and introduces me.

  • The video is lip-synced from my photo with an AI video model, using a clone of my own voice (recorded, then pitched slightly deeper).
  • The background was removed frame by frame with a segmentation model, then encoded as a transparent VP9 WebM, so the video sits on the page exactly where the photo was.
  • Safari doesn't play transparent WebM, so it gets an MP4 blended into the page instead. The swap between photo and video is a crossfade, so you never see a frame change.

The mini-me

The small character walking along the bottom of the screen is a 3D version of me.

  • It started as a single image, became a 3D model, and was then auto-rigged with three animations: wave, walk and idle. All three share one 24-bone skeleton, so they blend into each other smoothly.
  • The models are compressed with meshopt and small WebP textures.
  • three.js loads only when the browser is idle, after the page is already usable, so the character never slows down the first view.
  • It wanders, turns to face you before it waves, and stops when you talk to it.

Asking questions out loud

Click the mini-me and ask it anything about me. It answers in a speech bubble.

  1. Your browser's built-in speech recognition (the Web Speech API, set to Indian English) turns your voice into text, so my server only ever receives the text of your question, never audio.
  2. The question goes to an API route that retrieves the most relevant facts about me from MongoDB using BM25 ranking.
  3. DeepSeek writes a short answer using only those facts. If you ask something off-topic, it answers in one line and steers back to my work.

Because it's a public endpoint that spends money on every call, it has guards: requests must come from this site, there are per-minute and per-day limits for each visitor, prompt-injection attempts are refused before they reach the model, and answers are capped in length.

The demo videos

Each project has a narrated demo. They're built with HyperFrames, which renders video from HTML and CSS, so every title, diagram and animation is code. Narration is generated with a text-to-speech voice, and music is mixed underneath to broadcast loudness. The six videos were rendered in parallel by separate AI agents working from one shared design spec.

Hosting on 70 MB

The site runs on an Oracle Cloud ARM virtual machine that it shares with one of my AI agents.

  • It runs as a systemd service with a hard 2 GB memory cap, so it can never starve the agent next to it. In practice it uses about 70 MB.
  • Caddy handles HTTPS, and Cloudflare sits in front for DNS and caching.
  • A timer pings the database twice a month so the free MongoDB cluster is never paused for inactivity.

Making it fast

The first version of the hero looked great and loaded slowly. On a mid-range phone over 4G, my name took 4.8 seconds to appear, because it was hidden until the animation library loaded.

The fix was to move the hero's entrance animation into plain CSS, which runs the moment the HTML arrives. The intro animation you see on your first visit (the monogram drawing itself) is CSS too, with no network requests. The same measurement now comes in at 1.9 seconds.

These notes

The notes you're reading are stored in MongoDB and rendered with incremental static regeneration: pages are served as static HTML, then refreshed in the background every minute. A new post goes live without a redeploy, and every published post is also added to the mini-me's knowledge, so you can ask it about this one.

If you'd like something like this built for your product, get in touch.

  • Next.js
  • three.js
  • RAG
  • MongoDB
  • web performance

Written by Masum Kabir Biswas, AI/ML Engineer in Kolkata, India. Get in touch