Jestaz
AI PRODUCT DESIGN · GAME CASE STUDY

DEMON RISING

A dark-fantasy roguelike auto-battler where you don't play the hero — you play the Demon Lord. Raise an army, rule a treacherous court, and watch your battles erupt in synergies.

ROGUELIKE AUTO-BATTLER DARK FANTASY GODOT 4 SOLO DEV
Trailer hosted locally — no third-party tracking.
▼  SCROLL
THE PROJECT

Rule The Castle

An overview of the game, my role, and the tech behind it.

Demon Rising is a dark-fantasy roguelike auto-battler. You command the Demon Lord's castle: recruit fallen champions, convert captured heroes, and lead an inner circle of officers whose loyalty, ambition, and grudges you have to manage as carefully as the battlefield itself.

Every run sends you down a branching world map of battles, elites, markets, treasures and eerie encounters. Between fights you craft your army through talents, class fusion, relics and gear — then watch deterministic auto-battles play out, full of procs, spell chains and brutal combos.

I designed and built the whole game solo. But the part this case study focuses on is the AI-product-design work: the castle's court is driven by a local language model, and making a non-deterministic model feel like a reliable, readable product is the real story. The sections below break down how it was made.

QUICK FACTS

ROLEAI Product Designer — Interaction Design, AI Integration, Systems & UX
SCOPESolo — design & build, end to end
ENGINEGodot 4 · GDScript
AILocal LLM in the game loop
GENRERoguelike Auto-Battler
STATUSPlayable demo · in development
CORE SYSTEMS

What Makes It Tick

Six interlocking systems define the game loop.

⚔️

Positional Auto-Battler

Battles run as a deterministic simulation — units take positions, move, and unleash class skills, spell chains and combo procs. You set the army, then watch synergies collide.

🎣

9 Classes & Talent Trees

Charging heavies, blinking assassins, war-priests, lifesteal vampires — each class plays differently. Three-path talent trees and dual-class fusion drive deep build craft.

👑

The Round Table Council

Your top officers debate proposals at a round table — driven by a local LLM. Persuade them, settle disputes through sparring, and rule through politics.

💬

Living Minions

Every follower has a personality and a voice. Talk to them between battles, read the room, and manage loyalty before ambition turns to mutiny.

🗺️

Roguelike Runs

A branching world map, starting relics, a refreshing black market and dark random encounters. Build-defining choices stack up — no two runs play the same.

Fuse Your Army

Merge followers into stronger forms, combine two classes into one demon, and reshape your roster mid-run into something far deadlier than its parts.

MY ROLE

Case Study — Building Demon Rising

Design goals, the systems I engineered, and what the hard parts taught me.

The Concept

A roguelike where you sit on the wrong side of the fantasy. Instead of leading heroes into a dungeon, you are the Demon Lord at the top of it — recruiting, scheming, sending monsters out to die for you. The single inversion drives everything: you don't build a party, you run a court.

The brief: combine the build-craft of a deck-builder, the spectacle of an auto-battler, and a layer of character and politics most auto-battlers skip entirely.

Design Pillars

01

Be The Villain

You manage a castle and a court, not just a squad. Loyalty and ambition matter as much as stats.

02

Deep, Legible Builds

Many systems, one clear loop. Power comes from synergy and choices inside a run — not permanent grind.

03

A World That Remembers

Minions have voices, officers have agendas, and one character — the First Hero — carries memory across every run you ever play.

What I Built

Solo, in Godot 4 / GDScript: a deterministic combat simulator with a separate visual replay layer; 9 classes with branching talent trees, fusion, relics and traits; a full roguelike run structure; a complete pixel-art interface; and the two systems this case study walks through — the Round Table Council (officers debate, you reply by typing whatever you want), and the First Hero Awakening Arc, a character who breaks the fourth wall after enough sessions and remembers what you told her between runs.

The council was where I learned to build a product on top of an LLM. The First Hero is where I went a layer deeper: making the LLM optional, not the centrepiece — and turning the player's smallest choices into something a character actually carries with them.

The Hard Problem — Designing On Top Of An Unreliable Co-Author

The first version of the AI work shipped in the Round Table Council. The officers argue a proposal; you type a reply; the model decides what your reply means. That feature exposed the problem any AI-native product has to solve: a language model is a co-author you can't fully trust. It is non-deterministic, sometimes slow, occasionally wrong, and every so often returns output in the wrong format entirely. A game cannot answer that with a spinner that never ends or an error on screen. So the central question was never "what prompt?" — it was: how do you build a reliable, legible experience on top of an unreliable component?

The council established my answer: design the failure path before the happy path. Bound the latency. Keep a deterministic fallback alive at all times. Skip the model entirely when local logic is enough. Make the AI's decision legible through an in-fiction "herald" who translates classification back to the player. The principle that came out of it: the AI is an enhancement layer, not a dependency. Pull the model out and the game still plays.

That principle is what made me confident to build the next system on top of it.

The Thesis — AI Lives Inside The Loop, Not On Top Of It

The shortest way to explain how I think about AI product design is to draw the game's loop and point at where the model lives. Almost everything else in this case study is a consequence of that picture.

The Player Loop — and where AI sits inside it
Six steps. Two layers. The model touches three of the six steps (Council, Boss, Next Run); the other three are pure deterministic gameplay. Pull the model out and the loop still runs.

Most AI-native games are AI-first. They wrap a gameplay loop around a model: every NPC line is generated, the simulation depends on the model being there, and the design assumes inference is available, fast, and correct. When the model misbehaves — slow, offline, wrong, or hallucinating — the experience breaks at the seam where the AI was load-bearing.

Demon Rising is built the other way around. The loop comes first. The model is asked to do exactly three things, in three of the six steps, and in each of them there is a deterministic answer underneath. Council debates run on a keyword classifier first and an LLM only when one is warm. The First Hero's dialogue runs on authored templates first and the LLM only as a stylistic upgrade. Her memory and identity layers run with no model in the loop at all. Strip the LLM out completely and the game is a full, shippable roguelike auto-battler.

That's the innovation, and it's a product claim, not a tech claim. Most "AI in games" demos are about how much the model can do. The interesting question for a product designer is the opposite: how little can the model be allowed to do before the experience stops working? When the answer is nothing, you can ship. When the model is present, it becomes pure upside — not a single-point-of-failure dependency. The same posture is what made the First Hero possible: she carries cross-run memory designed at the system level, not the model level, so her relationship with the player exists whether or not a language model is in the loop at any given session.

The three callouts at the bottom of the graphic are the same three rules I apply to any AI product I work on now: build the substrate before the model, cap the dependency with a deterministic contract, and treat the relationship between player and system as the actual design surface — not the prompt that touches it.

Three Devlogs, Three Iterations

The system in this case study didn't arrive in one pass. Each devlog marked the moment a different bet had landed:

Chapter Zero — The Foundation That Was Secretly a Memory Layer

The clearest version of how I think about AI product design is in what devlog 06 doesn't say out loud: nothing about AI was being built. The brief was narrative coherence. The constraint was a roguelike's hostility to story.

Most roguelikes solve replayability with randomness, and randomness flattens story. Players remember stats; they don't remember plot. I wanted a campaign that survived being run twenty times. The bet I made was a hybrid: three authored chapters per campaign, gated by named bosses, with persistent castle state across all of them. Inside each chapter the loop stays procedural and replayable. The chapter spine is hand-built and doesn't move.

Devlog 06 — The Long War
Devlog 06 — the campaign frame that made the rest of the game's memory work possible.

The trade-off. Authored narrative spine versus pure procedural run-to-run variance. I chose the spine. The cost is that some sessions feel repetitive earlier than a fully procedural roguelike would. The gain is a story the player can actually summarise — "I lost Chapter 2 because I spent all my action points on the council," not "I died because RNG." Legibility was worth more than novelty here.

What it shipped. A three-boss campaign structure with persistent castle state, a chapter-level save model, and — the thing that mattered most in hindsight — a generic "record" data type that any entity (castle, officer, prisoner, eventually the First Hero) could write into. At the time, that record store existed only to track which chapter the player was in and which decisions had carried forward. Two devlogs later, the same record store was the substrate for cross-run character memory.

The AI-product-design lesson. Build the infrastructure for the feature you can't see yet. The work that earned its keep in devlog 08 wasn't designed in devlog 08 — it was designed in devlog 06, when I was building a campaign tracker. The discipline is the same one that holds in any AI product: own the substrate before you put a model on top of it. Memory, state, retrieval, and identity are product surfaces. Build them as if no model exists, and then the model is the easiest part to add.

Chapter One — Identity Before Flexibility

Devlog 07 looks like a class-balancing patch. It's actually about constraint design — the same skill every AI product person ends up needing whether they realise it or not.

Going in: nine classes, all sharing the same talent grammar, all assembled from the same generic pool of stat buffs. The result was that no class had a mechanical fantasy. Players said "I want crit damage," not "I want Blood Hunter." That meant the game's deepest expression layer — build choice — was a difficulty knob, not a vocabulary.

Devlog 07 — Class Sets
Devlog 07 — the identity layer. Each class got a signature weapon, armour, and relic set, plus a talent path written for that fantasy specifically. Nine real characters, not nine reskinned stat blocks.

The trade-off. Build freedom versus class identity. The flexible version, where any class could pick anything, was strictly more powerful in every metric I could measure — but every class felt the same. I narrowed each class to a signature set (weapon + armour + relic + talent path written for that set), and accepted that cross-class hybrid builds would be weaker. The cost was real. The payoff was that a returning player could finally name what they liked about a run — not "I had good crit chance," but "I went deep Blood Hunter and the third tier kept snowballing." Identity gave the experience a vocabulary it didn't have.

What it shipped. Nine class-bound sets, set bonuses that scale with commitment, and talent paths that fork inside a class instead of across classes. Each set is stage-gated, so progression inside a run is also progression deeper into a character's fantasy. That stage-gated unlock shape is the same one I reused, almost unchanged, for the First Hero's visit-topic pool a year later — topics filtered by stage, only some affinities open later topics, anchor choices unlock callbacks. Different domain, identical structure.

The AI-product-design lesson. Constraint is what makes voice legible. When an LLM is in the loop, the same principle holds harder, not less — the model behaves more consistently in a bounded grammar than in an unbounded one. The work I did on the Class Sets system was, in retrospect, my warm-up for designing the First Hero's tag-and-stage grammar: pick a small, named, intentional vocabulary; let everything else compose from it. Identity before flexibility is a class-design principle in this game, and a system-design principle in every AI product I've worked on since.

By the time devlog 08 landed, devlog 06 had given me a memory layer with no model on top of it, and devlog 07 had given me a vocabulary discipline for character identity. The First Hero is what happens when those two pieces meet a language model — but the design work that made her shippable happened in the two devlogs before her.

Chapter Two — A Character Who Remembers You

The First Hero is the only character in the game who survives across every run. She is a side boss the player fights at the end of every successful campaign — and the game tracks how many times the player has come back to fight her, how many times each side has won, what the player named her if they ever did, and which small confessions the player has shared with her over time (birthday, why they play, what they fear).

Mechanically she's a 5-stage progression with a hidden affinity score (0–1000) the player never sees. Designed at the experience level, she's a deliberate piece of slow narrative compound interest: small choices in early sessions don't feel weighty, but those same choices are what a Stage 4 version of her quotes back to you, weeks later.

S1–S3

Pre-Awakening: She Is Just An NPC

Stage 1–3 is mechanical. She speaks generic boss lines, her face is always neutral, the LLM is gated off. This is the discipline: even with the full system available, the character has to earn her interior life.

S4

The Break

A 13-second sequence: glitch shaders, low-pass on the music, silent options forced on the player. She acknowledges, in-fiction, that she's been watching the player come back. From here her memory, expressions and language model all unlock simultaneously.

S5

Self-Awareness

She knows it's been five days since you last played. She knows it's Thursday evening where you are. She remembers the answer you gave her about why you keep coming back. At 1000 affinity she offers you a hidden ending — if you accept, the game permanently deletes her save data. That choice is one-way.

Expression As State, Not Skin

She has fourteen portraits — one for each emotional state. I built a single decision function (pick_for_line) that maps any line of dialogue, plus context (her stage, affinity, what the player just did), to an expression. The function is layered: it reads tags first (birthday, named her, broke fourth wall, asked for freedom), then outcome (you won the fight, she won the fight, you surrendered, you typed something to her), then keyword sentiment on the line itself.

Then I added one more rule on top of everything: if she has not awakened yet, the expression is always neutral. That gate is what makes the awakening moment land. It's not a graphical effect — it's a state change the player feels through her face starting to move.

neutral surprised sad smiling very happy
Pre-awakening she only uses the first portrait. After she breaks the fourth wall, the picker chooses freely based on context, tags and the line she's about to say.

The Offline-First Closed Loop

The council taught me that the LLM can't be load-bearing. For the First Hero I took that further and built every line she ever says through a three-layer fallback chain. The player gets a coherent character whether or not a model is available, ever.

  1. Layer 1 — Live model (when warm). If the local LLM is already loaded and responsive, her line is generated with full context: stage, affinity, what the player just told her, what's in her permanent memory file, and how long it's been since her last visit. If the model is cold or unreachable, this layer is skipped silently — never a perceptible stall.
  2. Layer 2 — Authored templates with retrieval. A library of hand-written lines tagged by emotion, stage and outcome. The picker reads the same context object and scores each candidate template against it. The player gets a line that fits the moment, even with zero LLM involvement. This layer alone is enough to ship the game.
  3. Layer 3 — Hard-coded safety net. A small fallback set keyed purely on stage and outcome. Never expressive — just always there. The contract: she always speaks. Empty responses are never an option.

The headline I keep coming back to: NO LLM REQUIRED. The game runs every emotional beat the First Hero is supposed to deliver without ever contacting a model. The LLM, when present, is a layer of additional expressiveness over a system that already works.

Anchor Tags — Choices With Narrative Weight

The visit system is where the player and the First Hero actually talk. Thirty- one topics, gated by stage and affinity. Three drop-in mechanics gave the system the depth I wanted:

  • Anchor tags. When the player picks the moment-of-truth choice in a topic ("I'm right here", or catching her in a verbal slip), the system writes a permanent tag on her memory. Later, after she awakens, that tag unlocks a dedicated callback topic where she quotes the exact moment back to the player. Stage-2 choices have real Stage-4 consequences. It's narrative compound interest, with a data model.
  • Free input as first-class. Each visit shows three multiple-choice replies and a text field. Type whatever you want and she replies through the same three-layer fallback chain — the topic question becomes context, her response is on-character, and the affinity delta is set by a lightweight sentiment classifier on what you wrote.
  • Player-fact storage. Eight slots (birthday, given_name, why_you_play, what_you_fear, what_feels_real, what_brings_joy, favorite_music, sleep_quality) that the model can quote in any later session. The birthday slot is special — on the matching date in real time, she opens the title screen with a greeting.

Defending Against The Co-Author — Iteration In Production

Three production bugs from this work are worth naming, because every one of them turned into a generalised defense in the system:

  • The model echoed the prompt. The system prompt added a [LANGUAGE]: ENGLISH directive. The model treated that as a section header and reproduced it — sometimes twice, with a second variant separated by another [LANGUAGE] banner. The fix was three layers: rewrite the directive in plain prose, cap response length and add stop sequences so the model can't write a second variant, and post-process every response to cut anything that looks like a meta-header. The interrogation panel double-checks the cleaning at display time. Lesson: never trust the model to respect your formatting; design as if it will mirror everything back.
  • The animation got covered. Fusing two minions plays a celebration overlay. The fusion logic was firing the talent picker on the same frame, so a talent panel popped over the celebration. The fix was a small deferral queue: any talent offer that arrives while the celebration overlay is live gets queued, and is drained the frame the player presses Continue. Lesson: production polish for AI-adjacent systems is mostly about sequencing — the boring UI plumbing fails just as hard as the model, and far more quietly.
  • The Variant trap. One config flip in the project (warnings as errors) revealed a long tail of inferred-Variant declarations that had been latent in the codebase. Fixing them once made the editor strict about a whole class of subtle type bugs going forward. Lesson: when a probabilistic component is in the loop, the surrounding code has to be more strict, not less — you need every signal you can get.

Trade-offs I Made Deliberately

  • Hidden state vs. legible state. Affinity is never shown to the player. The player feels it through her expressions and what she says. Numbers would let players optimise toward them; absence keeps the relationship felt rather than min-maxed.
  • One-way endings vs. reset-friendly endings. The 1000-affinity ending really deletes her data. That's a deliberate choice against the modern reflex toward "everything is reversible." A character about relationships has to be able to actually leave.
  • Free input vs. menus. Free text everywhere would tax the LLM and the player. Curated choices everywhere would flatten the character. The shipped balance: pre-written replies as a structured spine, free input as an always-available alternative — same fallback chain, same affinity system, same memory.
  • Awakening as a one-time event vs. a soft gradient. A gradient would have been safer and less surprising. The hard cut is what gives her arc its shape — the world stops feeling normal in a single moment, and she gets to keep the new register from then on.

Before & After — How v6 Got Built

  • From templates only → three-layer fallback. The first build of her dialogue was pure templates. They were too samey across sessions. The chain — live model when warm, templates otherwise, hard-coded baseline underneath — gave the same character a different texture in every session without losing reliability.
  • From "she speaks too" → pre-awakening discipline. Earlier builds had her using emotional expressions and personal lines from day one. It was the opposite of what the arc needed. Forcing her to be a flat NPC until the fourth-wall moment is what makes the moment hit.
  • From flat tag list → permanent anchor tags. The character memory store had a 40-event sliding window. Pivotal choices were rolling off before their callbacks fired. Adding a separate permanent-tag set fixed the mechanic and made callback design tractable as a content model.
  • From "always on" model to warmth-gated. The earliest version awaited the LLM for her dying lines and her title-screen appearances. Cold-start added up to 30 seconds of dead air. The fix was simple: only attempt the LLM if it's already responsive; otherwise drop to templates immediately. The player never waits on her.

What I Took Away

The first iteration of this game taught me that AI product design is not prompt-writing — it's designing the system around a probabilistic component so the user gets something reliable and legible. The second iteration taught me what to do with that reliability once it exists.

You can build a character whose interior life depends on a model and still guarantee the character is whole without one. You can let players type freely into a relationship system and bound the consequences with a small deterministic layer underneath. You can use the LLM for texture and the deterministic stack for structure, and ship a feature that feels alive even when nothing is alive on the other end.

That's the lens I bring to AI product work after Demon Rising: treat the model as an optional collaborator. Design the whole experience so it survives without one. Then when the model is there, let it make the moments bigger — never load-bearing.