2026-09-24 · 9 MIN READ
The contract came first
My game's clouds went from painted puffs to a volume you can fly through in one evening. The part worth writing about is what happened first: after three weeks of water detail that vanished while every test passed, the rules for what the clouds must show were committed before a single pixel changed, and the first build failed them on four counts.

At six minutes to eight on the evening of September 23, my coding agent committed the twelfth capture run of my game's new clouds and wrote one line into the history beside it: detail erosion 1.13 against a floor of 1.15, dead by 0.02, floor not moved. The frames in that run were the best sky the game had ever drawn. The line said a part of them was not there.
Spaceframe is the survival game I have been building since July, on a planet 10 km in radius, in Godot, with my coding agent writing most of the code against probes I insist on. Until that evening its clouds were soft cartoon puffs that the sky shader drew in a layer at a fixed height above your eyes, so climbing a mountain lifted them with you and nobody could ever reach one. What replaced them is a volume of cloud wrapped around the planet, 1.2 to 4 km up, that you can climb through and look down on. The clips below are that first version, recorded from the running game.
The village at noon, the village at sunset, a climb from the ground up through the deck, the view from above it toward the planet's edge, and a mountain on the taller world in the morning, played back to back. A capture scene flies the camera and saves every frame at 2560x1440 under a fixed 60 fps clock; cuts only, no music, no narration.
The failure attached to that first version is the point of this post. The same afternoon the agent had finished a retrospective on the three weeks it took to make the game's water look real, which I wrote about here as it happened. Its headline was not what I expected. Almost nothing had been deleted by accident. The detail that went missing had mostly never reached the screen at all, while every test stayed green: math that summed to zero on a sphere, a shader that never compiled, an anti-aliasing default kept on a belief that had been disproved days earlier. Its table of losses says how long each one lasted.
From the water retrospective's table of 24 losses and regressions across 359 water-related commits since August 25. Each ran this long with its tests green. The anti-aliasing row counts from the day its belief was disproved. Three of the 24 were found by my eye and no test.
The cause the retrospective ranked first was simple to state: no test measured what each effect contributed on its own. The tests proved the model underneath, or the whole frame, and neither could see one term that had gone dead. So the clouds got a contract before they got a shader, and it has three parts. Every effect in the cloud system is listed with the knob that turns it off, and a probe renders the same frame with it on and off; if the difference falls below a floor written down in advance, the effect is dead and the check fails. A fixed set of camera stations, from the village at noon to 2 km up looking at the horizon, is captured on the current game first, so every number is a comparison with what was already there. And nothing that changes how the game looks merges until I press Approve for that exact commit on a review page.
That last part replaced a rule from the day before, under which the coordinating agent merged look changes on its own verdict from the captures. The retrospective credited three of its findings to no test at all, only to my eye. A second model, asked to critique the plan, called the whole thing over-engineered and suggested alerts in place of my sign-off. I kept the sign-off.
The order is in the git history. An afternoon spike had already answered the two questions that could have sunk the approach: whether a compute pass in Godot's compositor can read the depth buffer, so a hill hides the cloud behind it, and whether 32-bit floats hold up 10 km from the world's origin. They did, to 0.39 mm, once the ray-sphere intersection used a form that does not subtract two enormous numbers from each other. Then the contract, the capture script and the metric script landed with no rendering change at all. The current game's sky was captured against them twelve minutes later, and the first cloud commit came a few minutes after that.
The clouds themselves are marched, not drawn. A compute pass steps each pixel's ray through a shell between two spheres centered on the planet's core, reading a baked cube of noise for the billows, a smaller one for the frayed edges, and a weather map the GPU generates from the game's own weather state, so cloud forms where the weather says it should. To afford that, it marches at half resolution and reuses earlier frames, moving each pixel by the depth of its own cloud rather than by the terrain's motion. The lighting is deliberately crude for now, a single sun term plus two soft copies standing in for light that scatters many times inside a cloud. The difference from the village at noon is below.

The same station, sun and seed on the current game and on the CL1 branch at the High tier. The dark flecks in the old frame are birds; captures hide them now.
The third capture run failed on four counts. Three of the four effects measured below their floors, and 2 km up the new deck still stopped short of the horizon. The dead readings turned out to be partly the stations' fault rather than the effects'. The view from above the deck was mostly empty sky, so there was little cloud to score, and the game's own anti-aliasing blends frames together as well, which hid what the clouds' frame reuse was adding. The agent moved those stations, straight down onto the deck and with anti-aliasing off for that one pair, and wrote in the contract why. It did not touch a floor.
The gap at the horizon was a real bug. From inside or above the deck, a ray that dips under the cloud base and misses the planet climbs back out through the far side of the shell, beyond the curve of the world, and the first march stopped at the inner sphere and never looked there. Marching that second stretch closed the band where it counts for the gate, the median column, though 7 of the 17 columns measured are still outside it and the worst still shows 6.8° of open sky. The old clouds never could have closed any of it: they sit at a fixed height above the eye, so from 2 km up they still hover overhead, with nearly 40 degrees of empty sky between them and the true horizon. The two frames from that station show the difference.
The median across 17 columns of the frame at the 2 km station, 90° field of view with the true horizon in frame. In the final capture 10 of the 17 columns are inside the gate and the worst reads 6.8°.

Same station and time. On the left the old clouds float overhead with open sky beneath them; on the right the deck runs down over the curve of the planet.
The peak station taught the more awkward lesson. The contract asks for a mountain to pierce the deck, and on the default world none can, because its highest ground is 542 m and the deck starts at 1.2 km. So that one station borrows a taller world whose summit clears the cloud base by a few hundred meters, and there the top is bare rock with the deck wrapped around its flanks. The gate passes, on a world the player does not start on, which matters later.

The summit reaches 1,566 m against a deck base of 1,200 m. The metric finds no cloud on the summit and cloud over 84% of the peak's altitude band. The same frame shows the muddy brown of the first version's morning light.
Detail erosion was the effect that would not come alive. It eats into each cloud's edge with finer noise, so a silhouette frays the way real cumulus does instead of reading as a smooth blob. Between the third run and the twelfth the agent reworked it four times, coarser and stronger, then contrast-stretched, then finer, then stronger again, and its on/off ratio climbed from 0.71 to 1.13, against the floor of 1.15 set before the first capture.
Run 12, the one recorded in the contract. Each is a same-boot pair with the effect on and off, scored on coverage patchiness, frame-to-frame noise (off over on), local contrast and edge detail. At the third run, before three stations moved, the same four read 1.04, 1.10, 2.19 and 0.71. A later capture, not yet committed, read 4.76, 1.85, 1.51 and 1.24. The floors were set before the first capture and never changed.
The gap between 1.13 and 1.15 is too small to see, but that misreads what the number measures. After four reworks, the effect meant to fray every edge still barely changed the edges, and a floor set before anyone wanted a particular answer is how that stays a finding instead of a feeling. Across the water weeks the retrospective counts several gates loosened or overruled, each disclosed, one of them by me on this site when I kept foam that failed its coverage floor. This one was recorded as dead. Since then there has been an honest twist: a later capture, not yet committed, read the same term at 1.24 with the erosion's defaults unchanged. Either something else on the branch moved it, or a single on/off pair wobbles by more than the two hundredths the verdict hung on. The plan already calls for noise bands measured across several boots, and the cloud terms do not have them yet, so until they do the contract still says dead.
Ghosting failed next, and more usefully. Frame reuse is where the budget comes from, and its classic failure is a smear: fly fast and the last frame's cloud trails behind this one. The stability probe flies the camera through the deck and compares the trail with reuse on against the same flight with reuse off, and the difference may not exceed 0.01. It came in more than five times over. The agent's diagnosis was specific: against a fully settled frame, the whole cloud had shrunk about 1% toward the point the camera was flying at, which is history lagging behind, not blur.
A pan reprojects exactly, because turning the camera moves every point on screen the same way regardless of its depth. Flying does not: each part of a cloud slides by its own parallax, and one depth per pixel cannot hold a volume's worth of it. So the reused history now counts for less the further each pixel moved by translation that frame, and it is read through a sharper filter so that resampling it frame after frame does not soften it. All three flight samples now pass: the worst reads +0.002, and the other two smear less than the flight with no reuse at all.
The share of cloud samples trailing behind the cloud with frame reuse on, minus the same flight with it off; below zero means less smear than no reuse at all. The flight is 2.6 km up at 40 m a frame with the game's anti-aliasing on. A camera pan in the same run reads −0.024.
The rest of the contract passed and makes a shorter story, which is how it should be. The new clouds cost a fraction of a millisecond at every station, well inside the budget for this stage. The old clouds stay as a Classic tier until the handheld tier passes, and they render the same frame, byte for byte, as the game did before the branch. The weather map, 25 MB across six cube faces, hashes identically on two separate boots, which is what will let multiplayer clients share one sky by syncing the day counter they already send, with no new messages.
Paired frame-time medians with the clouds on and off at 1920x1080 on an RTX 4080, from the latest capture run; run 12 read within 0.03 ms of each. The High tier's budget rises to 2.5 ms once the lighting lands.
Then it was my turn. The review page is a private web page showing before and after frames, the numbers, and three buttons: Approve, Reject, Comment. Nine smaller visual branches from other lanes, shoreline plants and berry bushes among them, had already merged through it that day, each after my Approve for its exact commit. The clouds came to me first as a demo, five clips captured frame by frame at 1440p, which are the video near the top. I said two things. The first was that the form of the clouds is good, "but we need to research the different types of real world clouds and how they appear and how they form, and then use the tech that we just created to make those clouds." The second was shorter: "the clouds seem really far away."
The second note had its explanation sitting in the peak station all along. The deck's base is 1.2 km above the planet's surface and the default world tops out at 542 m, so from the village the nearest cloud is more than a kilometer overhead. The agent is preparing renders of the deck at lower bases for me to choose between on the review page. A lower deck would also bring the default world's own peaks into the cloud, which the peak station currently has to borrow a taller world to show.
The frames have other problems that no term in the contract measures yet, and they are in the gallery below because hiding them would defeat the point of the exercise. Golden hour at the peak is a muddy brown. The sunset is oversaturated, orange cloud against a red sky. The inside of a cloud is a featureless grey. From above, the planet is small enough that the deck covering it reads as a white dome rather than a sea of cloud. Most of that is the crude lighting, and the lighting checkpoint already has floors written for it: how much darker a cloud's underside must be than its top, a silver lining when you look toward the sun, and a band of hues for sunset undersides.



Sunset at the village, oversaturated; inside a cloud, a featureless grey; the deck from above, a white dome over a small planet. The peak frame earlier shows the fourth, the brown morning light.
The retrospective corrected me, too. In the water post I wrote that the sea had screen-space reflections for about a day before they were switched off. On main they lasted 58 minutes, and nothing else went off with them: the caustics and the refraction have been on since the day they shipped. That post now says so.
CL1, as the plan calls this first checkpoint, is not merged. The erosion term is recorded dead on evidence too thin to settle it either way, one capture run in the last round crashed the game outright, and nobody has diagnosed why yet, and the golden frames are waiting for my Approve. After the lighting comes the research from my first note, working through the ten cloud genera of the international cloud atlas and how each one forms, and god rays after that. What I keep noticing is how ordinary the most useful line of the day was: a ratio two hundredths short, written down as it came. The water taught me that a test cannot lose what it never measured. The clouds are the first system in this game where every part has to show, before it merges, that it reached the screen. That is one arc of work, an observation rather than a rule.



Frames from the clips, downscaled from 2560x1440 for the page. Tap any of them to open it full size.
- 01Where the ripples went: the three weeks of water
The water work this contract exists because of, including the two sentences the retrospective corrected.
/blog/where-the-ripples-went
- 02Schneider, The Real-time Volumetric Cloudscapes of Horizon: Zero Dawn (SIGGRAPH 2015 Advances)
The technique family the cloud shell follows: a weather map, baked Perlin-Worley and Worley noise, and a ray march through a layer of sky, amortized across frames.
https://advances.realtimerendering.com/s2015/index.html
- 03Hillaire, Physically Based Sky, Atmosphere and Cloud Rendering in Frostbite (SIGGRAPH 2016 course)
The scattering model the lighting checkpoint is aiming at, including the approximation for light that bounces many times inside a cloud.
https://blog.selfshadow.com/publications/s2016-shading-course/
- 04Haines, Günther and Akenine-Möller, Precision Improvements for Ray/Sphere Intersection (Ray Tracing Gems, ch. 7)
The intersection form behind the spike's 0.39 mm at 10 km from the origin; the textbook form subtracts two huge numbers and loses centimeters.
https://link.springer.com/chapter/10.1007/978-1-4842-4427-2_7
- 05International Cloud Atlas
Where the cloud-type research starts: ten genera, with how each one forms and how it looks.
https://cloudatlas.wmo.int/
- 06Godot Engine: the Compositor
The rendering hook the cloud pass runs in, after opaque geometry and the sky and before transparent surfaces.
https://docs.godotengine.org/en/stable/tutorials/rendering/compositor.html