Expressions
An expression is a line of JavaScript the overlay evaluates for you against the live match data.
Rive graphics use expressions for every data binding. A code graphic uses them in the
userExpressions array of its manifest, and receives
the results in userExpressionValues. The overlay evaluates every expression again on every data
change.
$d.1.score > $d.2.score ? $d.1.name : $d.2.nameThe language
Section titled “The language”An expression is JavaScript. The overlay evaluates it in a sandbox with the references and helpers on this page, and nothing else.
- One expression or many statements. A single expression returns its value. A script of
several statements returns the value of the last statement, with no
return.var,if,for,whileand function expressions all work. - No browser globals.
window,document,fetch,Date,RegExp,Promise,Symbol,Intl,Errorand timers are not in scope. Each one resolves toundefined. A call such asnew Date()throws, and the binding falls back to its default. There is no clock in an expression. Send a time value through the match data or a theme variable instead. - Regular expression literals work. The
RegExpconstructor is absent, but/live/i.test(x)andx.match(/\d+/)both work, because a literal is syntax and not a global. - The
NaNandInfinityglobals are absent. UseNumber.NaNandNumber.POSITIVE_INFINITY, or test withisNaN(x). - No logical assignment.
||=,&&=and??=do not work on match data. The left side is read before the missing-data rules apply, so the assignment never happens. Writex = x || 'fallback'instead. - No side effects. An expression cannot change the match data, the variables or the graphic.
- Numeric keys with dot notation.
$d.1.scoreis rewritten to$d['1'].scorebefore evaluation. Bracket notation works too.
The context
Section titled “The context”| Reference | Holds | Keyed by |
|---|---|---|
$d | The live match data for the sport. The same shape as sportData in Data binding | Sport field names |
$v | The control variables of the graphic. Each one is { value, data } | Variable name |
$t | The theme variables: colours, labels, sponsor names | Variable name |
$u | The other user expressions of the graphic, by name, already evaluated | Expression name |
$x | The latest snapshot of each external data source of the theme | Data source alias |
$d: match data
Section titled “$d: match data”$d is the sport data of the match. $d.1 is the home team and $d.2 is the away team in every
team sport. Read the schema for the field list: GET /v2/schemas/sports/{sport} over REST.
$d.1.abbreviation // "MUN"$d.clock // "43:30"$d.1.startingLineup[0].lastName // The first starter of the home team$d.1.scorers?.[0]?.player.lastName ?? '' // Optional chaining works$v: control variables
Section titled “$v: control variables”A control variable is { value, data }. value is what the operator set. data is the resolved
entity for an entity-typed variable: the team, the player, the fact or the statistic.
$v.Title.value // "LINEUP"!$v.hide.value // true while the graphic is on air$v.Team.value // 1, the team id$v.Team.data.name // "Manchester United"$v.StatOne.data.names.plural // "Shots"$v.StatOne.data[1] // The home team value of the statisticNumber($v.Rows.value) >= 3 // An enum value is a string$t: theme variables
Section titled “$t: theme variables”A theme variable resolves to its value. A per-graphic override wins over the theme value, and the theme value wins over the default.
$t.primaryColor // "#0000ff"$d.isLive ? $t.liveLabel : $t.idleLabel$u: user expressions
Section titled “$u: user expressions”A user expression can read another user expression by name. The overlay evaluates them in
dependency order. An expression in a cycle, or one that throws, resolves to null.
$u.leader + ' leads by ' + $u.margin$x: external data
Section titled “$x: external data”An external data source is a JSON or CSV snapshot the theme declares and a write key fills over REST. Read it by alias. See External data sources.
$x.results.rows[0].Home ?? ''$x.results.rows.lengthList context
Section titled “List context”Inside a list binding of a Rive graphic, two more names are in scope.
| Name | Value |
|---|---|
index | The position of the current item, from 0 |
length | The number of items in the list |
Helpers
Section titled “Helpers”| Helper | Returns |
|---|---|
startsWith(str, prefix) | true when str starts with prefix. false for a missing string |
endsWith(str, suffix) | true when str ends with suffix. false for a missing string |
contains(strOrArray, item) | true when the string or array holds item. false for a missing value |
find(array, fn) | The first item for which fn returns true |
findIndex(array, fn) | The index of that item, or -1 |
filter(array, fn) | The items for which fn returns true |
map(array, fn) | A new array of fn(item) |
reduce(array, fn, initial) | The folded value |
These JavaScript built-ins are in scope: Math, Number, String, Boolean, Array,
Object, JSON, parseInt, parseFloat, isNaN and isFinite. String and array methods work on
any value, so $d.1.name.toUpperCase() and $d.1.squad.map(p => p.lastName) both work.
Missing data
Section titled “Missing data”A missing value adapts to how you use it: blank as text, 0 in arithmetic. The same path works in
both places, with no guard.
$d.1.aggregateScore // Blank in a text binding$d.1.aggregateScore + $d.1.score // Adds as 0`agg ${$d.1.aggregateScore}` // "agg "Missing means null, or a field this match does not carry. 0, false and '' are real values.
They are never treated as missing.
The members of the field’s type work as well, so you do not have to guard before you call a method. A chain never throws, however deep.
$d.1.coachName.toUpperCase() // ''$d.1.coachName.length // 0$d.1.squad.map(p => p.lastName) // []$d.1.squad.length // 0$d.1.a.b.c // '' — no errorA path the schema does not know
Section titled “A path the schema does not know”A path outside the schema has no type to adapt to. It reads as an object you can keep reading into, and a method call on it throws, so the binding falls back to its default.
$d.1.coachName.toUpperCase() // '' — the schema knows coachName is a string$d.1.notInTheSchema.toUpperCase() // Throws — check the field name against the schemaRead the schema before you write a path: GET /v2/schemas/sports/{sport}.
Checking for a missing value
Section titled “Checking for a missing value”| Check | Matches |
|---|---|
x == null | null and absent. 0, false and '' do not match |
!x | null and absent, and also 0, false and '' |
Use == null when a zero is a real value you must keep on screen. Both || and ?? fall back on
a missing value.
$d.1.aggregateScore == null ? '-' : $d.1.aggregateScore$d.1.score == null // false — the team has 0, which is a value!$d.1.score // true — 0 is falsy$d.1.coachName || 'TBC'What the graphic receives
Section titled “What the graphic receives”The value your expression returns is not always the value the graphic sees.
Rive graphics
Section titled “Rive graphics”Every binding coerces the value to the type of its view model property. This is why a missing
number still shows 0 on a number property, even though the expression returned ''.
| Property type | Coercion |
|---|---|
string | String(value) |
number | Number(value), and 0 when that is not a number |
boolean | Truthy, except '', '0', 'false' and 0, which are all false |
color | A #rgb, #rrggbb or #rrggbbaa string, or a finite number read as ARGB (0xFFFF0000 is opaque red). Any other value, such as '' or 'red', is ignored and the graphic keeps its current color |
image | A URL string |
An expression that throws never reaches the binding. The binding falls back to the default for its type.
Code graphics
Section titled “Code graphics”A code graphic has no bindings, so nothing coerces the value. Each result arrives in
userExpressionValues exactly as the expression returned it, including '' for a missing number.
Handle the type in your own code.
const agg = Number(values.aggregateScore) || 0An expression that throws, or one in a dependency cycle, arrives as null.
Errors
Section titled “Errors”The overlay logs every expression error. Test each expression against a rehearsal scenario before
you publish: GET /v2/scenarios/{sport} returns sample sportData for the sport.
Run it against a scenario with missing data as well as a full one. Most expression bugs only appear when a field is absent.
Examples
Section titled “Examples”$d.1.abbreviation + ' ' + $d.1.score + ' - ' + $d.2.score + ' ' + $d.2.abbreviation$d.1.scorers?.[index] ? true : falsevar event = $d.1.scorers?.[0]?.scoreEvents?.[0]var marker = event?._fact === 'OWN_GOAL' ? ' (OG)' : event?.isPenaltyGoal ? ' (P)' : ''event ? event.minute + "'" + marker : ''var cards = $d.1.redCards + $d.2.redCardscards === 0 ? '' : cards === 1 ? '1 red card' : cards + ' red cards'$d.1.aggregateScore == null ? '' : '(' + $d.1.aggregateScore + ')'($d.1.squad || []).length