PlayKit.ai

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 playerToken directly 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-sdk

Direct 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:

  1. Ask users for their gameId and an apiKey (minted in the playkit.ai dashboard with the scopes the key needs)
  2. Users can obtain these from https://playkit.ai
  3. Fill in these values in the SDK initialization code you write
  4. 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

SizeUse Case
256x256Thumbnails, icons
512x512Small assets
1024x1024Standard images (recommended)
1792x1024Landscape backgrounds
1024x1792Portrait 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 IDUse case
default-chatGeneral text conversation (writing, role-play, reasoning)
default-chat-fastLow-latency, low-cost high-throughput conversation
default-imageText-to-image generation
default-image-multimodalImage input and editing (img2img, continuation, style transfer)
default-transcription-modelSpeech-to-text
default-tts-modelText-to-speech
default-3d-model3D 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 succeeds
  • unauthenticated - Triggered when session expires or user logs out
  • error - Triggered when SDK encounters an error
  • balance_updated - Triggered when player balance changes
  • insufficient_credits - Triggered when API call fails due to insufficient Spark
  • balance_low - Triggered when balance falls below 10 Spark
  • recharge_opened - Triggered when recharge window opens
  • ready - 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.message contains "denied"
    • Authorization expired or invalid: Other authentication errors
  • INSUFFICIENT_CREDITS - Insufficient Spark
  • NETWORK_ERROR - Network connection issues
  • INVALID_CONFIG - SDK configuration error (e.g., invalid gameId)

Best Practices:

  1. When user denies authorization: Clearly tell the user why authorization is needed and provide a way to re-authorize
  2. When Spark is insufficient: Prompt the user to recharge, can call sdk.openRechargeWindow()
  3. When network error occurs: Suggest the user check their network connection and retry
  4. Development environment debugging: Use console.error to 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.