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

@jackpotkit/core

v1.0.0

Published

Pure TypeScript game mechanics for JackpotKit.

Readme

@jackpotkit/core

Platform-independent TypeScript primitives for building deterministic, testable game mechanics.

npm install @jackpotkit/core
import {
  SeededRandomSource,
  createGameEvent,
  nextRandomValue,
  resolveResult,
  type GameResult,
  type ResultProvider,
} from '@jackpotkit/core';

const random = new SeededRandomSource('campaign-preview');
const sample = nextRandomValue(random); // always in [0, 1)

type PlayRequest = { campaignId: string };
type PlayData = { rewardId: string };

const provider: ResultProvider<PlayRequest, GameResult<PlayData>> = async (request) => {
  const response = await fetch(`/api/campaigns/${request.campaignId}/play`, {
    method: 'POST',
  });

  if (!response.ok) throw new Error('Play request failed');
  return response.json() as Promise<GameResult<PlayData>>;
};

const result = await resolveResult(provider, { campaignId: 'summer-2026' });
const event = createGameEvent('result-resolved', result);

Included primitives

  • Immutable result, reward, lifecycle, and typed event contracts.
  • MathRandomSource for ordinary client-side variation.
  • SeededRandomSource for reproducible previews, tests, and debugging.
  • Injectable RandomSource contracts with range validation.
  • Sync or async ResultProvider functions with normalized failures.
  • Typed configuration, result, provider, and lifecycle errors.
  • Composable validation results and assertion helpers.

SeededRandomSource uses a stable FNV-1a string hash and Mulberry32 generator. Its sequence is part of the public compatibility contract. It is deterministic, not cryptographically secure.

For rewards with real value, the backend must validate eligibility, choose and persist the outcome, and return that result. JackpotKit does not provide networking, settlement, fulfilment, or a security boundary.

Shared primitives are available from @jackpotkit/core; implemented games also have the intentional @jackpotkit/core/spin-wheel, @jackpotkit/core/scratch-card, @jackpotkit/core/slot-machine, @jackpotkit/core/bingo, @jackpotkit/core/dice, @jackpotkit/core/coin-flip, and @jackpotkit/core/lucky-box subpaths. Other internal paths are unsupported.

Spin Wheel

import { SeededRandomSource } from '@jackpotkit/core';
import { createSpinWheel } from '@jackpotkit/core/spin-wheel';

const wheel = createSpinWheel({
  segments: [
    { id: 'common', label: '10 points', weight: 9 },
    { id: 'rare', label: 'Bonus badge', weight: 1 },
  ],
  randomSource: new SeededRandomSource('preview'),
});

wheel.spin();
wheel.spinTo('rare');
await wheel.spinWith(serverResultProvider, request);
wheel.reset();

Weights affect selection probability only; every prebuilt visual slice remains equal. Controlled and server results are validated against configured segment IDs before animation.

Scratch Card

import { createScratchCard, createScratchProgressTracker } from '@jackpotkit/core/scratch-card';

const card = createScratchCard({
  threshold: 0.65,
  result: { prize: { id: 'points', amount: 250 } },
});

const tracker = createScratchProgressTracker({
  width: 320,
  height: 180,
  brushRadius: 20,
});

card.start();
card.scratch(tracker.scratchLine({ x: 20, y: 40 }, { x: 280, y: 40 }));
card.reveal();
card.reset();

Coverage uses a deterministic grid and is independent of Skia, React Native, or frame rate. startWith() accepts a consumer-supplied result provider; scratching never chooses or changes the prize.

Slot Machine

import { SeededRandomSource } from '@jackpotkit/core';
import { createSlotMachine } from '@jackpotkit/core/slot-machine';

const machine = createSlotMachine({
  symbols: [
    { id: 'cherry', weight: 5 },
    { id: 'star', weight: 1 },
  ],
  reelCount: 3,
  rowCount: 3,
  randomSource: new SeededRandomSource('preview'),
  paylines: [
    [0, 0, 0],
    [1, 1, 1],
    [2, 2, 2],
  ],
});

machine.spin();
machine.spinTo(controlledSelection);
await machine.spinWith(serverResultProvider, request);
machine.reset();

The grid is reel-major, and each payline contains one row index per reel. Built-in evaluation reports matching symbol IDs; optional consumer evaluation can add application-specific, non-monetary result metadata.

Bingo

import { SeededRandomSource } from '@jackpotkit/core';
import { createBingo } from '@jackpotkit/core/bingo';

const bingo = createBingo({ randomSource: new SeededRandomSource('preview') });

bingo.call(27);
bingo.mark(27);
bingo.check();
bingo.reset();

Classic cards use a 5 × 5, 1–75 layout with column ranges and a center free space. The engine also accepts externally supplied cards, configurable sizes and ranges, random remaining-number draws, mark/unmark, and row, column, diagonal, four-corners, full-board, or custom coordinate patterns. All exposed cards, patterns, results, and state snapshots are immutable.

Dice, Coin Flip, and Lucky Box

import { createCoinFlip } from '@jackpotkit/core/coin-flip';
import { createDice } from '@jackpotkit/core/dice';
import { createLuckyBox } from '@jackpotkit/core/lucky-box';

createDice({ count: 2, sides: 6 }).rollTo({ values: [2, 6] });
createCoinFlip().flipTo({ faceId: 'tails' });

const boxes = createLuckyBox({ boxes: [{ id: 'one' }, { id: 'two' }] });
boxes.select('one');
boxes.revealTo({ boxId: 'two' });

All three engines support injected randomness, exact controlled results, synchronous or asynchronous result providers, reset, immutable results, and late-provider invalidation. Lucky Box intentionally separates the selected and winning box.