vplay.gg

VPLAY.GG FOR DEVELOPERS

SDK documentation

Everything you need to connect a game to vplay.gg. New here? Start with the overview. To publish, apply to us.

Install

Load the SDK from vplay.gg. Do not bundle a copy: loading it from here means fixes reach your game within minutes.

import { VPlay } from "https://vplay.gg/sdk/v1/vplay-sdk.js";

Or with a plain script tag:

<script src="https://vplay.gg/sdk/v1/vplay-sdk.global.js"></script>
<!-- sets window.VPlay -->

TypeScript types: /sdk/v1/vplay-sdk.d.ts. A working reference game: example-game.html.

Quick start

const vp = await VPlay.init({
  gameId: "your-game-id",
  // Only while testing a local build; remove before launch:
  // hostOrigins: ["http://localhost:3000"],
});

if (vp.mode === "vplay") {
  showPrices(vp.items);          // prices come from vplay.gg
  showBalance(vp.vcoins);        // display only
  loadSave(vp.save);             // cloud save, or null
}

VPlay.loading(1);                // 0..1 while assets load
VPlay.gameplayStart();           // the player is actually playing

VPlay.milestone("ach.first-delivery");
const bought = await VPlay.purchase("skin.amber");
const result = await VPlay.gameOver({ score: 4200, level: 3 });

VPlay.saveCloud({ level: 3 });   // up to 64 KB, saved for you
VPlay.on("pause", pauseGame);
VPlay.on("resume", resumeGame);
Standalone always works. Outside vplay.gg, init resolves with mode: "standalone" and every other call does nothing. Never make gameplay depend on the SDK succeeding.

Connecting

VPlay.init({ gameId }) asks vplay.gg for the player, prices and save. It resolves with:

{
  mode: "vplay" | "standalone",
  player: { signedIn, displayName, member },
  vcoins: number,            // display only, never use it for game logic
  items: [{ id, label, priceVc, owned }],
  entitlements: string[],    // item ids this player owns
  save: any | null,          // cloud save
  capabilities: string[],    // what we switched on for your game
  sdkVersion: 1,
  host: { revision, features, limits, theme, locale, scoreOrder, tournament } | null
}

Your game trusts messages only from vplay.gg (and any hostOrigins you pass while testing). If the page that frames your game does not answer, the SDK falls back to standalone: after 12 seconds with no sign of a host, or after up to 45 seconds if a host is there but its server is slow. A temporary server error is retried for you.

API reference

CallWhat it does
init({ gameId, hostOrigins?, openUrl?, autoTheme? })Connects. Returns the object above. Never throws.
loading(progress)0 to 1 while assets load.
gameplayStart() / gameplayStop()Tell vplay.gg when the player is actually playing (a run opens on our server) and when a menu, pause or shop is up.
score(n) / lives(n) / level(n)Live hints, for display only. They are never used as your result.
gameOver({ score, level?, reason? })Reports a finished run. Resolves { accepted, flagged, best }. The server decides; a flagged run is never ranked or rewarded.
win({ score, level? })Same as gameOver, marked as a win.
purchase(itemId)Asks to unlock an item. vplay.gg shows its own confirm sheet. Resolves purchased, cancelled, needs_signin, insufficient, unavailable or error.
entitlements()Resolves the item ids the player owns.
milestone(id)Reports one-time progress. The reward is whatever we registered for that id; reporting twice does nothing.
saveCloud(data)Saves JSON up to 64 KB for the player. Writes are combined for you; call flush() to write immediately.
flush()Writes a pending cloud save now (for example when the player leaves).
showLeaderboard()Opens vplay.gg's own leaderboard over your game and pauses it. Your game receives nothing.
leaderboard({ scope?, limit? })Returns the board as data, for a game that draws its own (a capability we switch on per game). Scopes: all, week, day, tournament. Resolves null when unavailable.
feature(name)True if a platform feature is on right now: purchases, milestones, saves, leaderboard, tournaments.
host, theme, tournamentRead the live platform description, colours and the running tournament (or null).
applyTheme(el?)Writes the colours into CSS variables. Done for you unless you pass autoTheme: false.
on(event, fn)Subscribes to an event. Returns a function that unsubscribes.
openOnVplay()Standalone only: opens your game's page on vplay.gg.

Events

EventDataWhen
pausenoneA vplay.gg overlay is open (leaderboard, purchase sheet, exit dialog). Stop the action.
resumenoneThe overlay closed. Carry on.
mute / unmutenoneReserved for the platform's sound control.
entitlementsstring[]What the player owns changed (a purchase, signing in or out).
vcoinsnumberThe balance changed. Display only.
confighost objectThe theme, a feature switch, a limit or the tournament changed.

Ignore events you do not recognise: the platform may add more.

Items, rewards and saves

Items (VCoin purchases)

Your game never sends a price. Show items[].priceVc from init. When the player taps an item, call purchase(id): vplay.gg asks them to confirm, charges the price held on our server, and records ownership in one step. Buying something already owned does nothing. If the price changed since the sheet opened, the player is asked again.

Milestones (one-time rewards)

Ids look like ach.first-delivery or level.2. We register the rewards, and can use patterns such as level.*. Each player can earn each id once. A reward can be held for a short while (for example until the account's email is verified, or when a daily limit is reached) and is paid automatically later. An id we have no rule for is ignored.

Cloud saves

One JSON save per player per game, up to 64 KB, last write wins. Guests have no cloud save.

Ids may use letters, numbers and . _ : -, up to 80 characters.

Scores and leaderboards

A run starts at gameplayStart() and ends at gameOver() or win(). It is timed on our server, so your game never sends or sees a start time. A run is flagged, saved, and never ranked or rewarded if it is shorter than 3 seconds, above the maximum score we set for your game, or climbs faster than the per-second limit we set.

Boards rank each player's best accepted run (ties go to whoever got there first). We set per game whether a higher score or a lower one (a race time) wins. Boards cover all time, this week and today; a tournament is a named period with its own board and a prize list that we pay out after review. After each accepted run the player sees their rank on screen, and the game's page shows the top scores.

After a finished run, call gameplayStart() again when the next one begins so it is timed from the start.

Platform info and theme

host describes vplay.gg right now: which features are on, limits, the language, which score wins, the running tournament, and the theme. Read it when you draw a button rather than at start-up, or rebuild on the config event, because switches can change while your game is open. Never branch on a version number.

Colours are mirrored into CSS variables on the page: --vp-bg, --vp-surface, --vp-surface2, --vp-line, --vp-text, --vp-muted, --vp-accent, --vp-accent2, --vp-danger, --vp-warning, --vp-positive, plus data-vp-theme="dark|light" on the root element.

body {
  background: var(--vp-bg, #0c0c12);
  color: var(--vp-text, #eee);
}
a { color: var(--vp-accent, #b9ff43); }

Errors and limits

The SDK resolves with a safe default and does not throw, so a failure never breaks your game loop. Server errors use these codes:

CodeMeaning
needs_signinThe player is a guest. vplay.gg opens its own sign-in.
insufficientNot enough VCoins. vplay.gg tells the player.
unavailableThe item, game or feature is not available (or switched off).
price_changedThe price moved while the sheet was open; the player is asked again.
rate_limitedToo many requests. Slow down.
not_grantedYour game isn't allowed to do that. Ask us to switch it on.
LimitValue
Cloud save64 KB of JSON
Live hints (score, lives, level)10 per second
Shortest counted run3 seconds
Item and milestone ids80 characters
Purchase confirmationwaits up to 3 minutes for the player

Read the live numbers from host.limits instead of copying them.

Testing

  1. Open the test host with your game's URL. It behaves like vplay.gg with no account, and lets you flip features, theme and the tournament to see how your game reacts.
  2. Study the example game: its source uses every call.
  3. When you apply, we register your game as a private draft. Open it on vplay.gg to test the real wallet, confirm sheet, leaderboard and pause behaviour. To test a local build, we add http://localhost:PORT to your allowed addresses (and you pass it in hostOrigins). Remove both before launch.

Go-live checklist

  • The game plays normally with the SDK blocked or missing.
  • No local test addresses are left in your allowed list or hostOrigins.
  • Item and milestone ids are final and agreed with us, along with prices and rewards.
  • The game pauses and resumes on the events, and works on a phone and a desktop.
  • If it reports scores: a few real runs show up on the Trophy sheet, and the right "better score" direction is set.
  • The game is served over HTTPS from the address we registered.

Versions

This is version 1. It will not change underneath you: new features are additions, never removals or renames. A new platform feature shows up in host.features first, so a game that does not know about it is unaffected. A future version 2 would live at a new address and version 1 would keep working.

Chat just went liveTap the chat icon to jump in