We build our products and keep them running.

Fantagram is an AI-native team that has built deep expertise in three fields: data with KTRENZ, commerce with Welike, and private communication with Krypton.

[email protected]

01Products

  1. KTRENZ

    Status: Live at ktrenz.com

    A KTRENZ data report: the headline “41% of the K-pop releases KTRENZ tracked in the last 90 days were 3rd-gen acts”, the figure 41% and a bar chart of releases by generation.
    ktrenz.com, a data report

    An English-first K-culture data platform and publication that measures the Korean wave.

    • Trend ranks artists by 7-day velocity across Korean search volume, YouTube, press coverage and challenges.
    • Open data is served through four public REST endpoints that need no key.
    • K-Track counts, from KTRENZ’s own server logs, which answer engines fetch each release page.
    Platform
    Web, responsive
    Stack
    • Next.js 14, React 18, TypeScript
    • Supabase (Postgres)
    • Cloudflare Pages and Workers

    ktrenz.comHow it works

  2. Welike

    Status: Pre-launch; sign-up open

    The Welike page for creators: the headline “Get invited to K-beauty you’d actually post” on a dark background, above a sentence on matching creators to K-beauty campaigns.
    welike.show, the page for creators

    A managed platform that lets K-beauty brands sell on US TikTok Shop without a US entity, US logistics or a local team.

    • Pairs brands with US TikTok creators and handles invitations, free samples and commission.
    • Checks each video for FTC #ad disclosure and FDA/MoCRA cosmetic-claim rules before it goes live.
    • Connects to the TikTok Shop Open API (OAuth, webhooks) and runs pay-ins and payouts on Stripe Connect.

    Built and maintained by Fantagram. Welike is operated by Milestone Innovation Labs Inc. (United States), the merchant of record and TikTok Shop seller, and 주식회사 위라이크 (Korea).

    Platform
    Web: brand app (Korean), creator app (English)
    Stack
    • React 18, Vite, TypeScript
    • Supabase (Postgres, 18 Edge Functions)
    • Cloudflare Pages

    welike.showHow it works

  3. Krypton

    Status: iOS in TestFlight; Android built

    The Connections section of krypton.today on a phone: a short explanation of connections and the 2nd degree, above a map of people linked to “Me”. The Sealed section of krypton.today on a phone: text on end-to-end encryption, above a panel that shows a name and a bio as ciphertext.
    krypton.today on a phone

    An invitation-only social app for people who actually know each other.

    • End-to-end encrypted posts, replies, photos, videos and profiles. Our servers can’t read them.
    • No phone number or email to join. The account is a key made on your phone. With recovery set up, your PIN and the connections you entrusted with key pieces get it back if you lose the phone.
    • No ads. Screen capture is blocked.
    Platform
    iOS, Android
    Stack
    • Expo, React Native, TypeScript
    • Rust crypto core, Swift, Kotlin
    • Supabase
    • Cloudflare Workers and R2

    krypton.todayHow it worksSecurity design

02How they work

KTRENZ

KTRENZ collects public data on a schedule, measures it, and publishes the results on its site and as open data.

From public sources to open data
  1. 1

    Sources. YouTube, Naver, X, TikTok, Ticketmaster, TMDB and Korean public data, plus KTRENZ’s own server logs.

  2. 2

    Collect. A Cloudflare Workers cron fires every minute and every 10 minutes and starts 17 kinds of scheduled job, which write to Postgres on Supabase.

  3. 3

    Measure. Trend ranks artists by 7-day velocity across Korean search volume, YouTube, press coverage and challenges. K-Track counts which answer engines fetch each release page, read from KTRENZ’s own server logs (dashed line).

  4. 4

    Publish. ktrenz.com; four REST endpoints that need no key; and a remote MCP server and an npm package, listed in the official MCP Registry.

Welike

Welike lets a K-beauty brand sell on US TikTok Shop through US creators, with checks before a brand or a video goes live. Welike hasn’t launched yet; the steps below are what the built product does.

From product listing to payout
  1. 1

    Brand. Lists its products in the Korean brand web app, or imports them from Amazon.

  2. 2

    Check. A compliance checklist for each brand, and a two-stage screen of its documents. The screen is advisory; a person decides.

  3. 3

    Creators. US creators are matched and invited in the English creator app. They get free samples and earn commission.

  4. 4

    Check. Each creator video is checked for FTC #ad disclosure and FDA/MoCRA cosmetic-claim rules before it goes live.

  5. 5

    TikTok Shop. Orders come in through the TikTok Shop Open API, with OAuth and webhooks.

  6. 6

    Stripe. Pay-ins and payouts run on Stripe Connect.

Krypton

Krypton seals what people write on their own phones.

Sealing a post
  1. 1

    The writer’s phone makes a new content key inside its Rust core.

  2. 2

    It encrypts the post with that key: text, photos and videos. Text is padded to a size step first, so its exact length doesn’t show. Profiles are sealed on the phone too.

  3. 3

    It seals the content key to each reader’s encryption key, one 104-byte envelope per reader.

  4. 4

    The reader’s phone opens its own envelope with its encryption key, inside its Rust core.

  5. 5

    It decrypts the post.

In between, the server stores ciphertext and envelopes and passes them on. It sees who sent to whom and when, but it cannot read posts, replies, photos, videos, names or profiles. The full list is under Security design.

Getting an account back on a new phone
  • Set up. You pick a 6-digit PIN and 2 to 7 connections. Your phone seals your account key and encryption key into a backup with a secret S made from two halves, T and U. T is split into key pieces, any 2 of which rebuild it, and each piece is sealed to one connection. Our server keeps U, the backup and the sealed pieces; only each connection’s phone can open its own. The phone sends only a stretched form of the PIN, and the server counts wrong tries.

  • Lose your phone. A connection sends you a one-time recovery link. On the new phone you enter your PIN; holders confirm it’s you by phone, open their piece and reseal it to the new phone’s key.

  • Wait. The server releases U and the backup once 2 holders have approved and 48 hours have passed since the right PIN, or, without the PIN (if you picked at least 4 connections), once 4 holders have approved and 14 days have passed. Your old phone is told and can cancel. Five wrong PINs lock recovery for a day.

  • Back in. The new phone rebuilds S in its Rust core, opens the backup, and signs a new device key with the recovered account key. Older devices are signed out.

  • No one can do it alone. One holder can’t. Holders can’t without U, which the server releases only on the terms above. The server can’t without T: holders reseal their pieces to the new phone’s key as our server passes it on, but only after typing in the six-digit number read out from the new phone’s screen on the call, and a key swapped in by the server matches that number with a chance of one in a million per holder. This check does not stop someone imitating your voice on the call, does not cover a holder still on an old version of the app, and does not catch a holder’s key swapped at setup until recipient checks are switched on.

Joining by invitation
  1. 1

    Request. Your phone makes your keys; there is no phone number or email. You send an invitation request to a member you know, as a link or a QR code. The link carries no name: your name and bio are sealed with a key derived from the secret after the # in the link, which our servers never get, and later steps carry your name only sealed or as a salted hash.

  2. 2

    Invite and confirm. Current members, or the Krypton team, invite you and confirm you. As a rule, two members invite you together and each confirms you; until Krypton reaches a set number of members, one is enough. Invitations and confirmations are signed with their own keys; our servers record them. Until invitations without names are switched on, an invitation link carries the inviter’s name after the #.

  3. 3

    Member. You are in. Those who confirmed you are your sponsors and appear on your card.

03Security design

Krypton’s encryption runs in one Rust core that iOS and Android share.

Primitives in the Rust core
PrimitiveUsed for
X25519Sealing content keys to readers. Each envelope uses a fresh one-time key pair and the reader’s public key. All-zero shared secrets are rejected.
Ed25519The account identity key and each device key. The account key signs each device’s certificate and the account’s encryption key.
XChaCha20-Poly1305Encrypting and authenticating everything sealed: post bodies, envelopes, wrapped keys, the recovery backup, photos and videos. Random 24-byte nonces; a file’s chunks use a random base nonce with the chunk number.
HKDF-SHA256Deriving each envelope’s key from the X25519 shared secret, salted with both public keys, and the recovery secret from its two halves. Each use has its own label.
Shamir secret sharing over GF(28)Splitting one half of the recovery secret into key pieces. The field arithmetic runs in constant time, without lookup tables.
OS random generatorEvery key, nonce and key-piece coefficient.
Where the keys are
Private keys
Four slots inside the Rust core: account (Ed25519), device (Ed25519), encryption (X25519) and a temporary recovery key (X25519).
Content keys
A new random key for each item, held inside the core. The app gets an opaque handle that is not key material.
At rest
iOS Keychain; on Android, encrypted with a key held in Android Keystore. A private key leaves the core only for the native wrapper to store it there.
JavaScript
No call returns a private key to the app’s JavaScript, and a boundary check scans the app code for key handling.
Our servers
Public keys. For recovery: the backup, the server half U, and each connection’s key piece, sealed so that only that connection’s phone can open it. None of these opens the backup without T (see recovery, above). Recovery links are kept only as a keyed hash (HMAC) and erased three days after the request ends. Also the keys of the Krypton team’s web account, locked with a passphrase our servers don’t have.
Key checks
Phones get each other’s public keys from our servers and check that each encryption key is signed by its account key. There is no in-app way to compare keys yet, so this relies on our servers handing out the right account keys. Checks on each recipient (a chain of member certificates back to the founders and the Krypton team, both signatures on each connection, and for 2nd-degree connections a path through a checked connection) are built but not switched on yet; until they are, phones could also seal to a fake member, connection or key added on our servers. In recovery, holders also check the new phone’s key with a six-digit number on the call.
What Krypton’s servers can and cannot see

Cannot read

  • Posts, replies, photos and videos. Files are stored as ciphertext.
  • Names, one-line bios and profile photos. A card (name, one-line bio, sponsors’ account numbers and a coarse mosaic of the photo) and a half-blurred photo are sealed separately to each connection when the card’s owner picks “1st only”, and to each connection and 2nd-degree connection when the owner picks “Up to 2nd” (the default, though founders start at “Everyone”) or “Everyone”. A card set to “Everyone” is also sealed with the member key, so it opens to every member, including the Krypton team’s own account; anyone with one member’s key and a copy of our database can read all such cards. The half-blurred photo never goes beyond 2nd-degree connections, and the photo itself opens only to connections. When the owner narrows the range, our servers at once delete what was sealed with the member key and, for “1st only”, the envelopes for anyone who isn’t a connection. The phone then reseals the card with a new key, keeping the photo keys so the photos still open. Keys people already received and anything they already saw while the range was wider cannot be taken back. For a card set to “1st only”, our servers refuse envelopes for anyone who isn’t a connection, whichever version of the app sends them. The range applies only to this card, not to cards sent to one person (next item). An earlier version of the app shows only two settings, the narrower one matching “Up to 2nd”, and choosing either there ends “1st only”. A card uploaded from a version with no range setting stays sealed with the member key until it is uploaded again from the updated app. Taking the member key away from the team’s account is built but not switched on yet.
  • Cards sent to one person. A card that goes with a connection request, to people in a chat, or with a screenshot or photo-save notice is sealed separately to each person who gets it. A QR code, connection link or invitation request carries the card sealed with a key derived from the secret after the # in the link, which our servers never get; until it is deleted, anyone holding both the link and a copy of our database can open it. These copies are deleted when the request ends, when a connection link expires after a day, or when the person leaves the chat; requests and notices are cleared after 30 days. Invitation links without names are built but not switched on yet; today an invitation link carries the inviter’s name after the #.
  • Link previews. The writer’s phone makes them and seals them with the post.
  • The exact length of a post. Text is padded to size steps that start at 256 bytes.
  • What a new message says. The server sends a generic line with a sealed copy; an unlocked iPhone opens the copy to show who wrote.
  • Phone numbers and email addresses. They are never collected.

Can see

  • A random account number, membership status and public keys for each account, and the range its card is set to.
  • Who is connected to whom, who invited and confirmed whom, and when.
  • Who passed a post on to whom.
  • Who holds an envelope for each post, who is in each chat, and when people joined or left it.
  • The author, recipients and time of each post and reply.
  • Blocks, reports, and device tokens for notifications.
  • Screenshot attempts and photo saves: who, on whose post or page, and when.
  • File sizes. Photos and videos are not padded.
  • A reported post and its author’s name, opened to us by the person who reports it.
  • IP addresses and request times, in our hosting providers’ access logs. For sign-ups without an invitation, our database keeps a keyed hash of the IP for two days to limit sign-ups.
Implementation and checks
Memory
Inside the Rust core, keys and decrypted bytes live in buffers that are overwritten with zeros when released, including the buffers it hands to the Swift and Kotlin wrappers. Decrypted photos and videos are kept in a cache on the phone so they open without being decrypted again; the cache is cleared on sign-out and when the account is deleted.
Unsafe code
The crate denies unsafe. Only the two boundary files, for Swift (C ABI) and Kotlin (JNI), allow it.
Boundary
Every C entry point that runs core code catches panics, so a failure inside the core returns an error code to the app.
Large files
Encrypted in authenticated 64 KiB chunks. Truncating, reordering, extending or splicing a file makes it fail, and the decrypted file appears only after the whole file checks; a failed file leaves nothing behind.
Rust tests
22: 19 unit tests, 2 tests against the shared test vectors, and 1 check that the C header matches the exported functions.
Test vectors
The Rust core and the app’s JavaScript development core use the same byte format, and each must open the other’s fixed test vectors.
Review
An internal review before launch covered seven areas: database permissions, server functions, rate limits, media storage, the app, operator tools and secrets. It read the code and tried attacks on a local copy of the servers. There has been no independent audit yet.

04Engineering

Platforms
Web, iOS, Android
Languages
TypeScript, SQL, Rust, Swift, Kotlin
Runs on
Cloudflare, Supabase (Postgres)
Automated tests
More than 5,000 test cases across the three codebases
  • Cross-platform mobileExpo and React Native apps with native Swift (iOS) and Kotlin (Android) modules.Used in: Krypton
  • Applied cryptographyOne Rust encryption core shared by iOS and Android, keys held in Keychain and Keystore, and social key recovery with Shamir secret sharing.Used in: Krypton
  • Web platforms at the edgeNext.js on the edge runtime and a React app with Pages Functions, both deployed on Cloudflare.Used in: KTRENZ, Welike
  • Data pipelines and measurementScheduled jobs on Cloudflare Workers that collect from YouTube, Naver, X, TikTok, Ticketmaster, TMDB and Korean public data, and 7-day velocity rankings built from them.Used in: KTRENZ
  • Public APIsREST endpoints that need no key, a remote MCP server and an npm package, listed in the official MCP Registry.Used in: KTRENZ
  • Commerce and paymentsTikTok Shop Open API, Stripe Connect payouts, Stripe subscriptions, and App Store subscriptions with server notifications.Used in: KTRENZ, Welike, Krypton
  • Compliance toolingChecks for FTC ad disclosure and FDA/MoCRA cosmetic-claim rules, and a two-stage screen of brand documents (advisory; a person decides).Used in: Welike
  • Postgres backendsSupabase Postgres with row-level security, Edge Functions and 741 managed migrations.Used in: KTRENZ, Welike, Krypton
  • Multilingual productsKorean, English and Japanese in one app; a Korean brand app next to an English creator app.Used in: Welike, Krypton

05Contact

Partnerships, press and general questions.

[email protected]

For product questions, use each product’s site.