Skip to content

Repository files navigation

fifty-fifty-web

Fifty-Fifty — the blind voice arena. Two AI voices read your words with no labels and no logos; you crown the one that sounds human, and only then do we reveal who made it. A running scoreboard (win rate + Elo) tracks the most popular engine over time.

Built with Next.js 15 (App Router), Tailwind CSS v4, and framer-motion, styled after the speechify.ai design system: monochrome ink-on-paper, tight display tracking, and the signature animated waveform.

Blind by construction

The browser cannot cheat, even by reading the source:

  • Pre-vote types (lib/types.ts) contain no provider fields — just opaque sample IDs, TTFB, and estimated cost.
  • Audio arrives as anonymous bytes via /api/audio/[id].
  • Provider names enter the client only in the vote response, after the verdict is recorded server-side by the relay.
  • A/B order is shuffled by the relay per battle.

Architecture

Browser ──(same-origin fetch)──▶ Next.js serverless routes ──(Bearer session)──▶ fifty-fifty-relay
                                  /api/battle      POST /v1/battles
                                  /api/audio/[id]  GET  /v1/audio/:id
                                  /api/vote        POST /v1/battles/:id/vote
                                  /api/leaderboard GET  /v1/leaderboard

The relay (separate repo: fifty-fifty-relay) holds every provider key and all provider identities. The web app authenticates to it with per-visitor HMAC-signed session tokens, minted server-side using the shared RELAY_API_KEY and kept in an httpOnly cookie — no relay credentials or tokens are ever exposed to client JavaScript.

Run it

Start the relay first (see its README), then:

cp .env.example .env.local   # point at the relay + shared key
npm install
npm run dev                  # http://localhost:3000

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages