A modern, mobile-first web application for tracking scores and managing Mölkky games. Built with Preact, TypeScript, and Tailwind CSS.
Mölkky is a Finnish throwing game where players throw a wooden pin (the "mölkky") to knock down numbered wooden pins. The goal is to score exactly 50 points. If a player exceeds 50 points, their score is reset to 25.
- Game Modes: Support for both individual and team-based games
- Player Management: Add, remove, and manage players for your game
- Team Management: Create and manage teams with up to 4 players per team
- Team Player Reordering: Mobile-friendly reordering of players within teams
- Score Tracking: Record scores with automatic turn advancement
- Penalty System: Apply penalties that reset player scores to 25
- Game History: View and manage previous games
- End Game Functionality: End current game and return to start screen at any time
- Mobile-First Design: Optimized for mobile devices with touch-friendly interface
- PWA Support: Install as a mobile app with offline capabilities
- Real-time Updates: Live score updates and game state management
- Toast Notifications: User-friendly feedback for all game actions
- Error Handling: Robust error boundaries and validation
- Node.js (version 18 or higher)
- npm or yarn package manager
- Clone the repository:
git clone https://github.com/nikosalonen/moelkky.git
cd moelkky- Install dependencies:
npm install- Start the development server:
npm run dev- Open your browser and navigate to
http://localhost:5173
npm run buildThe built files will be in the dist directory.
- Choose Game Mode: Select between Individual or Team mode
- Add Players: Enter player names and click "Add Player" (minimum 2 players required)
- Create Teams (Team Mode): Create teams and assign players (2-4 players per team, minimum 2 teams)
- Reorder Team Players (Team Mode): Use the "Reorder" button to arrange players in throwing order (mobile-optimized)
- Start Game: Click "Start Game" to begin
- Track Scores: Use the score input to record points for each player/team
- Apply Penalties: Use the penalty button if a player/team violates rules
- End Game: Click the "End Game" button to return to the start screen and reset all scores
In team mode, the throwing order follows this pattern:
- Round 1: Team 1 Player 1 → Team 2 Player 1 → Team 3 Player 1 → ...
- Round 2: Team 1 Player 2 → Team 2 Player 2 → Team 3 Player 2 → ...
- Round 3: Team 1 Player 3 → Team 2 Player 3 → Team 3 Player 3 → ...
- And so on...
This ensures each team gets one throw per round, and all players within each team throw in the order you've set.
- Single Pin: Score the number on the pin
- Multiple Pins: Score the number of pins knocked down
- Exceeding 50: Score resets to 25
- Winning: First player/team to reach exactly 50 points wins
- Consecutive Misses:
- Individual Mode: Players are eliminated after 3 consecutive zero-point turns
- Team Mode: Teams are eliminated after 3 consecutive zero-point turns
- Click "View Game History" to see previous games
- View detailed statistics including penalties and game duration
src/
├── components/ # Preact components
│ ├── ErrorBoundary/ # Error handling
│ ├── GameBoard/ # Main game interface
│ ├── GameHistory/ # Game history modal
│ ├── GameModeSelector/ # Game mode selection
│ ├── MobileNav/ # Mobile navigation
│ ├── PlayerManager/ # Player management
│ ├── ScoreInput/ # Score input component
│ ├── TeamManager/ # Team management
│ ├── Toast/ # Notification system
│ └── WinnerDisplay/ # Winner announcement
├── context/ # Preact context providers
├── hooks/ # Custom Preact hooks
├── utils/ # Utility functions
│ ├── gameLogic/ # Game logic
│ ├── storage/ # Data persistence
│ └── types/ # TypeScript type definitions
└── main.tsx # Application entry point
npm run dev- Start development servernpm run build- Build for productionnpm run preview- Preview production buildnpm test- Run testsnpm run test:watch- Run tests in watch modenpm run test:ui- Run tests with UI
The project includes comprehensive tests using Vitest and Testing Library:
npm testTests cover:
- Component functionality
- Game logic and state management
- User interactions
- Error handling
The project also includes end-to-end tests using Playwright:
# Run e2e tests (recommended - automatically manages dev server)
npm run test:e2e
# Run e2e tests with headed browser
npm run test:e2e:headed
# Run e2e tests in debug mode
npm run test:e2e:debug
# Run e2e tests with UI
npm run test:e2e:ui
# Run e2e tests with built-in server (may hang)
npm run test:e2e:with-server
# View e2e test reports
npm run test:e2e:reportNote: The default test:e2e command uses a custom script that automatically starts and stops the development server, preventing the hanging issue that can occur with the built-in webServer option.
- Frontend Framework: Preact - Fast 3kB alternative to React
- Language: TypeScript - Type-safe JavaScript
- Styling: Tailwind CSS - Utility-first CSS framework
- Build Tool: Vite - Fast build tool and dev server
- Testing: Vitest - Fast unit testing framework
- Testing Library: @testing-library/preact - Testing utilities
- E2E Testing: Playwright - End-to-end testing framework
- PWA: Progressive Web App with offline capabilities
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'feat: add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project follows Conventional Commits:
feat:- New featuresfix:- Bug fixesdocs:- Documentation changesstyle:- Code style changesrefactor:- Code refactoringtest:- Test additions or changeschore:- Build process or auxiliary tool changes
This project is licensed under the MIT License - see the LICENSE file for details.
- Inspired by the traditional Finnish game Mölkky
- Built with modern web technologies for the best user experience
- Special thanks to the Preact and Tailwind CSS communities
If you encounter any issues or have questions, please:
- Check the Issues page
- Create a new issue with detailed information
- Include steps to reproduce the problem
Happy Mölkky playing! 🎯