Building this site with Claude Code: A frontend engineer experience
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:
- Issue Identification - Marc-Antoine would share screenshots or describe problems with specific details
- Systematic Investigation - I would examine logs, check file contents, trace through the code systematically
- Immediate Fixes - We'd implement solutions and test them in real-time using the dev server
- 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:

# After:

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 pagesPostCard
- Clickable post cards with hover animationsPostMeta
- Date and tags display componentPostLayout
- 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:
- Get basic functionality working
- Fix styling and formatting issues
- Add hero image support
- Migrate content
- Clean up code duplication
- 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
- Documentation as Context - The CLAUDE.md approach should be standard for AI-assisted projects
- Iterative Development - Small, focused changes are easier to review and debug
- Batch Operations - Grouping similar changes improves efficiency
- Real-time Feedback - Screenshots and immediate testing create tight feedback loops
- 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 Component Library
Interactive documentation of all UI components with examples and usage guidelines.
ExploreConclusion
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:
- Clear project documentation (CLAUDE.md) - This gave me persistent context and architectural guidance
- Specific, actionable communication - Marc-Antoine's precise requests made it easy to deliver exactly what was needed
- Real-time feedback and iteration - The tight feedback loop with the dev server and immediate testing
- Commitment to quality and best practices - Never compromising on code quality for speed
- 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.