This past week I’ve been in my equivalent of a drug binge. Out of nowhere, I became obsessed with the notion of implementing a text-based immersive sim relying on “vibe coding,” as has come to be known the extremely powerful approach of relying on very competent large-language models to code virtually everything in your app. Once I tasted Google’s Gemini 2.5 Pro’s power, I fell in love. The few times it makes mistakes, it’s usually my fault for not expressing my requirements correctly. Curiously enough, OpenAI released a more powerful model just a couple of days ago: o3. Sadly it’s under usage limits.
Anyway, let me explain about the project, named Living Narrative Engine. You can clone the repository from its GitHub page.

It’s a browser-based engine to play text adventures. My intention was to make it as moddable and data-driven as possible, to the extent that one could define actions in JSON files, indicating prerequisites for the action, the domain of applicability, what events it would fire on completion, etc, and the action-agnostic code would just run with it. I mention the actions because that’s the last part of the core of this app that I’m about to delve into; currently actions such as “look”, “hit”, “move”, “unlock” and such are harcoded in the system: each has a dedicated action handler. That’s terrible for the purposes of making it data-driven, so I’ve requested deep-search research documents and product requirement documents from ChatGPT, which look hella good. Before I start tearing apart the action system of the app, which may take a couple of days, I wanted to put this working version out there.
Currently the app does the minimum for a demo: it spawns you in a room, lets you move from room to room, kill a goblin, open doors, take items, equip items (and drop and unequip them), and also unlock doors (which was the hardest part of the app to codify). I have introduced quest and objective systems that listen to conditions; for example, there’s no key in the demo to open the door where the goblin is located, but when the event “event:entity_died” fires with that goblin as the subject, the door opens mysteriously. The single JSON file that drives that is below:
{
"id": "demo:trigger_unlock_treasure_door_on_goblin_death",
"listen_to": {
"event_type": "event:entity_died",
"filters": {
"deceasedEntityId": "demo:enemy_goblin"
}
},
"effects": [
{
"type": "trigger_event",
"parameters": {
"eventName": "event:unlock_entity_force",
"payload": {
"targetEntityId": "demo:door_treasure_room"
}
}
}
],
"one_shot": true
}
The goal is to make everything as data-driven and agnostic as possible.
Everything in the game world is an entity: an identifier and a bunch of components. For example, if any entity has the Item component, it can be picked up. If it has the Openable component, it can be opened and closed. If it has the Lockable component and also the Openable component, the entity cannot be opened if it’s locked. This leads to fascinating combinations of behavior that change as long as you add or remove components, or change the internal numbers of components.
The biggest hurdle involved figuring out how to represent doors and other passage blockers. All rooms are simple entities with a ConnectionsComponent. The ConnectionsComponent indicates possible exits. Initially the user could only interact with entities with a PositionComponent pointing to the user’s room, but doors aren’t quite in one room, are they? They’re at the threshold of two rooms. So I had to write special code to target them.
Anyway, this is way too much fun. Sadly for the writing aspect of my self, I haven’t written anything in about five days. I’ll return to it shortly, for sure; these binges of mine tend to burn out by themselves.
My near-future goal of this app is to involve large-language models. I want to populate rooms with sentient AIs, given them a list of valid options to choose from regarding their surroundings (such as “move north”, “eat cheesecake”, or “kick baboon”), and have them choose according to their written-in personalities. I want to find myself playing through RPG, text-based campaigns along with a harem of AI-controlled isekai hotties.
I’m going back to it. See ya.
Pingback: Living Narrative Engine #2 – The Domains of the Emperor Owl