tupicGames
DEVELOPERS

Game SDK

Inside every tupic Game the platform injects window.TupicSDK -- a tiny JS bridge for HUD, scoring, audio, and analytics. Use it from your generated game code or from custom logic you add by hand.

When the SDK is available

The SDK is exposed as a global on the window object inside the iframe that hosts the game. It is available as soon as the runtime loads and stays available for the whole game session.

JS
if (window.TupicSDK) {
  // SDK is ready
}

For backward compatibility, the same object is also exposed as window.GameSDK. New code should use window.TupicSDK.

The SDK is required everywhere your game runs

Important: every tupic Game -- whether played in a browser, embedded on a third-party site, packaged as a Telegram Mini App, wrapped into the Android APK, the iOS IPA, or exported via Unity Export -- depends on the SDK being present at runtime. The SDK is not optional integration; it is the bridge between the game and the platform services (HUD, scoring, leaderboards, audio, session tracking, post-game CTA).

Concretely:

  • Web & embed -- the runtime injects window.TupicSDK automatically when the game HTML loads. No setup needed.
  • Mobile (Android & iOS) -- the tupic Game mobile app loads your game inside a WebView with the SDK pre-injected. If you take a tupic Game build and host it inside your own app, you must include games-sdk.js from the platform; otherwise the game will boot but scoring, leaderboards, and the post-game CTA will silently no-op.
  • Telegram Mini App -- the SDK is loaded by the runtime; in addition the bridge layer translates Telegram-specific events (theme, viewport, haptics) into SDK calls.
  • Unity Export -- the C# starter scripts are written against the same surface area. They expect a backend that speaks the same scoring and session API. If you swap the backend or remove the SDK calls, leaderboards and tournaments will no longer work for your exported build.

If you ever need to run a tupic Game in a sandbox where window.TupicSDK cannot be present, stub it before the game loads (see Best practices below). A missing SDK does not crash the game, but no scores will be recorded and the platform features will be invisible.

Game context

Before the SDK runs, the runtime sets a few read-only globals you can use to identify the current session:

  • window.__TUPIC_GAME_ID -- ID of the game being played.
  • window.__TUPIC_USERNAME -- the player display name, or "Guest" for anonymous plays.
  • window.__TUPIC_EMBED -- true when the game is loaded via the embed endpoint (no toolbar, no SDK chrome).
  • window.__TUPIC_EDITOR_MODE -- true when the editor loads the game with ?editor=1.
  • window.__TUPIC_START_LEVEL -- numeric override from ?level=N, useful for testing specific levels.

Treat these as read-only. Do not rely on internal token globals; they are managed by the runtime.

Pause & audio

JS
window.TupicSDK.pause();           // freeze the game loop
window.TupicSDK.resume();          // unfreeze
window.TupicSDK.togglePause();     // flip pause state
window.TupicSDK.toggleMute();      // mute / unmute audio
window.TupicSDK.fullscreen();      // request fullscreen (must come from a user gesture)

fullscreen() only works when called inside a user-initiated event (click, keydown, touch). Browsers reject programmatic fullscreen requests from timers or network callbacks.

HUD

The SDK ships a small built-in HUD with score, level, lives, coins, and time. Set initial values with setHUD, then update individual fields with updateHUD:

JS
// Initial state
window.TupicSDK.setHUD({
  score: 0,
  level: 1,
  lives: 3,
  coins: 0,
  time: 60,
});

// Later, update one or more fields
window.TupicSDK.updateHUD({ score: 1280, coins: 7 });

// Hide / show
window.TupicSDK.hideHUD();
window.TupicSDK.showHUD();

You can also include a custom object inside setHUD for genre-specific stats (waves, combos, distance) and the HUD will display them with monospace formatting.

Submitting scores

When the player finishes a run, submit the score. The SDK takes care of auth, rate-limiting, and falling back to a postMessage if the page is embedded:

JS
// Two arguments: score, level
window.TupicSDK.submitScore(1280, 4);

Internally submitScore:

  • Throttles repeated submissions for the same level (15 second window) to keep servers honest.
  • Saves resume state to localStorage under tupic_resume_{game_id} so the player picks up where they left off.
  • POSTs to /api/v1/games/{game_id}/scores with the authenticated player when a token is available, otherwise as a guest.
  • Falls back to window.parent.postMessage when the request fails or when running outside an authenticated context, so the embedding page can still react.

Analytics events

Track gameplay milestones. The SDK recognizes a small set of well-known events and triggers automatic behavior:

JS
window.TupicSDK.analytics.track('level_complete', { level: 4, score: 1280 });
window.TupicSDK.analytics.track('game_over',      { score: 1280, level: 4 });
window.TupicSDK.analytics.track('victory',        { score: 1280, level: 4 });

For these events the SDK will:

  • Call submitScore automatically when a non-zero score is present.
  • Show the post-game CTA overlay (Challenge a friend, Play again, More games).
  • De-duplicate fast repeated calls within a 5 second window.

You can also pass arbitrary event names; they are forwarded to the analytics backend without the side effects above.

postMessage protocol

When the game runs inside an iframe, the SDK communicates with the host page via postMessage. The host can listen for these message types:

  • tupic-score -- payload {{ score, level }}, sent as a fallback when a score POST fails or runs without auth.
  • tupic-last-level -- payload {{ level, score }}, sent on score submission so the host can persist resume state.
JS
window.addEventListener('message', (e) => {
  if (e.origin !== 'https://games.tupic.com') return;
  if (e.data && e.data.type === 'tupic-score') {
    console.log('Final score', e.data.score, 'level', e.data.level);
  }
});

Always validate e.origin before trusting the payload.

Best practices

  • Call setHUD once at game start, then updateHUD on changes. Avoid calling setHUD in a hot loop.
  • Submit scores at run-end and on every level transition, not on every score change. The SDK throttles regardless, but explicit calls are cheaper.
  • Use analytics.track for milestone events only -- it is not a general logging channel.
  • When testing locally, set a stub: window.TupicSDK = { submitScore: console.log } so your code does not throw outside the platform.