Three million building pieces. One person. The only way to see what people had built was to stop flying the camera by hand and teach the geometry to place it instead.
Everything below this is machinery. This is what the machinery is for: photographs of other people's buildings, framed by arithmetic, on a server where no human ever lined up the shot.
The world is a community server sixteen eras old. Its save file holds roughly 3.15 million player-placed building pieces. Somewhere in there are the builds worth looking at, and there is no index of them — a Valheim save is a flat bag of objects with coordinates, not a list of buildings.
So the whole job is a funnel: turn a bag of pieces into a list of structures, rank the structures, photograph the top of the list, then rank the photographs.
The first version of this had a person in the middle: read a shot list off a second monitor, teleport, look around, press a key, repeat. That works for twenty shots. It does not work for fourteen hundred.
The fix was to make the plan a file the game reads at startup, and to make the game write back a receipt for every frame it takes. Once both halves exist, the loop closes and the operator's only job is launching it.
The two halves are written in different languages, run in different processes, and cannot call each other. Everything they share is a file. That constraint turned out to be a feature — each handoff is inspectable, replayable, and diff-able.
One deliberately unglamorous choice: the plan the mod reads is tab-separated text, not JSON. The plugin has no JSON parser, it scrapes with regex, and one flat line per shot is far harder to misparse than nested objects.
Every layer already existed for another reason. The world cache was built to answer steward questions. The perception model was on the box for a photo library. The mod started life as a proof that a camera could be moved at all. The work was wiring, not invention.
There are four small pieces of arithmetic in this, and none of them are clever. What made them work was measuring instead of guessing.
Building pieces are snapped to a 16 m grid. A cell holding at least four pieces is "occupied". Occupied cells touching in a 26-neighbourhood get unioned together. What falls out is one cluster per structure, with a true 3-D bounding box.
Doing this in three dimensions rather than two is not optional here. This world has builds stacked vertically, and a flat grid merges a sky platform with whatever sits on the ground beneath it — producing "structures" with nonsense five-kilometre bounding boxes.
Given a bounding box and a field of view, the standoff distance is secondary-school trigonometry. The part that took a second attempt was deciding what to frame.
The first version framed on the bounding diagonal, and every photograph came back as a smudge in the middle of a hazy frame. A cluster's diagonal is inflated by sprawl — outbuildings, walls, a dock — so framing on it pushes the camera back past the thing people came to see. Framing on the compact extent instead fixed it: on one build the diagonal wanted the camera 267 m out, the compact extent wanted 136 m. The second one is the photograph.
There is no heightmap. Valheim generates terrain from the world seed and the save holds only objects, so no offline elevation data exists at all. The trick is that a cluster's lowest piece is ground at that build, because a foundation rests on it. Only the in-game runner needs a real ground query, and only to stop a camera landing inside a hillside.
The first planner used time-of-day 0.70 and 0.30 for the two light variants, because those sound like golden hour. Then a 207-frame sweep measured luminance and contrast across the whole day, and both guesses turned out to sit past the good light.
| Time of day | Luminance | Contrast | |
|---|---|---|---|
| 0.29 | 74.9 | 105.2 | the old dawn value — already falling off |
| 0.32 | 121.5 | 157.4 | adopted: morning |
| 0.64 | 121.6 | 159.8 | adopted: peak contrast in the sweep |
| 0.67 | 118.8 | 153.7 | |
| 0.70 | 83.1 | 118.2 | the old orbit value — 26% less contrast |
The number on a gallery tile used to be the structure's ranking score, which is identical across all six photographs of the same building. It ranks places. It cannot tell a good picture of a place from a bad one, which is the thing a gallery actually needs.
So each frame now goes through a CLIP ViT-L/14 image encoder and a small LAION aesthetic head — the same model and weights already sitting on the box for an unrelated photo library. No new download, no new dependency.
The clearest way to explain a pipeline is to show what falls out of each end of it. These are real records from the run that produced the photographs above, with coordinates removed — they attribute real builds to real people, and this is a public page.
{
"world": "ComfyEra16.db",
"method": "3-D connected-component clustering of BUILDING ZDOs on a
16x16x16 m grid (min 4 pieces/cell, min 400 pieces/cluster)",
"count": 1833,
"clusters": [{
"cluster_id": 51, "region": "in-world", "sky": false,
"pieces": 21464, "score": 15.663, "distinct_prefabs": 132,
"center_x": ·····, "center_y": ·····, "center_z": ·····,
"size_x": 150.2, "size_y": 100.0, "size_z": 176.4,
"footprint_m2": 26494.0, "diagonal_m": 252.3,
"suggested_standoff_m": 227.1, "suggested_camera_y": 135.1,
"distinct_creators": 5, "portals": 4, "signs": 2857
}, … 1832 more]
}
# cluster_id shot cam_x cam_y cam_z yaw pitch env time aim label
439 orbit1 ···· ···· ···· 225.0 27.39 Clear 0.64 ··· Pirate's Haven
439 orbit2 ···· ···· ···· 315.0 27.39 Clear 0.64 ··· Pirate's Haven
439 orbit3 ···· ···· ···· 45.0 27.39 Clear 0.64 ··· Pirate's Haven
439 orbit4 ···· ···· ···· 135.0 27.39 Clear 0.64 ··· Pirate's Haven
439 dawn ···· ···· ···· 225.0 27.39 Clear 0.32 ··· Pirate's Haven
439 weather ···· ···· ···· 225.0 27.39 Misty 0.66 ··· Pirate's Haven
{
"run": "20260806-110505", "index": 478, "cluster_id": 407,
"shot": "dawn", "file": "0407_dawn.png",
"planned": { x: ···, y: 97.800, z: ··· }, ← what the planner asked for
"placed": { x: ···, y: 97.800, z: ··· }, ← where the engine put the player
"lens": { x: ···, y: 99.386, z: ··· }, ← where the camera actually was
"lens_offset_m": 1.648, "clearance": "planned",
"yaw": 45, "pitch": 26.31, "fov": 65,
"environment": "Clear", "time_of_day": 0.32,
"pieces_near_aim": 3377, "occluded": false,
"at": "2026-08-06T12:35:28.109-07:00"
}
Three positions, not one. planned is the request,
placed is where the engine actually dropped the player after its own
ground clamp, and lens is the camera — 1.6 m above the player
origin, because the eye is not the feet. Keeping all three is what lets a frame be
audited a week later instead of trusted on faith. occluded and
pieces_near_aim come from a raycast at capture time: if nothing is in
front of the lens, the frame is a photograph of fog and gets dropped.
{ "n": 1411, "runs": 54, "joined": 1411,
"environments": ["Clear","Misty","Rain","ThunderStorm"],
"kinds": ["build","hub","major hub","museum","settlement","sky build",
"sky museum","sprawl","tall hall","tower","shared build"],
"images": [{
"id": "20260806-071848_0439_orbit1", "variant": "orbit1",
"aesthetic": 6.313, "score": 11.013, "cluster_rank": 692,
"label": "Pirate's Haven", "kind": "hub", "builders": 3,
"pieces": 4124, "height_m": 25.8, "footprint_m2": 7049.8,
"occluded": false, "published": false
}, … 1410 more]
}
"published": false is the default on every single record,
and it is deliberate. Ingest is automatic; exposure is not. These are other people's
houses.
A cluster's identity in the save file is cluster 439. That is useless in a
gallery. The obvious fix — read the prefab names and infer "this is a longhouse"
— does not work: the analytics cache stores prefabs as hashes like
hash:538325542, and the offline name table holds 617 item names and
no building pieces at all.
So the naming step skips the metadata entirely and shows a vision model the photograph. It gets back a name, a one-line description, and a feature list.
{
"22": {
"name": "Pride's Portal",
"blurb": "A grand entrance to an ethereal realm with glowing
lanterns and a golden portal.",
"features": ["Glowing Lanterns", "Golden Portal",
"Architectural Columns"],
"from_image": "20260806-015620_a_clear_t38", "pieces": 9603
}
}
Names that came back this way include Tree of Light, Skyward Tower, Marble Oasis, Gothic Ruin and Kleenex Gate. The last one is not a mistake — it is a real build, and the model read the sign.