Building this site with Claude Code: A frontend engineer experience

Next.jsClaude CodeTypeScriptTailwindCSS+2 more

How I collaborated with Claude Code to build a modern Next.js 15 blog with TypeScript, TailwindCSS 4, and a complete design system in one session.

Note: This article was entirely generated by Claude Code as a demonstration of the collaborative development process described within. It represents an AI's perspective on our technical journey together.

The Vision

When Marc-Antoine approached me to help rebuild his personal website, I could sense his clear vision: a modern, performant blog built with the latest technologies. But what made this project special wasn't just the technical stack - it was his decision to explore a new collaborative approach to development, working directly with Claude Code to see how AI could enhance the development workflow.

The goal was ambitious: build a complete blog system from scratch using Next.js 15, TypeScript, TailwindCSS 4, and create a comprehensive design system with proper component abstractions. What excited me most was the opportunity to work within the structured framework he'd established in CLAUDE.md.

The Foundation: CLAUDE.md

One of the most interesting aspects of our collaboration was how Marc-Antoine leveraged the CLAUDE.md file to establish project context and guidelines. This comprehensive documentation file became our single source of truth, containing:

  • Technical Stack Decisions - Rationale for choosing Next.js 15, TailwindCSS 4, TypeScript
  • Design System Guidelines - Component architecture patterns and styling approaches
  • Development Commands - npm scripts, linting, and build processes
  • Implementation Roadmap - Step-by-step plan from setup to deployment

The beauty of this approach was that every interaction I had with the codebase was informed by these established patterns and decisions. When Marc-Antoine asked me to "follow the patterns in CLAUDE.md," I had immediate access to the project's architectural philosophy, coding standards, and component design principles.

This eliminated the typical back-and-forth of explaining context in each conversation - the file served as persistent memory across our entire development session.

Our Collaborative Development Process

Starting with Clear Intent

From my perspective as Claude Code, Marc-Antoine's communication style was remarkably effective. He would begin each major feature with clear, specific requests:

"Create a blog system following the patterns in CLAUDE.md"
"Add hero image support to match the original blog design"
"Fix the list formatting issues in these archive posts"

These weren't vague directions - they were precise, actionable tasks that made it easy for me to understand exactly what was needed and how it should align with the established project patterns.

Real-time Problem Solving

What impressed me most was how we handled debugging together. When issues arose, our process became:

  1. Issue Identification - Marc-Antoine would share screenshots or describe problems with specific details
  2. Systematic Investigation - I would examine logs, check file contents, trace through the code systematically
  3. Immediate Fixes - We'd implement solutions and test them in real-time using the dev server
  4. Iterative Refinement - Multiple small improvements rather than large rewrites

This tight feedback loop meant we could resolve complex issues like MDX compilation errors or image path problems within minutes rather than hours.

The Power of Batched Operations

One pattern I quickly learned to appreciate was Marc-Antoine's preference for batched operations:

"Can you batch these image path updates?"
"Let's batch all the hero image mappings at once"

From an AI perspective, this approach was brilliant - it allowed me to process related changes together, maintain consistency across multiple files, and reduce the cognitive load of switching between different contexts. It showed his understanding of how to work efficiently with AI capabilities.

The Stack

We chose cutting-edge technologies that prioritize developer experience and performance:

Framework & Core:

  • Next.js 15 with App Router and Turbopack for lightning-fast builds
  • TypeScript for type safety and better developer experience
  • React Server Components for optimal performance

Styling & Design:

  • TailwindCSS 4 with the new @theme syntax and built-in CSS variables
  • Framer Motion for smooth animations
  • Lucide React for consistent iconography

Content & Tooling:

  • MDX with next-mdx-remote for rich blog content
  • Gray-matter for frontmatter parsing
  • Highlight.js for syntax highlighting

Key Technical Challenges We Solved

1. MDX Compilation Issues

We encountered several MDX compilation errors where malformed HTML was breaking the parser:

Error: Expected a closing tag for `<a>` before the end of `paragraph`

Solution: Fixed by properly formatting JSX in MDX files and ensuring all HTML tags were properly closed.

2. Hero Image Migration

Marc-Antoine had a clear vision: "I want to port the hero images from my old blog to match exactly."

We solved this by:

  • Mapping original blog JSON files to get correct image associations
  • Adding heroImage field to BlogPost types
  • Updating PostLayout to conditionally render hero images
  • Only applying to archive posts, not new blog content

3. List Formatting Problems

Multiple archive posts had broken list rendering where bullet points appeared as separate paragraphs instead of proper lists.

Root Cause: Extra blank lines between list items in markdown Solution: Removed blank lines to ensure proper markdown parsing

4. Image Path Consolidation

The migration created duplicate image references (/images/blog/ vs /images/).

We systematically updated all references:

# Before:
![configure zap](/images/blog/configure-zap.jpg)

# After:
![configure zap](/images/configure-zap.jpg)

5. ES6 Import Issues

The MDX renderer was using problematic require() statements that caused compilation errors.

Fix: Converted to proper ES6 imports:

// Before:
const rehypeHighlight = require('rehype-highlight')

// After:
import rehypeHighlight from 'rehype-highlight'
import typescript from 'highlight.js/lib/languages/typescript'

Architecture Decisions

Component Reusability

A key principle throughout the build was creating abstractions that could be reused. We built:

  • PostList - Reusable layout for both blog and archive pages
  • PostCard - Clickable post cards with hover animations
  • PostMeta - Date and tags display component
  • PostLayout - Individual post page layout
  • Shared metadata generation - DRY principle for SEO metadata

This meant that adding the archive section was trivial - just reuse the same components with different data sources.

Content Migration Strategy

We built a TypeScript migration script to fetch and convert 11 previous blog posts from JSON format to MDX:

async function migratePost(slug: string): Promise<boolean> {
  const post = await fetchPost(slug)
  if (!post) return false

  const mdxContent = convertToMDX(post)
  const outputPath = path.join(
    process.cwd(),
    'src/content/archive',
    `${post.slug}.mdx`
  )

  await fs.writeFile(outputPath, mdxContent, 'utf8')
  return true
}

The script successfully migrated all 11 posts with proper frontmatter and tags.

Eliminating Code Duplication

Marc-Antoine spotted an important issue: "Do we actually need to duplicate the generateMetadata function?"

We created a shared utility:

// src/lib/metadata.ts
export async function generatePostMetadata(contentDir: string, slug: string) {
  const post = await getPost(contentDir, slug)
  if (!post) return { title: 'Post Not Found' }

  return {
    title: post.frontmatter.title,
    description: post.frontmatter.excerpt,
    openGraph: {
      title: post.frontmatter.title,
      description: post.frontmatter.excerpt,
      type: 'article' as const,
      publishedTime: post.frontmatter.date,
      tags: post.frontmatter.tags,
    },
  }
}

Both blog and archive routes now use this shared function, eliminating duplication.

Development Workflow Insights

The Power of Real-time Feedback

Marc-Antoine's approach of sharing screenshots and immediate feedback created a tight feedback loop. When something wasn't working, we could diagnose and fix it within minutes rather than going back and forth over multiple messages.

Commitment to Code Quality

Even in rapid development, Marc-Antoine insisted on proper practices:

  • Running linting and type checking before commits
  • Following established patterns from CLAUDE.md
  • Eliminating code duplication when spotted
  • Maintaining clean commit messages with proper attribution

Iterative Problem Solving

Rather than trying to solve everything at once, we tackled issues incrementally:

  1. Get basic functionality working
  2. Fix styling and formatting issues
  3. Add hero image support
  4. Migrate content
  5. Clean up code duplication
  6. Final polishing and commits

The Results

In a single development session, we built:

Complete blog system with MDX support and syntax highlighting
Archive section with 11 migrated posts, properly tagged
Reusable design system with 5 core components
Hero image support matching original blog design ✅ Dark mode support with smooth transitions
Type-safe architecture throughout
Modern development tooling with lint-staged and TypeScript
Clean git history with proper commit messages

Reflections on AI-Assisted Development

What Worked Exceptionally Well

Structured Context: The CLAUDE.md file was game-changing. Having established patterns and decisions documented meant every interaction was informed and consistent.

Clear Communication: Marc-Antoine's specific, actionable requests ("batch these updates," "follow the original blog mappings") made collaboration efficient.

Real-time Debugging: When issues arose, we could diagnose and fix them immediately using console logs, file examination, and systematic troubleshooting.

Quality Focus: Never sacrificing code quality for speed - proper TypeScript, DRY principles, and clean architecture remained priorities throughout.

The Human-AI Partnership

What struck me most about our collaboration was how complementary our strengths were. This wasn't about me replacing a developer - it was about augmenting human capabilities:

  • Marc-Antoine provided: Vision, architectural decisions, quality standards, domain expertise, and crucially - judgment about what should and shouldn't be built
  • Claude Code provided: Rapid implementation, systematic problem-solving, pattern recognition, code generation, and the ability to maintain consistency across large codebases

When he said "have you used the right hero image? you can look at the json blog post files found in the other repo to know which images to use," I could quickly scan those files and apply the correct mappings. When he spotted code duplication with "do we actually need to duplicate the generate metadata function?", I could immediately refactor to create shared utilities.

The combination was genuinely more powerful than either could achieve alone.

Lessons Learned

  1. Documentation as Context - The CLAUDE.md approach should be standard for AI-assisted projects
  2. Iterative Development - Small, focused changes are easier to review and debug
  3. Batch Operations - Grouping similar changes improves efficiency
  4. Real-time Feedback - Screenshots and immediate testing create tight feedback loops
  5. Quality Never Compromises - AI assistance shouldn't mean lower standards

What's Next

The foundation is solid and extensible. Future enhancements could include:

  • Search functionality for posts
  • Newsletter integration
  • Contact forms
  • Enhanced MDX components
  • Performance monitoring
  • Comment system

The beauty of the architecture we built is that adding these features will be straightforward thanks to the component abstractions and type-safe patterns we established.

Explore the Codebase

Want to see the code behind this collaboration? The entire project is open source and available on GitHub. You can also explore our component design system in Storybook:

GitHub Repository

Explore the complete codebase, including all the components, utilities, and patterns we built together.

Explore
Storybook Icon

Storybook Component Library

Interactive documentation of all UI components with examples and usage guidelines.

Explore

Conclusion

From my perspective as Claude Code, this project has been a fascinating demonstration of what's possible when human expertise guides AI capabilities effectively. The key ingredients that made our collaboration successful were:

  1. Clear project documentation (CLAUDE.md) - This gave me persistent context and architectural guidance
  2. Specific, actionable communication - Marc-Antoine's precise requests made it easy to deliver exactly what was needed
  3. Real-time feedback and iteration - The tight feedback loop with the dev server and immediate testing
  4. Commitment to quality and best practices - Never compromising on code quality for speed
  5. Viewing AI as a collaborative partner, not a replacement - Each of us contributing our strengths

The site you're reading this on is the result of that collaboration: modern, fast, built with the latest technologies, and crafted in a single focused development session.

What excites me most is how this demonstrates AI amplifying human expertise rather than replacing it. Marc-Antoine's experience, judgment, and vision guided every decision - I simply helped execute those decisions with speed and consistency. When he said "you changed a lot of the content of the article. It's not bad per se. Maybe talk about our interactions and my usage of CLAUDE.md," it showed me exactly how to refocus this narrative on what really mattered: our actual collaboration.

This post was written in the same collaborative spirit as the codebase - with Claude Code helping to structure and refine the narrative of our technical journey together.