← Back to Posts

Vibe Coding: Building software with my voice

A person vibing while coding

I recently discovered what people are calling vibe coding (or maybe Andrej Karpathy minted it first) - a completely different way of building software that feels more like having a conversation than traditional programming. Let me tell you about how I built this blog using just my voice with Cursor and SuperWhisper, and why it was such a game-changing experience.

What is Vibe Coding?

Vibe coding is when you're in a flow state with your AI coding assistant, where you can simply express your intentions conversationally and watch as your ideas materialize into working code. It's like pair programming with a highly capable partner who can understand your natural language and translate it into functional code instantly.

The Tools That Made It Possible

Cursor IDE

Cursor is not your typical code editor. It's an AI-powered IDE that understands context, can generate code, and helps you navigate your codebase effortlessly. What makes it special is its ability to maintain a coherent conversation about your code while making precise, contextual changes.

SuperWhisper

SuperWhisper voice coding in action

Adding SuperWhisper to the mix took things to another level. Being able to speak naturally to your computer and have it understand your coding intentions feels like science fiction. It's voice coding, but without the rigid command structure of traditional voice coding tools.

The Libraries Behind the Blog

Before diving into the code, let's understand the key libraries that make this blog possible:

  • gray-matter: Parses front-matter from markdown files, allowing us to extract metadata like title, date, and excerpt
  • react-markdown: Converts markdown content into React components
  • react-syntax-highlighter: Provides beautiful syntax highlighting for code blocks
  • next/navigation: Handles dynamic routing and navigation in Next.js
  • Tailwind CSS: A utility-first CSS framework for rapid UI development

Here's how they all come together in the blog post rendering component:

// Blog post page component combining all libraries import fs from 'fs'; import path from 'path'; import matter from 'gray-matter'; import { notFound } from 'next/navigation'; import ReactMarkdown from 'react-markdown'; import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; import { oneDark } from 'react-syntax-highlighter/dist/esm/styles/prism'; export default async function BlogPost({ params }: { params: { slug: string } }) { const { slug } = params; // Use Node.js file system to read markdown files const fullPath = path.join(process.cwd(), 'content/blog', `${slug}.md`); try { // Read and parse the markdown file const fileContents = fs.readFileSync(fullPath, 'utf8'); // Extract front-matter and content using gray-matter const { data, content } = matter(fileContents); return ( <article className="mx-auto mb-16 mt-10 max-w-3xl px-4"> <h1 className="text-3xl font-bold">{data.title}</h1> <time className="text-gray-500"> {new Date(data.date).toLocaleDateString()} </time> {/* Convert markdown to React components */} <div className="prose mt-8"> <ReactMarkdown components={{ // Custom handling of code blocks with syntax highlighting code({ className, children, ...props }) { const match = /language-(\w+)/.exec(className || ''); const code = String(children).replace(/\n$/, ''); return !match ? ( <code {...props}>{children}</code> ) : ( <div className="relative"> <CopyButton text={code} /> <SyntaxHighlighter style={oneDark} language={match[1]} PreTag="div" > {code} </SyntaxHighlighter> </div> ); } }} > {content} </ReactMarkdown> </div> </article> ); } catch (error) { // Handle missing posts with Next.js 404 notFound(); } }

This component showcases how modern libraries can work together seamlessly:

  • Files are read and parsed with Node.js built-ins and gray-matter
  • Markdown is transformed into React components with react-markdown
  • Code blocks are automatically detected and highlighted
  • The copy button is integrated into each code block
  • Everything is styled with Tailwind CSS classes

Building This Blog

The process of building this blog was surprisingly enjoyable. Here's how the code evolved through simple conversations:

  1. Starting with a basic blog component:
// Initial blog component export default function RecentBlogPosts() { return ( <div className="mt-5 mb-5"> <h4>Recent Posts</h4> {/* TODO: Add blog posts */} </div> ); }
  1. Adding dynamic blog post fetching:
// After asking for dynamic blog post loading import { getBlogPosts } from '../lib/blog'; export default async function RecentBlogPosts() { const posts = await getRecentPosts(); return ( <div className="mb-5 mt-5 flow-root rounded p-5 ring-1 ring-gray-200"> <h4 className="pb-2 text-sm font-semibold leading-7">Recent posts</h4> {posts.map((post) => ( <Link key={post.slug} href={`/blog/${post.slug}`} className="block pb-1 text-blue-600 hover:underline" > <div className="flex justify-between"> <h3>{post.title}</h3> <time className="text-gray-500">{post.date}</time> </div> </Link> ))} </div> ); }
  1. Adding syntax highlighting to code blocks:
// After requesting syntax highlighting import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; import { oneDark } from 'react-syntax-highlighter/dist/esm/styles/prism'; export default async function BlogPost({ params }) { // ... other code ... return ( <ReactMarkdown components={{ code({ className, children, ...props }) { const match = /language-(\w+)/.exec(className || ''); const code = String(children).replace(/\n$/, ''); return !match ? ( <code {...props}>{children}</code> ) : ( <div className="relative"> <SyntaxHighlighter style={oneDark} language={match[1]} PreTag="div" > {code} </SyntaxHighlighter> </div> ); }, }} > {content} </ReactMarkdown> ); }
  1. Adding a copy button to code blocks:
// After asking for a copy button 'use client'; export default function CopyButton({ text }: { text: string }) { const [copied, setCopied] = useState(false); const copy = async () => { await navigator.clipboard.writeText(text); setCopied(true); setTimeout(() => setCopied(false), 2000); }; return ( <button onClick={copy} className="absolute right-2 top-2 rounded bg-gray-700 px-2 py-1 text-xs text-white opacity-70 hover:opacity-100" > {copied ? 'Copied!' : 'Copy'} </button> ); }

Each of these features was implemented through natural conversation with the AI. I simply described what I wanted, and the AI understood the context and generated the appropriate code. No need to manually look up syntax or browse documentation - just express the intention and watch it come to life.

The Magic Moments

Some of my favorite moments included:

  • Natural Problem Solving: When I wanted to add syntax highlighting to code blocks, I just asked for it conversationally, and the AI understood exactly what I needed and implemented it with proper dependencies and configuration.

  • Rapid Iteration: Making changes was as simple as saying "I'd like the blog posts to look more modern" or "Can we center this element?" The AI understood the context and made precise adjustments.

  • Learning While Building: The AI didn't just write code; it explained its choices and taught me new patterns and practices along the way.

Why This Matters

This new way of coding feels like a glimpse into the future of software development. It's not about replacing programmers; it's about elevating the conversation to a higher level where we can focus on creativity and problem-solving rather than syntax and boilerplate.

The combination of:

  • Conversational AI in Cursor
  • Voice commands with SuperWhisper
  • Real-time code generation and editing
  • Contextual understanding of the codebase

Creates an experience that's not just more efficient, but more enjoyable and creative.

Looking Forward

As these tools continue to evolve, I'm excited about the possibilities. Will we reach a point where most coding feels this natural? Where we can focus entirely on the what and why, letting AI handle more of the how?

For now, I'm just enjoying the process of building through conversation, watching my ideas come to life through simple dialogue with my AI pair programmer. It's made coding feel less like writing instructions for a computer and more like collaborative creation.

Try It Yourself

If you're curious about vibe coding, I encourage you to try out Cursor IDE and experiment with voice coding tools like SuperWhisper. The learning curve is surprisingly gentle, and the experience might change how you think about coding.

Remember, the goal isn't to stop thinking like a programmer - it's to elevate your thinking to a higher level of abstraction while letting AI handle the implementation details.

Happy vibe coding! 🎵✨