| name | game-asset-pipeline |
| description | Standardize async asset generation workflow for game development. Use when generating game assets (PixelLab), waiting for async jobs, retrieving URLs, and updating game code. Trigger: "generate asset", "pixel lab", "asset pipeline", "async asset", "wait for job". |
Game Asset Pipeline
Standardize async asset generation workflow for game development. Pattern: Generate asset → Wait for Job → Retrieve URL → Update preload() → Verify.
Workflow Pattern
1. Generate asset (PixelLab MCP) → Get job_id
2. Poll job status → Wait for completion
3. Retrieve asset URL → Get download link
4. Update game code → Add to preload()
5. Verify asset loads → Test in game
PixelLab Integration
Character Generation
const result = await mcp_pixellab_create_character({
description: "cute wizard with blue robes",
n_directions: 8,
size: 48
});
const { character_id, job_id } = result;
let character = null;
while (!character || character.status !== 'completed') {
await sleep(5000);
character = await mcp_pixellab_get_character({
character_id: character_id
});
if (character.status === 'failed') {
throw new Error(`Character generation failed: ${character.error}`);
}
}
const downloadUrl = character.download_url;
const rotations = character.rotations;
Tile Generation
const result = await mcp_pixellab_create_isometric_tile({
description: "grass on top of dirt",
size: 32,
tile_shape: "block"
});
const { tile_id } = result;
let tile = null;
while (!tile || tile.status !== 'completed') {
await sleep(2000);
tile = await mcp_pixellab_get_isometric_tile({
tile_id: tile_id
});
}
const tileUrl = tile.image_url || tile.download_url;
Map Object Generation
const result = await mcp_pixellab_create_map_object({
description: "wooden barrel",
width: 64,
height: 64
});
const { object_id } = result;
let obj = null;
while (!obj || obj.status !== 'completed') {
await sleep(3000);
obj = await mcp_pixellab_get_map_object({
object_id: object_id
});
}
const objectUrl = obj.image_url || obj.download_url;
Updating Game Code
Add to Preload
preload() {
this.load.image('wizard-south', 'https://pixellab.ai/characters/abc123/south.png');
this.load.image('wizard-north', 'https://pixellab.ai/characters/abc123/north.png');
this.load.image('grass-tile', 'https://pixellab.ai/tiles/xyz789/tile.png');
this.load.image('barrel', 'https://pixellab.ai/objects/def456/object.png');
}
Create Spritesheet from Rotations
preload() {
this.registry.set('wizard-rotations', {
south: 'https://pixellab.ai/characters/abc123/south.png',
north: 'https://pixellab.ai/characters/abc123/north.png',
east: 'https://pixellab.ai/characters/abc123/east.png',
west: 'https://pixellab.ai/characters/abc123/west.png',
});
}
Verification Checklist
After adding assets to game:
Common Pitfalls
❌ Don't: Use Job ID Instead of Asset ID
const character = await get_character({ character_id: job_id });
const character = await get_character({ character_id: character_id });
❌ Don't: Forget to Wait for Completion
const character = await create_character({ description: "wizard" });
const url = character.download_url;
let character = await create_character({ description: "wizard" });
while (character.status !== 'completed') {
await sleep(5000);
character = await get_character({ character_id: character.character_id });
}
❌ Don't: Hardcode Localhost URLs
this.load.image('wizard', 'http://localhost:3000/assets/wizard.png');
this.load.image('wizard', 'https://cdn.example.com/assets/wizard.png');
this.load.image('wizard', 'assets/characters/wizard.png');
Helper Functions
Poll Until Complete
async function waitForJob(getJob, jobId, maxWait = 60000) {
const startTime = Date.now();
while (Date.now() - startTime < maxWait) {
const job = await getJob({ [jobId.key]: jobId.value });
if (job.status === 'completed') {
return job;
}
if (job.status === 'failed') {
throw new Error(`Job failed: ${job.error || 'Unknown error'}`);
}
await sleep(job.eta_seconds ? job.eta_seconds * 1000 : 5000);
}
throw new Error(`Job timed out after ${maxWait}ms`);
}
const character = await waitForJob(
mcp_pixellab_get_character,
{ key: 'character_id', value: character_id }
);
Download and Save Asset
async function downloadAsset(url, localPath) {
const response = await fetch(url);
const blob = await response.blob();
const buffer = await blob.arrayBuffer();
const fs = require('fs');
fs.writeFileSync(localPath, Buffer.from(buffer));
return localPath;
}
const localPath = await downloadAsset(
character.download_url,
'assets/characters/wizard.zip'
);
Integration with Phaser
Preload Pattern
preload() {
const wizardRotations = this.registry.get('wizard-rotations');
Object.entries(wizardRotations).forEach(([direction, url]) => {
this.load.image(`wizard-${direction}`, url);
});
this.load.once('complete', () => {
this.createWizardSpritesheet();
});
}
createWizardSpritesheet() {
}
Related Skills
@pixellab-mcp: PixelLab MCP server documentation
@phaser-gamedev: Phaser asset loading patterns
@phaser-game-testing: Verify assets load correctly in tests
Remember
- Generate → Get job/asset ID
- Wait → Poll until status === 'completed'
- Retrieve → Get download/image URL
- Update → Add to
preload() or asset manifest
- Verify → Test asset loads in game
- Commit → Download and commit to repo, or use CDN URLs