Ruleset Editor and API

This article will go over how to use the Ruleset Editor and the functions of the JavaScript API.

Create a Ruleset

To begin creating rulesets, first log in, or from the Campaigns page, click “Ruleset Editor” at the top.

You will be taken to the Ruleset selection page. If you have never created a Ruleset before, this page will be empty.

Ruleset Editor Selection

Click “Create New Ruleset” to begin making or editing an existing Ruleset. A good way to get started is to copy an existing one so you can see examples of other implementations. You can always remove any unnecessary code or settings once you do so. Provide a Name, a Description of the Ruleset, and optionally select a Ruleset to copy data from. You can also start completely fresh.

Create Ruleset Modal

Once the Ruleset is created you will be navigated to the Records tab of the Editor.

Rulesets are composed of Records, types of data that are defined by the fields that can be edited or changed on the record’s HTML.

The Settings tab of the editor is used for editing important settings of the Ruleset to define how certain VTT functions behave, options for Effects, etc. (more on this later.)

Saving Changes

On both the Records and Settings tab there is a Save button. Be sure to save often if you are not using your own source control! You will be prompted when navigating to a different function if you have not saved, but it is easy to lose changes on accident.

Note: Ruleset code can get quite complex! We recommend that you rely on your own source control such a git and use an editor offline such as Visual Studio Code. Then, copy and paste changes into the editor.

Records and Lists

All Rulesets must have a Characters type and an NPCs type. These cannot be removed and are listed by default.

From the Records tab you can create new Record types or List types. For both, you will see a Required Fields section and an area to enter the HTML and JavaScript.

Changes in the editor appear after a brief second in the Preview section, which shows you what the Record type looks like in the VTT, and allows you to add Tabs to it (or edit the tabs.)

Editing a Record

Records

For each defined Record type you will see a section in the “Compendium” of the VTT that allows users to create new entries of that type. For Records that will be used in a List type (such as Items, Spells, or Abilities) we recommend also including a portrait field in the HTML (more on this later in the Fields section.)

Record Required Fields

All Records have the following required fields:

  • Name: How it is displayed to the players in the VTT

  • Type: The underlying “type” used by the backend and when querying for this record type

  • Width: The default width of the record window

  • Height: The default height of the record window

  • Filters: This will define filters that players in the VTT can select in order to quickly search for specific records. In the above example, there is one set for the size field

Record Tabs

All records have the ability to add or edit Tabs. Click the “Add Tab” button above the Preview to add a new tab. Click a tab and click “Edit Tab” to remove Tab, change its position, or rename it.

Each tab has their own HTML and JS code for it. Once clicking on a Tab, enter the HTML and JS for that tab.

Lists

Lists are built in a similar way as Records but they are in fact not shown in the Compendium. A List Record Type allows you to define one element of a List of elements that can then be added to a record type. For example, you might have a Items Record Type. And then you might also define an Item List Type. The Item List would be rendered on the Character Sheet so you can create an Inventory of Items.

From the List type you define in the HTML and JS the behavior or one element of the list. Then, when save it when done. Once you want to add that List Type to a Record sheet, go back to that Record type on the Records & Lists selection, then scroll all the way down in the “Fields” section, and click the defined List type. (More on this in the Fields section.) List do not have tabs like records do.

List Required Fields

All Lists have the following required fields:

  • Name: A display name for the List in the Editor

  • Type: The underlying “type” used by the VTT when adding this list to a record

  • Width: The default width of the editor preview window (unlike records, this does not affect the element size when rendered)

  • Height: The default height of the editor preview window (unlike records, this does not affect the element size when rendered)

  • Show Add Button: Enables the ability to Add one-off elements of the list on the record that uses it

  • Show Delete Button: Enables the ability to Delete elements from the list on the record that uses it

  • Single Row: Renders each element of the list in one row, instead of each being its own row

  • Empty List Text: Text to show in the List when rendered without elementgs

  • Add Button Text: Text to use in the Add button

  • New Item Name: Name to set on all new elements added to the list

  • New Item Unidentified Name: All records have an Unidentified Name, and this lets you define the default Unidentified Name when adding elements to this list

  • Allowed List Record Types: This sets the default types that can be drag and dropped to the list. Most lists only define one, but there may be cases where you want two different record types to be able to be added to a list.

    • Disable Drop: This disables the drag and drop behavior when allowed list record types are set. This is useful when you want it to default to the icon of an allowed record type on Add of a new item, but wish to handle the Drag and Drop behavior manually (such as in the Drag and Drop script of a record, more on this later.)

    • Stack Duplicates: Enable this setting when you want duplicate entries to be counted more than once, and provide the name of the field used to keep track of the count.

  • Order Criteria: Fields that appear in the Record HTML will show up in this dropdown. Select the field you want to sort the list by (such as name, count, etc.) and then whether it is Ascending of Descending. You can provide more than one criteria which is sorts in order. (Example, sorting by name then by count.)

  • Filter Criteria: Define filter criteria when you want the list to only show elements that match a specific filter. Select the field, then the operator, then the value you are looking for.

    • Example: Suppose you want a list of Attacks on another tab, and suppose you want to only show Attacks with Weapons from the Inventory that are Equipped. You could add two filters, one for a “type” field and one for an “equipped” field.

  • Max Length: Use this field when you want to impose a maximum length of the list.

Fields and HTML API

The HTML in Realm VTT is modified to support our support fields. Additionally, each record type can define a “script” and in the script you can put an “onDrop” handler. This will be executed any time a record is dropped to the record.

In the Script of a record type, you make also want to create functions used by the fields within. See an example below for how this might look.

Additionally, the JavaScript executed in Records has an API that be called for VTT functions, see the JavaScript API section for more information.

Record Scripts

Record types can also reference code from a “Common” Script that you define. The Common Script is defined in the “Settings” tab under “Additional Settings.” It is a good idea to place re-used code here, so you do not re-write it across all your Record types!

<script>
  function onDrop(type, recordLink) {
    if (type === 'spells') {
      onDropSpell(recordLink);
    }
  }

  function onDropSpell(recordLink) {
    // Code here...
  }
  
  function rollInitiative() {
    // Roll initiative for the character
    // Code here ...
  }
</script>

<div style="width: 100%; display: flex; justify-content: flex-end;">
  <button field="rollInitBtn" size="xs" icon="D20" label="Initiative" variant='outline'
    onclick='rollInitiative();'></button>
</div>

Record Fields

Here are all the currently supported field types with the HTML.

With the exception of the Name, Unidentified Name, and Portrait, the values for all Fields are stored in the data object of each record. (Example, a character with a number field defined as “hp” will have it stored in data.hp). The following fields are stored directly on each record (i.e. not in data):

  • name

  • unidentifiedName

  • portrait

  • locked

Record Metadata

Sometimes you need access to the metadata of a field, for example, manually setting whether a field is hidden. This is stored in the fields section of a record. Example, setting the “hp” value to hidden, is stored in: fields.hp.hidden = true. (More on this later.)

Accessing List Values

Sometimes in the API you need to access or change the value in a list. You can do this using dot notation (more on this later) to the element in the list. Example: The data path to the “equipped” value on the first element of a list called “inventory” would be: data.inventory.0.data.equipped

Colors

Colors for fields use the Mantine color system. Click here to see more information.

Icons

Icons that are available in Realm VTT come from Tabler icons.

Portrait

Description: Allows setting and displaying a portrait for the record. For Characters and NPCs, it also allows setting a Token. Portraits (and Tokens) can be edited when the Record is unlocked by clicking on the Portrait. When set, it can be viewed or shared with players by clicking on the Image icon in the bottom-right.

Attributes:

  1. field - The data field to store the portrait, which should always be “portrait” — this cannot be changed

  2. All common attributes (see Common Attributes section below)

Example:

<portrait field="portrait" width="150px" height="150px"></portrait>

String Field

Description: Allows setting and displaying a string value on the record.

Attributes:

  1. field - The data field to store the string value

  2. defaultvalue - Default value if none is set

  3. textalign - Text alignment (left, center, right)

  4. multiline - If true, allows multiple lines of text

  5. maxrows - Maximum number of rows for multiline input

  6. All common attributes

Example:

<stringfield 
  field="description" 
  label="Description" 
  multiline="true" 
  maxrows="4"
  placeholder="Enter description..."
></stringfield>

Rich Text Field

Description: Allows setting and displaying rich text on the record.

Attributes:

  1. field - The data field to store the rich text

  2. disablecontrols - If true, hides the formatting controls

  3. All common attributes

Example:

<richtextfield 
  field="notes" 
  label="Notes"
  height="300px"
></richtextfield>

Number Field

Description: Allows setting and displaying a number value on the record.

Attributes:

  1. field - The data field to store the number

  2. minvalue - Minimum allowed value

  3. maxvalue - Maximum allowed value

  4. showsign - If true, always shows + or - sign

  5. defaultvalue - Default value if none is set

  6. textalign - Text alignment (left, center, right)

  7. All common attributes

Example:

<numberfield 
  field="modifier" 
  label="Modifier" 
  showsign="true"
  minvalue="-5"
  maxvalue="5"
></numberfield>

Name Field

Description: Special field for displaying and editing the record's name, with support for unidentified states. If on a List type, it is the name of that List element.

Attributes:

  1. field - The data field for the name (usually "name")

  2. defaultvalue - Default name if none is set

  3. textalign - Text alignment (left, center, right)

  4. multiline - If true, allows multiple lines

  5. maxrows - Maximum number of rows for multiline input

  6. All common attributes

<namefield 
  field="name"
  label="Character Name"
  placeholder="Enter name..."
  size="xl"
></namefield>

Record Link

Description: Creates a link to another record.

Note: See the API section for setRecordLink on how to use this field. It expects the value to be a recordLink (like from an onDrop handler.)

Attributes:

  1. field - The data field containing the linked record data

  2. All common attributes

<recordlink 
  field="weapon"
  label="Equipped Weapon"
></recordlink>

Checkbox

Description: Creates a checkbox for boolean values.

Attributes:

  1. field - The data field to store the boolean value

  2. All common attributes

Example:

<checkbox 
  field="proficient"
  label="Proficient"
></checkbox>

Radio Button

Description: Creates a radio button for selection within a group.

Attributes:

  1. field - The data field to store the selection, should be the same for all radio buttons in the same group

  2. All common attributes

Example:

<div>
  <radio 
    field="alignment"
    label="Lawful Good"
    value="lg"
  ></radio>
  <radio 
    field="alignment"
    label="Neutral Good"
    value="ng"
  ></radio>
</div>

Label

Description: Displays static text.

Attributes:

  1. textalign - Text alignment (left, center, right)

  2. All common attributes

Example:

<label 
  label="Combat Statistics"
  size="lg"
  color="blue"
  textalign="center"
></label>

Divider

Description: Adds a horizontal or vertical line separator.

Attributes:

  1. orientation - Direction of the divider ("horizontal" or "vertical")

  2. All common attributes

Example:

<divider 
  label="Combat"
  orientation="horizontal"
  size="lg"
></divider>

Tag

Description: Adds a tag that displays text with tooltip descriptions.

Attributes:

  1. field - The data field to display

  2. tooltip - The tooltip text to show on hover

  3. variant - Visual style ('default' or 'filled')

  4. color - Color of the tag (uses Mantine color system)

  5. size - Size of the tag (xs, sm, md, lg, xl)

  6. All common attributes

Example:

<tag 
  field="status" 
  tooltip="Current status effect" 
  variant="filled"
  color="blue"
  size="sm"
></tag>

Dropdown

Description: Creates a dropdown selection menu.

Attributes:

  1. field - The data field to store selection

  2. options - Array of options (as JSON string)

  3. optionsquery - JSON of a query to get data from the backend. This will only get data that exists in the current campaign. Expects JSON string in the format: {"type": "effects", "query": {}} where “type” is a record type (or one defined by the VTT such as ‘effects’) and “query” is a MongoDB style query (if you wish to filter it to specific entries.)

  4. icon - Icon to display

  5. multiselect - Allow multiple selections if true

  6. searchable - Enable search functionality if true

  7. defaultvalue - Default selected value

  8. All common attributes

Example:

<dropdown 
  field="class" 
  label="Character Class"
  options='[
    {"value": "fighter", "label": "Fighter"},
    {"value": "wizard", "label": "Wizard"},
    {"value": "rogue", "label": "Rogue"}
  ]'
  searchable="true"
></dropdown>

<dropdown 
  size='sm'
  field="effects"
  label="Effects"
  searchable='true' multiselect='10'
  description='Effects that this ability can apply'
  optionsquery='{"type": "effects", "query": {}}'
  placeholder='Select Effects...'>
</dropdown>

Progress Bar

Description: Adds a horizontal progress bar

Attributes:

  1. field - The name for the field of the progress bar (not used for data)

  2. currentvaluefield - The field for current value of the progress bar

  3. maxvaluefield - Field containing the maximum value

  4. maxvalue - Static maximum value, if maxvaluefield is not used

  5. color - Can be set to 'health' to render the progress bar in different shades depending on the %-remaining

  6. All common attributes

Example:

<progressbar 
  currentvaluefield="hp" 
  maxvaluefield="maxHp"
  label="Hit Points"
  color="health"
  radius="xl"
></progressbar>

Counter

Description: Adds a horizontal list of checkboxes for tracking counts.

Attributes:

  1. field - The data field to store the count value

  2. maxvalue - Static maximum value, used if maxvaluefield is not set

  3. maxvaluefield - Field containing maximum value

  4. All common attributes

<counter 
  field="hitDice" 
  label="Hit Dice"
  maxvaluefield="level"
></counter>

Button

Description: Displays a clickable button.

Attributes:

  1. field - The data field to bind to

  2. icon - Icon to display on the button, if set

  3. disablediflocked - If true, button is disabled when record is locked, if false it is enabled even when locked

  4. All common attributes

Example:

<button 
  label="Roll Initiative"
  onclick="rollInitiative"
  icon="dice"
  color="blue"
  variant="filled"
></button>

Icon Button

Description: Displays a button with different icon states. Can be used to toggle different states, or just have a button that is a singular icon.

Attributes:

  1. field - The data field to bind the current value/state of the button to

  2. disablediflocked - If true, button is disabled when record is locked, if false it is enabled even when locked

  3. options - Array of state options (as JSON string)

    1. Uses the JSON format [ {"value": "value", "label": "Label”, "icon": "TablerIconName"} ]

  4. getoptions - Function name to get options dynamically

  5. All common attributes

Example:

<iconbutton 
  field="lightSource"
  options='[
    {"value": "off", "label": "Light Off", "icon": "IconBulbOff"},
    {"value": "dim", "label": "Dim Light", "icon": "IconBulb"},
    {"value": "bright", "label": "Bright Light", "icon": "IconBulb"}
  ]'
  onchange='onLightChange(value)'
></iconbutton>

Accordion

Description: Creates a collapsible section.

Attributes:

  1. field - The data field to bind the collapsed state to

  2. icon - Icon to display on the header

  3. All common attributes

Example:

<accordion label="Equipment" field="equipAcc">
  <div style="padding: 8px">
    <!-- Accordion content here -->
    <list field="equipment" listtype="item"></list>
  </div>
</accordion>

Indicator

Description: Adds an indicator around another field.

Attributes:

  1. field - The data field to display in the indicator

  2. position - Position of the indicator

  3. All common attributes

Example:

<indicator 
  field="concentration"
  position="top-right"
  color="yellow"
>
  <stringfield field="spell" label="Active Spell"></stringfield>
</indicator>

List

Description: Creates a list of sub-records of a specific type as described above.

Attributes:

  1. field - The data field containing the list items

  2. listtype - The record type to use for list items (must match the ‘type’ defined for the List Type)

  3. allowadd - Function to call to determine if new items can be added — must return true or false and should be defined in the script section

  4. getfilters - Function name to determine list filters programatically.

  5. All common attributes

Example of Get Filters:

  function getSpellFilters() {
    // If "Hide Unprepared Spells" is checked, filter out unprepared spells
    if (record?.data?.hideUnpreparedSpells) {
      return [{ field: 'prepared', operator: 'not_equals', value: 'unprepared' }];
    }
    return [];
  }

Example:

<list 
  field="inventory" 
  listtype="item"
  label="Inventory"
  allowadd="canAddItem()"
  height="400px"
></list>

Common Attributes

All components support these basic attributes:

  1. field - Data field to bind to

  2. label - Display label above the field, if supported by field type

  3. height - Element height

  4. width - Element width

  5. description - Description text displayed under the label, if supported by field type

  6. placeholder - Input placeholder text, if supported by field type

  7. size - Element size (xs, sm, md, lg, xl)

  8. color - Element color (uses Mantine color system)

  9. variant - Visual variant — uses Mantine variants, with some modifications for certain fields (unstyled, outline, filled, striped, outline-striped)

  10. onclick - Click event handler function name, should be a function either in the Common Script or in the Record’s script

  11. onload - Load event handler function name, should be a function either in the Common Script or in the Record’s script

  12. onchange - Change event handler function name, should be a function either in the Common Script or in the Record’s script, called ONLY on the machine of the User that changes the value, NOT when changed by another user or process

  13. hidden - If true, element is hidden by default — see the API section for hiding and unhiding fields

  14. radius - Border radius (xs, sm, md, lg, xl)

  15. textalign - Text alignment (left, center, right)

  16. hideonlocked - If true, hidden when record is locked

  17. hidewhenidentified - Controls visibility based on identification state, useful for fields that should not be visible to players when unidentified

JavaScript API

The Realm VTT API provides a comprehensive set of tools for interacting with the virtual tabletop environment. This API is available within scripts and macros, allowing for complex automation and game management.

The following section describes all the functions and data available in the JavaScript executed by the VTT.

These values and the functions provided in api can be used in the Script section of a Record, List, or anywhere a Script is defined in the Settings tab.

Additionally, some of this information is provided in the auto complete functions of the Code Editors within the Ruleset Editor.

Context

Scripts are run in a particular context (usually a Record, a Roll Handler, a Combat Tracker Script, a Token Context Script, or a Party Sheet Script).

Scripts have access to several context variables:

  1. value - The current field's value

  2. dataPath - Path to the field's data in the parent record

  3. record - The current record or list item

  4. isGM - Boolean indicating if user is GM

  5. userId - Current user's ID

  6. recordType - Type of current record

  7. data - Additional contextual data

    1. data.token: object | null

      1. [Combat Tracker Scripts] The currently active token in combat.

    2. data.tokens: Array<object>

      1. [Combat Tracker Scripts] All tokens currently in the combat tracker.

    3. data.initiative: number

      1. [Combat Tracker Scripts] The current initiative count in combat.

    4. data.round: number

      1. [Combat Tracker Scripts] The current round count in combat.

    5. data.roll: object

      1. [Roll Handler Scripts] The result of a dice roll, containing total, dice results, and metadata.

    6. data.character: object | null

      1. [Macros] The most recent character created by the player in the campaign.

Available API Calls

Getting Records

getRecord(recordType: string, recordId: string, callback: (record) => void)

You can fetch any record in the currrent campaign using getRecord.

// Fetch a character record
api.getRecord("characters", "id-here", (character) => {
  console.log(character.name);
});

Setting Record Links

setRecordLink(path: string, recordLink: {value: object, tooltip: string, type: string}, callback?: (record) => void)

Record links are set on Record Link fields using setRecordLink.

api.setRecordLink("equipment.mainHand", {
  value: weaponRecord,
  tooltip: "Longsword",
  type: "weapons"
}, (updatedRecord) => {
  console.log("Weapon equipped");
});

Effect Management

addEffect(effectName: string, actorToken: object, effectDurationSeconds?: number, effectValue?: string)

Adds an effect to a token by Effect Name. The Effect must be in the campaign.

addEffectById(effectId: string, actorToken: object, effectDurationSeconds?: number, effectValue?: string)

Adds an effect to a token by Effect ID. The Effect must be in the campaign.

addTokenChangeEffect(npcId: string, actorToken: object)

Adds an Effect to the actor token that changes their Token to match the token image and size of the given NPC, by ID. That NPC must be in the campaign.

removeEffectById(effectId: string, actorToken: object)

Removes the Effect by the given Effect ID on the token.

// Add a "Poisoned" effect for 60 seconds
api.addEffect("Poisoned", targetToken, 60, customV);

// Add effect by ID with a custom value
api.addEffectById("effect-id-1", targetToken, undefined, "Concetration on Bless");

// Change token appearance
api.addTokenChangeEffect("npc-wolf-id", characterToken);

Value Management

getValue(path: string): any

Gets a value from the current record's context data by dataPath.

This could also be a path to a List value, see example below.

const hp = api.getValue("data.hpCurrent");

const item2 = api.getValue("data.items.1");

setValue(dataPath: string, newValue: any, callback?: (record) => void)

Sets a value in the current record's data.

api.setValue("data.hp", hp - 5, (updatedRecord) => {
  console.log("HP updated");
});

setValues(dataPathValues: {[path: string]: any}, callback?: (record) => void)

Sets multiple values at once in the current record's data. This is recommending when changing many values in an onchange handler, such as when updating a Character’s attribute. For performance reasons, you should always use setValues when affecting more than one value on a Record.

You can even use this to unhide/hide values using the fields metadata object. See example below:

api.setValues({
  "data.hpCurrent": hp - 5,
  "data.wounded": true,
  "fields.woundedLabel.hidden": false,
  "fields.healthyLabel.hidden": true
}, (updatedRecord) => {
  console.log("Values updated");
});

addValue(path: string, newValue: object, callback?: (record) => void)

Adds a single value to a list field at the specified path. The element will automatically be assigned a unique ID.

api.addValue("data.inventory", {
    name: "Health Potion",
    data: {
      quantity: 1,
      weight: 0.5
    }
}, (updatedRecord) => {
    console.log("Item added to inventory");
});

addValues(path: string, values: Array<object>, callback?: (record) => void)

Adds multiple values to a list field at the specified path. Each value will automatically be assigned a unique ID.

// Add multiple items to inventory at once
api.addValues("data.inventory", [
    {
        name: "Sword",
        data: {
          damage: "1d8",
          weight: 3
        }
    },
    {
        name: "Shield",
        data: {
          armorClass: 2,
          weight: 6
        }
    }
], (updatedRecord) => {
    console.log("Items added to inventory");
});

removeValue(path: string, index: number, callback?: (record) => void)

Removes a value from a list field at the specified path and index.

api.removeValue("data.inventory", 1, (updatedRecord) => {
    console.log("Second item removed from inventory");
});

setValueOnToken(token: object, relativePath: string, newValue: any, callback?: (record) => void)

Sets a value on a specific token using a relative path. This is useful when you need to modify a different token's data directly (and not the current record context).

api.setValueOnToken(token, "data.hpCurrent", 50, (updatedRecord) => {
  console.log("Token HP updated");
});

setValueOnTokenById(tokenId: string, recordType: string, relativePath: string, newValue: any, callback?: (record) => void)

Sets a value on a token using its ID and record type. This is useful when you only have a token's ID and need to modify its data.

api.setValueOnToken('some-token-id', "data.hpCurrent", 50, (updatedRecord) => {
  console.log("Token HP updated");
});

Dice Rolls

roll(roll: string, metadata?: object, rollType: string = "chat")

Performs a roll without prompting. The roll type defaults to “chat” but otherwise, it should match a Roll Type as defined in the Settings tab. (See the section later on Roll Handlers.)

api.roll("2d20dl1 + 5", { rollName: "Attack Roll" }, "attack");

rollInstant(roll: string): {total: number, results: Array<{type: number, value: number}>, modifier: number}

Performs an immediate roll and returns the result without any animation in the VTT.

const result = api.rollInstant("1d20");
console.log(`Rolled a ${result.total}`);

promptRoll(name: string, roll: string, modifiers: Array<{name: string, type: string, value: any, active: boolean}>, metadata?: object, rollType: string = "chat")

Prompts for a roll with modifiers and passes along the given metadata to the roll handler. The roll type defaults to “chat” but otherwise, it should match a Roll Type as defined in the Settings tab. (See the section later on Roll Handlers.)

This is the primary method that should be used for most rolls, so that Players have more control over the modifiers that are passed along and can toggle or add more the roll beforehand.

Note: Metadata should be relatively light. Do not add entire Records or Tokens to Metadata as this may cause performance issues later if the Records are very large. Pass IDs instead and use the getRecord API call in the Handlers.

api.promptRoll(
  "Fire Sword",
  "1d6 piercing + 1 piercing",
  [
    { name: "Fire Enchantment", type: "fire", value: "1d4 fire", active: true }
  ],
  { "isAttack": true },
  "damage"
);

promptRollForToken(tokenForRoll: object, name: string, roll: string, modifiers: Array<object>, metadata?: object, rollType: string = "chat")

When called, opens a Roll Prompt using the given token as the actor making the roll. Used when needing to make rolls as a specific token rather than the selected one.

const selectedTokens = api.getSelectedOrDroppedToken();
selectedTokens.forEach(token => {
  const tokenDexMod = token.data.dexMod || 0;
  api.promptRollForToken(
    token,
    "Dexterity Save",
    "1d20",
    [{
      name: "Dex Mod",
      type: "",
      value: tokenDexMod
    }],
    { saveDC: 15 },
    "save"
  );
});

Token Management

getSelectedTokens(): Array<object>

Returns all selected tokens on the scene.

const tokens = api.getSelectedTokens();

getTargets(): Array<object>

Gets all targeted tokens and their distances to the token corresponding to the current record context.

const targets = api.getTargets();
targets.forEach((target) => {
  const targetToken = target.token;
  const targetDistance = target.distance || 0;
});
  

getSelectedOwnedTokens(): Array<object>

Returns an array of tokens that are both selected and owned by the current player. If no owned tokens are selected, returns an array containing just the player's default token (if any). This is particularly useful for player scripts where you want to ensure they can only affect tokens they own.

// Get all tokens the player owns and has selected
const ownedTokens = api.getSelectedOwnedTokens();

getDistance(token1: object, token2: object): number

Gets the distance between two tokens.

const distance = api.getDistance(tokenA, tokenB);

getToken(): object | null

Returns the current token based on context. Priority order:

  1. Token from data context

  2. For GMs: First selected token

  3. For Players: Player's token

  4. Token associated with current record

// Get the contextually relevant token
const token = api.getToken();
if (token) {
    console.log("Found token:", token.name);
}

getOtherTokens(): Array<object>

Returns all tokens on the current scene except for the contextual token (from getToken()).

// Get all other tokens on the scene
const otherTokens = api.getOtherTokens();
console.log(`There are ${otherTokens.length} other tokens on the scene`);

// Example: Find nearest token
const nearestToken = otherTokens.reduce((nearest, current) => {
    const currentDistance = api.getDistance(api.getToken(), current);
    const nearestDistance = nearest ? api.getDistance(api.getToken(), nearest) : Infinity;
    return currentDistance < nearestDistance ? current : nearest;
}, null);

getSelectedOrDroppedToken(): Array<object>

Returns an array of tokens based on the current context. The method follows this priority:

  1. If the macro was dropped on a token, returns an array containing just that token

  2. If tokens are selected, returns array of selected tokens

  3. If user is not a GM and has a character, returns array containing their character

  4. Otherwise, returns empty array

const tokens = api.getSelectedOrDroppedToken();

isOwner(token: object): boolean

Determines if the current user owns the specified token. Returns true if the user is a GM or if they are the owner of the token.

// Check if current user owns a token
const token = api.getToken();
if (api.isOwner(token)) {
    console.log("User can control this token");
} else {
    console.log("User cannot control this token");
}

Chat & Notifications

sendMessage(message: string, roll?: object, recordLinks?: Array<object>, tags?: Array<string>, asToken?: object)

Sends a chat message. Record Links are added to the bottom of the message, if provided. Tags are rendered at the top of the message, if provided.

Messages support Markdown using the following:

  1. **bold** → bold

  2. *italic* → italic

  3. ***bold italic*** → bold italic

  4. ~~strikethrough~~ → ~~strikethrough~~

  5. # Header 1

    ## Header 2

    ### Header 3

    #### Header 4

    ##### Header 5

    ###### Header 6

  6. Tables
    | Header 1 | Header 2 |

    |----------|----------|

    | Cell 1 | Cell 2 |

    | Cell 3 | Cell 4 |

  7. Lists
    - Unordered list item

    * Also unordered

    1. Ordered list item

    2. Second ordered item

  8. Macros
    ```MacroNameSeparatedByUnderscores

    Code to Execute on Click
    ```

  9. Custom Tags

    1. :iconname: → Displays icon from system

    2. [tagname|tooltip] → Displays tag with hover tooltip

    3. [color=red]Colored text[/color] → Colored text

    4. [center]Centered text[/center] → Centered text

    5. [gm]Only GMs can see this[/gm` → Text only visible to GMs

// Basic message
const tags = [
  {
    tooltip: "Basic Attack",
    name: "Attack",
  }
]
api.sendMessage(`Attack Result: ${someValue}`, undefined, tags);

// Send a message as a specific token (GM only)
api.sendMessage("*growls*", null, [], [], tokenObject);

Macros within messages can become pretty complex considering they must be placed within backticks (`). Here is an example:

const damageButton = `\`\`\`Roll_Damage
api.promptRoll(\`${spellName} Damage\`, '${spellDamage}', ${JSON.stringify(damageModifiers
)}, ${JSON.stringify(saveDamageMetadata)}, 'damage')
\`\`\``;

const message = `
  ${damageButton}
`

api.sendMessage(message);

editMessage(messageId: string | null, message: string, callback?: () => void)

Edits an existing chat message. For more examples, you can see the “damage” roll handler in Realm VTT Basic or D&D 5e for how it gets the message ID and edits messages.

api.editMessage("message-id-123", "Updated text");

showNotification(message: string, color?: string, title?: string)

Shows a notification to the user.

api.showNotification(
  "Target is too far away!",
  "red",
  "Range Error"
);

Utility Functions

showPrompt(name: string, label: string, text: string, options: Array<{label: string, value: any}> | null, optionsQuery: {type: string, query: object} | null, callback?: (selection: any) => void, okButtonText: string = "OK", cancelButtonText: string = "Cancel", maxOptions: number = 1)

Shows a selection prompt to the user. Can be a defined set of options, or a query to get data from the current campaign. Used for when prompting to make selections such as during a Level Up.

api.showPrompt(
  "Choose Weapon",
  "Select weapon to start with",
  "Choose carefully",
  [
    { label: "Sword", value: "sword" },
    { label: "Bow", value: "bow" }
  ],
  null,
  (selection) => console.log(selection),
  "Select",
  "Cancel",
  1 // Only allow 1 option
);

// Another example, note that chaining prompts should be done 
// using the callbacks
api.showPrompt(
  `Choose 2 Skills`,
  "Skills",
  "Select 2 General Skills...",
  null,
  {
    type: "skills",
    query: {
      "data.type": "general",
    },
  },
  skillSelectionCallback,
  "OK",
  "Cancel",
  2
);

richTextToMarkdown(html: string): string

Converts HTML to markdown. Useful for converting descriptions from Rich Text fields to a Chat Message.

const markdown = api.richTextToMarkdown("<strong>Bold</strong>");

getSetting(key: string): string

Gets a campaign setting value. The key must be a setting as defined in the Ruleset Settings tab.

const includeCoinage = api.getSetting("coinWeight") === "yes";

awardExp(amount: number, reason: string): void

Awards experience points to the party. Only works if called by a GM and if the Awards tab is enabled in the Party Sheet. Typically used in a Macro sent in a message by the Combat Tracker’s onEncounterEnd handler.

// Award XP to the party
if (isGM) {
    api.awardExp(100, "Defeated the dragon");
}

dealFromDeck(deckName: string, tokenId: string, itemId: string, removeFromDeck: boolean, shuffleOnEmpty: boolean, callback: function): void

Looks up a Deck within the current campaign with the given name, then deals an item from the deck to the given tokenId. A tokenId of “all” deals the item to be visible to all players. A tokenId of “gm” deals it just the GM. Otherwise, it must be an ID of a Token on the Combat Tracker.

Provide an itemId to deal a specific Item from the Deck (by ID) or leave it as an empty string to deal the first item in the deck (after shuffling.) If removeFromDeck is true, the item is removed, else it is left in the Deck for others to get the same item (useful for Token packs.) If shuffleOnEmpty is true, the deck will be reshuffled once the last card is dealt, otherwise, it will error if empty.

The callback function is called with the item that was dealt as the only parameter.

const callback = (item) => {
	console.log('Drew: ' + item.value);
};
api.dealFromDeck('Test Deck', 'all', '', true, true, callback);

shuffleDeck(deckName: string, useDiscardPile: boolean, callback: function): void

Looks up a Deck within the current campaign with the given name, then shuffles the Deck if found. If useDiscardPile is true, only the cards in the discard pile (if any) are shuffled back into the deck order, and the current dealt cards are left the same. Otherwise, all cards are dealt back to the deck.

The callback function is called with the deck that was shuffled as the only parameter.

const callback = (item) => {
	console.log('Shuffled: ', item);
};
api.shuffleDeck('Test Deck', false, callback);

Ruleset Settings

The Settings Tab of the Ruleset gives you additional controls over how the Ruleset functions within the VTT.

Token Health

From this Section you can define which fields are used in an NPC and Characters record for the max health and current health of the token (stored in data.(fieldName).

You can also disable health indicators in the ruleset by clicking the checkbox “Disable Health Indicators.”

If both fields are defined and set properly, you can also define what the color of the health bars on the tokens should be for a given percentage remaining.

The label defined for each is the “Health Status” that is shown to players. Players do not see the Health Bars of enemy faction tokens, but will see it for Friendly tokens.

Damage & Healing

The Damage & Healing settings controls the ability to set damage or healing on a Token via the Token Context Menu (right clicking a Token) in the VTT. If enabled, the fields will show up. The scripts defined in each Accordion (Damage Script / Healing Script) are executed when a value is set. These scripts must be written per the definition of your Characters and NPCs. Note that the Health fields must be the same on both Characters and NPCs.

These scripts execute with record set as the token selected and value set as the value entered.

Here is an example:

// Apply healing
// Ignore negative healing as that is what damage is for
// This script ignores tempHp, as it is not a factor in healing
if (value > 0) {
  var curhp = record.data?.curhp || 0;
  curhp += value;
  if (curhp < 0) { curhp = 0; }
  if (curhp > record.data?.hitpoints) { curhp = record.data?.hitpoints; }
  api.setValue("data.curhp", curhp);
}

The Damage Type Icons accordion can be expanded to define custom icons for specific damage type that are used in the scripts of your Ruleset.

Icons must be either a Tabler Icon or one of the following:

  • icon-acid

  • icon-bleed

  • icon-bludgeoning

  • icon-cold

  • icon-fire

  • icon-force

  • icon-lightning

  • icon-necrotic

  • icon-piercing

  • icon-poison

  • icon-mental

  • icon-radiant

  • icon-slashing

  • icon-sonic

  • icon-unholy

  • icon-spirit

  • icon-vitality

  • icon-void

  • icon-holy

  • icon-explosive

  • icon-handgun

  • icon-rifle

  • icon-grenade

  • icon-magic

  • icon-healing

  • icon-precision

Token Size Options

From this section, you can define what Size tokens are rendered at by the data.size field on the NPC or Character.

Note: To use this function your NPCs and Characters should define a size string field on the record that is editable.

Combat Tracker

In the Combat Tracker settings you can define the value used on NPCs and Character’s for storing initiative (and rendered in the Combat Tracker) as well as whether it is descending or ascending order.

The Additional Fields accordion allows you to define additional fields that you want to render in the Combat Tracker.

  • Note: The fields should all be defined on both NPCs and Characters otherwise they will be empty for one or the other

The following Event Types are editable in a different script handler here, and are called at various times when the Combat Tracker is used. The Context is set per the Data above in the API section.

These scripts are only executed by the GM.

  • On Token Add

    • When a token is added to the Combat Tracker, this script is called.

  • On Encounter Start

    • When clicking Start Encounter, this script is called.

  • On Encounter End

    • When clicking End Encounter, this script is called.

  • On Turn Start

    • When clicking the Next Turn button, this script is called with the data.token set to the one who’s turn is starting.

  • On Turn End

    • When clicking the Next Turn button, this script is called with the data.token set to the one who’s turn is ending.

  • On Round Start

    • When clicking Next Turn (if a new round is starting) or when clicking Next Round, this script is called

  • On Round End

    • When clicking Next Turn (if a new round is starting) or when clicking Next Round, this script is called

  • On Roll Initiative

    • This script is called when the Combat Tracker “Roll Initiative” button is pressed and should define how to prompt for an initiative roll for the context’s token in data.token

  • On Roll Initative (Group)

    • This optional script is called when the Combat Tracker “Roll Initiative for Each NPC Group” button is pressed and should define how to prompt for an initiative roll for each unique NPC

Party Sheet

Additional Party Fields

From the Party Sheet settings you can define all the fields that are shown on each entry in the Party Sheet. The GM can add Characters to the Party Sheet. Each field defined here will show up on each entry.

Inventory Tab Settings

You can enable or disable the Inventory Tab here as well as define fields that show up for each element in the Inventory tab of the Party Sheet.

Awards Tab Settings

In the Awards Tab you can define if XP can be awarded and if so what the default method is and what the name of the field is to store XP on each Character Sheet.

You can also define a list of Currencies that will then show up in the Party Sheet and allow the GM to distribute currency to Characters in the Party.

Misc

The Party Sheet also has hooks into Encounters. For example, if there are 2 PCs in the Party Sheet and the GM has an encounter with Goblins in it, he can set the number of the Goblins in the encounter to “$PC” and it will add 2 Goblins to the Combat Tracker.

Calendars

In the Calendars setting you can define Calendars that are available in the Ruleset.

By default, all Rulesets can use the Gregorian calendar.

Effects

From the Effects settings we define the list of additional Rule Types that can be selected when creating Effects in the Campaign.

These Rule Types do nothing on their own, they simple provide a way for GMs and Players to add them to an Effect so that they can then be used by the scripts in the Ruleset.

The Roll Handlers and Macros throughout the ruleset should check for these Effects on tokens and add modifiers as necessary to roll prompts. You can check out the D&D 5e (2024) ruleset for a comprehensive example of how this works.

We also suggest using the Common Script in Additional Settings to define your function for gathering all the Effects (and any modifiers from token values such as equipped items, etc.) that you can then re-use and call everywhere in your ruleset code for automation of these effects.

Roll Handlers

The Roll Handlers section should define a Roll Handler for every type used within your scripts. For example, if you prompt a roll in a script of type “attack” you should define a Roll Handler here called “attack” and then enter the script.

The script is called by the User who performed the Roll, so keep that in mind when writing the code. If you do not want Users to edit a token directly (for example when dealing damage) then you should have the Roll Handler output a message with a macro that the GM can use to apply damage. The D&D 5e (2024) ruleset is a good starting place to see how it is implemented there.

Metadata that was passed along to a Roll is provided here in the handler via data.roll.metadata

Campaign Settings

The Campaign Settings section lets you define additional settings that the GM can set for their campaign. These settings do nothing on their own, you should use the api.getSetting call to check the value of a setting in all relevant scripts.

Additional Settings

Finally, the Additional Settings section has some miscellaneous settings for the Ruleset.

  • Show Advantage / Disadvantage Buttons in Roll Prompt

    • If your ruleset has the ability to roll with some type of “advantage” (i.e. 2d20 drop lowest) or “disadvantage” you can define how this works here by selecting dice types for when the buttons should show up

  • Advantage Name

    • If your ruleset calls it something like “Boon” you can change the name here

  • Advantage Short Name

    • The short name rendered in the Dice Tray, example “ADV”

  • Disadvantage Name

    • If your ruleset calls it something like “Bane” you can change the name here

  • Disadvantage Short Name

    • The short name rendered in the Dice Tray, example “DIS”

Common Script

Here you can define all the functions you want available throughout your ruleset. You should place all common code here so that you are not re-defining it in all your scripts and records. Examples of what you might want to place in the Common Script would be functions to double dice damage, parse damage types from roll strings, collect effects and modifiers on a record or token, alter a record or token’s data when an attribute is changed, and so on.

Previous
Previous

VTT Controls