Skip to content
DavidSling
All work

offlyn.love

Dating through friends of friends, like normal people. Your pool is the people your friends actually know. Web app plus an Expo app for iOS and Android.

Role
Product, design, engineering
When
2026
Platforms
Web, iOS, Android
Stack
Supabase, Expo, TanStack Start

The idea

Dating apps match you with strangers. offlyn.love matches you through friends of friends: your pool is the people your friends actually know, the way people met before apps.

I took it end to end: the product, the brand, the landing page, a web app and an Expo app for iOS and Android.

The rule that took the most thought

A mutual friend is the whole point, and also the riskiest thing to show. Name them too early and every swipe leaks who knows whom.

So the friend stays hidden until you both like each other. Before a match it's "someone you both know". After it, their name is the opener.

Two sample profile photos tilted toward each other

Someone liked you.

You both know someone

Sample profiles. The friend you have in common stays hidden until you both like each other.

The app

People shows you friends of your friends. A match names the friend you share, and the chat opens on them, so the first message is never "hey". The screens below are redrawn with sample profiles.

People: friends of your friends, one at a time
A match names the friend you share
The chat opens on that friend

The decisions that mattered

  • SQL as the API

    I started with Edge Functions out of habit. The agent wrote SQL more fluently than I do, so the API became Postgres functions behind row-level security, with auth.uid() doing the auth. Two round trips and an admin client became one RPC.

  • A swipe is one transaction

    record_swipe() records the swipe, clears the feed cache, checks for a match and opens the conversation, all or nothing. Blocking later became one guard at the top of the same function.

  • 497 KB down to 6 KB

    The landing page's one 3D shape started on Three.js. Rewritten in raw WebGL it does the same job for a fraction of the bytes, and with an agent writing it, the lower-level version cost no more time.

  • One table, not two

    For inviting a friend who isn't on the app yet, the agent proposed a separate invites table. I added one nullable column to friendships instead: one source of truth, no reconciliation when they sign up.

How I built it

I spent more tokens planning than building. Explain the product, refine the journey, let the agent draft the schema, then tune it by hand before anything is built. That last step is never optional.

I also wrote down what I got wrong: no shared colour config and no service layer, two habits I'd have had on day one writing it myself. The full story is in I Vibecoded a Full Stack App.