essay · on the rule · 6 min
a dating app without photos. yes really. here's how it works.
When we tell people Soulmate has no photos in the matching loop, the most common reaction is: how does that even work.
It works the way every other matching system works, except we removed one feature. The vector is text and voice. The cosine similarity is computed over those vectors. The score gets ranked. The top results show up on the discover surface. No part of the pipeline has read access to your photo.
This essay is the technical answer to the question.
what the matching engine sees
When you complete onboarding, the app produces a structured payload from your answers:
- Five written prompts. Free-text, roughly a hundred words each at the median.
- Ten ideology axes. Five-point Likert scales we collapse into a small numeric vector.
- Three values you marked from a long list. Concrete tags like 'gentleness' or 'curiosity.'
- Three passions you marked. Concrete tags like 'long walks' or 'climate work.'
- A thirty-second voice clip. We transcribe it server-side with Whisper. The audio is held in private storage, gated by row-level security, and the matching engine has no read access to the bytes. The matching engine sees the transcript.
- Three intents — friendship, relationship, community — as filter flags, not weights.
We concatenate the prompts and the voice transcript, pass them through an embedding model — currently OpenAI's text-embedding-3-small at 1536 dimensions — and store the resulting vector. The ideology answers become a small separate vector. The values and passions become bag-of-tag sets.
how matches are computed
Match score is a weighted sum:
- 0.4 × cosine similarity between the two embeddings (the main term).
- 0.2 × ideology proximity (one minus the normalised ideology distance).
- 0.15 × shared-value overlap (set intersection size, normalised).
- 0.15 × shared-passion overlap (same).
- 0.1 × intent-overlap score (a small bump if both souls marked the same intent).
Anything above 0.45 enters the candidate pool. The discover surface picks the top five for the day. There is no photo signal entering the score. The arithmetic does not have a face term.
where the photos actually live
Photos live in a separate Supabase bucket gated by row-level security. The bucket can be read by exactly two roles: the user who uploaded the photo, and another user with whom that uploader has a mutual vibe.
The matching service runs as a third role that does not appear in the access policy. There is no code path in the engine that calls into that bucket. We don't blur photos and downweight them; we just don't expose them to the layer that decides who you meet.
When two souls both tap 'vibe with' on each other, three things happen in the same transaction: a connection row is created, the photo access is granted simultaneously to both users, and an LLM-generated icebreaker is written. Until then, every avatar on the app is a gradient circle with the user's first initial.
what people get wrong about this
The most common misunderstanding: 'so the app is for ugly people.' No. The point of the rule is not to advantage people who would lose the photo competition. The point is that the photo competition was a bad ranking function for whether you'd actually click with someone.
The second misunderstanding: 'so it's catfishing-friendly.' No. Once a mutual vibe happens, you see the other person's photo before you talk. If they had three layers of filters on, you find out then, on both sides at the same time. We are not asking you to date without ever seeing someone. We are asking you to choose without seeing first.
The third misunderstanding: 'this is a gimmick.' Possibly. The bet is that 150 features per profile (five prompts plus ideology plus voice transcript) find your people better than the single feature of a photograph does. If the bet is wrong, the app fails. We are okay with that risk.
the small, honest part
Soulmate is in beta. The matching engine works in tests with seeded data. It has unit tests in `packages/core` you can read. We have a small number of real users and no mutual matches between strangers yet because the cohort is still small. The next month is about whether the engine works in the wild.
The door is at byvibration.com. The first thing it asks is what makes you most alive. There is no photo upload until the onboarding is otherwise complete, and even then the upload is gated until someone vibes with you. There is no swipe.