Inspiration

You know the moment: two notes into a song and you already know what it is. Tack is built around that moment.

It started this summer as one of two dozen small browser minigames I made. The song one was the only one people kept coming back to, so I rebuilt it as a native iPhone app and shipped it on August 13.

What it does

Tack plays about a second of a hit song and shows you four titles. Your score comes from three things: how little of the song you needed (40%), how fast you answered (30%) and your streak (30%). Up to 1,000 points a song, six songs a round.

  • Free Fall (new in 1.6): the whole 30-second preview plays and your points drain the entire time. You answer the moment you know it.
  • The Daily: the same songs for everyone in the world, one attempt, one global board.
  • More than a dozen ways to play: Classic, Endless, Survival (one miss and you're out), Speed Run (60 seconds), Quick Three, Type It (no multiple choice), Songdle (six guesses, no sound), Guess the Year, Drop the Needle, Last Second, Replay, and Pass & Play on one phone.
  • Challenge links that carry the round itself: your friend gets the same songs in the same order, and the result screen calls the head-to-head.
  • 400+ collections: seven decades, genres, Bollywood, K-pop, Afrobeats, city charts, and about 370 artist packs where all four options are by the same artist. Every pack has its own leaderboard.
  • My Music: a round built on your device from your own Apple Music library, plus a playlist builder that saves back to Apple Music.
  • Five interface languages (English, German, French, Spanish, Hindi), 16 appearances including light ones, and Dynamic Type up to the accessibility sizes.

The core game is free, with no ads and no account.

How I built it

  • iOS app in Swift and SwiftUI. It shares a small package with my other three games: theme, Game Center with an offline score queue, local notifications and the purchase layer.
  • Audio is Apple's public 30-second iTunes previews, served through my own small Node server (built-in node:sqlite, no npm dependencies) behind Caddy on a VPS. The server deals every round as a signed token (so a challenge link can't be tampered with), runs the Daily and the per-artist leaderboards, and caches previews on disk.
  • RevenueCat powers both subscription tiers (Tack Pro and Tack Pro Max, each weekly, monthly or yearly): offerings, entitlements and restore. The app only ever asks RevenueCat what a player is entitled to, so a price or offer change needs no app update.
  • Layers is integrated for deferred deep linking, so a challenge can survive the App Store install gap. The app side is live; the landing-page hand-off is the next step (see What I learned).
  • Tests: over 340 unit tests, plus UI tests that play real rounds against a real server.

Challenges I ran into

  • A fair clock. On a slow connection the points started falling before the song had even loaded. Nothing crashed and nothing logged; the timer simply started when the question appeared instead of when the audio could play. 1.6 starts the clock only once the snippet can actually play, and prefetches the next two songs while you answer.
  • Scoring in three codebases. The Daily ranks web and iPhone players on one board, so the scoring model lives in Swift, on the server and in the web game, pinned to the same exact numbers by tests on each side.
  • Analytics that fail silently. When I renamed a mode, the app kept sending the new name, the server kept rejecting it, and that mode counted zero plays with no error anywhere. Both sides now have a test pinning the exact list of events.
  • Pricing on the App Store. Apple only preserves prices on an increase. When I lowered prices, every existing subscription moved to the new price too.

Accomplishments that I'm proud of

  • Seven releases in six weeks: 1.0 on August 13, 1.6 on September 22.
  • 644 new players finished onboarding in the 20 days since I started counting, and about 4,000 rounds were finished.
  • Coins you earn by playing and can never buy. Players have traded them for 210 hours of Pro.
  • No ads, no account, no advertising identifier. Usage stats are per-day totals with no identifier in them.

What I learned

  • Ask the people who don't buy. When someone closes the paywall, Tack asks what they'd pay and why not now. 107 people answered: "too expensive" was the top reason, and 40 people named $2 a month. The first 48 answers came in within a day, and the next day Pro dropped to CHF 3 a month.
  • Sharing has to be designed, not just enabled. About 15,900 rounds have been dealt, but only 16 challenge links were ever opened by someone new. Auditing that loop for this submission, I also found its missing half: the challenge landing page sends people to the App Store without handing the challenge to Layers, so a friend who installs starts on the home screen instead of in the round.
  • The bug players feel isn't always the one in your tracker.

What's next for Tack

  • Make sharing the natural end of a round: a result card worth posting, and the Daily as a shareable grid.
  • Packs curated by music creators, with their name on them.
  • More collections, which ship from the server without an app update.

Built With

Share this project:

Updates

Submission history