Project Info
This project did not submit a demo video on Devpost.
AI is the thing nowadays. Everyone in Cal Hacks has probably vibe coded something for their project. And it’s not just taking over tech; it’s affecting every industry. That means a new highly sought for skill is emerging in our society. That’s right, prompt engineering. So we thought… how can we prepare everyone for the future? Oh yeah, of course. Why not MAKE A GAME?... Introducing Impromptu! Each game, everyone gets the same topic - something tricky, weird, or creative. Your mission? Prompt the AI to give the best possible response to that topic. Once everyone submits their prompts, we unleash our AI judges, including personalities like AI Gordon Ramsay, who’s never afraid to tell you if you cooked or served up raw garbage. 🍳 What Inspired Us We were inspired by the sudden, massive rise of large language models like ChatGPT. We noticed that everyone was getting wildly different results, and it became clear that "prompt engineering" is a new, creative skill. We saw a fun opportunity to take this new skill and turn it into a hilarious, competitive party game, much in the spirit of Jackbox Games, but built for the AI generation. We wanted to answer the question: who is really the best at talking to machines? How We Built It Impromptu is a full-stack web application using Next.js. For the multiplayer functionality, we used Supabase Realtime to handle our realtime changes to the database. The backend consists of Next.js API Routes. These routes manage the core game logic, but most importantly, they securely handle the calls to two separate LLM APIs: one to generate the player's creative response and a second, specialized "Judge AI" to critically analyze and score all the submissions. We also used Mastra to add a “deep research” feature. The Challenges We Faced The challenges we faced were significant, as this project was ambitious on two fronts. First, for most of the team, this meant learning a brand new tech stack from scratch. Second, this was our first time making a multiplayer game, and we quickly learned that managing real-time game state, player turns, and asynchronous events across multiple clients was far more complex than we realized. We had two possible solutions to add functionality to update state in real time. We could use WebSockets, which would not be compatible with Next.js because when you deploy Next.js to a service like Vercel, they turn your backend into serverless functions. That means that nothing is running on one central server. Alternatively, we could use a realtime database like Supabase that makes it easy to store data and check for updates live. Since the backend is a third party service, it doesn’t matter where it’s hosted. This seemed like the more efficient approach, so we went with Supabase. However there were downsides to choosing a realtime database service. If we wanted to add any actual server side code, such as watching the database until all players have submitted a response to start AI judging, it wouldn’t be straightforward. The solution to that was to use Supabase Edge Functions which are small server actions that can be run when a certain condition is met. This is caused by a trigger on the Postgres database. In addition, there are countless race conditions that could happen with doing asynchronous/realtime operations like this (and that we probably have not spotted yet). For example, we encountered a bug where, when someone joined a game, we created a user profile in the database and tried to assign the player to the room at the same time. But you need to have the user profile created first to add them to a room, so if the room add happens first you’d result in an error. What We Learned Through this project, we learned a tremendous amount about modern, full-stack web development. We gained practical experience with the entire Next.js ecosystem, from building interactive React components to writing robust, serverless backend logic. We also learned the core principles of real-time application design and the complexities of state management in a multiplayer environment. Most interestingly, we learned about the nuances of AI prompting itself. It's one thing to prompt an AI for a creative answer, but it's a completely different and fascinating challenge to engineer a prompt that forces an AI to act as an impartial, critical judge and return a consistent, structured score. Built with We built the frontend using Next.js and React, the realtime database with Supabase Realtime, and the backend with Next.js API routes. We called the Google Gemini 2.0 Flash Experimental API, Anthropic’s Claude Sonnet 4.5, and OpenAI’s GPT 4o mini in the chat room interface so that users can experiment with different models.
Prompt Battle - Real-Time Multiplayer Setup Guide
A real-time multiplayer prompt competition game where two players compete with their prompts and Gemini AI judges the winner.
Features
- Real-time room-based multiplayer using Supabase Realtime
- Create or join game rooms with unique 6-digit codes
- Waiting room with ready status
- 3-2-1 countdown before battle starts
- 60-second timer for prompt submission
- Gemini AI judges prompts on creativity and quality
- Beautiful results screen with scores and AI reasoning
- Player statistics tracking (wins/losses)
Prerequisites
- Node.js 18+ installed
- A Supabase account (free tier works!)
- A Google Gemini API key (free tier available)
Step 1: Create Supabase Project
1.1 Sign Up and Create Project
- Go to https://supabase.com
- Click "Start your project" and sign up
- Create a new project:
- Name:
prompt-battle(or your choice) - Database Password: Create a strong password (save it!)
- Region: Choose closest to your location
- Plan: Free tier is fine
- Name:
- Wait 1-2 minutes for setup to complete
1.2 Run Database Schema
- In Supabase dashboard, click "SQL Editor" in the left sidebar
- Click "New query"
- Copy the entire contents of
supabase/schema.sqlfrom this project - Paste into the SQL Editor
- Click "Run" or press
Ctrl+Enter - You should see: "Success. No rows returned"
This creates all tables, security policies, indexes, and enables real-time subscriptions.
1.3 Get API Keys
-
Go to Settings → API in the left sidebar
-
Copy these three values:
Project URL: https://xxxxxxxxxxxxx.supabase.co anon/public key: eyJhbGci... service_role key: eyJhbGci... (keep this secret!)
1.4 Enable Authentication
- Go to Authentication → Providers
- Ensure Email provider is enabled
- For easier testing, go to Authentication → Settings:
- Disable "Confirm email" (enable later in production)
- Click Save
Step 2: Get Gemini API Key
- Go to https://aistudio.google.com/app/apikey
- Sign in with your Google account
- Click "Create API Key"
- Select "Create API key in new project" or choose existing
- Copy the API key
Step 3: Configure Environment Variables
- Create
.env.localfile in your project root:
cp .env.local.example .env.local
- Edit
.env.localwith your actual keys, e.g.:
# Supabase Configuration
NEXT_PUBLIC_SUPABASE_URL=https://xxxxxxxxxxxxx.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGci...your_anon_key
SUPABASE_SERVICE_ROLE_KEY=eyJhbGci...your_service_role_key
# Gemini AI Configuration
GEMINI_API_KEY=your_gemini_api_key_here
Important: Never commit .env.local to git! It's already in .gitignore.
Step 4: Deploy Edge Function to Supabase
4.1 Log in to Supabase through the CLI
npx supabase login
You should get either a browser link or a URL where you can enter a verification code.
4.2 Deploy the ai-judge function
This is the backend function that will be called when everyone's submitted their prompts. Select the Supabase project that you're using for this repo.
npx supabase functions deploy ai-judge
4.3 Import the secrets from your .env file onto the server.
npx supabase secrets set --env-file .env.local
4.4 Add SQL trigger
Copy the contents of the file supabase/judge_func_example.sql into the Supabase SQL editor. This is so when everyone's submitted a prompt, it will trigger the edge function.
Make sure to replace the edge function URL in the file with the one in Supabase dashboard > Edge Functions > copy your edge function URL in the table, and replace with your actual anon key.
Step 5: Install Dependencies
npm install
Step 6: Run the Development Server
npm run dev
Open http://localhost:3000 in your browser.
Step 7: Test the Game
Testing Requires Two Players
Since this is a multiplayer game, you need two browser sessions:
Browser 1 (Player 1)
- Open http://localhost:3000 in Incognito/Private mode
- Sign up with email (e.g.,
player1@test.com) - Click "Create New Room"
- Copy the 6-digit room code displayed
Browser 2 (Player 2)
- Open http://localhost:3000 in a different browser or regular mode
- Sign up with different email (e.g.,
player2@test.com) - Click "Join Room"
- Enter the room code from Player 1
Play the Game
- Both players click "Ready"
- Watch the 3-2-1 countdown
- Submit your best prompts within 60 seconds
- Wait for Gemini AI to judge
- View results with scores and reasoning!
Project Structure
├── app/
│ ├── api/
│ │ ├── judge/route.ts # Gemini AI judging endpoint
│ │ └── rooms/
│ │ ├── create/route.ts # Create game room
│ │ ├── join/route.ts # Join existing room
│ │ ├── ready/route.ts # Toggle ready status
│ │ └── submit-prompt/route.ts # Submit prompt
│ ├── room/[roomCode]/page.tsx # Dynamic room page
│ ├── layout.tsx # Root layout
│ └── page.tsx # Home page
├── components/
│ ├── BattleArena.tsx # Battle UI with timer
│ ├── Results.tsx # Results screen
│ └── RoomLobby.tsx # Waiting room
├── lib/
│ ├── supabase/
│ │ ├── client.ts # Browser client
│ │ ├── server.ts # Server client
│ │ └── admin.ts # Admin client
│ └── types/
│ └── database.types.ts # TypeScript types
└── supabase/
└── schema.sql # Database schema
How It Works
Game Flow
- Room Creation: Host creates a room → unique 6-digit code generated
- Joining: Other player joins with room code
- Lobby: Both players mark ready → auto-starts when all ready
- Countdown: 3-2-1 countdown animation
- Battle: 60-second timer, both submit prompts
- Judging: Gemini AI evaluates based on:
- Creativity and originality
- Clarity and specificity
- Engagement potential
- Overall quality
- Results: Scores (0-100), winner declared, AI reasoning shown
Real-Time Features
The app uses Supabase Realtime for:
- Room status updates (waiting → countdown → playing → finished)
- Player ready status
- Prompt submissions
- Results broadcasting
All participants see updates instantly without page refresh!
Database Tables
profiles- User profiles with username, wins, lossesgame_rooms- Active game rooms with statusgame_participants- Players in each roomgame_results- Battle outcomes with AI reasoning
Customization
Change Battle Duration
Edit countdown_duration in supabase/schema.sql:
countdown_duration INTEGER DEFAULT 60 -- Change to 120 for 2 minutes
Then update the room in Supabase dashboard or re-run schema.
Change Max Players
Currently supports 2 players. To change:
max_players INTEGER DEFAULT 2 -- Change to 4 for 4 players
Customize AI Judging
Edit the judging prompt in app/api/judge/route.ts to change criteria.
Troubleshooting
"Unauthorized" Errors
- Verify users are signed up and logged in
- Check
.env.localhas correct Supabase keys - Ensure tables exist in Supabase (run schema.sql)
Real-time Not Working
- Check browser console for errors
- Verify Realtime is enabled: SQL Editor → run:
ALTER PUBLICATION supabase_realtime ADD TABLE game_rooms; ALTER PUBLICATION supabase_realtime ADD TABLE game_participants; ALTER PUBLICATION supabase_realtime ADD TABLE game_results;
Gemini API Errors
- Verify API key in
.env.local - Check quota at https://aistudio.google.com
- Ensure you're using a valid Gemini model
Database Errors
- Ensure complete schema.sql was run
- Check Row Level Security (RLS) policies are enabled
- Verify foreign key relationships
Next Steps & Ideas
- Add user profiles with avatars
- Implement ELO rating system
- Add match history and leaderboards
- Create tournament brackets
- Add voice chat during battles
- Implement themes/categories for prompts
- Add sound effects and animations
- Mobile app version
Support
Happy battling! 🎮✨
Analysis
View
Metric
- 59
- 40
- 19
- 18
Figures cover GitHub contributors during the hackathon window. A co-authored commit counts in full for each author, so per-member totals add up to more than the whole-team figures.
Technology
- AnthropicIn code
- CSSIn code
- Google GeminiIn code
- JavaScriptIn code
- Next.jsIn code
- OpenAIIn code
- ReactIn code
- SQLIn code
- SupabaseIn code
- Tailwind CSSIn code
- TypeScriptIn code
- Vercel AI SDKIn code
12 of 12 appear in the indexed code.
AI coding agents
- Claude CodeCommits
Detected from committed agent config files and commit authorship. Absence of a signal is not proof an agent was unused.
Codebase size
Source size
358 KB
Source files
99
Counts recognized source files only; vendored directories, binaries and lockfiles are excluded, so this is smaller than the repository on disk.
Repository
Rmandal01/impromptu
121 files · 1.4 MB · @ a187155
Structure
Interface
71 files · 59%Screens, components and styles rendered to the user.
+3 moreAPI & routing
8 files · 7%Request entry points: routes, handlers and controllers.
Application logic
6 files · 5%Domain rules, services and shared utilities.
Data & schema
13 files · 11%Schema definitions, migrations and data access.
Supporting
Layers are inferred from where files sit in the tree, not from reading the code. A project that names its directories unconventionally will read oddly here — open the file browser to check anything the diagram implies.
Languages
- TypeScript89%
- Markdown4%
- SQL3%
- CSS3%
- JavaScript0%
Share of indexed source by file size. Binary and vendored files are excluded.
Dependencies
package.json
npm · 73- @ai-sdk/anthropic
- @ai-sdk/google
- @ai-sdk/openai
- @ai-sdk/react
- @google/generative-ai
- @hookform/resolvers
- @mastra/core
- @radix-ui/react-accordion
- @radix-ui/react-alert-dialog
- @radix-ui/react-aspect-ratio
- @radix-ui/react-avatar
- @radix-ui/react-checkbox
- @radix-ui/react-collapsible
- @radix-ui/react-context-menu
- @radix-ui/react-dialog
- @radix-ui/react-dropdown-menu
- @radix-ui/react-hover-card
- @radix-ui/react-label
- +55 more
Declared in the repository’s manifests at the indexed commit. A declared package is not proof it is used, and runtime dependencies are listed first.
This project’s features have not been analysed yet.
Export this project's context (description, README, evidence, key source files) to chat with an AI agent elsewhere.