<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Narrative Sim</title><description>Narrative Sim makes small narrative games where the AI is a mechanic, not a chatbot. Play the prototypes and read the thinking behind them.</description><link>https://narrativesim.com/</link><item><title>sharing memories with NPCs</title><link>https://narrativesim.com/blog/sharing-memories-with-npcs/</link><guid isPermaLink="true">https://narrativesim.com/blog/sharing-memories-with-npcs/</guid><description>npc memory shares</description><pubDate>Sat, 29 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;[interactive block — &lt;a href=&quot;/blog/&quot;&gt;read it on the site&lt;/a&gt;]&lt;/em&gt;&lt;/p&gt;
</content:encoded></item><item><title>A Budget of Consequence</title><link>https://narrativesim.com/blog/a-budget-of-consequence/</link><guid isPermaLink="true">https://narrativesim.com/blog/a-budget-of-consequence/</guid><description>Why I hand the AI a short, pre-approved menu of things it is allowed to do to you, and never a blank check.</description><pubDate>Thu, 27 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;A playtester spent a conversation needling an innkeeper. Third jab about her cooking, and she told them to sleep somewhere else tonight. For the rest of that in-game evening, the common room was actually closed to them.&lt;/p&gt;
&lt;p&gt;I did not script that outcome. I also did not let the AI reach in and decide it on its own. The truth is in between.&lt;/p&gt;
&lt;h3&gt;The blank check problem&lt;/h3&gt;
&lt;p&gt;If a language model can change the world just by asserting it, eventually it will, and not always in ways you would sign off on. It will be inconsistent between runs, and players will learn to talk it into things. &quot;Actually, you already gave me the key&quot; is not a sentence you want to be load-bearing.&lt;/p&gt;
&lt;p&gt;I have written about &lt;a href=&quot;/blog/semantic-state-interpretation/&quot;&gt;turning dialogue into real mechanics&lt;/a&gt;. This post is about the step before that: deciding what a character is even &lt;em&gt;allowed&lt;/em&gt; to do to you in the first place.&lt;/p&gt;
&lt;h3&gt;The menu&lt;/h3&gt;
&lt;p&gt;Before a conversation, the engine works out a short list of consequences that would make sense right now. It weighs who this NPC is, how much authority they actually have, whose ground you are standing on, and how the encounter is going.&lt;/p&gt;
&lt;p&gt;A field hand cannot bar you from anywhere. An innkeeper can close her own inn to you and nothing else. A guard can decide you are worth keeping an eye on.&lt;/p&gt;
&lt;p&gt;The model receives that menu and a rough budget. It can spend nothing. It can pick one thing. It cannot invent a new option that was not on the list.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;right now this NPC can:
  - refuse to serve you
  - ask you to leave for tonight
  - remember this as an insult

budget: enough for one real consequence
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;The engine still gets the last word&lt;/h3&gt;
&lt;p&gt;The model proposes; the engine checks the choice still makes sense in the half-second since the menu was drawn, and then applies it. There are caps on how far a single conversation can move things. Everything is written down. The innkeeper&apos;s ban lifts on its own after a while.&lt;/p&gt;
&lt;h3&gt;What it feels like to play&lt;/h3&gt;
&lt;p&gt;Conversations get weight. You can feel when one is load-bearing before it goes wrong.&lt;/p&gt;
&lt;p&gt;And when it does go wrong, it is legible afterward. You know exactly which line cost you the room. Because the menu is short and hand-built, the world stays coherent in the other direction too: nobody signs over a title deed because you were charming for ninety seconds.&lt;/p&gt;
</content:encoded></item><item><title>NPCs Who Remember That One Time</title><link>https://narrativesim.com/blog/npcs-who-remember/</link><guid isPermaLink="true">https://narrativesim.com/blog/npcs-who-remember/</guid><description>Reputation you never see as a number. Just people who treat you differently than they did last week.</description><pubDate>Thu, 20 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;A playtester came back to a district they had not visited in a few in-game days. A guard who had waved them through before now stopped them, asked where they were headed, and looked in their bag.&lt;/p&gt;
&lt;p&gt;The playtester sighed and said, &quot;he is still mad about the gate thing.&quot; I had never told them a &quot;gate thing&quot; was being tracked. It just was.&lt;/p&gt;
&lt;h3&gt;No reputation bar&lt;/h3&gt;
&lt;p&gt;Most games hand you a meter and let you manage it. I do not show one, because a single number is not how people actually hold a grudge. Grudges are specific, they are personal, and they fade at different speeds depending on what caused them.&lt;/p&gt;
&lt;p&gt;So instead of a global score, each NPC carries their own sense of you. The innkeeper&apos;s opinion and the guard&apos;s opinion are separate things, and neither of them is a slider you can watch move.&lt;/p&gt;
&lt;h3&gt;How it reaches the conversation&lt;/h3&gt;
&lt;p&gt;When you talk to someone, the engine gives the model a short read on where you stand with &lt;em&gt;that&lt;/em&gt; person. Warm. Wary. Owes you a favor. Has not forgiven you yet. It does not replay your whole history; it just sets the temperature.&lt;/p&gt;
&lt;p&gt;The model does the rest. The guard does not read your rap sheet aloud. He is simply short with you, and searches the bag he would have waved past a week ago.&lt;/p&gt;
&lt;h3&gt;It fades, and it spreads&lt;/h3&gt;
&lt;p&gt;Some of it cools off on its own. Some of it does not. And some of it travels: the guard mentions it to the other guard, and now you are dealing with two people who have heard a version of the same story. That second part deserves its own post.&lt;/p&gt;
&lt;h3&gt;What it feels like to play&lt;/h3&gt;
&lt;p&gt;You cannot grind reputation, because there is no bar to grind. You just end up with a history with people, the same way you do anywhere.&lt;/p&gt;
&lt;p&gt;Walking back into a place you left on bad terms feels different, and you cannot un-feel it. The upside runs the same direction: sometimes someone you helped weeks ago greets you like an old friend before you have quite placed their face.&lt;/p&gt;
</content:encoded></item><item><title>The Blacksmith Smelled the Mushroom</title><link>https://narrativesim.com/blog/the-blacksmith-smelled-the-mushroom/</link><guid isPermaLink="true">https://narrativesim.com/blog/the-blacksmith-smelled-the-mushroom/</guid><description>My NPCs react to things I never wrote a line of dialogue for, because the engine is the one paying attention.</description><pubDate>Thu, 13 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;During a playtest last week, my blacksmith Garth stopped mid-swing, wrinkled his nose, and told the player to take &quot;that glowing rot&quot; outside before it ruined his steel.&lt;/p&gt;
&lt;p&gt;I never wrote that line. I never wrote a rule that says &quot;blacksmiths dislike mushrooms.&quot; What happened is smaller and, I think, more interesting.&lt;/p&gt;
&lt;h3&gt;What the NPC actually notices&lt;/h3&gt;
&lt;p&gt;When you walk up to someone in one of my games, the engine assembles a small snapshot of the moment: a few things you are carrying, what the NPC was busy doing, roughly what time it is, and how they feel about you already.&lt;/p&gt;
&lt;p&gt;The important word is &lt;em&gt;small&lt;/em&gt;. It is not &quot;here is everything true about the world.&quot; It is closer to &quot;here are the four or five things a person in this spot would actually clock.&quot; Garth noticed the smell, noticed he had been interrupted, and noticed his patience was already thin that morning.&lt;/p&gt;
&lt;h3&gt;The engine decides, the model phrases&lt;/h3&gt;
&lt;p&gt;Garth did not &lt;em&gt;choose&lt;/em&gt; to be annoyed. The engine did. The item crossed a line, his mood was low, and the result was a grumpy blacksmith.&lt;/p&gt;
&lt;p&gt;The language model&apos;s entire job was to take &quot;annoyed, interrupted, something here reeks&quot; and turn it into something Garth would plausibly say. I have written before about &lt;a href=&quot;/blog/llms-as-mechanics/&quot;&gt;treating the model like a renderer&lt;/a&gt; rather than a decision-maker, and this is that idea doing ordinary work.&lt;/p&gt;
&lt;h3&gt;Why not just script it&lt;/h3&gt;
&lt;p&gt;Because the branches do not exist to be written. Item times mood times current activity times relationship times location is not a dialogue tree, it is a fog. You cannot author your way through it. But you &lt;em&gt;can&lt;/em&gt; describe a single moment accurately and let the wording be generated fresh each time.&lt;/p&gt;
&lt;h3&gt;What it feels like to play&lt;/h3&gt;
&lt;p&gt;The world feels like it is watching. Playtesters start doing things just to find out who reacts: walking into a shop soaking wet, showing up somewhere at three in the morning, wearing the wrong colors into the wrong tavern.&lt;/p&gt;
&lt;p&gt;Most of those little reactions do not change the plot. They just make the place feel inhabited by people who have their own bad mornings.&lt;/p&gt;
</content:encoded></item><item><title>Turning NPC conversation logs into readable devlog posts</title><link>https://narrativesim.com/blog/posting-conversations-with-mdx/</link><guid isPermaLink="true">https://narrativesim.com/blog/posting-conversations-with-mdx/</guid><description>The game exports every conversation as JSON. Here is how I get those onto the devlog without reformatting a thing.</description><pubDate>Mon, 11 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Every conversation in the game gets logged as structured JSON: who was there, what each line was, and any context the engine fed the model. When something funny or revealing happens in a playtest, I want it on the devlog. The question was how, without it becoming a chore.&lt;/p&gt;
&lt;h3&gt;The options I did not take&lt;/h3&gt;
&lt;p&gt;A screenshot is the obvious move, and it is the worst one. You cannot read it on a phone, a screen reader gets nothing, and you cannot copy a line out of it to quote later.&lt;/p&gt;
&lt;p&gt;Hand-formatting each transcript as Markdown blockquotes is the other obvious move. It works, but every post ends up slightly different, and you lose the visual difference between the player talking, an NPC talking, and the engine&apos;s internal notes.&lt;/p&gt;
&lt;h3&gt;MDX does the boring part&lt;/h3&gt;
&lt;p&gt;This site&apos;s posts are not Markdown files, they are &lt;strong&gt;MDX&lt;/strong&gt; files. MDX is Markdown that can also import and render components. Astro&apos;s content collections are happy to treat an &lt;code&gt;.mdx&lt;/code&gt; file as a blog entry, which means inside a post I can write normal prose and then drop a real component between two paragraphs.&lt;/p&gt;
&lt;p&gt;So I wrote one component, &lt;code&gt;&amp;lt;DevDiary&amp;gt;&lt;/code&gt;. It takes the export more or less as-is: a day label, and a list of conversations, each with its participants and a transcript. Player lines, NPC lines, and &quot;context memory&quot; notes each render in their own style.&lt;/p&gt;
&lt;p&gt;Here is one, rendered from about a dozen lines of data pasted straight into this post:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;[interactive block — &lt;a href=&quot;/blog/&quot;&gt;read it on the site&lt;/a&gt;]&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Why this shape is worth it&lt;/h3&gt;
&lt;p&gt;The export format and the component&apos;s props are nearly the same thing, so posting a clip is paste-and-wrap. Nothing gets retyped, so nothing drifts.&lt;/p&gt;
&lt;p&gt;When I want a new kind of content in a post, a stat block, a schedule, a before-and-after, I write one small component and every future post can use it. The post itself stays plain text: it diffs cleanly in git, it degrades to something readable if the component ever breaks, and eventually it is the kind of thing I can paste into a browser CMS and publish without touching the repo.&lt;/p&gt;
&lt;p&gt;That last part is the actual goal. This was the first thing I built on Astro, mostly to see if the idea held up. It did.&lt;/p&gt;
</content:encoded></item><item><title>A social roguelike: NPCs who watch, remember, and gossip</title><link>https://narrativesim.com/blog/2d-game-in-development/</link><guid isPermaLink="true">https://narrativesim.com/blog/2d-game-in-development/</guid><description>I&apos;ve been working towards a new game, using dialogue system and npc awareness in a 2d world, instead of the visual novel approach in Gates and Gossip.</description><pubDate>Sun, 10 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;If you played &lt;em&gt;Gates and Gossip&lt;/em&gt;, you know I love deep, character-driven games.&lt;/p&gt;
&lt;p&gt;Welcome to my new 2D systemic RPG—a &quot;Social Roguelike.&quot;&lt;/p&gt;
&lt;p&gt;Like Gates and Gossip the narrative emerges organically from the simulation itself. To do this,  two highly dynamic, interconnected systems:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;NPC Awareness &amp;amp; Memory:&lt;/strong&gt; Characters in this 2D world actually observe their surroundings. They notice if you drop a strange item, remember if you helped them with a task, and form real mechanical opinions based on your actions. If you chase the farm&apos;s chickens they&apos;ll react, and even spread rumors.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A Living Dialogue System:&lt;/strong&gt; Instead of the game picking from a pre-written list of responses for an NPC, responses are generated on the fly based on mechanical truths. When you talk to an NPC, the dialogue system reads the raw mechanical state of the game—what the NPC recently witnessed, their current mood, the time of day, and their relationship with you—to generate completely natural, unscripted conversations that reflect the physical reality of the world.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You aren&apos;t just clicking through a story anymore; your physical actions in the world constantly ripple through the social fabric of the town. It’s a massive technical leap, and I can&apos;t wait to share more about how it plays!&lt;/p&gt;
</content:encoded></item><item><title>Structuring an LLM-driven NPC sim in ECS</title><link>https://narrativesim.com/blog/ecs/</link><guid isPermaLink="true">https://narrativesim.com/blog/ecs/</guid><description>Why I Stopped Thinking in Objects and Started Thinking in Data</description><pubDate>Sun, 10 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;If you’ve spent any time building games with an object-oriented mindset, you’ve probably hit the wall. Not immediately — OOP feels great at first. You have a `Player` class, an `Enemy` class, maybe a nice `Character` base class they both extend. Tidy. Logical. Until the moment you need a `FriendlyEnemyWhoIsAlsoAMerchant`, and suddenly your inheritance tree looks like a family reunion nobody wanted.&lt;/p&gt;
&lt;p&gt;Entity Component System — ECS — is the architecture pattern that solves this, and once it clicks, it’s hard to go back.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;The OOP Problem, Concretely&lt;/h2&gt;
&lt;p&gt;In object-oriented game design, a game object *is* a thing. A `Guard` has methods. It *knows* how to patrol. It *knows* how to detect intruders. Its behavior and its data are bundled together, which feels intuitive because that’s how we think about real objects.&lt;/p&gt;
&lt;p&gt;But games are full of edge cases. What happens when:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;A guard gets drunk and starts wandering randomly?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A merchant needs to react to threats like a guard would?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;An NPC falls asleep and temporarily stops being *anything* useful?&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You end up with either deep, fragile inheritance chains or a bloated base class that has a little bit of everything — the infamous “god object.” Neither scales well. Refactoring either one mid-project is painful.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;The ECS Mental Shift&lt;/h2&gt;
&lt;p&gt;ECS flips the model:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;**Entities** are just IDs. Empty vessels. A number.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;**Components** are plain data attached to those IDs. No logic. Just state.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;**Systems** are functions that operate on entities that have a specific set of components.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A guard isn’t a `Guard` object. It’s an entity with a `Position` component, a `PatrolRoute` component, a `Faction` component, and maybe a `Schedule` component. If you want that guard to also be a merchant during off-hours? Add a `MerchantInventory` component. No new class. No refactor. Just data.&lt;/p&gt;
&lt;p&gt;The behavior emerges from which components are present, and systems only run on entities that qualify.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Why This Matters More Than It Sounds&lt;/h2&gt;
&lt;p&gt;The power isn’t just organizational tidiness — it’s *composability at runtime*.&lt;/p&gt;
&lt;p&gt;In a recent project I’m building (a simulation-heavy RPG engine), NPCs needed to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Follow patrol routes&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Stick to daily schedules&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;React to things they witnessed — a theft, a fight, someone walking around smelling like mushrooms&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Have their behavior temporarily overridden by status effects&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In an OOP model, each of those features risks touching a central `NPC` class. In ECS, each is its own component. A status effect that makes an NPC avoid you? That’s just attaching a `StatusEffect` component with the right data. The avoidance system picks it up automatically. Remove the component when the effect wears off. Done.&lt;/p&gt;
&lt;p&gt;What surprised me most was how *emergent* this gets. I didn’t script NPCs confronting the player about witnessed behavior — I just built an observation pipeline that writes to a knowledge component, and a reaction system that reads from it. The confrontations fall out naturally. The status effect humor? Completely unscripted. It’s a side effect of composable, data-driven logic.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;The Practical Tradeoffs&lt;/h2&gt;
&lt;p&gt;ECS isn’t without friction.&lt;/p&gt;
&lt;p&gt;**Debugging is different.** When behavior is spread across systems rather than encapsulated in objects, tracking down why an NPC is doing something weird means checking which components it has and which systems are touching it — rather than just setting a breakpoint on a method. Good tooling helps enormously here.&lt;/p&gt;
&lt;p&gt;**The mental model takes time.** If you’ve spent years thinking in classes, ECS feels backwards at first. You keep wanting to put logic *on* the entity. Resist that impulse.&lt;/p&gt;
&lt;p&gt;**Queries are your friend.** The real productivity unlock is fluent querying — asking the world “give me all entities with *these* components” and getting them back efficiently. This is where purpose-built ECS libraries pay for themselves over rolling your own.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Why Miniplex Specifically&lt;/h2&gt;
&lt;p&gt;For JavaScript/TypeScript game projects, &lt;a href=&quot;https://github.com/hmans/miniplex&quot;&gt;Miniplex&lt;/a&gt; hits a sweet spot. It’s lightweight, has an elegant TypeScript-first API, and its query system feels natural once you’ve internalized the ECS mental model. Defining a query is as simple as describing what components you care about — and it handles the entity bookkeeping so you don’t have to.&lt;/p&gt;
&lt;p&gt;It also plays well with Phaser, which has its own scene/game object model. The trick is treating Phaser’s rendering objects as *one component* among many, rather than the center of gravity. Your simulation logic lives in ECS; Phaser just draws what the simulation says.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;When to Reach for It&lt;/h2&gt;
&lt;p&gt;ECS shines when:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;You have many entities with overlapping but non-identical behavior&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You need to add or remove capabilities from entities at runtime&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Emergent behavior from system interactions is a feature, not a bug&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You want your simulation logic decoupled from your rendering&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It’s probably overkill for a simple platformer with five enemy types. But if your game world has NPCs with schedules, knowledge, relationships, and dynamic status — ECS stops being a nice-to-have and starts feeling like the only sane choice.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;The shift from “objects that do things” to “data that systems act on” is subtle on paper and profound in practice. Once your guard becomes an entity with components instead of a `Guard` class, a whole class of design problems quietly disappears — and a whole class of emergent surprises quietly appears.&lt;/p&gt;
&lt;p&gt;That trade feels worth it.&lt;/p&gt;
</content:encoded></item><item><title>Multi-provider LLM routing in a live game</title><link>https://narrativesim.com/blog/providers/</link><guid isPermaLink="true">https://narrativesim.com/blog/providers/</guid><description>The Pattern That Connects Everything: Providers in a Data-Driven Game Engine</description><pubDate>Sun, 10 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In the &lt;a href=&quot;/blog/ecs&quot;&gt;last post&lt;/a&gt;, I talked about why Entity Component System architecture is worth the mental shift — how thinking in *data* instead of *objects* makes your game world composable in ways inheritance never could.&lt;/p&gt;
&lt;p&gt;But there’s a follow-on problem ECS doesn’t automatically solve: once your world is a sea of components spread across thousands of entities, how do any of your systems make sense of it cleanly?&lt;/p&gt;
&lt;p&gt;The answer, at least in my engine, turned out to be a single pattern I kept reaching for without fully naming it: **providers**.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;The Problem: Systems Are Hungry&lt;/h2&gt;
&lt;p&gt;A game simulation has a lot of mouths to feed. At any given moment:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;A dialogue system needs to know everything relevant about the current conversation — who the NPC is, what they’ve witnessed, what they think of the player, what the player is carrying&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A behavior AI needs to evaluate dozens of potential actions and score them against the current world state&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A world history pipeline needs to know what factions exist, what they believe, and what events they’ve witnessed&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each of these systems needs *contextual information*, and that information is scattered across your ECS. You could hardcode queries into each system — but then you’ve just rebuilt the spaghetti you were trying to escape.&lt;/p&gt;
&lt;p&gt;Providers are the cleaner answer.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;What a Provider Actually Is&lt;/h2&gt;
&lt;p&gt;A provider is a small, focused object with one job: look at the current world state and return a slice of relevant information in a standardized form.&lt;/p&gt;
&lt;p&gt;It doesn’t act on anything. It doesn’t own anything. It just observes and reports.&lt;/p&gt;
&lt;p&gt;In practice, a provider might:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Query the ECS for components on a specific entity&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Check a knowledge ledger for what an NPC has witnessed&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Read a relationship table and return a tension score&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Inspect the player’s inventory for items with relevant properties&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each provider is narrow — it knows about one thing. But because they share a common interface, any system that needs context can simply ask: *“Run all relevant providers and give me what they find.”*&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;The Composability Payoff&lt;/h2&gt;
&lt;p&gt;What makes this pattern powerful isn’t any individual provider. It’s that you can compose them.&lt;/p&gt;
&lt;p&gt;When my dialogue system builds context before handing off to the LLM, it doesn’t have one monolithic “gather everything” function. It runs a stack of providers — personality, relationship state, current activity, witnessed events, carried items — each contributing its slice. Add a new provider and every system that consumes the stack gets richer context automatically. Remove one and nothing breaks.&lt;/p&gt;
&lt;p&gt;The same pattern feeds my behavior AI. Instead of dialogue hints, providers return scored inputs — considerations that the system uses to evaluate which action an NPC should take. The mechanism is identical; only the output shape differs.&lt;/p&gt;
&lt;p&gt;Further out, the world history pipeline uses the same idea at a larger scale — providers that look at faction relationships, accumulated events, and cultural context to seed NPC memories and beliefs before the simulation even starts.&lt;/p&gt;
&lt;p&gt;Same pattern. Three very different systems. Zero special-casing.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Why This Pairs With ECS&lt;/h2&gt;
&lt;p&gt;If ECS is about making your *entities* composable — snapping capabilities on and off at runtime — providers are about making your *information flow* composable. They’re the read layer that sits above the raw component data and gives systems a coherent view of what’s happening.&lt;/p&gt;
&lt;p&gt;Together, the two patterns push in the same direction: keep data flat and decoupled, let systems compose it into meaning at the moment they need it. Neither pattern is complicated in isolation. The leverage comes from applying them consistently.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;What This Unlocks&lt;/h2&gt;
&lt;p&gt;The practical benefits are less about elegance and more about velocity.&lt;/p&gt;
&lt;p&gt;When a new system needs world context, you don’t write a new data pipeline. You write or reuse providers. When an existing provider needs to return richer data, every system consuming it benefits immediately. When you want to understand why an NPC made a decision, you can inspect exactly which providers fired and what they returned — the information flow is traceable by design.&lt;/p&gt;
&lt;p&gt;Testing also becomes surprisingly smooth. Because each provider is a pure, narrow function — world state in, data slice out — you can test them in complete isolation. Feed it a mock ECS world with two components and assert what it returns. No scene setup, no running game loop, no trying to simulate the conditions that triggered a bug. This isn’t something I planned for upfront; it’s just a natural consequence of the pattern’s shape. Narrow inputs, predictable outputs, no side effects.&lt;/p&gt;
&lt;p&gt;For a solo developer juggling simulation, dialogue, behavior AI, and world history in the same codebase, that combination of traceability and testability is less of a nice-to-have and more of a survival mechanism.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;In future posts, I’ll go deeper on each of the systems this feeds: how providers slot into the dialogue context pipeline, how they drive NAAS behavior scoring, and how the world history enrichment pipeline uses the same idea at generation time. Each of those is its own rabbit hole — but they all share this same quiet foundation.&lt;/p&gt;
&lt;p&gt;The pattern isn’t glamorous. It doesn’t have a dramatic origin story. It just kept being the right answer, system after system, until it became the connective tissue of the whole engine.&lt;/p&gt;
&lt;p&gt;That tends to be how the good patterns go.&lt;/p&gt;
</content:encoded></item><item><title>The Chatbot Trap: Why I Stopped Letting AI Run the Game</title><link>https://narrativesim.com/blog/the-chatbot-trap/</link><guid isPermaLink="true">https://narrativesim.com/blog/the-chatbot-trap/</guid><description>Why I abandoned the &apos;LLM as Game Director&apos; model in favor of deterministic simulation.</description><pubDate>Wed, 29 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Remember the first time you saw a video of an RPG NPC hooked up to ChatGPT? It was intoxicating. You could type anything, and the blacksmith would respond. You could ask him about his childhood, his favorite color, or his philosophical views on the monarchy.&lt;/p&gt;
&lt;p&gt;But then the illusion broke. You asked him for a million gold pieces, and because LLMs are inherently designed to &quot;yes-and&quot; the user, he said, &lt;em&gt;&quot;Of course, traveler! Here you go.&quot;&lt;/em&gt; Except... your inventory didn&apos;t change. The game engine had no idea what the LLM just promised. And five minutes later, the blacksmith forgot your name.&lt;/p&gt;
&lt;p&gt;When I set out to build &lt;strong&gt;Narrative Sim&lt;/strong&gt;, I looked at the current landscape of &quot;AI in Games&quot; and realized the industry is falling into a trap. Developers are treating Large Language Models as state machines. They are asking the AI to be the Game Director.&lt;/p&gt;
&lt;h3&gt;The Problem with LLM Game Directors&lt;/h3&gt;
&lt;p&gt;While outright hallucinations are getting rarer with better models, the fundamental drawbacks of LLMs remain:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;They are stateless:&lt;/strong&gt; They have context windows, not true memory.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;They are people-pleasers:&lt;/strong&gt; They struggle to hold firm boundaries against a player&apos;s inputs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;They don&apos;t know math:&lt;/strong&gt; They don&apos;t know the player&apos;s true X/Y coordinates, their actual gold count, or the pathfinding navmesh.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;The Narrative Sim Philosophy&lt;/h3&gt;
&lt;p&gt;I decided to flip the architecture on its head. In my engine, &lt;strong&gt;the LLM makes zero behavioral decisions.&lt;/strong&gt; Instead, the system splits into two distinct halves:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;The LLM as a Text Renderer:&lt;/strong&gt; The game&apos;s Entity Component System (ECS) and my deterministic Utility AI (NAAS) calculate the rigid, mathematical truth of the world. The LLM is simply handed that truth and asked to &quot;render&quot; it into natural language.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Semantic Meaning Turned Mechanical:&lt;/strong&gt; When a dialogue scene concludes, the LLM doesn&apos;t just output text. It outputs strict, schema-validated JSON commands that hook directly back into the game engine&apos;s physics, economy, and scheduling.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Over the next two posts, I&apos;m going to dive into the exact data structures and pipelines that make this work. I&apos;ll look at how I generate infinite dialogue without ever breaking the simulation, and how I turn a simple menu-click into a physical, systemic consequence.&lt;/p&gt;
</content:encoded></item><item><title>Treating the LLM as a Semantic Text Renderer</title><link>https://narrativesim.com/blog/llms-as-mechanics/</link><guid isPermaLink="true">https://narrativesim.com/blog/llms-as-mechanics/</guid><description>How I use the Narrative Affordance &amp; Agency System (NAAS) to treat AI like a GPU for prose.</description><pubDate>Tue, 28 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In traditional RPGs, if a player tries to talk to a blacksmith while holding a smelly, toxic item, you have two choices: write a hardcoded if (player.hasItem(&apos;smelly_mushroom&apos;)) dialogue branch, or let the NPC ignore it entirely.&lt;/p&gt;
&lt;p&gt;Yesterday during a playtest, my blacksmith, Garth, abruptly stopped hammering, pinched his nose, and told the player to get out of his shop. I didn&apos;t script a single line of that dialogue. But more importantly, the LLM didn&apos;t &lt;em&gt;decide&lt;/em&gt; to make Garth angry. The game engine did.&lt;/p&gt;
&lt;h3&gt;The &quot;Brain&quot; vs. The &quot;Mouth&quot;&lt;/h3&gt;
&lt;p&gt;In my architecture, the &lt;strong&gt;Narrative Affordance &amp;amp; Agency System (NAAS)&lt;/strong&gt; is the brain. It evaluates the world state on a staggered tick. It knows exactly who the player is, what time it is, and whether the NPC likes them.&lt;/p&gt;
&lt;p&gt;When the player clicks the &quot;Interact&quot; menu, my &lt;strong&gt;Dialogue Director v2 (DDv2)&lt;/strong&gt; steps in. DDv2 gathers &quot;Hints&quot; from the ECS and compiles them into a rigid context payload.&lt;/p&gt;
&lt;p&gt;I treat the LLM exactly like a GPU. You don&apos;t ask a GPU to calculate gravity; you calculate gravity in the physics engine and say, &lt;em&gt;&quot;Render this box here.&quot;&lt;/em&gt; I calculate the social physics, pass it to the LLM, and say, &lt;em&gt;&quot;Render an angry greeting.&quot;&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;The Data (Show, Don&apos;t Tell)&lt;/h3&gt;
&lt;p&gt;Here is a sanitized look at the exact JSON payload my HintProviders inject into the LLM context when the player approaches Garth:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;actor_profile&quot;: {
    &quot;name&quot;: &quot;Garth&quot;,
    &quot;occupation&quot;: &quot;Blacksmith&quot;,
    &quot;personality&quot;: [&quot;gruff&quot;, &quot;proud&quot;, &quot;easily_annoyed&quot;]
  },
  &quot;current_state&quot;: {
    &quot;activity&quot;: &quot;working_anvil&quot;,
    &quot;interrupted_by&quot;: &quot;Player&quot;
  },
  &quot;awareness_hints&quot;: [
    &quot;Player is currently holding: [Item: Smelly Glowing Mushroom]&quot;
  ],
  &quot;relationship_context&quot;: {
    &quot;tension_level&quot;: 0.8,
    &quot;archetype&quot;: &quot;annoyed_acquaintance&quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The LLM is given strict instructions: &lt;em&gt;Translate this mechanical state into a response.&lt;/em&gt; Because the LLM is constrained by the mathematical reality of the ECS, it doesn&apos;t hallucinate a quest about a dragon. It simply renders the data:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&quot;Are you out of your mind bringing that glowing rot in here? Put that away or get out before the stench ruins my steel!&quot;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I get the infinite variance and natural phrasing of an LLM, but the rigid, unbreaking stability of a systemic simulation. The engine owns the logic; the AI just owns the prose.&lt;/p&gt;
</content:encoded></item><item><title>Closing the Loop: Turning Semantics into Mechanics</title><link>https://narrativesim.com/blog/semantic-state-interpretation/</link><guid isPermaLink="true">https://narrativesim.com/blog/semantic-state-interpretation/</guid><description>Bridging the gap between LLM semantic output and hard-coded game mechanics using a Command Registry.</description><pubDate>Mon, 27 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Talk is cheap. In a systemic RPG, if I insult a guard, I don&apos;t just want a dynamically generated, angry response. I want him to physically arrest me, or at least kick me out of the tavern.&lt;/p&gt;
&lt;p&gt;The biggest challenge with AI dialogue is giving it &quot;teeth.&quot; If the AI generates text but the game world doesn&apos;t change, the illusion shatters.&lt;/p&gt;
&lt;h3&gt;The Menu-Driven Player&lt;/h3&gt;
&lt;p&gt;In Narrative Sim, the player does not type free-text to NPCs. Player agency is menu-driven.&lt;/p&gt;
&lt;p&gt;When an event happens—say, the player is caught stealing—my IActionProvider dynamically populates the player&apos;s UI with contextual choices: [Apologize], [Bribe (50g)], or [Flee].&lt;/p&gt;
&lt;p&gt;This grounds the player&apos;s inputs in the mechanical reality of the game. But what happens &lt;em&gt;after&lt;/em&gt; the player clicks a choice?&lt;/p&gt;
&lt;h3&gt;The Semantic Command Registry&lt;/h3&gt;
&lt;p&gt;When the player clicks [Bribe (50g)], DDv2 evaluates the interaction against the NPC&apos;s traits (e.g., is this guard corrupt or honorable?).&lt;/p&gt;
&lt;p&gt;I force the LLM to output its response not just as text, but as strict JSON containing an array of commands.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;internal_thought&quot;: &quot;The player is offering gold. I am underpaid and my &apos;corrupt&apos; tag is active. I will accept the bribe.&quot;,
  &quot;actorID&quot;: &quot;npc-kael&quot;,
  &quot;dialogueLine&quot;: &quot;Just this once. But if I catch your hands near the merchant&apos;s cart again, you&apos;re going in the cage.&quot;,
  &quot;topic_uris&quot;: [],
  &quot;commands&quot;: [
    {
      &quot;command&quot;: &quot;transfer_gold&quot;,
      &quot;amount&quot;: 50,
      &quot;from&quot;: &quot;player&quot;,
      &quot;to&quot;: &quot;npc-kael&quot;
    },
    {
      &quot;command&quot;: &quot;modify_tension&quot;,
      &quot;amount&quot;: -0.2
    },
    {
      &quot;command&quot;: &quot;clear_active_situation&quot;
    }
  ]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;The Physics of Conversation&lt;/h3&gt;
&lt;p&gt;My CommandRegistry catches that JSON object. Because these commands are strongly typed, the engine executes them flawlessly.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;50 gold is mechanically deducted from the player and added to Kael&apos;s inventory.&lt;/li&gt;
&lt;li&gt;The RelationshipManager lowers the tension between them.&lt;/li&gt;
&lt;li&gt;The SituationDirector clears the &quot;Confrontation&quot; override.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Instantly, Kael&apos;s underlying NAAS evaluation changes. Because the confrontation is cleared and his tension dropped, his controller stops targeting the player, he turns around, and he physically walks back to his patrol route.&lt;/p&gt;
&lt;p&gt;I have completely bridged the gap between dialogue and mechanics. The LLM translates the social consequence, and the ECS turns it back into physics.&lt;/p&gt;
</content:encoded></item></channel></rss>