tile-artist
Skill4 starsChanged 7 months agoMITView on GitHub
Generates a tileset PNG from the GDD's tilesetPalette. Default mode calls GPT Image 2 once per tile type (512×512 → 32×32) for real pixel-art textures. Falls back to procedural flat-color cells if FAL_KEY is absent. Writes tile metadata into manifest.json. Use after game-designer has produced a tile palette.
- Reads credentials
In this repository22 other files it gives its agents.
- action-platformerSkill
- audio-composerSkill
- beat-em-upSkill
- bg-artistSkill
- codesmithSkill
- game-designerSkill
- gameforgeSkill
- gap-checkerSkill
- iso-city-builderSkill
- iso-living-worldSkill
- manifest-auditorSkill
- mobile-compat-checkerSkill
- multiplayerSkill
- palette-enforcerSkill
- parallel-qa-orchestraSkill
- physics-debug-validatorSkill
- pixel-action-adventureSkill
- playtesterSkill
- refinerSkill
- rpg-overworldSkill
- sprite-artistSkill
- world-architectSkill
The file
We split this skill into the rules it gives an agent
3 rules. About 0 are common, 0 are distinctive, and 3 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
This author's own choices. Worth a look.
3
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 21
After game-designer produces a GDD with tilesetPalette.
- Very specific: line 44
Call fal.run/openai/gpt-image-2 at image_size: { width: 512, height: 512 }, quality: low (configurable).
- Very specific: line 47
If the call fails, paint the solid color value for that tile (no crash).
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Tile Artist
Generates tiles.png and tile metadata. GPT Image 2 is the default — one API call per non-SKY tile, each generated at 512×512 then downscaled to 32×32. Falls back to procedural flat-color cells when FAL_KEY is unavailable.
Two modes
| Mode | When | Cost | Output |
| GPT Image 2 (default) | FAL_KEY present | ~$0.01–0.05 per tile at low quality | Real pixel-art textures (cobblestone, brick mortar, grass blades, etc.) |
| Procedural fallback | No API key | Free | Flat-colored cells with a subtle 1-pixel darker border |
Both produce identical manifest entries — downstream Preload and Game.js are unaware which was used.
When to use
After game-designer produces a GDD with tilesetPalette. Runs in parallel with sprite-artist and bg-artist.
GDD palette format
Each entry in gdd.tilesetPalette:
{
"id": "STONE", // used as tile key in levels and manifest.ids
"color": "#607070", // fallback color if GPT call fails
"passable": false, // false = solid collision, true = walk-through
"desc": "gray cobblestone dungeon floor, beveled stone blocks with mortar cracks"
// ↑ optional but strongly recommended — used as the GPT Image 2 prompt
}If desc is omitted, the skill falls back to a built-in description map keyed on id (covers common ids: STONE, BRICK, SPIKE, LADDER, PIPE, FLOOR, ACID, GROUND, WALL, PROP, GRASS, WATER, FLOWER, TREE). If the id is not in the map, it constructs a generic prompt from the id and color.
How GPT generation works
For each palette entry (skipping SKY / #FF00FF tiles):
- Build a prompt:
"Pixel art game tile, flat seamlessly tileable surface texture: {desc}. {genre} game aesthetic. Seamlessly tileable, 16-bit retro pixel art, chunky well-defined pixels, clean sharp edges. No text, no characters, no HUD elements, no border frame." - Call
fal.run/openai/gpt-image-2atimage_size: { width: 512, height: 512 },quality: low(configurable). - Downscale the 512×512 result to
tileSize × tileSize(default 32) usingsharp. - Copy into position
i * tileSizein the horizontal output strip. - If the call fails, paint the solid
colorvalue for that tile (no crash).
SKY tiles are filled with solid magenta (#FF00FF) — Game.js hides them via setAlpha(0) so the parallax background shows through.
Output
public/assets/tiles.png— horizontal strip:(tileSize × numTiles) × tileSizepixels, one tile per palette entry.- Manifest entry under
tiles:
{
"tiles": {
"relSheet": "assets/tiles.png",
"tileSize": 32,
"ids": ["SKY", "STONE", "BRICK", "SPIKE", "LADDER"],
"passable": [true, false, false, true, true]
}
}ids[i] and passable[i] both correspond to tile index i in any level's tiles[][] array.
Implementation
The core function is generateTilesetGPT() in src/lib/sprites.js. It is called by scripts/gen_game.mjs for all example games. For agent-driven pipeline use, invoke it from codesmith or a custom orchestration script:
import { generateTilesetGPT } from '../src/lib/sprites.js';
const tileset = await generateTilesetGPT({
palette: gdd.tilesetPalette, // array of { id, color, passable, desc? }
outPath: 'public/assets/tiles.png',
tileSize: 32,
genre: gdd.genre, // added to each tile prompt for style coherence
tagline: gdd.tagline, // added to each tile prompt
quality: 'low', // low | medium | high
log: console.log,
});
// → { sheet, tileSize, ids }Fallback scripts (kept for reference / standalone use):
scripts/paint_tiles.mjs <project-dir>— procedural flat-color strip, no API key needed.scripts/generate_tiles_gpt.mjs <project-dir> [--quality low]— thin CLI wrapper aroundgenerateTilesetGPT.
Dependencies
sharp— raw RGBA buffer → PNG, resize.FAL_KEYin env or~/.all-skills/.env— for GPT Image 2 calls. Falls back gracefully if missing.
Why GPT tiles look better than procedural
Procedural tiles are obviously synthetic — flat green for grass, flat brown for dirt. GPT Image 2 produces texture variation: grass blades, dirt speckles, brick mortar lines, pipe rivets. At 32×32 the detail reads clearly. Combined with bg-artist's parallax background, the visual quality jumps from "tech demo" to "real game".
Transparent SKY trick
For platformers and action games, the first palette entry is { id: "SKY", color: "#FF00FF", passable: true }. The tile artist fills it with solid magenta. In Game.js:
const skyIdx = manifest.tiles.ids.indexOf('SKY');
if (skyIdx >= 0) {
this._tileLayer.forEachTile(t => { if (t.index === skyIdx) t.setAlpha(0); });
}This makes the sky tile invisible, letting the bg-artist background show through — no extra draw calls, no extra texture.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

