Skip to content

Output Format

Output Files

The generator produces brotli-compressed JSONL files in the output directory, plus an optional plain JSON config:

output/
  ├─ entries.jsonl.br        (entry metadata — brotli-compressed JSONL)
  ├─ scenarios.jsonl.br      (scenario data — brotli-compressed JSONL)
  └─ config.json             (game configuration — plain JSON, via end() config option)

All features (basegame, freespin, bonus, etc.) — including buy-feature pools — are written to the same entries.jsonl. Each entry line includes a feature field to identify which feature it belongs to.

JSONL files are automatically compressed to .br (brotli, quality 9) and raw .jsonl files are removed. config.json is written as plain JSON (not compressed).

Entry Format

Each line in entries.jsonl is a JSON object:

json
{"feature":"basegame","id":0,"weight":612483,"cumulativeWeight":612483,"win":0,"metaTags":["no-win"],"scenarioCount":1000}
{"feature":"basegame","id":1,"weight":23891,"cumulativeWeight":636374,"win":50,"metaTags":["big-win"],"scenarioCount":1000}
{"feature":"basegame","id":2,"weight":500,"cumulativeWeight":636874,"win":0,"metaTags":["freespin-trigger"],"featureAwards":{"type":"randomChoice","awards":[{"count":10,"feature":"freespin"}]},"progressionAwards":{"scatter-collection":0.01},"scenarioCount":500}
{"feature":"freespin","id":3,"weight":80000,"cumulativeWeight":80000,"win":5,"metaTags":["small-win"],"scenarioCount":1000}

Each entry includes a cumulativeWeight — the running total of weights within that feature, used by the engine for efficient weighted selection. Optional fields (metaTags, featureAwards, progressionAwards) are omitted when not present — no null values are written.

Scenario Format

Each line in scenarios.jsonl is a JSON object:

json
{"entryId":0,"scenarioIndex":0,"scenario":[{"reels":[[2,3,1],[2,2,2],[4,0,5]],"winLines":0}]}
{"entryId":1,"scenarioIndex":0,"scenario":[{"reels":[[5,5,5],[2,3,1],[4,0,5]],"winLines":3}]}

The scenario field is an array of game state records (single-element for normal spins, multiple for multi-result features like sticky symbols).

Config Format

The optional config.json file contains game configuration consumed by the hizi engine at import time:

json
{
  "gameCode": "my-slot",
  "gameType": "slot",
  "rtp": 95.97,
  "featureWeights": { "basegame": 636874, "freespin": 80000 },
  "stakes": [0.20, 0.40, 1.00, 2.00, 5.00],
  "features": ["freespin"],
  "wagerFeatures": ["color-red", "color-black"],
  "progressionCounters": [
    { "name": "scatter-collection", "onComplete": { "type": "randomChoice", "awards": [{ "count": 10, "feature": "freespin" }] }, "stakeSpecific": false }
  ]
}

Write it by passing config to end(). The featureWeights field is auto-populated from featureTotalWeights if not already set.

Buy-Features Format

Buy-feature pools are materialised into entries.jsonl as synthetic features named bf_<sanitized-id> — there is no separate buyfeatures.jsonl. Each pool entry is an ordinary entry line carrying the pool's feature name and its selection weight:

json
{"feature":"bf_buy_freespin","id":3,"weight":500,"cumulativeWeight":500,"win":5,"metaTags":["small-win"],"scenarioCount":1000}
{"feature":"bf_buy_freespin","id":4,"weight":300,"cumulativeWeight":800,"win":8,"metaTags":["small-win"],"scenarioCount":1000}

Pool entries reuse their source entry's id, so they share scenarios (scenarios key on entryId, not feature) — only the weight rows are added, never scenario data. The engine selects from a pool by filtering entries on the bf_<id> feature and weight-picking via cumulativeWeight, bounded by featureWeights[bf_<id>]. Write pools by passing buyFeatures / buyFeatureDefinitions to end(); see Buy-Features.

Why JSONL?

  • Streaming — Scenarios stream directly to disk as they're generated. No memory accumulation, supporting billions of results.
  • Cross-platform — Works in Node.js and browsers. No native binary dependencies.
  • Compressible — Brotli compression (quality 9) typically achieves 90%+ compression for efficient distribution.

INFO

Actual file sizes depend on the complexity of your scenario data and meta tag frequency. Simpler scenarios produce smaller files.

Reading Output Files

TypeScript (Node.js)

typescript
import { readFileSync } from 'fs';
import { brotliDecompressSync } from 'zlib';
import { HiziEngineGenerator } from '@hizi.io/engine-generator';

const entriesJsonl = brotliDecompressSync(readFileSync('./output/entries.jsonl.br')).toString();
const scenariosJsonl = brotliDecompressSync(readFileSync('./output/scenarios.jsonl.br')).toString();

// Load all basegame entries with scenarios
const entries = HiziEngineGenerator.loadEntries(entriesJsonl, scenariosJsonl, 'basegame');

Command Line

bash
# View entries
brotli -d output/entries.jsonl.br --stdout | jq -c . | head -5

# View config (plain JSON, no decompression needed)
cat output/config.json | jq .