Building an Astro Portfolio with AI-Assisted Development
WEB PLATFORMS

Building an Astro Portfolio with AI-Assisted Development

Personal Project
FULL-STACK DEVELOPER
Dec 2024 – Present

MODERN PORTFOLIO FEATURING AI-ASSISTED DEVELOPMENT AND SMOOTH VIEW TRANSITIONS.

Building an Astro Portfolio with AI-Assisted Development

Impact Statement

A case study in modern web development: leveraging Figma Make prototypes, AI coding agents, and Astro view transitions to build a performant portfolio site.

Overview

This personal portfolio site is itself a case study in modern web development practices. Rather than a traditional build process, it leveraged Figma Make for rapid prototyping, AI coding agents for conversion and implementation, and Astro’s view transitions for a polished SPA-like experience.

What Makes This Site Different

AI-Assisted Design Evolution

This site’s design workflow has evolved through multiple AI design tools:

Initial Approach (Figma Make): The site started as a prototype generated with Figma Make, which exported a React codebase. AI coding agents converted this to Astro components.

Current Approach (Google Stitch): Design iteration now uses Google Stitch, which generates framework-agnostic HTML/CSS. This eliminates the React-to-Astro conversion step and enables faster iteration on visual designs.

For a detailed comparison of AI design tools, see AI-Assisted Design: From Prompt to Production.

Astro View Transitions

The site uses Astro’s ClientRouter for smooth, app-like navigation without JavaScript frameworks. Astro provides transition directives like transition:name, transition:animate, and transition:persist to control how elements behave during navigation.

Navbar Persistence: The navigation bar uses transition:name="main-navbar" to remain stable during page transitions, with individual nav links animated via transition:name for active state morphing.

Work Card Animations: Project cards on /work use coordinated transitions:

  • transition:name="work-card-{slug}" - Card container morphs to detail page
  • transition:name="work-img-{slug}" - Hero image expands seamlessly
  • transition:name="work-title-{slug}" - Title text transitions in place
  • transition:name="work-body-{slug}" - Content area animates smoothly

This creates a shared-element expansion effect where clicking a project card feels like zooming into the detail page.

URL-Based Category Filtering: Rather than client-side JavaScript filtering, categories use static routes:

  • /work - All projects
  • /work/category/web-platforms - Filtered by category
  • /work/resume-chatbot - Project detail

This approach provides:

  • SEO-friendly URLs - Each category is a crawlable page
  • Shareable links - Users can share filtered views
  • No JavaScript required - Works with JS disabled
  • Proper view transitions - Cards animate seamlessly between all/filtered/detail views

Technical Stack

LayerTechnology
FrameworkAstro 5 with Content Collections
UI ComponentsDaisyUI 5 (neobrutalism theme)
StylingTailwind CSS 4 with CSS-first config
TransitionsAstro ClientRouter + View Transitions API
ContentMDX with Astro Content Collections
DeploymentCloudflare Pages

Neobrutalism Design System

The site implements a custom neobrutalism theme through DaisyUI overrides:

  • Bold borders - 2-4px solid black borders on all interactive elements
  • Hard shadows - Offset box shadows (4px 4px) for depth without blur
  • Vibrant colors - High-saturation accent colors (magenta, yellow, cyan)
  • Uppercase typography - Headlines use uppercase with tight tracking
  • Chunky components - Cards, badges, and buttons with generous padding

View Transitions Deep Dive

The navbar implements a morphing active indicator that smoothly moves between nav items during page transitions. Here’s the actual implementation:

Navbar Component Structure:

Navbar.astro
<nav class="btn-group h-full items-center relative">
{topLevelNavItems.map((item) => (
<a
href={item.href}
class={topLevelLinkClass(item.href)}
transition:name={`nav-link-${item.href.slice(1)}`}
>
{isActive(item.href) && (
<span
class="nav-active-bg"
transition:name="nav-active-bg"
/>
)}
<span class="relative z-10">{item.label}</span>
</a>
))}
</nav>

Key Concepts:

  1. Per-link transition names: Each link gets transition:name={nav-link-work}, transition:name={nav-link-approach}, etc. This allows Astro to track each link’s position across pages.

  2. Shared active background: The nav-active-bg span only renders on the active link, but uses a shared transition:name="nav-active-bg". When navigating from /work to /background, the background element “moves” from one link to another.

  3. Z-index layering: The text uses relative z-10 to sit above the morphing background.

CSS Animations for View Transitions:

/* BaseLayout.astro <style> block */
@keyframes scale-up {
from { transform: scale(0.8); opacity: 0; }
to { transform: scale(1); opacity: 1; }
}
@keyframes scale-down {
from { transform: scale(1); opacity: 1; }
to { transform: scale(0.8); opacity: 0; }
}

Project Card Expansion

When navigating from /work to /work/[slug]:

  1. The card’s hero image matches the detail page hero via shared transition:name
  2. The title and body content animate from card positions to full-width layout
  3. Browser calculates geometry changes and animates position/size automatically

Lifecycle Hooks

The site uses Astro’s view transition lifecycle events for state management:

ClientRouter Setup (BaseLayout.astro):

<head>
<!-- Enable SPA-style navigation -->
<ClientRouter />
</head>

Dark Mode Sync:

document.addEventListener("astro:before-swap", (event) => {
event.newDocument.documentElement.dataset.theme =
localStorage.getItem("color-scheme") || "light";
});

Re-initializing Scripts After Navigation:

With view transitions, DOMContentLoaded only fires on the initial page load. For interactive elements (like category filters), use astro:page-load:

function initCategoryFilter() {
const buttons = document.querySelectorAll('[data-category]');
// ... filter logic
}
// Initial load
initCategoryFilter();
// After view transitions
document.addEventListener('astro:page-load', initCategoryFilter);

This pattern ensures interactive scripts work both on initial load and after SPA-style navigation.

AI-Assisted Development

This site was primarily built using AI coding agents (Cursor, Claude, Antigravity) with specific patterns:

  • Component extraction - Agents extracted reusable patterns from Figma export
  • Content separation - All content moved to src/content/ collections
  • AGENTS.md guidance - Project-specific instructions for AI collaborators
  • Iterative refinement - Rapid feedback loops between human and AI

Lessons Learned

  • Figma Make as reference - Export quality varies, but it’s excellent as a translation reference
  • View transitions require planning - Element naming must be consistent across pages
  • Neobrutalism is opinionated - Hard shadows and bold borders need careful balance
  • AI agents need structure - AGENTS.md and clear file organization accelerate development

Deep Dives

For more technical detail on specific components: