Rez includes many elements that you will combine to create your game, starting with the @game element that wraps the whole thing.

All elements in a Rez source file are prefixed by @.

A few Rez elements like @game and @zone contain other elements but most do not.

Directives

Alias (Directive)

The @alias directive allows the author to refer to a particular kind of element using a convenient and meaningful name. It is usually used in conjunction with parent specifiers. For example it might be more meaningful to define @sword and @shield as aliases for particular kinds of @item.

Example

In our Maltese Parrot game hats are a big deal and a range of hat items will be needed but we don’t want to repeat ourselves defining each one using @item so we can create an alias that specifies that a hat is an item and how hats are, generally, configured. Then our hat definition just needs to supply what’s different about that hat.

Here’s an example:

@item hat {
  type: :hat
  wearable: true
  usable: false
  bogie_would_approve: false
}

@alias hat = item<hat>

@hat wool_fedora {
  material: :wool
  colour: :black
  description: "A Messer black wool fedora hat"
  bogie_would_approve: true
}

@hat brown_derby {
  material: :felt
  colour: :brown
  description: "Battered brown derby"
}

In this example we have made an alias, @hat for @item specifying a parent id hat. Using @hat creates new @item`s that specify the `hat item as their parent. Equalivent to:

@item wool_fedora<hat> {
  ...
}

Note that an alias can specify multiple parents.

Actor (Element)

An actor represents an in-game character which could be the player avatar or a non-playable character that the player interacts with. Define an actor with the @actor element. In-game actors are represented by the RezActor object.

Actors are an optional concept and a simple game might not need them, choosing instead to represent any actors via attributes of the game or scene. But in more complex games it’s useful to be able to model actors separately.

Example

In this example of our game the player can decide which of the antagonists they wish to play as. Each has different abilities and trust other characters different amounts.

@actor sam_spade {
  name: "Sam Spade"
  stats: {
    gunplay: 6
    fisticuffs: 7
    drinking: 8
    flirting: 6
    sluething: 9
    chat: 6
  }
  container: #sams_stuff
}

@rel #sam_spade -> #miss_wonderly {affinity: +2}
@rel #sam_spade -> #joel_cairo {affinity: -2}
@rel #sam_spade -> #kaspar_gutman {affinity: -4}

@actor joel_cairo {
  name: "Joel Cairo"
  stats: {
    gunplay: 3
    fisticuffs: 3
    drinking: 5
    flirting: 9
    sleuthing: 6
    chat: 8
  }
  container: #joels_stuff
}

@rel #joel_cairo -> #sam_spade {affinity: 1}
@rel #joel_cairo -> #miss_wonderly {affinity: -1}
@rel #joel_cairo -> #kaspar_gutman {affinity: -3}

@actor miss_wonderly {
  name: "Ruth Wonderly"
  stats: {
    gunplay: 4
    fisticuffs: 2
    drinking: 5
    flirting: 10
    sleuthing: 4
    chat: 9
  }
  container: #ruths_stuff
}

@rel #miss_wonderly -> #sam_spade {affinity: 4}
@rel #miss_wonderly -> #joel_cairo {affinity: 1}
@rel #miss_wonderly -> #kaspar_gutman {affinity: -2}

@actor kaspar_gutman {
  name: "Kaspar Gutman"
  stats: {
    gunplay: 1,
    fisticuffs: 3,
    drinking: 9,
    flirting: 2,
    sleuthing: 7,
    chat: 9
  }
  container: #kaspar_stuff
}

@rel #kaspar_gutman -> #sam_spade {affinity: 2}
@rel #kaspar_gutman -> #miss_wonderly {affinity: -2}
@rel #kaspar_gutman -> #joel_cairo {affinity: 1}

By using a set of @actor`s we can keep things separate and easier to understand and use the built-in `@rel directive to create relationships between the actors.

Required Attributes

Optional Attributes

tags

Set

a set of keyword tags

container

Element Ref

id of the inventory that represents items carried by this actor

Event Handlers

on_accept_item

on_accept_item(actor, event) => {...}

The event argument is a map in the form:

{
  decision: <decision_obj>,
  inventory_id: <id>,
  slot_id: <id>,
  item_id: <id>
}

This is a script that can be called to check whether an item can be placed into an inventory slot of a container that they are owner of (See also: inventory#owner)

on_accept_item: (actor, event) => {
  event.decision.no(actor.name + " doesn't want to be burdened by worldly
  goods.");
}

on_init

on_init: (actor, event = {}) => {...}

This script will be called during game initialization and before the game has started.

on_enter

on_enter: (actor, event) => {...}

The event argument is a map

{
  location_id: <id>
}

This callback will be received when the actor is moved to a new location and is passed the id of the location to which the actor has moved.

on_leave

on_leave: (actor, event) => {...}

The event argument is a map

{
  location_id: <id>
}

This callback will be received when the actor has left a location and is passed the id of the location which has been vacated.

on_turn

on_turn: (actor, event = {}) => {...}

If the game turn mechanism is being used this callback will be received on each game turn. This is intended for simple cases and if you need to coordinate behaviours across multiple elements it may be better to use a system instead.

Asset (Element)

An @asset element refers to a file on disk, typically an image, audio, or video file, that will be presented in game.

Rez automatically copies asset files into the game distribution folder when the game is compiled and manages pathing so that assets can be referred to in game without worrying about filenames and paths.

Assets can be collected into groups (using @group) dynamically choose from among related assets.

Example

@asset hat_01 {
  file_name: "hat_01.png"
  tags: #{:hat}
}

This defines an asset that will be copied into the game when built and which can be referred to in-game by it’s id.

Rez will ensure that all assets are available during compilation.

Assets are the key to using asset groups that can be used for showing different but randomised media.

Required Attributes

file_name

String

name of the asset file in the assets folder

Optional Attributes

Event Handlers

on_init

on_init: (asset, event = {}) => {...}

This script will be called during game initialization and before the game has started.

Behaviour (Element)

Behaviours are elements that describe components of a behaviour tree. There are four types of behaviour:

  • condition — these test some property of the game world

  • action — these modify the game world

  • composite — these act on a group of 'child' behaviours

  • decorators — these modify other behaviours

While the difference between conditions and actions are fairly intuitive, the difference between composites and decorators is more subtle. Composites are about coordinating between a series of other behaviours, while a decorator typically modifies the results of another behaviour.

For example the $sequence core behaviour executes its children in turn and succeeds or fails based on them, while the $invert core behaviour turns its childs succees into failure (or vice verca).

When a behaviour is executed it either succeeds or fails.

As we have seen from the examples above, a composite behaviour usually succeeds or fails based on the success or failure of its children. A decorator typically modifies the success or failure of another behaviour. Conditional behaviours succeed or fail based on a test and action behaviours succeed based on whether their implied action is successful.

From these four simple concepts some very powerful behaviours can be built.

Rez defines a number of 'core' behaviours. By convention these have $ prefix to their id to separate them from author written behaviours. The core behaviours are mostly composites and decorators that are intended to be building blocks for author written behaviours.

The core of a behaviour element is its execute: script attribute. This is intended to implement the functionality of the behaviour and return a value whether it succeeds or fails.

Each behaviour can, optionally, receive options and, again optionally, a list of child behaviours. Conditions and actions are not expected to have children while composites and decorators don’t make sense without at least one child.

When a behaviour tree is run it gets passed an empty object {} as "working memory" to allow different behaviours to communicate state required to run the tree. As a new working memory is used each time the tree is run, any persistent state changes should be in the world model.

Let’s look at an example. We want a condition that tests whether a given actor is in a certain location. Here’s how we could implement it.

Example

@behaviour actor_in {
  options: [:actor :location]

  execute: (behaviour, wmem) => {
    const actor_id = behaviour.option("actor");
    const actor = $(actor_id);
    const location_id = behaviour.option("location");
    if(actor.location == location_id) {
      return {success: true, wmem: wmem};
    } else {
      return {success: false, error: "Actor is not in location", wmem: wmem};
    }
  }
}

Here we define the actor_in condition behaviour that tests whether a specified actors is in a specifed location. We might use it like this:

In this example we have defined a condition behaviour to test whether a specified actor is in a given location. This could be used in a sequence to ensure that an action only gets performed if in the correct location.

^[$sequence
  [actor_in actor=sam_spade location=sams_office]
  ...
]

The rest of the behaviours in this sequence will only be run if Sam is in his office, otherwise the sequence will fail.

Required Attributes

options

List

keywords describing the options that this behaviour uses. If there are no options use the empty list []

execute

Script

script that takes two parameters behaviour (a reference to the RezBehaviour itself) and wmem which is a reference to a map of "working memory" that can be used to record behaviour state or pass state between behaviours. The return value must either be a map that is either {success: true, wmem: wmem} or {success: false, error: "Message", wmem: wmem}.

Optional Attributes

Behaviour Template (Directive)

A behaviour template is a composable element of behaviour. When writing behaviour trees you may find yourself wanting to use some behaviours over and over but not want to copy a whole tree. That’s where behaviour templates come in. With a template you can include just the parts of behaviour you need.

Syntax

The syntax for a behaviour template look like:

@behaviour_template <template_id> ^[...]

Behaviour template id’s are separate to element id’s and can overlap without conflict.

Usage

Let’s look at an example. Here is an actor with some behaviours:

@actor sam_spade {
  behaviours: ^[$select [$sequence [actor_in location_type=:bar] [actor_is state=:thirsty] [actor_says msg="Give me a whisky."]]
                        [..more behaviours..]]
}

Maybe it’s not just Sam that you want to be able to order liquor at the bar. But you don’t want to copy Sam’s entire behaviours: attribute as it contains some behaviours that are unique to Sam. We can move this specific behaviour into a template and share it among multiple actors (or any other behaviour supporting object in your game):

@behaviour_template order_whisky ^[$sequence [actor_in location_type=:bar] [actor_is state=:thirsty] [actor_says msg="Give me a whisky."]]

@actor sam_spade {
  behaviours: ^[$select &order_whisky
                        [..behaviours unique to Sam..]]
}

@actor joel_cairo {
  behaviours: ^[$select &order_whisky
                        [..behaviours unique to Joel..]]
}

Now both Sam and Joel can make use of the behaviour.

Templates can also include other templates allowing for clean composition of many complex behaviours.

Card (Element)

Cards are the basic unit of content & interaction in a Rez game. Cards are "played" into a scene to present what is happening to the user and offer them choices about what to do next. In this they serve a similar role to Twine passages.

The content attribute is key as it defines the template that is rendered each time the card is played. Optionally a card may also define flipped_content which is what is displayed in a scene using a stack layout after the card has been used (i.e. the player has followed a link from that card).

Cards can be part of the main interface but can also be used as blocks in other cards. For example a card could be defined to represent a sidebar and included into scene layout.

Internally the content and flipped_content attributes of the card are converted into template expressions (a kind of Javascript function) so that they render quickly.

Example

@card intro_part_1 {
  content: ```
  You are in a mazy of twisty passages all alike.
  [[Go forward|intro_part_2]]
  ```
}

@card intro_part_2 {
  content: ```
  You get the idea!
  [[Go backward|intro_part_1]]
  ```
}

Required Attributes

content

Template

primary content to be displayed when this card is played into a scene

Optional Attributes

flipped_content

Template

content that is presented after the card is used in a stack layout

blocks

List

List of element-ids of the cards that can be referenced in the content or flipped_content templates, e.g. [#sidebar] is available as ${sidebar}

bindings

Table

keys to bindings which can either be game object ids or functions returning a value. E.g. bindings: {player: #player} allows ${player.name}

css_class

String

custom CSS classes to apply, "information is-primary"

Event Handlers

on_init

on_init: (card, event = {}) => {...}

This script will be called during game initialization and before the game has started.

on_enter

on_enter: (card, event = {}) => {...}

on_render

on_render: (card, event = {}) => {...}

on_ready

on_ready: (card, event = {}) => {...}

on_leave

on_leave: (card, event = {}) => {...}

Notes

Card content is written in Markdown and converted to HTML. It’s somewhat similar to a Twine passage and some of the basic syntax, e.g. [[Go forward|intro_part_2]] translate across to Rez.

However there are a number of additional syntaxes. For example it’s possible to hijack this mechanism using a script:

@card intro_part_1 {
  content: ```
  You are in a mazy of twisty passages all alike.
  [[Go forward]]
  ```
  on_go_forward: (game, evt) => {return Scene.load_card(game, "intro_part_2");}
}

Here we define an event handler which will respond to the link being clicked. By default Rez will automatically convert a link such as "Go forward" into the equivalent "go_forward" by downcasing and replacing whitespace with a single _ character.

Rez also has support for more dynamic types of links:

@card intro_part_1 {
  content: ```
  You are in a mazy of twist passages all alike.
  [[Go forward|go_forward]]
  ```
  go_forward: (game, evt) => {evt.choice.show("Go forward);}
  on_go_forward: (game, evt) => {return Scene.load_card(game, "intro_part_2")}
}

When a card link is written in this format, Rez will look inside the card for an attribute with the same name and a function value. It will call the function which can determine whether the link should be shown or hidden and, if it is shown whether it should be enabled or disabled. whether it is enabled or disabled.

However there is support for other kinds of actions and dynamic links. See the COOKBOOK for more information.

Component (Directive)

A @component directive is used to specify an HTML component used in templates.

For example we may have specified a button like this:

` <button class="button is-small" data-event="reload">…</button> `

There’s nothing wrong with this but the details are obscured by the attribute syntax, what if we could write:

` <event_button* event="reload">…</event_button*> `

The in event_button indicates that this tag is implemented by a component with the same name.

Let’s write this component:

` @component event_button (bindings, assigns, content) ⇒ { return `<button class="button is-small" data-event="${assigns["event"]}">${content}</button>; } ``

Container components like <event_button*> have their contents available in the content argument, attribute values in assigns, and all bindings available at the component site in bindings. Self contained components have no content specified.

Declare (Directive)

A @declare directive is a shorthand for defining an @object element without attributes. Typically you use this for declaring an object to be the target of relationships but which does not, itself, need to be defined in terms of a set of attributes.

Example

In this example we are specifying that the player hates the dark (affinity -5) but we don’t need "the dark" to be more than a placeholder to be the target of the relationship

@declare the_dark
@rel #player -> #the_dark {
  affinity: -5
}

Derive (Directive)

The @derive directive is used to form keywords into hierarchies of types for items, effects, and so on.

Let’s take an example of where this might be useful: inventories.

We setup a hierarchy as follows:

@derive :weapon :item
@derive :sword :weapon
@derive :mace :weapon
@derive :potion :item

The result is that an item with type: :sword, type: :mace, or type: :potion can be placed into a slot that accepts: :item. It’s not required to list all the different types of items that are legal in that slot. Equally our sword can be placed into a slot that accepts: :sword but an item type: :mace cannot, nor can an item type: :potion.

An item hierarchy can be as simple of complex as you need. At run-time all of the item type information is converted into tags. For example an item with type: :sword would have tags as if we had written tags: #{:sword :weapon :item}.

Effect (Element)

Effects are modifiers to aspects of the game that can be applied and removed dynamically as the game progresses.

For example an item, when worn, might convey a bonus to the actor wearing it. In this case the effect, attached to the item, is applied when the item is worn and removed when the item is removed.

Effect support is limited in v0.8. Effect scripts will be called and its up to the caller to ensure these work. In particular there is no support yet for effects that, for example, wear off over time.

Example

@effect drunk {
  name: "Drunk"
  description: "you're drunk, it's so much harder to concentrate"
  on_apply: (evt) => {
    const actor = $(evt.actor_id);
    // Add drunkness effects
  }
  on_remove: (evt) => {
    const actor = $(evt.actor_id);
    // Remove drunkness effects
  }
}

Required Attributes

Optional Attributes

Event Handlers

on_init

: (effect, event = {}) ⇒ {…​}

This script will be called during game initialization and before the game has started.

on_apply

: (effect, event = {}) ⇒ {…​}

on_remove

: (effect, event = {}) ⇒ {…​}

on_turn

: (effect, event = {}) ⇒ {…​}

If the game turn mechanism is being used this callback will be received on each game turn. This allows an effect to, for example, grow or decline over time.

Faction (Element)

Factions represent in-game groups with their own agenda, reputation, and views of others. Define a faction using a @faction element.

Example

@faction police {
  ...
}

@faction gutman {
  ...
}

@faction player {
  ...
}

Required Attributes

Optional Attributes

Event Handlers

on_init

: (faction, event = {}) ⇒ {…​}

This script will be called during game initialization and before the game has started.

Enum (Directive)

An @enum directive defines a set of legal values for an attribute. The syntax is:

@enum <attr-name> [:value1 :value2 :value3]

Here’s an example:

@enum color [:red :green :blue]

@object {
  color: :orange
}

This would cause a compilation error because the color attribute does not use one of the legally defined values.

'color' attribute value 'orange' is not legal enum value ('red', 'green', 'blue')

Notes:

  • an enum applies over all uses of that named attribute, you can’t use color: [255, 0, 255] in another element.

  • an enum only applies to attributes using keyword values, @enum size [1.0 2.0 3.0] is not a legal enum.

Filter (Directive)

A @filter directive defines a filter function that can be used in a subsitution Template Expression. A filter has a name which is how you refer to it in a template expression, e.g. capitalize and an impl function that takes a variable number of parameters (but at least one).

Example

Let’s say we wanted to be able to output a numeric attribute replacing any value over 4 with "a suffusion of yellow". Here’s a filter that would do that:

@filter SUFFUSION_OF_YELLOW_FILTER {
  name: "soyf"
  impl: (n) => {
    if(n < 4) {
      return ""+n;
    } else {
      return "a suffusion of yellow";
    }
  }
}

and the expression would be

${number_value | soyf}

As of v0.11.0 the Rez stdlib defines a number of filters and you can see how they are implemented by reading the stdlib.rez.

See also the filter_catalog.

Game (Element)

The game element is the top-level specification of the game and its metadata. It also defines the scebe entry point of the game.

The @game element has an implicit ID of game. All other elements and directives should be nested inside the top-level @game.

Example

@game {
  name: "The Maltese Parrot"
  author_name: "Dachshund Hamlet"
  IFID: "D2050DE2-97A2-1ED1-4CCA-AF9D3B0DD883"
  created: "2022-08-31 22:13:43.830755Z"
  version: 10
  layout: ```${content}```
  initial_scene_id: #sam_and_wonderly_meet
}

Required Attributes

name

String

name of the game

initial_scene_id

Element Ref

id of the scene the game begins with

IFID

String

ID of the game in the IFID database (an ID will automatically be generated when the game is created, it’s up to you whether you register it or not)

Optional Attributes

Event Handlers

on_init

on_init: `(game, event = {}) => {...}`

This script will be called during game initialization and before the game has started.

on_start

: (game, event = {}) ⇒ {…​}

The on_start event is triggered right after the Rez framework has initialized itself and before the first scene or card gets rendered. It’s an opportunity to customise game setup.

on_scene_change

: (game, event) ⇒ {…​}

event = {
  scene_id: <id>
}

The on_scene_change script is called whenever a new scene gets started.

The callback happens between the on_finish and on_start scripts of the scenes that are ending and beginning respectively.

on_card_change

: (game, event = {}) ⇒ {…​}

The on_card_change script is called whenever a new card is played into the current scene.

The callback happens between the on_leave and on_enter scripts of the card that is being played.

Group (Element)

A group specifies a collection of assets that can be selected from. Groups can be static by defining the id of member assets, or dynamic by specifying a set of tags. In the latter case the group will collect together all assets with any of the specified tags.

A group can be used to select an image at random, or cycle through the collection one-by-one.

Example

Required Attributes

type

Keyword

One of :image, :audio, :video which specifies the type of assets the group should contain

include_tags

Set

Set of tags that appear on assets that should be included in the group

exclude_tags

Set

Set of tags that appear on assets that should be excluded from the group

Optional Attributes

Event Handlers

on_init

on_init: (group, event = {}) => {...}

This script will be called during game initialization and before the game has started.

Inventory (Element)

The @inventory element creates a container that can hold `@item`s through the use of `@slot`s. Rez inventories are deliberately flexible to handle a range of use cases for example working memory (where items are thoughts) or spell books (where items are spells).

Rez has a fairly flexible inventory system that is based around 'slots' that define how items can be held. This allows an inventory to hold different kinds of items: you could have an inventory for items as well as an inventory for spells (spell book).

Inventory slots are matched against items to determine whether it’s possible to put an item in a slot.

Inventories are defined using the @inventory tag.

Inventories have a category which determines the kind of items that can be added to their slots. For example "spell" could represent a spell book, while "equipment" could represent the players inventory.

Example

@inventory player_inventory {
  slots: #{#hat_slot #jacket_slot #trousers_slot #shoes_slot #holster_slot}
}

Required Attributes

slots

Set

Set of element ids of `@slot`s that are included in this inventory

Optional Attributes

Event Handlers

on_init

on_init: (inventory, event = {}) ⇒ {…​}

This script will be called during game initialization and before the game has started.

on_insert

on_insert: (inventory, event) ⇒ {…​}

event = { slot_id: <id>, item_id: <id> }

This script will be called when an item has been added to the specified slot of this inventory.

on_remove

on_remove: (inventory, event) ⇒ {…​}

event = {
  slot_id: <id>,
  item_id: <id>
}

This script will be called after an item has been removed from the specified slot of this inventory.

Item (Element)

The @item element defines a conceptual item the player the player (or potentially an NPC) can acquire and add to an inventory. Items don’t have to represent physical objects but anything a player has for example a spell could be an item or even a memory.

Items are required to have a type keyword-attribute that connects them to compatible slots in inventories. That might include a shop, a wardobe, and a players backpack inventories.

However the Item/Inventory system is quite flexible so we can also think about spells as Items with the Inventory being a spell-book, or knowledge as Items with an Inventory being memory.

Items may be usable in which case they may have a limit to the number of times they can be used.

Some items can grant effects, either when the item is acquired, put into a specific slot (e.g. equipped), or when it is used.

The can_equip/on_equip scripts are used to decide whether the player can put an item in a given inventory & slot, and to process what happens when doing so.

For example equipping a magic ring might confer an effect on the player. But first it may be necessary to check that the player doesn’t already have a magic ring equipped.

A potion on the other hand confers no effect until it is used and might have only one use after which is presumed to be consumed.

Example

@item black_fedora {
  type: :hat
  description: "black fedora"
  wearable: true
  description: "A Messer wool fedora hat. Classy."
}

Note that this example throws up a design issue to be aware of: tags and boolean attributes are equivalent. For example wearable: true can also be represented by presence or absence of a tag wearable. In the case of Item elements its further possible to use the type system:

@derive :wearable :item
@derive :hat :wearable

In this case an Item with type: :hat will automatically be tagged as :wearable and :item.

Required attributes

type

Keyword

a keyword representing the type of the item, e.g. :hat that has optionally been `@derived’d

name

String

the name of the item

Optional attributes

description

String|Heredoc|Template

player description of the item

size

Number

where inventories should manage size, defaults to 1

usable

Boolean

if the item can be used, defaults to false

uses

Number

if usable is true, number of uses, assumed >= 0

container

Element Ref

Container this item begins the game inside

on_equip

Script

can_equip

Script

on_use

Script

can_use

Script

Event Handlers

on_init

: (item, event = {}) ⇒ {…​}

This script will be called during game initialization and before the game has started.

Keybinding (Directive)

Use the @keybinding directive to generate custom events from the user pressing a specific key, optionally with modifiers.

The syntax is:

(modifiers)? + keyName

Example

@keybinding ctrl+shift+C :show_character_sheet

Notes

Available modifiers are:

  • shift

  • ctrl

  • meta (the Command key on Mac computers)

  • alt (the Option key on Mac computers)

Modifiers are optional. Where the shift modifier is used the keyName should be in upper case.

KeyNames follow the Javascript KeyboardEvent rules.

Event processing follows the usual custom event processing rules (card → scene → game) allowing for processing events in different places.

List (Element)

A list is a named collection of values that can be used by other in-game elements, for example lists of names, locations, actors, and so on. Lists are defined using the @list element.

The run-time API supports selecting randomly from lists including with & without replacement.

Example

@list antagnoists {
  content: [#sam_spade #miss_wonderly #kaspar_gutman #joel_cairo]
}

@list lines {
  content: [
    "I distrust a man that says when. If he's got to be careful not to drink to much it's because he's not to be trusted when he does."
    "The cheaper the crook, the gaudier the patter."
    "I couldn't be fonder of you if you were my own son. But, well, if you lose a son, its possible to get another. There's only one Maltese Falcon."
    "What do you want me to do, learn to stutter?"
  ]
}

Required Attributes

Optional Attributes

Event Handlers

on_init

: (list, event = {}) ⇒ {…​}

This script will be called during game initialization and before the game has started.

Object (Element)

An @object element describes an author-driven concept. Isn’t everything in Rez an object of some kind? Yes, but elements like @author, @item, and @plot have built-in meaning and functionality. By contrast @object is a blank canvas that an author can use for anything they think of.

Example

Imagine we are building a role-playing game and we want to introduce the notion skills and perks. Rez does not provide either of these concepts out of the box but we can use the @object element to make them ourselves.

@object skill {
  $template: true
  description: "Something an actor has acquired the ability to do"
  min: 0
  max: 5
  cur: 0
}

@alias skill = object<skill>

@object perk {
  $template: true
  cost: 1
}

@alias perk = object<perk>

@perk gun_license {
  description: "Without this cops might pick you up for flashing your lead pumper."
}

@perk dont_go_down_easy {
  description: "Takes more than a bullet to put you down."
}

@perk beguile {
  description: "One look into your eyes and they're putty in your hands."
  cost: 2
}

@skill puzzling {
  description: "Figuring out how the clues fit together."
  ...
}

@skill gunplay {
  description: "Shooting straight, esp. when it matters."
  ...
}

@skill drinking {
  description: "Hold your liquour, yes sir!"
  ...
}

@skill fisticuffs {
  description: "Marquis of Queensbury be damned, hit 'em where it hurts."
  ...
}

@skill intimidate {
  description: "You don't actually **need** to shoot 'em."
  ...
}

@skill evade {
  description: "Never end up in the wrong place at the wrong time."
  ...
}

@skill fast_talk {
  description: "They'll think it was you doing a favour for them!"
  ...
}

@skill scheming {
  description: "They'll never see it coming."
  ...
}

In a real-game we’d expect to see more definition of what skills & perks do but at least we can talk about them meaningfully even though Rez knows nothing about them. As a consequence Rez cannot validate them or their attributes.

Extra care should be taken here that they are well-formed.

Plot (Element)

Example

Required Attributes

priority

Number

from 1 to 100, higher priorities break plot deadlocks

Optional Attributes

Event Handlers

on_init

: (plot, event = {}) ⇒ {…​}

This script will be called during game initialization and before the game has started.

Relationship (Element)

The @rel directive describes the relationship between two game elements called the source (the element which has the relationship) and the target (the element the source has relationship with).

A relationship is unidirectional from source to target. Where applicable use a second @rel to describe the relationship in the opposite direction.

A relationship can be specified between any two elements with an id. The most obvious example being between one actor and another, but you could equally define relationships between actors and factions, factions and factions, or — if it makes sense in your game — factions and items (the holy grail anyone?).

Example

The @rel element does not follow the usual element syntax. Instead it looks like this:

@rel source_id -> target_id {
  <attributes>
}

@rel #player -> #gutman_faction {
  affinity: -1.0
}

A relationship element isn’t assigned an id but automatically derives its id from the source and target id, in the example above the id would be rel_player_gutman_faction.

The syntax uses the symbol to help understand the unidirectionality of a relationship as being from a source element upon a target element.

The getRelationship(source, target) API on the RezGame object is a short- hand for doing this lookup manually.

We can use @rel to define all kinds of relationships:

%% the Gutman faction loves the Falcon
@declare falcon
@rel #gutman_faction -> #falcon {
  affinity: 1.0
}

%% the player hates brocolli
@declare brocolli
@rel #player -> #brocolli {
  affinity: -1.0
}

In these examples we have used an affinity: attribute (range: -1.0 to +1.0) to define the strength of the relationship but you can use any attributes you like. The following would be equally valid:

@rel #player -> #miss_wannalee {
  love: 65
  suspicion: 25
}

An alternative approach is to use tags:

@rel #player -> #miss_wannalee {
  tags: #{:lover :suspicious}
}

Required Attributes

Optional Attributes

Event Handlers

on_init

on_init: (relationship, event) => {...}
event = {}

on_change_affinity

Scene (Element)

A Game in Rez is authored in terms of @scene`s and `@card`s. Each `@card represents some content that is presented to the player. By contrast the @scene represent the structure and intelligence about which `@card`s to represent and how to respond to player input.

If you are familiar with Twine then a @card is roughly equivalent to a Twine passage. A Twine game is one long stream of passages woven together. Rez differs from Twine in that it uses the @scene to organise how the player interacts with the game and which/how the content is presented.

For example you might use different scenes for moving around the map, examining items, interacting with NPCs, buying from shops, and so on. You don’t have to, you could implement the game in a single scene, but the different layout and event handling possibilities make it easier.

A @scene requires an initial_card: #card_ref attribute that identifies the card that will be rendered when the scene begins. Additionally it requires a layout: attribute that specifies the surrounding markup.

Within the layout using the ${content} template expression to specify where scene content is inserted.

A @scene requires a layout_mode: attribute which must be either :single or :stack. In the :single layout mode only a single @card is ever displayed. While in :stack mode each new @card is layed out after the previous one.

Lastly a @scene may optionally have a blocks: [#card_id_1 #card_id_2 …​] attribute. Each referenced @card will be rendered and it’s content can be inserted into the layout using ${card_id_1}, ${card_id_2}, etc.

Example

@scene introduction {
  title: "Introduction"
  initial_card: #intro_part_1
  blocks: [#sidebar_1 #sidebar_2]
  layout_mode: :single
  layout: """
    <div class="sidebar">
      {{{sidebar_1}}}
      {{{sidebar_2}}}
    </div>
    <div>
      {{{content}}}
    </div>
  """
  on_new_card: (game, evt) => {...}
}

Required Attributes

title

String

what you present to the user to tell them what scene they are in

initial_card_id

Element Ref

id of the @card that is played when the scene begins

layout_mode

Keyword

One of :single for one-card-at-a-time and :stack for multi-card scenes

layout

Template

template containing the scene content in which cards are embedded

Optional Attributes

bindings

Table

See [Card]

blocks

List

See [Card]

layout_reverse

Boolean

In reverse mode new cards are played at the top of the stack (default: false)

layout_separator

String

Markup content to be inserted between cards when in stack mode (defaults: "")

Event Handlers

Scenes support a range of events:

on_init

: (scene, event = {}) ⇒ {…​}

The on_init script is called during game initialization and before the player has been able to take any actions. It will be passed an empty map of arguments.

on_start

: (scene, event) ⇒ {…​}

event = {
  card_id: <id>
}

The on_start script is called when a new scene is started. It will receive a map containing the scene_id.

on_finish

: (scene, event = {}) ⇒ {…​}

The on_finish script is called when a scene has eneded.

on_interrupt

: (scene, event = {}) ⇒ {…​}

The on_interrupt script is called when a scene is being interrupted by an interlude.

on_resume

: (scene, event = {}) ⇒ {…​}

The on_resume script is called when a scene is being resumed after an interlude.

on_render

: (scene, event = {}) ⇒ {…​}

The on_render script is called every time the scene is being rendered.

on_start_card

: (scene, event) ⇒ {…​}

event = {
  card_id: <id>
}

The on_start_card script is called when a new card is played into the scene. It will be passed a map containing the id of the card that has been played.

on_finish_card

: (scene, event) ⇒ {…​}

event = {
  card_id: <id>
}

The on_finish_card script is called when when a card has 'finished' as a new card is being played into the scene. It will be passed the id of the card that is finished.

Script (Directive)

A script is used to include arbitrary Javascript code into the compiled game. Specify a script using the @script directive.

The @script directive consists of a string containing the code to include between { and } markers.

The code defined in the game’s @script directives will be automatically included as <script> tags before the end of the <body> element of the generated HTML template.

Example

@script {
  function customFunction() {
    // Javascript code here
  }
}

Slot (Element)

A @slot describes a component of an @inventory so that an inventory can hold different types of things.

For example an inventory representing what a player is wearing might have slots for coats, trousers, and so forth while an inventory representing a spell book might have slots for different levels of spell.

See also: [Type Hierarchy]

Example

@slot holster_slot {
  accepts: :pistol
}

Required Attributes

name

String

name of the slot e.g. "Holster" that could be displayed to the player

accepts

Keyword

a keyword representing the type of Items that are permitted to be in the slot

Optional Attributes

capacity

Number

the sum of the sizes of @item`s that fit in the slot, see [Item] `size attribute

Event Handlers

on_init

: (slot, event = {}) ⇒ {…​}

This script will be called during game initialization and before the game has started.

on_insert

: (slot, event) ⇒ {…​}

event = {
  inventory: <id>,
  item: <id>
}

When an @item is placed into a @slot the on_insert event handler will be called.

on_insert: (inventory_id, item_id) => {
  // Do something
}

on_remove

: (slot, event) ⇒ {…​}

event = {
  inventory_id: <id>,
  item_id: <id>
}

When an @item is taken out of an inventory @slot the on_remove event handler will be called.

on_remove: (inventory_id, item_id) => {
  // Do something
}

Style (Directive)

A style is used to include arbitrary CSS into the compiled game. Specify a style using the @style directive.

The @style directive consists of a string containing the CSS to include between { and } markers.

The styles defined in the game’s @style directives will be automatically included as <style> tags before the end of the <head> element of the generated HTML template.

Example

@style {
  .card {
    /* My custom styles here */
  }
}

Required Attributes

Optional Attributes

Event Handlers

API

System (Element)

The @system element describes an author defined system that can respond to events generated in the game and modify the game world.

Systems are orthogonal to event handlers that are specific to a given event. For example, when a user clicks a link this has a specific outcome that will be meaningful to the player. However any number of systems might also respond to this event.

For example we might want to model weather in our game world and have the weather change, automatically, over time. This change is not necessarily related to any specific player activity (e.g. clicking a link to move between locations) but any event might trigger such a change.

Whenever the player generates an event all @system`s whose `enabled: attribute is true get the opportunity to process, and potentially modify, the event before normal processing and to change the result afterward.

Every @system must have a priority: attribute that is a number greater than 0. @system`s are run in highest-priority order (so priority `100 runs before priority 99).

Every @system must define at least one of before-event: or after-event: but can potentially define both.

Example

%% Here is a system that maintains wall clock time and when an event changes
%% the time, calculates new weather

@system weather_system {
  enabled: true
  priority: 25 %% low-priority

  wall_time: 0
  past_wall_time: _ %% just so we get an accessor

  weather: "It is sunny"

  before_event: (system, event) => {
    system.past_wall_time = system.wall_time;
  }

  after_event: (system, event, result) => {
    if(system.wall_time != system.past_wall_time) {
      system.calculate_weather();
    }

    return result;
  }

  calculate_weather: function() {
    this.weather = ["It is raining", "It is sunny"].randomElement();
  }
}

Required Attributes

  • enabled [Boolean]: if false, this system will not be run

  • priority [Number]: systems are run in descending priority order

Optional Attributes

Event Handlers

on_init

on_init: (system, event = {}) ⇒ {…​}

This script will be called during game initialization and before the game has started.

before_event

before_event: (system, event = {}) ⇒ {…​}

This handler will be called before the event has been processed by handleBrowserEvent(). If the handler modifies the event, the modified event will be passed on to successive systems and handleBrowserEvent().

after_event

after_event: (system, event = {}, result) ⇒ {…​}

This handler will be called after the event has been processed by handleBrowserEvent() and receives both the event in question and also the result that has been generated.

If the handler modifies the result, the modified result will be passed back through successive systems and to the browser itself. Modifying the event does nothing as it has already been processed.

Timer (Element)

The @timer element describes a game component that generates events after specific time interval has passed, either once or repeatedly.

Use a timer element when you want something to happen irrespective of player input.

For example a timer could be used to create a proper "wandering monster" scenario, where every minute the player is at risk of a monster wandering into their location.

Example

…​ @timer wandering_monsters { auto_start: true repeat: true interval: 60000 event: :wandering_monster } …​

Pre-Defined Attributes

auto_start

Boolean

If true, this timer will start when the game starts.

repeat

Boolean

If true this timer will keep sending events until it stops, otherwise it will only send one event.

count (optional)

Integer

With a repeated timer this specifies the number of times it should repeat.

event

Keyword

Specifies the name of the event that will be sent when the timer runs down. The event follows the normal rules for custom events.