Skip to content

Replay Expressions ​

This reference covers the native video player and the counters and custom events on the video analysis page. It does not apply to third-party players. All three use expr-eval syntax, but their fields and result requirements differ.

Three Contexts ​

FeatureVideo playerAnalyzer counterAnalyzer custom event
LocationCustom counter in the native player dialogNumeric counter on the analysis page; data tracks reference its resultsCustom event rows on the analysis page
InputReplay getters at the current playback positionNative event snapshots and static replay dataThe same fields as analyzer counters
Final resultConverted to text; numbers and strings can be concatenatedMust be a single number; NaN and positive/negative infinity are allowedMust be a boolean, number or string
EvaluationWhen playback position updatesAt samples selected by each row's sampling modeContinuous sampling: the last native event in each millisecond
Between samplesDoes not use analyzer sample interpolationLinear interpolation over time; outside the sample range, holds the nearest endpointUses sampled occurrence states, not interpolated truth values
Display formatroundTo, string concatenation, etc. inside the expressionSeparate d3-format format input, default .3fColor and marker/line styles; no numeric format
ErrorsDisplays the error textDisplays the error in the value cellParse/evaluation errors or invalid result types mean the event does not occur
Difference function dNot supportedSupported; predecessors follow the row's sampling modeSupported; predecessors follow continuous sampling

Custom events use native JavaScript truthiness: true, nonzero numbers and nonempty strings mean occurrence; false, 0, -0, NaN and empty strings mean no occurrence. Positive/negative infinity mean occurrence. "false", "0" and whitespace-only strings also mean occurrence. Other types, including arrays and functions, mean no occurrence.

Continuous sampling includes all native event types and samples every millisecond. It uses the last event in that millisecond, or all fields of the latest preceding native event when there is no event, including time. The sample timestamp advances, but time keeps the source event's original time. Counter button/board-change modes filter eligible events first, then keep the last eligible event in each millisecond without filling gaps. Counter row sampling settings do not affect custom events.

The timeline and board use the same event hover details: pulses show their time and the numeric or string expression result, omitting boolean values; sustained events show their full start time, end time and duration, even when the visible range clips them. Times are displayed in seconds with three decimal places.

The custom-event “Board marker size” setting affects only the board layer. Timeline markers stay at 8px and retain the event shape, color and opacity.

New configurations enable the board custom-event layer with pluck selected. Hover over a pulse marker to see its time and value (omitting booleans), or over a sustained-event trace to see its full start time, end time and duration, even when only part of the trace is shown. Saved layer settings are preserved.

Supported Fields ​

“Yes” means the name is available directly as an expression variable; “—” means it is not. Names are case-sensitive. Analyzer dynamic values come from sampled events; static values describe the entire replay. The player reads its current getters without substituting 0. Names outside these tables, including currentMs, current_time, timeMs and bvs, are not supported. Counter row keys and event keys are not variables in other expressions.

Static Board and Replay Fields ​

FieldMeaning and unitVideo playerAnalyzer counterCustom event
rowBoard row countYesYesYes
columnBoard column countYesYesYes
mine_numTotal mine countYesYesYes
pix_sizeOriginal replay cell size in pixels, not the displayed sizeYesYesYes
bbbv3BV of the entire boardYesYesYes
opOpening count of the entire boardYesYesYes
islIsland count of the entire boardYesYesYes
cell0Number of zero (blank) cells on the entire boardYesYesYes
cell1Number of cells showing 1 on the entire boardYesYesYes
cell2Number of cells showing 2 on the entire boardYesYesYes
cell3Number of cells showing 3 on the entire boardYesYesYes
cell4Number of cells showing 4 on the entire boardYesYesYes
cell5Number of cells showing 5 on the entire boardYesYesYes
cell6Number of cells showing 6 on the entire boardYesYesYes
cell7Number of cells showing 7 on the entire boardYesYesYes
cell8Number of cells showing 8 on the entire boardYesYesYes
ziniFlagging operation count estimated by a greedy algorithm (ZiNi)YesYesYes
hziniOperation count after opening all openings first, then applying the greedy algorithm (Human ZiNi)YesYesYes
rtimeTotal replay duration in seconds, not current playback progressYesYesYes
levelReplay difficulty level codeYesYesYes
modeReplay game mode codeYesYesYes

cell0 through cell8 are nine separate variables. cell0-8 is not a variable name.

Dynamic and Player-Only Fields ​

FieldMeaning and unitVideo playerAnalyzer counterCustom event
timeOriginal sampled event time in seconds; may be negative before the game timer starts and differs from page playback progress—YesYes
pathCumulative mouse path length, retaining the library's value regardless of displayed cell sizeYesYesYes
bbbv_solved3BV solved so farYesYesYes
leftCumulative left clicksYesYesYes
rightCumulative right clicksYesYesYes
doubleCumulative double clicksYesYesYes
lceCumulative effective left clicksYesYesYes
rceCumulative effective right clicksYesYesYes
dceCumulative effective double clicksYesYesYes
flagFlag countYesYesYes
op_solvedOpenings opened so far—YesYes
isl_solvedIslands solved so far—YesYes
mouse_stateMouse state code; analyzer samples use the state after the native eventYesYesYes
bbbv_s3BV per secondYes——
ceTotal effective clicksYes——
ce_sEffective clicks per secondYes——
clTotal clicksYes——
cl_sClicks per secondYes——
left_sLeft clicks per secondYes——
right_sRight clicks per secondYes——
double_sDouble clicks per secondYes——
flag_sFlagging rateYes——
etimeEstimated completion time in secondsYes——
rtime_msTotal replay duration in millisecondsYes——
rqpRQP speed metricYes——
stnbSTNB completion and speed metricYes——
corrOperation accuracy metricYes——
thrpThroughput efficiency metricYes——
ioeIndex of efficiencyYes——
pluckCumulative Pluck metricYesYesYes
current_event_idCurrent native event array index, not a time valueYes——
game_board_stateGame board state codeYes——
video_start_timeReplay start time offset in secondsYes——
video_end_timeReplay end time coordinate in secondsYes——

The analyzer does not expose bbbv_s, cl or ce directly. You can combine supported fields, for example bbbv_solved / time, left + right + double or lce + rce + dce. Such formulas are not guaranteed to match player getter algorithms in every special state.

The Analyzer computes per-event pluck when loading a replay. Raw values are preserved: unavailable values may be NaN, and the mine-hit failure value is Number.MAX_VALUE, without replacement by zero or infinity.

mouse_state Codes ​

ValueStateMeaning
1UpUpBoth left and right buttons released
2UpDownLeft released, right pressed
3UpDownNotFlagLeft released, right pressed without placing or removing a flag
4DownUpLeft pressed, right released
5ChordingBoth buttons pressed
6ChordingNotFlagBoth pressed after pressing the right button first on a cell that cannot be right-clicked
7DownUpAfterChordingRight released first after chording, left still pressed
8UndefinedUninitialized state

Names such as DownUp are not expression constants. Use their numeric codes, for example mouse_state == 4.

Operators and Syntax ​

All three contexts support the following operations, but a counter's final result must still be numeric. Arrays, strings and booleans may be intermediate results. The table roughly follows precedence from highest to lowest; use parentheses when unsure.

Operator or syntaxMeaning and exampleVideo playerAnalyzer counterCustom event
(...)Grouping, e.g. (left + right) / timeYesYesYes
f(...), a[i], x.yFunction call, zero-based indexing and property access, e.g. [left, right][0] or [left, right].length; does not bypass the variable whitelistYesYesYes
[a, b, ...], "text", 'text'Array and string literalsYesYesYes
x!Postfix factorial: 5! is 120, not logical NOTYesYesYes
x ^ yExponentiation: 2 ^ 3 is 8, not XORYesYesYes
+x, -x, not xNumeric conversion, negation and logical NOT; unary math functions are listed belowYesYesYes
*, /, %Multiplication, division and remainderYesYesYes
+, -Numeric addition and subtraction; + is not string concatenationYesYesYes
x || yString concatenation, or array concatenation when both operands are arrays; not logical ORYesYesYes
==, !=, <, <=, >, >=Comparisons, e.g. left > rightYesYesYes
x in aArray membership, e.g. mouse_state in [4, 5, 7]YesYesYes
x and yLogical AND; skips the right operand if the left is falseYesYesYes
x or yLogical OR; skips the right operand if the left is trueYesYesYes
c ? a : bConditional expression; only evaluates the selected branch; nesting allowedYesYesYes
a; bEvaluates in sequence and returns the last result; not a variable declarationYesYesYes
x = valueAssignmentNoNoNo
f(x) = exprFunction definitionNoNoNo
if (...) { ... }, &&, !x, **, ===, =>JavaScript statements/operators or arrow functions; not this expression grammarNoNoNo

Use the keywords and, or and not. Logical results are booleans; use condition ? 1 : 0 for a numeric counter result. Scientific notation such as 1e-3 is supported. Prefer parentheses around unary function arguments, e.g. sin(time)^2, to avoid precedence ambiguity.

Constants ​

Constant or expressionMeaningAll three contexts
PIPiSupported
EEuler's numberSupported
true, falseBooleansSupported, but not valid final counter results
0 / 0Produces NaNSupported; retained as a counter number, false for custom events
1 / 0, -1 / 0Produces positive/negative infinitySupported; retained as counter numbers, true for custom events
NaN, Infinity, Inf, null, undefinedThese names are not built-in constantsNot supported

Functions ​

These built-in functions and function-form unary operators are supported in all three contexts. x, a and f are argument placeholders, not extra replay fields. Angles are in radians.

FunctionMeaning and exampleVideo playerAnalyzer counterCustom event
abs(x)Absolute value, e.g. abs(-3)YesYesYes
sign(x)Sign; negative/zero/positive numbers normally produce -1/0/1YesYesYes
ceil(x)Round upYesYesYes
floor(x)Round downYesYesYes
round(x)Round to the nearest integer using JavaScript rounding rulesYesYesYes
trunc(x)Remove the fractional part towards zeroYesYesYes
roundTo(x, n)Round to n decimal places, e.g. roundTo(time, 3); negative n rounds to tens, hundreds, etc.; does not pad trailing zerosYesYesYes
min(a, b, ...)Minimum; also accepts an array, e.g. min([left, right])YesYesYes
max(a, b, ...)Maximum; also accepts an array, e.g. max([left, right])YesYesYes
sqrt(x)Square rootYesYesYes
cbrt(x)Cube rootYesYesYes
pow(x, y)Exponentiation, equivalent to x ^ yYesYesYes
hypot(a, b, ...)Square root of the sum of squared argumentsYesYesYes
pyt(a, b, ...)Alias for hypotYesYesYes
exp(x)E ^ xYesYesYes
expm1(x)exp(x) - 1YesYesYes
ln(x)Natural logarithmYesYesYes
log(x)Alias for ln; not base 10YesYesYes
log2(x)Base-2 logarithmYesYesYes
log10(x)Base-10 logarithmYesYesYes
lg(x)Alias for log10YesYesYes
log1p(x)ln(1 + x)YesYesYes
sin(x)SineYesYesYes
cos(x)CosineYesYesYes
tan(x)TangentYesYesYes
asin(x)Inverse sineYesYesYes
acos(x)Inverse cosineYesYesYes
atan(x)Inverse tangentYesYesYes
atan2(y, x)Direction angle of vector (x, y); y comes firstYesYesYes
sinh(x)Hyperbolic sineYesYesYes
cosh(x)Hyperbolic cosineYesYesYes
tanh(x)Hyperbolic tangentYesYesYes
asinh(x)Inverse hyperbolic sineYesYesYes
acosh(x)Inverse hyperbolic cosineYesYesYes
atanh(x)Inverse hyperbolic tangentYesYesYes
gamma(x)Gamma function; for positive integer n, gamma(n) = (n - 1)!YesYesYes
fac(x)Factorial, corresponding to x!; non-integers use the Gamma extensionYesYesYes
random(n)Random number in [0, n); uses 1 if n is omitted or zero; unsuitable for reproducible analysisYesYesYes
length(x)String or array lengthYesYesYes
indexOf(x, a)First zero-based index of x in string or array a; -1 if absentYesYesYes
join(sep, a)Join array elements into a string using separator sepYesYesYes
map(f, a)Apply a function to array elements and return an array, e.g. map(abs, [-1, 2])YesYesYes
filter(f, a)Keep elements whose function result is truthy; returns an array, e.g. filter(abs, [-1, 0, 2])YesYesYes
fold(f, initial, a)Reduce an array to one value, e.g. fold(pow, 2, [3, 2]) produces 64YesYesYes
if(c, a, b)Select a or b based on c, but evaluates both arguments first; use c ? a : b for short-circuitingYesYesYes
not(x)Logical NOT, also written not x; returns a booleanYesYesYes
d(expr)Numeric expression at the current sample minus its value at the preceding sample—YesYes
d(expr, n)Subtract the value n samples earlier; n must be a positive integer—YesYes

Function arguments to map, filter and fold may use compatible built-ins, not JavaScript arrow functions or new function definitions. There are no general String, Number, isNaN, isFinite or Math.* functions. Use unary + for numeric conversion, "" || value for text concatenation and value != value to test for NaN, replacing value with an actual field or expression. d requires a direct call and cannot be used as an array-function callback.

Difference Rules ​

RuleExplanation
OperandA field or numeric expression, e.g. d(left), d(left + right) or d(bbbv_solved) / d(time)
Default stepd(expr) equals d(expr, 1); counts retained samples, not milliseconds or native event count
Step expressionn is evaluated at the current sample, e.g. d(left, time > 1 ? 2 : 1); nonpositive/noninteger steps are errors
Missing predecessorsReturns NaN; counters retain it, custom events treat it as no occurrence
Nestingd(d(left)) and d(d(left, 2), 3) work; their first two and five samples respectively are NaN
No automatic normalizationDoes not divide by the step or elapsed time; explicitly divide by d(time) for a rate
Evaluation orderFilter and deduplicate millisecond samples, then evaluate differences; counter interpolation and formatting happen afterwards
Conditional branchesSkipping a difference call does not change which sample is the predecessor

Default Counters ​

On first use, the counters use continuous sampling and the .3f display format:

keyExpressionDefault Plot
Bvsd(bbbv_solved, 1000) / d(time, 1000)Plot 1
Cesd(lce+rce+dce, 1000)/d(time, 1000)Plot 1
Movd(path, 1000) / d(time, 1000) / 16Plot 2

Here, 1000 counts continuous millisecond samples; the denominator uses the difference in the original event's time. The first 1000 samples are NaN, and a zero time difference can also produce non-finite values. The lowercase bvs is no longer a default counter. Saved counter and Plot configurations are preserved.

Default Custom Events ​

On first use, the following events are included:

keyTypeExpression
leftSustainedmouse_state in [4, 5, 6, 7]
rightSustainedmouse_state in [2, 3, 5, 6]
pluckPulsed(pluck)

The pluck pulse occurs when the cumulative value changes from the previous millisecond. An unchanged value or a NaN difference produces no pulse. Existing saved custom events are preserved.

Examples ​

ContextExpressionResult
Video playerroundTo(bbbv_s, 3) || "@" || bbbv_solved || "/" || bbbvCombine rate, solved BV and total BV as text
Analyzer countertime > 0 ? bbbv_solved / time : 0Cumulative 3BV/s; the separate format can be .3f
Analyzer counterd(bbbv_solved) / d(time)3BV/s between samples; first sample is NaN
Pulse custom eventd(left) > 0A pulse when cumulative left clicks increase
Sustained custom eventmouse_state in [4, 5, 6, 7]Continuous segments where the left button is pressed
Custom eventmouse_state == 4 and d(left) > 0Require both a mouse state and a click increase

Syntax reference: expr-eval. Separate counter display formatting: d3-format; format is not an expression function.