The Black Box is a playful AI web app that takes any short piece of text and rewrites it through a randomly chosen absurd persona. The frontend is a React + Vite single-page app, and the backend is a Cloudflare Worker that calls Gemini, serves localized routes, and stores shareable results in Cloudflare KV.
- Accepts freeform user input and transforms it with a random persona such as a conspiracy theorist, noir detective, cat, bard, or alien anthropologist
- Supports 6 languages: English, Chinese, French, Spanish, Japanese, and Korean
- Generates localized home, privacy, and share routes
- Lets users create shareable result links backed by Cloudflare KV
- Adds SEO metadata and localized canonical/alternate tags at the worker layer
- React 19
- Vite 6
- TypeScript
- Tailwind CSS 4
- Motion
- Cloudflare Workers
- Cloudflare KV
- Gemini API
- Node.js
- npm
npm installCreate a local worker secrets file:
cp .dev.vars.example .dev.varsThen set at least:
GEMINI_API_KEY=your_key_hereOptional:
GEMINI_MODELis already set inwrangler.tomland defaults togemini-2.5-flash
Run the worker in one terminal:
npm run dev:workerRun the frontend in another:
npm run devOpen http://localhost:3000.
Vite proxies /api/* requests to the worker on http://localhost:8787, so both processes are required for the full app.
npm run devstarts the Vite frontend on port3000npm run dev:workerstarts the Cloudflare Worker on port8787npm run buildbuilds the frontend intodist/npm run deploybuilds the frontend and deploys the workernpm run previewpreviews the production frontend buildnpm run lintruns TypeScript type-checking withtsc --noEmit
Before the first deploy, make sure the Cloudflare resources and secrets are configured correctly.
The worker expects a KV namespace bound as BLACK-BOX-SHARE. The current binding is declared in wrangler.toml.
If you need a new namespace for your account/environment, create one and update the namespace id in wrangler.toml:
npx wrangler kv namespace create BLACK-BOX-SHAREwrangler secret put GEMINI_API_KEYnpm run deploysrc/ React app, localized UI, route helpers, components
worker/index.ts Cloudflare Worker entrypoint and API/SEO logic
public/ Static assets
wrangler.toml Worker config, KV binding, assets binding, runtime vars
- Maximum input length is
2000characters - Share links are stored in KV with a 90-day TTL
- The worker includes a simple in-memory IP rate limiter of
10requests per minute per worker instance - Share pages are intentionally marked
noindex - Persona prompt instructions are kept server-side; the client only sends a
personaId
- The React app handles input, loading states, result rendering, sharing, and language switching
- The worker exposes:
POST /api/generatePOST /api/shareGET /api/share/:id
- The worker also serves localized route redirects, robots/sitemap responses, and SEO metadata rewriting for HTML pages