Skip to content

Designing games around providers

The Rollerz SDK connects your game to a provider — a backend math engine (RGS) that determines bet outcomes. Your game's theme, mechanics, and animations should be designed around the data your chosen provider returns.

This guide helps you pick the right provider and shows how to turn its result fields into compelling game experiences.

What is a bet type?

A bet type is a hint sent with every bet that tells the math server which math model to use for the round. Different bet types control volatility, max payout, and potentially the valid bet amounts.

The full resolution and validation rules live in the bet types section of the API reference — here, the design question is simply: how do you want the player to choose his bet type?

Note that the framework's default bet selector renders whatever provider.getBetTypes() returns as a segmented control.

General design tips

  • Map every result field to something visual. If a field exists, show it. Players should see the data reflected in what happens on screen.
  • Animate the reveal. Don't just show the final state — build anticipation. Stagger rock breaks, flip cards one by one, show the multiplier climbing.
  • Make the common fields the core mechanic. count/multiplier/cardPacks are the main event. hasBonus/crashed/rarity summaries are the twist.
  • Use the session data. currency for formatting, chipLevels for bet options, defaultBet for sensible defaults. The framework's bet selector handles this out of the box.
  • Treat bet types as a player-facing choice. See the section above — surface them in your UI, don't bury them in a settings menu.
  • All amounts are raw (in cents). Every monetary value from the SDK — balance, bet amounts, payouts, win amounts — is in the smallest currency unit (e.g. 10000 = $100.00). Never divide or scale these yourself. Use formatAmount() from the framework whenever you display a monetary value to the player.
  • Test with dev mode. Every predefined provider — GO3, Stepper, Rippin Rumble, and GP — ships with a devConfig. Drop them all into a single dev panel and you get per-provider domain controls (counts, multipliers, crash points, card combos, raw math overrides) that force specific outcomes without hitting the real RGS.

Choosing a provider

ProviderFlowBest for
GO3Bet → instant result → collectGames where the outcome is revealed all at once
StepperBet → step → step → ... → collect or crashGames where the player pushes their luck
Rippin RumbleBet → cards dealt → collectGames built around revealing or collecting items
GP (General Purpose)Bet → result (raw math) → collectGames connecting to an external or custom math server

Explore providers in the Playground

Switch between Go3, Stepper, Rippin Rumble, and GP in the SDK Provider Playground. Trying each provider there — open a session, place bets, use step/collect where it applies — is the quickest way to get a feel for how the flows and responses differ before you commit your game design.

The key question: how does your game deliver its result?

  • If the player bets and immediately sees what they won → GO3
  • If the player makes repeated risk/reward decisions after betting → Stepper
  • If the player receives a set of items to reveal → Rippin Rumble
  • If you're connecting to your own math server or a third-party RGS → GP

Need custom math?

If none of the built-in providers fit your game concept, the Rollerz team can build a custom math server for you. See Adding a new math server for details.

GO3: instant-reveal games

GO3 returns everything in a single bet result: how many items were hit, whether a bonus was triggered, and the win multiplier. Design your game around revealing these fields.

Key result fields (see Go3BetResult for all fields):

FieldTypeDesign role
countnumber[0,1,2,3]How many things the player hit/broke/matched
hasBonusbooleanWhether a bonus or rare event occurred
multipliernumberThe win multiplier

Bet types: BASE (default) and BOOSTED. The boosted list is the session's chip levels multiplied by the math server's boosted multiplier (typically 2×), and the math model pays out more aggressively. Surface boost as a clear "risk it for higher stakes" toggle — the sample smash game uses a fiery visual shift when the player flips to BOOSTED. You can also use the legacy { boosted: true } sugar on placeBet if it reads better in your code.

Game idea

🔒
Vault CrackerBe the first to build this game!Heist / Thriller

You're a safecracker on a heist. Pick one of three vault dials to turn, and see how well you crack the code.

Field mapping

countTumblers cracked — 0 = jammed, 1 = one click, 2 = two clicks, 3 = vault opens
hasBonusDiamond stash inside — vault glows, jewels spill out
multiplierPayout based on how many tumblers cracked

Design notes

  • The dial pick is purely cosmetic — the math result is the same regardless. But it gives the player agency and lets you animate a satisfying dial-turn sequence.
  • Animate the crack attempt in stages: hand on dial, slow turn, tumbler clicks one by one.
  • Jammed (0) should still feel dramatic — dial resists, alarm almost triggers, tension sting.
  • Diamond stash deserves a full celebration: vault door swings open, jewels cascade, spotlight glint.

Stepper: risk-reward games

Stepper is unique — after placing a bet, the player repeatedly chooses to step (increase their multiplier) or collect (cash out). But each step risks a crash that loses the bet. Design your game around this tension.

Key result fields (see StepperBetResult for all fields):

FieldTypeDesign role
currentStepnumberHow far the player has climbed
currentPayoutnumberWhat the player wins if they cash out now
stepsStepperStep[]The full ladder — each step has a payout and outcome (SAFE, CRASH, UNDECIDED)
roundEndedbooleanWhether the round ended (crash or cash out)
difficultystringThe risk level (BEGINNER, EASY, MEDIUM, HARD, INSANE)

Bet types: the five difficulty levels above. Each is a separate math model with its own step count and max multiplier — BEGINNER has 24 steps and caps at 20× while INSANE has 16 steps and caps at 10000×. This isn't a cosmetic choice: it fundamentally reshapes the risk curve, so treat it as a first-class game decision, not a settings-menu afterthought. The framework's bet selector renders all five as a segmented control automatically. Stepper does not support the boosted: true sugar — pass { betType: 'HARD' } (etc.) explicitly.

Design-wise, theme the difficulty labels to match your game — BEGINNER/INSANE might read as "Stroll" vs. "Apocalypse" in a zombie game, or "Rookie" vs. "Champion" in a combat gauntlet. The result.difficulty field echoes whatever the player chose back to you, so you can use it to drive visual intensity (louder music, faster heartbeat, heavier particle effects on INSANE).

Game idea

🧟
Zombie CrashBe the first to build this game!Survival / Horror

Move through a zombie-infested zone, mowing down undead along the way. When a close encounter hits, time slows — fight on or bail with your winnings.

Field mapping

currentPayoutPayout amount — grows with each step, cash out anytime
roundEndedBitten — the run is over, bet lost
stepsThe path ahead — each step shows payout and outcome (SAFE/CRASH/UNDECIDED)

Core loop

  1. Player bets and enters the zone.
  2. Between encounters, the player moves through the environment killing zombies freely — this is gameplay filler that builds atmosphere. Track a kill count and accuracy as fun stats (cosmetic only, no effect on payout).
  3. A close encounter triggers — time slows down. The player decides: fight (step()) or bail (collect).
  4. Safe step — encounter survived, RGS returns the new multiplier, and the player keeps moving until the next encounter.
  5. Crash — caught and bitten. Round over.

Design notes

  • The decision moment is everything. Slow-motion, heartbeat audio, visual tension.
  • Between encounters, let the player enjoy the zombie-killing gameplay — it's the "filler" that makes the encounter moments feel earned.
  • On a safe step: satisfying encounter kill. On a crash: quick, brutal — no slow-mo escape.
  • Layer a narrative goal on top — fighting toward a rescue point or saving a survivor gives the "keep going" choice emotional weight beyond the multiplier.
  • This pattern works for other combat themes: FPS corridor, sword fight gauntlet, martial arts tournament.
Demo: Watch a gameplay walkthrough of this concept in action.
Compliance note: The outcome is always determined by the math server. Fight/bail maps to step/collect — no skill action. Animations suggest action, but the result is predetermined. Verify with your compliance team.

Rippin Rumble: card-reveal games

Rippin Rumble deals one or more card packs per round. Each pack has 5 cards, each with a rarity (COMMON / UNCOMMON / RARE / LEGENDARY), plus per-rarity summary objects that give a pre-computed payout breakdown per tier. Design your game around the reveal of these cards and pack-level payouts.

Key result fields (see RippinRumbleBetResult for all fields):

FieldTypeDesign role
cardPacksCardPack[]1 pack for BASE/BOOSTED, 11 packs for BASE_BUNDLE
cardPacks[].cardsCard[]The 5 cards dealt in that pack
cardPacks[].{common,uncommon,rare,legendary}CardPackRaritySummaryPer-rarity count / valuePerCard / multiplier / totalValue
cardPacks[].totalPayoutnumberSum of totalValue across rarities for this pack

Bet types: BASE (default), BOOSTED, and BASE_BUNDLE. Boosted chip levels are base chips × boostedMultiplier (default 2, env RIPPINRUMBLE_BOOSTED_MULTIPLE). Base-bundle chip levels are base chips × baseBundleMultiplier (default 10, env RIPPINRUMBLE_BASE_BUNDLE_MULTIPLE). Bundles return 11 packs per round — good framing for "open a box of 11 packs" mechanics.

Game idea

🎯
Shadow ContractBe the first to build this game!Sniper / Hitman

You're an assassin on a rooftop with a contract. A group emerges from a building — scope in, pick your mark, collect the bounty.

Field mapping

cardPacks[0].cardsPeople in the group — each card is a person with a role
cardPacks[0].rare.totalValue / .legendary.totalValueBounty totals for high-value groupings
cardPacks[0].totalPayoutTotal bounty for this contract

Core loop

  1. Player bets. Briefing screen shows the target and location.
  2. A group emerges — people revealed one at a time through the scope.
  3. Player picks who to assassinate. The choice is cosmetic — payout comes from the group composition — but it adds to a persistent hit list.
  4. High-value rarity tiers trigger bonus totals — rare pairs, legendary groups.
  5. Collect the bounty.

Design notes

  • Reveal people one at a time with a scope sweep. Build tension as each steps into view.
  • Rarity highlights: the scope lights up high-value targets, a "HIGH VALUE" banner appears.
  • Vary settings each round — different rooftop, weapon skin, city. Use storage to persist the hit list across sessions.
  • Legendary pack: an entire group of high-value targets. Dramatic music, slow-mo scope pan.

GP: generic math server

The GP (Generic Provider) is a passthrough provider that connects your game to any external math server. Unlike the providers above, GP does not define game-specific result fields — the SDK handles session management and betting, but the math result structure depends entirely on the connected server.

When to use GP:

  • You have your own math server or are connecting to a third-party RGS
  • You want to use the SDK's session and bet infrastructure without being locked into a specific result format
  • You're prototyping with a custom math backend

Key result fields (see GPBetResult for all fields):

FieldTypeDesign role
mathRecord<string, unknown>Raw response from the math server — structure varies by server
totalWinAmountnumberTotal win amount
roundIdstringRound ID for collecting winnings

Since the math field is a passthrough, your game must extract and map the fields it needs. For example, if your math server returns GO3-style results:

javascript
const result = await sdk.gp.placeBet(100, { betType: 'BASE' });
const details = result.math?.details || {};
const rocksCrushed = details.rocksCrushed || 0;
const multiplier = details.multiplier || 0;

Bet types: unlike the other providers, GP ships with no predefined bet types — the set your math server understands depends entirely on your deployment. You have two options:

  1. Register a fixed set at startup via sdk.gp.configureBetTypes([...], options?). After this, GP behaves exactly like the predefined providers: getBetTypes() returns your list, the bet selector renders it, and any unknown betType passed to placeBet throws client-side before hitting the network.
  2. Leave it unconfigured and pass arbitrary betType strings straight through. No client-side allow-list; whatever you send is forwarded to the math server verbatim. This is the right choice for experimental setups or when the set changes at runtime.
javascript
// Option 1 — recommended for games shipping to players.
sdk.gp.configureBetTypes(['BASE', 'BOOSTED'], {
  defaultBetType: 'BASE',
  boostedBetType: 'BOOSTED', // enables the `{ boosted: true }` sugar
});

// Option 2 — unconfigured pass-through.
await sdk.gp.placeBet(100, { betType: 'WHATEVER' });

Without configureBetTypes, placeBet() with no opts (and placeBet({ boosted: true })) throws — there's no default to fall back to. See gp.configureBetTypes for the full API.

See it in practice

The GP variant of the smash game example walks through a real hosting app wiring GP up against a GO3-compatible math server — including the configureBetTypes(['BASE', 'BOOSTED'], { ... }) call that makes the bet selector and boosted sugar work.

Custom endpoint path

By default, the SDK appends /gameevent to the server URL. If your math server uses a different path, pass the path parameter when opening the game:

javascript
await sdk.gp.openGame({
  serverUrl: 'https://math.example.com',
  internalClientCode: 'go3',
  path: '/gameevent/v2',
});

See API reference — gp.openGame for details.

Server URL precedence

GP accepts serverUrl from two places: the launch URL (?server=…) or the explicit openGame({ serverUrl }) argument. The URL parameter wins when both are present — host-driven launches must be able to override in-code defaults. openGame() only throws if neither source provides a serverUrl. internalClientCode is always required from openGame() options — the launch URL doesn't carry it.