Personal Website

This site, gilang.web.id, is where I write about code, share projects, and keep a small corner of the internet that’s entirely mine. It’s also a project in its own right, so here is the story behind it.

TL;DR

  • What is it: My personal corner of the internet for blogging, sharing my portfolio, and experimenting with modern web architecture.
  • Tech Stack: Astro, TypeScript, Tailwind CSS, Markdown/MDX, Cloudflare Pages & Edge Functions, Google Gemini / OpenAI APIs, Satori (dynamic OG images).
  • Key Features: Content-grounded interactive AI assistant (/chat), dynamic OG social images, zero-overhead static rendering, and costs $0 to host at the Edge.

How it works

The site is built with Astro and renders to static HTML at build time. No client-side framework is required to read a page. Content (blog posts, project write-ups, and page copy like this one) lives in Markdown/MDX files inside a separate content repository, managed through Astro’s content collections with Zod schemas for type safety. That separation means I can edit or add a post without touching any application code.

Styling is done with Tailwind CSS on top of a curated design token system (colors, spacing, type scale) so light and dark mode stay consistent across every page. The layout features a persistent sidebar navigation, a responsive content column, and an accessible typography hierarchy.

Integrated AI Assistant & Build-time RAG

The site includes a dedicated interactive Ask AI assistant (/chat) that can answer visitor questions grounded strictly in the portfolio, resume, projects, and articles.

  1. Build-time Knowledge Compilation: A custom build script (scripts/generate-knowledge.js) parses and strips frontmatter/MDX from all content collections, compiling everything into a unified knowledge base and generating contextual question suggestions at build/install time with zero runtime DB latency.
  2. Serverless Edge Streaming: Chat requests are handled at the Edge via Cloudflare Pages Functions (functions/api/chat.ts) streaming Server-Sent Events (SSE). It natively supports both Google Gemini (gemini-2.0-flash) and OpenAI-compatible models (gpt-4o-mini), equipped with domain guardrails and prompt-injection defenses.
  3. Interactive UI: The chat interface in src/scripts/ai-chat.ts handles real-time token streaming, smooth auto-resizing text inputs, quick-prompt suggestion cards, and two-stage markdown and link rendering.

Dynamic Open Graph Images

Using @vercel/og (Satori) and @resvg/resvg-js, the site dynamically generates social sharing preview images for every blog post and project page during the build process, ensuring consistent branding when links are shared on social platforms.

Why Astro

A few things made Astro the right fit for a personal site like this:

  • Performance by default. Astro ships zero JavaScript unless a component explicitly needs interactivity (its “islands” architecture). For a mostly static site like this one, that means blazing-fast loads without fighting framework overhead.
  • Content collections, Markdown/MDX first. Writing is the core of this site, so having typed content collections that validate frontmatter and let me write in Markdown/MDX was a big draw over reaching for a general-purpose SPA framework.
  • Simplicity over full SPA complexity. I didn’t need client-side routing, heavy state management libraries, or complex hydration cycles for what is fundamentally content. Astro’s simpler mental model matches the actual shape of the problem.

Where it’s deployed

The site is deployed on Cloudflare Pages. The build produces a static dist/ folder (astro build), while Edge Functions under functions/ run serverlessly across Cloudflare’s global edge network. Every push to main triggers an automatic build and deploy.

Deploy your own, it’s free

Here’s the part I like most: everything this site runs on costs $0. GitHub hosts the code for free, Cloudflare Pages hosts the site and edge functions for free, and Astro is open source. You don’t need complex infrastructure to get your own copy live:

  1. Fork the repository: Open the GitHub repository and click Fork in the top-right corner.
  2. Sign up for Cloudflare: Create a free account at cloudflare.com.
  3. Connect your fork: In the Cloudflare dashboard, go to Workers & Pages → Create → Pages → Connect to Git, and select your repository.
  4. Configure build settings: Framework preset: Astro, Build command: npm run build, Output directory: dist.
  5. (Optional) Configure AI Assistant: Add GEMINI_API_KEY (or OPENAI_API_KEY) to your Cloudflare Pages Environment Variables.
  6. Click deploy: Within minutes, your personal portfolio with an AI assistant is live!