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

@lippelt/srd-npcgen

v0.6.0

Published

Gerador de NPCs/stat blocks para a família d20 (D&D, Pathfinder, Starfinder), com saída para o tracker do GM Control Room e para o Campaign Codex.

Readme

@lippelt/srd-npcgen

Gerador de NPCs / stat blocks para a família d20 dos sistemas gmcr-srd-systems (D&D 5e 2024/2014, D&D 3.5, Pathfinder 1e/2e, Starfinder 1e/2e), com saída pronta para o tracker do GM Control Room e para o Campaign Codex.

Uso

import { generateNpc, toTrackerCombatant, toCodexMarkdown } from '@lippelt/srd-npcgen'

const npc = generateNpc({ systemId: 'dnd5e-2024', level: 5, role: 'soldier' })

toTrackerCombatant(npc) // { name, initiative, hp, maxHp, statuses, fields: { ac } }
toCodexMarkdown(npc)    // stat block em Markdown

Opções (generateNpc)

| Campo | Padrão | Descrição | |-------|--------|-----------| | systemId | — | Id de um sistema d20 (ex.: dnd5e-2024). | | level | 1 | Nível/CR aproximado (1..20). | | role | sorteado | Arquétipo: brute, soldier, skirmisher, archer, caster, leader, lurker, minion. | | abilityMethod | standard | standard (array 15..8), elite, average ou rolled (4d6 descarta menor). | | name | gerado | Nome fixo, senão gerado por sílabas. | | seed | — | Geração reproduzível (define o RNG internamente). |

Modelos de matemática

Dois modelos cobrem a família d20:

  • proficiency (5e 2024/2014, Pathfinder 2e, Starfinder 2e): bônus de proficiência 2 + ⌊(nível−1)/4⌋. Multiataque adiciona ataques com mesmo bônus.
  • bab (D&D 3.5, Pathfinder 1e, Starfinder 1e): BAB cheio aproximado (= nível) e saves bom/fraco. Ataques iterativos com bônus decrescente (−5).

Sistemas baseados em pool (Daggerheart, Candela Obscura, GUMSHOE) agora são suportados (v0.2.0+) — generateNpc despacha automaticamente por família. Veja seção Sistemas de pool abaixo.

As fórmulas são aproximações ao estilo "NPC de mesa" (não builds completos de PC): atributos por arquétipo, HP por dado de vida + CON, CA por armadura + Dex limitada, e ataque/perícias com a progressão do modelo.

Multiataque, escala de dano e benchmarks (v0.1.1)

Cada NPC gerado tem attacks: NpcAttack[] (lista) além do attack (alias do primeiro).

Multiataque por papel + modelo + nível

| Papel | proficiency | bab | |---|---|---| | Marciais (brute, soldier, skirmisher, archer, lurker) | 1 → 2 (lvl 5) → 3 (lvl 11) → 4 (lvl 20) | 1 → 2 (BAB 6) → 3 (BAB 11) → 4 (BAB 16) | | Leader | 1 → 2 (lvl 5) | 1 → 2 (lvl 5) | | Caster, Minion | 1 (sempre) | 1 (sempre) |

Escala de dado de dano

| Papel | Quantidade de dados | |---|---| | Caster | 1 (lvl 1–4) → 2 (5–10) → 3 (11–16) → 4 (17+) — estilo cantrip 5e | | Brute | 1 (1–10) → 2 (11+) | | Demais marciais / leader / minion | 1 (sempre — a arma "escala" via multiataque) |

Benchmarks de CR

getBenchmark(level) retorna HP/CA/ataque/CD/dano-por-round esperados pelo estilo 5e DMG. Cada NPC gerado já vem com npc.benchmark pra você comparar a saída com o alvo do CR.

Sistemas de pool (v0.2.0)

generateNpc({ systemId: 'daggerheart' | 'candela-obscura' | 'gumshoe' }) agora retorna PoolGeneratedNpc em vez de lançar erro. O retorno é uma união discriminada — use os type guards isD20Npc / isPoolNpc pra narrow.

import { generateNpc, isD20Npc, isPoolNpc } from '@lippelt/srd-npcgen'

const npc = generateNpc({ systemId: 'daggerheart', level: 5, name: 'Boss' })

if (isPoolNpc(npc)) {
  npc.tracks.hp        // { current: 12, max: 12 }
  npc.extra            // sistema-específico (Daggerheart: tier/difficulty/evasion/thresholds)
}

Daggerheart

  • 10 roles: bruiser, horde, leader, minion, ranged, skulk, social, solo, standard, support
  • 4 tiers (lvls 1-3 / 4-6 / 7-9 / 10)
  • Tracks: HP, Stress, Armor, Hope
  • Extra: difficulty, evasion, majorThreshold, severeThreshold, range

Candela Obscura

  • 7 roles: cultist, investigator, mundane, occultist, spectre, thug, whisper
  • 3 tiers (capacho / padrão / chefe)
  • Tracks: marcas de body, brain, bleed (0..3 cada)
  • Extra: hitThreshold, drives (nerve/cunning/intuition)

GUMSHOE

  • 7 roles: cultist, investigator, mook, monster, professional, thug, witness
  • 3 tiers (escalando pools)
  • Tracks: Health, Stability + Athletics, Fighting, Weapons (pools)
  • Extra: hitThreshold, pools, attackDamageMod

Hook de sistema (v0.1.4)

Cada sistema do @lippelt/srd-* pode opcionalmente expor npc: SystemNpcHooks no objeto System (definido no @lippelt/srd-core). O npcgen aceita os mesmos hooks via NpcOptions.npc:

import { getSystem } from '@lippelt/srd-core'
import { generateNpc } from '@lippelt/srd-npcgen'

const pf2 = getSystem('pathfinder-2e')!
const npc = generateNpc({
  systemId: 'pathfinder-2e',
  level: 10,
  role: 'soldier',
  npc: pf2.npc, // passa hooks do sistema se existirem
})

| Hook | Default genérico | Quando faz sentido | |---|---|---| | attackProgression(level, role) | 5e: 2 + ⌊(lvl−1)/4⌋ (proficiency) ou BAB cheio | PF2/SF2: level + rank bonus (rank trained +2 / expert +4 / master +6 / legendary +8) | | cantripDamageDice(level) | 5e: 1/2/3/4 dados em 1/5/11/17 | PF2: heightening a cada 2 níveis | | skills | (não usado ainda) | Lista canônica de perícias do sistema | | defaultLanguages(creatureType) | Português padrão por tipo (Comum, Abissal, etc) | Settings exóticos (Starfinder: Galáctico, Vesk, Ysoki etc) |

Sem hook → cai no genérico. Hook parcial é OK: só os campos definidos são usados.

Criatura, armas e resistências (v0.1.3)

Todo NPC vem com:

  • npc.creaturetype (humanoid/beast/undead/fiend/celestial/fey/dragon/aberration/construct/elemental/giant/monstrosity/ooze/plant), size (tiny..gargantuan), senses (darkvision-60/120, blindsight, low-light, tremorsense, truesight), movements (walk/fly/swim/climb/burrow em pés), languages.
  • npc.resistancesdamageResistances/damageImmunities/damageVulnerabilities/conditionImmunities, derivadas do tipo (undead imune a poison, fiend resiste a cold/fire/lightning vulnerável a radiant, construct imune a várias condições, etc).
  • npc.weapon — arma assinatura completa (name, category, damageDie, damageType, range/reach, properties). Mapeada do role (brute → machado grande, archer → arco longo, caster → dardo arcano, etc).

Opções novas

| Opção | Default | Conteúdo | |---|---|---| | creatureType | 'humanoid' | Um dos tipos acima. Afeta sentidos/movimentos/idiomas/resistências. | | creatureSize | 'medium' | tiny/small/medium/large/huge/gargantuan. Afeta walking. | | nameStyle | 'fantasy' | fantasy / sci-fi / lovecraftian / cyberpunk / plain. | | withEpithet | false | Anexa título/epíteto ("Korak o Astuto", "V1per netrunner"). |

Exemplos

// Dragão jovem azul, large, com voo e darkvision
generateNpc({ systemId: 'dnd5e-2024', level: 10, role: 'brute',
              creatureType: 'dragon', creatureSize: 'large' })

// Replicante operativo no Starfinder, com epíteto sci-fi
generateNpc({ systemId: 'starfinder-2e', level: 5, role: 'archer',
              nameStyle: 'sci-fi', withEpithet: true })

// Avatar do Yog-Sothoth com nome lovecraftiano
generateNpc({ systemId: 'dnd5e-2024', level: 15, role: 'caster',
              creatureType: 'aberration', nameStyle: 'lovecraftian',
              withEpithet: true })

Tuning específico por papel/sistema (v0.1.2)

Quando aplicável, o NPC ganha campos extras:

| Campo | Quando aparece | Conteúdo | |---|---|---| | npc.magic | role === 'caster' | { spellAbility, spellSaveDC, spellAttackBonus, cantripDamage } | | npc.starfinder | systemId em SF1/SF2 | { stamina, kac, eac, resolve } (drena SP antes do HP) | | npc.proficiencyRank | systemId em PF2/SF2 | 'trained' \| 'expert' \| 'master' \| 'legendary' | | npc.fortSave/refSave/willSave | sempre | atalhos pros saves clássicos (CON/DEX/WIS) |

A matemática do PF2 (level + bônus de rank) difere do 5e. O attackProgression ainda usa o 5e — proficiencyRank é informativa. Tuning matemático fino do PF2 é planejado pro próximo PR (Bloco A item 11, hook System.npc?).

Exemplo

const mago = generateNpc({ systemId: 'dnd5e-2024', level: 9, role: 'caster' })
mago.magic              // { spellAbility: 'cha', spellSaveDC: 14, spellAttackBonus: 6, cantripDamage: '2d8+2' }
mago.fortSave           // atalho pra saves.con

const operative = generateNpc({ systemId: 'starfinder-2e', level: 11, role: 'archer' })
operative.starfinder    // { stamina: ..., kac: ..., eac: ..., resolve: ... }
operative.proficiencyRank  // 'master'
const npc = generateNpc({ systemId: 'dnd5e-2024', level: 10, role: 'brute' })
npc.attacks.length     // 2 (Extra Attack ativo)
npc.attacks[0].damage  // '1d10+4' (brute lvl 10, ainda 1 dado)
npc.benchmark          // { level: 10, hp: 250, ac: 17, attackBonus: 7, ... }