Brackenmere / dev log

Posts Building Brackenmere

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.

G20 5 min read

How shall I tell it?

The valley I had just laid out was 448 metres across, and from the square you could not see the other side of it. The haze was full at the edge of what the game loaded, so the keep on its crag, the chapel on its rise and the far shore of the mere dissolved into one pale wall.

That was the look problem. The cost problem was worse: the relayout's measurements showed the first-person frame was mostly spent on things a long way off.

On 5 October the agents built an answer in a morning: draw the far land cheaply as baked tiles, draw the middle distance's trees as flat cards, and in exchange load full detail less far.

First person at the mere's jetty: the far shore with trees and two cottages clear against the hills The far shore of the mere from the jetty, 5 October, with far tiles and tree cards.

Where it stood

The relayout to my map landed early that morning, and my first request was to see it: "can you load up a dev server for me to play what we have on so far ... including any mazes etc".

The village was over its frame limits, and I accepted that until the next spec measured again. I also asked whether those limits were made up at all (the answer was half yes: the frame limits come from real refresh rates, but the 8 and 6 ms streaming budgets "were picked by agents and you accepted them", and everything had been measured on my own fast Mac), adding "especially when we start to look at integrating meshy models etc". I kept the milliseconds and loosened something else: "Lets relax on the initial Kb download, I dont mind this being raised a little."

Under the hood On High, first person at the village spawn took 13.2 ms a frame. Everything past 60 m cost 4.6 to 5.1 ms of it: about 575 woodland trees at full detail (one model was 45,000 triangles), field walls and cottages, all loaded out to 192 m.

Tiles and cards

The plan, which went through two Codex review rounds before I saw it, had two parts.

A far tile is 128 metres of land baked into one simple mesh with no textures: lanes painted into the ground's colour, every building simplified and tinted with the average colour of its own textures. A small map says which chunks are loaded in full, so each patch of ground is drawn once, near or far, never both.

A tree card is a tree drawn as a flat picture that turns to face you. The bake photographs each tree from eight sides and the game shows whichever matches where you stand, lit so a card still darkens on its shaded side.

One ruling went to me: build it as specced and judge the haze and the card swap once I could see them? I answered with the morning's other questions: "go with your recommendation elsewhere". In the same message I saved the chapel. Its new spire, built that morning because the chapel did not read as a chapel from the square, had pushed the village's code over its size ceiling, and trimming it was an option. "raised js limit is fine, dont cut the chapel 0.7kb".

The agents built it in four pieces, all merged by lunchtime: Low's slow building steps split into smaller ones, the far ring itself, the bake, then the cards.

First person from the tithe barn before far tiles: a wall and lane lead into a pale haze where the village should be From the tithe barn, before: the village is a smudge in the haze.

The same view after far tiles: the chapel's spire, cottages and a fir stand clear across the fields The same spot after, with the same light and settings. The spire was already there; now you can see it.

Under the hood Each tile is capped at 200 KB. The final cap of 15,000 triangles a tile left the whole village's far land at 16 tiles and about 1.3 MB, and on High the full-detail ring came in from 192 m to about 128 m.

Did the cards look like trees?

The test that mattered was whether you could tell. The agents shot the north woods with cards and with every tree as its full model, in summer and winter. Side by side they are hard to tell apart. The swap itself was still a hard switch, left for me to judge when I walked it.

Four crops of the same woods: full models on the left, cards past 64 m on the right, summer above and winter below The north woods: every tree a full model (left) against cards past 64 m (right), in summer and winter. Period evidence from the cards piece.

Then the credits ran out

Early that afternoon my Claude usage ran out with the last piece, far-4 (its fixes and the performance tuning), half done and an art stream running beside it. I opened Codex and asked it to take over: "I've run out of credits. I want you to take over... What I'm worried about is they were in the middle of working when we ran out of usage."

The Codex agents recovered the interrupted measurements and carried on. An hour later I wanted a clean stop: "Can you get art and far-4 to a sensible stopping point?" Then I talked myself into finishing instead: "the moment I feel like we're a bit fragmented with far-4 not merged. I know we haven't done performance acceptance and reviews..." And: "Okay, let's do that one final far-4 piece so we can properly merge and remove its worktree."

The number that did not move

The view was the easy half. The plan had written down a target, 9.5 ms for that first-person frame, and four tuning steps in order: cards closer, full detail closer, lighter tiles, the far edge pulled in. The best reached 11.5 ms. After the art merge and the last fixes, the final measurement was 13.0.

Under the hood Final High numbers at the village spawn: first person 13.0 ms against 9.5 (missed), overhead 11.1 against 11.5 (met), streaming updates 5.2 to 5.7 ms against 8. No shader compiled while drawing on any walk.

The landing note recorded a miss, not a new limit, and handed the number to my next request, sent as I went AFK: independent audits, starting with "General performance of the app when playing".

Drawing the far land cheaply had worked. It just was not where most of the frame went: the spec had already guessed, for the overhead view, that the rest was the shading of what stands near you.

The mere from the jetty before far tiles: the far shore's trees and cottages are ghosts in the haze The view at the top of this post, before: the same jetty, the far shore lost in haze.

A stall inside three.js

That night the agents chased a hitch walking towards the proving ground: one callback took 44.5 ms because five shader programs were still linking mid-play. The cause was a known three.js bug, already fixed upstream, so they backported that fix as a pinned patch rather than writing their own shadow code. The hitch fell from about 40 ms to 12.9. The next morning's commit recorded the first-person investigation "without speculative tuning": find the cost before you change anything.

What I took from it

Measure first, and write the target down. The tiles fixed the view for very little, but the written target is what stopped a better view passing for a faster frame.

The valley I had just laid out was huge, and from the village square you couldn't see the other side of it. The keep on its crag, the chapel on its hill and the far shore of the lake all melted into one pale wall of haze. The game was also working hard on things a long way off, and that was slowing it down.

On 5 October the AI helpers built an answer in a morning.

First person at the mere's jetty: the far shore with trees and two cottages clear against the hills The far shore of the lake from the jetty, now clear to see.

Painting the distance

The trick is the same one a theatre uses with a painted backdrop. Things far away don't need every detail.

  • Far land is now drawn as a simple model with the colours painted on: lanes, fields and buildings in their own colours, but no fine detail.
  • Far trees are drawn as flat pictures that turn to face you, like cardboard cut-outs. Each tree has pictures from eight sides, so it still looks right as you walk round.

Close up, everything is still full detail. The game just doesn't load full detail quite so far out.

First person from the tithe barn before far tiles: a wall and lane lead into a pale haze where the village should be Before: from the barn, the village is a smudge in the haze.

The same view after far tiles: the chapel's spire, cottages and a fir stand clear across the fields After: the same spot. The chapel spire was always there; now you can see it.

Could you tell?

The real test was whether the cut-out trees looked like trees. Side by side with the real ones, in summer and winter, they're hard to tell apart.

Four crops of the same woods: full models on the left, cards past 64 m on the right, summer above and winter below Real trees on the left, cut-outs on the right, summer and winter.

Running out of helpers

Halfway through the afternoon I ran out of usage on my main AI helper, with the last piece half done. I switched to a different one and asked it to take over. It picked up where the first had left off, and we finished the job properly rather than leaving it in pieces.

The speed didn't really improve

The view was the easy half. I'd written down a target for how fast the game should run, and we didn't hit it. It barely moved. Drawing the distance cheaply worked, but it turned out most of the effort was going on things near the hero, not far away. So the next job became a proper check of where the game was actually slow.

What I learned

Measure first, and write the target down. The far view was fixed for very little. But having the target written down is what stopped a prettier view being mistaken for a faster game.

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

G18 6 min read

The village becomes a streamed region and Kit Yard retires

On 3 October the village moved onto the open-world engine without a single building moving, and Kit Yard, the test hamlet, was retired. The proof was boring on purpose: every village test passed without changing what it checked.

Building Brackenmere

G15 7 min read

Streaming an open world: chunks, paths and haze

Over three days the agents built the groundwork for Brackenmere as one seamless, ever-growing valley: chunks that stream in round the hero, a test square kilometre, people who can walk across it and haze instead of fog. The real faults were found by walking it, not by the tests.