diff --git a/src/AcDream.App/Streaming/StreamingController.cs b/src/AcDream.App/Streaming/StreamingController.cs
index 35362a6..6bdd957 100644
--- a/src/AcDream.App/Streaming/StreamingController.cs
+++ b/src/AcDream.App/Streaming/StreamingController.cs
@@ -26,26 +26,22 @@ public sealed class StreamingController
public int Radius { get; set; }
///
- /// Cap on completions drained per call. Defaults to
- /// effectively unlimited because the current LandblockStreamer
- /// is synchronous — every EnqueueLoad writes to the outbox on
- /// the same thread, so by the time we drain there's no backlog
- /// to spread, and the cap only serves to *delay* applying landblocks
- /// the user is already trying to look at.
+ /// Cap on completions drained per call. The cap is
+ /// the GPU upload budget for one frame: terrain mesh + per-entity GfxObj
+ /// sub-mesh uploads + texture uploads for one landblock take a few ms;
+ /// applying 25 of them in a single frame produces a memory spike
+ /// (observed: out-of-memory crash on the 5×5 first-frame load).
///
///
- /// The original async design used a small cap (4) to limit per-frame
- /// GPU upload spikes. That reasoning becomes relevant again if/when
- /// the streamer moves back to async loading; lower this knob then.
- /// Crucially, dropping completions to a lower frame is what was
- /// silently breaking live spawns: the post-login spawn flood would
- /// arrive on a frame where only 4 of the 25 visible-window landblocks
- /// had been applied, the spawns for the other 21 hit
- /// AppendLiveEntity with no matching loaded slot, and got
- /// dropped (now: parked in the pending bucket).
+ /// 4 is the original async-streamer value; it spreads a 5×5 first-frame
+ /// load over ~7 frames (~116ms at 60fps), which is below the human
+ /// perception threshold. Spawn races that previously dropped entities
+ /// while landblocks were in flight are now handled by
+ /// 's pending-spawn list, so spreading
+ /// completions doesn't lose any data.
///
///
- public int MaxCompletionsPerFrame { get; set; } = int.MaxValue;
+ public int MaxCompletionsPerFrame { get; set; } = 4;
public StreamingController(
Action enqueueLoad,