← All articles

No. 04DNA Seed

Two phones, ninety seconds

In DNA Seed you swap your DNA in person. Here is how the app asks for a meeting rather than a link, and what it does and does not prove.

Vincent Porret

Co-founder and CEO · · 3 min read

Print 04, Braid. Drops and combs on a bath, pulled when the site is built.Point at it to drop ink.

DNA Seed is a social game you play in person. Every player carries a DNA, a code that is theirs alone, and collects the codes of the people they meet. The rule that makes the game is easy to say and harder to build: a swap should happen face to face, not through a link someone forwarded.

What we ruled out

A permanent QR code can be photographed and posted. A share link travels anywhere. A remote invite to swap is the opposite of the point. We set all three aside, along with a QR code on its own, and we dropped NFC too. What was left is a QR code that lives for ninety seconds, and Bluetooth.

Ninety seconds

When you choose to receive, a server function opens a swap session: a long random token, a short random nonce, and an expiry ninety seconds away. Your screen shows the token and the expiry as a QR code, with a countdown:

{ "v": 2, "type": "adn_exchange", "exchangeToken": "…", "expiresAt": "…" }

The code is not signed and does not need to be. It is only a key the server looks up, and the server trusts its own clock and its own records, not the code. At the same time, your phone starts advertising over Bluetooth a temporary service identifier derived from the nonce. The nonce is not in the QR code: it only goes out over the air.

The other phone has to hear yours

The person in front of you scans the code. Their phone checks that it has not expired, then listens for nearby phones for up to seven seconds. Only if it hears one does it ask the server to join the session, and the server checks that it heard the right phone. Then you both confirm on screen, and only then does the swap go through. If Bluetooth is off or not allowed on either phone, that phone says so and the swap cannot happen. There is no way round it with the QR code alone.

To be precise about what that proves: the phone that scans has to be within Bluetooth range of the phone that shows the code, inside a ninety-second window, and both players have to say yes. Bluetooth range is not a measured distance, and we do not claim it is.

Within Bluetooth range, inside ninety seconds, and two yeses. That is the bar we set.

The server writes, the phones read

The server checks the rest: the person scanning is signed in, the session exists, it has not been used, it has not expired, which is checked again when you both confirm, and nobody is scanning their own code. That last rule is enforced twice, in the function and by a constraint in the database. Players can read their swaps and delete their own, but never create or change one: row-level security leaves the inserts to the server functions alone.

A swap merges collections both ways. Each player gets the other’s DNA at once, then, a moment later, every other code the other carries, from a queue on the server. A unique index on carrier and code makes the merge idempotent: the same code never lands twice. Every code also remembers who passed it on and how many swaps it took to arrive, which is what draws its family tree.

A map without GPS

The map shows, country by country, how far a DNA has travelled. The app never reads your location: the country is the one each player declares on their profile. The map is there to say how far a DNA went, not where anyone is.

It is not a map SDK either. It is a custom painter in Flutter over the Natural Earth country outlines, in a plain longitude and latitude projection. One dependency fewer, and no map service is called to draw it.

Vincent