The System of the World

Basic Primer

  • Defines the "rules" and core components of a Game
  • Specialize labels and terms for the Game, localizable
  • Defines the layouts of sheets and flyouts
  • Describes the special behaviors of the Gamespace
  • The lists of Game objects, such as Skills, Weapons, or Spells.

This is the core rules engine that defines a lot of things. It has many sections, each with their own dictionary of values, and each section may have separate documentation.

This game supports these types of player (or NPC) characters and this is what they look like. The default is usually just "character" but think also "ground_vehicle", "air_vehicle", "voidship", etc. If two entities can't use the same character sheet, they should be different sheets.

{ "entities":{ "character":{ "primer":{ }, "attributes":{ }, "collections":{ } }, "entitytype":{ "primer":{ }, "attributes":{ }, "collections":{ } } } }

This defines complex objects that are used by the game, such as a "spell" or "weapon". These are things that characters may have 0 or more of, and the thing they have can be pulled from a list.

Collection Identifiers (collectionId) is important. They must be unique and simple. When a module or catalog is imported, it may include additional entries for the collection. Sometimes you may have to say "use these items as this type of collection" which will force the Game engine to see the data as that type of object.

Collections define a bunch of things, they are the meat of content in many ways. They are used in many ways. Collections are defined at the engine level (so that it knows what to do with them), and later they are also referenced in the Character definition as well.

{ "collections":{ "items":{ "id":"items", "type":"complex_object", "label":"items", "static":false, "fields":{ "bonus":{ "type":"meta", "label":"bonus", "value":"number", "default":1 }, "label":{ "name":"label", "type":"meta", "label":"name", "value":"string" }, "description":{ "name":"description", "type":"meta", "label":"description", "value":"string" } }, "additem":true, "catalog":true, "default":true, "generic":{ "bonus":0, "label":"Generic Item", "source":"Custom", "description":"", "nonsearchable":true }, "personal":true, "targeted":false, "testable":false } } }

Collection definitions have many possible keys. They describe both how a thing, such a a Skill or Weapon, looks and behaves inside the Game, as well as how its Catalog windows and Flyouts can behave. Some Games may say "this collection contains only these items, and cannot be modified" (like with a skill tree).

Not all collections have all traits, and some traits are exclusionary to each other. We shall discuss them in sections.

Basic Attributes

The basic attributes of a collection definition are:

  • id: String, the same ID
  • label: String, this is run through Babel for translation/localization
  • itemname: String, run through Babel, this is the single unit name of the item ("skill" vs. "skills").
  • type: "complex_object" - you only ever want this, but it's important, there's vestigial stuff about arrays
  • default: Boolean - Is this granted to the character by default? Not sure this works or is needed anymore
  • static: Boolean - If true, this Catalog does not have child elements and is a definition only (like "armor points")
  • testable: Boolean - Can you test this item?
  • targetable: Boolean - Can you target this item? [UNIMPLEMENTED]
  • defaultvalue: Variable; depends on the data type
  • default_action: Testname (if present, this is the action for the item when it is executed
Value Attributes

'When I ask for the value of this item, what are you sending me?' This can have several meanings depending on the Game. For a Skill, we could be returning the total value of it, or the ranks, or the dice to be rolled - it depends.

  • value: Enumeration, described below
  • calc: A calculation, and only used if value = "calculation".
  • ranked: Boolean, only present if item is ranked (ranked only)
  • ranks: A dictionary of values that show how the value can change based on the rank (ranked only)

The values that can given to the value field are:

  • raw: Just the raw value of the collection item. Do no processing or lookup (reads "value" field).
  • calculation: Take the value of "calc" and run it against this item
  • rank_calculation: With ranks, return the value of the rank's calc
  • $fieldname: Return the value of the field in the collection item (similar to raw)
Ranked Items

For ranked items, we have an addition sub-dictionary that can describe different effects at different ranks. This field, ranks, is only used if both ranked is true the value of value is "rank_calculation".

{ "ranks":[ { "rank":1, "label":"basic", "calc":"floor(self[attribute] * .5)" }, { "rank":2, "label":"trained", "calc":"self[attribute] +0" }, { "rank":3, "label":"+10", "calc":"self[attribute] +10" }, { "rank":4, "label":"+20", "calc":"self[attribute] +20" } ] }
Catalog and Gamespace Behaviors
  • additem: Boolean (if false, the catalog won't allow you to add items from it)
  • canfavorite: Boolean (Can these items be favorited?)
  • singular: Boolean (If true, the same catalog items cannot be added twice. This is for things like 'skills'.)
Catalog Values

The catalog field describes what to show in this field when viewing the catalog.

  • catalog: Enumeration, see below

Values for the catalog field can be:

  • value: Give me the value of the field, parsed through the language dictionaries
  • raw: Give me the value of the field, no parsing
  • lookup_value: For enumerations, give me the value from the options

The collection definition's fields dictionary describes the Collection Item and what it looks like. Some fields (such as description) exist whether you define them or not.

Each field in an item can have the following attributes:

  • name: String, the name of the field, machine readable
  • label: String, the label of the field, run through the dictionary lookup (human readable)
  • type: Enumeration, values: string, meta, int
  • default: Variable, what to use if no value
  • catalog: Enumeration
  • value: Enumeration
  • values: Dictionary, only present if value is "enumeration"
{ "fields":{ "label":{ "name":"label", "type":"string", "label":"name" }, "attribute":{ "name":"attribute", "label":"attribute", "type":"meta", "catalog":"lookup_value", "value":"enumeration", "values":{ "weapons_skill":"weapons_skill", "ballistic_skill":"ballistic_skill", "strength":"strength", "toughness":"toughness", "agility":"agility", "intelligence":"intelligence", "perception":"perception", "willpower":"willpower", "fellowship":"fellowship" } }, "ranks":{ "name":"ranks", "label":"ranks", "type":"int" }, "bonus":{ "name":"bonus", "label":"bonus", "type":"int", "default":0 }, "type":{ "name":"type", "label":"type", "catalog":"value", "type":"enumeration", "options":[ { "label":"basic", "value":"basic" }, { "label":"advanced", "value":"advanced" } ] } } }

These are really atomic parts of interactivity. Before you think "why not balkanize these," a lot of these actions are system-dependent - for instance, not every game has "initiative".

{ "tests":{ "grant_xp":{ "special":"grant", "resultinto":"total_xp" }, "roll_initiative":{ "die":"d10", "modifier":"+ attribute[agility_bonus]", "resultinto":"initiative" }, "d100_less_or_equal_to_value":{ "die":"d100", "successcriteria":"less_or_equal" }, "melee_attack":{ "die":"d100", "successcriteria":"less_or_equal", "stat":"weapons_skill" } } }

Actions are passed actors and targets by context. These then execute the test, or have it executed on them, etc. They are not defined here but are passed as arguments.

- You cannot have both eachactor and eachtarget

  • targeted: Boolean (needs a target attribute)
  • isattack: Boolean (is an attack) [poorly implemented]
  • eachactor: Enumeration, see below
  • eachtarget: Enumeration, see below
  • test: Which test [see above] to execute inside this action
  • message: message_key (Use this message in the Table Log)
  • prefertoolmessage: Boolean (If there is a tool and the tool has a message, let it override)
  • special: Special_action_name (use a special action, see below)
  • metrics: Dictionary (additional metrics to include when displaying)

The values for eachactor and eachtarget can be:

  • map_entity: "Living" tokens on the map, both player and storyteller
  • map_corpse: "Dead" tokens on the map
  • map_player: Player-controlled tokens on the map
  • player: Every player-controlled entity
  • map_npc: Every storyteller-controlled entity on the map [UNIMPLEMENTED]

These are special actions, and handled by the system.

"special" : "view_character_sheet"
  • view_character_sheet: Pop open the feather
  • edit_permissions: Open the edit perms dialog for an entity
  • clear_map_tokens: Clear all tokens from the current map
  • start_combat: Start the combat sequence
  • end_combat: End the combat sequence
  • take_control: Take operational control of an entity
  • remove_from_map: Remove an entity token from the map
{ "actions":{ "roll_initiative_for_map":{ "eachactor":"map_entity", "test":"roll_initiative" }, "roll_initiative":{ "test":"roll_initiative" }, "grant_xp_to_party":{ "eachtarget":"player", "test":"grant_xp" }, "grant_xp":{ "test":"grant_xp" }, "skill_test":{ "test":"d100_less_or_equal_to_value", "message":"skill_test_generic", "metrics":{ "successes":"$[difference] / 10", "label":"successes" } }, "melee_attack":{ "test":"melee_attack", "prefertoolmessage":true, "message":"actor_attacked_target_with_weapon-melee_generic", "targeted":true, "isattack":true, "metrics":{ "successes":"$[difference] / 10", "label":"successes" } } } }

Character definitions are three dictionaries, two of which are of primary importance. NPC versions of these are templates (unless deployed to a Board). The version included in the Game definition will have a Primer but exported or deployed versions will not.

Only in the Game definition, acts as a map between attributes and system-aware variables. This is a lookup table, where the key is the system term for the thing, and the value is the local character attribute term. In the example below, the equivalent value for "maxhealth" is set to "wounds", and "currhealth" is set to "curr_wounds". Those could be "max_hit_points" and "curr_hit_points" - or any other term that indicates character health.

Your Game may not need these things.

{ "primer": { "move": "half_move", "doublemove":"full_move", "maxhealth": "wounds", "currhealth": "curr_wounds", "defense": "armor", "turnorder": "initiative", "soak": "toughness_bonus" } }

Only exists in instanced applications of the definition (e.g., PC, NPC, or NPC Template). This section contains values that are not intended to be addressed by the Game engine parser. They are things like avatar icons, creator information, update information, etc.

There are one-to-one values; that is, a character can only have one of them, such as a "Strength" score, or an "Attack Bonus". These can be of several data types and may be calculated or derived rather than hard set. Some attributes (such as "description") will always exist.

An Attribute definition is a dictionary that describes several values:

  • label: A string, but will be passed through the localizer
  • type: Enumeration: "meta", "attribute", or "derived_attribute"
  • value: Enumeration: "number", "string", "paragraph"
  • calculation: Math calculation for derived values
  • volatile: Boolean, the default is false
  • generate: Calculation

type: Functionally, "meta" and "attribute" behave the same but may or may not appear in certain list views. "derived_attribute" means it is calculated at run time.

value: "Number" values are checked to be sure that they are numbers. "String" means "never try to treat this as a number". "Paragraph" implies a large text field that may include Rich Text. This should have minvalue, maxvalue, default, but it doesn't yet.

calculation: If present, the value is derived, and uses the calculation provided (see below for syntax).

volatile: If present and true, then players who only have OPERATE permissions may edit these values. Otherwise, only those with EDIT permissions may change things.

generate: Tell us how to generate this [ NOT IMPLEMENTED YET]

{ "attributes":{ "speed":{ "type":"attribute", "label":"speed", "value":"number" }, "strength":{ "type":"attribute", "label":"strength", "value":"number" }, "strength_mod":{ "calc":"floor((attribute[strength] - 10) / 2)", "type":"derived_attribute", "label":"strength_mod" } } }

In a calculation, the following attributes get expanded:

  • attribute[name]: Get character attribute
  • d[die]: Roll a die
  • \dd[die]: Roll a die x times
  • global[name]: Global variable (game level)
  • party[name]: Party-level game variable (e.g. Profit Factor) [UNIMPLEMENTED]
  • tabletop[name]: Tabletop variable (a setting) [UNIMPLEMENTED]
  • target[name]: Selected token attribute
  • map[name]: Attribute of the map (x, y, currcoords, coords)
  • self[name]: Refers to attributes on the self, used in things like collection calculations("attribute[ballistic_skill] + self[bonus] + target[rangemod]")
  • collectionitem[name]: [poorly implemented]
  • character[name]: [poorly implemented]

In the character definition, the collections dictionary shows what the character has in its pocketses. Often empty by default ("gear"), and often pre-populated at creation ("skills").

{ "collections":{ "collection1":{ "itemid":{ "value":0 }, "itemid2":{ "value":4 } }, "collection2":{ }, "collection3":{ } } }

A Catalog is a list* of item definitions that are used by a Game. Anything of which a character can have multiple items - something that fits one of the Collections - is an entry from a Catalog.

Catalogs are seen differently by Players and Storytellers. Players see a collated version of all the Catalogs of a type that have been included in a Tabletop; the Storyteller sees the individual Catalogs and their sources. Regardless of the source, the entry and creation of a Catalog are the same.

(*Actually a dictionary)

This is a dictionary of terms that is used by the Game, its Sheets, and its Catalogs that are specific to the Game (such as "Hit Points" or "Wounds" or "Warp Factor").

Entries are simple key = value pairs - and can be seen that way - but there is a language to them that can be used for pluralization, variable interpolation, and even pronoun usage in messages.

Messages are parsed as standard internationalized (i18n) messages ($1 as well as going through a context processor (see below). Arguments are resolved $1, $2, $3, etc.

(Note that the localization system is not online so all keys need to be in 'en', but the instant there's a localization it goes up in priority.)

{ "en":{ "lookup-key":"Lookup Key", "hit_points":"Hit Points", "wounds":"Wounds", "weapons":"Weapons" }, "ork":{ "lookup-key":"Lookit 'ere", "hit_points":"'it Points", "wounds":"Orkiness", "weapons":"Weapons" } }

In addition to i18n processing, messages go through an addressing system. Each fragment is passed an entity and possibly an item. Addressing follows this format, in this order of seeking:

  • $[actor] A context-relevant interactive element for the Actor. In the Gamespace, $[actor] will display the actor's name as a hot link, which highlights the actor's token if visible, and clicking will zoom to them/open a sheet view.
  • $[actor.field] Gives the raw value in the context of an Actor
  • $[] - Gives a deep look into the context of an Actor
  • $[actor.pronouns.possessive] Possessive pronoun [sentence case] ('They')
  • $[] Lowercase possessive pronoun ('they')
  • $[actor.pronouns.possessive.uc] Uppercase possessive pronoun ('THEY')
  • $[tool.field] Gives the raw value in the context of a tool (weapon, spell, etc.)
  • string can be looked up with BABEL.string();

A workflow understands the context of its execution. This context is provided to any kind of messaging. Not all elements are present in a workflow; a workflow shouldn't have "empty" values for things it doesn't need and these should not be in the dictionary.

  • $[datestamp] Spits out a span of the "from now" time. Tooltipped to show the full time.
  • $[resolutionstamp] If the workflow is resolved, spits out when it was, as above
  • $[user] is the user doing the thing. Nearly _always_ present. Not static or forgeable.
  • $[targetuser] Targets user of an action, if needed
  • $[user|targetuser.namestring] Returns hot/active name string
  • $[user|targetuser.avatarstring] Returns avatar image
  • $[user|targetuser.hotavatar] Avatar image that links to a user's /@ profile page
  • $[user|targetuser.pronouns.single] Default is 'they'
  • $[user|targetuser.pronouns.subjective]Default is 'they'
  • $[user|targetuser.pronouns.objective] Default is 'them'
  • $[user|targetuser.pronouns.possessive] Default is 'their'
  • $[actor] The entity that performed the action
  • $[target] The target entity
  • $[actor|target.namestring] Returns hot/active name string
  • $[actor|target.avatarstring] Returns avatar image
  • $[actor|target.hotavatar] Avatar image that links to the profile page (Not yet implemented awaiting /tabletops/$tabletopId/entities/$entityId)
  • $[actor|target].pronouns.single] Default 'they'
  • $[actor|target].pronouns.subjective] Default 'they'
  • $[actor|target].pronouns.objective] Default 'them'
  • $[actor|target].pronouns.possessive] Default 'their'
  • $[tabletopinvite]
  • $[tabletopinvite.avatarstring] Returns avatar image
  • $[tabletopinvite.hotavatar] Avatar image that links to the Tabletop profile page
  • $[document] References a document from the Tabletop
  • $[flag] References a pointer flag on a Tabletop's Board
  • $[tool] A Catalog item used in the action
  • $[metrics] Optional, defines additional ways of looking at the response
  • $[metrics.namestring]
  • $[metrics.successes]
  • $[metrics.successcount]
  • $[test] Which test to execute inside this action
  • $[test.die] Die result from the test
  • $[test.pool] Dice pool results from the test
  • $[test.poolstring]
  • $[value] The value part contains a lot
  • // The value part contains a lot.
  • $[value.namestring]
  • $[value.finalvalue]
  • $[value.diestring]
  • $[value.diename]
  • $[value.modifier] Value of a roll modifier
  • $[value.resultstring] Returns the raw value string of the object
  • $[value.resultclasses] Returns an array of classes
  • $[value.result]
  • $[value.rollresult] same as result, but calculated from pool
  • $[value.bonus] Returns the value of a bonus
  • $[value.difference] Represents the calculated difference between final value and result value.
  • $[value.success]

Any other elements given to the message compiler will remain, but they will not have anything special done with them; they will just be addressable as:


Character sheets are defined outside of the Game definition as the Tabletops (and eventually players) may choose to override these without changing the rules. This would normally get attached to the Tabletop, but there needs to be a default, and it's easiest to think of this outside of the entity type nest.

Games should have as many Sheet definitions as they have entity (Token) types defined.

{ "charactersheets":{ "character":{ }, "voidship":{ }, "ground_vehicle":{ } } }

Character sheets should be thought of as three "modes":

  • : The character as Flyouts and a Slug
  • : The character as seen in a single Sheet
  • : The character as seen outside of the virtual tabletop or on a mobile device (defaults to Full Sheet)

A character sheet definition JSON blob consists of the following primary keys:

  • templates: A dictionary of character sheet templates.
  • fullsheet: How to draw the full character sheet
  • slug: How to draw the slug, in Operator
  • panels: An array of template definitions

This is a dictionary of interactive content blocks. Content blocks are either atomic elements laid out in a pattern, or templates applied to collections, or a combination of both.

Templates should be designed around common intent or group. A template for "skills" should not also contain blocks for attribute editing, for instance.

The same content can be used in multiple templates. A flyout may use tabs over scrollable sections, and thus want a different template for the same items.

Describes the layout of elements for the slug in the Operation interface. We are concerned primarily with a "status" array inside, which is read as a series of template blocks.

This describes the display of the Operator flyouts. This is a simple array of template ID keys. The order in which they are listed is how they will display in the Operation interface. Currently only a "sections" array is used.

{ "fullsheet":{ "sections":[ "vital_statistics", "skills", "publicnotes", "items" ] } }

This describes the display of the Operator flyouts. This is a simple array of template ID keys. The order in which they are listed is how they will display in the Operation interface.

{ "panels":[ "vitals", "skills", "items" ] }

Describes how Gamespace components behave. [This isn't well implemented]

  • : []
  • : []
  • : what to do when tokens drop
  • : token actions and status
  • : partyflyout columns
  • : combat servitor columns and config