🍻 Juomapeli
July 25, 2026 · View on GitHub
🍻 Juomapeli
A fast, browser-based drinking card game for Finnish game nights.
About
Juomapeli draws randomized Finnish-language challenge cards for a group of players. Start a quick game immediately or add player names to track turns and ongoing card effects.
Features
- 235 challenge cards across four visible rarity tiers
- Quick play without player setup
- Player mode with automatic turn tracking
- Continuous effects tracked per player
- No immediate repeats from the recent card history
- Resume an interrupted game from the start screen
- Keyboard controls — the space bar draws the next card, Escape closes overlays
- Dark, mobile-first UI that scales from a 320 px phone to a wide desktop
Interface
The UI is built for a dim room and a phone passed around a table:
- Dark theme with a neon accent, so nobody gets a white flash at midnight
- The card is the screen — tap it anywhere to draw, or use the button below it
- Rarity is visible: each card is tinted by tier (
Tavallinen,Epätavallinen,Harvinainen,Legendaarinen), and legendary draws get a shimmer - Mobile puts turn order in a scrolling rail and moves the player and effect lists into bottom sheets
- Desktop shows those lists as side rails flanking the card
- Text and controls meet WCAG AA contrast, respect
prefers-reduced-motion, and honour safe-area insets
Getting started
Requirements
- Node.js
- npm
Installation
git clone https://github.com/roqqq3/card-game.git
cd card-game
npm ci
Start the development server:
npm run dev
Open http://localhost:3000 in your browser. The page reloads automatically when you edit the source files.
Available commands
| Command | Description |
|---|---|
npm run dev | Start the development server |
npm run build | Create an optimized production build in build/ |
npm start | Serve the existing production build |
npm test | Run tests in interactive watch mode |
To run the production version locally:
npm run build
npm start
Adding cards
Cards live in src/cards/cardsData.js. Add a new object to cardsDataWithoutIds:
{
"name": "Example card",
"description": "Describe the challenge here.",
"rarity": 20,
"continuous": false
}
| Field | Meaning |
|---|---|
name | Short title displayed on the card |
description | Instructions shown to the players |
rarity | Draw threshold from 0 (common) to 100 (extremely rare) |
continuous | Whether the effect remains active for the assigned player |
Card IDs are generated automatically from their position in the array, so they should not be added manually.
The rarity value also drives the card's appearance. The tier boundaries live in
src/cards/rarity.ts:
rarity | Tier |
|---|---|
0–19 | Tavallinen |
20–49 | Epätavallinen |
50–69 | Harvinainen |
70+ | Legendaarinen |
Project structure
src/
├── cards/ # Card data, types and rarity tiers
├── components/ # Game screens and reusable UI components
├── copy/ # Start-screen quotes
├── types/ # Shared TypeScript types
├── utils/ # Session persistence and player-name rules
├── App.css # App shell layout (menu column, game board grid)
├── index.css # Design tokens, reset and global styles
├── App.tsx # Game state, card selection, keyboard handling
└── index.tsx # Application entry point
Styling is split deliberately: index.css owns the design tokens (colour,
type, radii, motion) and App.css owns the page-level layout, while individual
components use styled-components that read those tokens as CSS variables.