The tool formally known as Json 5e convert CLI.
CLI to convert 5eTools (๐ง and Pf2eTools) JSON into crosslinked, tagged, and formatted (with templates) markdown for use with Obsidian.md.
The instructions below still reference the released ttrpg-convert
CLI. New stuff is on the way!
Jump | โฌ Download | โ๏ธ Build | ๐ Conventions |
๐ Plugins | ๐ 5etools Data | ๐จ Templates | ๐ Changelog |
I use Obsidian to keep track of my campaign notes. This project parses json sources for materials that I own from the 5etools mirror to create linked and formatted markdown that I can reference in my notes.
๐ Check out Changes that impact generated templates and files and/or release notes for breaking changes and new capabilities.
There are several options for running ttrpg-convert
. Choose whichever you are the most comfortable with:
- Use pre-built platform binary
- Use Java Jar
- Build from source
- Using Windows? See the Windows README
Download the latest release of the zip or tgz for your platform. Extract the archive. A ttrpg-convert
binary executable will be in the extracted bin directory.
ttrpg-convert --help
Use this binary in the instructions below. Continue to notes about Conventions.
Notes:
- Open a command prompt in a folder (Windows)
- Running executables from the command line (Windows)
- To show emoji in Windows Commmand Prompt:
chcp 65001
and choose a font with emoji support (Consolas is one). You can also try the new Windows Terminal (wt.exe
). - MacOS permission checking (unverified executable):
xattr -r -d com.apple.quarantine <path/to>/ttrpg-convert
-
Install JBang: https://www.jbang.dev/documentation/guide/latest/installation.html
-
Install the pre-built release:
jbang app install --name ttrpg-convert --force --fresh https://github.com/ebullient/ttrpg-convert-cli/releases/download/2.0.5/ttrpg-convert-cli-2.0.5-runner.jar
If you want the latest unreleased snapshot (may not match this doc!):
jbang app install --name ttrpg-convert --force --fresh https://jitpack.io/dev/ebullient/ttrpg-convert-cli/299-SNAPSHOT/ttrpg-convert-cli-299-SNAPSHOT-runner.jar
There may be a pause if you download the snapshot; it is rebuilt on demand.
๐น Feel free to use an alternate alias by replacing the value specified as the name:
--name ttrpg-convert
, and adjust the commands shown below accordingly. -
Verify the install by running the command:
ttrpg-convert --help
Continue to notes about Conventions.
- Clone this repository
- Ensure you have Java installed on your system and active in your path.
- Build this project:
quarkus build
or./mvnw install
- Verify the build:
java -jar target/ttrpg-convert-cli-299-SNAPSHOT-runner.jar --help
To run commands listed below, either:
-
Replace
ttrpg-convert
withjava -jar target/ttrpg-convert-cli-299-SNAPSHOT-runner.jar
, or -
Use JBang to create an alias that points to the built jar:
jbang app install --name ttrpg-convert --force --fresh ~/.m2/repository/dev/ebullient/ttrpg-convert-cli/299-SNAPSHOT/ttrpg-convert-cli-299-SNAPSHOT-runner.jar
๐น Feel free to use an alternate alias by replacing the value specified as the name:
--name ttrpg-convert
, and adjust the commands shown below accordingly.
-
Links. Documents generated by this plugin will use markdown links rather than wiki links. A css snippet can make these links less invasive in edit mode by hiding the URL portion of the string.
-
File names. To avoid conflicts and issues with different operating systems, all file names are slugified (all lower case, symbols stripped, and spaces replaced by dashes). This is a familiar convention for those used to jekyll, hugo, or other blogging systems.
File names for resources outside of the core books (PHB, MM, and DMG) have the abbreviated source name appended to the end to avoid file collisions.
-
Organization. Files are generated in two roots:
compendium
andrules
. The location of these roots is configurable (see below).The following directories may be created in the
compendium
directory depending on what sources you have enabled:backgrounds
,bestiary
(with contents organized by monster type),classes
(separate documents for classes and subclasses),deities
,feats
,items
,names
,races
, andspells
. -
Styles. Every document has a
cssclass
attribute that you can use to further tweak how page elements render.css-snippets
has some snippets you can use to customize elements of the compendium.- 5e tools:
json5e-background
,json5e-class
,json5e-deity
,json5e-feat
,json5e-item
,json5e-monster
,json5e-names
,json5e-note
,json5e-race
, andjson5e-spell
. - pf2e tools:
pf2e
,pf2e-ability
,pf2e-action
,pf2e-affliction
,pf2e-archetype
,pf2e-background
,pf2e-book
,pf2e-delity
,pf2e-feat
,pf2e-hazard
,pf2e-index
,pf2e-item
,pf2e-note
,pf2e-ritual
,pf2e-sleep
,pf2e-trait
,
- 5e tools:
-
Admonitions.
ad-statblock
- 5e tools:
ad-flowchart
,ad-gallery
- pf2e tools:
ad-embed-ability
,ad-embed-action
,ad-embed-affliction
,ad-embed-avatar
,ad-embed-disease
,ad-embed-feat
,ad-embed-item
,ad-pf2-note
,ad-pf2-ritual
.
-
Admonitions: The admonitions plugin is used to render the statblocks and other admonitions. It also supports a codeblock style that is used for more complicated content like statblocks, where callout syntax would be difficult to manage.
Import one or more admonition json files in the examples directory to create the custom admonition types used for converted content:
- admonitions-5e.json for 5e tools
- admonitions-pf2e.json for pf2e tools
- other-admonitions.json if they are interesting
-
Force note view mode by front matter: I use this plugin to treat these generated notes as essentially read-only.
Ensure the plugin has the following options enabled:
- "Ignore force view when not in front matter": the plugin will only change the view mode if
obsidianUIMode
is defined in the front matter. - "Ignore open files": the plugin won't try to change the view mode if the file is already open.
- "Ignore force view when not in front matter": the plugin will only change the view mode if
-
TTRPG Statblocks: Templates for rendering monsters can define a
statblock
in the document body or provide a full or abridged yaml monster in the document header to update monsters in the plugin's bestiary. See Templates for more information. -
Initiative Tracker: Templates for rendering monsters can include information in the header to define monsters that initiative tracker can use when constructing encounters.
Within the examples/css-snippets
folder, you will find some CSS snippets that have been created to further customize the look of the generated content. They include:
- Functionality to float token images to side of a statblock.
- Further enhancement of the admonition styles.
- PF2 Only: More realistic looking Statblocks
- PF2 Only: Link Test to display action icons.
- PF2 Only: Light styling of pages as defined through css-classes.
- And much more.
If using the entire compendium
snippet, then you will not need to download and use the dnd5e-only-statblocks.css
or pf2-only-statblocks.css
snippets.
However, if interested in only using the statblock snippets, you will need to download one or both of the only-statblock.css
snippets, dependent on the system you are using.
โ ๏ธ Do not use anonly-statblock.css
snippet beside a compendium.css snippet.
-
Download a release of the 5e tools mirror, or create a shallow clone of the repo (which can/should be deleted afterwards):
git clone --depth 1 https://github.com/5etools-mirror-1/5etools-mirror-1.github.io.git
-
Invoke the CLI. In this first example, let's generate indexes and use only SRD content:
ttrpg-convert \ --index \ -o dm \ 5etools-mirror-1.github.io/data
--index
Createall-index.json
containing all of the touched artifact ids, andsrc-index.json
that shows the filtered/allowed artifact ids. These files are useful when tweaking exclude rules (as shown below).-o dm
The target output directory. Files will be created in this directory.
The rest of the command-line specifies input files:
5etools-mirror-1.github.io/data
Path to the data directory containing 5etools files (a clone or release of the mirror repo)
-
Invoke the command again, this time including sources and custom items:
ttrpg-convert \ --index \ -o dm \ -s PHB,DMG,SCAG \ -c dm-sources.json \ 5etools-mirror-1.github.io/data \ 5etools-mirror-1.github.io/data/adventure/adventure-lox.json \ 5etools-mirror-1.github.io/data/book/book-aag.json \ my-items.json
-
-s PHB,DMG,SCAG
Will include content from the Player's Handbook, the Dungeon Master's Guide, and the Sword Coast Adventurer's Guide, all of which I own.๐ธ Source abbreviations are found in the source code (around line 138)
-
-c dm-sources.json
contains configuration parameters (shown in detail below) -
Books (
/book/book-aag.json
) and adventures (/adventure/adventure-lox.json
) should be listed explicitly -
my-items.json
defines custom items for my campaign that follow 5etools JSON format.
-
๐ญ I recommend running the CLI against a separate directory, and then using a comparison tool of your choice to preview changes before you copy or merge them in.
You can use
git diff
to compare arbitrary directories:git diff --no-index vault/compendium/bestiary generated/compendium/bestiary
๐ ๐ง ๐ ๐ง ๐ ๐ง ๐ ๐ง
-
Download a release of the Pf2eTools mirror, or create a shallow clone of the repo (which can/should be deleted afterwards):
git clone --depth 1 https://github.com/Pf2eToolsOrg/Pf2eTools.git
-
Invoke the CLI. In this first example, let's generate indexes and use only SRD content (using the alias set up when installing the cli):
ttrpg-convert \ -g pf2e \ --index \ -o dm \ Pf2eTools/data
-g p2fe
The target output directory. Files will be created in this directory.--index
Createall-index.json
containing all of the touched artifact ids, andsrc-index.json
that shows the filtered/allowed artifact ids. These files are useful when tweaking exclude rules (as shown below).-o dm
The target output directory. Files will be created in this directory.
The rest of the command-line specifies input files:
5etools-mirror-1.github.io/data
Path to the data directory containing 5etools files (a clone or release of the mirror repo)
Configuration can also be provided as a JSON or YAML file instead of using command line parameters. See examples/config for the general config file structure.
I use something like this:
{
"from": [
"AI",
"PHB",
"DMG",
"TCE",
"LMoP",
"ESK",
"DIP",
"XGE",
"FTD",
"MM",
"MTF",
"VGM"
],
"paths": {
"rules": "/compendium/rules/"
},
"excludePattern": [
"race|.*|dmg"
],
"exclude": [
"monster|expert|dc",
"monster|expert|sdw",
"monster|expert|slw"
]
}
-
from
defines the array of sources that should be included. Only include content from sources you own. If you omit this parameter (and don't specify any other sources on the command line), this tool will only include content from the SRD.๐ธ Source abbreviations are found in the source code (around line 138)
-
paths
allows you to redefine vault paths for cross-document links, and to link to documents defining conditions, and weapon/item properties. By default, items, spells, monsters, backgrounds, races, and classes are in/compendium/
, while files defining conditions and weapon properties are in/rules/
. You can reconfigure either of these path roots in this block:"paths": { "compendium": "/compendium/", "rules": "/rules/" },
๐น Note: the leading slash indicates the path starting at the root of your vault.
-
exclude
andexcludePattern
: Exclude a single identifier (as listed in the generated index files), or all identifiers matching a pattern. In the above example, I'm excluding all of the race variants from the DMG, and the monster-form of the expert sidekick from the Essentials Kit. As it happens, I own these materials, but I don't want these variants in the formatted bestiary. -
include
(as of 1.0.13): Include a single identifier (as listed in the generated index files). This allows you to include a specific resource without including the whole source and excluding everything else. Useful for single resources (classes, backgrounds, races, items, etc.) purchased from D&D Beyond. To include the Changeling race from Mordenkainen Presents: Monsters of the Multiverse, for example, you would add the folowing:"include": [ "race|changeling|mpmm" ]
-
convert
(as of 1.0.18): specify books or adventures to import into the compendium (which will allow cross-linking, etc.). Either provide the full relative path to the adventure or book json file, or specify its Id (as found in the source code):"convert": { "adventure": [ "WBtW", "tftyp-wpm", ], "book": [ "5etools-mirror-1.github.io/data/book/book-phb.json" ] }
Note that some adventures, like Tales from the Yawning Portal, are treated as a collection of standalone modules. The generated index contains these as reference
items, but it can help you find the sources you own. The three sources shown in the example above are listed in the index as reference|adventure-wbtw
, reference|adventure-tftyp-wpm
, and reference|book-phb
respectively.
To generate player-focused reference content for a Wild Beyond the Witchlight campaign, I constrained things further. I am pulling from a smaller set of sources. I included Elemental Evil Player's Companion (Genasi) and Volo's Guide to Monsters (Tabaxi), but also used exclude
and excludePattern
to remove elements from these sourcebooks that I don't want my players to use in this campaign (some simplification for beginners).
The JSON looks like this:
{
"from": [
"PHB",
"DMG",
"XGE",
"TCE",
"EEPC",
"WBtW",
"VGM"
],
"includeGroups": [
"familiars"
],
"excludePattern": [
".*sidekick.*",
"race|.*|dmg",
"race|(?!tabaxi).*|vgm",
"subrace|.*|aasimar|vgm",
"item|.*|vgm",
"monster|.*|tce",
"monster|.*|dmg",
"monster|.*|vgm",
"monster|.*|wbtw",
"monster|animated object.*|phb"
],
"exclude": [
"race|aarakocra|eepc",
"feat|actor|phb",
"feat|artificer initiate|tce",
"feat|athlete|phb",
"feat|bountiful luck|xge",
"feat|chef|tce",
"feat|dragon fear|xge",
"feat|dragon hide|xge",
"feat|drow high magic|xge",
"feat|durable|phb",
"feat|dwarven fortitude|xge",
"feat|elven accuracy|xge",
"feat|fade away|xge",
"feat|fey teleportation|xge",
"feat|fey touched|tce",
"feat|flames of phlegethos|xge",
"feat|gunner|tce",
"feat|heavily armored|phb",
"feat|heavy armor master|phb",
"feat|infernal constitution|xge",
"feat|keen mind|phb",
"feat|lightly armored|phb",
"feat|linguist|phb",
"feat|lucky|phb",
"feat|medium armor master|phb",
"feat|moderately armored|phb",
"feat|mounted combatant|phb",
"feat|observant|phb",
"feat|orcish fury|xge",
"feat|piercer|tce",
"feat|poisoner|tce",
"feat|polearm master|phb",
"feat|prodigy|xge",
"feat|resilient|phb",
"feat|second chance|xge",
"feat|shadow touched|tce",
"feat|skill expert|tce",
"feat|slasher|tce",
"feat|squat nimbleness|xge",
"feat|tavern brawler|phb",
"feat|telekinetic|tce",
"feat|telepathic|tce",
"feat|weapon master|phb",
"feat|wood elf magic|xge",
"item|iggwilv's cauldron|wbtw"
]
This application uses the Qute Templating Engine. You can make simple customizations to markdown output by copying a template from src/main/resources/templates
, making the desired modifications, and then specifying that template on the command line.
ttrpg-convert 5etools \
--background examples/templates/tools5e/images-background2md.txt \
--index -o dm dm-sources.json ~/git/dnd/5etools-mirror-1.github.io/data my-items.json
Additional templates can also be specified in your configuration file:
"template": {
"background": "examples/templates/tools5e/images-background2md.txt",
"monster": "examples/templates/tools5e/monster2md-scores.txt"
}
The flag used to specify a template (either on the command line or in a config file) corresponds to the type of template being used. In general, take the file name of a default templates and remove the 2md.txt
suffix.
- Valid keys for 5etools:
background
,class
,deity
,feat
,item
,monster
,name
,note
,race
,spell
,subclass
- Valid keys for Pf2eTools:
ability
,action
,affliction
,archetype
,background
,book
,deity
,feat
,hazard
,inline-affliction
,inline-attack
,item
,monster
,note
,ritual
,spell
,trait
.
Not everything is customizable. In some cases, indenting, organizing, formatting, and linking text accurately is easier to do inline as a big blob. The default and example templates show what is available to tweak.
Of particular note are the varied monster templates:
- Admonition codeblock: monster2md.txt
- Admonition codeblock with alternate score layout: monster2md-scores.txt
- TTRPG statblock in the body: monster2md-yamlStatblock-body.txt
- Admonition codeblock in the body with minimal TTRPG/Initiative tracker YAML metadata in the header: monster2md-yamlStatblock-header.txt
-
๐ฅ A leading slash (
/
) is no longer used at the beginning of compendium and root paths. This should allow you to move these two directories around more easily.- I recommend that you keep the compendium and rules sections together as big balls of mud.
- If you do want to further move files around, do so from within obsidian, so obsidian can update its links.
-
๐ฅ D&D 5e subclasses now use the source of the subclass in the file name.
If you use the Templater plugin, you can use a templater script to rename files in your vault before merging with freshly generated content. View the contents of the template before running it, and adjust parameters at the top to match your Vault.
-
๐จ CSS styles for D&D 5e and Pathfinder are now available in
examples/css-snippets
. -
๐ Admonitions are also available for import:
Note:
admonitions-5e.json
andother-admonitions.json
use colors from CSS snippets to adjust for light and dark mode.
If you are using the default templates and want to render dice rolls, set
useDiceRoller
to true to use dice roller strings when replacing dice {@dice }
, and {@damage }
strings. This can be set differently for either "5e" or
"pf2e" configurations. Please note that if you are using a custom template and fantasy statblocks, you do not need to set the dice roller in your config. Fantasy statblocks will take care of the rendering itself.
See examples/config for the general structure of config.
The conversion tool downloads fluff images into img
directories within each type, e.g. backgrounds/img
or bestiary/aberration/img
. These images are unordered, and are not referenced in entry text. Templates must be modified to include them.
To display all images, you can do something like this:
{#each resource.fluffImages}![{it.caption}]({it.path})
{/each}
Note that the line above ends with two spaces, which serves as a line break when you have strict line endings enabled. You may need something a little different to get things to wrap the way you want in the case that there are multiple images (which is infrequent for these types).
You can also use two separate blocks, such that the first image is used at the top of the document, and any others are included later:
{#if resource.fluffImages && resource.fluffImages.size > 0 }{#let first=resource.fluffImages.get(0)}
![{first.title}]({first.vaultPath}#right)
{/let}{/if}
...
{#each resource.fluffImages}{#if it_index != 0}![{it.caption}]({it.path}#center)
{/if}{/each}
Notice the #right
and #center
anchor tags in the example above. The following CSS snippet defines formatting for two anchor tags: #right
(which will float the image to the right) and #center
(which will display the image as a centered block).
.json5e-background div[src$="#center"],
.json5e-item div[src$="#center"],
.json5e-monster div[src$="#center"],
.json5e-race div[src$="#center"],
.json5e-spell div[src$="#center"] {
text-align: center;
}
.json5e-background div[src$="#center"] img,
.json5e-item div[src$="#center"] img,
.json5e-monster div[src$="#center"] img,
.json5e-race div[src$="#center"] img,
.json5e-spell div[src$="#center"] img {
height: 300px;
}
.json5e-background div[src$="#right"],
.json5e-item div[src$="#right"],
.json5e-monster div[src$="#right"],
.json5e-race div[src$="#right"],
.json5e-spell div[src$="#right"] {
float: right;
margin-left: 5px;
}
.json5e-background div[src$="#right"] img,
.json5e-item div[src$="#right"] img,
.json5e-monster div[src$="#right"] img,
.json5e-race div[src$="#right"] img,
.json5e-spell div[src$="#right"] img {
height: 300px;
}
.rendered-widget .admonition-statblock-parent,
.markdown-rendered .admonition-statblock-parent,
.markdown-preview-section .admonition-statblock-parent {
clear: both;
}
Notes:
- I recommend constraining the image height (rather than the width) in your CSS snippet for images.
- The above snippet also adds a
clear
setting to the admonition parent. Some text descriptions are shorter than the constrained image height. Settingclear: both
onadmonition-parent
ensures that images floated to the right do not impact thestatblock
display. - This configuration is in the compendium.css snippet.
- There is an example for each type in the example templates directory directory. Relevant file names start with
images-
.
Use convert
to import source text for books and adventures that you own:
"convert": {
"adventure": [
"WBtW"
],
"book": [
"PHB"
]
}
Specify templates in json:
"template": {
"background": "path/to/template.txt",
}
Be careful of paths here. Relative paths will be resolved depending on where the command is run from. Absolute paths will be machine specific (most likely). Use forward slashes for path segments, even if you're working on windows.
You can place this configuration one file or several, your choice.
Text for changes to spells at higher levels is added to spells a little differently depending on how complicated the spell is.
Some spells effectively have subsections. Create or Destroy Water, from the PHB, has one subsection describing how water is created, and another describing how it is destroyed. In many layouts, there is just a bit of bold text to visually highlight this information. I've opted to make these proper sections (with a heading) instead, because you can then embed/transclude just the variant you want into your notes where that is relevant.
If a spell has sections, then "At Higher Levels" will be added as an additional section. Otherwise, it will be appended with **At Higher Levels.**
as leading eyecatcher text.
The default spell template has also been amended. It will test for sections in the spell text, and if so, now inserts a ## Summary
header above the Classes/Sources information, to ensure that the penultimate section can be embedded cleanly.
optfeature
text is rendered (Tortle package)flowcharts
is rendered as a series offlowchart
callouts
Use the admonition plugin to create a customflowchart
callout with an icon of your choice.- The adventuring gear tables from the PHB have been corrected
As shown in monster2md-scores.txt, you can now access ability scores directly to achieve alternate layouts in templates, for example:
- STR: {resource.scores.str} `dice: 1d20 {resource.scores.strMod}`
- DEX: {resource.scores.dex} `dice: 1d20 {resource.scores.dexMod}`
- CON: {resource.scores.con} `dice: 1d20 {resource.scores.conMod}`
- INT: {resource.scores.int} `dice: 1d20 {resource.scores.intMod}`
- WIS: {resource.scores.wis} `dice: 1d20 {resource.scores.wisMod}`
- CHA: {resource.scores.cha} `dice: 1d20 {resource.scores.chaMod}`
Property tags on items are now sorted (not alphabetically) to stabilize their order in generated files. This should be a one-time bit of noise as you cross this release (using a version before to using some version after).
Each file name will now contain an abbreviation of the primary source to avoid conflicts (for anything that does not come from phb, mm, dmg).
If you use the Templater plugin, you can use a templater script to rename files in your vault before merging with freshly generated content. View the contents of the template before running it, and adjust parameters at the top as necessary.
Symbols and tokens have changed in structure. Custom templates will need a bit of adjustment.
For bestiary tokens:
{#if resource.token}
![{resource.token.caption}]({resource.token.path}#token){/if}
For deities:
{#if resource.image}
![{resource.image.caption}]({resource.image.path}#symbol){/if}
This project uses Quarkus, the Supersonic Subatomic Java Framework. If you want to learn more about Quarkus, please visit its website: https://quarkus.io/.
This project is a derivative of fc5-convert-cli, which focused on working to and from FightClub5 Compendium XML files. It has also stolen some bits and pieces from pockets-cli.