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

mtg-calculator

v0.1.7

Published

an MtG calculator for computing the probability of being able to draw and play cards from a deck

Downloads

12

Readme

MtG Calculator

Installation

npm i mtg-calculator

Getting started

import { computeCurve } from 'mtg-calculator';

const island = {
  name: 'Island',
  quantity: 15,
  mana_cost: '',
  types: 'Basic Land — Island',
  type: 'Land',
  producible_mana_colors: 'U',
  tap_land: false
};

const vizzerdrix = {
  name: 'Vizzerdrix',
  quantity: 1,
  mana_cost: '{6}{U}',
  types: 'Creature — Rabbit Beast',
  type: 'Nonland'
};

const deck = [
  island,
  vizzerdrix,
];

const { calculations } = computeCurve(vizzerdrix, deck);

console.log(calculations); /* -> [
    {
      independent: '0',
      conditionalTargetDrawn: '0',
      conditionalEnoughLand: '0'
    },
    {
      independent: '0',
      conditionalTargetDrawn: '0',
      conditionalEnoughLand: '0'
    },
    {
      independent: '0',
      conditionalTargetDrawn: '0',
      conditionalEnoughLand: '0'
    },
    {
      independent: '0',
      conditionalTargetDrawn: '0',
      conditionalEnoughLand: '0'
    },
    {
      independent: '0',
      conditionalTargetDrawn: '0',
      conditionalEnoughLand: '0'
    },
    {
      independent: '0',
      conditionalTargetDrawn: '0',
      conditionalEnoughLand: '0'
    },
    {
      independent: '0.8125',
      conditionalTargetDrawn: '1',
      conditionalEnoughLand: '0.8125'
    }
  ]
  */

API

computeCurve(card, deck, options)

Returns an array of probabilities of being able to play the given card from the given deck, on the given turn. Where the index of the calculation in the list is turn - 1.

Parameters:

  • card (Card, required): minimal card object transformed from Scryfall's API
  • deck (Card[], required): a list of cards
  • options (AlgoOptions, optional): configuration options, see types below for more info

Returns: Object (Calculations): list of calculations for each turn (in order starting from turn 1), and a flag to denote if simulations were used.

scryfallToCard(card)

Transforms a card object directly from the Scryfall API (or an object implementing the PartialScryfallCard interface), into a usable card object for computeCurve.

Parameters:

  • card (PartialScryfallCard | CardFace, required): The card to transform into usable input for calculations

Returns: Object (Card): The object type/structure for creating decks and computing probabilities with.

Types

// Based off of Scryfall.com's API, see https://scryfall.com/docs/api/cards for more info
interface PartialScryfallCard {
  name: string;
  type_line?: string;
  oracle_text?: string;
  mana_cost?: string;
  produced_mana?: string[];
  card_faces?: CardFace[];
  quantity?: number;
  [key: string]: any;
}

interface CardFace {
  name?: string;
  type_line?: string;
  oracle_text?: string;
  mana_cost?: string;
}

// Inputs:
type AlgoOptions = {
  maxComplexity?: number, // default: 30,000 — a threshold that when crossed causes the algorithm to fallback on a statistical simulation. If set to 0, will never fallback on simulations
  upToTurn?: number, // default: card CMC — how long the list of calculations should be
  simulationOptions?: {
    iterations?: number // default: 10,000 - how many iterations of the simulation should be done when complexity threshold is crossed
  };
}

type Card = {
  name: string,
  mana_cost: string, // example: "{W}{W}{3}"
  types: string, // example: "Land - Enchantment"
  type: CardType,
  producible_mana_colors: string, // example: "G,W,C"
  tap_land: boolean,
  quantity: number,
}

enum CardType {
  Nonland = "Nonland",
  Land = "Land",
}

type Deck = Card[]

// Outputs
type Calculations = {
  calculations: ProbabilitiesOnGivenTurn[],
  simulated: boolean,
}

type ProbabilitiesOnGivenTurn = {
  [key in ProbabilityTypes]: Probability;
}

enum ProbabilityTypes {
  independent = "independent", // P of being able to draw and play the card
  conditionalTargetDrawn = "conditionalTargetDrawn", // P of being able to play the card, given it was drawn
  conditionalEnoughLand = "conditionalEnoughLand", // P of being able to draw and play the card given enough lands to play its CMC
}

type Probability = string // representing a number between 0-1, up to 20 decimal places

License

This project is licensed under the CC BY-NC 4.0.
Non-commercial use only. For commercial use, contact [email protected]