redor.blue
A global social-dilemma experiment — one irreversible choice, live results, no take-backs.
- React
- TypeScript
- Supabase
The premise
Every visitor makes one irreversible choice. If red is the majority, only those who chose red survive; if blue is the majority, everyone survives. You cannot communicate, and you cannot change your mind. One press, forever.
How it works
A vote POSTs to a serverless function that hashes the visitor's IP (SHA-256 + salt) before anything is stored — no raw IP ever touches the database — deduplicates within a 24-hour window on that hash, inserts the vote, and reads current totals. The results page polls every five seconds, and the survived / eliminated outcome is derived from the live majority on each poll, never persisted, so it always reflects the current state rather than the majority at vote time.
User votes → POST /api/vote
├─ IP hashed (SHA-256 + salt) — raw IP never stored
├─ 24h dedup check on the hash
├─ vote inserted → results recomputed
└─ outcome derived from current majority
/results polls GET /api/results every 5s
└─ "survived" recalculated live — never persistedEngineering highlights
- Privacy-preserving dedup — IPs are salted and SHA-256 hashed before storage; deduplication runs on the hash over a 24-hour window.
- Stateless serverless design — each API function is fully self-contained, with no shared in-memory state.
- Real-time results without WebSockets — the results page polls with stale-while-revalidate cache headers; simple, reliable, zero infrastructure overhead.
- 12 languages with RTL — browser-language auto-detection via i18next; Arabic triggers a full RTL layout through Tailwind's rtl: variants.
Stack
React 19 + TypeScript + Vite on the front end, Tailwind v4 and Framer Motion for the interface, Vercel serverless functions and Supabase (Postgres) on the back end, deployed on Vercel.