BLOG / VIBE-CODING

The App Has No Customers, but the Button Is Tremendous

Notes from an afternoon of vibe coding, accidental product strategy, and one suspiciously confident button.

8 MIN READJAW

I woke up with an idea.

Not a normal idea. A platform idea.

By 9:17 a.m., I had a domain name. By 9:24, I had a logo. By 9:31, I had changed the logo because the first one didn't communicate velocity.

Do I know what the product does?

Not entirely.

But the landing page loads in 0.4 seconds, and the button has a little bounce when you click it. That's product-market fit adjacent.

A startup is just a folder called final-final-v3 that somehow acquired a payment processor.

The Pitch

The app is called Pigeon.

Pigeon is an asynchronous collaboration layer for people who are already collaborating asynchronously but would like another asynchronous layer on top of it.

The value proposition is simple:

  1. You write a thought.
  2. Pigeon puts the thought in a little digital envelope.
  3. Somebody else receives it at an emotionally appropriate time.
  4. Nobody schedules a meeting.

That fourth point is the moat.

You can view the extremely real project at jawdroppuh.lol, assuming I have connected the domain by the time you read this.

The Target Audience

Pigeon is designed for:

  • Founders with seven unfinished Notion workspaces
  • Developers who communicate primarily through commit messages
  • Designers who say “let's explore this direction” with dangerous confidence
  • People who have muted every workplace notification
  • Anyone currently hiding from a calendar invitation

It is not designed for:

  • Organizations with a procurement department
  • People who ask for an Excel export during the first demo
  • My accountant
  • Anyone who knows what our infrastructure costs

The Technical Architecture

I wanted the architecture to be elegant, scalable, and easy to explain.

Instead, it is currently this:

person has thought
        ↓
React component
        ↓
mysterious function
        ↓
database, probably
        ↓
another person eventually sees thought

The frontend began as a single component.

export default function Pigeon() {
  const [messages, setMessages] = useState<string[]>([]);

  function releasePigeon(message: string) {
    setMessages((current) => [...current, message]);
  }

  return (
    <main>
      <h1>Pigeon</h1>
      <button onClick={() => releasePigeon("Important business thought")}>
        Release the pigeon
      </button>
    </main>
  );
}

Clean. Focused. Majestic.

Then I added authentication. Then animations. Then a command palette. Then I spent forty minutes making the command palette open with a keyboard shortcut that nobody knows about.

The component is now 612 lines long and has developed opinions.

A Small but Critical Utility

Every serious startup needs at least one function that sounds more important than it is.

type Message = {
  id: string;
  body: string;
  urgency: "eventually" | "soon-ish" | "the-building-is-on-fire";
};

export function calculatePigeonVelocity(message: Message): number {
  const baseVelocity = message.body.length * 0.42;

  if (message.urgency === "the-building-is-on-fire") {
    return baseVelocity * 10;
  }

  return baseVelocity;
}

Is this used anywhere?

No.

But when investors inspect the repository, they're going to see the wordVelocity, and the meeting will take care of itself.

A note on scalability

We will address scalability immediately after achieving something worth scaling.

The Development Process

My process is highly disciplined.

  • Open the project
  • Identify the most important feature
  • Notice that the border radius feels wrong
  • Adjust the border radius
  • Reconsider the entire visual identity
  • Add one feature at 1:00 a.m.
  • Discover it already exists in the browser
  • Call it a prototype

The current task list looks like this:

  • Purchase domain
  • Create landing page
  • Add tasteful glass effect
  • Make tasteful glass effect slightly less tasteful
  • Add button bounce
  • Decide what happens after the button bounces
  • Find customers
  • Add pricing
  • Launch

That last checkbox is sitting there looking at me. I don't care for its tone.

Commands I Have Run With Confidence

Some commands are instructions. Others are negotiations.

npm run dev
npm run build
git status
git status
git status

And, when things become serious:

# This usually fixes the emotional problem.
npm install

For actual documentation, I occasionally consult MDN Web Docsor search GitHub for somebody who encountered the same problem in 2017.

Never mind, fixed it.

Fixed it how, Derek? What did you see?

Current Metrics

MetricValueInterpretation
Registered users1Strong founder adoption
Messages sent14All from me
Messages received14Excellent retention
Revenue$0Pre-revenue
Button satisfaction96%Self-reported
Console warnings3Stable

The remaining 4% of button dissatisfaction concerns the easing curve. I'm working through it.

What I Learned

1. Motion creates confidence

If the interface responds immediately, people assume the system knows what it is doing. The system may not know. But the button knows.

2. Constraints are useful

Constraints help you locate the exact moment you stopped listening to yourself.

3. “Temporary” is a powerful database schema

{
  "message": "hello",
  "status": "in_flight",
  "pigeonMood": "determined",
  "deliveryWindow": "when_the_time_is_right",
  "metadata": { "temporary": true }
}

The temporary field is permanent.

An Important Aside About Names

Naming a startup is harder than building one.

  • Short
  • Memorable
  • Available as a domain
  • Easy to pronounce
  • Capable of becoming a verb

“Send me a Pigeon.” “You Pigeoned the file?” “I've been Pigeoning all morning.”

That's language-market fit.

I briefly considered calling it BirdWork.

We don't need to discuss BirdWork.

The Plan From Here

Tomorrow, I will focus entirely on the core product. No redesigns. Just the essentials:

  1. Finish message delivery.
  2. Add useful empty states.
  3. Test the mobile experience.
  4. Let one other human use it.
  5. Remain calm while they use it incorrectly.

If that goes badly, I'll call it a research preview. Either way, we're shipping.

Final Thought

There is a strange moment in every project when the idea stops being imaginary but has not yet become sensible. That's where Pigeon is right now.

It exists. It runs. It has no customers, no revenue, and no defensible explanation for why the notification sound is a tiny man whispering “incoming.”

But it exists.

And the button?

The button is tremendous.


Filed from the founder's office, which is currently one chair, two monitors, and a bowl of cereal I no longer trust.1

1 The cereal was poured before the authentication rewrite.