DESIGN · ENGINEERING · OPERATIONS
Building a detailed AI city simulation on my own
A year of building Slow Vale, from a single virtual pet to a city of 1,000 AI residents.
Over the past year, I’ve been building Slow Vale, a detailed AI city simulation driven by language models. Players create a resident and keep in touch through texts, phone calls and gifts. The resident decides how to work, eat and socialize. The game introduction covers what they can do.
I originally wanted to make a virtual pet powered by a language model. The first version had one character in a small world, farming, cooking and spending time outdoors. The player could check in a few times a day and send a message. After a while, though, the character settled into a dull loop: farm, eat, sleep.
So I added more characters for them to talk to, then more things to do and more problems to deal with. Eventually they had jobs, businesses, production, trade, relationships and shared homes. What began as a pet became a city that needed to keep running. Many of the technical decisions grew out of that change.
1. What makes this a detailed AI city simulation?
Fine-grained decisions with consequences
Residents make fine-grained decisions, interactions unfold through concrete steps that take time, and actions change the world state that later decisions depend on.
One way to build a game like this is to have an LLM decide a longer stretch of activity. It might generate a daily schedule, then leave movement, work and meals to a separate policy executor. Another approach is to use dialogue to simulate discussions, negotiations and agreements between characters.
I chose smaller decisions. Walking to an adjacent location, saying something to a particular person, taking out a phone, sending a text, checking a shelf, turning a menu page, buying an item and deciding how long to sleep all involve choices made by the LLM.
After each decision, the resident spends time carrying out the chosen action. Sleep might last two hours; speaking and turning a menu page take time too. Their physical condition keeps changing, and other residents keep acting. When the activity ends or is interrupted, the resident decides what to do next from the new situation.
Defining these basic rules accounts for a large part of the work. When two people trade, each chooses items from their own bag or an amount of money. Both confirm the exchange. Only then do the goods and money change hands.
A medical appointment works similarly. The patient knows how they feel and how much it hurts. The doctor’s medical skill determines which signs of illness they can recognize. The patient describes their symptoms, the doctor asks questions, the patient answers, and the doctor makes a diagnosis and chooses a treatment. For a minor illness, the right diagnosis can lead to a cure. A wrong one can leave the patient with a consultation bill and no improvement.
Each participant makes their own decisions with different information. The doctor has to judge within the limits of their ability; the patient has to describe their experience. Executing those decisions changes the world and the characters’ state.
Giving residents something to talk about
One direct benefit of this detail is that it constrains hallucinations about the results of actions. Inventory, cash, physical condition and activity records come from things that happened in the simulation. Buying something adds it to the bag. Eating changes hunger.
It also gives conversations more substance. Residents talk about prices, income, work and people they have met. Conflicting interests can cause disagreements. Being treated to dinner or helped with a loan can change a relationship.
This was the problem I wanted to solve when I began adding complexity to the single-character world. Residents need enough experiences to have lives worth following. Players can see those details and understand why someone is happy, why they are complaining, or why they have changed their plans.
2. How the system runs
Around 180,000 model calls a day
Game time usually moves at two to three times real time. After expanding to 1,000 residents, the game makes roughly 180,000 LLM calls a day. With around 900 daily active players, that works out to about 200 calls per active resident per day.
At that volume, cost matters. I mainly use inexpensive models such as DeepSeek Flash, and I have spent a lot of time on context structure. Input cache hits exceeded 90% in earlier operation.
A resident living in the world for months repeatedly uses much of the same information: personality, system rules, memories and recent experiences. I put stable material at the front of the request, followed by current physical condition, surroundings and available actions. History is appended in a stable order, with as few changes to existing material as possible.
The context cannot grow forever. Each day’s experiences are summarized, and long-term memory has its own maintenance tasks. Rules for a particular activity enter the context when the resident needs them; related reminders should leave once the matter is settled.
Context organization also affects behavior. Without current state, residents repeatedly attempt actions that cannot work. Stale information can interfere with later decisions. I therefore treat context management as part of the backend architecture.
Dynamic choices and caching
One specific problem was how to combine a changing action space with tool calling or an output schema.
Who is nearby, what is in stock and which facilities are available can change on every decision. Putting those candidates directly into a tool definition or output schema means the schema changes too. Some APIs I tested early on placed those definitions at the beginning of the request. Changing them invalidated cache reuse for the large, otherwise stable context that followed.
On the main decision path, I instead have the model generate JSON as ordinary text. Dynamic candidates go into the current decision context, and the program handles parsing and validation. The stable material at the front of the request can then be reused.
That means handling formatting errors and invalid parameters myself. The program sends the specific error back to the model and allows a limited number of retries. In one 24-hour observation in early October, roughly 160,000 completed decisions produced around 1,490 additional validation retries, adding about 0.9% to the call count.
When choosing a calling method, I consider format reliability, character behavior, latency and cost together. Dynamic candidates provide useful constraints, but where they appear in a request also has a substantial effect on the cost of the whole system.
The world has to keep moving while models think
With one character, scheduling was simple. When I added interactions between residents, I first used shared context and let participants take turns. An interaction could finish within a single world tick. Later, different interaction groups ran in parallel, but each round still waited for every group to finish. If one group talked for a long time, the whole world waited.
Eventually, I separated model inference from world advancement.
A decision has three stages: prepare context, run inference, then validate and execute the result. Multiple residents can run inference in a pool with a concurrency limit, while a single execution thread modifies world state. When a result comes back, the program checks the execution conditions again before applying it.
A resident may decide to buy the last fish on a shelf, only for someone else to buy it while the model is thinking. Or they may decide to invite someone to dinner, but that person has started work by the time the result returns. Execution has to use the state of the world now.
Concurrency therefore involves more than sending several model requests at once. It also means handling changes that happen before requests finish, competition for resources, and new dependencies between residents.
Pausing and resuming activities
The implementation separates behavior into Activity and Process. An Activity occupies time: sleeping, cooking or moving, for example. A Process organizes the sequence of decisions and activities. In a consultation, the patient describes symptoms, the doctor asks questions, the patient answers, and the doctor diagnoses. Each step belongs to the appropriate participant.
Single-resident operations need processes too. Opening a phone, choosing an app and completing an operation requires context to carry across several steps. A process with multiple residents must also track whose turn it is, who remains occupied and when it can advance. Residents outside that process keep acting and thinking as usual.
Suppose a resident is cooking at home when a friend comes over to talk. They can pause, reply and then continue cooking. The system has to remember the progress and ingredients already used so that cooking resumes from the same point.
Different activities have different rules. Some can be paused, some end when interrupted, and some cannot currently be interrupted. During a trade or medical consultation, the participants cannot be pulled into another interaction.
On resuming, the program checks that the location and resources are still available. Items already produced, money already transferred and dialogue already recorded are not undone by an interruption.
Restarting the service presents the same problems. I save activities, paused state and processes involving multiple residents in the world snapshot, then restore participation and resource reservations. Unfinished model requests can be recomputed from their decision point; results already executed are retained.
Resident history, live logs and scene presentation all update from the actual progress and results of activities. Later decisions read experiences derived from those same events.
Developing and maintaining it alone
Detailed simulation takes a lot of work. Over the past year, the project has grown to roughly 500,000 lines of code and 2,300 Git commits, covering world simulation, character decisions, the economy, frontend, Phaser, observability and operations. Once the game is running, there are releases, incidents, performance issues, analysis and promotion to handle too.
Advances in AI coding tools are a large part of why I have been able to do this alone. I decide or stay closely involved in product direction, core mechanics, frontend–backend protocols and backend architecture, while delegating much of the implementation to AI. For Phaser and parts of the frontend, I mainly judge the running result and establish design tokens, page structure and component reuse rules.
To let AI handle more of the work, I organized documentation and runbooks by task and module. They specify what to read for each task, which sources describe the current system and which decisions belong to me. They also define which documents AI can maintain when they drift from the implementation.
I provide the tools it needs: logs, Langfuse, database access, monitoring, product analytics and service maintenance tools. Being able to query and verify independently makes useful investigation possible. Reading, editing, committing and deploying have separate authorization.
AI now assists heavily with code review, incident investigation and fixes, daily checks of resident behavior, removal of one-off maintenance code, promotional content and data analysis. More of my time goes into design decisions and reviewing results.
3. Four months on the Mainland server
These are the Mainland server’s operating results as of October 24, 2026.
Full after the October expansion
Early access mostly used invitation codes. During the National Day holiday in early October, I expanded capacity to 1,000 residents and opened recruitment through posts on Xiaohongshu, largely removing the earlier screening.
On October 3–4, 699 people registered, and 486 entered the game that same day. By the reporting date, 602 people from that group had entered. The server filled quickly, and later arrivals had to watch for an opening.
Another 693 people registered between October 5 and 24, when average DAU was 890. By October 24, the game had 2,429 registered users, 1,796 active users over the preceding 30 days and 914 active users that day.
How long players stay
Among the 486 people who registered and entered on October 3–4, next-day retention was 79.8%, day-seven retention 51.3%, and day-fourteen retention 43.7%. The three entry cohorts looked like this:
Swipe to see all columns.
| Player cohort | D1 | D7 | D14 |
|---|---|---|---|
| Entered before public access, mostly by invitation | 79.8% | 56.9% | 48.4% |
| Registered and entered on October 3–4 | 79.8% | 51.3% | 43.7% |
| Entered during the full-capacity queue period | 90.2% | 70.2% | 62.3% |
The earliest cohorts now provide four months of retention data:
Swipe to see all columns.
| Day | Retention | Returned / eligible players |
|---|---|---|
| D30 | 44.8% | 277 / 618 |
| D60 | 34.5% | 138 / 400 |
| D90 | 26.9% | 49 / 182 |
| D120 | 19.7% | 14 / 71 |
I also checked how frequently those 14 day-120 players had played before then. Over their first 120 days, they were active on an average of 111.9 days, with a median of 117. Eleven had played on at least 100 days. Six had entered the game every day.
A few daily visits, or something to watch for hours
I originally imagined a pet that would take a few minutes a day. In practice, some players spend hours watching: waiting for a resident to finish something, for a friend to arrive, or to see whether they follow a suggestion just sent by text.
On October 7, median daily usage among 850 players was about 30 minutes, and P90 was around four hours. Between October 1 and 7, 86 players were active on at least four days and averaged more than three hours on their active days.
This has shaped the interface. Someone returning occasionally needs an understandable recap. Someone watching continuously needs to know what the resident is doing, why they are waiting and whether an interaction has finished.
New players from public recruitment were active on an average of 4.87 days in their first week, with median usage of 35.6 minutes on active days. They sent 33,627 texts during that week. A text, call request or note was sent on 90.2% of active user-days.
Across all players, the preceding 30 days produced 324,400 texts, averaging 14.5 per daily active user. Players keep trying to influence their residents and waiting to see how they respond.
What it costs each day
After the expansion, the Mainland server has roughly 900 daily active users and makes about 180,000 model calls a day. From October 12–24, inference cost averaged CNY 612 a day, with an average DAU of 901: about CNY 0.68 per daily active user per day.
A DeepSeek bill from October 7 gives a single-day example: approximately 4.424 billion tokens, 163,742 requests and CNY 472.33 in charges. Inexpensive models and extensive cache reuse make the city’s ongoing inference costs affordable for me.
I also surveyed interest in a monthly pass at CNY 30 per character. Among 338 responses from publicly recruited players, 26.0% said they would definitely or probably buy it; 7.7% said definitely.
I first added characters and activities to stop a virtual pet’s life from becoming repetitive. Four months into operation, some people come back every day to follow the same resident. That is what I want to keep working on: a character’s life that can hold someone’s interest over time.