Example Games
Reference

Real examples showing how each primitive is used. Copy any of these as a starting point for your own game.

Which Primitive?

Dice / Slots / Roulette

one-shot

Single bet → instant result

Mines / Towers

path

Pick tiles, avoid hazards

Crash / Rocket

multiplier

Rising multiplier, cash out in time

Rock Paper Scissors

pvp-escrow

Two players, escrowed stakes

Blackjack / Hi-Lo

state-machine

Multi-step with branching

Plinko / Wheel

one-shot

Single spin → weighted outcome

Dice Game (one-shot)

Simple dice roll. Player bets, platform picks a random outcome from the multiplier table.

1<!DOCTYPE html>
2<html>
3<head><title>Dice</title></head>
4<body>
5 <div id="dice">🎲</div>
6 <button onclick="roll()">ROLL</button>
7
8 <script>
9 // 6 multipliers — platform auto-calculates probabilities for 97% RTP
10 window.GAME_CONFIG = {
11 primitive: 'one-shot',
12 multipliers: [0, 0.5, 1, 2, 5, 10]
13 };
14
15 // id-based communication (same pattern all games use)
16 var pendingRequests = new Map();
17 var requestId = 0;
18
19 function sendToParent(data) {
20 return new Promise(function(resolve, reject) {
21 var id = ++requestId;
22 pendingRequests.set(id, { resolve: resolve, reject: reject });
23 var payload = Object.assign({}, data, { id: id });
24 if (window.TEST_MODE) {
25 payload.gameConfig = window.GAME_CONFIG_FOR_API;
26 }
27 parent.postMessage(payload, '*');
28 setTimeout(function() {
29 if (pendingRequests.has(id)) {
30 pendingRequests.delete(id);
31 reject(new Error('Timeout'));
32 }
33 }, 30000);
34 });
35 }
36
37 window.addEventListener('message', function(e) {
38 if (e.data && e.data.id && pendingRequests.has(e.data.id)) {
39 var h = pendingRequests.get(e.data.id);
40 pendingRequests.delete(e.data.id);
41 if (e.data.error) h.reject(new Error(e.data.error));
42 else h.resolve(e.data);
43 }
44 });
45
46 async function roll() {
47 try {
48 var resp = await sendToParent({
49 type: 'bet',
50 stake: window.GAME_STAKE || 1,
51 currency: window.GAME_CURRENCY || 'USDT'
52 });
53 // resp.result.multiplier = the winning multiplier (e.g. 5)
54 // resp.result.result = 'WIN' | 'PUSH' | 'LOSS'
55 var r = resp.result;
56 if (r.error) return alert(r.error);
57 document.getElementById('dice').textContent =
58 r.result === 'LOSS'
59 ? '🎲 Lost!'
60 : '🎲 Won ' + r.multiplier + 'x!';
61 } catch (err) {
62 alert(err.message);
63 }
64 }
65
66 parent.postMessage({ type: 'gameReady' }, '*');
67 </script>
68</body>
69</html>
One-shot is purely random — the player doesn't choose a number or target. The platform picks one of the multipliers based on calculated probabilities. Use continuous mode if you want the player to choose their own target multiplier (see One Shot docs).

Coin Flip (one-shot)

50/50 coin flip — two multipliers, one wins 1.94x, one loses.

1window.GAME_CONFIG = {
2 primitive: 'one-shot',
3 multipliers: [0, 1.94]
4 // Platform calculates: ~50% chance of 0x, ~50% of 1.94x
5 // RTP = 0.5 * 0 + 0.5 * 1.94 = 0.97 (97%)
6};
7
8// Bet:
9parent.postMessage({
10 type: 'bet',
11 id: Date.now(),
12 stake: window.GAME_STAKE,
13 currency: window.GAME_CURRENCY
14}, '*');
15
16// Result: e.data.result.multiplier = 0 (loss) or 1.94 (win)
17// e.data.result.result = 'WIN' or 'LOSS'

Mines (path)

5×5 grid with 3 mines. Click tiles, avoid mines, cash out anytime.

1window.GAME_CONFIG = {
2 primitive: 'path',
3 totalChoices: 25,
4 losingChoices: 3,
5 replacement: false
6};
7
8// Start → pathStart (include id for response matching)
9// Click tile → pathReveal with id + position (0-24)
10// Cash out → pathCashout with id
11// See "Path" docs for full template with sendToParent helper

Crash (multiplier)

Multiplier rises from 1.00x. Cash out before it crashes.

1window.GAME_CONFIG = {
2 primitive: 'multiplier',
3 curve: 'exponential', // 'linear' or 'exponential'
4 growthRate: 1, // 0.01 – 10
5 maxMultiplier: 1000 // hard cap
6};
7
8// Start → multiplierStart (places bet, starts round)
9// Cash → multiplierCashout
10// Listen for 'serverCrash' push event when round ends
11// Listen for 'serverSync' for clock calibration
12// Animate multiplier locally using growthRate + curve from start response
13// See "Multiplier" docs for full response shapes

Rock Paper Scissors (pvp-escrow)

Two players, equal stakes, classic RPS rules.

1window.GAME_CONFIG = {
2 primitive: 'pvp',
3 resolver: 'rps',
4 fee: 0.05 // 5% platform fee
5};
6
7// Create/join → pvpCreate (matchmaking or new match)
8// Choose action → pvpCommit with action: 'rock'|'paper'|'scissors'
9// Push events from parent:
10// pvpOpponentJoined — someone joined your match
11// pvpOpponentCommitted — opponent has committed
12// pvpResult — match resolved (winner, payout, etc.)
13// pvpCancelled — match cancelled
14// Cancel → pvpCancel
15// See "PVP Escrow" docs for full response shapes

Common Patterns

Listening for Messages

1// All games use id-based request/response matching
2var pendingRequests = new Map();
3var requestId = 0;
4
5function sendToParent(data) {
6 return new Promise(function(resolve, reject) {
7 var id = ++requestId;
8 pendingRequests.set(id, { resolve, reject });
9 var payload = Object.assign({}, data, { id: id });
10 // In preview mode, include gameConfig so the platform can
11 // validate your game without an upload
12 if (window.TEST_MODE) {
13 payload.gameConfig = window.GAME_CONFIG_FOR_API;
14 }
15 parent.postMessage(payload, '*');
16 setTimeout(() => {
17 if (pendingRequests.has(id)) {
18 pendingRequests.delete(id);
19 reject(new Error('Timeout'));
20 }
21 }, 30000);
22 });
23}
24
25window.addEventListener('message', (e) => {
26 const data = e.data;
27
28 // id-based response routing (from your sendToParent calls)
29 if (data.id && pendingRequests.has(data.id)) {
30 const h = pendingRequests.get(data.id);
31 pendingRequests.delete(data.id);
32 if (data.error) h.reject(new Error(data.error));
33 else h.resolve(data);
34 return;
35 }
36
37 // Stake update (user changed bet amount in parent UI)
38 if (data.type === 'stakeUpdate') {
39 state.stake = data.stake;
40 state.stakeUsd = data.stakeUsd;
41 state.currency = data.currency;
42 }
43
44 // Session restore (active path/multiplier/state-machine game)
45 if (data.type === 'sessionResume') {
46 // data.primitive = 'path' | 'multiplier' | 'state-machine'
47 // data.session = { sessionId, ... }
48 // Restore your UI to match the saved state
49 }
50
51 // Push events (multiplier crash, PVP updates, etc.)
52 if (data.type === 'serverCrash') { /* round crashed */ }
53 if (data.type === 'pvpOpponentJoined') { /* opponent found */ }
54 if (data.type === 'pvpResult') { /* match resolved */ }
55});

Sending gameReady

Always send gameReady when your game loads. This tells the platform your iframe is ready to receive config and active session data:

1// Send this at the end of your script
2parent.postMessage({ type: 'gameReady' }, '*');
All games are just HTML files. Use any framework, library, or plain vanilla JS. The only requirement is the postMessage API for communication.