I rebuilt iMessage line for line. Nobody wanted it.
I spent about a year rebuilding iMessage in SwiftUI. Not a chat UI similar to iMessage, but the real deal. Everything. The collated bubbles that only have a tail at the end. The typing dots that breathe in a wave. The keyboard you can drag down with your finger from the top of the input bar. The “Delivered” fading into “Read” smoothly with the same scale effects. I am still impressed that I was able to do it. It might be the best UI I’ve ever made.1
Then I turned it into a package, and nobody wanted it.
Here it is, in all its glory:
What went into it
I sort of always had admired iMessage, but the impetus to rebuild it came from a client. Protector wanted a chat-with-your-protector feature in their app, and Nick (the CEO) was shocked that Apple didn’t have an iMessage SDK. Later, Polymarket wanted a chat in its markets. So I was seeing the pattern. I decided to just build it once, for everyone.
Reading the build post, you can see the effort that went into it. Here’s the log, from the private source repo:
| Commits | 655 |
| Days with a commit | 85 |
| First commit | August 11, 2025 |
| Most recent commit | September 7, 2026 |
| Lines written | 36,755 |
| Lines deleted | 17,372 |
| Swift lines standing | 17,286 |
ChatViewController.swift | 3,845 lines |
| Commits mentioning the bubble | 117 |
| Commits mentioning the tail | 35 |
Even though this is packaged as an easy SwiftUI view for anyone to use, it obviously uses UIKit under the hood. A UICollectionView powers most of it, because List is useless. The one collection view file is almost a quarter of the package. The keyboard drag has to be corrected frame by frame. Every bubble is attached to a stiff mini spring. The bubble shape was hand-traced from an iMessage screenshot. The new-message haptic is a custom buzz pattern that I had to generate to match iMessage’s feel. Here’s the result of two of those things:


By the way, twelve people have commits in the repo. I made about sixty percent. The tail shape that was finally perfect came from a contractor I hired last year.
Over and over in the process, people told me this stuff wasn’t necessary. But somehow I just felt compelled to build it. I wanted exactly the same thing Apple had built in my apps. And I basically ended up getting there.
The big day
I polished the README and made the screenshots in both light and dark mode. I built an entire separate demo app so people could try it.2

Then I pushed the package to the public, wrote about it here on this blog, and I think I tweeted a few times. I didn’t do much more than that. I was scared to, honestly.
Nothing happened.
To be clear, this was barely a launch. So I don’t want to overstate it. But I was still surprised by the silence. Here’s the public repository today, ten months later:
| Stars | 9 |
| Forks | 0 |
| Watchers | 0 |
| Issues ever opened | 0 |
| Views, last 14 days | 20 (5 unique) |
| Clones, last 14 days | 12 (7 unique) |
| Top referrer | github.com |
Twelve clones over the course of two weeks, mostly me I think. I thought maybe something was broken.3
Comparing my other packages
I could say it was just that nobody wants Swift packages. But I have a bunch of them, published on my same org, and promoted in a similar way. So you can compare them:
union-tab-view is a tab bar. It went live eleven days after union-chat. It’s one sixteenth the code. And it has fourteen times the stars. union-confetti is 435 lines of code that just shows confetti, and it beat union-chat almost three to one.
So it wasn’t that people didn’t want Swift packages. They just didn’t want this one.
The diagnosis
My first theory was distribution. Just that I posted on the wrong day. Or the wrong channel, or needed a better launch video. The last package I had launched became the most upvoted post in the history of r/swift, so this was the theory: the product was great but the launch just wasn’t loud enough. And we could fix that.
It took me a while to admit to myself that a real launch would have barely changed anything. You cannot market a product that nobody wants or asked for. And nobody wanted this.
Here’s the calculation I should have done before I made this. How many people are making a native iOS app with a chat screen this year? Definitely some. How many want their chat to look exactly like iMessage instead of their own branding? Fewer, but still some. How many of those people would want to adopt a dependency instead of building it themselves? Even fewer. And how many of those very, very few remaining would find my package?
I think I was a bit afraid of the answer to that. The two clients who kicked off this exploration had wanted chat screens. The line-for-line recreation was really just my objective. Nobody else wants to waste time making sure their typing indicator breathes right. I was chasing a standard more than anything. Something I held up for myself.
The responses people did give me were all basically “wow, impressive.” Nobody was saying “finally.” And “impressive” but “no” times a thousand is zero usage.
That’s what I really was blind to. Building something hard is not the same as building something people want. And you only get users when people want what you built.
The last thing working against it might have been that it shipped as a closed-source binary. Nobody actually ever complained about that, but I was waiting to open the source until someone asked. The final thing that shipped was basically some Swift around the xcframework. So you can’t read it or patch it. Also, it requires iOS 18 and uses a third-party image library. Even after forty-six releases it’s still not out of beta. So the very few people who did stumble across the package had good reasons to pass on it. It really was built for me, I guess.
The coda
Here’s something interesting:
Two hundred and eighty-one commits in the month I launched. Then there was a long decay before not being touched in March, April, May, and June. But it came back in a big way this summer.
Not because people picked it up.
A few weeks after launch, union-chat was added to Rate.fm, the music app I actually run. I originally used it to leave comments under reviews. Now, it’s a fully-featured chat product with real users. So every detail I churned out for the past year, collated tails, the delivery labels, the interactive keyboard, is now in an app that hundreds of people are using every day.
And Rate.fm isn’t the only one! Polymarket still runs a heavily modified version of union-chat. It’s also in Tally, my calorie counter and workout app, as the coach chat, and in Jester, where you can paste in a screenshot of a conversation and ask what to say next:
So the code is in four real apps now, and the forcing function from the users has made the package much better much more quickly.
I don’t really regret it. The work definitely forced me to be better in a way clients never did. No client would ever pay for thirty-five message bubble tail commits.4 Everything I did in the package went into craft skills that I used elsewhere in my apps. And now it’s embedded in products I own.
I don’t really have any reason to open the source, because nobody has asked. There might be too much now. I’m not sure. Open to recommendations! But the package for now is free, closed, and unadopted, while it runs in four real apps. And maybe more from me to come.
So nobody wanted it. And then eventually someone did. Me. Not a very good business plan. But not the worst ending.
Footnotes
-
I’m a bit biased, but the receipts are in this post: springs, frame-by-frame keyboard math, and the hand-traced bubbles. ↩
-
The demo app also has no users :) ↩
-
It worked. ↩
-
In the first draft of this post I rhetorically said “the ninth version of the bubble tail.” The real commit log shows thirty-five commits mentioning the bubble tail. They started a week before launch and were most recently last week. So ten months on the bubble’s corner. ↩