Repository navigation
How it works
What was measured (2026-10-14, in the game on a Mac, at the launch pad, with a 230-part craft and every mod of the
workspace installed, after a session of loads and scene changes): a frame took 25.8 ms, waiting on the processor. The
dearest thing the game itself did was its terrain coroutine, PQS.UpdateSphere: 6.0 ms of every frame. Kerbin's
terrain (its quad tree) was being updated 75 times a frame.
Why (the game's own code, decompiled): a world's terrain update is started as StartCoroutine(UpdateSphere()), the
routine itself, at every start of the sphere (every load, every scene change, every time the world is brought back), and
stopped with StopCoroutine("UpdateSphere"), by its name. Unity's stop by name ends only coroutines that were started by
name: none ever is, so each start adds one more update that runs until the game is closed.
The fix: the newest update started for each sphere is noted, and an older one still running for the same sphere ends at its next step, doing nothing more. Measured again in the same place: the terrain's update took 0.23 ms a frame.
Its twin: the sphere's other coroutine, ResetAndWaitCoroutine (started at every reset, stopped the same way by
name), leaks alike: 28 of them were found ticking every frame for the worlds not in use, each waiting for its world to
come alive. They are cheap while they wait; they are mended the same way.
KSP Community Fixes mends the same flaw in its own way. With it installed only one update is ever running, and this fix changes nothing.
What was measured (the test save, rounds of scene changes: space centre, assembly building, space centre, a
flight): every round left about 420 more handlers on the game's events (a handler: someone the game tells when
something happens), 4,200 after the third round against 2,950 at the start. Some 330 of each round's were the game's
own records of which parts share resources (PartSet), two each. Most of the rest belonged to things already
destroyed: a craft's network link, the staging list's groups, the editor's own logic.
Why (the game's own code, decompiled): such a record adds itself to two events when it is made and takes itself off only in its finaliser, which never runs, because the events themselves keep it alive. So every one ever made stays, told of every change to a resource's flow, keeping the parts of craft destroyed long ago in memory for the collector to go through at every collection. And the game takes a handler off an event only when what it belongs to is gone altogether, while a destroyed object of Unity's is still something to the code that checks.
The fix: once each scene is ready, every one of the game's events is gone through, and a handler is taken off if what it belongs to is a destroyed object, or one of those records whose craft is destroyed or whose every part is. A record that is empty, or whose craft is being built in the editor with no parts yet, is left alone; nothing else is touched. Measured: 363 taken off at one change from a flight to the space centre, 332 of them part sets'; with it, a round of scene changes left 18 more handlers instead of 420, and the managed memory freed at one clean-up was 15 MB.
What was measured (from a flight to the space centre): Unity went through every one of its loaded things for any no longer used three times, 190 to 200 ms each with the game's quarter of a million things, nearly all of it in marking what is still used. The first freed the 3,727 things of the flight; the second freed nothing; the third, once the space centre was in, freed 11.
Why: the game changes scenes by loading a scene that is all but empty first (its "loading buffer") and then the one
asked for. Unity goes through its things by itself every time a scene takes another's place; and the game, in the same
step as asking for the buffer, asks for one more (HighLogic.bufferedLoad), which comes right after Unity's own with
nothing having changed in between.
The fix: that one call of the game's is left out, in both of its ways of changing scenes; Unity's own, after the buffer is in, still frees everything the last scene left. Measured: two goings-through instead of three (3,730 things freed, then 11), and the change from a flight to the space centre took 3.22 s to the space centre's last mod being ready instead of 3.36.
KSP Community Fixes has a fix of its own for this (by its own account, one going-through left of three). This one only leaves out the game's own extra call and never touches Unity's, so with both installed nothing is lost.
What was measured (in the game on a Mac): a place fixed on the planet, where the middle of the picture meets the sea,
followed across the screen frame by frame; the judder is how far its speed across the screen strays from its running
mean over 17 frames, as a share of that mean (0 is perfectly even; 0.3 is jumps of about a third). An Aeris 4A at 260
m/s, 700 m over the sea, the camera 25 m from it looking down 40 degrees: 0.31 to 0.32 at 31 frames a second, 0.26 to
0.27 held at 30 (29 came). Held at 25 it was 0.03 to 0.06: then every frame took a little over 40 ms, the game holds its
clock to 40 ms a frame at most (PHYSICS_FRAME_DT_LIMIT), and every frame got exactly two steps.
Why (found by the rendering research, from the game's own code, decompiled): the game moves everything in physics steps of 0.02 s and draws the pose the last step left; nothing smooths a part's body between steps. At 31 frames a second some frames carry two steps and some one, and the picture goes forward in uneven jumps. And above 5 m/s the game holds the craft flown still in the scene and moves the world past it instead, also a step at a time.
The fix: once the frame's scripts are through, just before its first camera draws, every craft in physics is
carried on to where it has got to: everything of each part that is drawn (its model, and what hangs beside it: a
decoupler's shroud, the game's effects, all of a kerbal on foot) by the craft's velocity against the world (its bodies'
own and the game's moving frame's) times the time since the last step, and turned by its turning about its centre of
mass. The camera goes with the craft it follows, unless a mod holds it still (Cinema Camera's camera left standing on
the ground). Loose bodies (fairing panels, a wreck's pieces) go by their own velocity, and what other mods hang on the
moving frame by its own going on. All is put back after the near camera has drawn, and again before every physics step
and every Update; the parts' own bodies are never moved, and physics never sees any of it. Other mods that draw things
riding with a craft read how far it was carried from Keystone (Keystone.Motion).
Measured again in the same place: 0.31 to 0.07 at 31 frames a second; 0.27 to 0.04 and 0.06 held at 30; held at 25, with no beat to take out, the same with it and without (0.05 and 0.06). In a low orbit (2,060 m/s), with a kerbal out beside the capsule and each carried on by up to 41 m a frame, the gap between them on the screen moved by 0.01 pixels from frame to frame, the kerbal flown or the capsule. A rocket's flames, its smoke and the lamps on its engines stay at their nozzles. It costs 0.46 ms a frame for a craft of 230 parts in orbit, and nothing for one standing still.
Found on Windows: after a switch to a pilot holding a plane's ladder, the whole view tilted for a frame or two every 0.1 to 0.16 s (the horizon up to the right, the plane jumping), and went on so while the pilot only held on. With "Each frame at its own moment" off, none; with the blending or Steady Camera off, still there. The cause: the camera's pivot hangs from a kerbal's part, so it was carried as one of the part's models, turn and all, in every view (the carrying means to turn the camera with a craft only in the locked view); and a kerbal on a ladder has a turning the game gives its body and it never makes, carried over up to a fiftieth of a second: a kick each time the frames and the physics steps fell out of step (56 frames a second against 50 steps). The fix: the pivot is left to the pivot's own carrying, moved with the craft and turned only in the locked view. After: on Windows no kicks in three films of the pilot on the ladder, the picture as still as with the carrying off, and the switches filmed again without a flicker, flash or jump; on the Mac the pilot on the ladder filmed twice and walking once, every frame: no flicker, jump or jitter.
Asked for (the owner, 2026-10-11: "If your computer runs at, say, 10 FPS, it'll blend the frames together as well as it can"; 2026-10-17: "I want the frame blending to be even better"). What can be done: the game cannot be made to show frames it does not run. Every frame shown is a whole round of the game, and on a Mac the round itself, not the drawing, holds the frame (measured the same night: the plane over the sea 26 of its 30 ms on the main thread), so a frame made up in between would cost a round as well. What makes a film at 24 frames a second read as motion is its shutter: each frame holds what passed while the shutter was open, smeared along the way it went. That is what is done here.
How: after the scene, its clouds and its smoke are drawn, and before the drops on the camera's glass (they ride with the camera), each pixel is blended along the way its point moved against the camera since the last frame, for the shutter's share of the frame (180 degrees by default: half; a film's). Where the point is comes from the near camera's depth picture; beyond it (the far camera's ground, which the near camera never sees) the planet's own round ground where the line of sight meets it, or the sky, infinitely far. How the camera moved is reckoned in the planet's own frame, so the game moving the world under the craft, moving its origin, or turning the planet changes nothing. The craft the camera follows, and one more within 300 m, are given their own motion inside their box (from their parts' colliders): a followed craft moves with the camera and stays sharp, while the ground streams past it; a craft rolling under a locked camera stays sharp while the world turns round it. What stands well in front of a pixel's own point is not blended into it, so the ground streaming past a craft does not take the craft's colours along. A cut (the view changed, another craft taken: the camera turned by more than 30 degrees in a frame, or moved further than its craft could) is drawn as it is; so is time warp on rails, where a frame jumps by minutes, and any frame a lens of Keystone's already smears (Cinema Camera's shutter): the two would smear twice.
What was seen (2026-10-18, the Aeris 4A at 256 m/s 400 m over the sea, frames held at 15 to 20 a second): the sea near the camera and the sun's path on it smeared along the motion, the plane, the clouds and the sky sharp; rolling under a locked camera beside it, the world streaked up and down by about 16 pixels (the camera swinging round the plane's axis at 37 degrees a second), the plane sharp. Cost: within the noise of these frames (35-41 ms either way, three rounds each): it is one pass on the graphics card, twelve looks a pixel, and none at all in a frame where nothing moved.
Measured (fresh games, the test rocket's first lift-off from the pad, with Mono's own record of what it compiles, put in while the game runs through its profiler hooks): the runtime compiles each method the first time it is called and keeps it for the rest of the game, and a game's first lift-off calls 137 of the game's own methods for the first time (staging, an engine's first steps and its effects, the staging list's gauges, the flight's log, the gimbal, leaving the pad's colliders): 11.3 ms of compiling on the game's thread, 7.6 of it in the staging frame and most of the rest in the frame after, which were already the two slowest of the flight.
Here: four seconds into the first flight scene of a game, those methods (and the few generic ones of the game's own
classes they use) are looked up and compiled, a millisecond and a half's worth a frame (MethodHandle.GetFunctionPointer,
on the game's own thread). 160 compiled in 12 to 16 ms spread over a dozen frames; in the lift-off after it the compile
log showed none of the game's methods compiled, only the mods' own. Only methods of classes the game is already using by
then are on the list: compiling a method readies its class, and a class not yet in use could have its own set-up run
early (the ones on the list set up only events and plain numbers). Not compiled ahead on another thread: a class readied
there whose set-up touches Unity breaks for good.
Measured (the test save's craft in a 250 km orbit of Kerbin, a round of time warp on rails from x5 up to x1000 and back,
the game drawing as fast as it can, with the development tracer on the game's terrain): the warp's longest frames, 110 to
154 ms, were the game building the terrain under the craft as it raced over it, 65 to 119 ms of a frame in
PQS.UpdateQuads: some thirty of the terrain's squares built at once, with the normals along their edges. The game lets a
world's terrain take up to a tenth of a second of any frame (PQS.maxFrameTime) before it leaves the rest of its building
for the next frame, and under warp, with the ground going by at hundreds of kilometres a second, it uses it.
Here: while time is warped on rails (where nothing meets the ground: the craft is high above it, or landed and still), and for five seconds after while the craft is more than 10 km up, every world's terrain is given 8 ms of a frame, its building going on in the frames after; then the game's own tenth again. The nearest squares are built first either way (the game sorts them by distance), so it is the furthest that come a few frames later. Not while the game builds a world's maps all at once (it sets its own budget for that).
The same round of warp four times, loaded afresh each time, with the fix off, on, off, on (frame lengths only):
| frames | over 50 ms | over 100 ms | the longest | mean | |
|---|---|---|---|---|---|
| off | 2997 | 11 | 4 | 151, 147, 138 ms | 11.1 ms |
| on | 2919 | 5 | 0 | 81, 70, 57 ms | 11.4 ms |
| off | 2781 | 11 | 4 | 155, 147, 140 ms | 11.9 ms |
| on | 2719 | 6 | 0 | 95, 76, 64 ms | 12.2 ms |
The mean frame is 0.3 ms longer with it on: the terrain's work is spread over more frames rather than done in fewer.
Found (Warm Start's probe build, and the game's own code): a launch's longest step is the home world's terrain, and it
is built twice. Setting a new craft on its launch site (FlightDriver.setStartupNewVessel), the game starts the site's
sphere (PSystemSetup.SetPQSActive with that sphere: PQS.ForceStart, the whole sphere round the site built at once,
482 of its squares, 1.2 to 1.7 s; every other sphere told to reset and wait), puts the craft on the ground, and then calls
SetPQSActive() with no sphere, which tells every sphere to reset and wait: the one just built is thrown away, and since
the craft is on it, built again on the spot. A save's craft loaded into flight, and a revert to launch, are set up the
other way, once.
Here: within a launch's setting up, that second call is left out when a sphere was started for the launch (every other sphere was already told to reset and wait by the first). KSP Community Fixes mends the same (its PQSOnlyStartOnce): where it is installed this one stands aside.
Kerbal X launched from the space centre four times, the fix off, on, off, on (from the ask to the craft on the pad and unpacked): 8.46, 7.23, 8.07 and 7.37 s, a second sooner with it. Seen afterwards from 120 m and from 2.5 km: the pad, the buildings, the runway and the ground round them whole.
Each traced with the development tracer (the game's classes for the case and the mods' own), the frames over a limit kept:
- Time warp (as above): besides the game's terrain, Natural Weather's lying snow was worked out from orbit, where it is never drawn: 20 to 23 ms of every frame under warp (the last three days at each new place, the craft 20 km on every ten seconds, worked out again). The weather of a place made on the game's thread when first asked for, 3 to 15 ms a time, and at x1000 ten places in a frame, 12 to 28 ms. Both mended in Natural Weather (0.5.0). Still there: Natural Weather's look through the whole scene for EVE's clouds (to hide them), which runs whenever the camera has moved 3 km and so every frame under warp, 5 to 58 ms.
- The map view (the test save at the pad at midday, the map of Kerbin with every craft's orbit): 187 frames a second, 36 of 719 frames over 12 ms (the longest 32): Natural Weather's lightning working out a region's storms on the game's thread every ten seconds (15 ms), its wind on the craft (12 ms) and its icing (10 ms, twice a second), Natural Light's daylight under the clouds (3.7 ms). Natural Weather now makes each region's and each place's weather for the next stretch of time on another thread, and the icing uses the region's: 193 frames a second, 1 of 972 frames over 12 ms (13.8 ms).
- The editor (the assembly building with a craft of 230 parts): 58 frames a second, 6 of 362 frames over 20 ms, each of them Kerbal Skins looking through the whole scene for kerbals' heads twice a second (7 to 10 ms) and dressing them (3.5 to 4.3 ms). Kerbal Skins (0.3.0) now looks through the scene every five seconds outside flight and keeps each kerbal's head pieces and eyes between: 66 frames a second, 1 of 404 frames over 20 ms (22 ms) and none of the next 394.
The tracer's own cost is in all of these: the later traces wrapped fewer methods, and some of the difference is that.
Timed from the game with Warm Start's probe build (the steps the game and every mod take in a scene change, through Harmony,
and every frame's length), on this Mac with the workspace's mods: the pad to the space centre 5.8 s, a save loaded again
2.8 s, a launch 8.9 s, a revert 5.5 s, a recovery 6.7 s. In every one the largest step is the same: the home world's
terrain started again from nothing (PSystemSetup.SetPQSActive → PQS.ForceStart, which builds the whole sphere of
terrain at once), 1.34 to 1.47 s each time, in the change's first long frame; a launch adds the craft's own building, about
1.2 s more. The mods' own Awake, Start and OnStart come to tens of milliseconds a change. The first flight after a start
holds a frame of 11.7 s in which the game logs nothing and none of the timed steps runs, just after the flight's interface
wakes. A native sample of the game through it (macOS's sample) found the main thread computing in its own code, the
engine's or the game's (under Rosetta they cannot be told apart), not in the graphics driver: not shaders. The next look:
every one of the game's own behaviours' Awake and Start timed. Not yet cut: the terrain's start is the game's own, and building less of it at once would show
the ground filling in.
Looked at again on 2026-10-20 with the development tracer (the game's classes of a flight's making and every mod's own),
the game started afresh and its first flight loaded from the space centre: the longest frame was 4.1 s, not 11.7. Of it
1.9 s was the flight's start (FlightDriver.Start), 1.7 s of that the terrain's (482 squares built at once: the worlds'
heights at 108,450 points 0.75 s, the squares' tangents and normals 0.27 s, the normals along their edges 0.28 s); the
rest the game's and Unity's own, outside anything wrapped. The terrain's start is left as it is: building it over frames
would show the ground filling in round the craft, and EVE's clouds, Scatterer and the space centre's buildings wake with
it. What could go was the second building in a launch, above.
In the Keystone window (the keystone button on the game's toolbar, or Alt-K; Option-K on a Mac), under Smooth Running: a switch for each fix, and what each has done in this game (extra terrain updates ended, clean-ups left out, handlers taken off, warps with the terrain spread over frames, launches' second building of the terrain left out).
- Eight fixes so far. The rest of the measured frame is the game's own physics and drawing, and each further fix waits on its own measurement. A scene change still has two goings-through of Unity's things: the last, after the scene asked for is in, is Unity's own and could be left out only by changing how the game loads its scenes.
- Each frame at its own moment: what the game's own particle systems throw into the world (a solid booster's smoke) is
thrown from the nozzle where the last step left it, so a trail can begin up to a step's travel behind its nozzle (a
few metres at a few hundred metres a second), mostly inside the flame. Things other mods hang on a craft in the scene,
apart from its parts, are carried only if those mods read
Keystone.Motion; the ones that do are listed on Keystone's page for mod authors. Not while time is warped or the game is paused, nor in the cockpit's view or the map. - Frame blending blends only what the camera's and the craft's own motions explain: a craft that moves while the camera stands still (a launch watched from a tripod) is drawn sharp, and a thing moving with the camera that is not a craft (smoke riding with it) is blended as if it stood still. Its edges are those of a craft's box, a little larger than the craft. Not in the map view.
- Tried on a Mac only. On Windows it is the same code but for frame blending's shader, which the Unity editor builds
there (
blend-windows.bundle, at the release); nobody has run it there yet.