vibe coding · platform design

My first WordPress plugin

A vibe coding experiment that shipped, and got noticed.

Building with an AI-native stack. Summer 2025 to October 2026.

Problem

Every off-the-shelf WordPress text-to-speech plugin I found required a paid subscription.

Move

Prototyped in Lovable, checked the code with Copilot, then cut scope to one job, reliable playback.

Outcome

A free, self-contained narrator on every page of this site, now published in the WordPress.org Plugin Directory.

0-to-1Vibe coded from scratch 0Subscriptions required WordPress.orgFree public plugin

The context

The narrator play button

I spend a lot of time listening to audiobooks and podcasts. I wanted to give visitors to my website that same option. I also needed it to be free, self-contained, and not tied to a monthly subscription. It was easily the most useful thing I did that summer.

This is how a non-developer used AI tools to build and ship a custom WordPress text-to-speech plugin, and what happened next.

Act 1:How I got to Lovable

By mid-2025, vibe coding was all anyone was talking about. Many of my soccer buddies are developers and data scientists. I started pelting them with questions about training LLMs and IDEs. They pointed me to tutorials, and I went deeper with Python exercises and spending time on Kaggle. I started reading code instead of just copying it.

My first real experiment was in Lovable.dev, trying to build a simple, bot-resistant contact form for this site. I was frustrated with the exercise and losing confidence in its value fast.

Create a bot-resistant simple embeddable form to collect name, email, and a brief message for deployment on my WordPress 2025 templated website. Ideally, would like to collect entries on a Google sheet or Airtable.

My starting prompt

It didn’t go anywhere I wanted. So I pivoted.

Act 2:The idea: a plugin that reads my pages aloud

I’d looked at off-the-shelf WordPress text-to-speech plugins but they all required paid subscriptions. I wanted something free, self-contained, and mine. With those two constraints as a rough product spec, I started prompting in Lovable.

Lovable’s enthusiasm was immediately suspicious.

This is a fascinating request! You want to create a WordPress-compatible web widget that can read and analyze the text content of any webpage it’s placed on. This evokes modern accessibility tools, content analysis widgets, and reading assistance plugins.

Lovable.dev

Most are familiar with this tone. You’ve suddenly become extremely talented, or you’re being managed. I pressed on.

An AI-generated calculation of what I did in Lovable and how long it took me.

Act 3:The dream, and then the constraints

At first, the sky seemed like the limit. I was experimenting with multilingual versions, accent choices, and displays that tracked your position in the text. I’d only signed up for a month of Lovable, so I had a built-in deadline.

The early versions required a Supabase connection and third-party integrations that were sometimes working, mostly not. Playback would stall. I kept asking why, and the debugging loop became its own project. I spent every evening describing what I needed in step-by-step detail. Slowly it became clear that the complexity was the problem.

I went back to basics. Just make it play reliably. No frills. No language choices.

I started pulling code artifacts from Lovable and running them through Visual Studio Copilot. It was a useful gut-check on what could break and what might be unsafe. I also leaned on my product experiences. I’ve been in enough rooms where engineering, UX, and product debate real and imagined constraints. I knew when it was time to ruthlessly cut scope and just ship an MVP.

Act 4:What I ended up with

No setup, simple two-state controls, variable playback speeds, dismissible, read time and current position.

It’s the play button in the bottom-right corner of every page on this site. It’s simple, self-contained, and needs no subscription. You can install the public version from the WordPress.org Plugin Directory, or inspect the original site version on GitHub.

Building it taught me to read and reason about code I didn’t write. This was new.

Act 5:Sharing it on WordPress.org

The version on this site was built for an audience of one. In October 2026 I packaged it so anyone running WordPress could install it without touching code.

Testing theme inheritance, contrast, and WordPress Plugin Check compliance before release.

Making a personal tool work on other people’s sites mostly meant stripping out my site’s customized theme and running the checks required for public release.

  • Theme inheritance. The player now pulls its colors and type from the active theme, with neutral light and dark fallbacks that pass WCAG AA contrast checks.
  • Smaller settings. Color presets are gone. Settings cover on or off, post types, corner placement, and an optional Google Analytics toggle that stays off by default.
  • Standard WordPress QA. Tested in a local WordPress 7.1 environment across core themes and checked with the official WordPress Plugin Check tool.
  • Same privacy rule. Speech still runs in the visitor’s browser via the Web Speech API. No account, no API key, and no data sent anywhere.

Version 1.1.0 is now available as // dadalab page narrator in the WordPress Plugin Directory. The custom version for this site remains on GitHub.

Tools used. The initial prototype started in Lovable with GitHub Copilot. Preparing, testing, and packaging the public release used Claude, ChatGPT, Antigravity, and Hyperagent.

PostScript

The plugin may have played a role in landing a contract with ServiceNow. That work led to an AI-first approach to content governance, where we collaborated across teams to compress an ITSM deployment timeline from 242 days down to under 30.

My developer friends scoffed at the idea of shipping production code from a vibe coding app. They remain supportive, encouraging my experiments and providing useful feedback.

Curious what I would build for you?

The plugin is free on WordPress.org. The thinking behind it travels.