Appearance
Scenario Compression
Scenarios (see Core Concepts) are the per-spin snapshots of game state. The engine returns them to your game client. For rich games, especially slots, scenarios are large and highly repetitive. The hizi pipeline stores and sends them in a minified form. It expands them back to the full shape on the client.
This process is transparent. With one line of setup, your game client sees exactly the same scenario objects it always has. This page explains what changes on the wire and how to opt in.
Why
- Smaller payloads: less bandwidth for each
placeBetcall. Smaller items in storage. - Harder to read: a third party who watches network traffic cannot easily read a minified scenario.
What "minified" means
The hizi pipeline applies two transforms to each scenario:
- Short keys: the pipeline turns verbose keys into short codes (
board→b,winAmount→wa,winMultiplier→wm, …). - Integer symbols: the pipeline turns symbol and enum string values into integers (
"wild"→6,"winline"→0, …).
A slot board step looks like this on the wire:
jsonc
// full (what your client sees after decoding)
{ "board": [["low1", "wild", "scatter"], ["low2", "low1", "wild"]],
"winAmount": 7,
"wins": [{ "mode": "winline", "positions": [{ "column": 0, "row": 1 }], "winMultiplier": 5 }] }
// minified (what travels on the wire)
{ "b": [[0, 6, 7], [1, 0, 6]],
"wa": 7,
"w": [{ "m": 0, "p": [{ "c": 0, "r": 1 }], "wm": 5 }] }The game's config publishes the integer-to-symbol-name mapping as symbolMap. A scenarioSchema marker flags the game as using minification. Both arrive in the loadConfig response:
typescript
const cfg = await loadConfig({ backendURL, token });
// cfg.result.config.scenarioSchema -> e.g. 1 (present only for minified games)
// cfg.result.config.symbolMap -> { "0": "low1", "1": "low2", "6": "wild", "7": "scatter", ... }How it flows
Creator ── builds game-data.zip with scenarios stored minified
│
Engine ── stores minified, sends minified on the wire (placeBet / loadConfig / pfVerify)
│ (expands internally where it needs to: game-history rendering, RTP simulation,
│ and games whose logic reads the scenario, e.g. mines/keno)
▼
SDK ── decodes back to full string-symbol scenarios for your clientDecoding in the SDK
The easiest path: pass the config you got from loadConfig into placeBet (and pfVerify). The SDK decodes the returned scenario for you before resolving.
typescript
const cfg = await loadConfig({ backendURL, token });
const config = cfg.success ? cfg.result.config : undefined;
// placeBet decodes the scenario when you pass `config`.
const bet = await placeBet({ backendURL, token, stake, config });
if (bet.success) {
const scenario = bet.result.result.scenario; // full, string-symbol form
}loadConfig automatically decodes any scenarios embedded in its own reply (a resumed round or history in previousResults). Those scenarios are already expanded.
To decode a result you are handling yourself (for example one you stored), call decodeScenario directly:
typescript
import { decodeScenario } from '@hizi.io/engine-sdk';
decodeScenario(gameResult, config); // mutates gameResult.scenario in placeSafe by default / backward compatible
- Passing
configis always safe.decodeScenariois a no-op for games that do not minify (noscenarioSchema). It is also a no-op whenconfigis missing. You never need to branch on game type. - For games that do not minify, the API returns results unchanged. For rounds recorded before minification was enabled, the API also returns results unchanged.
- If you do not pass
config,placeBetreturns the raw (minified) reply untouched. Use this if you want to handle decoding yourself.
Notes
@hizi.io/engine-sdkdefines the scenario codec once, as the single source of truth. The engine (wire minify) and the builder (storage compression) import it. This way, the three sides can never disagree on the format. TheSCHEME_VERSIONconstant guards the scheme.- Server-rendered game history expands scenarios automatically. You do not need to do anything there.