A Jeopardy! practice app built with Next.js, powered by thousands of real archive questions.
- Solo play — pick a category and answer questions one at a time with immediate feedback
- Score tracking — sign in to track your correct/total ratio across sessions
- Multiplayer — compete with up to 10 players in real-time (no account required)
- Smart answer judging — string rules handle exact matches; everything else is judged against the clue under Jeopardy rules by Jev (via OpenRouter), with verdicts cached per clue. Falls back to the rules if Jev is unavailable or unsure
Create a game and share the 6-character code (or QR code) with friends. Up to 10 players can join anonymously — no login needed.
Game settings (host configures before starting):
- 1–5 rounds
- 3–10 questions per round
- Final Jeopardy on/off
- Watch mode — host spectates instead of playing
Scoring — full value for answers within 10 seconds, decaying to 25% minimum by 30 seconds.
Flow:
- Host creates game → players join via code
- Each round: questions revealed one at a time, all players answer simultaneously
- Per-question results shown after each answer phase
- Leaderboard shown between rounds
- Optional Final Jeopardy: 20s wager phase → 60s question phase → reveal
Players who disconnect miss those questions (scored as wrong) but can rejoin and continue.
- Framework: Next.js 16 (App Router, TypeScript)
- Styling: Tailwind CSS v4
- Database / Auth: Supabase (Postgres + Realtime Broadcast)
- Hosting: Vercel
- Questions: J! Archive via internal Supabase
cluestable
npm install
npm run devCopy .env.example to .env.local and fill in your Supabase project URL and anon key.
NEXT_PUBLIC_SUPABASE_URL=
NEXT_PUBLIC_SUPABASE_ANON_KEY=
SUPABASE_SERVICE_ROLE_KEY= # server-only: judge route + clue importer
OPENROUTER_API_KEY= # server-only: Jev answer judging
Run in the Supabase SQL editor to create the verdict cache (server-only; RLS on with no policies, so only the service role can touch it):
create table answer_judgments (
clue_id bigint not null,
response_norm text not null,
correct boolean not null,
probability real not null,
created_at timestamptz default now(),
primary key (clue_id, response_norm)
);
alter table answer_judgments enable row level security;Compare rules-only vs. rules + Jev on the hand-labelled cases in scripts/judge-cases.mjs:
node scripts/judge-eval.mjs