Silverbullet excels as a place to organize your notes as a ttrpg/D&D dungeon master. Being able to link worlds and adventures and players and player characters and monsters and locations – and being able to query between them all – can help the most scatter-brained forever-DM’s among us keep track of our many adventures and all the myriad ways our players run amuck.
Open5E is an open source project aiming to provide a usable database and API of open-licensed 5th edition and 5e compatible content.
Enter: Space Script. This in-progress project aims to create a set of space script functions that call Open5E, and accompanying snippets that make it easy to slash-command add spells, monsters, items – whatever – right into your notes. I’d certainly appreciate any help along the way, but the proof of concept is already here and very promising.
To start off, wherever you’re saving your space-script functions (I have a “space-script-index” page), let’s add the following:
Open 5e Fetch Functions:
Fetch Spell Function:
silverbullet.registerFunction("fetchSpell", async (spellName) => {
const url = `https://api.open5e.com/spells/${spellName}`;
const response = await fetch(url);
if (!response.ok) {
throw new Error(`Error fetching spell: ${response.statusText}`);
}
const spellData = await response.json();
return spellData;
});
Fetch Monster Function:
silverbullet.registerFunction("fetchMonster", async (monsterSlug) => {
const url = `https://api.open5e.com/monsters/${monsterSlug}`;
const response = await fetch(url);
if (!response.ok) {
throw new Error(`Error fetching monster: ${response.statusText}`);
}
const monsterData = await response.json();
return monsterData;
});
Open5E Snippets
Now, let’s create a snippet for spells:
---
tags: template
description: inserts a spell from Open5E
hooks.snippet.slashCommand: 5e-spell-snippet
---
```template
{{escapeDirective("#let @spell = fetchSpell('|^|')")}}
# {{escapeDirective "@spell.name"}}
- **Description**: {{escapeDirective "@spell.desc"}}
- **Range**: {{escapeDirective "@spell.range"}}
- **Components**: {{escapeDirective "@spell.components"}}
- **Duration**: {{escapeDirective "@spell.duration"}}
- **Casting Time**: {{escapeDirective "@spell.casting_time"}}
- **Level**: {{escapeDirective "@spell.level"}}
- **School**: {{escapeDirective "@spell.school"}}
{{escapeDirective("/let")}}
```
Now, once you reload your system you should be able to call the function with, e.g. {{fetchSpell(“fireball”)}} or {{fetchMonster(“kobold”)}} in a template codeblock, or use the snippet to get a more neatly formatted spell by typing “/5espellsnippet”.
Monster Snippet/statblock:
Now, here’s where you come in, if you know more about this than I do. The monster statblock is a WIP, and currently is having trouble rendering actions, abilities and legendary actions (I think it’s because the API returns an array, and I can’t figure out how to get that to display correctly…). But here’s what I’m working with now:
---
tags: template
description: Inserts comprehensive monster information from Open5E
hooks.snippet.slashCommand: 5e-monster-snippet
---
{{escapeDirective("#let @monster = fetchMonster('|^|')")}}
# {{escapeDirective("@monster.name")}}
*Size*: {{escapeDirective("@monster.size")}}, *Type*: {{escapeDirective("@monster.type")}}, *Alignment*: {{escapeDirective("@monster.alignment")}}
- **Armor Class (AC)**: {{escapeDirective("@monster.armor_class")}}
- **Hit Points (HP)**: {{escapeDirective("@monster.hit_points")}} ({{escapeDirective("@monster.hit_dice")}})
- **Speed**: {{escapeDirective("@monster.speed")}}
**Abilities:**
| STR | DEX | CON | INT | WIS | CHA |
|-----|-----|-----|-----|-----|-----|
| {{escapeDirective("@monster.strength")}} | {{escapeDirective("@monster.dexterity")}} | {{escapeDirective("@monster.constitution")}} | {{escapeDirective("@monster.intelligence")}} | {{escapeDirective("@monster.wisdom")}} | {{escapeDirective("@monster.charisma")}} |
**Senses**: {{escapeDirective("@monster.senses")}}
**Languages**: {{escapeDirective("@monster.languages")}}
**Challenge Rating (CR)**: {{escapeDirective("@monster.challenge_rating")}}
{{escapeDirective("#if @monster.special_abilities")}}
## Special Abilities
{{escapeDirective("#each @monster.special_abilities")}}
{{escapeDirective("#if this")}}
- **{{escapeDirective("this.name")}}**: {{escapeDirective("this.desc")}}
{{escapeDirective("/each")}}
{{escapeDirective("/if")}}
{{escapeDirective("#if @monster.actions")}}
## Actions
{{escapeDirective("#each @monster.actions")}}
- **{{escapeDirective("this.name")}}**: {{escapeDirective("this.desc")}}
{{escapeDirective("/each")}}
{{escapeDirective("/if")}}
{{escapeDirective("#if @monster.legendary_actions")}}
## Legendary Actions
{{escapeDirective("#each @monster.legendary_actions")}}
- **{{escapeDirective("this.name")}}**: {{escapeDirective("this.desc")}} (Attack bonus: {{escapeDirective("this.attack_bonus")}}, Damage: {{escapeDirective("this.damage_dice")}} + {{escapeDirective("this.damage_bonus")}})
{{escapeDirective("/each")}}
{{escapeDirective("/if")}}
**Source**: {{escapeDirective("@monster.document__title")}} (Page {{escapeDirective("@monster.page_no")}})
*{{escapeDirective("@monster.document__url")}}*
{{escapeDirective("/let")}}
Next Steps:
Obviously there’s a lot that can be done here. The Open5E API is full of great information that would be wonderful to implement in snippets/scripts. I think nailing down the monster snippet/statblock will make things move a lot quicker, but next I’d like to replicate this approach for magic items, equipment, character facing mechanics - anything I might want in Open5E.
It might also be nice if, instead of dropping in a live-updating template block it instead prompted you for a spell/monster/whatever name and then just pasted in theactual markdown text.
If there’s a way to autofill the names that might also be a nice feature, given that many of these items have long fantasy ass names and getting it right on the first swing might be difficult.
Anyways, long story short, I think that Silverbullet+space script+Open5E really represents an awesome potential for DM’s everywhere. I can’t be the only one coming to SB from Obsidian or Notion primarily as a DM first and coder/regular productive note taker second. Would love to help work with other users to refine some DM facing SB tools.