3/23/26 Update
Hello Creators,
We are excited to announce that Texture Streaming is rolling out to clients across platforms starting today. Texture streaming gives you the freedom to add more texture variety and detail to your experiences without having to worry about scaling across all devices. It does this by rapidly loading baseline quality textures first in order of importance and then increases quality of textures up to the available memory on the device.
With texture streaming,
- Perceived load times can be much faster and total download sizes can be lower
- Important objects in your scene get higher quality textures without sacrificing stability
- Your players will face fewer Out of Memory (OOM) crashes due to textures
As a creator, you don’t have to do anything to enable texture streaming within your experience. As it rolls out on each platform, your players will automatically get the above benefits. We will keep this post updated with the latest roll-out status so make sure you like / follow this post to follow along.
Let’s dive into each of these improvements in more detail using the Modern City Template as an example.
Faster perceived load times and lower download sizes
With texture streaming, textures rapidly load in at a baseline quality first and in order of importance – so your players perceive your experience almost instantaneously. After the initial load, texture quality is progressively ramped up to the highest quality each device can support based on scene importance. Object importance is determined by a number of factors including distance from the camera and how much screen-space the texture takes up.
Side by side comparison of loading textures from a clean cache with and without Texture Streaming enabled. Timers stop when all textures in the scene have loaded at baseline quality.
Both videos were captured with a 100Mbit/s network connection
Using the new cloud transcoding infrastructure, textures are transcoded into individual Mippacks allowing the engine to request and load texture Mip packs with a lot more granularity. Everything the engine does download is compressed in flight and at rest when stored in the local disk cache, further reducing download sizes.
| Modern City Template | Without Texture Streaming | With texture Streaming |
|---|---|---|
| Time to baseline quality (Initial load) | 20.6s | 3.0s |
| Time to steady state quality | 20.6s | 9.9s |
| Texture memory used | 280 MB | 155 MB |
| Total download size (all assets) | 236 MB | 110 MB |
Table comparing key stats without and with texture streaming enabled on the Modern City Template experience. These numbers were captured from the same scene above on a single run with a 100Mbit/s network connection.
Note: Actual numbers experienced by players in your experience will vary based on scene complexity, other scripts you might have and several other factors.
Texture quality distribution based on scene importance and a strict budget
With texture streaming, the engine continuously evaluates the resolution at which each texture should be rendered, based on the importance of the object it is mapped to (e.g., screen footprint). This allows the engine to allocate memory budget to the right textures and avoid wasting memory on unnecessary ones, while staying within the budget set by Harmony. As a result, players see high-quality textures where they matter most, and the engine can reclaim texture memory where they don’t.
Side by side debug view showing how texture resolution is selected based on scene importance on the right (With Texture Streaming) whereas all textures are simply loaded at the highest quality on the left (Without Texture Streaming). The Colors in the debug view represent desired ideal texture quality. Red = highest quality, Yellow = medium and Blue / Cyan = lowest quality.
Another side by side comparison of the same scene without and with texture streaming enabled on a low-end Android device. Notice how with texture streaming enabled, you get higher quality textures on the road and the avatar since they are deemed more important while the entire system still stays within a reasonable texture memory budget
Fewer out of memory (OOM) crashes
As Harmony can dynamically set the total texture budget based on available resources and the texture streaming system has multiple levers to stick to the budget, this can drastically reduce the probability of an out of memory event occurring due to texture memory. One of the leading causes of OOM crashes on low-end devices is due to the resource spike caused by loading a large number of textures when an experience first loads. With texture streaming, these spikes are smoothed out over time allowing your players to stay in your game no matter how much texture detail you throw at the engine.
As we enter Modern City Template, we can see the legacy system shooting up to 225MB and staying there. With texture streaming, we only go up to ~50MB to reach ideal quality from the initial spawning point.
As the player moves around (~frame 850), additional mips for approaching objects are loaded (the grey line increases), but the amount of memory actually required to stay at ideal quality barely moves (green line) because we need less detail on the objects we’ve moving away from.
If a low-memory event occurs, the system can safely drop back down to the green line with no quality loss. The engine can always re-load these mips into memory later if necessary. In the worst case, if Harmony needs to reclaim even more texture memory budget to prevent a crash, the system can drop all the way down to the grey line – trading off texture quality momentarily to keep the player in the experience. As soon as memory frees up, the system can ramp up quality again.
What does Texture Streaming work with?
With this first release of texture streaming, we are enabling the system on the most frequently used instances that utilize textures to get the largest impact. Here is a quick summary on the specific instances that texture streaming will work with today:
-
Enabled today: MeshPart (Skinned and Unskinned meshes), SurfaceAppearance, Texture, Decal, MaterialVariant, and the base materials used with PartOperation and BasePart instances.
-
Coming next: 2D UI Textures, SurfaceGUI textures, ParticleEmitter, Terrain, TerrainDetail, Sky, and base materials bundled with the app (Plastic, Water, default Sky)
-
No plans to enable: Classic clothing (Shirts, Pants), Thumbnails (rbxthumb://) and EditableImage
Best Practices
While texture streaming was designed to work out of the box with your existing experiences, there are some best practices you can follow to get the most out of the system:
-
As you build confidence in the system once it is released on all platforms, you should feel liberated to use more unique textures in your experience.
-
Only use texture atlases if they are typically seen together on parts that are batchable (such as block parts, the same mesh, etc.) If one texture in an atlas is required at a certain mip level, the entire atlas will be streamed in at that mip level whether the remaining textures are being sampled or not. Texture streaming will work better with individual, unique textures, if they are not batchable.
-
Use near-uniform texel density in your UV-mapped meshes. This will allow the mip selection heuristic to produce the best results.
-
Be aware of the instance types currently supported by texture streaming. If an instance is not supported yet (e.g.: ParticleEmitter), you will still need to be judicious about texture memory until it is supported by texture streaming
How it all works: The lifecycle of a texture
Expand this section for a more nerdy and detailed look at how the end to end pipeline works
The end to end texture pipeline today consists of several steps, many of which have been overhauled to support texture streaming
Cloud:
-
Upload + Ingestion: You upload an image to Roblox In Studio or via OpenCloud Asset APIs
-
Storage: We store your original image at up to 8k resolution
-
Processing: Our cloud transcoders generate multiple platform-specific representations and resolutions of your image (various “mip levels”) and then compresses and packs them into a series of Mippacks ready for download.
Client:
-
Harmony: Harmony is continuously monitoring the available memory resources on the device. Every frame, it sets a total texture budget for the texture streaming system balancing the needs of all subsystems within the engine.
-
Texture streaming: The texture streaming system continuously evaluates all instances it needs to draw in a given frame and conservatively estimates what mip resolution the GPU will use, so that it can have all necessary mips available in memory.
- During the first few frames, when your experience is starting up, the system biases toward retrieving a minimally acceptable mip resolution on all instances first. This ensures the world around the player is perceptible as quickly as possible.
- Then, it will try to load mips up to the ideal resolution for all textures
- If there isn’t sufficient memory budget from Harmony, it will first trim mip levels above the ideal resolution on less important objects.
- If there is still insufficient budget, it will continue trimming mips below the ideal resolution.
- This evaluation of quality vs. importance vs. residency happens continuously as the player moves through the experience requiring the engine to load more and more textures.
With texture streaming, the same scene at the same quality—or better quality—will use less or equal memory compared to rendering without texture streaming.
-
Texture fetching: The texture streaming system loads the required texture mips from the CDN or from the local disk cache. For efficiency, when fetching from the CDN, multiple mips are batched together into a “Mippack” for the lower resolutions. The priority of pending requests is continually adjusted to adapt to sudden changes in the game—such as teleports, newly spawned objects, etc.—so that older, less important requests do not delay newer, higher-priority ones.
What’s next
Texture streaming is a major step towards our goal of giving you freedom to create without having to worry about scaling your experiences across devices. Alongside other technologies like SLIM and Instance streaming, we hope to see a whole new era of experiences that push the boundaries of visual fidelity on Roblox.
With this foundation, here is where we are planning to go next:
- Address your feedback: Make further improvements to the system using feedback from you and from our own internal tests.**
- Enable 4k Texture rendering: With texture streaming in place, we feel confident that we can safely enable 4k texture rendering on the platform, for the instance types that support texture streaming, now that the engine can dynamically scale texture quality up and down. Give it a try in the 4k texture rendering Studio Beta.
- Enable texture streaming across more instances: As mentioned above, we focused this initial launch on the most frequently used instances to have the most impact. We hope to tackle UI textures and other instances over the coming months so all instances can stream in textures in a coordinated manner.
- Enable mesh streaming: Other than textures, meshes are the most used asset type on Roblox so we plan to bring the same improvements to meshes as well. Since textures are requested only after downloading the mesh, we expect to see further improvements to perceived load times, OOM crashes and even SLIM once we can interleave both mesh and texture asset streaming together. Mesh streaming will be released alongside a vastly improved Mesh LoD simplification algorithm as we announced at RDC.
We really value your feedback and any bug reports. As you test out these new improvements in your experiences, feel free to post before / after results below (especially if you notice something amiss)
Thank you on behalf of the Rendering, Geometry and Content platform teams.




