5 min read

AI NPC Portrait Generation for Games: A Developer's Guide

How to generate identity-consistent NPC portraits for games using AI. Covers the technical pipeline, API integration, batch generation, and managing visual identity for hundreds of non-player characters.

game-devnpcuse-case

The NPC Portrait Problem

Every RPG, visual novel, and narrative game needs character portraits. Traditionally, this means hiring artists to draw each character — expensive, slow, and doesn't scale when you need hundreds of NPCs.

AI image generation seems like the obvious solution. But the standard approach — generating each portrait independently — creates a cast of characters that don't feel like they belong in the same world. Worse, if an NPC appears in multiple scenes (different locations, different times of day, different outfits), they look like a different person each time.

For named NPCs that players interact with repeatedly, this breaks immersion. The blacksmith you visited yesterday shouldn't look like a different person today.

What Game Developers Need

The requirements for game NPC portraits are specific:

  1. Identity consistency — The same NPC looks the same across all appearances
  2. Scene variation — The same NPC in their shop, at the tavern, during a quest
  3. Outfit changes — Armor for battle, casual clothes at home, formal wear at court
  4. Expression control — Happy when greeting, angry when threatened, sad during story beats
  5. Style consistency — All NPCs should feel like they belong in the same art style
  6. Batch generation — You need portraits for dozens or hundreds of characters

The Pipeline

Here's a practical pipeline for generating NPC portraits with consistent identity:

Phase 1: Create Identity Baselines

For each named NPC, generate a standardized identity reference:

import requests

API_KEY = "sk_live_YOUR_KEY"
BASE_URL = "https://www.aurashot.art"

def create_npc_baseline(face_url: str) -> str:
    """Generate a 4-in-1 ID photo as the NPC's identity anchor."""
    resp = requests.post(
        f"{BASE_URL}/v1/character/id-photo",
        headers={"Authorization": f"Bearer {API_KEY}"},
        json={"images": {"face": face_url}},
    )
    data = resp.json()
    return data["outputs"][0]["url"]

# Create baselines for your NPCs
npcs = {
    "blacksmith": create_npc_baseline("https://your-cdn.com/npc-faces/blacksmith.jpg"),
    "innkeeper": create_npc_baseline("https://your-cdn.com/npc-faces/innkeeper.jpg"),
    "merchant": create_npc_baseline("https://your-cdn.com/npc-faces/merchant.jpg"),
}

Phase 2: Generate Scene Variants

For each NPC, generate the portraits you need for different game contexts:

def generate_npc_portrait(npc_id_photo: str, scene_prompt: str) -> str:
    """Generate an NPC portrait in a specific scene."""
    resp = requests.post(
        f"{BASE_URL}/v1/character/generate",
        headers={"Authorization": f"Bearer {API_KEY}"},
        json={
            "prompt": scene_prompt,
            "images": {"face": npc_id_photo},
        },
    )
    return resp.json()["outputs"][0]["url"]

# Generate the blacksmith in different contexts
blacksmith_portraits = {
    "shop": generate_npc_portrait(
        npcs["blacksmith"],
        "standing in a medieval blacksmith shop, leather apron, holding a hammer, warm forge light"
    ),
    "tavern": generate_npc_portrait(
        npcs["blacksmith"],
        "sitting at a wooden tavern table, casual clothes, holding a mug of ale, evening candlelight"
    ),
    "battle": generate_npc_portrait(
        npcs["blacksmith"],
        "wearing plate armor, serious expression, battlefield background, dramatic lighting"
    ),
}

Same face in every portrait. Different scene, outfit, and mood.

Phase 3: Expression Variants

For dialogue systems, you often need the same scene with different expressions:

expressions = {
    "neutral": "neutral expression, calm",
    "happy": "warm smile, friendly eyes",
    "angry": "furrowed brows, stern expression",
    "sad": "downcast eyes, melancholy expression",
    "surprised": "wide eyes, raised eyebrows",
}

blacksmith_shop_expressions = {}
for expr_name, expr_prompt in expressions.items():
    blacksmith_shop_expressions[expr_name] = generate_npc_portrait(
        npcs["blacksmith"],
        f"standing in a medieval blacksmith shop, leather apron, {expr_prompt}, warm forge light"
    )

Batch Generation Script

For production, you'll want to batch-generate all NPC portraits:

import json
import time

def batch_generate_npc_portraits(npc_config: dict) -> dict:
    """
    npc_config format:
    {
        "blacksmith": {
            "face": "https://...",
            "scenes": {
                "shop": "standing in a blacksmith shop...",
                "tavern": "sitting at a tavern table..."
            }
        }
    }
    """
    results = {}

    for npc_name, config in npc_config.items():
        print(f"Processing {npc_name}...")

        # Step 1: Create identity baseline
        id_photo = create_npc_baseline(config["face"])
        results[npc_name] = {"id_photo": id_photo, "portraits": {}}

        # Step 2: Generate each scene
        for scene_name, prompt in config["scenes"].items():
            portrait_url = generate_npc_portrait(id_photo, prompt)
            results[npc_name]["portraits"][scene_name] = portrait_url
            time.sleep(1)  # Rate limiting

    return results

# Save results for your asset pipeline
with open("npc_portraits.json", "w") as f:
    json.dump(results, f, indent=2)

Art Style Consistency

To keep all NPCs in the same visual style, include style directives in every prompt:

STYLE_PREFIX = "fantasy RPG art style, painterly, warm color palette, "

def generate_styled_portrait(npc_id_photo: str, scene_prompt: str) -> str:
    return generate_npc_portrait(npc_id_photo, STYLE_PREFIX + scene_prompt)

For anime-style games, adjust the prefix:

STYLE_PREFIX = "anime art style, cel shading, vibrant colors, "

The face reference maintains identity. The style prefix maintains visual cohesion across your entire cast.

Integration with Game Engines

The generated portraits are standard image URLs. Download them into your asset pipeline:

import urllib.request

def download_portrait(url: str, local_path: str):
    urllib.request.urlretrieve(url, local_path)

# Download into your Unity/Godot/Unreal asset folder
download_portrait(
    blacksmith_portraits["shop"],
    "Assets/Portraits/blacksmith_shop.png"
)

For games with dynamic content (procedurally generated NPCs), you can call the API at runtime — but pre-generation during loading screens or between scenes is usually better for player experience.

Cost Planning

Portrait generation costs per image. Plan your budget based on:

  • Named NPCs × scenes × expressions = total portraits needed
  • A game with 20 named NPCs, 4 scenes each, 5 expressions = 400 portraits
  • AuraShot Max plan: 1600 images/month at $59.9 — covers initial generation plus iteration

For indie games, the Pro plan (200 images/month at $7.9) is enough for prototyping and small casts.

Compared to Traditional Art

| Factor | Traditional Art | AI Generation | |--------|----------------|---------------| | Cost per portrait | $20-100+ | ~$0.04-0.30 | | Time per portrait | Hours to days | Seconds | | Identity consistency | Depends on artist | Automatic (face-anchored) | | Iteration speed | Slow (revision cycles) | Instant (re-generate) | | Style consistency | Depends on artist | Prompt-controlled | | Scalability | Linear cost increase | Marginal cost near zero |

AI generation doesn't replace concept artists for hero characters, but it's transformative for populating a world with hundreds of consistent NPCs.

Getting Started

  1. Get a free API key — 5 images to test the pipeline
  2. Create face references for 2-3 test NPCs
  3. Generate ID photos as identity baselines
  4. Generate scene variants and verify consistency
  5. Scale to your full NPC cast

The API is stateless — you manage your NPC data and portraits in your own asset pipeline. AuraShot just generates the images.

Ready to give your AI agent a face?

AI NPC Portrait Generation for Games: A Developer's Guide | AuraShot