Simon Tasker

Games, apps, and the occasional detour.

Game Dev · · 5 min read

Tiny World: A world that keeps running when nobody is watching

A new project, an island that carries on whether anyone is playing or not, why it is TypeScript rather than Godot, and how a seed becomes somewhere people settle.

Something that carries on without you#

New project, and a different sort of one.

I wanted a small world that keeps going whether or not anybody is playing it. Trees spread and get cut down. Deer graze and wolves hunt them. Villages grow, run short of food, catch colds and argue about who is on guard tonight. Somebody who drops in should feel like a visitor somewhere that was already busy, rather than the reason anything is happening at all.

That gave me one rule, and everything else in this project follows from it. The simulation comes first and the game sits on top. If the world is not interesting with nobody in it, no amount of quests is going to fix that.

It is called Tiny World and it is running at tinyworld.simontasker.co.uk while you read this.

One thing I should say up front, because it will come up repeatedly. When I say we in these posts, I mean me and Claude Code. It wrote most of the code and I made the calls about what the thing is and how it should behave. I am not going to pretend otherwise in a build diary, and frankly the interesting decisions in here are not the ones about syntax.

Why not Godot.#

Edge of Space is built in Godot and I am comfortable there, so that was the obvious first thought.

It is the wrong tool for this one. A world that runs all day on a server with nobody watching wants a headless program, not a game engine that would like to open a window. And once you have accepted that the server is a plain program, it makes a great deal of sense for the server and the browser to speak the same language.

So it is TypeScript everywhere. A Node process runs the simulation and owns the truth about every tree, villager and wolf. Phaser 4 draws it in the browser and simulates nothing whatsoever. A WebSocket sits between them, and the world is cut into chunks so a browser is only ever sent the part near its camera.

The terrain table, the constants and the protocol live in a shared folder that both halves import, which means the two ends cannot quietly disagree about what a message contains. That is the single most useful consequence of one language on both sides.

The server owning the truth also makes multiplayer, saving and cheating mostly stop being problems rather than becoming them. Two players see the same wolf because there is only one wolf.

Growing an island.#

Every world comes from a seed, and the generator builds it in layers.

Height first, from layered noise that gets warped so it stops looking like noise, with ridges for the mountains and a falloff at the edges so the land is always an island. Sea level is then set by percentile rather than a fixed number, so every seed ends up with roughly the same amount of land rather than one in five being a puddle.

Then water, which is the part I find most satisfying. Every tile is given a downhill route out to the sea. Hollows with no way out fill up and become lakes, and the rain collected along those routes becomes rivers that actually reach the coast, because they were built by following the water rather than by drawing lines that look like rivers.

Moisture comes from being near fresh water, temperature falls with latitude and height, and the biomes fall out of those three.

Then the world gets a warm up before anybody sees it, so forests have already seeded and spread. The first view of an island looks lived in rather than freshly painted.

Rivers turned out to matter far more than I expected. They decide where villages settle, where bridges get built, where a palisade has to stop, and later on, where the floods happen.

Time.#

It ticks ten times a second. One real second is 1.2 game minutes, so a game day is twenty real minutes, with seven days to a season and four seasons to a year.

That pace was chosen rather than stumbled into. A day has to be long enough to watch a villager walk to the woods, fell a tree and carry the logs home, because that is the thing I want people to watch. A season has to be short enough that winter arrives while you are still sitting there.

Not everything runs every tick. Each part of the world is its own system running at its own pace, so plants grow slowly and cheaply while movement happens every tick. That is the whole reason one small server can run an island.

Living on my own box.#

It is self hosted, and deploying is one script that packs the build, copies it up, installs it and restarts the server under pm2. The world saves itself as a compressed snapshot periodically and on shutdown, so a restart or a deploy carries on exactly where it was, and the browser reconnects on its own.

That sounds like plumbing and it changed how I work. Because a deploy loses nothing, I can fix something in the middle of a living world and watch the fix take hold in a place that has been running for days.

The bit that told me it was working.#

Early on we added a spectator tour. Before you join, the camera drifts slowly between villagers at work, wildlife, and whatever has just happened, with a line underneath saying what each person is doing. Carrying four logs back to the woodcutter's hut, that sort of thing.

It was meant to be a loading screen. It turned into the best test of the entire idea, because if the tour is boring then the world is boring and no amount of features will rescue it. It is also how I check on the live world now, which is where the fourth post in this series ends up.

What was already wrong#

The first villages built on beaches and marsh, which looked ridiculous. Buildings stand on firm ground now and keep back from the water.

Animals flipped left and right on the spot whenever their path changed, a sort of permanent indecision. That class of problem, things flip flopping, came back in about five different disguises over the following days.

And paths that nobody used stayed forever, so the island slowly filled up with the ghosts of old journeys. Feet wear trails now, and trails nobody walks grow back over.

Next time, the villagers themselves, what they remember, and the rule that nothing in this world appears out of thin air.