Asset subclients—characters, scenes, items, sprites, mobs, music, sound effects, and voices. Unified interface for listing, creating, and fetching asset data.
Asset Subclients
The PUClient exposes several asset subclients that share a unified interface. Each handles a specific asset type: characters, scenes, items, sprites, mobs, music, sound effects, and voices. Use them to list, create, fetch metadata, and download asset binaries.
Asset Subclients
| Subclient | Purpose |
|---|---|
client.characters | Character assets |
client.scenes | Scene/level assets |
client.items | Item assets |
client.sprites | Sprite assets |
client.mobs | Mob (mobile entity) assets |
client.music | Music track assets |
client.soundEffects | Sound effect assets |
client.voices | Voice assets (slightly different API) |
Common Methods
All asset subclients (except voices) support the same interface:
| Method | Signature | Description |
|---|---|---|
listAll | (params?) => Promise<AssetRecord[]> | List assets with optional filters |
getOne | (id: string) => Promise<AssetRecord> | Get asset metadata by ID |
getDataFor | (id: string) => Promise<ArrayBuffer> | Fetch asset binary data |
delete | (id: string) => Promise<void> | Delete an asset |
createOne | (params) => Promise<AssetRecord> | Create a new asset |
listAll(params?)
listAll(params?: {
own?: boolean;
search?: string;
sortBy?: string;
sortOrder?: 'asc' | 'desc';
}): Promise<AssetRecord[]>Lists assets with optional filters.
| Param | Type | Description |
|---|---|---|
own | boolean | Only assets you own |
search | string | Search by name/description |
sortBy | string | Field to sort by |
sortOrder | 'asc' | 'desc' | Sort direction |
const characters = await client.characters.listAll({ own: true });
const scenes = await client.scenes.listAll({ search: 'forest', sortBy: 'name' });getOne(id)
getOne(id: string): Promise<AssetRecord>Fetches asset metadata by ID.
const character = await client.characters.getOne('character-uuid');
console.log(character.name, character.description);getDataFor(id)
getDataFor(id: string): Promise<ArrayBuffer>Fetches the raw binary data for an asset (e.g. image, audio, model file).
const buffer = await client.characters.getDataFor('character-uuid');
// Use buffer for blob, base64, or file savedelete(id)
delete(id: string): Promise<void>Deletes an asset by ID.
await client.characters.delete('character-uuid');createOne(params)
createOne(params: {
id?: string;
name: string;
description?: string;
file: Blob | ArrayBuffer | File;
preview?: Blob | ArrayBuffer | File;
metadata?: Record<string, unknown>;
}): Promise<AssetRecord>Creates a new asset. Requires name and file (the binary data).
| Param | Type | Description |
|---|---|---|
id | string | Optional custom ID |
name | string | Asset name |
description | string | Optional description |
file | Blob | ArrayBuffer | File | Binary asset data |
preview | Blob | ArrayBuffer | File | Optional preview image |
metadata | Record<string, unknown> | Optional metadata |
const character = await client.characters.createOne({
name: 'Hero',
description: 'Main protagonist',
file: imageBuffer,
preview: thumbnailBuffer,
});Voices Subclient
The client.voices subclient is slightly different—voice assets have a different shape and may expose alternate methods (e.g. for listing available voices for NPCs or TTS). Check the SDK types for the exact voices API.
Voice assets are often used for NPC speech. See NPCs for configuring voice on an NPC (e.g. kittentts:expr-voice-5-m).
Code Examples
Characters
import { PUClient } from 'pu-client';
const client = new PUClient({ apiKey: process.env.PU_API_KEY! });
const characters = await client.characters.listAll({ own: true });
const char = await client.characters.getOne(characters[0].id);
const data = await client.characters.getDataFor(char.id);
console.log(char.name, data.byteLength);import { PUClient } from 'pu-client';
const client = new PUClient({ apiKey: process.env.PU_API_KEY! });
const file = await fetch('hero.png').then(r => r.arrayBuffer());
const preview = await fetch('hero-thumb.png').then(r => r.arrayBuffer());
const character = await client.characters.createOne({
name: 'Knight',
description: 'A brave knight',
file,
preview,
metadata: { style: 'fantasy' },
});
console.log(`Created: ${character.id}`);Scenes
import { PUClient } from 'pu-client';
const client = new PUClient({ apiKey: process.env.PU_API_KEY! });
const scenes = await client.scenes.listAll({ search: 'dungeon' });
const scene = scenes[0];
const buffer = await client.scenes.getDataFor(scene.id);
// Save or process scene data
const blob = new Blob([buffer]);import { PUClient } from 'pu-client';
const client = new PUClient({ apiKey: process.env.PU_API_KEY! });
const sceneData = await fetch('my-scene.glb').then(r => r.arrayBuffer());
const preview = await fetch('scene-preview.png').then(r => r.arrayBuffer());
const scene = await client.scenes.createOne({
name: 'Castle Hall',
description: 'Grand entrance hall',
file: sceneData,
preview,
});
console.log(`Scene ready: ${scene.id}`);AssetRecord Fields
Common fields across asset types:
| Field | Type | Description |
|---|---|---|
id | string | Asset ID |
name | string | Display name |
description | string | null | Description |
url | string | null | Direct URL when available |
metadata | Record<string, unknown> | Custom metadata |
created_at | string | Creation timestamp |
updated_at | string | Last update |
Relationship to Generations
Many assets are produced by the generations pipeline. After a generation completes, its output (e.g. character ID, scene URL) becomes an asset you can fetch via these subclients.
1. Create generation
const id = await client.generations.create({
type: 'character',
input: { prompt: 'Steampunk fox', smartPrompt: true },
});2. Poll until done
let gen = await client.generations.get(id);
while (gen.state !== 'done' && gen.state !== 'error') {
await new Promise(r => setTimeout(r, 2000));
gen = await client.generations.get(id);
}3. Fetch via assets
const charId = gen.output?.character_id;
if (charId) {
const char = await client.characters.getOne(charId);
const data = await client.characters.getDataFor(charId);
}