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

@tourneytek/blind-structure

v1.0.0

Published

Generate poker blind structures from player count, stack, and target duration — chip-denomination aware, with breaks, antes and chip-ups. Zero dependencies.

Readme

@tourneytek/blind-structure

CI npm types license

Generate a poker blind structure from the things a host actually knows: how many players, how many chips each, how long the night should run, and which chips are on the table.

Zero dependencies. One pure function. Ships ESM + CJS with types.

Extracted from Poker Hawk.

npm install @tourneytek/blind-structure
import { generateBlindStructure } from '@tourneytek/blind-structure';

const schedule = generateBlindStructure({
  playerCount: 8,
  startingStack: 10_000,
  tournamentLengthHrs: 3,
  levelDurationMins: 15,
  chipDenoms: [25, 100, 500, 1_000, 5_000],
  blindFactor: 1,
  roundingThresholdFactor: 1,
  breakFrequency: 4,
  breakDurationMins: 10,
  includeChipUp: true,
  bbRule: 'double',
  anteRule: 'none',
});

// [ { level: 1, type: 'blind', smallBlind: 25, bigBlind: 50, ante: 0, durationMins: 15 },
//   …
//   { level: 4, type: 'chip-up', durationMins: 10 },
//   … ]

The chips are the whole problem

Plenty of tools will draw you a geometric curve from 25/50 up to something enormous. That curve is useless if it asks for a 150 chip when the smallest denomination in the box is 25 — and worse if it asks for 25s an hour after you coloured them up.

So the rounding base climbs through your denominations as the blinds grow. When it promotes, the structure can emit a chip-up break at exactly the moment the room needs to swap chips:

schedule.filter((e) => e.type === 'chip-up');
// → the breaks where a denomination just left play

roundingThresholdFactor tunes how eagerly that promotion happens — raise it to keep smaller chips in play longer.

Options

| Option | Meaning | | --- | --- | | playerCount, startingStack | Together set the chips in play. The final big blind targets 7% of that. | | tournamentLengthHrs | Target running time. An hour of padding is added so a structure that runs long doesn't fall off the end. | | levelDurationMins | Minutes per level. | | chipDenoms | Denominations on the table. Required — this drives all rounding. | | blindFactor | Escalation shape. 1 spreads the climb evenly; higher accelerates, lower flattens. | | roundingThresholdFactor | How eagerly the rounding base promotes. 1 is the default cadence. | | breakFrequency, breakDurationMins | Break every N levels. Omit for none. | | includeChipUp | Mark a break as chip-up when the denomination promotes. | | bbRule | 'none' · 'double' · 'min1_5x' | | anteRule | 'none' · 'bb_percent' · 'match_sb' · 'match_bb' | | antePercent | Percentage of the big blind when anteRule is 'bb_percent'. Default 12.5. |

The result is a discriminated union — type: 'blind' entries carry blinds and an ante; type: 'break' | 'chip-up' entries carry only a duration:

import { blindLevelsOnly, scheduleDurationMins } from '@tourneytek/blind-structure';

blindLevelsOnly(schedule); // just the playing levels
scheduleDurationMins(schedule); // total minutes, breaks included

Guarantees

  • Blinds are never zero. See below.
  • Blinds only ever use payable denominations — every value is a multiple of your smallest chip.
  • Blinds escalate monotonically. No level is cheaper than the one before it.
  • Antes never exceed the big blind, and never fall below the smallest chip (an ante you can't pay isn't an ante).
  • A break is never the last thing on the schedule — that's just an early night.
  • Bad input returns [] rather than throwing: no denominations, non-positive denominations, or a non-positive level duration.

The zero-blind bug

This library exists partly because of one bug worth naming.

The rounding step is Math.round(value / base) * base. When the base promotes to the next denomination while the small blind is still under half of it, that expression returns 0 — and with bbRule: 'double', the big blind derives from the small blind and goes to zero too. The result is a level, mid-tournament, with blinds of 0/0.

Across a sweep of 600 realistic parameter combinations against the original implementation, 11.2% produced at least one zero-blind level — 170 broken levels in total. Denomination sets starting at 100 were the worst hit.

The fix is a floor at the rounding base, so a promoted blind lands on the new denomination rather than on nothing. It's covered by a test that sweeps every denomination set, blind factor and rounding threshold this library ships with.

License

MIT © TourneyTek, Inc.