Creating a Pathfinder Second Edition Foundry VTT Content module pt. 1
Posted on Wed 30 August 2023 in pf2e
When investigating on how to create a Content Module for PF2e, I discovered a couple of things:
- Foundry VTT V11 has changed their default dB backend from neDB to LevelDB: Version 11 Content Packaging Changes
- There is a nodejs package to help you in creating these dBs from json or yaml files: foundryvtt-cli
- The Foundry VTT PF2e community has a wiki with all sorts of stuff, but most importantly, an article on creating a content module: Creating a PF2e Content Module
What I want to do:
I have converted the Dragonborn race from the other TTRPG to a PF2e ancestry, which includes ancestry features, ancestry feats and ancestry heritages. You can find my doodle on this Scribe page
So in a list:
- Create a Foundry VTT content module for my custom resources
- Create custom ancestries
- Create custom ancestry features
- Create custom feats
- Create custom heritages
Getting started
First off, I recommend versioning your code, so you can easily roll back any mistakes you make. It'll help you in the long run.
So let's get started with creating your repository base. In my case it will be named bushvin-pf2e-expansion, and I will need a directory where I will store my source files:
~ $ mkdir bushvin-pf2e-expansion
~ $ cd bushvin-pf2e-expansion
~/bushvin-pf2e-expansion $
Next, I will create the directories which will be consumed by Foundry VTT. I chose the names based on what I found in the Foundry VTT Pf2e System repo
~/bushvin-pf2e-expansion $ mkdir -p bushvin-pf2e-expansion/packs/{ancestries,ancestryfeatures,feats,heritages}
The names are important, and will be used later in the module manifest. So, it is a good idea to take some time in defining names here.
dB files tend to be binary files, which are hard to version, and very difficult to manage, hence I want to manage them in a more human-friendly way. For this I will need another set of directories to store these files. The names of these files are based on what I created earlier:
~/bushvin-pf2e-expansion $ mkdir -p src/packs/{ancestries,ancestryfeatures,feats,heritages}
Next: Create the placeholder for the manifest which we will start filling up.
~/bushvin-pf2e-expansion $ touch module.json
The manifest
The module manifest (module.json) is a json file containing all the directives for Foundry VTT to understand what it needs to do with your module.
The full schema description of all Foundry VTT related manifests, can be found in the foundry-schemas repository. I recommend checking these out while writing your own manifest
Let's start with the basics:
{
"id": "bushvin-pf2e-expansion",
"name": "bushvin-pf2e-expansion",
"title": "Bushvin's Pathfinder2e expansion",
"description": "Additional resources created for my campaigns",
"version": "0.0.1",
"packs": [],
"compatibility": {},
"relationships": {},
"authors": []
}
id
This is the unique identifier for your module. It can be directly used within any code you write. Make sure you know what you do when changing this afterwards. Every resource I found mentions this can be identical to your name.
name
This is the internal name of the module, and your directory should be named identically. Try to stick to alphanumeric characters, dash and underscore.
title
The title used by Foundry VTT in the web interface and in the Foundry VTT Packages registry, when registered
description
The description of your module.
authors
Since you're going to be working on this, and maybe other people contribute to the contents, not necessarily only the code, it is worth mentioning everybody contributing to your module. There aren't a lot of options about how to contact you, but url is the one I'm using. Alternatively you can also use email, but maybe that's not a good idea if you want to avoid spam.
...
"authors": [
"name": "bushvin",
"url": "https://github.com/bushvin/"
]
relationships
This is an interesting section, as it allows us to define dependencies on Worlds, Systems and other packages. All my content is related to PF2e so it makes sense to include this relationship:
...
"relationships": {
"systems": [
{
"id": "pf2e",
"type": "system",
"compatibility": {
"minimum": "5.3.2"
}
}
]
},
...
I specified System version requirements, as I do not intent to backport the module, nor do I intend to test it on versions prior to v11, because of the dB incompatibility.
compatibility
This section allows you to configure the Foundry VTT version requirements for the module
packs
The section in the manifest to define the content the module provides.
According to the documentation it should list all the directories you create under packs.
In our case, we will add an entry for each pack subdirectory:
...
"packs": [
{
"label": "Bushvin's Ancestries",
"name": "ancestries",
"path": "./packs/ancestries",
"type": "Item",
"system": "pf2e",
"ownership": {
"PLAYER": "OBSERVER",
"ASSISTANT": "OWNER"
}
},
{
"label": "Bushvin's Ancestry Features",
"name": "ancestryfeatures",
"path": "./packs/ancestryfeatures",
"type": "Item",
"system": "pf2e",
"ownership": {
"PLAYER": "OBSERVER",
"ASSISTANT": "OWNER"
}
},
{
"label": "Bushvin's Feats",
"name": "feats",
"path": "./packs/feats",
"type": "Item",
"system": "pf2e",
"ownership": {
"PLAYER": "OBSERVER",
"ASSISTANT": "OWNER"
}
},
{
"label": "Bushvin's Heritages",
"name": "heritages",
"path": "./packs/heritages",
"type": "Item",
"system": "pf2e",
"ownership": {
"PLAYER": "OBSERVER",
"ASSISTANT": "OWNER"
}
},
...
The full file can be found here
First Try
We now have our skeleton for the module, which should be able to be used.
I copy pasted the entire bushvin-pf2e-expansion directory in to the modules directory of Foundry VTT and restarted my podman instance. You can do the same if you have a local installation. The important part is that you restart Foundry VTT after this.
In your admin console, you should now see the module you have just created:

Don't mind the additional modules I installed. This is, afterall, my test environment.
You will notice that some files have been created in your pack subdirectories: this is Foundry VTT initializing the levelDB for new content. This is a good thing, as the next step is performed using the Web UI, as it is simpler, and less error-prone.
bushvin-pf2e-expansion$ ls -l packs/*/
packs/ancestries/:
total 20
-rw-r--r-- 1 165956 165956 1506 Aug 25 13:59 000005.ldb
-rw-r--r-- 1 165956 165956 0 Aug 30 15:52 000016.log
-rw-r--r-- 1 165956 165956 16 Aug 25 18:11 CURRENT
-rw-r--r-- 1 165956 165956 0 Aug 25 13:59 LOCK
-rw-r--r-- 1 165956 165956 732 Aug 30 15:52 LOG
-rw-r--r-- 1 165956 165956 729 Aug 25 18:10 LOG.old
-rw-r--r-- 1 165956 165956 134 Aug 30 15:52 MANIFEST-000014
packs/ancestryfeatures/:
total 20
-rw-r--r-- 1 165956 165956 2019 Aug 25 13:59 000005.ldb
-rw-r--r-- 1 165956 165956 0 Aug 30 15:52 000016.log
-rw-r--r-- 1 165956 165956 16 Aug 25 18:11 CURRENT
-rw-r--r-- 1 165956 165956 0 Aug 25 13:59 LOCK
-rw-r--r-- 1 165956 165956 732 Aug 30 15:52 LOG
-rw-r--r-- 1 165956 165956 729 Aug 25 18:10 LOG.old
-rw-r--r-- 1 165956 165956 134 Aug 30 15:52 MANIFEST-000014
packs/feats/:
total 24
-rw-r--r-- 1 165956 165956 5062 Aug 25 13:59 000005.ldb
-rw-r--r-- 1 165956 165956 0 Aug 30 15:52 000016.log
-rw-r--r-- 1 165956 165956 16 Aug 25 18:11 CURRENT
-rw-r--r-- 1 165956 165956 0 Aug 25 13:59 LOCK
-rw-r--r-- 1 165956 165956 736 Aug 30 15:52 LOG
-rw-r--r-- 1 165956 165956 733 Aug 25 18:10 LOG.old
-rw-r--r-- 1 165956 165956 136 Aug 30 15:52 MANIFEST-000014
packs/heritages/:
total 20
-rw-r--r-- 1 165956 165956 2403 Aug 25 13:59 000005.ldb
-rw-r--r-- 1 165956 165956 0 Aug 30 15:52 000016.log
-rw-r--r-- 1 165956 165956 16 Aug 25 18:11 CURRENT
-rw-r--r-- 1 165956 165956 0 Aug 25 13:59 LOCK
-rw-r--r-- 1 165956 165956 736 Aug 30 15:52 LOG
-rw-r--r-- 1 165956 165956 733 Aug 25 18:10 LOG.old
-rw-r--r-- 1 165956 165956 136 Aug 30 15:52 MANIFEST-000014
The only thing you need to do now, is enable the module as a Gamemaster
To be continued in Part 2...