Character Vault
Any Concept / Any System
Your System Come To Life
Roll20 for Android
Streamlined for your Tablet
Roll20 for iPad
Streamlined for your Tablet

Personal tools

Sheet Worker Scripts

From Roll20 Wiki

Revision as of 06:29, 19 January 2016 by Chris D. (Talk | contribs)

Jump to: navigation, search

Sheet Worker Scripts are an advanced feature of the Character Sheets system which allows the sheet author to specify JavaScript which will execute during certain events, such as whenever the values on a sheet are modified.


Adding a Sheet Worker Script

To add a sheet worker script to a Character Sheet, simply add the script into the "HTML" section of the sheet using the following format:

<script type="text/worker">

on("change:strength", function() {


// ... etc


Note that the script tag must have a type of "text/worker" to be properly handled by the system. When the game loads, all script tags are removed from the sheet's template for security purposes. However, script tags with a type of "text/worker" will be used to spin up a background worker on each player's computer that can respond to changing values in their sheets and take action as needed.

Sheet Workers vs. Auto-Calculating Fields: Which should I use?

There's no hard-and-fast rule about this. Both of these tools are capable of achieving the same thing. Let's take a hypothetical use-case of a "Strength" attribute, which we want to use to keep a "Strength Mod" attribute updated. Here would be the differences between the two tools for this use case:

  • The auto-calculating fields are all re-calculated every time a sheet is opened for the first time. The Sheet Worker fields, on the other hand, only recalculate when their dependent values change. This means that sheets utilizing the Sheet Worker option will be much, much faster for players to open and interact with.
  • In addition, the Sheet Worker calculations run on a background process, meaning that there is no user interface lag created while the calculations are run. Disabled fields, on the other hand, run on the main process and as such can cause "lockups" or "stuttering" if there are large numbers of them being calculated at once (for example, if you have a very complicated sheet using thousands of disabled fields).
  • The auto-calculating Strength Mod field would appear disabled to the player. A Strength Mod field that is updated by a Sheet Worker, on the other hand, would be modifiable after the calculation has run (although any value entered would be overwritten when the Strength value changes). So a Sheet Worker would better support homebrew rules since the player could simply modify the Mod value after Strength changes. On the other hand, the auto-calculating field would not allow such a change, so rules would be "enforced" more rigidly.

In general, our recommendation is that you use auto-calculating fields sparingly. Give yourself a budget of 500 to 1,000 auto-calculating fields at most. We recommend using the new Sheet Worker functionality for most calculations, especially calculations which only need to be performed rarely (for example, your Strength value (and therefore your Strength Mod) probably only changes at most once per session when the character levels up. There's no need to re-run the same calculation over and over again every time the sheet is opened.

Sheet Worker API



Allows you to listen to the changes of specific attributes, or in the case of a repeating section any changes in the entire section. It's very straigthforward:

on("change:strength change:StrengthMod change:StrengthOtherThing", function() {
   //Do something here

on("change:repeating_spells:spellname", function() {
   //Do something here

on("change:repeating_spells", function() {
   //Would be triggered when any attribute in the repeating_spells section is changed

Note: All attribute names are lowercased in events. So even if you normally refer to an attribute as "Strength", use "change:strength" in the event listener.

Note: This supports the "_max" suffice in that ether "change:strength" or "change:strength_max" will fire an event, however these two variations seem to be interchangeable, in that ether or both will fire when ether "strength" or "strength_max" changes.


This is an event which will fire whenever a row is deleted from a repeating field section. You can also listen for a specific row to be deleted if you know its ID, such as on("remove:repeating_inventory:-ABC123")


This event will fire the first time a sheet is opened by a player in a game session. Note that it will fire again the next game session, and it most likely will fire on multiple people's computers (each time a person opens the sheet). However, it should be useful for doing things like checking for needed sheet upgrades.


// Do something the first time the sheet is opened by a player in a session



getAttrs(attributeNameArray, callback)

The getAttrs function allows you to get the values of a set of attributes from the sheet. Note that the function is asynchronous, which means that there is no guarantee that the order in which multiple getAttrs calls are made is the order in which the results will be returned. Rather, you pass a callback function which will be executed when the values have been calculated. The callback function receives a simple Javascript object with a list of key-value pairs, one for each attribute that you requested.

Here's an example:

on("change:strength", function() {
   getAttrs(["Strength", "Level"], function(values) {
      //Do something with values.Strength, values.Level

Values in repeating sections require a little special handling. If the event that you are inside of is already inside of a repeating section, you can simply request the variable using its name prefaced by the repeating group name and you will receive the value in the same repeating section the event was triggered in. For example, if we have a repeating_spells section that has both SpellName, SpellLevel, and SpellDamage, then:

on("change:repeating_spells:spelllevel", function() {
    ], function(values) {
      //values.repeating_spells_SpellDamage and values.repeating_spells_SpellName will both be from the same repeating section row that the SpellLevel that changed is in.

On the other hand, if aren't currently in a repeating section, you can specifically request that value of a field in a repeating section row by specifying its ID manually:



The setAttrs function allows you to set the attributes of the character sheet.

on("change:strength", function() {
   getAttrs(["Strength", "Level"], function(values) {
          StrengthMod: Math.floor(values.Strength / 2)

Note that although the setAttrs call does not take a callback, it is an asynchronous function and there is no guarantee to which order the actual attributes will be set for multiple setAttrs() calls.

For repeating sections, again, you have the option of using the simple variable name if the original event is in a repeating section, or you can specify the full repeating section variable name including ID in any event.

on("change:repeating_spells:spelllevel", function() {
   getAttrs(["repeating_spells_SpellLevel", "repeating_spells_SpellName"], function(values) {
         repeating_spells_SpellDamage: Math.floor(values.repeating_spells_SpellLevel / 2) + 10


This function allows you to get a list of the IDs which currently exist for a given repeating section. This is useful for calculating things such as inventory where there may be a variable number of rows.

on("change:repeating_inventory", function() {
   getSectionIDs("repeating_inventory", function(idarray) {
      for(var i=0; i < idarray.length; i++) {
         //Do something with the IDs


A synchronous function which immediately returns a new random ID which you can use to create a new repeating section row. If you use setAttrs() and pass in the ID of a repeating section row that doesn't exist, one will be created with that ID.

Here's an example you can use to create a new row in a repeating section:

var newrowid = generateRowID();
var newrowattrs = {};
newrowattrs["repeating_inventory_" + newrowid + "_weight"] = "testnewrow";