Vibe Coding
Game development with AI using Vibe Coding
You are not implementing PlayKit from scratch, but understanding the PlayKit SDK and using it to help users develop AI-native games.
Overview
PlayKit is an AI development platform simplified for game development scenarios, enabling game developers to quickly integrate AI features such as text generation, image generation, and NPC conversations into web games. Compatible with P5.js, Phaser, PixiJS, and vanilla JavaScript.
Your current task is to use PlayKit's JavaScript SDK to help users develop AI-native games. The SDK's npm package name is playkit-sdk. Check whether npm is available first; if so, use npm install. Otherwise use direct browser import (UMD).
Core Features
- Text generation, image generation
- NPC conversation management with automatic history tracking (built on top of text generation)
- Simple authentication: use an API key during development, remove it for production so the game automatically prompts each player to sign in via device auth
- Real-time streaming responses
- Framework-agnostic design (P5.js, Phaser, PixiJS, vanilla JS)
- Multiple bundle formats (ESM, CJS, UMD)
- Full TypeScript support
- Player balance management and recharge functionality
- Server mode for backend integration
Server Mode
The SDK supports a mode: 'server' option for backend/Node.js environments. In server mode:
- UI-related features are disabled (no login dialogs, no visual indicators)
- You can pass a
playerTokendirectly for authentication - Ideal for backend services that need to make AI calls on behalf of users
import { PlayKitSDK } from 'playkit-sdk';
// Server-side usage with user's token
const sdk = new PlayKitSDK({
gameId: 'your-game-id',
playerToken: userTokenFromRequest, // Token received from client
mode: 'server'
});
await sdk.initialize();
const chat = sdk.createChatClient('default-chat');
const response = await chat.chat('Hello');For token validation without SDK instantiation, use TokenValidator:
import { TokenValidator } from 'playkit-sdk';
const validator = new TokenValidator();
const userInfo = await validator.validateToken(token, 'your-game-id');
// userInfo: { userId, balance, ... }See Backend Services for detailed backend integration guide.
Installation
npm package (preferred when npm is available)
npm install playkit-sdkDirect browser import (UMD)
For P5.js, vanilla HTML, and projects without a build tool:
<script src="https://unpkg.com/playkit-sdk@latest/dist/playkit-sdk.umd.js"></script>Quick Start
For P5.js and Vanilla HTML
<script src="https://unpkg.com/playkit-sdk@latest/dist/playkit-sdk.umd.js"></script>
<body>
<script>
// window.PlayKitSDK is the constructor itself — call it directly.
const sdk = new PlayKitSDK({
gameId: 'your-game-id',
apiKey: 'your-api-key',
});
sdk.initialize().then(() => {
console.log('SDK Ready!');
// Start using the SDK
});
</script>
</body>
</html>Backward compatibility: the legacy form
new PlayKitSDK.PlayKitSDK({ ... })is preserved as a self-reference, so v1.x projects upgrade with no code changes.
For TypeScript/Module Projects
import { PlayKitSDK } from 'playkit-sdk';
const sdk = new PlayKitSDK({
gameId: 'your-game-id',
apiKey: 'your-api-key',
});
await sdk.initialize();Notes
Please remember:
Credential Configuration
When helping users develop games with PlayKit SDK:
- Ask users for their
gameIdand anapiKey(minted in the playkit.ai dashboard with the scopes the key needs) - Users can obtain these from https://playkit.ai
- Fill in these values in the SDK initialization code you write
- There may be a "## Your Game Info" section at the bottom of this document provided by other AI assistants. If it exists, you can directly use the gameId, apiKey, and configured AI model list from it
Security Requirements
Critical: An API key is a server-side credential and must never ship inside a game. When preparing code for production deployment, help users remove the apiKey, and the game will automatically switch to player sign-in via device auth.
Without an API key, the SDK will automatically prompt each player to log in or register, ensuring proper authentication and Spark management.
When initializing this project, you can add code like this:
const isDevelopment = window.location.protocol === 'file:' ||
window.location.hostname === 'localhost' ||
window.location.hostname === '127.0.0.1' ||
window.location.hostname === '[::1]';
if (apiKey && !isDevelopment) {
alert('Warning: API key detected in a shipped game! Copy this message to your AI assistant for explanation.');
}As a safety net.
Common Use Cases
Text Generation
const chat = sdk.createChatClient('default-chat');
const response = await chat.chat('Hello, introduce yourself');Streaming Response
await chat.chatStream(
'Tell me a story',
(chunk) => process.stdout.write(chunk),
(fullText) => console.log('\nFull content:', fullText)
);Image Generation
const imageClient = sdk.createImageClient('default-image');
const image = await imageClient.generate('A futuristic city');
const imgElement = await image.toHTMLImage();Image Sizes
| Size | Use Case |
|---|---|
256x256 | Thumbnails, icons |
512x512 | Small assets |
1024x1024 | Standard images (recommended) |
1792x1024 | Landscape backgrounds |
1024x1792 | Portrait scenes |
const landscape = await imageClient.generateImage({
prompt: 'A mountain range at sunset',
size: '1792x1024'
});Transparent Background
Generate sprites and game items with transparent backgrounds:
const sprite = await imageClient.generateImage({
prompt: 'A fantasy sword, game item',
size: '512x512',
transparent: true
});
if (sprite.transparentSuccess) {
console.log('Background removed successfully');
}Image-to-Image (img2img)
Transform existing images using AI:
// Convert data URL to ImageInput format
const imageInput = PlayKitSDK.ImageClient.dataUrlToImageInput(dataUrl);
// Transform with text guidance
const result = await imageClient.img2img(
[imageInput],
'Transform to pixel art style'
);GeneratedImage Object
const image = await imageClient.generate('A dragon');
image.base64; // Raw base64 data
image.toDataURL(); // Data URL for img src
image.toHTMLImage(); // Returns Promise<HTMLImageElement>
image.originalPrompt; // Your original prompt
image.revisedPrompt; // AI-enhanced prompt (may differ)NPC Conversation
const npc = sdk.createNPCClient({
characterDesign: 'You are a mysterious wizard.'
});
const reply = await npc.talk('Who are you?');Character Design Best Practices
const npc = sdk.createNPCClient({
characterDesign: `You are Greta, the blacksmith.
Background: Former adventurer, retired after losing her arm to a dragon.
Personality: Gruff but kind-hearted. Respects strength and courage.
Speech: Direct, uses forge metaphors. Calls everyone "spark".
Secret: She knows the location of the legendary Dragonbane sword.`
});Memory System
Dynamically add context that affects NPC responses:
npc.setMemory('playerName', 'Hero');
npc.setMemory('relationship', 'Friendly - helped before');
npc.setMemory('currentQuest', 'Defeat the Dragon');
// NPC will now reference these memories in responses
const response = await npc.talk('Do you remember me?');
// Get/clear memories
const name = npc.getMemory('playerName');
npc.clearMemories();Actions (Tool Calling)
Let NPCs trigger game actions based on conversation:
const actions = [
{
actionName: 'give_item',
description: 'Give an item to the player',
parameters: [
{ name: 'itemName', type: 'string', required: true },
{ name: 'quantity', type: 'number', required: false }
]
},
{
actionName: 'start_quest',
description: 'Offer a quest to the player',
parameters: [
{ name: 'questId', type: 'string', required: true }
]
}
];
const response = await npc.talkWithActions('I completed your quest!', actions);
if (response.hasActions) {
for (const action of response.actionCalls) {
switch (action.actionName) {
case 'give_item':
givePlayerItem(action.arguments.itemName, action.arguments.quantity);
break;
case 'start_quest':
startQuest(action.arguments.questId);
break;
}
}
}Reply Predictions
Automatically generate suggested player responses:
const npc = sdk.createNPCClient({
characterDesign: 'You are a quest giver.',
generateReplyPrediction: true,
predictionCount: 4
});
npc.on('replyPredictions', (predictions) => {
displayDialogueOptions(predictions);
});
await npc.talk('Welcome! I have a dangerous mission.');Save/Load Conversations
Persist NPC conversations across game sessions:
// Save
const saveData = npc.saveHistory();
localStorage.setItem('npc_wizard', saveData);
// Load
const saved = localStorage.getItem('npc_wizard');
if (saved) {
npc.loadHistory(saved);
}Player Balance
const playerInfo = await sdk.getPlayerInfo();
console.log('Spark:', playerInfo.balance);
sdk.openRechargeWindow();
sdk.on('balance_updated', (credits) => console.log('New balance:', credits));API Models
Prefer PlayKit's built-in default models — they work out of the box with zero configuration, and PlayKit automatically picks a well-rounded model based on the current model landscape:
| Default model ID | Use case |
|---|---|
default-chat | General text conversation (writing, role-play, reasoning) |
default-chat-fast | Low-latency, low-cost high-throughput conversation |
default-image | Text-to-image generation |
default-image-multimodal | Image input and editing (img2img, continuation, style transfer) |
default-transcription-model | Speech-to-text |
default-tts-model | Text-to-speech |
default-3d-model | 3D asset generation |
Just pass these IDs to the matching client, e.g. sdk.createChatClient('default-chat'), sdk.createImageClient('default-image').
Only when a developer wants to pin a specific model should you have them go to the "AI Endpoints" tab on the website to add it, then come back and tell you the "endpoint name" (there's a copy button on the right side of the endpoint name) for you to put into the code. If a "## Your Game Info" section at the end of this document mentions models, you can use those directly too.
Don't add model selectors or input fields in the game. Keep AI models hidden from the frontend, don't show them to players — think with a product mindset.
Core Architecture
Main Components
- PlayKitSDK (
src/core/PlayKitSDK.ts) - SDK main entry point - ChatClient (
src/core/ChatClient.ts) - Text generation client - ImageClient (
src/core/ImageClient.ts) - Image generation client - NPCClient (
src/core/NPCClient.ts) - NPC conversation manager - PlayerClient (
src/core/PlayerClient.ts) - Player info and balance management
Authentication System
- AuthManager (
src/auth/AuthManager.ts) - Handles authentication flow - AuthFlowManager (
src/auth/AuthFlowManager.ts) - OAuth flow management - TokenStorage (
src/auth/TokenStorage.ts) - Encrypted token storage
Providers
- ChatProvider (
src/providers/ChatProvider.ts) - Chat API integration - ImageProvider (
src/providers/ImageProvider.ts) - Image API integration
Utilities
- StreamParser (
src/utils/StreamParser.ts) - Parses streaming responses - RechargeManager (
src/recharge/RechargeManager.ts) - Handles player recharge flow
Events
The SDK inherits from EventEmitter and emits the following events:
Core Events
authenticated- Triggered when authentication succeedsunauthenticated- Triggered when session expires or user logs outerror- Triggered when SDK encounters an errorbalance_updated- Triggered when player balance changesinsufficient_credits- Triggered when API call fails due to insufficient Sparkbalance_low- Triggered when balance falls below 10 Sparkrecharge_opened- Triggered when recharge window opensready- Triggered when SDK initialization completes
Usage Examples
Authentication Events:
sdk.on('authenticated', (authState) => {
document.getElementById('status').textContent = 'Logged in';
});
sdk.on('insufficient_credits', (error) => {
showRechargeModal();
});Error Handling
Authorization Denied
When a user clicks "Deny" during the authorization flow, the SDK will throw an error. You need to handle this error correctly and provide user-friendly feedback.
Error Handling Example:
const sdk = new PlayKitSDK({
gameId: 'your-game-id',
// apiKey: 'your-api-key', // Remove for a shipped game
});
try {
await sdk.initialize();
console.log('SDK Ready!');
} catch (error) {
if (error.code === 'AUTH_ERROR' && error.message.includes('denied')) {
// User denied authorization
alert('You denied authorization. The game cannot use AI features without authorization. Please refresh the page to re-authorize.');
// Or show a more friendly UI prompt
showAuthDeniedMessage();
} else {
// Other errors
console.error('Initialization failed:', error);
alert('Game initialization failed, please refresh the page to retry.');
}
}Common Error Types:
AUTH_ERROR- Authentication related errors- User denied authorization:
error.messagecontains "denied" - Authorization expired or invalid: Other authentication errors
- User denied authorization:
INSUFFICIENT_CREDITS- Insufficient SparkNETWORK_ERROR- Network connection issuesINVALID_CONFIG- SDK configuration error (e.g., invalid gameId)
Best Practices:
- When user denies authorization: Clearly tell the user why authorization is needed and provide a way to re-authorize
- When Spark is insufficient: Prompt the user to recharge, can call
sdk.openRechargeWindow() - When network error occurs: Suggest the user check their network connection and retry
- Development environment debugging: Use
console.errorto log detailed error information
sdk.on('error', (error) => {
console.error('SDK error:', error);
});
sdk.on('insufficient_credits', () => {
if (confirm('Insufficient Spark. Would you like to recharge?')) {
sdk.openRechargeWindow();
}
});Next Steps
For now, just understand this. Don't create any files yet. The first priority is to ask the user what kind of game they want to make. Once the user tells you what game they want to make, you can start implementing.