Back to Essays

Beyond Scripted: Giving NPCs Real Personality

July 25, 20256 min read

Exploring how large language models can create NPCs that feel genuinely alive, with their own goals, fears, and quirks.

"I used to be an adventurer like you, then I took an arrow in the knee."

We've all heard it. A thousand times. In every city. From every guard. It became a meme not because it was funny, but because it revealed how painfully robotic our NPCs have been.

But what if that guard had a name? What if he remembered you? What if, three quests later, you found him drunk in a tavern, crying about his lost dreams of adventure?

The Personality Revolution

Large language models have given us something unprecedented: the ability to create NPCs with actual personality. Not just dialogue trees with branches, but characters with:

  • Memory: They remember what you did, what you said, and how you treated them
  • Goals: They want things beyond giving you quests
  • Relationships: They form opinions about you and each other
  • Growth: They change based on their experiences

The Old Way vs. The New Way

Traditional NPC Design

const guard = {
  dialogue: [
    "Welcome to Whiterun",
    "I used to be an adventurer like you...",
    "No lollygagging",
    "Wait, I know you..."
  ],
  getResponse: function() {
    return this.dialogue[Math.floor(Math.random() * this.dialogue.length)];
  }
};

Personality-Driven NPCs

class Guard {
  constructor(name) {
    this.name = name;
    this.memories = new MemorySystem();
    this.personality = {
      bravery: Math.random(),
      humor: Math.random(),
      loyalty: Math.random(),
      cynicism: Math.random()
    };
    this.backstory = generateBackstory(this.personality);
    this.currentMood = 'neutral';
    this.relationships = new Map();
  }
  
  interact(player, context) {
    const memory = this.memories.recall(player);
    const relationship = this.relationships.get(player.id) || 0;
    const mood = this.evaluateMood(context);
    
    return generateResponse({
      personality: this.personality,
      memory: memory,
      relationship: relationship,
      mood: mood,
      context: context
    });
  }
}

The Three Pillars of NPC Personality

1. Consistent Inconsistency

Real people aren't perfectly consistent. They have bad days, change their minds, and act out of character. Your NPCs should too:

  • A normally cheerful merchant who's grumpy because their shipment is late
  • A brave knight who's terrified of spiders
  • A wise sage who gives terrible advice about relationships

2. Personal Stakes

Every NPC should want something that has nothing to do with the player:

  • The blacksmith saving money to send his daughter to wizard school
  • The innkeeper trying to win back their ex
  • The guard captain dealing with a corruption scandal

These desires should influence how they interact with the player. Maybe the blacksmith offers better prices if you help with their daughter's tuition.

3. Dynamic Relationships

NPCs shouldn't exist in isolation. They should have opinions about each other:

// NPCs gossiping about the player
npc1.tell(npc2, "The hero helped me yesterday!");
npc2.adjustOpinion(player, +10);
npc2.addMemory("Heard good things about the hero from " + npc1.name);
 
// Next time you meet npc2:
"Oh, you're the one Martha was talking about! She said you helped her out."

Real Examples That Almost Get It Right

The Forgotten City

Every NPC has a full daily routine, relationships, and secrets. The game is built on understanding these personalities and how they interact.

Disco Elysium

Your internal voices have more personality than most games' main characters. They bicker, disagree, and develop over time.

Hades

Characters remember everything. Hundreds of contextual dialogue lines create the illusion of real relationships evolving over time.

The LLM Advantage

With large language models, we can now:

Generate Unique Dialogue in Real-Time

const response = await generateNPCDialogue({
  npc: "Gruff Blacksmith",
  personality: "Sarcastic but kind-hearted",
  context: "Player just sold them a rusty sword",
  memory: "Player previously bought their best armor",
  mood: "Amused"
});
 
// "Another 'ancient relic' from a tomb, eh? At least you 
// bought quality from me last time. Tell you what, since 
// you're good for business, I'll give you 10 gold for this 
// tetanus dispenser."

Create Emergent Backstories

Let NPCs generate their own histories based on their experiences:

  • An NPC who becomes a merchant after you save their caravan
  • A former enemy who becomes a philosopher after defeat
  • A child NPC who grows up to be a knight inspired by you

Enable Real Conversations

Not dialogue trees, but actual conversations where:

  • NPCs can be convinced or deceived
  • They form opinions based on what you say
  • They remember lies and call you out later

The Technical Challenge

Creating personality-driven NPCs isn't trivial. You need:

Memory Management

class MemorySystem {
  constructor(capacity = 100) {
    this.memories = [];
    this.capacity = capacity;
  }
  
  add(memory) {
    this.memories.push({
      ...memory,
      timestamp: Date.now(),
      importance: this.calculateImportance(memory)
    });
    
    this.prune();
  }
  
  recall(trigger) {
    return this.memories
      .filter(m => this.isRelevant(m, trigger))
      .sort((a, b) => b.importance - a.importance)
      .slice(0, 5);
  }
  
  prune() {
    if (this.memories.length > this.capacity) {
      // Keep important memories, forget mundane ones
      this.memories.sort((a, b) => b.importance - a.importance);
      this.memories = this.memories.slice(0, this.capacity);
    }
  }
}

Personality Persistence

NPCs need to maintain their personality across sessions while still being able to grow and change.

Performance Optimization

Generating responses for hundreds of NPCs in real-time requires clever caching and prioritization.

The Uncanny Valley of Personality

There's a danger here. NPCs that are almost human can be more disturbing than obviously robotic ones. The key is to lean into the artificiality:

  • Let NPCs be aware they're in a game sometimes
  • Give them impossible quirks (a merchant who only speaks in rhymes)
  • Make their limitations part of their character

Best Practices for Personality Design

Start with Archetypes, Then Subvert

  • The gruff blacksmith who writes poetry
  • The wise elder who's terrible at giving directions
  • The villain who's genuinely trying to help (badly)

Give Them Failure States

  • NPCs who give up on their dreams
  • Relationships that deteriorate
  • Character growth that goes backward

Make Them Petty

  • The merchant who charges you extra because you ignored them
  • The guard who "forgets" to open the gate because you were rude
  • The quest-giver who sends you to the dangerous route because you rushed them

The Future: AI Dungeon Masters

Imagine NPCs that can:

  • Generate their own quests based on their needs
  • Form factions and alliances dynamically
  • Create emergent storylines without developer input
  • Remember players across different games

We're not far from this future. The technology exists. We just need developers brave enough to use it.

Call to Action

Next time you're designing NPCs, ask yourself:

  • What does this character want that has nothing to do with the player?
  • How would they react if the player never showed up?
  • What would make them change their mind about something?

Stop creating quest dispensers. Start creating people.

Even if those people are sometimes annoying, irrational, and wonderfully, beautifully flawed.


Because the best NPCs aren't the ones who always have the perfect quest for you. They're the ones who sometimes tell you to come back tomorrow because they're having a bad day.

Tags

AINPCsLLMsCharacter DesignNarrative