Official TypeScript SDK for the Playcademy platform
The Playcademy SDK provides a comprehensive, type-safe interface for building games on the Playcademy platform. It handles authentication, game sessions, user data, inventory management, and all platform APIs through a unified client interface.
The SDK serves as the primary interface between your game and the Playcademy platform, providing:
- Automatic Environment Detection: Seamlessly works in development and production
- Type-Safe API Access: Full TypeScript support with comprehensive type definitions
- Session Management: Automatic game session handling and state persistence
- Event System: Real-time notifications for inventory changes, level ups, and more
- Developer Tools: Built-in support for game development and testing workflows
- Zero Configuration: Automatic initialization with environment detection
- Production Ready: Battle-tested API patterns with robust error handling
- Real-Time Events: Subscribe to platform events like inventory changes and level ups
- Comprehensive Coverage: Access to all Playcademy platform features
- Development Experience: Integrated with sandbox environment for local development
- Game Development: Primary SDK for building games on Playcademy
- Web Applications: Frontend applications interacting with the platform
- Developer Tools: Scripts and utilities for game management
- Server Integration: Backend services integrating with Playcademy APIs
- Testing & Automation: Automated testing of platform integrations
Install the SDK using your preferred package manager:
# Using Bun (recommended)
bun add @playcademy/sdk
# Using npm
npm install @playcademy/sdk
# Using yarn
yarn add @playcademy/sdk
# Using pnpm
pnpm add @playcademy/sdk
For most game development scenarios, use automatic initialization:
import { PlaycademyClient } from '@playcademy/sdk'
async function initializeGame() {
try {
// Automatic initialization - detects environment and configures appropriately
const client = await PlaycademyClient.init()
// Get current user
const user = await client.users.me()
console.log('Welcome,', user.name)
// The client is ready for all platform operations
return client
} catch (error) {
console.error('Failed to initialize Playcademy SDK:', error)
throw error
}
}
The SDK automatically detects and configures for different environments:
-
Development: Connects to local sandbox (started by
@playcademy/vite-plugin
) - Production: Receives configuration from Playcademy platform loader
- Testing: Falls back to mock configuration for automated testing
// Automatic session management when gameId is available
const client = await PlaycademyClient.init()
// Save transient game state (position, health, temporary data)
await client.games.saveState({
currentLevel: 'forest_glade',
playerPosition: { x: 100, y: 200 },
health: 85,
activePowerUps: ['speed_boost'],
})
// Load previously saved state
const gameState = await client.games.loadState()
console.log('Loaded state:', gameState)
// Exit game (automatically ends session if managed)
await client.runtime.exit()
// Get user information
const user = await client.users.me()
// Inventory operations (accepts UUIDs or slugs)
const inventory = await client.users.inventory.get()
await client.users.inventory.add('magic-sword', 1)
await client.users.inventory.remove('health-potion', 1)
// Check item quantities and ownership
const goldCount = await client.users.inventory.quantity('gold-coin')
const hasKey = await client.users.inventory.has('dungeon-key')
const hasEnoughGold = await client.users.inventory.has('gold-coin', 100)
// Platform currency management
const balance = await client.credits.balance()
await client.credits.add(100)
await client.credits.spend(50)
// Check affordability
if ((await client.credits.balance()) >= 100) {
await client.credits.spend(100)
console.log('Purchase successful!')
}
// Level management
const userLevel = await client.levels.get()
const progress = await client.levels.progress()
console.log(`Level ${userLevel.currentLevel}, ${progress.xpToNextLevel} XP to next level`)
// Add experience points
const result = await client.levels.addXP(100)
if (result.leveledUp) {
console.log(`Level up! ${result.oldLevel} → ${result.newLevel}`)
console.log('Credits awarded:', result.creditsAwarded)
}
-
logout()
: Logs out user and clears authentication token
-
me()
: Get current user information -
Inventory (
client.users.inventory
):-
get()
: Get user's inventory -
add(identifier, quantity)
: Add items to inventory -
remove(identifier, quantity)
: Remove items from inventory -
quantity(identifier)
: Get item quantity -
has(identifier, minQuantity?)
: Check item ownership
-
-
list()
: Get all available games -
fetch(gameIdOrSlug)
: Get specific game details -
saveState(state)
: Save transient game state -
loadState()
: Load saved game state -
startSession(gameId?)
: Start game session -
endSession(sessionId, gameId?)
: End game session
-
balance()
: Get current credits balance -
add(amount)
: Add credits to user -
spend(amount)
: Spend user credits
-
get()
: Get current user level information -
progress()
: Get level progress and XP to next level -
addXP(amount)
: Add experience points -
Config (
client.levels.config
):-
list()
: Get all level configurations -
get(level)
: Get specific level configuration
-
-
elements(mapId)
: Get map elements and points of interest
-
getGameToken(gameId, options?)
: Get game-specific authentication token -
exit()
: Signal platform to exit game view
-
fetch(options?)
: Get leaderboard for a specific game-
options.timeframe
: Filter by time period ('all_time'
,'monthly'
,'weekly'
,'daily'
) -
options.gameId
: Game ID to fetch leaderboard for (required) -
options.limit
: Number of entries to return (default: 10) -
options.offset
: Pagination offset (default: 0)
-
-
submit(gameId, score, metadata?)
: Submit a score for any game -
getUserScores(userId, options?)
: Get all scores for a user-
options.gameId
: Filter by specific game (optional) -
options.limit
: Number of scores to return (default: 50)
-
-
applyForDeveloper()
: Apply for developer status -
getDeveloperStatus()
: Check current developer status
-
upsert(slug, metadata, gameFile)
: Create or update game -
update(gameId, updates)
: Update game properties -
delete(gameId)
: Delete game
-
createKey(gameId, name)
: Create API key for server authentication -
listKeys()
: List all API keys -
revokeKey(keyId)
: Revoke API key
-
list(gameId)
: List all items for a game -
get(gameId, slug)
: Get specific item -
create(gameId, slug, data)
: Create new game item -
update(gameId, itemId, updates)
: Update existing item -
delete(gameId, itemId)
: Delete item
The SDK provides real-time event notifications for important platform changes:
// Authentication changes
client.on('authChange', payload => {
console.log('Authentication changed:', payload.token)
})
// Inventory changes
client.on('inventoryChange', payload => {
console.log(`Item ${payload.itemId}: ${payload.delta} (total: ${payload.newTotal})`)
})
// Experience gained
client.on('xpGained', payload => {
console.log(`Gained ${payload.amount} XP (total: ${payload.totalXP})`)
})
// Level up notifications
client.on('levelUp', payload => {
console.log(`Level up! ${payload.oldLevel} → ${payload.newLevel}`)
console.log('Credits awarded:', payload.creditsAwarded)
})
// Update UI in response to platform events
client.on('inventoryChange', payload => {
updateInventoryDisplay(payload.itemId, payload.newTotal)
})
client.on('levelUp', payload => {
showLevelUpAnimation(payload.newLevel)
showCreditsAwarded(payload.creditsAwarded)
})
client.on('xpGained', payload => {
updateXPBar(payload.totalXP, payload.leveledUp)
})
For server-side applications or custom environments:
import { PlaycademyClient } from '@playcademy/sdk'
import type { LoginResponse } from '@playcademy/sdk'
// Step 1: Authenticate
const loginData: LoginResponse = await PlaycademyClient.login(
'https://api.playcademy.com',
'user@example.com',
'password',
)
// Step 2: Initialize client
const client = new PlaycademyClient({
baseUrl: 'https://api.playcademy.com',
token: loginData.token,
gameId: 'your-game-id', // Optional: enables automatic session management
})
const client = new PlaycademyClient({
baseUrl: 'https://api.playcademy.com',
token: 'your-auth-token',
gameId: 'your-game-id',
// Additional options
timeout: 10000, // Request timeout in milliseconds
retries: 3, // Number of retry attempts
})
import { PlaycademyError } from '@playcademy/sdk'
try {
const user = await client.users.me()
// Handle success
} catch (error) {
if (error instanceof PlaycademyError) {
console.error('Playcademy API Error:', error.message)
console.error('Status Code:', error.statusCode)
console.error('Error Code:', error.code)
} else {
console.error('Unexpected error:', error)
}
}
When using the official Playcademy Vite templates, the development environment is automatically configured:
// In your game's main file
import { PlaycademyClient } from '@playcademy/sdk'
// The vite plugin automatically starts the sandbox
const client = await PlaycademyClient.init()
// SDK automatically connects to local sandbox at http://localhost:4321
If not using the Vite plugin, start the sandbox manually:
# Start sandbox server
bunx @playcademy/sandbox --port 4321 --verbose
# In your application
const client = new PlaycademyClient({
baseUrl: 'http://localhost:4321/api',
token: 'dev-token' // Sandbox provides mock authentication
})
-
Always use automatic initialization for game development with
PlaycademyClient.init()
- Handle initialization errors gracefully with proper try-catch blocks
- Store the client instance for reuse throughout your application lifecycle
-
Use
games.saveState()
for transient data (current level, position, temporary status) -
Use
users.inventory
for persistent items and resources that carry between sessions - Save state periodically, not on every frame or minor change
- Load state once at game start, then manage locally
- Cache frequently accessed data like user information and inventory
- Batch inventory operations when possible instead of individual API calls
- Use event listeners to update UI reactively rather than polling
- Implement proper loading states for better user experience
- Wrap all SDK calls in appropriate try-catch blocks
- Provide fallback behavior for network errors and API failures
- Show meaningful error messages to users when operations fail
- Implement retry logic for non-critical operations
- Use the sandbox environment for all local development
- Test both online and offline scenarios to ensure robust error handling
- Enable verbose logging during development for debugging
- Validate API responses and handle edge cases appropriately
// Mock the SDK for unit tests
import { jest } from '@jest/globals'
// Mock the entire SDK module
jest.mock('@playcademy/sdk', () => ({
PlaycademyClient: {
init: jest.fn().mockResolvedValue({
users: {
me: jest.fn().mockResolvedValue({ id: 'test-user', name: 'Test User' }),
inventory: {
get: jest.fn().mockResolvedValue([]),
add: jest.fn().mockResolvedValue(undefined),
},
},
}),
},
}))
// Test with real sandbox
import { PlaycademyClient } from '@playcademy/sdk'
describe('Playcademy Integration', () => {
let client: PlaycademyClient
beforeAll(async () => {
// Initialize with sandbox
client = new PlaycademyClient({
baseUrl: 'http://localhost:4321/api',
token: 'test-token',
})
})
test('should fetch user data', async () => {
const user = await client.users.me()
expect(user).toBeDefined()
expect(user.name).toEqual(expect.any(String))
})
})
SDK Initialization Timeout
Error: PLAYCADEMY_INIT not received within 5000ms
- Ensure you're running in the correct environment (development with sandbox, or production with platform)
- Check that the Vite plugin is properly configured
- Verify the sandbox is running on the expected port
Authentication Errors
Error: Unauthorized (401)
- Check that your authentication token is valid
- Ensure you have the necessary permissions for the operation
- Try re-authenticating with
PlaycademyClient.login()
Network Connection Issues
Error: Failed to fetch
- Verify the API endpoint is accessible
- Check network connectivity
- Ensure CORS is properly configured for cross-origin requests
Use these debugging techniques for troubleshooting SDK issues:
// Check initialization process
try {
const client = await PlaycademyClient.init()
console.log('SDK initialized successfully')
} catch (error) {
console.error('SDK initialization failed:', error)
}
// Monitor network requests in browser dev tools (Network tab)
// Check console for SDK error messages
// Verify API responses and error details
- Check the platform documentation for detailed guides
- Review the Vite plugin configuration for development setup
- Examine the game templates for working examples
- Use browser dev tools to inspect network requests and responses
The SDK is a critical component of the Playcademy platform ecosystem. When contributing:
- Maintain Type Safety: Ensure all new APIs are fully typed
- Update Documentation: Keep this README and JSDoc comments current
- Add Tests: Include both unit and integration tests for new features
- Follow Patterns: Use consistent patterns with existing SDK methods
- Handle Errors: Implement proper error handling and user feedback
For general contribution guidelines, see the monorepo CONTRIBUTING.md.
-
@playcademy/api-core
: API handlers used by the SDK -
@playcademy/data
: Database schema and type definitions -
@playcademy/vite-plugin
: Development environment integration -
@playcademy/sandbox
: Local development server -
Game Templates: See
/templates
for example integrations