npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

uno-engine-js

v0.2.0

Published

A headless, zero-dependency uno game logic engine written in TypeScript.

Readme

uno-engine-js

npm version

A headless, zero-dependency uno game logic engine written in TypeScript.

Supports both human and bot players, with full game state management, turn-based play, and standard UNO rules (including wild cards, draws, skips, and reverses).

Features

  • Full UNO Deck: 108 cards with accurate distribution (numbers 0-9, actions, wilds, draw4s).
  • Player Management: Supports 2-10 players, including bots with random play.
  • Turn Logic: Handles direction reversal, skips, draws (2/4), and wild colour changes.
  • Validation: Enforces playable card rules (colour, number, or symbol match).
  • Game State: Track piles, current player, winner detection.
  • Extensible: Interfaces for custom player/card extensions.

Installation

Install via npm:

npm install uno-engine-js

Quick Start

Basic Game Setup

import Game, { Colours, CardTypes } from 'uno-engine-js';

// Define players (strings for humans, objects for bots)
const players = [
  'Osaka',  // Human player
  'Tomo',    // Human player
  { name: 'Chiyo', isBot: true }  // Bot player
];

const game = new Game(players);

// Check initial state
console.log(game.toString());

Playing a Turn

// Get current player's playable cards
const playable = game.playableCards;
console.log('Playable cards:', playable);

// For human players with multiple options:
try {
  // Play a specific card with wild colour if needed
  const cardToPlay = playable[0];  // Assume first playable
  let wildColour: Colours | undefined;
  if (cardToPlay.type === CardTypes.WILD || cardToPlay.type === CardTypes.DRAW4) {
    wildColour = Colours.GREEN;  // Choose a colour
  }
  game.playTurn(cardToPlay, wildColour);
} catch (error) {
  console.error('Invalid play:', error);
}

// For bots or auto-play: Call without params
if (game.currPlayer.isBot) {
  game.playTurn();  // Bot plays randomly
}

// Advance turns until game over
while (!game.isOver) {
  game.playTurn();  // Handles bot/human logic internally
}

console.log('Winner:', game.winner.name);

No Playable Cards

If no cards are playable, the player draws one and the turn passes automatically.

if (game.playableCards.length === 0) {
  game.playTurn();  // Draws and advances
}

API Reference

Enums

  • Colours: Card colours (RED=1, YELLOW=2, GREEN=3, BLUE=4).
  • CardTypes: Card types (NUMBER=1, SKIP=2, REVERSE=3, DRAW2=4, DRAW4=5, WILD=6).

Classes

Game

The main game controller.

Constructor:

new Game(players: (string | { name: string; isBot: boolean })[])
  • Initializes with 2-10 players.
  • Deals 7 cards per player and starts the discard pile.

Getters:

  • isOver: boolean - True if any player has 0 cards.
  • winner: Player - The first player with 0 cards (throws if game not over).
  • players: readonly Player[] - All players.
  • drawPile: readonly Card[] - Cards to draw from.
  • discardPile: readonly Card[] - Played cards.
  • currPlayerIndex: number - Current turn index.
  • currPlayer: Player - Current player (throws if invalid index).
  • nextPlayerIndex: number - Next turn index (handles wraparound and direction).
  • isReversed: boolean - True if play direction is backward.
  • playableCards: Card[] - Current player's legal moves.

Methods:

  • playTurn(card?: Card, wildColour?: Colours): void
    • Executes the current turn (see Quick Start for details).
    • Throws on invalid inputs for human players.
  • toString(): string - String representation of game state (piles + players).

Player

Represents a player.

Instead of this class, an interface extending this class is exported.

Constructor:

new Player(name: string, isBot?: boolean)

Properties:

  • hand: readonly Card[] - Player's cards.
  • name: string - Player name.
  • isBot: boolean - True if bot-controlled.

Methods:

  • toString(): string - String of name + hand.

Card

Represents a single card.

Instead of this class, an interface extending this class is exported.

Constructor:

new Card(type: CardTypes, colour?: Colours, value?: number)
  • Colour required except for WILD/DRAW4.
  • Value required for NUMBER.

Properties:

  • type: CardTypes
  • colour?: Colours
  • value?: number

Methods:

  • toString(): string - Formatted string (e.g., "5 RED", "SKIP BLUE", "WILD").

Interfaces

  • IPlayer extends Player - For extending Player.
  • ICard extends Card - For extending Card.
import type {IPlayer, ICard} from "uno-engine-js";

Contributing

Feel free to contribute but please ensure your code passes all tests before submitting a pull request:

npm run test       # Run test suite