Determinism
The same definitions, the same starting save and the same inputs (outside events and clock steps) give the same result. Inputs are recorded, so an error can be replayed. These rules hold bit for bit on the server, in the native game and in the browser; "(server)" marks what exists only on the server.
| Subject | Rule |
|---|---|
| Order | Left to right; arguments left to right. In a compound assignment the target first, then the right side. and/or short-circuit. |
int | 32-bit signed. Overflow of + - *, of unary - and of conversions is an error. |
/, % on int | / truncates toward zero; % takes the sign of the dividend (-7 % 3 == -1). Division by zero and -2147483648 / -1 are errors. mod(a, b) gives 0 … b-1 for b > 0 (mod(-7, 3) == 2); b ≤ 0 is an error. |
float | IEEE 754 binary64, round to nearest; every operation is rounded on its own and nothing is fused (no FMA; Rust does not fuse a multiplication and an addition by itself). An operation giving NaN or ±∞ is an error; -0 becomes 0. |
| Rounding | round rounds halves away from zero: round(-1.5) == -2 (JavaScript's Math.round gives -1 and is not used). floor, ceil, round and as int fail when the result does not fit; as int truncates toward zero. |
| Exact functions | abs min max clamp sqrt mod and the colour operations are bit for bit the same everywhere. In clamp(x, lo, hi), lo > hi is an error. |
| Trigonometry | sin and cos exist only on the client and use pure-Rust libm rather than the platform's library, so every target gives the same result. Opening them to the server is a decision for the next version. |
| Strings | Sequences of code points; length and slice count code points; comparison is by code point (JavaScript's UTF-16 order is not used). There is no case conversion in v1. |
as string | int in decimal. float as ECMAScript's Number::toString (the shortest round trip). bool as true/false, time as HH:MM, duration as 1h30m. A color's channels are clamped to 0–1, multiplied by 255, rounded with round and written #rrggbbaa. |
| Random numbers (server) | Every instance has its own xoshiro128** generator (32-bit operations only). Its seed is the world's seed XORed with the FNV-1a hash of the object's and the binding's ids; SplitMix64 fills the four state words. random() gives u32 / 2³² in [0, 1); random(a, b) includes both ends and is unbiased by rejection sampling; a > b is an error. The state is part of the transaction and is saved. |
| Clock (server) | There is no wall clock: now() and clock() are the world's. |
The same conformance vectors run on the native and the WebAssembly builds. When the Rust VM replaced the first prototype, the two gave the same results on 2,083 programs, including 2,000 random ones.