- TypeScript 85.1%
- PLpgSQL 14.7%
- JavaScript 0.2%
| .forgejo/workflows | ||
| app | ||
| assets | ||
| components | ||
| lib | ||
| screens | ||
| supabase | ||
| types | ||
| .env.example | ||
| .gitignore | ||
| .npmrc | ||
| app.json | ||
| eas.json | ||
| eslint.config.js | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| tsconfig.json | ||
Challengers Draft
A mobile app (iOS, Android, Web) as a digital draft companion for the board game Challengers!. Multiple players can create a shared draft session, draw cards from various sets, and build their hand — without physically shuffling and distributing cards.
Features
- Session system — create or join a session via a 6-character code
- Real-time sync — all participants see deck changes live via Supabase Realtime
- Three decks (A / B / C) — correspond to the difficulty tiers in the original game
- Draft flow — draw 5 cards, pick the ones you want, discard the rest; redrawing is supported
- Draw to hand — draw a single card directly from a deck into your hand
- Set selection — admin chooses which of the 14 available sets are included before the draft starts
- Automatic reshuffle — when a deck runs out, discarded cards are automatically reshuffled back in
- Card preview — cards are rendered as sprites from the original card illustrations
- Anonymous authentication — no account required, uses Supabase Anonymous Auth
Tech Stack
| Layer | Technology |
|---|---|
| Framework | Expo (React Native, New Architecture) |
| Routing | Expo Router (file-based) |
| Backend | Supabase (Postgres, Auth, Realtime) |
| Language | TypeScript |
| Platforms | iOS, Android, Web |
Prerequisites
- Node.js >= 18
- Expo CLI (
npm install -g expo-cli) - Supabase CLI (for local development)
- A Supabase project (cloud or local)
Setup
1. Install dependencies
npm install
2. Set environment variables
Copy .env.example to .env and fill in your values:
cp .env.example .env
EXPO_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
EXPO_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
3. Set up the database
Run migrations against your Supabase project:
supabase link --project-ref <your-project-ref>
supabase db push
Alternatively, run locally with supabase start and then supabase db reset.
4. Start the app
npm start # Expo dev server (QR code for Expo Go)
npm run ios # iOS Simulator
npm run android # Android Emulator
npm run web # Browser
Project Structure
.
+-- app/
| +-- _layout.tsx # Root layout, anonymous authentication
| +-- index.tsx # Home screen: create / join session
| +-- session/
| +-- [id].tsx # Session route (lobby or draft depending on status)
+-- screens/
| +-- SessionLobby.tsx # Waiting room: participants, set selection, start draft
| +-- SessionDraft.tsx # Draft view: draw cards, pick, manage hand
+-- components/
| +-- SpriteCard.tsx # Renders a card from a sprite sheet
+-- lib/
| +-- supabase.ts # Supabase client
| +-- session.ts # Session actions (offerCards, keepCards, ...)
| +-- types.ts # Shared TypeScript types
+-- supabase/
| +-- migrations/
| +-- ..._schema.sql # Tables, enums, RLS policies, Realtime
| +-- ..._card_data.sql# Card data for all sets
| +-- ..._rpcs.sql # SECURITY DEFINER functions
+-- assets/
+-- images/ # Sprite sheets (sheet_game_cards-0..3.jpg)
+-- icons/ # App icons, splash screen
Database Schema
users id, name
sessions id, code, admin_id, status (waiting | drafting | finished)
participants id, session_id, user_id
card_types id, sheet, row, column, count, set, level (S|A|B|C)
card_assignment id, card_type_id, owner, session_id, card_position (deck|offered|player|discarded)
All write operations on card_assignment and sessions go exclusively through SECURITY DEFINER RPCs; the tables themselves are read-only for the client via RLS.
RPCs
| Function | Description |
|---|---|
create_session(code) |
Creates a session and adds the creator as admin participant |
initialize_draft(session_id, sets) |
Admin: inserts all cards as deck cards, sets status to drafting |
offer_cards(session_id, level, count) |
Draws N random cards from a deck (idempotent) |
keep_cards(session_id, card_ids) |
Moves offered cards into the player's hand |
discard_cards(session_id, card_ids) |
Discards cards (offered or player -> discarded) |
leave_session(session_id) |
Player leaves; transfers admin role or deletes session if last player |
delete_session(session_id) |
Admin: deletes session including all dependent data (CASCADE) |
Card Sets
14 sets are available (corresponding to the Challengers! expansions):
City Rainbow Castle Fairground Space Film Studio Haunted House Shipwreck Enchanted Forest Toy Store Mountain Peak Secret Lab University Beach Club
Draft Flow
- Players open the app — anonymous auth happens automatically
- Enter a name, then create a session or join one via code
- Lobby: admin selects sets and starts the draft
- Draft: each player draws cards independently
- Choose a deck -> 5 cards are offered
- Tap desired cards (highlighted in blue)
- Keep & discard: confirm selection, the rest go to the discard pile
- Redraw: keep already selected cards, draw new ones for the rest
- +1 Hand: draw one card directly into your hand (no offer shown)
- Remove a card from hand: tap the red X on the card
- When a deck runs empty, discarded cards are automatically reshuffled back in
Deployment
Builds are created via EAS Build:
eas build --platform ios
eas build --platform android
The EAS project configuration lives in eas.json.