The Glimmerwings Problem
I’ve been building the quest system. It’s been going well, mostly. NPCs can offer quests, players can accept them, encounters get spawned on the map at target hexes. I got the basic loop in and then sat down to do some end-to-end testing. And of course that’s when the floor fell out from under me.
An NPC offered me a quest to defeat the Glimmerwings.
What Are the Glimmerwings?
Great question - they do not exist. There is no enemy type called the Glimmerwings in this game. The AI hallucinated them somewhere during quest generation, and then the system dutifully tried to find and spawn a “glimmerwings” encounter and of course found nothing.
Digging into the server logs, I could trace exactly where things went wrong. The NPC encounter prompt generated the quest offer dialogue first. In that dialogue, the NPC described the threat: a fearsome creature called the Glimmerwings, terrorizing the nearby forest. At this point there’s no validation happening - this is narrative, and the AI is just writing a story.
Later, when the player accepts the quest, a second prompt runs to generate the mechanical details: what enemy type? The AI reads the full conversation log, sees the Glimmerwings mentioned in the NPC’s dialogue, and treats that as a real entity. It dutifully outputs enemy_type_id: "glimmerwings" and then the whole thing falls apart.
The Root Cause
The problem is ordering. The quest offer dialogue was generated before we had any mechanical details. The AI filled in a specific enemy name because that’s what good storytelling demands - vague threats are less compelling than named ones. But by naming something that doesn’t exist in the game’s data, it poisoned every prompt that came after it.
The deeper issue is that I was trying to do too much in a single pass. The original design had one prompt generating both the quest narrative and the target specification, which could be anything from the enemy type to fight, the item ID to go find, or the NPC ID to go talk to. The model was simultaneously trying to write a good story and select valid IDs from a list of real data. Narrative pressure and data accuracy were competing in the same output, and narrative won.
Specificity Has to Flow Downstream
Here’s the design principle that came out of this: narrative specificity must flow downstream from mechanical choices, not upstream.
When you ask an LLM to write a story about a specific enemy type, and you give it the real list of enemy types to choose from, it will pick one and write coherent narrative around it. The specifics are grounded because they came from real data first.
When you ask an LLM to write a story and then later try to reverse-engineer which enemy type it was describing, you get the Glimmerwings.
But this brings us to a chicken and egg problem - what kind of quest does the NPC even want us to go on? Our entry point when we first encounter an NPC has only the NPC’s motivations and the player’s motivations. From this the LLM must invent a goal, a request made by the NPC to the player: please take care of this thing for me. But what thing? I wanted to try and infer the quest type type and its details from the open ended narrative.
Breaking It Down Further
The fix is to break down the generation pipeline into even smaller steps:
Pass 1 - narrative only. The quest offer dialogue and the first pass of quest generation produces only narrative fields: title, description, a one-sentence objective. No entity IDs whatsoever. The prompt now explicitly instructs the AI not to name any specific entities. The NPC can be vivid about the urgency, the stakes, the emotion - they just can’t invent specific names. “There’s something terrible in the forest” not “There’s Glimmerwings in the forest.” Yes, there is some specificity built into the motivations, and those are OK to build on because they already have mechanics assigned (I hate this specific other NPC, I want to find this specific legendary item, etc). But if the AI needs new content to connect the dots, it must be vague.
Pass 2 - mechanics from real data. After the player accepts the quest, a second prompt runs to determine the quest type and attach mechanics. For an attack quest, this prompt receives the actual list of enemy types that exist in the game, and it asks: which of these fits the quest description? The output is validated server-side - if the ID isn’t in the real list, it’s rejected.
Pass 3 - more narrative. Originally I expected to generate the quest encounter content from templates with blanks in them, like filling in a mad-libs. Now I’m switching to something more dynamic, using the same system I use when you encounter NPCs. When the player arrives at the quest location, the encounter is generated dynamically one node at a time. By this point we know the real enemy type. The encounter’s opening scene can say “you find the goblin camp” because we actually know the enemy type is goblin. The narrative is now specific and grounded, but it got that way by flowing from the mechanics rather than the other way around.
What’s Next
The refactor is planned out. First up is attack quests end-to-end through the new system, including the full completion loop - accept, travel, fight, return to NPC for the reward. Once that’s solid and tested I’ll layer in the other quest types: investigate, deliver, and fetch (which is the most complex, with three different acquisition sub-types).
The quest system has been one of the gnarliest systems I’ve worked on yet, but I think that’s a really good thing. It’s exposing exactly the issues I wanted to expose and making me think about how and when to interact with the LLM. It also keeps reinforcing my original thoughts on prompt engineering: keep the prompts small, answer one question at a time, force the LLM to select from lists and only give it free reign to make flowery text when all the mechanical details are known.
This is the good stuff. I’m glad I’m finally at this point. I really appreciate the Glimmerwings helping me get here.