This document locks the authored interface for computed variables.
Computed variables are read-only derived values exposed through the same
variables.* template namespace as stored variables. They are recalculated from
current engine state and are not persisted as mutable state.
- Let authors define derived values such as labels, percentages, flags, and UI objects.
- Reuse the existing conditional-action
whencondition model. - Keep literal objects easy to write.
- Avoid arbitrary custom functions.
- Keep save/load, scoped persistence, and rollback state free of derived values.
A variable with a computed property is computed:
resources:
variables:
hp:
type: number
scope: context
default: 80
maxHp:
type: number
scope: context
default: 100
hpPercent:
type: number
scope: context
computed:
expr:
round:
- mul:
- div:
- var: variables.hp
- var: variables.maxHp
- 100Presence of computed implies read-only behavior. readonly is not required
for computed variables.
Computed variables must still declare type and scope:
typeis the expected output type.scopedescribes the variable's authored namespace. It does not make the computed value persistent.
Computed variables must not declare a top-level default. Use
computed.default only as the fallback for computed branches.
A simple computed variable uses exactly one of computed.expr or
computed.value.
Use expr for evaluated expressions:
hpRatio:
type: number
scope: context
computed:
expr:
div:
- var: variables.hp
- var: variables.maxHpUse value for literal data:
mainMenuBadge:
type: object
scope: context
computed:
value:
text: Main Menu
colorId: whitevalue may be any literal YAML value, including objects and arrays.
Conditional computed variables use ordered branches plus an explicit
default.
hpState:
type: string
scope: context
computed:
branches:
- when:
lte:
- var: variables.hp
- 0
expr: down
- when:
lte:
- var: variables.hp
- 25
expr: critical
default:
expr: healthyBranch rules:
- Branches are evaluated in order.
- The first branch whose
whencondition passes wins. - Every branch must have
when. - Every branch must have exactly one of
exprorvalue. - Branches without
whenare invalid. Fallback belongs indefault.
Default rules:
defaultis required whenbranchesexists.defaultmust have exactly one ofexprorvalue.defaultuses the same result shape as branches.
Literal object fallback example:
hpBadge:
type: object
scope: context
computed:
branches:
- when:
lte:
- var: variables.hp
- 0
value:
text: Down
colorId: gray
- when:
lte:
- var: variables.hp
- 25
value:
text: Critical
colorId: red
default:
value:
text: OK
colorId: greenExpression fallback example:
hpPercent:
type: number
scope: context
computed:
branches:
- when:
lte:
- var: variables.maxHp
- 0
expr: 0
default:
expr:
round:
- mul:
- div:
- var: variables.hp
- var: variables.maxHp
- 100when uses the same condition model as conditional actions.
when:
gte:
- var: variables.trust
- 70String expression conditions are not supported.
Conditions evaluate against:
variablesruntime
when uses the conditional-action condition grammar, not the computed expr
operator grammar. Put arithmetic or object derivation in expr, or reference a
separate computed variable from when.
Computed variable conditions do not receive event context. _event.* bindings
are not available.
expr is an evaluated expression. It may be:
- a primitive literal: string, number, boolean, or null
- a variable reference
- one of the fixed expression operators
Primitive literals:
expr: 0
expr: true
expr: healthy
expr: nullVariable reference:
expr:
var: variables.hpExpressions may read:
variables.*runtime.*
Objects and arrays should be authored with value, not expr, unless the
object is an expression operator.
Computed expressions use a fixed operator set. Arbitrary function calls and custom functions are not part of this interface.
Arithmetic:
add: [a, b]
sub: [a, b]
mul: [a, b]
div: [a, b]
mod: [a, b]
neg: [value]Numeric helpers:
round: [value]
floor: [value]
ceil: [value]
min: [a, b]
max: [a, b]
clamp: [value, min, max]Comparisons:
eq: [a, b]
neq: [a, b]
gt: [a, b]
gte: [a, b]
lt: [a, b]
lte: [a, b]Logical operators:
and: [a, b]
or: [a, b]
not: [value]Collection helpers:
length: [value]
includes: [collection, value]Each operator object must contain exactly one operator key.
Computed variables are projected into variables whenever the engine builds
template data, render state, or action condition context.
They must be visible anywhere stored variables are visible:
content: "HP: ${variables.hpPercent}%"when:
eq:
- var: variables.hpState
- criticalComputed values are not stored in:
state.global.variablescontext.variables- save slots
- scoped data persistence updates
- rollback recorded actions
updateVariable must reject attempts to update a computed variable.
Hosts can evaluate the same computed-variable interface outside an engine
instance with resolveComputedVariables.
import { resolveComputedVariables } from "rvn-temp";
const variables = resolveComputedVariables({
projectData,
variables: {
hp: 40,
maxHp: 100,
},
runtime: {
muteAll: false,
},
});The helper accepts either full projectData or a variableConfigs object:
resolveComputedVariables({
variableConfigs: projectData.resources.variables,
variables,
runtime,
});The returned object contains stored variables plus resolved computed variables.
Computed keys in the input variables object are ignored and recomputed from
their declarations.
After evaluation, the computed result must match the variable type.
Expected output types:
number: finite JavaScript numberboolean: booleanstring: stringobject: non-null object or array
Type mismatches fail fast.
Computed variables may reference stored variables and other computed variables
through variables.*.
Authoring order should not affect correctness. Implementations should evaluate computed variables as a dependency graph and fail fast for cycles.
Invalid cycle example:
a:
type: number
scope: context
computed:
expr:
add:
- var: variables.b
- 1
b:
type: number
scope: context
computed:
expr:
add:
- var: variables.a
- 1computedimplies read-only behavior.- Computed variables must declare
typeandscope. - Computed variables must not declare top-level
default. computedmust contain either:- exactly one of
exprorvalue branchesplusdefault
- exactly one of
computed.exprandcomputed.valueare mutually exclusive.- Each branch must have
when. - Each branch must have exactly one of
exprorvalue. - Branches without
whenare invalid. computed.defaultis required whenbranchesexists.computed.defaultmust have exactly one ofexprorvalue.exprobject values must contain exactly one supported operator.- Arbitrary function calls are not supported.
- Evaluation output must match
type. - Cycles between computed variables are invalid.