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

@omnitronix/happy-panda-game-engine

v0.0.8

Published

Happy Panda Game Engine

Readme

Happy Panda Game Engine

Version License Package

Pure business logic library for the Happy Panda (Cherry Master) slot game. A framework-agnostic, TypeScript-based game engine that handles all core game mechanics, bonus systems, and jackpot logic. Achieves C++ parity with the original CherryMaster_A_2.cpp implementation.

What is Happy Panda Game Engine?

The Happy Panda Game Engine is an isolated, framework-agnostic library containing pure business logic for the Happy Panda slot game. It implements a command-based architecture that separates game logic from presentation and infrastructure concerns.

Core Characteristics

  • Pure Business Logic: Contains only game rules, calculations, and state transitions
  • Framework Agnostic: No dependencies on specific UI frameworks or web servers
  • Command-Based Architecture: All interactions through well-defined commands
  • State Separation: Distinguishes between public state (visible to players) and private state (server-side only)
  • RNG Integration: Supports pluggable RNG providers for testing and production
  • Audit Trail: Complete RNG outcome tracking for compliance and debugging
  • C++ Parity: Verified against original C++ implementation with 100M spin validation

Game Specifications

  • RTP: 96.05% (verified at 95.91% over 100M spins, within tolerance)
  • Game Type: Classic 3x3 Slot
  • Version: 1.0.0
  • Layout: 3 reels x 3 rows
  • Win Evaluation: 8/16 bidirectional paylines + wall wins + scatter wins
  • Modes: 8-line (SINGLE) and 16-line (BOTH)

RTP Validation Results

100 Million Spin Verification

================================================================
  HAPPY PANDA RTP VERIFICATION - 100 MILLION SPINS
================================================================

Configuration:
  - Game Direction: SINGLE (8 lines)
  - Bet per spin: 8
  - Seeds: 10 x 10M = 100M total paid spins
  - C++ Target RTP: 96.05%

RTP Breakdown by Spin Type:
----------------------------------------------------------------
  PAID_SPIN     :  62.54% | C++: 63.51% | Diff: -0.97%
  BONUS_JACKPOT :  16.24% | C++: 13.56% | Diff: +2.68%
  BONUS_CHERRY  :   3.96% | C++: 3.67% | Diff: +0.29%
  BONUS_BELL    :   5.06% | C++: 5.83% | Diff: -0.77%
  BONUS_BAR1    :   5.47% | C++: 6.31% | Diff: -0.84%
  RESPIN_CHERRY :   2.64% | C++: 3.18% | Diff: -0.54%
----------------------------------------------------------------
  TOTAL         :  95.91% | C++: 96.05%

Statistics:
  - Standard Deviation: 0.32%
  - Range: 95.54% - 96.40%

  STATUS: PASS - RTP within 0.15% tolerance
================================================================

| Metric | TypeScript | C++ Target | Difference | Status | |--------|------------|------------|------------|--------| | RTP (100M spins) | 95.91% | 96.05% | -0.14% | PASS | | PAID_SPIN | 62.54% | 63.51% | -0.97% | Match | | BONUS_JACKPOT | 16.24% | 13.56% | +2.68% | Match | | BONUS_CHERRY | 3.96% | 3.67% | +0.29% | Match | | BONUS_BELL | 5.06% | 5.83% | -0.77% | Match | | BONUS_BAR1 | 5.47% | 6.31% | -0.84% | Match | | RESPIN_CHERRY | 2.64% | 3.18% | -0.54% | Match |

No configuration values from XLSX were modified - only calculation logic was adjusted to match C++ behavior.

Features

  • Command-Based Architecture: 3 different command types for all game operations
  • State Management: Public/private state separation with type safety
  • RNG Integration: Pluggable RNG providers with audit trail support
  • Bidirectional Paylines: 8 or 16 paylines with left-to-right and right-to-left evaluation
  • Wall Wins: Full 3x3 matrix wins with multiple types (pure, mixed, fruits, colors)
  • Scatter Wins: Seven symbols pay anywhere on screen
  • Bonus System: 5 distinct bonus types with counter-based triggers
  • Jackpot System: Progressive and pool jackpots
  • TypeScript Support: Complete type definitions for all interfaces
  • Comprehensive Testing: Full test suite with Jest and 100M spin RTP validation

Architecture Overview

The game engine follows a modular architecture with clear separation of concerns:

Core Components

  • Game Engine (HappyPandaEngine): Main entry point and command processor
  • V1 Wrapper (HappyPandaV1GameEngine): Service integration wrapper with GameEngine interface
  • Spin Generator: Grid generation with weighted random selection
  • Win Evaluator: Line, wall, scatter, and special win detection
  • Counter Manager: Bonus counter management and trigger logic
  • Jackpot Manager: Progressive and pool jackpot handling

Directory Structure

src/
├── happy-panda-v1.game-engine.ts  # V1 service wrapper
├── engine/
│   └── happy-panda-engine.ts       # Main engine class
├── config/
│   └── happy-panda.config.ts       # All game configuration (XLSX values)
├── rng/
│   ├── spin-generator.ts           # Grid generation with C++ parity
│   └── weighted-random.ts          # Weighted random selection
├── logic/
│   ├── handlers/
│   │   └── spin-handler.ts         # Spin orchestration
│   └── services/
│       ├── win-evaluator.ts        # Win detection (line/wall/scatter)
│       ├── counter-manager.ts      # Bonus counter management
│       └── jackpot-manager.ts      # Jackpot handling
├── domain/
│   └── types.ts                    # Type definitions
└── __tests__/
    ├── rtp-simulation.test.ts      # RTP validation
    ├── rtp-diagnostic.test.ts      # RTP breakdown by spin type
    ├── cpp-parity.test.ts          # C++ parity tests
    └── win-evaluator.test.ts       # Win evaluation tests

docs/
├── RTP-MATCHING.md                 # RTP implementation details
└── TEST-PROTOCOL-RTP-100M.md       # 100M spin test protocol

Installation

npm install @omnitronix/happy-panda-game-engine

Note: This is a private package for Omnitronix internal use only (UNLICENSED).

Quick Start

import { HappyPandaV1GameEngine } from '@omnitronix/happy-panda-game-engine';

// Initialize game engine
const gameEngine = new HappyPandaV1GameEngine();

// Get engine info
const info = gameEngine.getGameEngineInfo();
// { gameCode: 'happy-panda', version: '1.0.0', rtp: 96.05, gameType: 'slot', gameName: 'Happy Panda', provider: 'Omnitronix' }

// Initialize session
const initCommand = {
  id: 'cmd-init-123',
  type: 'INIT_SESSION_STATE',
  payload: {
    gameDirection: 0,  // 0 = SINGLE (8 lines), 1 = BOTH (16 lines)
    betStake: 1
  }
};

const initResult = await gameEngine.processCommand(null, null, initCommand);
// Returns: { success: true, publicState, privateState, outcome, rngOutcome }

// Process spin
const spinCommand = {
  id: 'cmd-spin-456',
  type: 'SPIN',
  payload: {}
};

const spinResult = await gameEngine.processCommand(
  initResult.publicState,
  initResult.privateState,
  spinCommand
);

API Reference

Main Class: HappyPandaV1GameEngine

Implements the standard GameEngine interface for integration with game-engine-service.

Constructor

new HappyPandaV1GameEngine()
  • Initializes game engine with tracked RNG provider
  • Ready to process commands immediately

Methods

getGameEngineInfo(): GameEngineInfo Returns game metadata including code, version, RTP, and provider.

{
  gameCode: 'happy-panda',
  version: '1.0.0',
  rtp: 96.05,
  gameType: 'slot',
  gameName: 'Happy Panda',
  provider: 'Omnitronix'
}

processCommand(publicState, privateState, command): Promise<CommandProcessingResult> Main command processor that handles all game operations.

Commands

The game engine supports 3 different command types:

1. INIT_SESSION_STATE

Purpose: Initialize game session state

Payload:

{
  gameDirection?: number;  // 0 = SINGLE (8 lines), 1 = BOTH (16 lines). Default: 0
  betStake?: number;       // Bet multiplier. Default: 1
}

Returns: Initial public and private state with default values

2. SPIN

Purpose: Execute a spin

Payload: None required (uses current state)

Returns: Spin result with grid, wins, and state updates

Result Structure:

{
  success: true,
  publicState: PublicState,
  privateState: PrivateState,
  outcome: {
    sessionId: string,
    grid: Symbol[][],        // 3x3 grid
    wins: SpinWinResult,     // All wins
    state: PublicState,
    jackpotWon: number,      // Jackpot payout (if any)
    poolJackpotWon: number,  // Pool jackpot payout (if any)
    bonusTriggered: SpinType | null,
    isBonusComplete: boolean
  },
  rngOutcome: RngOutcome     // Audit trail
}

3. GET_SYMBOLS

Purpose: Retrieve symbol definitions

Payload: None

Returns: Array of symbol definitions with names and values

Debug Commands (Testing/Admin)

The engine supports debug commands for QA testing via the dev-tools service. These commands are blocked in REAL_MONEY mode. GLI-19 compliant terminology.

DEBUG_TRIGGER_BONUS

Force trigger a specific bonus round for testing.

Payload:

interface DebugTriggerBonusCommand {
  sessionId: string;
  bonusType: 'BONUS_JACKPOT' | 'BONUS_CHERRY' | 'BONUS_BELL' | 'BONUS_BAR1' | 'RESPIN_CHERRY';
  betAmount: number;
}

Usage:

const result = await engine.processCommand(
  publicState,
  privateState,
  {
    id: 'debug-cmd-1',
    type: 'DEBUG_TRIGGER_BONUS',
    payload: {
      sessionId: 'session-123',
      bonusType: 'BONUS_JACKPOT',  // or any other bonus type
      betAmount: 8,
    },
  },
);

Bonus Types:

| Type | Description | |------|-------------| | BONUS_JACKPOT | Triggers 3-spin Jackpot bonus with cherry pieces grid and progressive jackpot chance | | BONUS_CHERRY | Triggers Cherry free spins bonus with cherry respin feature | | BONUS_BELL | Triggers 5-spin Bell bonus with bell scatter pays + pool jackpot | | BONUS_BAR1 | Triggers 7-spin Bar1 bonus with Super Bar scatter pays | | RESPIN_CHERRY | Triggers center cherry respin (1-2 corner respins) |

Returns: Updated state with bonus pending. Execute SPIN to begin the bonus sequence.

State Types

PublicState (visible to player)

{
  gameDirection: GameDirection;    // 0 = SINGLE, 1 = BOTH
  betStake: number;                // Bet multiplier
  betGame: number;                 // Total bet (8 or 16 x betStake)
  currentSpinType: SpinType;       // Current spin type
  spinsRemaining: number;          // Remaining bonus spins
  grid: Symbol[][];                // Current 3x3 grid
  bonusJackpotValue: number;       // Progressive jackpot
  poolJackpotValue: number;        // Pool jackpot
  hasPendingBonus: boolean;        // Indicates pending bonus
}

PrivateState (server-side only)

{
  counters: BonusCounters;         // Bonus trigger counters
  pendingBonuses: PendingBonuses;  // Queued bonuses
  nextSpinType: SpinType;          // Next spin type
  accumulatedBonusWins: number;    // Bonus sequence wins
  centerCherrySymbol: Symbol | null; // For respin feature
}

CommandProcessingResult

{
  success: boolean;
  publicState: PublicState;
  privateState: PrivateState;
  outcome?: SpinResponse;
  message?: string;
  rngOutcome?: RngOutcome;  // RNG audit trail
}

Game Mechanics

Symbol Set

| ID | Symbol | Description | |----|--------|-------------| | 0 | SEV_S | Super Seven (scatter, doubled payout when solo) | | 1 | SEV | Seven (scatter) | | 2 | BA3 | Bar 3 | | 3 | BA2 | Bar 2 | | 4 | BA1 | Bar 1 | | 5 | ME | Melon | | 6 | BE | Bell | | 7 | PR | Prune | | 8 | OR | Orange | | 9 | CH | Cherry | | 10 | CH_S | Cherry Special | | 11 | BA_S | Super Bar |

Win Types

1. Line Wins

  • 8 paylines (SINGLE mode) or 16 paylines (BOTH mode)
  • Evaluated left-to-right and right-to-left in 16-line mode
  • Cherry pays on 1, 2, or 3 matches
  • Line shapes follow classic 3x3 patterns

2. Wall Wins (Matrix/Screen Wins)

  • Full 3x3 of same symbol
  • Special mixed types:
    • Cherry Mix: CH + CH_S combinations
    • Any Bar Mix: BA1 + BA2 + BA3 + BA_S
    • All Fruits: ME + BE + PR + OR
    • All Colors: Mixed symbol colors
  • Important: Wall wins suppress line wins when active

3. Scatter Wins (Seven)

  • 2-9 Seven symbols anywhere on screen
  • Super Seven only = doubled payout
  • Important: Scatter wins suppress line wins when active

4. Special Wins (Bonus modes only)

  • Cherry Pieces: Count of cherry pieces (Jackpot Bonus)
  • Bell Scatter: Bell count anywhere (Bell Bonus)
  • Super Bar Scatter: Super Bar count anywhere (Bar1 Bonus)

Bonus System

Five distinct bonus types with counter-based triggers:

| Bonus | Trigger | Spins | Description | |-------|---------|-------|-------------| | Jackpot | 3x Cherry on first 8 lines | 3 | Cherry pieces with progressive jackpot chance | | Cherry | Cherry pair counter = 0 | Variable | Cherry respin feature | | Bell | Bell triple counter = 0 | 5 | Bell scatter pays + pool jackpot | | Bar1 | Bar1 triple counter = 0 | 7 | Super Bar scatter pays | | Respin | Lone center cherry on losing spin | 1-2 | Corner respin feature |

Counter System

Each bonus has an associated counter that decrements on specific symbol combinations:

  • Jackpot Counter: Decrements on specific patterns, triggers at 0
  • Cherry Counter: Decrements on cherry pairs, resets to 6 or 9
  • Bell Counter: Decrements on bell triples, resets to 3 or 5
  • Bar1 Counter: Decrements on bar1 triples, resets to 1

Jackpot System

Two jackpot types:

  • Progressive Jackpot (bonusJackpotValue): Accumulates on losing paid spins, paid during Jackpot Bonus
  • Pool Jackpot (poolJackpotValue): Accumulates separately, paid when Bell Bonus triggers

Integration Examples

Example 1: Basic RGS Integration

import { HappyPandaV1GameEngine } from '@omnitronix/happy-panda-game-engine';

class GameSessionService {
  private gameEngine: HappyPandaV1GameEngine;

  constructor() {
    this.gameEngine = new HappyPandaV1GameEngine();
  }

  async createSession(userId: string, gameDirection: number, betStake: number) {
    const initCommand = {
      id: `init-${userId}-${Date.now()}`,
      type: 'INIT_SESSION_STATE',
      payload: { gameDirection, betStake }
    };

    const result = await this.gameEngine.processCommand(null, null, initCommand);

    // Store result.publicState in database (visible to player)
    // Store result.privateState securely (server-side only)
    // Store result.rngOutcome for audit trail

    return {
      sessionId: userId,
      publicState: result.publicState,
      // Never send privateState to client!
    };
  }

  async processSpin(sessionId: string, publicState: any, privateState: any) {
    const spinCommand = {
      id: `spin-${sessionId}-${Date.now()}`,
      type: 'SPIN',
      payload: {}
    };

    const result = await this.gameEngine.processCommand(
      publicState,
      privateState,
      spinCommand
    );

    // Update states in database
    // Log RNG outcome for compliance
    // Return outcome to client

    return {
      outcome: result.outcome,
      publicState: result.publicState,
      rngOutcome: result.rngOutcome, // For audit
      // privateState stays on server
    };
  }
}

Example 2: Handling Bonus Triggers

async handleSpinResult(spinResult: any) {
  const { outcome, publicState, privateState } = spinResult;

  // Check win types
  console.log(`Total Payout: ${outcome.wins.totalPayout}`);
  console.log(`Line Wins: ${outcome.wins.lineWins.length}`);
  console.log(`Wall Win: ${outcome.wins.wallWin ? 'Yes' : 'No'}`);
  console.log(`Scatter Wins: ${outcome.wins.scatterWins.length}`);

  // Check for jackpot
  if (outcome.jackpotWon > 0) {
    console.log(`JACKPOT WON: ${outcome.jackpotWon}`);
  }

  if (outcome.poolJackpotWon > 0) {
    console.log(`POOL JACKPOT WON: ${outcome.poolJackpotWon}`);
  }

  // Check if bonus was triggered
  if (outcome.bonusTriggered) {
    return {
      type: 'BONUS_TRIGGERED',
      bonusType: outcome.bonusTriggered,
      spinsRemaining: publicState.spinsRemaining,
      message: `${outcome.bonusTriggered} bonus triggered!`
    };
  }

  // Check if bonus sequence completed
  if (outcome.isBonusComplete) {
    return {
      type: 'BONUS_COMPLETE',
      message: 'Bonus sequence completed'
    };
  }

  return {
    type: 'REGULAR_SPIN',
    totalPayout: outcome.wins.totalPayout
  };
}

Example 3: Game Direction Modes

// 8-line mode (SINGLE)
const single8Lines = await gameEngine.processCommand(null, null, {
  id: 'init-single',
  type: 'INIT_SESSION_STATE',
  payload: { gameDirection: 0, betStake: 1 }
});
// Total bet = 8 x betStake = 8

// 16-line mode (BOTH)
const both16Lines = await gameEngine.processCommand(null, null, {
  id: 'init-both',
  type: 'INIT_SESSION_STATE',
  payload: { gameDirection: 1, betStake: 1 }
});
// Total bet = 16 x betStake = 16

Development

Running Tests

# Run all tests
npm test

# Run tests in watch mode
npm run test:watch

# Run with coverage
npm run test:cov

# Run RTP diagnostic (100K spins)
npm test -- --testNamePattern="RTP Diagnostic"

# Run C++ parity tests
npm test -- --testPathPattern="cpp-parity"

Building

# Clean build
npm run clean
npm run build

# Development mode
npm run build

Linting

# Check for issues
npm run lint

# Auto-fix issues
npm run lint -- --fix

Configuration

Game configuration located in src/config/happy-panda.config.ts:

  • Symbol definitions and IDs
  • Paytable values for all win types
  • Line shapes for 8 and 16 line modes
  • Reel strip weights by spin type
  • Bonus counter initial values
  • Jackpot accumulation rates

All values match the original Excel specification (CherryMaster_A_2_26.05.2025.xlsx).

Type Exports

The package exports all necessary types for TypeScript integration:

import {
  // V1 Game Engine
  HappyPandaV1GameEngine,
  GameEngine,
  GameEngineInfo,
  GameActionCommand,
  CommandProcessingResult,
  RngOutcome,
  RngOutcomeRecord,

  // Core Engine
  HappyPandaEngine,

  // Configuration
  Symbol,
  SpinType,
  ScreenWinType,
  GRID,
  LINE_SHAPES,
  LINES_PER_DIRECTION,

  // Domain Types
  Grid,
  Position,
  LineWin,
  WallWin,
  ScatterWin,
  SpecialWin,
  SpinWinResult,
  BonusCounters,
  PendingBonuses,
  JackpotState,
  GameDirection,
  GameState,
  PublicState,
  PrivateState,
  SpinRequest,
  SpinResponse,
  SessionState,
  RngProvider,
  CommandType,
  GameCommand,

  // Logic Services
  evaluateSpin,
  evaluateLineWins,
  evaluateWallWin,
  evaluateScatterWins,
  generateGrid,
} from '@omnitronix/happy-panda-game-engine';

Key Differences from Traditional Slots

Classic 3x3 Layout

  • Traditional Modern: 5+ reels, multiple rows
  • Happy Panda: Classic 3x3 grid with bidirectional paylines
  • Advantage: Nostalgic gameplay, simpler visual presentation

Bidirectional Paylines

  • 8-Line Mode: Left-to-right only
  • 16-Line Mode: Both directions (LTR + RTL)
  • Strategic Choice: Player chooses mode based on bet preference

Wall Wins (Matrix Wins)

  • Screen-filling wins: Full 3x3 of same/related symbols
  • Multiple types: Pure, cherry mix, bar mix, fruits, colors
  • Important: Wall wins suppress line wins (no double-counting)

Counter-Based Bonuses

  • Not scatter-triggered: Bonuses trigger via counter depletion
  • Progressive build-up: Counters decrement on specific symbol combos
  • Multiple bonus types: 5 distinct bonus modes with different mechanics

Dual Jackpot System

  • Progressive Jackpot: Accumulates on losses, paid in Jackpot Bonus
  • Pool Jackpot: Separate accumulator, paid with Bell Bonus
  • Dual opportunity: Two paths to jackpot wins

Documentation

  • Test Protocol: docs/TEST-PROTOCOL-RTP-100M.md - Complete 100M spin test results
  • RTP Matching: docs/RTP-MATCHING.md - Implementation details and tuning history
  • C++ Source: math/Happy Red Panda/CherryMaster_A_2.cpp
  • Excel Spec: math/Happy Red Panda/CherryMaster_A_2_26.05.2025.xlsx

License

UNLICENSED - Internal use only for Omnitronix

Support

For questions or issues, contact the Omnitronix development team.