Background Artist
Generates a single PNG that the Phaser runtime renders behind the tilemap with a scrollFactor < 1 for parallax. Pure deterministic helper plus one GPT Image 2 call.
When to use
After game-designer produces a GDD. Whenever the genre + theme benefit from a backdrop:
- platformer / action-platformer / dungeon-crawler / shoot-em-up: yes (sky, cave, space)
- beat-em-up: yes — layered street/park/forest background is essential for visual quality
- top-down-adventure: usually no (the tilemap fills the view)
- puzzle / abstract: optional
The orchestrator decides; the skill exposes the deterministic call.
Output
public/assets/bg.png — single image, no transparency
- Manifest field merged into
public/assets/manifest.json:
{
"bg": {
"relPath": "assets/bg.png",
"scrollFactor": 0.3 // 0 = locked to camera, 1 = locked to world; ~0.2-0.4 = subtle parallax
}
}
The Phaser template's Preload scene loads bg automatically when this manifest field is present. Game.js adds it as add.image(...).setDepth(-100) and applies the scrollFactor.
Default themes
| Genre |
Theme |
Prompt skeleton |
| platformer / action-platformer |
outdoor-day |
Soft pastel sky, fluffy clouds, distant green rolling hills silhouetted in 3 depth layers |
| platformer / action-platformer |
outdoor-night |
Deep blue night sky, large full moon, mountain range silhouetted in 2 layers, scattered stars |
| action-platformer |
dungeon |
Dark damp stone dungeon interior, crumbling brick walls receding into shadows, faint torch glow on side walls, no characters |
| dungeon-crawler |
cave |
Rough cave walls with stalactites, faint bioluminescent moss patches, distant dark tunnel, atmospheric blue-green tint |
| shoot-em-up |
space |
Deep blue-black space, star field with 3 brightness levels, 1-2 colourful distant nebulae, no planets in foreground |
| beat-em-up |
forest-park |
3 depth layers: far = muted blue-grey sky + canopy silhouettes; mid = orange-brown tree trunks + fence; near = dirt ground strip. NES Double Dragon color palette. No characters or UI. |
| beat-em-up |
city-street |
Far = dark grey building facades with lit windows; mid = parked cars / dumpsters silhouetted; near = sidewalk strip. Urban night palette. |
| beat-em-up |
warehouse |
Industrial brick walls with high windows; dim overhead light pools; stacked crates silhouetted in mid distance. |
| top-down-adventure |
(none — uses tilemap fill) |
n/a |
Process
- Read
gdd.genre and levelHints.themes[0] from game-state.json.
- Pick a prompt template (above) and fill in the theme.
- POST to GPT Image 2 with
quality: low, dimensions ~1280×768 (16:10, well within FAL/OpenAI constraints).
- Downscale to ~480×288 with sharp using
kernel: 'nearest' to preserve pixel-art crispness.
- Save to
public/assets/bg.png.
- Merge
bg field into manifest.json.
- Update
game-state.json assets.bg reference.
Hard rules for prompts
- Always 8-bit pixel art style, chunky pixels, no anti-aliasing.
- No characters, no foreground objects, no text, no UI, no borders. The bg is a backdrop only.
- Vivid clean colors that complement the player sprite without competing.
- Aspect ratio close to 16:10 or 16:9; avoids the 3:1 cap.
Scripts
scripts/generate_bg.mjs <project-dir> [--theme outdoor-day|outdoor-night|cave|space] [--quality low|medium|high]
References
references/themes.md — full per-theme prompt templates
../sprite-artist/references/gpt-image-2.md — endpoint/auth/constraints (shared with sprite-artist)
Why parallax instead of a static fill
A scrollFactor: 0 background is fine but feels "stuck on" to the camera. 0.2-0.4 makes the world feel deeper as the camera moves — clouds appear to drift relative to terrain — for free. The trade-off: with very large levels the bg image has to tile or stretch; we stretch via setDisplaySize(worldW, worldH) which works well for short levels and acceptably for longer ones.
1---2name: bg-artist3description: Generates a parallax background image (sky, hills, cave interior, space, etc.) for a Phaser game using GPT Image 2 (gpt-image-2). The Phaser runtime treats this as an optional layer that scrolls slower than the world, providing depth without consuming gameplay collision. Use after game-designer if the genre benefits from a scenic backdrop.4---56# Background Artist78Generates a single PNG that the Phaser runtime renders behind the tilemap with a `scrollFactor < 1` for parallax. Pure deterministic helper plus one GPT Image 2 call.910## When to use1112After `game-designer` produces a GDD. Whenever the genre + theme benefit from a backdrop:13- platformer / action-platformer / dungeon-crawler / shoot-em-up: yes (sky, cave, space)14- beat-em-up: yes — layered street/park/forest background is essential for visual quality15- top-down-adventure: usually no (the tilemap fills the view)16- puzzle / abstract: optional1718The orchestrator decides; the skill exposes the deterministic call.1920## Output2122- `public/assets/bg.png` — single image, no transparency23- Manifest field merged into `public/assets/manifest.json`:2425```jsonc26{27 "bg": {28 "relPath": "assets/bg.png",29 "scrollFactor": 0.3 // 0 = locked to camera, 1 = locked to world; ~0.2-0.4 = subtle parallax30 }31}32```3334The Phaser template's `Preload` scene loads `bg` automatically when this manifest field is present. `Game.js` adds it as `add.image(...).setDepth(-100)` and applies the `scrollFactor`.3536## Default themes3738| Genre | Theme | Prompt skeleton |39|---|---|---|40| platformer / action-platformer | outdoor-day | Soft pastel sky, fluffy clouds, distant green rolling hills silhouetted in 3 depth layers |41| platformer / action-platformer | outdoor-night | Deep blue night sky, large full moon, mountain range silhouetted in 2 layers, scattered stars |42| action-platformer | dungeon | Dark damp stone dungeon interior, crumbling brick walls receding into shadows, faint torch glow on side walls, no characters |43| dungeon-crawler | cave | Rough cave walls with stalactites, faint bioluminescent moss patches, distant dark tunnel, atmospheric blue-green tint |44| shoot-em-up | space | Deep blue-black space, star field with 3 brightness levels, 1-2 colourful distant nebulae, no planets in foreground |45| beat-em-up | forest-park | 3 depth layers: far = muted blue-grey sky + canopy silhouettes; mid = orange-brown tree trunks + fence; near = dirt ground strip. NES Double Dragon color palette. No characters or UI. |46| beat-em-up | city-street | Far = dark grey building facades with lit windows; mid = parked cars / dumpsters silhouetted; near = sidewalk strip. Urban night palette. |47| beat-em-up | warehouse | Industrial brick walls with high windows; dim overhead light pools; stacked crates silhouetted in mid distance. |48| top-down-adventure | (none — uses tilemap fill) | n/a |4950## Process51521. Read `gdd.genre` and `levelHints.themes[0]` from `game-state.json`.532. Pick a prompt template (above) and fill in the theme.543. POST to GPT Image 2 with `quality: low`, dimensions ~1280×768 (16:10, well within FAL/OpenAI constraints).554. Downscale to ~480×288 with sharp using `kernel: 'nearest'` to preserve pixel-art crispness.565. Save to `public/assets/bg.png`.576. Merge `bg` field into `manifest.json`.587. Update `game-state.json` `assets.bg` reference.5960## Hard rules for prompts6162- Always 8-bit pixel art style, chunky pixels, no anti-aliasing.63- No characters, no foreground objects, no text, no UI, no borders. The bg is a backdrop only.64- Vivid clean colors that complement the player sprite without competing.65- Aspect ratio close to 16:10 or 16:9; avoids the 3:1 cap.6667## Scripts6869- `scripts/generate_bg.mjs <project-dir> [--theme outdoor-day|outdoor-night|cave|space] [--quality low|medium|high]`7071## References7273- `references/themes.md` — full per-theme prompt templates74- `../sprite-artist/references/gpt-image-2.md` — endpoint/auth/constraints (shared with sprite-artist)7576## Why parallax instead of a static fill7778A `scrollFactor: 0` background is fine but feels "stuck on" to the camera. `0.2-0.4` makes the world feel deeper as the camera moves — clouds appear to drift relative to terrain — for free. The trade-off: with very large levels the bg image has to tile or stretch; we stretch via `setDisplaySize(worldW, worldH)` which works well for short levels and acceptably for longer ones.