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% RTP10 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>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.94x5 // 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_CURRENCY14}, '*');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: false6};7
8// Start → pathStart (include id for response matching)9// Click tile → pathReveal with id + position (0-24)10// Cash out → pathCashout with id11// See "Path" docs for full template with sendToParent helperCrash (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 – 105 maxMultiplier: 1000 // hard cap6};7
8// Start → multiplierStart (places bet, starts round)9// Cash → multiplierCashout10// Listen for 'serverCrash' push event when round ends11// Listen for 'serverSync' for clock calibration12// Animate multiplier locally using growthRate + curve from start response13// See "Multiplier" docs for full response shapesRock 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 fee5};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 match11// pvpOpponentCommitted — opponent has committed12// pvpResult — match resolved (winner, payout, etc.)13// pvpCancelled — match cancelled14// Cancel → pvpCancel15// See "PVP Escrow" docs for full response shapesCommon Patterns
Listening for Messages
1// All games use id-based request/response matching2var 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 can11 // validate your game without an upload12 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 state49 }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 script2parent.postMessage({ type: 'gameReady' }, '*');postMessage API for communication.