Loading...
Loading...
Integrates the Yandex Games JavaScript SDK (YaGames) into JavaScript games. Initializes the SDK and lifecycle hooks, manages player authentication and authorization, handles per-player cloud storage, controls ad placements (interstitial, rewarded video, sticky banner), implements in-app purchases and leaderboards, retrieves remote config flags, and supports social features such as review prompts and home-screen shortcuts. Use when the user mentions Yandex Games, YaGames, yandex sdk, deploying a game to the Yandex.Games platform, or integrating features like ads, leaderboards, in-app purchases, or player authentication into a Yandex-hosted JavaScript game.
npx skill4agent add hungify/playables-skills yandex-js-sdkyandex.<tld>/gamesYaGamesLoadingAPI.ready()GameplayAPI.start/stopGamesAPI<script src="https://yandex.ru/games/sdk/v2"></script>window.YaGames && window.YaGames.initinit()async function bootstrap() {
// 1. Ensure SDK script has loaded
if (!window.YaGames?.init) {
throw new Error('YaGames SDK not available — check that the script tag loaded');
}
// 2. Initialize — all subsequent SDK calls require ysdk
const ysdk = await window.YaGames.init();
// 3. Bind host-driven pause / resume before anything else
ysdk.on('game_api_pause', () => {
/* mute audio, pause gameplay */
});
ysdk.on('game_api_resume', () => {
/* unmute, resume */
});
// 4. Signal that the loading screen is gone
ysdk.features.LoadingAPI?.ready();
// 5. Read environment (language, device type)
const env = readEnvironment(ysdk);
// 6. Fetch player — fall back to guest mode if not authorized
let player = null;
let storageCache = {};
try {
const info = await getPlayer(ysdk);
player = info.raw;
if (info.isAuthorized) {
storageCache = await loadStorage(player);
}
} catch (err) {
console.warn('Player init failed, continuing as guest:', err);
}
// 7. Start gameplay tracking
onGameplayStarted(ysdk);
return { ysdk, player, storageCache, env };
}function readEnvironment(ysdk) {
return {
language: ysdk.environment.i18n.lang.toLowerCase(),
tld: ysdk.environment.i18n.tld.toLowerCase(),
deviceType: ysdk.deviceInfo.type // 'desktop' | 'mobile' | 'tablet' | 'tv'
};
}async function getPlayer(ysdk, { useSignedData = false } = {}) {
const player = await ysdk.getPlayer({ signed: useSignedData });
return {
raw: player,
id: player.getUniqueID(),
name: player.getName() || null,
photos: ['small', 'medium', 'large'].map((size) => player.getPhoto(size)).filter(Boolean),
isAuthorized: player.isAuthorized(),
payingStatus: player.getPayingStatus(),
signature: useSignedData ? player.signature : null
};
}
async function authorizePlayer(ysdk, options) {
const current = await getPlayer(ysdk, options);
if (current.isAuthorized) {
return current;
}
await ysdk.auth.openAuthDialog();
return getPlayer(ysdk, options);
}localStorageasync function loadStorage(player) {
return player.getData();
}
async function setStorage(player, cache, key, value) {
const data = { ...(cache || {}) };
if (Array.isArray(key)) {
for (let i = 0; i < key.length; i++) {
data[key[i]] = value[i];
}
} else {
data[key] = value;
}
await player.setData(data);
return data;
}
async function deleteStorage(player, cache, key) {
const data = { ...(cache || {}) };
if (Array.isArray(key)) {
for (let i = 0; i < key.length; i++) {
delete data[key[i]];
}
} else {
delete data[key];
}
await player.setData(data);
return data;
}
function getCached(cache, key) {
if (Array.isArray(key)) {
return key.map((k) => (typeof cache?.[k] === 'undefined' ? null : cache[k]));
}
return typeof cache?.[key] === 'undefined' ? null : cache[key];
}onClose(wasShown)wasShown === falsefunction showInterstitial(ysdk, handlers = {}) {
ysdk.adv.showFullscreenAdv({
callbacks: {
onOpen: () => handlers.onOpen?.(),
onClose: (wasShown) => handlers.onClose?.(wasShown),
onError: (err) => handlers.onError?.(err)
}
});
}onRewardedonClosefunction showRewarded(ysdk, handlers = {}) {
ysdk.adv.showRewardedVideo({
callbacks: {
onOpen: () => handlers.onOpen?.(),
onRewarded: () => handlers.onRewarded?.(),
onClose: () => handlers.onClose?.(),
onError: (err) => handlers.onError?.(err)
}
});
}async function getBannerStatus(ysdk) {
return ysdk.adv.getBannerAdvStatus(); // { stickyAdvIsShowing: boolean, reason?: string }
}
async function showBanner(ysdk) {
const data = await ysdk.adv.showBannerAdv();
return data.stickyAdvIsShowing === true;
}
async function hideBanner(ysdk) {
const data = await ysdk.adv.hideBannerAdv();
return data.stickyAdvIsShowing === false;
}signed: trueasync function initPayments(ysdk, { signed = true } = {}) {
return ysdk.getPayments({ signed });
}async function getCatalog(payments) {
const products = await payments.getCatalog();
return products.map((p) => ({
id: p.id,
title: p.title,
description: p.description,
imageURI: p.imageURI,
price: p.price,
priceValue: p.priceValue,
priceCurrencyCode: p.priceCurrencyCode,
priceCurrencyImage: p.getPriceCurrencyImage?.('medium')
}));
}async function purchase(payments, productId, payload) {
const result = await payments.purchase({ id: productId, developerPayload: payload });
if (!result?.purchaseData?.purchaseToken) {
throw new Error(
`Purchase succeeded but returned no purchaseToken for product ${productId}`
);
}
return { id: productId, ...result.purchaseData };
}async function getPurchases(payments) {
const list = await payments.getPurchases();
return list.map((purchase) => ({ id: purchase.productID, ...purchase.purchaseData }));
}async function consumePurchase(payments, purchaseToken) {
if (!purchaseToken) {
throw new Error('consumePurchase: purchaseToken is required');
}
await payments.consumePurchase(purchaseToken);
}async function setLeaderboardScore(ysdk, leaderboardId, score) {
const lb = await ysdk.getLeaderboards();
await lb.setLeaderboardScore(leaderboardId, score);
}
async function getLeaderboardEntries(ysdk, leaderboardId, { isPlayerAuthorized = false } = {}) {
const lb = await ysdk.getLeaderboards();
const options = { quantityTop: 20 };
if (isPlayerAuthorized) {
options.includeUser = true;
options.quantityAround = 3;
}
const result = await lb.getLeaderboardEntries(leaderboardId, options);
if (!result || result.entries.length === 0) {
return [];
}
return result.entries.map((e) => ({
id: e.player.uniqueID,
name: e.player.publicName,
score: e.score,
rank: e.rank,
photo: e.player.getAvatarSrc('large')
}));
}ysdk.getFlags(options){ key: stringValue }async function getRemoteConfig(ysdk, options = {}) {
const params = { clientFeatures: [], ...options };
return ysdk.getFlags(params);
}function getServerTime(ysdk) {
// Returns Unix timestamp in milliseconds
return ysdk.serverTime();
}async function requestReview(ysdk) {
const can = await ysdk.feedback.canReview();
if (!can.value) {
throw new Error(can.reason || 'review not available');
}
const { feedbackSent } = await ysdk.feedback.requestReview();
return feedbackSent;
}async function canAddToHomeScreen(ysdk) {
const prompt = await ysdk.shortcut.canShowPrompt();
return prompt.canShow === true;
}
async function addToHomeScreen(ysdk) {
const result = await ysdk.shortcut.showPrompt();
return result.outcome === 'accepted';
}async function clipboardWrite(ysdk, text) {
await ysdk.clipboard.writeText(text);
}GameplayAPI.start()GameplayAPI.stop()function onGameplayStarted(ysdk) {
ysdk.features.GameplayAPI?.start();
}
function onGameplayStopped(ysdk) {
ysdk.features.GameplayAPI?.stop();
}function bindPauseHandlers(ysdk, { onPause, onResume }) {
ysdk.on('game_api_pause', () => onPause?.());
ysdk.on('game_api_resume', () => onResume?.());
}document.visibilitychangewindow.blurwindow.focusfeatures.GamesAPIasync function getAllGames(ysdk) {
const { games } = await ysdk.features.GamesAPI.getAllGames();
return games;
}
async function getGameById(ysdk, gameId) {
const { game, isAvailable } = await ysdk.features.GamesAPI.getGameByID(gameId);
return { ...game, isAvailable };
}