Skip to content

Lifecycle & bootstrapping (Web)

The SDK needs to do three things that involve your game:

  1. Pause and resume the game loop — whenever an ad is shown, the tab is backgrounded, or the channel demands it.
  2. Mute and unmute audio — same triggers, different hook, so you can cross‑fade cleanly.
  3. Show a splash screen while the game loads, branded per channel.

Lifecycle hooks cover (1) and (2); the bootstrapper covers (3).

FRVR.lifecycle.onSuspend      = () => game.pause();     // REQUIRED — freeze update loop
FRVR.lifecycle.onResume       = () => game.resume();    // REQUIRED — unfreeze
FRVR.lifecycle.onAudioSuspend = () => mixer.mute();     // REQUIRED — mute sound
FRVR.lifecycle.onAudioResume  = () => mixer.unmute();   // REQUIRED — unmute
FRVR.lifecycle.onGamePause    = () => game.showPauseMenu();  // REQUIRED — channel‑level pause

Implement every hook — even if one ends up a no‑op for your game, set it explicitly so it’s obvious you considered it. An empty () => {} is allowed; a missing hook is not.

When they fire

HookTriggered by
onSuspend / onResumeInterstitial, rewarded ads. Tab/app backgrounding.
onAudioSuspend / onAudioResumeSame triggers, but separately so you can handle audio independently (e.g. cross‑fade).
onGamePauseChannel‑level pause events (e.g. user navigates away).

Not every channel fires every hook — they’re best‑effort. Implement all five for maximum portability.

FRVR.bootstrapper.init()           // shows the channel splash
  .then(() => loadGame(p => FRVR.bootstrapper.setProgress(p)))  // 0..1
  .then(() => FRVR.bootstrapper.complete());  // hides the splash
  • init() — render the splash screen for the current channel. Resolves immediately so you can start loading.
  • setProgress(0..1) — call as many times as you want; the splash shows a progress bar where supported.
  • complete() — hide the splash and let your game take over.

If the splash is hidden without setProgress(1) first, the bootstrapper still completes cleanly — progress is advisory.

The complete startup looks like:

// 1. Load scripts in <head> (synchronous — no async/defer).
//    In local dev: frvr-sdk.min.js + frvr-channel-dev.min.js.
//    In production: FRVR injects the right channel bundle for you.

// 2. Configure (usually supplied by FRVR's generator)
FRVR.config = { gameId: 'my-game' };

// 3. REQUIRED lifecycle hooks
FRVR.lifecycle.onSuspend      = () => game.pause();
FRVR.lifecycle.onResume       = () => game.resume();
FRVR.lifecycle.onAudioSuspend = () => mixer.mute();
FRVR.lifecycle.onAudioResume  = () => mixer.unmute();
FRVR.lifecycle.onGamePause    = () => game.showPauseMenu();

// 4. Init the SDK (synchronous; returns a promise you can ignore)
FRVR.init();

// 5. Bootstrap and run
FRVR.bootstrapper.init()
  .then(loadGame)
  .then(() => FRVR.bootstrapper.complete());

Pass 'dev' to init() while developing to get noisier logging and looser defaults; omit or pass 'prod' for production. See Environments.

FRVR.init('dev');

A rule of thumb: call any module you like after FRVR.init(). Anything that needs network (IAP catalog, cloud storage) becomes reliable once complete() has fired.

If you have code that must run once FRVR has finished bootstrapping — even if you’re not the one calling complete() — register a hook:

FRVR.setPostCompleteHook(() => {
  console.log('FRVR is fully ready');
});

Setting it after bootstrap has already completed runs the callback immediately.