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 🙏

© 2024 – Pkg Stats / Ryan Hefner

ttrpg-tools

v1.2.1

Published

API for generating random dice rolls, NPCs, towns, names, etc. for TTRPG campaigns.

Downloads

34

Readme

ttrpg-tools

Npm package version Npm package total downloads GitHub issues Maintenance Maintainer Twitter Maintainability Test Coverage

Library for generating random dice rolls, NPCs, towns, names, etc. for TTRPG campaigns.

  1. How To Import
  2. API
  3. Customize Data
  4. Supported Races
  5. Supported Classes
  6. Contribute
  7. Contact Information

How to Import

ES Module Default Export

import ttrpgTools from 'ttrpg-tools'

const {
  coin, d4, d6, d8, d10, d12, d20, d100, diceRoll, data,
  generateNpcName, generateTownName, generateNpc, generateTown
} = ttrpgTools

ES Module Named Exports

import {
  coin, d4, d6, d8, d10, d12, d20, d100, diceRoll, data,
  generateNpcName, generateTownName, generateNpc, generateTown
}  from 'ttrpg-tools'

API

Standard Dice

| Parameter | Type | Default | Description | | --------- | ---- | ------- | ----------- | | dieCount | Number | 1 | How many dice to roll. | | verbose | Boolean | false | Whether to return an object with individual roll results and total. | | modifier | Number | 0 | Add modifier to roll. | | withAdvantage | Boolean | false | Whether to roll with advantage. | | withDisadvantage | Boolean | false | Whether to roll with disadvantage. |

import { d4, d6, d8, d10, d12, d20, d100 } from 'ttrpg-tools'

const d4Roll = d4() // Defaults to a single die
const d6RollThreeDice = d6(3)
const d8RollFiveDiceVerbose = d8(5, true)
const d10RollWithModifier = d10(1, false, 2)
const d12RollWithAdvantage = d12(1, false, 0, true)
const d20RollWithDisadvantage = d20(1, false, 0, false, true)
const d100RollWithClashingAdvantage = d100(1, false, 0, true, true) // First roll is used
// d4 roll - single die
{ "4": 3 }

// d6 roll - three dice
{ "6": 15 }

// d8 roll - five dice, verbose
{ "8": {
    "rolls": [3, 7, 4, 8, 6],
    "total": 28
  }
}

// d10 roll - single die
{ "10": 8 }

// d12 roll - single die
{ "12": 5 }

// d20 roll - single die
{ "20": 16 }

// d100 roll - single die
{ "100": 42 }

Custom Dice

| Parameter | Type | Default | Description | | -------- | ---- | ------- | ----------- | | dice | Object | | (Required) How many coins to flip. | | asNumeric | Boolean | false | Whether to return an object with 1 and 0 instead of "heads" and "tails", respectively. | | modifier | Number | 0 | Add modifier to roll. | | withAdvantage | Boolean | false | Whether to roll with advantage. | | withDisadvantage | Boolean | false | Whether to roll with disadvantage. |

import { diceRoll } from 'ttrpg-tools'

const rollManyDieTypes = diceroll({
  "4": 2,
  "6": 1,
  "8": 2,
  "10": 3,
  "12": 1,
  "42": 1
}, true)
// diceRoll with multiple die types
{
  "4": {
    "rolls": [2, 1],
    "total": 3
  },
  "6": {
    "rolls": [5],
    "total": 5
  },
  "8": {
    "rolls": [5, 7],
    "total": 12
  },
  "10": {
    "rolls": [10, 2, 6],
    "total": 18
  },
  "12": {
    "rolls": [9],
    "total": 9
  },
  // NOTE: You can also roll custom die types
  "42": {
    "rolls": [42],
    "total": 42 // The Meaning of life, the universe, and everything!
  }
}

Coin Flips

| Parameter | Type | Default | Description | | -------- | ---- | ------- | ----------- | | coinFlips | Number | 1 | Specify which die types and their counts to be rolled. | | verbose | Boolean | false | Whether to return an object with individual roll results and total. | | modifier | Number | 0 | Add modifier to coin toss. | | withAdvantage | Boolean | false | Whether to toss coin with advantage. | | withDisadvantage | Boolean | false | Whether to toss coin with disadvantage. |

import { coin } from 'ttrpg-tools'

const flippedCoin = coin() // Defaults to one coin flip
const flippedCoins = coin(3)
const flippedCoinsNumericResults = coin(3, true) // Replace "heads" and "tails" with 1 and 0 respectively.
// flippedCoin
{ "heads": 1,  "tails": 0 }

// flippedCoins
{ "heads": 2,  "tails": 1 }

// flippedCoins with numeric results
{ "1": 2,  "0": 1 }

Name Generators

| Parameter | Type | Default | Description | | --------- | ---- | ------- | ----------- | | generateNpcName | sex | String | | (Required) The sex of the NPC: 'male' or 'female'. | | | generateTownName | withDescriptor | Boolean | false | Whether to guarantee a descriptor name part. If false, there's only a 20% chance to add it. | | withPostDescriptor | Boolean | false | Whether to guarantee a postDescriptor name part. If false, there's only a 20% chance to add it. | | usePremade | Boolean | false | Whether to use a premade town name instead of a generated name. |

import { generateNpcName, generateTownName } from 'ttrpg-tools'

const npcName = generateNpcName('male')
const townName = generateTownName()
const townNameWithDescriptor = generateTownName(true)
// Randomly generated NPC name
"Jon Heder"

// Randomly generated town name
"Spruceport"

// Randomly generated town name with guaranteed descriptor name part
"Little Redwoods"

NPC Generator

The parameters are passed in as a single object, with the property names defined below.

| Property | Type | Default | Description | | -------- | ---- | ------- | ----------- | | familyName | String | | Specify NPC's family/last name. | | givenName | String | | Specify NPC's given/first name. | | homeTown | String | | Specify name of NPC's hometown. | | languages | Array[Strings] | | Specify the languages spoken by the NPC. | | npcClass | String | | Specify NPC's class. (Can deviate from Supported Classes section below.) | | occupation | String | | Specify NPC's occupation. | | race | Array[Strings] | | Specify the NPC's race. (Must match races from Supported Races section below.) | | randomizeClass | Boolean | | Whether to ensure the NPC has a class. If false, then NPC has 10% of having a class. | | sex | String | | Specify NPC's sex. |

import { generateNpc } from 'ttrpg-tools'

const npc = generateNpc()
const npcWithSpecifiedName = generateNpc({ givenName: 'Tina', familyName: 'Fey' })
{
  // NPC's name
  "fullName": "Tina Fey",
  "givenName": "Tina",
  "familyName": "Fey",

  // NPC's sex
  "sex": "female",

  // Randomized town name for NPC's hometown
  "homeTown": "New York City",

  // NPC's occupation
  "occupation": "Actor",

  // NPC's class. Unless specified or `randomizeClass` flag is passed, NPCs will only have a class 10% of the time.
  "class": "Bard",

  // Languages spoken by the NPC
  "languages": [ "Common" ],

  // NPC's race
  "race": {
    "name": "Human",
    "avgAgeOfDeath": 100,
    "avgHeight": 6,
    "avgWeight": 180,
    "size": "medium",
    "baseClimbSpeed": 15,
    "baseFlightSpeed": 0,
    "baseSwimSpeed": 15,
    "baseWalkSpeed": 30,
    "languages": [ "Common" ]
  }
}

Town Generator

The parameters are passed in as a single object, with the property names defined below.

| Property | Type | Description | | -------- | ---- | ----------- | | name | String | Specify the town name. | | races | Array[Strings] | Specify the prevalent races in the town. Must match races from Supported Races section below. | | size | String | Specify the town population size ranges. xs: 5-20, sm: 21-50, md: 51-100, lg: 101-250, xl: 251-1000 |

import { generateTown } from 'ttrpg-tools'

const town = generateTown()
const townWithSpecifiedName = generateTown({ name: 'Feywild City' })
{
  // Town name
  "name": "Oakport",

  // Population size
  "size": 124,

  // 1-5 prevalent races in the town.
  "races": [
    {
      "name": "Halfling",
      "avgAgeOfDeath": 250,
      "avgHeight": 3,
      "avgWeight": 40,
      "size": "small",
      "baseClimbSpeed": 12,
      "baseFlightSpeed": 0,
      "baseSwimSpeed": 12,
      "baseWalkSpeed": 25,
      "languages": [ "Common",  "Halfling" ]
    },
    ...
  ],

  // Languages spoken in the town
  "languages": [ "Common", "Halfling" ],

  // Is one of the prevalent races, speaks all town's languages.
  "leader": randomizedNpcObject
}

Customize Data

This library is intended to continually grow its data to provide the best procedurally generative experience possible, but may not grow as fast as you would like. In an attempt to roll high initiative in that combat, I introduce to you the ability to customize the data!

The data methods are made available via the data named export.

import { data } from 'ttrpg-tools'

Classes, Languages, and Occupations

Classes, Languages, and Occupations data are all arrays of strings. The examples below could be appllied to any of these three data sets.

// Get the available list of classes (customized or not)
data.classes.get()

// Get the list of classes provided originally by ttrpg-tools
// It can be useful to use this if you want to use most classes, but filter out a few for when you call the customize method.
data.classes.getOriginal()

// Customize the available classes (Append to existing classes)
// Note: This will append your list of new classes to the end of the available list.
// Note: Duplicates are removed.
data.classes.customize(['Couch Potato'])

// Customize the available classes (Replace existing classes)
// Note: This will replace the existing classes with the list of classes you provide here.
data.classes.customize(['Couch Potato'], true)

// Reset to factory settings
data.classes.reset()

Races

Races data is stored in this format:

{
  "Human": {
    "name": "Human",
    "avgAgeOfDeath": 100,
    "avgHeight": 6.0,
    "avgWeight": 180.0,
    "size": "medium",
    "baseClimbSpeed": 15,
    "baseFlightSpeed": 0,
    "baseSwimSpeed": 15,
    "baseWalkSpeed": 30,
    "languages": [
      "Common"
    ]
  }
}

Note: Any missing properties will be filled in with the Human's values. Note: You can add custom properties to a race. Note: You can override a race by using the same key name with a new race object.

// Get the available races (customized or not)
data.races.get()

// Get the races data originally provided by ttrpg-tools
data.races.getOriginal()

// Customize the available races (Append to existing races)
// Note: The remaining expected properties will be filled in using Human values.
data.races.customize({
  'Couch Potato': {
    name: 'Couch Potato', // Required
    avgAgeOfDeath: 30,
    size: 'large',
    customPropertyThatIWouldLikeToInclude: 42
  }
 })

// Customize the available races (Replace existing races)
// Note: This will replace all races with the races provided.
data.races.customize({
  'Couch Potato': {
    name: 'Couch Potato', // Required
    avgAgeOfDeath: 30,
    size: 'large',
    customPropertyThatIWouldLikeToInclude: 42
  }
 }, true)

// Reset to factory settings
data.races.reset()

NPC Name Parts

NPC Name Parts data is stored in this format:

{
  givenNames: {
    female: ['Brienna'],
    male: ['Bryce'],
  },
  familyNames: ['Lastnamington']
}

Note: You do not have to customize all name parts arrays when you call the customize method. For example, you could only pass in { givenNames: { male: ['Brad', 'Chad', 'Lad']}} to just affect the male givenNames.

// Get the available NPC name parts (customized or not)
data.npcNames.get()

// Get the NPC name parts data originally provided by ttrpg-tools
data.npcNames.getOriginal()

// Customize the available NPC name parts (Append to existing name parts)
// Note: This example adds the female and male given names to the available name parts data, and it leaves the familyNames as it is.
data.npcNames.customize({
  givenNames: {
    female: [ 'Lynn', 'Patricia', 'Gertrude' ],
    male: [ 'Carl', 'Buster' ]
  }
})

// Customize the available NPC name parts (Replace existing NPC name parts)
// Note: This will replace all femilyNames with the provided list, but the male and female given names will be left alone.
data.npcNames.customize({ familyNames: ['Owlbearslayer'] }, true)

// Reset to factory settings
data.npcNames.reset()

Town Name Parts

Town Name Parts data is stored in this format:

{
  descriptors: ['Little', 'Higher', 'Grand']
  prefixes: ['Red', 'Asp']
  suffixes: ['woods', 'river', ' Town']
  postDescriptors: ['in the East', 'City', 'Creek'],
  premades: ['Rivendell', 'Hobbiton', 'Gondor']
}

Note: You do not have to customize all name parts arrays when you call the customize method. For example, you could only pass in { descriptors: ['Brad', 'Chad', 'Lad'] } to just affect the male descriptor name parts.

// Get the available town name parts (customized or not)
data.townNames.get()

// Get the NPC name parts data originally provided by ttrpg-tools
data.townNames.getOriginal()

// Customize the available town name parts (Append to existing name parts)
// Note: This example adds the descriptor, prefix, and postDescriptor name parts to the currently available town name parts data.
data.townNames.customize({ descriptors: ['Lower'], prefixes: ['Green', 'Oak'], postDescriptors: ['Landing'] })

// Customize the available town name parts (Replace existing town name parts)
// Note: This will replace suffix name parts and premades data with the provided lists of suffixes and premades.
data.townNames.customize({ suffixes: ['Owlbear', 'Mound'], premades: ['Mordor']}, true)

// Reset to factory settings
data.townNames.reset()

Supported Races

Currently, the only races supported are form D&D 5e.

  • Aarakocra
  • Aasimar
  • Air Genasi
  • Bugbear
  • Centaur
  • Changeling
  • Deep Gnome
  • Dragonborn
  • Duergar
  • Dwarf
  • Earth Genasi
  • Eladrin
  • Elf
  • Fairy
  • Firbolg
  • Fire Genasi
  • Githyanki
  • Githzerai
  • Gnome
  • Goblin
  • Goliath
  • Grung
  • Half-Elf
  • Halfling
  • Half-Orc
  • Harengon
  • Hobgoblin
  • Human
  • Kalashtar
  • Kenku
  • Kobold
  • Leonin
  • Lizardfolk
  • Locathah
  • Loxodon
  • Minotaur
  • Orc
  • Owlin
  • Satyr
  • Sea Elf
  • Shadar-kai
  • Shifter
  • Tabaxi
  • Tiefling
  • Tortle
  • Triton
  • Vedalken
  • Verdan
  • Warforged
  • Water Genasi
  • Yuan-ti

Supported Classes

Currently, the only classes supported are the basic D&D 5e class. More will be added.

  • Artificer
  • Barbarian
  • Bard
  • Cleric
  • Druid
  • Fighter
  • Monk
  • Paladin
  • Ranger
  • Rogue
  • Sorcerer
  • Warlock
  • Wizard

Contribute

I welcome any help you are willing to provide! Simply add an "Issue" in the Issues section in Github or fork the project and create a pull request. Feel free to send me an email or tweet if you want to have a conversation.

Thank you for you support!

Contact Information

Email: [email protected]

Twitter: @JHStoops