This page provides an overview and tutorial of the basic steps required to create an entire Game System from scratch as a module which can be used for your homebrew games or shared with other players.

As an example of a fairly feature-complete game system implementation - please feel free to examine the D&D5e system which has open source code: https://gitlab.com/foundrynet/dnd5e


Before you Begin

Game system development in Foundry Virtual Tabletop is both rewarding and challenging. If you are considering this process, we encourage you to consider the following advice:


The System Manifest

Each game system must include a system.json file which provides the system specification. This file is required and must be included at the root level of your system folder. The system folder itself must match the "name" attribute designated within the specification file. For example, if we create a game system with the name mysystem, then we would create the file {userData}/Data/systems/mysystem/system.json.

{
  "name": "mysystem",
  "title": "Minimal World Building",
  "description": "Many details here.",
  "version": "1.0.0",
  "templateVersion": 2,
  "author": "John Doe",
  "scripts": [
    "scripts/system-script-1.js",
    "scripts/system-script-2.js"
  ],
  "esmodules": [
    "scripts/system-module-1.mjs"
  ],
  "styles": [
    "styles/system-styles-1.css",
    "styles/system-styles-2.css"
  ],
  "packs": [
    {
      "name": "monsters",
      "label": "Monsters",
      "system": "mysystem",
      "module": "mysystem",
      "path": "packs/monsters.db",
      "entity": "Actor"
    },
    {
      "name": "items",
      "label": "Items",
      "system": "mysystem",
      "module": "mysystem",
      "path": "packs/items.db",
      "entity": "Item"
    }
  ],
  "languages": [
    {
      "lang": "en",
      "name": "English",
      "path": "lang/en.json"
    }
  ],
  "socket": false,
  "initiative": "1d20",
  "gridDistance": 10,
  "gridUnits": "ft",
  "primaryTokenAttribute": "resources.health",
  "secondaryTokenAttribute": "resources.power",
  "url": "https://your/hosted/system/repo/",
  "url": "https://your/hosted/system/repo/system.json",
  "download": "https://your/packaged/download/archive.zip"
}
name

Choose a unique system identifier. This should be an all lower-case string with no special characters. This name must align with the name of the parent directory within which you create the system.

title

Provide a human readable title for the game system which is displayed when selecting from available systems in the World creation menu.

description

This field can contain a more lengthy description of the game system. This text will be used to display help or contact information about your system and is also a good place to include any special licensing or attribution information that you need to distribute.

version

The system version number can be a number or a string depending on what versioning scheme you prefer to use. You should always increment the system version number if you make changes to the Data Template which is described below. When the system version is changed, the platform will automatically migrate all content to match the new Data Template schema.

author

Provide your name as the system creator. This field can be any string if you wish to include an email address or other contact information also.

minimumCoreVersion

Specify the minimum Foundry VTT version which is required in order for this system to function properly.

scripts

You can designate JavaScript files which should be included in the game session whenever this System is being used. Each listed script path should be relative to the system root directory. All scripts which exist will be automatically included in the game session and loaded in their listed order. As a best practice, I recommend serving system scripts out of a subdirectory named scripts, but this is not required.

esmodules

In addition to including traditional JavaScript script files, you may also include JS files which use the newer ES6 modules specification. These files are identified separately in the system manifest so they may be correctly loaded as a module rather than a script.

styles

You can designate CSS files which should be included in the game session whenever this System is being used. Each listed stylesheet path should be relative to the system root directory. All stylesheets which exist will be automatically included in the game session and loaded in their listed order. As a best practice, I recommend serving stylesheets out of a subdirectory named styles, but this is not required.

packs

Game systems may come bundled with Compendium packs which add pre-generated content for Actors, Items, or other supported Entity types. Compendium packs are defined as objects which have their own internal metadata. For each included compendium. These options are listed below:

name

The compendium pack name - this should be a unique lower-case string with no special characters.

label

The compendium pack label - this should be a human readable string label which is displayed in the Compendium sidebar in-game.

system

Since you are creating compendium content specifically for your system, be sure to reference that the content inside each compendium pack requires the system by providing the system name that you chose.

module

The module attribute of each compendium pack designates which content module provided the pack, since this pack is coming from the system itself we can once again provide the system name.

path

The path for each compendium pack should designate a database file with the .db extension. As a best practice, I recommend placing these database files within the packs subdirectory. You do not need to create these files yourself. If a system includes a compendium pack, the database file for that pack will be created automatically when the system is loaded, if it does not already exist.

entity

Each compendium pack must designate a specific Entity type that it contains. Valid entities include Actor, Item, or Scene.

languages

The game system may designate an array of languages specifications that it supports by default. Each element in the languages array is an object which defines the language tag, label, and path to its localization file. The elements of a language object are the following:

lang

The official 2-character language code in lower-case letters, for example "en".

name

The formal and readable name for the language, for example "English".

path

Path to a JSON file relative to the system directory where language translation strings are provided.

socket

A system may request for a specialized socket namespace to be provided. If set to true, a socket event will be handled by the server with the name system.${id}, in this example case system.mysystem which transacts a arbitrary data object by broadcasting that data to all connected clients. This allows the system to have a reserved channel for messaging events which are needed to coordinate actions across multiple connected clients.

initiative

Not every game system uses the concept of initiative, but this field provides the default dice rolling formula that can be used to determine the turn order of Tokens within the combat tracker.

gridDistance

This field designates the default amount of distance that a single grid space should typically represent under this game system. This value configures the default value used when a new Scene is created, but can always be changed for each Scene independently.

gridUnits

This field designates the standard unit of measure used to describe distances under this game system. This defines the default value used when new a new Scene is created, but can always be changed for each Scene independently.

primaryTokenAttribute

An attribute path within the system data model that points to an object that contains both a value and max key. The prototype Token for each Actor created in this system will automatically have this resource assigned as it's primary bar. Omit this key or set it to null for no default attribute.

secondaryTokenAttribute

An attribute path within the system data model that points to an object that contains both a value and max key. The prototype Token for each Actor created in this system will automatically have this resource assigned as it's secondary bar. Omit this key or set it to null for no default attribute.

url

A public URL that links to the repository or documentation pages for the game system. This link will be displayed for users to allow them to find more information about your system.

manifest

A stable URL that describes the latest release version of your system manifest file. This URL is used for automatic system installation in the Foundry VTT setup screen. This manifest URL is consulted during the system update check to see whether a new system version is available for download. It is important that this address remain stable, otherwise updates will not be detected.

download

A public URL that provides a zip archive of your system. The archive at this URL is retrieved during the automated system installation or update process.


System File Structure

The file structure of a system folder requires a parent directory whose name identically matches the name attribute in the manifest. Within that directory, the system.json and template.json files are required and must live at the root level. The naming conventions for other files and folders able to be freely configured, but we recommend a standard structure with subdirectories for scripts, styles, and packs if applicable.

{userData}/Data/systems/mysystem/
    system.json
    template.json
    scripts/
        system-script-1.js
        system-script-2.js
        system-module-1.mjs
    styles/
        system-styles-1.css
        system-styles-2.css
    packs/
        monsters.db
        items.db

To share the system with other players, simply zip the mysystem directory and distribute it using whatever mechanism is most convenient. Players can download the system and extract it within their own systems folder - making the system available for them to use in Foundry Virtual Tabletop!


The Data Template

In addition to the System Specification file described above, each game system must include a Data Template file named template.json at the root-level of the system folder which defines the data model used by Actors and Items under this game system. For example, if we create a game system with the name mysystem, then we would create the file {userData}/Data/systems/mysystem/template.json.

{
"Actor": {
  "types": ["hero", "pawn", "villain"],
  "templates": {
    "background": {
      "biography": "",
      "hairColor": "blue"
    },
    "resources": {
      "health": {
        "min": 0,
        "value": 10,
        "max": 10
      },
      "power": {
        "min": 0,
        "value": 1,
        "max": 3
      }
    }
  },
  "hero": {
    "templates": ["background", "resources"],
    "goodness": {
      "value": 5,
      "max": 10
    }
  },
  "pawn": {
    "templates": ["resources"]
  },
  "villain": {
    "templates": ["background", "resources"],
    "wickedness": {
      "value": 5,
      "max": 100
    }
  }
},
"Item": {
  "types": ["weapon", "spell"],
  "templates": {
    "rarity": {
      "rarity": "Common",
      "price": 20
    }
  },
  "weapon": {
    "templates": ["rarity"],
    "damage": 5
  },
  "spell": {
    "templates": ["rarity"],
    "cost": 2
  }
}
}

The basic structure of the data template is the following. Top-level entries specify data schemas for the Actor and Item entity types. Within each entity type, the "data" entry defines shared data elements which all entities of that type have. Objects defined as siblings to "data" define specialized entity sub-types which may have data elements which extend or overwrite those defined by the basic data object.

In the example, the Actor entity has 3 sub-types: ["hero", "pawn", "villain"]. All 3 types include the common set of "resources", while heroes and villains also include a "background".

Elements in the data model may have any of the primitive types of string, number, or boolean. Additionally elements of the data model may also represent Object or Array structures. There is no requirement or limitation on the depth or structure of the template - however we encourage logical grouping of similarly themed attributes within named objects as this tends to help with organization and maintainability.

Resource Attributes

Specific attributes will be recognized by the game system as a "resource" if (and only if) they contain keys which define a value and a max. In the above example, health, power, and goodness would be detected as eligible resources for hero type characters.

How the Data Model is Applied

When a new Entity is created in a game using this system, it will automatically have it's own internal data populated to conform to the schema defined in the system template. For example, when using this system, if I were to execute the following code:

Item.create({name: "Test Weapon", type: "weapon"}).then(item => {
  console.log(item.data);
})

I would observe that the item was created and assigned an ID, and the data contained within the item matches the expected contents defined by my game system template.

{
  "_id": "e6c7US1VK2cqejVJ",
  "name": "Test Weapon",
  "permission": {
    "default": 0
  },
  "data": {
    "rarity": "Common",
    "damage": 5
  },
  "flags": {},
  "type": "weapon",
  "img": "icons/mystery-man.png"
}

Data Model Migrations

Often, during the course of system development, changes to the template data structure are needed. In such cases, if you increment the version number in your system manifest file any existing Actors or Items will be automatically migrated to the latest template data specification when a World that uses the system is next loaded. During this migration process - any newly added data attributes will be added to existing entities, however old attributes which are no longer required by the template are not removed in case that data needs to be migrated.

To apply additional migration rules, the recommended approach is to provide client side logic which detects whether a migration and uses the client side API to facilitate additional changes.