Brackenmere / dev log

Posts Building Brackenmere

Steady frames, 2x MSAA and the limits of optimisation

Four agent passes made Brackenmere's village noticeably smoother without changing a pixel of the art, then hit a wall: the last 25% of a steady 60 could only come from changing the picture. Those calls came back to me, and I made them without knowing what MSAA was.

G25 6 min read

How shall I tell it?

By 9 October Brackenmere looked the way I wanted, but walking the village in first person, it hitched.

That evening I gave the agents the job in one long dictated message: "I want you to go through the whole gameplay experience here and figure out ways of making it more performant." I was clear about the trade: "preloading stuff in the initial game loading is fine, like as long as like we show like Brackenmere is loading the assets. And if that takes a minute before the game starts, that's okay. I'd much rather that than things be jolty or buggy during the game."

And I asked the question that had been bugging me: "I can play Quake 3 in the browser. How does that work with such, with no lag and such smoothness to it all? There must be something going on here, because... definitely our textures and details aren't as much."

The village square in first person after the performance passes The square at the well, rendered from the final build of pass 4. The art did not change; the cost of drawing it did.

Four passes, one at a time

I wanted one agent to investigate, plan, build and measure, then a completely fresh one to start again from its results: "let's see how far we can push these performance improvements." I checked the process first: "Does that go through any review rounds, etc.? And then when does... you start another... agent? Like, what's the kind of process here?"

Each pass got one independent review and had to prove itself with numbers. Then I handed it over: "ok im off, its all yours."

The first two passes ran overnight on Codex. They went after hitches: shadows that rediscovered the whole scene every frame, and materials that compiled the first time you swung a sword or the weather turned. In the morning I asked for "a morning rundown. Whats happened? Pass 2 has finished. Give me before and after stats." The jolts at a weather change had gone. Walking in first person was no smoother.

Under the hood The worst frame when night rain rolled in fell from 154.5 ms to 14.9 ms, and the first sword swing from 57.1 ms to 14.7 ms. A steady 60 needs every frame under 16.7 ms.

The machine was not as quiet as I said

I had told them "You're the only thing running on this machine." I was wrong: a macOS media-analysis service started up during the runs, eating CPU cores and GPU time. The agents spotted it, marked those timings as contaminated and kept only numbers from quiet windows.

What actually cost the frames

Passes 3 and 4 ran on Opus later that morning, in Claude. The first finding was blunt: the village was limited by the graphics card, with too many pixels to fill at Retina resolution.

The Quake 3 answer fell out of that. Quake 3 baked its lighting and visibility into the level offline, so none of it ran per frame. Brackenmere was paying at runtime for things nobody could see: ten street lamps switched off by day still ran their lighting maths on every pixel, and every fern was drawn on its own.

Under the hood With vsync off, a first-person frame cost 24.0 ms. At a quarter of the pixels it was 14.8 ms. Ferns alone were 459 of 1,371 draw calls; batching them took the frame's draws down to 960.

So the passes removed work that changed nothing on screen: lamps that are off are skipped, ferns are drawn as one batch per chunk, merged meshes share their corners, shadow taps are compared in hardware, and the far land loads behind the loading card.

Each was checked by rendering the same frozen frame from two builds and comparing pixels. If the picture changed, the change went, even when faster.

The same ferns rendered before and after batching, side by side The pixel check for fern batching: the same frozen frame from the build before and the batched one. One draw per chunk instead of hundreds, and the same picture.

The limit

After four passes the overhead view barely missed a frame. First person at High still missed a third.

Missed frames in the village falling across the passes Missed frames on the measured routes, from the plan's tables. The last group is Steady frames, the option I turned on.

Both owners had written the same warning before building: a steady 60 in first person at High needed about a quarter less GPU work than any picture-identical change could find. The rest had to come from the picture itself, and that was my call.

Under the hood First person went from 24.0 to 21.25 ms a frame across passes 3 and 4. What was left was attributed: 4.9 ms of anti-aliasing, about 2.5 ms of sun-shadow sampling, 3.8 ms of the craft wood and stone.

My choices, honestly made

The agents came back with a list. My first reply says a lot about building a game this way: "I like the steady frames journal option, but Im not 100% clear what its doing / the downside / The anti-aliasing msaa - again no idea what this is or whether Id notice / Shadow samples - again confused."

In plain terms: Steady frames draws fewer pixels for a moment when the game falls behind, softening the picture instead of stuttering. MSAA smooths jagged edges by sampling each pixel several times; we used four, and two cost much less.

Five minutes later I had decided: "Steady frames, lets implement / Lets try 2x, change it to that / Shadow samples - lets leave for now if its minimal." For the models: "The big models seems like not a lot we can do here now, and we might use those animations so leave for the time being."

The journal's Graphics section with Steady frames on Steady frames in the journal, on by default from 10 October.

With Steady frames on, first person at High missed 6% of frames instead of 33%.

The shadow clock, tried and taken out

The day before, I had tried a fix of my own. Our days pass quickly, so fence shadows sweep across the grass as you watch. "It's not a bug. It's true. The sun is moving... I don't want to kind of complicate things, but it's really quite off-putting when you're playing."

Picket fence shadows in the village from above The screenshot I sent on 9 October: thin pales, close gaps, shadows that crawl as the sun moves.

An agent researched it and I said "let's build what it suggests so we can check this out." The sun's light moved in small steps, with a switch to compare. The crawl stopped, but every few seconds every shadow jumped at once. I kept the continuous sun: the cure was worse than the symptom, and the switch let me find that out by looking.

Only download what changed

One more thing came out of that list. "Otherwise Brotli compression I can turn on, and can we add long cache lifetimes?" and then "Build the asset fingerprinting and nginx block."

Every shipped file now carries a hash of its contents in its name, so a browser can keep it for a year and a returning player downloads only what changed. The agent wrote the nginx block for me to apply on Forge.

Under the hood A warm reload fetched one file over the network, the page, and took the other 452 from the browser's cache.

What I took from it

Optimisation has a floor you reach honestly. Once the invisible work was gone, the only levers left changed what you see. I did not need to know what MSAA was to make that call; I needed an agent to tell me what I would lose.

I used it again the next morning, planning a flyover for the new opening, I added: "we can go low quality for the flyover, pause the time of the day so we aren't re-computing flyovers, and not have characters in it."

By October Brackenmere looked the way I wanted, but walking round the village it would judder now and then. So I asked the AI helpers to make it run more smoothly, without changing how it looks. I didn't mind a longer loading screen at the start if that meant no stutters while playing.

I also asked the question that had been bugging me: I can play Quake 3, a famous old game, in a web browser with no lag at all. Why couldn't we?

The village square in first person after the performance passes The square at the well after all the work. The pictures didn't change; how hard the computer works to draw them did.

Four rounds, one at a time

I set it up as four rounds. In each one, a helper looked for slow spots, fixed them and measured the result, then a completely fresh helper started again from there. Each round was checked by a second helper and had to prove itself with numbers. Then I said "ok im off, its all yours."

Overnight, the first two rounds got rid of the big jolts, like the freeze when rain rolled in or the first time you swung your sword. But walking around still wasn't any smoother.

Where the time was going

The next morning the other two rounds found the real problem: the computer was spending effort on things nobody could see. Ten street lamps switched off in daytime were still being worked out on every bit of the screen. Every fern was drawn one at a time.

That was also the Quake 3 answer. Old games like that worked out their lighting in advance, once, instead of every moment you play.

So the helpers took out work that changed nothing on screen. Lamps that are off are skipped. Ferns are drawn in batches. And every change was tested by drawing the exact same scene before and after and comparing them dot by dot. If the picture changed at all, the change was thrown out, even if it was faster.

The same ferns rendered before and after batching, side by side The same ferns, before and after drawing them in batches. Much less work, the same picture.

The limit

After four rounds the view from above was nearly perfect. Walking around in first person was better but still not smooth. To get the rest, we would have to change the picture itself, even a tiny bit. That was my decision.

Missed frames in the village falling across the passes How often the game stuttered, round by round. The last group is with Steady frames turned on.

Making choices I didn't fully understand

The helpers gave me a list. My honest reply: "I like the steady frames journal option, but Im not 100% clear what its doing... The anti-aliasing msaa, again no idea what this is or whether Id notice."

So they explained it plainly:

  • Steady frames: when the game falls behind for a moment, it draws the picture slightly softer instead of stuttering.
  • Anti-aliasing: smooths jagged edges. We could do half as much smoothing for a lot less effort.

Five minutes later I'd decided: turn on Steady frames, and halve the smoothing. With that, walking around stuttered about a sixth as often as before.

The journal's Graphics section with Steady frames on The Steady frames switch in the journal settings, now on by default.

A fix I tried and took back out

Days in the game pass quickly, so fence shadows creep across the grass as you watch. I found it off-putting. We tried moving the sun in little steps instead. The creeping stopped, but every few seconds every shadow jumped at once, which was worse. So I put it back. Having a switch to compare the two meant I could decide by looking.

Picket fence shadows in the village from above The fence shadows I complained about.

Faster coming back

One last change: when you come back to play again, your browser now only downloads the bits of the game that have changed, not the whole thing.

What I learned

There's a point where making things faster without changing anything simply runs out. After that, every option changes what you see. I didn't need to know what the technical terms meant to choose. I needed a helper to tell me, in plain words, what I'd lose.

Building Brackenmere

G30 6 min read

Immersion: a world that answers the hero

One quiet night I asked the agents to research what makes game worlds feel real and build it in three independent rounds: the hero's touch, a world that lives, and places that tell stories. Then three more rounds paid for it, and my own play the next morning found the rough edges.

Building Brackenmere

G22 6 min read

Twenty-seven pieces of feel

On 8 October I asked the agents what makes a game feel real, as someone who is not a game designer. One research pass became 27 small pieces of atmosphere and polish, built and merged in a day, and a lesson about how many agents one Mac can carry.

Building Brackenmere

G20 5 min read

Far tiles and tree cards

The valley I had just laid out was 448 metres across and you could not see the other side of it. In a day the agents drew the far land as baked tiles and the middle distance's trees as cards: the view opened up, but the frame time I hoped it would fix barely moved.