Help us improve
Share bugs, ideas, or general feedback.
From phaser-assets
Find and integrate free 2D game assets (sprites, tilesets, UI, audio) into Phaser JS projects. Triggers when the user needs game art, sprites, tilesets, backgrounds, UI elements, sound effects, or music for a Phaser game, or mentions OpenGameArt, Kenney, or itch.io assets.
npx claudepluginhub ehartye/phaser-assets --plugin phaser-assetsHow this skill is triggered — by the user, by Claude, or both
Slash command
/phaser-assets:asset-finderThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Find free 2D game assets from trusted sources and integrate them into Phaser JS projects — complete with download, file organization, and ready-to-use loading code.
Creates code-only pixel art sprites, animated characters, and visual assets for browser games. Upgrades geometric shapes to recognizable pixel art entities.
Builds and refactors Phaser 3 browser games for new projects, scenes, entities, physics, UI, tilemaps, animations, input, audio, cameras, and Phaser-specific bugs or performance issues.
Use this skill when loading and managing resources in PixiJS v8. Covers Assets.init, Assets.load/add/unload, bundles, manifests, background loading, onProgress, caching, spritesheets, video textures, web fonts, bitmap fonts, animated GIFs, compressed textures, SVG as texture or Graphics, resolution detection, per-asset data options, and forcing a specific loader with the parser field (for extension-less URLs). Triggers on: Assets, Assets.load, Assets.init, loadBundle, manifest, backgroundLoad, Spritesheet, Cache, LoadOptions, unload, parser, loadParser, loadWebFont, loadBitmapFont, loadVideoTextures, GifSource, VideoSourceOptions.
Share bugs, ideas, or general feedback.
Find free 2D game assets from trusted sources and integrate them into Phaser JS projects — complete with download, file organization, and ready-to-use loading code.
This skill searches the web for free game assets, presents them visually so the user can pick what they like, downloads the selected assets, and generates Phaser JS code to load and use them. The goal is to go from "I need a character sprite" to playable assets in minutes, not hours of browsing asset sites.
Before searching, clarify these details (many will be obvious from context):
If the user is vague ("find me some assets"), ask a quick question or two. If they're specific ("I need a 32x32 pixel art knight with idle and run animations"), go straight to searching.
Use WebSearch to find assets from these trusted free sources. Read references/asset-sources.md for the full list of sources with search URL patterns and license details.
Search strategy:
Constructing good searches:
site:kenney.nl {art_style} {asset_type} {genre_keywords}
site:opengameart.org {asset_type} {art_style} {genre_keywords}
site:itch.io game-assets free {asset_type} {art_style}
Use WebFetch on promising results to get:
itch.io listing pages are Cloudflare-protected, so WebFetch will often fail on them. When the asset server is running, use these endpoints instead — they use a Playwright-driven Edge browser to bypass Cloudflare automatically.
Search — POST /api/itch/search
Find free game assets on itch.io with tag, sort, and query filters.
curl -s -X POST http://localhost:8483/api/itch/search \
-H "Content-Type: application/json" \
-d '{"tags": ["pixel-art", "platformer"], "sort": "top-rated", "max_results": 10}'
Request body:
tags (array, optional): itch.io tags to filter by (e.g. ["pixel-art", "tileset", "fantasy"])sort (string, optional): one of "top-rated", "most-recent", "most-downloaded"query (string, optional): free-text search termmax_results (int, optional): max assets to return, default 30, capped at 60Response:
{"url": "https://itch.io/game-assets/free/tag-pixel-art/...", "count": 10, "assets": [
{"name": "...", "url": "https://author.itch.io/pack", "previewUrl": "https://...", "creator": "...", "source": "itch.io"}
]}
Details — POST /api/itch/details
Scrape a single itch.io asset page for description, license, file list, and download type.
curl -s -X POST http://localhost:8483/api/itch/details \
-H "Content-Type: application/json" \
-d '{"url": "https://author.itch.io/asset-pack"}'
Request body:
url (string, required): full itch.io asset page URLResponse:
{"url": "...", "name": "...", "description": "...", "license": "CC0...", "download_type": "direct",
"files": [{"name": "sprites.zip", "upload_id": "12345", "size": "2 MB"}]}
download_type is "direct", "name-your-price", or "unknown".
Download — POST /api/itch/download
Download files from an itch.io asset page. Handles both direct downloads and name-your-price gate flows automatically. Prefers ZIP files when available.
curl -s -X POST http://localhost:8483/api/itch/download \
-H "Content-Type: application/json" \
-d '{"url": "https://author.itch.io/asset-pack", "dest_dir": "/absolute/path/to/save"}'
Request body:
url (string, required): full itch.io asset page URLdest_dir (string, required): absolute path to save downloaded filesResponse:
{"downloaded": [{"name": "sprites.zip", "path": "/absolute/path/sprites.zip", "size": 204800}], "count": 1}
If some files fail, the response includes an "error" field with details.
Note: The first call to any itch.io endpoint launches a headed Edge browser window (minimized). The browser persists for the server lifetime and is closed on /shutdown.
Aim to find 4-8 options across sources so the user has real choices.
This is the key step that makes asset selection visual and fun instead of a wall of text links. The asset server handles preview, selection, and downloading all in one flow.
[
{
"id": "kenney-knight",
"name": "Kenney Knight Character Pack",
"source": "Kenney.nl",
"sourceUrl": "https://kenney.nl/assets/...",
"previewUrl": "https://..../preview.png",
"license": "CC0 (Public Domain)",
"type": "sprite",
"description": "32x32 pixel knight with idle, walk, attack, and death animations. 4 color variants.",
"formats": ["PNG sprite sheet", "Individual frames"],
"tags": ["pixel-art", "character", "knight", "fantasy", "animated"]
}
]
curl -s http://localhost:8483/health || python "$CLAUDE_PLUGIN_ROOT/scripts/server.py" --port 8483 --no-open &
curl -s -X POST http://localhost:8483/start \
-H "Content-Type: application/json" \
-d '{"assets": <asset_json_array>, "project_path": "<absolute_project_path>", "search_context": "<what was searched for>"}'
Tell the user to open http://localhost:8483 to browse and select assets. They click "Download to Project" and the server downloads assets directly into the project.
Poll for completion:
curl -s http://localhost:8483/api/status
Wait until status is "done".
curl -s http://localhost:8483/api/results
The response contains downloaded (array of assets with path relative to project) and failed (array with source_url preserved for retry).
source_url from the failed array — do NOT re-search:curl -L -o "<project_path>/<appropriate_subdir>/<filename>" "<source_url>"
curl -s -X POST http://localhost:8483/shutdown
Default asset directory structure — use the project's existing structure if it has one, otherwise the server organizes assets into:
assets/
├── images/
│ ├── characters/
│ ├── tiles/
│ ├── backgrounds/
│ └── ui/
├── audio/
│ ├── sfx/
│ └── music/
└── tilemaps/
Create a CREDITS.md in the assets directory listing each asset, its source, author, and license. This is important — even CC0 assets deserve attribution, and CC-BY assets require it.
Generate the code the user needs to load and use each asset in their Phaser game. Read references/phaser-integration.md for the exact code patterns for each asset type.
Use the path field from the /api/results response to reference exact file locations — do not guess paths. Each entry in the downloaded array includes the relative path where the file was saved.
What to generate:
this.load.* calls for each asset, using the exact path from resultsPresent this code clearly, either:
Example output for a character sprite sheet:
// In your preload() method:
// Use the exact path from /api/results downloaded[].path
this.load.spritesheet('knight', 'assets/images/characters/knight.png', {
frameWidth: 32,
frameHeight: 32
});
// In your create() method:
this.anims.create({
key: 'knight-idle',
frames: this.anims.generateFrameNumbers('knight', { start: 0, end: 3 }),
frameRate: 8,
repeat: -1
});
this.anims.create({
key: 'knight-run',
frames: this.anims.generateFrameNumbers('knight', { start: 4, end: 11 }),
frameRate: 12,
repeat: -1
});
const player = this.physics.add.sprite(400, 300, 'knight');
player.anims.play('knight-idle');