Skip to content

iteplenky/hat-game

Repository files navigation

Hat Game 🎩

Real-time multiplayer word guessing game built with Go and React

Go Version React License PRs Welcome

FeaturesDemoQuick StartAPIContributing


📖 About

Hat Game is a digital version of the classic party game where players guess words/names across three rounds with different explanation rules. Built with real-time WebSocket communication, it supports 2-8 players with spectator mode, game history, and mobile-friendly responsive design.

Inspired by: The traditional "Hat" party game (also known as "Celebrities" or "Fishbowl")

✨ Features

🎮 Game Mechanics

  • 3 Rounds with Different Rules
    • Round 1: Explain with words (unlimited)
    • Round 2: Explain with gestures only
    • Round 3: Explain with one word only
  • 2-8 Players with automatic team rotation
  • 60-Second Turns with live countdown timer
  • Seating Arrangement — host can reorder players before game starts
  • Animated Table — toggle between round/square visualization
  • Live Scoreboard — per-round and total scores

🌐 Multiplayer

  • Real-time WebSocket communication with auto-reconnect
  • Spectator Mode — watch games and send emoji reactions (👏 😂 😮 🔥)
  • Quick Join Links — shareable /join/{roomId} URLs
  • Password-Protected Rooms — private games
  • Presence Detection — see who's online

👤 User Experience

  • Guest Mode — play without registration
  • JWT Authentication — optional account creation for stats tracking
  • Game History — track personal stats and recent games
  • Sound Effects — countdown beeps and turn notifications
  • Mobile-Friendly — fully responsive design
  • Dark Mode Ready — UI prepared for theme switching

🎬 Demo

Note: Add screenshots/GIFs of gameplay here when available

# Typical game flow:
Lobby → Enter Cards → Seating → Rules → Round 1 → Round 2 → Round 3 → Final Scores

Live Demo: (Coming soon)

🛠 Tech Stack

Layer Technology
Backend Go 1.24, gorilla/websocket, zerolog
Database PostgreSQL (pgx/v5, sqlc), Redis (go-redis)
Frontend React 18, TypeScript, Vite, TailwindCSS
State Zustand (client), Redis (server)
Testing Go testing, Playwright E2E
Auth JWT (golang-jwt), bcrypt

📁 Architecture

hat-game/
├── cmd/server/              # Application entry point
├── internal/
│   ├── app/                 # Server initialization
│   ├── config/              # Environment configuration
│   ├── domain/              # Business logic (DDD)
│   │   ├── auth/            # Authentication service
│   │   ├── game/            # Game mechanics & state machine
│   │   └── room/            # Room management
│   ├── http/                # Middleware (auth, rate limiting)
│   ├── storage/
│   │   ├── postgres/        # User persistence, game history
│   │   └── redis/           # Active game state, sessions
│   └── transport/
│       ├── rest/            # HTTP handlers, DTOs
│       └── ws/              # WebSocket hub & connections
├── frontend/                # React SPA (Feature-Sliced Design)
│   ├── src/
│   │   ├── app/             # Router, providers
│   │   ├── entities/        # Game, Player models
│   │   ├── features/        # Auth, Room logic
│   │   ├── pages/           # Landing, Room, History, Spectator
│   │   ├── widgets/         # Lobby, Game, Scoreboard, Seating
│   │   └── shared/          # API clients, UI components
│   └── e2e/                 # Playwright tests
└── pkg/                     # Shared utilities (clock, randid, validator)

State Machine

LOBBY → ENTERING_CARDS → SEATING → READING_RULES → ROUND_IN_PROGRESS → ROUND_FINISHED
                                         ↑                                    ↓
                                         └────────────── (repeat 3x) ─────────┘
                                                                              ↓
                                                                     GAME_FINISHED

🚀 Quick Start

Prerequisites

  • Go 1.24+
  • Node.js 18+ & npm
  • Docker & Docker Compose
  • Make (optional, for convenience)

Installation

# Clone repository
git clone https://github.com/iteplenky/hat-game.git
cd hat-game

# Install dependencies and setup infrastructure
make setup

# Start development server
make dev

The application will be available at http://localhost:8080

Manual Setup (without Make)

# Install Go tools
go install github.com/sqlc-dev/sqlc/cmd/sqlc@latest
go install github.com/pressly/goose/v3/cmd/goose@latest

# Start databases
docker-compose up -d postgres redis

# Run migrations
cd internal/storage/postgres/migrations
goose postgres "postgres://user:pass@localhost:5432/hat_game" up

# Install frontend dependencies
cd frontend
npm install

# Build frontend
npm run build

# Start backend
go run cmd/server/main.go

Development Commands

make dev           # Hot reload mode (air + vite)
make test          # Run all tests
make lint          # Run linters
make db-up         # Start PostgreSQL + Redis
make db-down       # Stop databases
make db-migrate    # Run database migrations
make sqlc-generate # Regenerate SQL code from queries
make docker-build  # Build Docker image

📚 API Reference

REST Endpoints

Method Endpoint Description Auth Required
POST /api/auth/guest Create guest session
POST /api/auth/register Register new account
POST /api/auth/login Login with credentials
GET /api/auth/me Get current user
POST /api/rooms Create new room
GET /api/rooms List public rooms
GET /api/rooms/:id Get room info
POST /api/rooms/:id/join Get WebSocket join token
DELETE /api/rooms/:id Close room (host only)
GET /api/users/me/stats Get user statistics
GET /api/users/me/history Get game history
GET /join/:id Quick join page

WebSocket Protocol

Connect: ws://localhost:8080/ws?roomId={roomId}&playerId={playerId}

Client → Server Messages
// Submit cards for the round
{ type: "submit_cards", cards: ["Name1", "Name2", ...] }

// Start the game (host only)
{ type: "start_game" }

// Start next round (host only)
{ type: "start_round", round: 1|2|3 }

// Confirm rules have been read
{ type: "confirm_rules" }

// Start your turn
{ type: "start_turn" }

// Mark card as guessed
{ type: "card_guessed" }

// Skip current card
{ type: "skip_card" }

// End your turn early
{ type: "end_turn" }

// Reorder players before game starts (host only)
{ type: "reorder_players", playerOrder: ["id1", "id2", ...] }

// Toggle rules confirmation requirement (host only)
{ type: "set_skip_rules", skipRules: true|false }
Server → Client Messages
{ type: "room_state", ... }        // Full game state
{ type: "player_joined", player }  // New player joined
{ type: "player_left", playerId }  // Player disconnected
{ type: "game_started" }           // Game has begun
{ type: "round_started", round }   // New round started
{ type: "turn_started", turn }     // Turn started
{ type: "card_drawn", card }       // New card drawn
{ type: "card_guessed", cardId }   // Card was guessed
{ type: "turn_ended", scores }     // Turn finished
{ type: "round_finished", scores } // Round finished
{ type: "game_finished", winner }  // Game completed
{ type: "timer_tick", remaining }  // Countdown update
{ type: "players_reordered", ... } // Player order changed
{ type: "spectator_joined", ... }  // Spectator connected
{ type: "reaction", emoji, ... }   // Spectator reaction

⚙️ Configuration

Copy .env.example to .env and configure:

# Server
PORT=8080
ENV=development

# PostgreSQL
DATABASE_URL=postgres://hatgame:hatgame@localhost:5432/hat_game

# Redis
REDIS_HOST=localhost
REDIS_PORT=6379

# Security (generate strong secrets!)
SESSION_SECRET=your-32-char-secret-minimum-length
ALLOWED_ORIGINS=http://localhost:8080,http://localhost:5173

# Frontend (frontend/.env)
VITE_API_URL=http://localhost:8080
VITE_WS_URL=ws://localhost:8080

💾 Database Schema

View Schema
-- Users (persistent storage)
CREATE TABLE users (
  id UUID PRIMARY KEY,
  email VARCHAR UNIQUE,
  password_hash VARCHAR,
  last_name VARCHAR,
  is_guest BOOLEAN DEFAULT false,
  total_games INTEGER DEFAULT 0,
  total_wins INTEGER DEFAULT 0,
  created_at TIMESTAMPTZ DEFAULT NOW(),
  last_seen_at TIMESTAMPTZ DEFAULT NOW()
);

-- Game History
CREATE TABLE game_history (
  id UUID PRIMARY KEY,
  room_id VARCHAR NOT NULL,
  user_id UUID REFERENCES users(id),
  player_name VARCHAR NOT NULL,
  is_host BOOLEAN DEFAULT false,
  started_at TIMESTAMPTZ NOT NULL,
  finished_at TIMESTAMPTZ,
  final_score INTEGER DEFAULT 0,
  place INTEGER,
  won BOOLEAN DEFAULT false
);

-- Indexes
CREATE INDEX idx_game_history_user_id ON game_history(user_id);
CREATE INDEX idx_game_history_finished_at ON game_history(finished_at);

🧪 Testing

Test Coverage

Package          Coverage
auth             80.6%
game             67.3%
room             92.3%
validator        66.7%
randid           84.6%

Run Tests

# Backend tests
make test                  # All tests with coverage
go test -v ./...           # Verbose mode
go test -cover ./...       # Coverage report

# Frontend E2E tests
cd frontend
npm test                   # Playwright tests
npm run test:ui            # Interactive mode

📊 Project Stats

  • Backend: ~10,600 lines of Go
  • Frontend: ~6,200 lines of TypeScript
  • Total Files: 100+
  • Dependencies: 15 Go modules, 20 npm packages

🗺 Roadmap

  • Voice chat integration
  • Custom card packs
  • Tournament mode
  • Mobile apps (React Native)
  • Analytics dashboard
  • Internationalization (i18n)

🤝 Contributing

Contributions are welcome! Please follow these steps:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Please read CONTRIBUTING.md for details on our code of conduct and development process.

Development Guidelines

  • Follow Go best practices and golangci-lint rules
  • Write tests for new features
  • Update documentation for API changes
  • Keep commits atomic and descriptive
  • Use conventional commit messages

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

🙏 Acknowledgments

  • Inspired by the traditional "Hat" party game
  • Built with amazing open-source libraries:

📧 Contact

Author: Denis Teplenky (@iteplenky)

Issues: GitHub Issues


⬆ Back to Top

Made with ❤️ and Go

About

🎩 Multiplayer word guessing game with real-time WebSocket gameplay

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors