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.
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.
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.)
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.)
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.
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:
field - The data field to store the portrait, which should always be “portrait” — this cannot be changed
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:
field - The data field to store the string value
defaultvalue - Default value if none is set
textalign - Text alignment (left, center, right)
multiline - If true, allows multiple lines of text
maxrows - Maximum number of rows for multiline input
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:
field - The data field to store the rich text
disablecontrols - If true, hides the formatting controls
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:
field - The data field to store the number
minvalue - Minimum allowed value
maxvalue - Maximum allowed value
showsign - If true, always shows + or - sign
defaultvalue - Default value if none is set
textalign - Text alignment (left, center, right)
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:
field - The data field for the name (usually "name")
defaultvalue - Default name if none is set
textalign - Text alignment (left, center, right)
multiline - If true, allows multiple lines
maxrows - Maximum number of rows for multiline input
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:
field - The data field containing the linked record data
All common attributes
<recordlink field="weapon" label="Equipped Weapon" ></recordlink>
Checkbox
Description: Creates a checkbox for boolean values.
Attributes:
field - The data field to store the boolean value
All common attributes
Example:
<checkbox field="proficient" label="Proficient" ></checkbox>
Radio Button
Description: Creates a radio button for selection within a group.
Attributes:
field - The data field to store the selection, should be the same for all radio buttons in the same group
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:
textalign - Text alignment (left, center, right)
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:
orientation - Direction of the divider ("horizontal" or "vertical")
All common attributes
Example:
<divider label="Combat" orientation="horizontal" size="lg" ></divider>
Tag
Description: Adds a tag that displays text with tooltip descriptions.
Attributes:
field - The data field to display
tooltip - The tooltip text to show on hover
variant - Visual style ('default' or 'filled')
color - Color of the tag (uses Mantine color system)
size - Size of the tag (xs, sm, md, lg, xl)
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:
field - The data field to store selection
options - Array of options (as JSON string)
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.)icon - Icon to display
multiselect - Allow multiple selections if true
searchable - Enable search functionality if true
defaultvalue - Default selected value
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:
field - The name for the field of the progress bar (not used for data)
currentvaluefield - The field for current value of the progress bar
maxvaluefield - Field containing the maximum value
maxvalue - Static maximum value, if maxvaluefield is not used
color - Can be set to 'health' to render the progress bar in different shades depending on the %-remaining
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:
field - The data field to store the count value
maxvalue - Static maximum value, used if maxvaluefield is not set
maxvaluefield - Field containing maximum value
All common attributes
<counter field="hitDice" label="Hit Dice" maxvaluefield="level" ></counter>
Button
Description: Displays a clickable button.
Attributes:
field - The data field to bind to
icon - Icon to display on the button, if set
disablediflocked - If true, button is disabled when record is locked, if false it is enabled even when locked
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:
field - The data field to bind the current value/state of the button to
disablediflocked - If true, button is disabled when record is locked, if false it is enabled even when locked
options - Array of state options (as JSON string)
Uses the JSON format
[ {"value": "value", "label": "Label”, "icon": "TablerIconName"} ]
getoptions - Function name to get options dynamically
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:
field - The data field to bind the collapsed state to
icon - Icon to display on the header
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:
field - The data field to display in the indicator
position - Position of the indicator
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:
field - The data field containing the list items
listtype - The record type to use for list items (must match the ‘type’ defined for the List Type)
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
getfilters - Function name to determine list filters programatically.
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:
field - Data field to bind to
label - Display label above the field, if supported by field type
height - Element height
width - Element width
description - Description text displayed under the label, if supported by field type
placeholder - Input placeholder text, if supported by field type
size - Element size (xs, sm, md, lg, xl)
color - Element color (uses Mantine color system)
variant - Visual variant — uses Mantine variants, with some modifications for certain fields (unstyled, outline, filled, striped, outline-striped)
onclick - Click event handler function name, should be a function either in the Common Script or in the Record’s script
onload - Load event handler function name, should be a function either in the Common Script or in the Record’s script
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
hidden - If true, element is hidden by default — see the API section for hiding and unhiding fields
radius - Border radius (xs, sm, md, lg, xl)
textalign - Text alignment (left, center, right)
hideonlocked - If true, hidden when record is locked
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:
value - The current field's value
dataPath - Path to the field's data in the parent record
record - The current record or list item
isGM - Boolean indicating if user is GM
userId - Current user's ID
recordType - Type of current record
data - Additional contextual data
data.token: object | null
[Combat Tracker Scripts] The currently active token in combat.
data.tokens: Array<object>
[Combat Tracker Scripts] All tokens currently in the combat tracker.
data.initiative: number
[Combat Tracker Scripts] The current initiative count in combat.
data.round: number
[Combat Tracker Scripts] The current round count in combat.
data.roll: object
[Roll Handler Scripts] The result of a dice roll, containing total, dice results, and metadata.
data.character: object | null
[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:
Token from data context
For GMs: First selected token
For Players: Player's token
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:
If the macro was dropped on a token, returns an array containing just that token
If tokens are selected, returns array of selected tokens
If user is not a GM and has a character, returns array containing their character
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:
**bold** → bold
*italic* → italic
***bold italic*** → bold italic
~~strikethrough~~ → ~~strikethrough~~
# Header 1
## Header 2
### Header 3
#### Header 4
##### Header 5
###### Header 6
Tables
| Header 1 | Header 2 ||----------|----------|
| Cell 1 | Cell 2 |
| Cell 3 | Cell 4 |
Lists
- Unordered list item* Also unordered
1. Ordered list item
2. Second ordered item
Macros
```MacroNameSeparatedByUnderscoresCode to Execute on Click
```Custom Tags
:iconname: → Displays icon from system
[tagname|tooltip] → Displays tag with hover tooltip
[color=red]Colored text[/color] → Colored text
[center]Centered text[/center] → Centered text
[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.