@pixels-online/pixels-client-js-sdk
v3.12.0
Published
Pixels Client JS SDK
Downloads
1,633
Readme
Pixels BuildOn Client JS SDK
A powerful TypeScript SDK for integrating Pixels BuildOn offerwall functionality into web applications and games. This SDK provides real-time offer management, player progression tracking, and reward handling capabilities.
🚀 Features
- Real-time Offer Management - Live updates via Server-Sent Events (SSE)
- Player Progression Tracking - Monitor player stats, achievements, and conditions
- Reward System Integration - Handle various reward types (coins, items, exp, etc.)
- Event-Driven Architecture - React to offer events and player actions
- TypeScript Support - Full type safety and IntelliSense support
- Flexible Configuration - Customizable asset resolution and hooks
- Multi-Environment Support - Local, Test, staging, and production environments
- Auto-Reconnection - Robust connection management with retry logic
📦 Installation
npm install @pixels-online/pixels-client-js-sdk🔧 Quick Start
1. Basic Setup
import { OfferwallClient } from '@pixels-online/pixels-client-js-sdk';
const client = new OfferwallClient({
env: 'test', // or 'live' for production
tokenProvider: async () => {
// Fetch JWT token from your server. We recommend using our server-side SDK on your server for JWT creation
const response = await fetch('/api/auth/pixels-token', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
});
const data = await response.json();
return data.token;
},
assetResolver: (_, id: string) => {
return {
name: exampleGameLib[id]?.name || 'Unknown2',
image: exampleGameLib[id]?.image,
};
},
fallbackRewardImage: 'https://example.com/default-reward.png',
hooks: {
onOfferSurfaced: (offer) => {
var random = Math.random() < 0.5;
return random; // 50% chance to show the offer
},
},
autoConnect: true,
});2. Initialize and Connect
// Initialize the client
await client.initialize();
// Listen for offers
client.on('offersUpdated', (offers) => {
console.log('Available offers:', offers);
displayOffersInUI(offers);
});
// Listen for player updates
client.on('playerUpdated', (player) => {
console.log('Player snapshot updated:', player.snapshot);
console.log('Player data updated:', player.data);
updatePlayerStatsUI(player);
});3. Render Offer UI/UX
Each offer object returned by the SDK includes helper methods for rendering offer state in your UI.
Checking if an Offer is Claimable
Use offer.canClaim() to determine whether the player has met all requirements and can claim the offer:
const claimable = offer.canClaim?.();
renderClaimButton(offer, { disabled: !claimable });Displaying Offer Progress
Use offer.getProgressPercent() to get the player's overall completion percentage (0–100):
const progress = offer.getProgressPercent?.() ?? 0;
// Example: render a progress bar
renderProgressBar(offer, { percent: progress });Rendering Completion Conditions
Use offer.getCompletionConditions() to get a list of individual conditions, each with isMet (boolean) and text (human-readable description):
const conditions = offer.getCompletionConditions?.() ?? [];
for (const condition of conditions) {
renderCondition({
text: condition.text,
completed: condition.isMet,
});
}
// Example React rendering
function OfferConditions({ offer }) {
const conditions = offer.getCompletionConditions?.() ?? [];
return (
<ul>
{conditions.map((c, i) => (
<li key={i} style={{ color: c.isMet ? 'green' : 'gray' }}>
{c.isMet ? '✓' : '○'} {c.text}
</li>
))}
</ul>
);
}Rendering Team Offer Sibling Progress
For team offers (offers where all team members must complete for anyone to claim), use offer.getSiblingProgress() to display each sibling's progress:
const isTeamOffer = offer.labels?.includes('team_offer');
if (isTeamOffer) {
const siblingProgress = offer.getSiblingProgress?.() ?? [];
for (const sibling of siblingProgress) {
renderSiblingRow({
playerId: sibling.playerId,
percentCompleted: sibling.percentCompleted,
isComplete: sibling.isComplete,
});
}
}
// Example React rendering
function TeamProgress({ offer }) {
const siblings = offer.getSiblingProgress?.() ?? [];
if (!siblings.length) return null;
return (
<div>
<h4>Team Progress</h4>
{siblings.map((s) => (
<div key={s.playerId}>
<span>{s.playerId}</span>
<span>{s.percentCompleted}%</span>
<span>{s.isComplete ? '✓ Complete' : 'In Progress'}</span>
</div>
))}
</div>
);
}3. Claim Offers
// Claim an offer
try {
const result = await client.claimOffer(offerId);
console.log('Offer claimed successfully:', result);
} catch (error) {
console.error('Failed to claim offer:', error);
}📊 Player Data Structure
The SDK provides player information through the IClientPlayer interface:
interface IClientPlayer {
snapshot: IPlayerSnapshot; // Core player data (levels, currencies, achievements, etc.)
data?: IPlayerData | null; // Additional game-specific data
}Accessing Player Information
// Get the current player
const player = client.getPlayer();
if (player) {
// Access core player data
console.log('Player ID:', player.snapshot.playerId);
console.log('Player level:', player.snapshot.levels?.combat?.level);
console.log('Currency balance:', player.snapshot.currencies?.gold?.balance);
// Access additional player data (if available)
if (player.data) {
console.log('Additional currencies:', player.data.currencies);
}
}🎯 Configuration Options
OfferwallConfig
interface OfferwallConfig {
/** Environment: 'test' | 'live' | custom endpoint */
env: 'test' | 'live' | (string & {});
/** Auto-connect on initialization (default: false) */
autoConnect?: boolean;
/** Enable auto-reconnection (default: true) */
reconnect?: boolean;
/** Reconnection delay in ms (default: 1000) */
reconnectDelay?: number;
/** Max reconnection attempts (default: 5) */
maxReconnectAttempts?: number;
/** Enable debug logging (default: false) */
debug?: boolean;
/** Event hooks for custom logic */
hooks?: Partial<OfferwallHooks>;
/** Custom asset resolver for rewards */
assetResolver?: AssetResolver;
/** Fallback image for unknown rewards */
fallbackRewardImage: string;
/** JWT token provider function */
tokenProvider: TokenProvider;
}🎨 Asset Resolution
Customize how rewards are displayed in your game:
const gameAssets = {
gems: { name: 'Gems', image: '/assets/gems.png' },
gold: { name: 'Gold Coins', image: '/assets/gold.png' },
sword_1: { name: 'Iron Sword', image: '/assets/sword_iron.png' },
};
const client = new OfferwallClient({
// ... other config
assetResolver: (reward, assetId) => {
const asset = gameAssets[assetId];
if (asset) {
return { name: asset.name, image: asset.image };
}
return { name: `Unknown Item (${assetId})`, image: null };
},
});🎣 Event Hooks
Implement custom logic with event hooks:
const client = new OfferwallClient({
// ... other config
hooks: {
// Control which offers to show
onOfferSurfaced: (offer) => {
// Custom logic to determine if offer should be shown
const currentPlayer = client.getPlayer();
return currentPlayer?.snapshot.levels?.overall?.level >= offer.minLevel;
},
// Handle successful offer claims
onOfferClaimed: async (offer, rewards) => {
console.log('Offer completed!', { offer, rewards });
// Award rewards in your game
await showConfetti(rewards);
},
// Handle connection events
onConnect: () => {
console.log('Connected to Pixels BuildOn');
showConnectionStatus('connected');
},
onDisconnect: () => {
console.log('Disconnected from Pixels BuildOn');
showConnectionStatus('disconnected');
},
},
});📡 Events
Listen to various events emitted by the client:
// Offer-related events
client.on('offersUpdated', (offers) => {
/* Handle offers update */
});
client.on('offerAdded', (offer) => {
/* Handle new offer */
});
client.on('offerRemoved', (offerId) => {
/* Handle offer removal */
});
client.on('offerUpdated', (offer) => {
/* Handle offer changes */
});
// Player-related events
client.on('playerUpdated', (player) => {
/* Handle player data changes */
});
// Connection events
client.on('connected', () => {
/* Handle connection */
});
client.on('disconnected', () => {
/* Handle disconnection */
});
client.on('reconnecting', (attempt) => {
/* Handle reconnection attempts */
});
// Error events
client.on('error', (error) => {
/* Handle errors */
});🏗️ API Reference
OfferwallClient Methods
initialize(): Promise<void>
Initialize the client and establish connection.
disconnect(): Promise<void>
Disconnect from the service.
refreshOffersAndPlayer(): { offers: IClientOffer[], player: IClientPlayer }
Refresh and get all current offers.
claimOffer(offerId: string): Promise<ClaimResult>
Claim an offer and receive rewards.
getConnectionState(): ConnectionState
Get current connection status.
Utility Functions
import { meetsConditions, AssetHelper } from '@pixels-online/pixels-client-js-sdk';
// Check if player meets offer conditions
const canClaim = meetsConditions(player.snapshot, offer.surfacingConditions);
// Asset helper utilities
const assetHelper = new AssetHelper(assetResolver, fallbackImage);
const rewardAsset = assetHelper.resolveRewardAsset(reward, assetId);🌍 Environments
The SDK supports multiple environments:
test- Sandbox environment for developmentlive- Production environment
� Migration Guide
v1.0.0+ Breaking Changes
Player Data Structure Update
The player data structure has been updated to provide better separation between core player data and additional game-specific data:
- Old:
IClientPlayerSnapshot(flat structure) - New:
IClientPlayer(structured withsnapshotanddataproperties)
Migration Steps:
// Before (v0.x)
const player = client.getPlayer(); // IClientPlayerSnapshot
const level = player.levels?.combat?.level;
const gold = player.currencies?.gold?.balance;
// After (v1.0+)
const player = client.getPlayer(); // IClientPlayer
const level = player.snapshot.levels?.combat?.level;
const gold = player.snapshot.currencies?.gold?.balance;
// Access additional data (new feature)
const additionalCurrencies = player.data?.currencies;Event Handler Updates:
// Before
client.on('playerUpdated', (playerSnapshot) => {
updateUI(playerSnapshot.currencies);
});
// After
client.on('playerUpdated', (player) => {
updateUI(player.snapshot.currencies);
// Also handle additional data if needed
if (player.data) {
handleAdditionalData(player.data);
}
});�📋 Requirements
- Node.js 16+
- TypeScript 4.5+ (if using TypeScript)
- Modern browser with EventSource support
🤝 Contributing
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
📄 License
This project is licensed under the AGPLv3 License - see the LICENSE.md file for details.
🔗 Links
📞 Support
For support and questions:
- Create an issue on GitLab
- Contact the Pixels team
Made with ❤️ by the Pixels team
