# How I’m improving performance with 10,000 characters

Pilgrimage devlog 4 · September 10, 2026

[Pilgrimage](https://www.youtube.com/watch?v=tIvISy8WUdw)

This devlog is about two days of work on [Pilgrimage](https://www.tomjohn.design/content/pilgrimage), and mostly it's performance, performance, performance [(0:23)](https://www.youtube.com/watch?v=tIvISy8WUdw&t=23s). It's a long one.

The new loading page has three monks parading around, and it's there partly because it buys a second or two while all the assets download, so starting a new game only has to generate the map [(1:32)](https://www.youtube.com/watch?v=tIvISy8WUdw&t=92s). I spent about six hours with Astra and four with Fable trying to get the frame rate up, and the bar was that scrolling at 3x speed never drops below 30 FPS [(5:56)](https://www.youtube.com/watch?v=tIvISy8WUdw&t=356s).

## Doing less

When the game sees a sustained frame drop, it starts taking out things that don't matter to the gameplay. Every other tree goes first. Does it look as good? Not quite. But it works a lot better [(4:00)](https://www.youtube.com/watch?v=tIvISy8WUdw&t=240s). Zoomed out, the characters drop their edges and most of their walk frames, the trees go and building interiors aren't rendered at all [(4:25)](https://www.youtube.com/watch?v=tIvISy8WUdw&t=265s). Characters off screen aren't drawn [(5:33)](https://www.youtube.com/watch?v=tIvISy8WUdw&t=333s), and a lot of what was Three.js is now sprites, so one tree is drawn a thousand times instead of a thousand trees [(6:23)](https://www.youtube.com/watch?v=tIvISy8WUdw&t=383s).

![The map thinning out its trees as the frame rate drops, captioned as I say: “start to drop off as soon as there is an FPS or sustained FPS drop. And so I remove every other tree. Does it look as good? Not quite. But does it work”](https://nlzkl2bo0qmd3uti.public.blob.vercel-storage.com/talks/clips/pilgrimage-performance/dropping-trees-f7NH6g36ByYdvbSGPTCpD8TTRDaImD.mp4 "Clip")

Pathfinding was the biggest bottleneck. Every character is deciding where to go, whether they need water or should turn down the path to the relic, and with 10,000 of them it was 10,000 routes, all in the browser [(9:47)](https://www.youtube.com/watch?v=tIvISy8WUdw&t=587s). Then I realized from the history that people in the Middle Ages didn't travel alone. It was dangerous, and kind of weird. So I added groups, and by a happy accident the pathfinding only has to work out a route for each group, which took those 10,000 routes down to about 500 [(10:32)](https://www.youtube.com/watch?v=tIvISy8WUdw&t=632s).

![A travelling company of pilgrims on the road, captioned as I say: “so what happens by a happy accident, what I realized is by treating them as groups, the pathfinding was dramatically improved because then I only had to pathfind on the”](https://nlzkl2bo0qmd3uti.public.blob.vercel-storage.com/talks/clips/pilgrimage-performance/travel-groups-SurDGlyt2Ewuts555sCJFNQD6dOgc3.mp4 "Clip")

## The town

People used to sleep on the side of the road, which was a hard problem for a group, so I removed it and added taverns along the road instead [(13:10)](https://www.youtube.com/watch?v=tIvISy8WUdw&t=790s). There are wells and springs, beggars when people run out of money, and shallows people wade across [(14:43)](https://www.youtube.com/watch?v=tIvISy8WUdw&t=883s). Everyone ends up stooped over and too hungry way too quickly, which is fairly depressing, so that needs work [(15:30)](https://www.youtube.com/watch?v=tIvISy8WUdw&t=930s).

Buildings change when you put them next to each other, which I loved in Townscaper, so a house and a tavern can share a chimney, and every building has its own layout [(17:01)](https://www.youtube.com/watch?v=tIvISy8WUdw&t=1021s). An inn can stand on its own or go on top of a tavern, because that's how a lot of buildings were built, one generation on top of the last [(18:37)](https://www.youtube.com/watch?v=tIvISy8WUdw&t=1117s). And because I can add anything I think of, there's a cheat code where one in every hundred trees stands up and walks around, the last march of the Ents [(19:56)](https://www.youtube.com/watch?v=tIvISy8WUdw&t=1196s).

![Placing an inn on top of a tavern, captioned as I say: “if you build it an inn, you'll be able to put it on top of the tavern. And the cool thing about”](https://nlzkl2bo0qmd3uti.public.blob.vercel-storage.com/talks/clips/pilgrimage-performance/inn-on-a-tavern-K4bLTskiEXpr96a09w2K2NesTPbyVg.mp4 "Clip")

## The sprite pipeline

The characters don't use image generation. Getting consistent isometric sprites from it is unbelievably expensive, so with Astra I worked out a pipeline instead [(21:31)](https://www.youtube.com/watch?v=tIvISy8WUdw&t=1291s): 3D shapes, bones so a staff stays in a hand, a pass for depth, and a mask so characters get an edge when they walk in front of each other [(22:15)](https://www.youtube.com/watch?v=tIvISy8WUdw&t=1335s). It had made 311,000 sprites in four days, and when I wanted nuns, it reused the existing rigs and added them [(24:49)](https://www.youtube.com/watch?v=tIvISy8WUdw&t=1489s).

![The sprite pipeline, from 3D shape to finished sprite, captioned as I say: “expensive to make that work. And so what I did was I figured out a very compute efficient um way of doing this with obviously the help of Astra. Um”](https://nlzkl2bo0qmd3uti.public.blob.vercel-storage.com/talks/clips/pilgrimage-performance/sprite-pipeline-BUPjiejLtihiUjDvsJKe6qvwk86abT.mp4 "Clip")

## Maps that look real

I rebuilt how maps are seeded [(27:15)](https://www.youtube.com/watch?v=tIvISy8WUdw&t=1635s). Forests have wind direction now, because that's how seeds get carried, so the longer lines of trees look like they grew there [(28:20)](https://www.youtube.com/watch?v=tIvISy8WUdw&t=1700s). I wanted it to look real when you zoom all the way out, and I'm really happy with it, though the cliffs still look a bit Minecrafty [(29:52)](https://www.youtube.com/watch?v=tIvISy8WUdw&t=1792s). It also works well on an iPad now, with gestures, and it might be a better mobile game than desktop [(26:07)](https://www.youtube.com/watch?v=tIvISy8WUdw&t=1567s).

![Generating a map with forests seeded by the wind, captioned as I say: “have was I wanted the forest to look like they were actually natural se naturally seeded and a forest would be naturally seeded by wind because seeds would be pulled by the wind. And so I”](https://nlzkl2bo0qmd3uti.public.blob.vercel-storage.com/talks/clips/pilgrimage-performance/wind-seeding-XpbaAfMfzj27BVItYvA2KtWnEvTEbv.mp4 "Clip")

It's not a game yet, but it's getting close. The game is revealing itself to me, and now the hard part is making it fun [(31:47)](https://www.youtube.com/watch?v=tIvISy8WUdw&t=1907s). That's where [the next devlog](https://www.tomjohn.design/content/pilgrimage-sound-design) picks up.
