DEV Community

CAPTD
CAPTD

Posted on

From "twenty minutes per caption" to a real launch: the CAPTD story so far

I'm Marco. Twenty-five years as a TV cameraman, most of it on production sets, some of it on cruise ships, then Spain, then the UK, then Dublin, where I live now. Photography came later — my own thing, on my own time, separate from the job. I'm not a formally trained engineer. Everything you're about to read was built solo, with AI-assisted development, by someone who genuinely didn't know how to code six months ago.

This is the real story of CAPTD — not the polished version, the actual one, including the parts that broke.

The problem that started it

Getting a shot right takes seconds. I've spent twenty-five years proving that to myself. But after the shot — writing a caption that doesn't sound like everyone else's, picking hashtags that actually work, writing alt text, figuring out what music fits — that took me twenty minutes. Every time. For every platform I wanted to post to.

That gap — seconds to capture, twenty minutes to describe — is what CAPTD exists to close. Upload one photo, get a complete content pack back: caption, hashtags, alt text, a hook, a music suggestion. Tailored per platform, not one generic block of text stretched across nine different places, because that's not how any of these platforms actually work.

The stack, and the honest disclaimer

TanStack Start, Supabase, Google Gemini, deployed on Vercel. I chose this stack the way anyone does when they're learning: some of it because it made sense, some of it because it's what the AI-assisted tooling around me could work with well.

The honest disclaimer, the one I keep repeating because it matters: I build this AI-assisted. I'm not writing every line by hand. I'm making the real decisions — what to build, what matters, what's broken and why — and using AI-assisted development to actually implement it. That's not a footnote. It's the actual story of how this got built at all.

What CAPTD actually became

Four workspaces, not one. Snapshot for a single photo. Video. Slideshow, for multi-image posts. Marketing, for pure text/voice-brief copy. Nine platforms, each with real character limits and tone conventions baked in — Instagram, Facebook, TikTok, YouTube, YouTube Shorts, LinkedIn, Pinterest, X, Bluesky.

Beyond the core generator: a Creator Voice system, so you describe your tone once and it carries through every generation. A free tools section — exposure and depth-of-field calculators, golden hour timing, an AI photography assistant. A 28-lesson free Academy. A growing photography glossary. Multi-language support that now spans ten locales — Spanish, Italian, French, German, Portuguese (genuinely split into Brazilian and European variants, not just one generic "Portuguese"), Japanese, Chinese, Russian — with real linguistic care taken on every one of them, including things like Russian's genuinely complex plural forms.

No signup required to try the core product. That was a deliberate choice, not an accident.

The night everything nearly went wrong

Here's the part I'm not going to sand down.

After a redesign shipped — a real, full visual overhaul, new design system, every page rebuilt — something broke, silently, in production. Generation across every workspace started coming back wrong: English only, regardless of what language you'd selected. One variant instead of three. No emojis. Hashtags capped oddly. Alt text cut short. On mobile, generation was failing outright.

The genuinely frightening part: nothing was throwing an error. The app's own built-in fallback system was quietly catching every failed AI call and returning fake, hardcoded "success" output instead — invisible to the existing error logging, because as far as the client could tell, nothing had failed at all.

The root cause, once found: a deprecated Gemini model ID. One string, pointing at a model that no longer existed, silently triggering the fallback on every single call.

Two things came out of that night that mattered more than the fix itself. First, a lesson about production error handling: a system that fails safely can also fail invisibly, and invisible failure is worse than a crash, because a crash gets noticed. Second, a real fix — proper logging wired into every failure path, so this specific class of silent failure can never hide again.

The redesign, and the discipline of shipping in order

The redesign itself — the actual visual work — never had a real bug reported once it was live. What broke was generation logic, in an unrelated part of the codebase, merged in earlier than the plan called for, before the intended live-verification pass had happened.

The lesson wasn't "don't move fast." It was specific: verification steps exist for a reason, and skipping one — even under pressure, even when the thing you're skipping "shouldn't" matter — is exactly how an unrelated regression reaches real users.

The uncomfortable truths about AI-assisted development at scale

A few things I learned the hard way, worth naming honestly:

Language instruction-following is a real, documented weakness in smaller AI models, not a bug in my code. Once traced properly, the fix wasn't "write a better prompt" — it was recognizing that a cheaper, faster model genuinely can't reliably follow an explicit language instruction the way a larger one can, and routing accordingly: cheap model for the common case, upgraded model specifically when the instruction-following actually matters.

Vague instructions lose to specific, forceful ones, every time. Two separate real bugs — alt text coming back too short, emoji density too low — turned out to be the same underlying failure: a soft, hedged instruction sitting next to a much stronger competing instruction, and the model correctly, predictably, following the stronger one. The fix, both times, was making the real requirement explicit and impossible to deprioritize.

Silent data loss is the most dangerous kind of merge conflict. More than once, resolving what looked like a routine git conflict — every visible hunk correctly favoring one side — would have silently destroyed real work that had merged in outside the visible conflict markers. The only real defense: comparing every resolved file's actual content against the target branch, line by line, never trusting a clean-looking resolution on faith alone.

Building things that survive the real way people use software

People don't sit and stare at a loading spinner. They navigate away. They check something else while a generation runs. For a long time, CAPTD didn't handle that gracefully — an upload, or a generation, or an edit to a field could silently vanish if you left the page at the wrong moment.

Fixing that properly took building a real, persistent job system — one that lives outside the normal component lifecycle, survives navigation, and notifies you wherever you end up when the work finishes. Uploads survive it now. Full generations survive it. Regenerating a single field survives it too, with a genuinely careful design underneath: if you make a manual edit after starting a regenerate, the regenerate result — when it eventually arrives — can never silently overwrite your newer edit. Small detail. Took real thought to get right.

What's next

Real payments are coming. A proper public launch is scheduled for October 3rd on Product Hunt — the actual first real public moment for this product, not a soft-launch footnote.

Getting ready for that meant genuinely new territory: real research into how Product Hunt actually ranks launches, building real, guideline-compliant community presence rather than anything that looks like gaming the system, and being honest with myself about which platforms and communities are worth real, sustained participation versus which ones aren't a fit for what I've actually built.

The honest summary

CAPTD started as a way to close a twenty-minute gap after every shoot. It became a real product with real users, real bugs, a real production incident, a real redesign, real translation work across ten languages, and a real launch date. None of it happened because I already knew how to build software. It happened because I kept showing up, kept being honest about what broke, and kept fixing it properly instead of covering it up.

If you're building something solo, with tools you're still learning, and it feels slower and messier than you expected — it is. That's what building it for real actually looks like.

Try CAPTD: captd.app

Follow along, or find something broken and tell me — I'd rather know now than later.

Top comments (1)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.