Skip to content

Launch and loading screens

The remote gaming server (RGS) supplies the launch and session data. The frontend owns the loading screens and input controls.

Launch contract

Read login and token from the query string with URLSearchParams. Preserve other launch parameters for the operator adapter. Do not decode a parameter twice.

ValueSourceUse
Login URL and launch tokenQuery parameters login, tokenExchange once. A launch token can be single-use.
Session tokenConnect reply tokenSend with each engine request. Keep it in memory.
API addressSDK backendURL; raw reply backendUrlSend SDK operations to this address. Do not construct endpoint paths.
Refresh and logout addressesSDK refreshURL, logoutURLRetain the complete URLs, including their query strings.
Socket addressSDK webSocketURLOptional for slots. See transport.
SettingsgameSettingsApply before enabling any control. Reapply after refresh.
Game and playertokenData.gameId, tokenData.playerId, tokenData.operatorIdUse for Operator Interface setup.
Language, currency, modetokenData.language, tokenData.currency, tokenData.modeSelect translations and display units. The mode is REAL or DEMO. Do not infer real mode from the balance.
Currency factortokenData.currencyMultiplierReturned stakes are already in account units. Do not multiply them again. See stakes and money.
Open roundtokenData.gameRoundA hash here means an unfinished round. Restore it before play.
Operator protocoloperatorProtocolUse the negotiated protocol. Do not select one from the hostname.
Reality-check offsetRaw gameVariables.rcElapsedTime already elapsed towards the next reminder. See jurisdictions for the unit.
Operator dataTop-level passThroughData on the connect replyRoute through the integration for that operator.

Use the platform launch flow from Studio Quickstart. A page opened without launch parameters needs a launch instruction. It must not place a real bet.

Connect with login()

Use SDK login(). It is the supported connect call. Do not write your own replacement for it.

login() and refresh() return tokenData, and tokenData carries the session identity: playerId, operatorId, gameId, language, currency, currencyMultiplier, mode, and any open gameRound. The typed name of the game mode is mode, not gameMode. ITokenData is an open record ([key: string]: unknown), so the SDK also passes through any extra field your operator puts in tokenData.

Use the SDK error helper to retain operator error data.

ts
// Read the launch parameters the operator puts on your frontend URL, in the shape
// SDK login() takes: { loginURL, launchToken }. login() builds the request itself.
//
// There is deliberately no replacement for login() here. login() is the supported
// connect call. Re-implementing it to recover a dropped field risks exchanging a
// single-use launch token twice, and drifts from the SDK on every release.
export function launchParams(search: string): { loginURL: string; launchToken: string } {
  const params = new URLSearchParams(search);
  const loginURL = params.get('login');
  const launchToken = params.get('token');
  if (!loginURL || !launchToken) throw new Error('Launch URL requires login and token');
  return { loginURL, launchToken };
}
typescript
import { loadConfig, login } from '@hizi.io/engine-sdk';
import { launchParams } from './launch';
import { SdkRequestError } from './sdk-error';

const connected = await login(launchParams(location.search));
if (!connected.success) throw new SdkRequestError(connected.error);
const connection = connected.result;

const session = { backendURL: connection.backendURL, token: connection.token };
const loaded = await loadConfig(session);
if (!loaded.success) throw new SdkRequestError(loaded.error);
// Read the player, game, language and currency from connection.tokenData.
// Restore loaded.result before enabling the first paid spin.

A launch token can be single-use. Exchange it once. Do not call login() twice, and do not add a second connect path beside it.

What login() does not return

parseConnectReply() copies eleven top-level keys: token, backendURL, refreshURL, logoutURL, webSocketURL, balance, gameSettings, tokenData, freePlaysAvailable, featuresAvailable, and operatorProtocol. It discards every other field of the raw connect reply.

Most of what it drops you get again on the next call. Only login() and refresh() use this narrowing step. Every other SDK operation returns the raw reply unchanged, so loadConfig gives you gameRoundInfo, amountToCollect and the resumed round state straight after connecting. An error reply keeps passThroughData.

Two fields do not come back:

FieldConsequence
gameVariables.rcElapsedThe elapsed time towards the next reality check. Without it a relaunch restarts the reminder interval at zero.
freePlayInfoThe singular package-progress block (used, granted, won, isLast, serial). The plural freePlaysAvailable survives; this one does not.

Do not fork login() to recover them. A second exchange of a single-use launch token is a real failure, and a hand-written copy of parseConnectReply() drifts from the SDK on every release. The cost of that workaround is higher than the two fields are worth.

Handle them as integration requirements instead:

  • Where the operator contract gives the wrapper the reality check, the wrapper owns the elapsed time. Send realityCheck(...) through the Operator Interface and do not track the offset yourself.
  • Where the game owns the reminder, ask hizi.io support to carry rcElapsed in tokenData, which login() does return. Record the gap in your integration notes until it is carried. See jurisdictions.
  • For freeplay progress, drive the ticket picker from freePlaysAvailable. The RGS puts freePlayInfo on every gameround reply once freeplays are active, and placeBet is not narrowed, so the block reaches you there. IPlaceBetReply does not declare it, so read it as an extra field and validate it yourself.

Catch fetch failures and invalid JSON at the application boundary. Keep play disabled. Follow error handling.

Do not log the launch URL, session token, or complete connection object. Restrict allowed launch hosts in your deployment configuration. Remove consumed credentials from visible history only after the wrapper has read its launch parameters.

Loading sequence

  1. Display a loading screen immediately. Disable all inputs that can place a bet.
  2. Read saved preferences. Apply the operator's storage restrictions.
  3. Exchange the launch token. Preserve metadata that your operator needs.
  4. Register Operator Interface listeners. Await OperatorInterface.setup.
  5. Call OperatorInterface.loadProgress(0).
  6. Fetch loadConfig. Validate its game type, settings, currency, and available stakes.
  7. Load the required fonts, translations, symbol textures, rules, and sounds. Report progress from 0 to 1.
  8. Call gameDataLoaded() after configuration and required game data are ready.
  9. Restore any interrupted round. Display its last board or pending player choice.
  10. Keep loadMsg visible for at least minLoadTime milliseconds after the message appears.
  11. Show the paytable when displayPaytableOnEnterGame is true. Require acknowledgement before play.
  12. Call loadProgress(1) and loadComplete() when loading ends.
  13. Send initialGameState(muted). Send the current stake and balance.
  14. Call gameReady() when the player can interact with the restored game.

gameReady() does not mean a new paid spin is available. A restored game can require collection or a bonus choice.

Use gameUIUpdated(buyMenuOpen, splashVisible, waitingForConfirmation) when those states change. Keep a splash acknowledgement separate from a spin request.

loadingScreens and messages

The engine SDK defines no loadingScreens API or response field. Implement the loading screens in your frontend. The standard settings are loadMsg and minLoadTime.

Treat loadMsg as text. Use textContent or your framework's escaped text binding. Do not insert it as HTML. Use an approved translation when the operator supplies a message identifier instead of prose.

Keep essential instructions readable on narrow screens. Do not cover a required message with progress animations. If an asset fails, show a clear error with recovery or exit controls. Do not report successful loading.

The RGS does not supply a complete set of translated jurisdiction messages. Include approved messages in your game assets. See jurisdiction messages.

Audio, background tabs, and mobile

Start the browser audio context from a player gesture. A successful unmute request can still require that gesture. Keep the audio icon consistent with the effective state.

Track three independent conditions: the player's mute preference, an operator mute request, and suspension while hidden or paused. Play audio only when all conditions permit it. An operator resume must not override the player's mute preference.

Handle mute, unmute, and toggle requests through one audio controller. Report actual changes with muted() or unmuted(). Stop sounds, music, and queued win sounds when muted.

On visibilitychange, suspend presentation and new input. A hidden tab does not stop server time or a Crash round. Reconcile state before continuing after disconnection.

Apply orientation and fullscreen restrictions before presenting controls. Support resize, safe areas, keyboard focus, and touch. Never stretch a fixed board into inaccessible buttons. See settings.