The Immersion Engine: Turning AI Prose Into Game State
How RoleCall's 27 reactive trackers turn narrative text into combat encounters, relationship meters, inventory, and a living world — all driven by AI directives.
Most AI roleplay apps are chat interfaces. You type, the AI types back. The "game" lives entirely in the text.
RoleCall looks different. When combat starts, a battle tracker appears with enemy HP bars and turn order. When you befriend an NPC, a relationship meter ticks up. When you find a sword, it appears in your inventory. When you travel, the map updates. None of this is scripted — it's all emergent, driven by the AI's narrative output.
We call this the Immersion Engine. It's a system of 27+ reactive state trackers that turn AI-generated prose into structured game mechanics — in real time, with no manual input from the user.
The core loop: directives in, game state out
The DM (our story director AI) doesn't just plan narrative — it emits structured ImmersionDirective objects alongside its story guidance. These directives are typed JSON that describe game state changes:
{
combat: {
inCombat: true,
enemies: [
{ name: "Shadow Beast", hp: 80, maxHp: 100, threat: "high" }
],
turnOrder: ["player", "Shadow Beast"]
},
relationships: [
{ npcName: "Marcus", affinityDelta: -10, reason: "You refused to help" }
],
resources: { hpDelta: -15, reason: "Shadow Beast clawed you" },
knowledge: [
{ type: "add", subject: "Shadow Beasts",
content: "Vulnerable to fire", reliability: "suspects" }
]
}
One turn. Four systems updated. The user sees a combat tracker appear, Marcus's disposition shift, their HP drop, and a new lore entry — all because the DM decided these things happened in the story.
The flow is unidirectional: DM generates directives → parser converts them → Zustand stores update → React components re-render. No polling, no manual triggers. When the DM says combat starts, combat starts.
The 27 trackers
Each tracker is an independent Zustand store managing a specific domain. They're modular — you can enable or disable systems per campaign. Here's the full roster:
Core mechanics
Battle Tracker — combat encounters with tracked enemies (HP, threat level, boss flag, status effects), turn order, a combat log, and a built-in dice roller that parses expressions like 2d6+3.
Resources — player vitals: HP, MP, AP, Shield. Plus XP with leveling, currency, and survival needs. Tracks change history so the UI can show "+15 HP" animations.
Status Effects — buffs and debuffs with duration parsing ("30min" → milliseconds), stat modifiers, and per-minute drains/regens. Smart effect guessing: if the DM says "Poisoned" without specifying mechanics, the system auto-applies -1 HP/min based on name patterns.
Inventory — items by rarity (common through unique) and category, with equipment slots (main hand, off hand, head, body, hands, feet, neck, two rings, back). Stacking, sorting, rarity-colored borders.
Social systems
Relationships — NPC affinity on a 0-100 scale, mapping to dispositions: Hostile (0-10) → Wary → Cold → Neutral → Warm → Friendly → Devoted (91-100). Each NPC tracks memories with emotional impact, a 7-point chemistry radar, and Sims-style needs.
Artifact — in-world messaging. NPCs can text you, call you, send alerts. The device adapts to the world type: a Whisperstone in fantasy, a DataPad in sci-fi, a Cursed Relic in horror. Typing indicators, contact lists, the works.
Gossip — rumor spread mechanics. Gossip has belief levels (certain → skeptical), spread status (spreading/dormant/mutating), truth branches tracking how rumors diverge from fact, and natural decay rates.
Memory Journal — NPC-specific memories organized by category: interactions, promises, betrayals, gifts, shared experiences. The DM writes these as events happen — they're the NPC's actual recollection.
Progression
Quests — active/completed/failed/abandoned with typed objectives, progress tracking, quest chains, and linked NPCs. Quest types: main, side, hidden, urgent, daily, event.
Map — discovered locations as points of interest, current position, scene context (time of day, weather, atmosphere, present NPCs). Procedurally seeded from the world description.
Knowledge — lore entries tagged by reliability: certain, believes, suspects, uncertain, wrong. Because in a roleplay, not everything the player "knows" is actually true.
Spellbook — spells by status (learned/observed/theoretical), template (attack/buff/heal/summon/ritual), with casting costs and success history.
Advanced systems
Corruption — five metrics from 0-100: corruption, submission, dependence, obsession, identity loss. Tracks milestone thresholds for narrative consequences.
Parallel Events — world events happening independently with urgency levels. The player can intervene or let them resolve on their own.
Bonds — supernatural connections with intensity levels (faint → absolute) and type-specific mechanical effects.
Biological Cycles — fertility, pregnancy with week-by-week tracking and trimester data, lunar-tied emotional states.
Creature Codex — a bestiary with species entries, individual instances, ecology notes, taming data, and arcane properties.
Calendar — story time tracking with moons, zodiacs, celestial events, and seasonal progression.
The relationship system (in detail)
The relationship tracker deserves special attention because it's the system that makes NPCs feel alive. It goes far beyond a simple affinity number.
Chemistry metrics
Every NPC relationship tracks a 7-point chemistry radar:
- Intellectual Spark — how stimulating they find conversation with the player
- Emotional Resonance — how deeply they connect emotionally
- Physical Magnetism — physical attraction
- Sexual Tension — unresolved desire
- Personality Mesh — how well their personalities fit
- Life Compatibility — practical life alignment
- Goal Alignment — shared or conflicting objectives
Chemistry has a trend — rising, stable, declining, or volatile — that hints at where the relationship is heading.
NPC needs (Sims-style)
Different NPC archetypes have different needs:
| Archetype | Needs |
|---|---|
| Adult | Hunger, Energy, Morale, Social, Comfort, Stress |
| Pet | Hunger, Happiness, Energy, Loyalty, Grooming, Playfulness |
| Baby | Hunger, Comfort, Attention, Cleanliness, Warmth, Sleep |
| Familiar | Attunement, Essence, Loyalty, Mana, Awareness |
| Monster | Territory, Aggression, Hunger, Alertness, Pack Instinct |
The DM can update these needs each turn. A hungry NPC becomes irritable. A lonely NPC seeks the player out. An overstimulated pet hides. The needs don't just track numbers — they influence how the DM writes the NPC's behavior.
Scene presence
The relationship store tracks whether each NPC is currently in the scene — their location, attire, and current activity. When Valen is "at the tavern, wearing travel-worn leather, studying a map," the narrator knows to write him that way.
World-adaptive theming
The same tracker system looks different depending on the world type:
This isn't just cosmetic. The terminology changes: "Send Message" becomes "Commune" in fantasy, "Transmit" in sci-fi, "Whisper" in horror. The map labels change. The artifact device looks physically different. The entire UI language adapts to match the world, maintaining immersion.
The directive processing pipeline
When a DM response arrives with an immersion directive, it flows through a specific pipeline:
Processing order matters. Combat is processed first because it affects turn state. Resources second because HP changes might trigger "critical health" UI. Effects third because stat modifiers affect everything downstream. This ordering prevents flickering and ensures derived state is consistent.
Normalization
The parser handles the reality that AI output isn't always perfect:
- Affinity clamped to 0-100 (the DM might say +50 when the NPC is already at 80)
- Duration strings parsed into milliseconds (
"30min","2 hours","3 turns") - Stats coerced to numbers (the AI sometimes outputs strings)
- Duplicates deduplicated (the DM might mention the same enemy twice)
- Null/undefined gracefully handled everywhere
You can't trust AI output to be perfectly structured. The parser is the safety layer that turns "mostly right JSON" into "definitely correct state."
State persistence
Game state needs to survive across sessions — and handle the tricky case of message deletion. We use a snapshot system: each message stores an ImmersionStateSnapshot in its metadata, capturing the full tracker state at that point.
If a message is deleted or the user swipes to an alternative response, the system can restore state from the previous message's snapshot. No re-running the AI, no recalculating from history — just a clean restore from the saved checkpoint.
The DM's context also snapshots alongside: active arcs, pacing state, core memories, story health. This means the entire narrative + mechanical state can be rewound to any message in the conversation.
What makes it feel like a game
The technical architecture is interesting, but what matters is the experience. Here's what the user actually sees:
When combat starts — a battle panel slides in with enemy cards, HP bars with threat-colored borders, and a turn order tracker. A pulsing "IN COMBAT" badge appears. Suggested actions offer attack options.
When relationships change — a subtle animation shows "+5" or "-10" on the NPC's affinity bar. The disposition badge updates (Neutral → Warm). A new memory appears in their profile.
When items are found — a loot notification appears with the item's rarity color. The inventory updates. If it's equipment, the slot lights up.
When effects apply — a status icon appears with the buff/debuff name, colored by type (green for buffs, red for debuffs). A duration countdown ticks. Stat modifiers show in the resource panel.
None of this requires the user to do anything. They just play the story, and the game state materializes around them. The trackers appear when relevant and stay out of the way when they're not.
Cascading mechanics
The most satisfying moments happen when one directive triggers cascading effects across multiple systems:
A single relationship change with an NPC might:
- Update their affinity and disposition
- Trigger a gossip entry that spreads to other NPCs
- Shift a corruption metric if the NPC has that influence
- Advance a quest objective ("Gain Marcus's trust")
- Create a parallel event ("Marcus tells the guild about you")
- Update the NPC's needs (social need fulfilled)
The DM orchestrates all of this in one turn. The user sees a web of consequences from a single interaction — the world feeling like it actually responds to their choices.
What we learned
Modular stores over monolithic state. 27 independent Zustand stores sounds like a lot, but each one is small, focused, and independently testable. A monolithic game state object would have been a nightmare to maintain. Zustand's selective subscriptions mean components only re-render when their specific tracker changes.
Normalization is non-negotiable. AI output is approximate. It sends strings where you need numbers, values out of range, duplicate entries, missing fields. The parser layer that normalizes everything before it hits the stores saves an enormous amount of debugging downstream.
Processing order prevents flicker. When you update 7 stores from one directive, the order matters. Combat before resources before effects ensures the UI never shows an inconsistent intermediate state. We learned this the hard way — a brief flash of "0 HP" before the combat tracker appeared was not a good look.
World-adaptive theming sells the fantasy. Changing "Send Message" to "Commune" and making the phone look like a magical stone costs almost nothing in implementation but dramatically increases immersion. Users notice and care about these details far more than we expected.
The Immersion Engine is what makes RoleCall feel like a game rather than a chat app. The AI writes the story. The engine makes the story tangible.