load
Synchronously loads a 3D model from the specified URI string and returns its root entity.
WARNING:
This method performs blocking I/O. While it can be called on the main thread, on slow devices or with unstable storage/content-provider latency it may cause jank or even ANR.
Prefer the async API
loadSuspend(...). If you must use a sync call, execute it off the main thread or in a coroutine context such aswithContext(Dispatchers.IO).
For complex or high-resolution resources that require significant processing time, it is strongly recommended to leverage coroutines for loading. This approach prevents blocking the main thread, ensuring a responsive and fluid user experience.
Usage
Recommended to call within a coroutine context (preferably not Dispatchers.Main):
val entity = withContext(Dispatchers.IO) {
Entity.load("asset://models/box.usdz") // Asset example
// or
Entity.load("file:///sdcard/models/box.glb") // File example
}Performance notes
This is a blocking I/O operation. Heavy operations block the calling thread.
Large models may cause frame drops or even ANR if called on main thread.
Textures are recommended to be pre-compressed (ASTC/ETC2).
Single texture memory limit: 256MB (includes mipmaps).
File access time affects loading duration.
Security considerations
Ensure the file is accessible and has the necessary permissions.
Avoid loading models from files that may contain sensitive data.
Avoid loading models from files that are not intended for public consumption.
Return
The root entity of the loaded scene.
Parameters
The URI representing the location of the 3D model to load. Supported URI schemes:
asset://- Loads from application assets.file://- Loads from local storage. Forcontent://URIs, useload(contentResolver: ContentResolver, uri: Uri)instead.
See also
loadSuspend(String) for non-blocking alternative.
Throws
If loading fails due to invalid URI, missing file, unsupported format, and more.
Synchronously loads a 3D model from a file and returns its root entity.
WARNING:
This method performs blocking I/O. While it can be called on the main thread, on slow devices or with unstable storage access it may cause jank or even ANR.
Prefer the async API
loadSuspend(...). If you must use a sync call, execute it off the main thread or in a coroutine context such aswithContext(Dispatchers.IO).
For complex or high-resolution resources that require significant processing time, it is strongly recommended to leverage coroutines for loading. This approach prevents blocking the main thread, ensuring a responsive and fluid user experience.
Usage
Recommended to call within a coroutine context (preferably not Dispatchers.Main):
val entity = withContext(Dispatchers.IO) {
Entity.load(File("/sdcard/models/box.glb"))
}Performance notes
This is a blocking I/O operation. Heavy operations block the calling thread.
Large models may cause frame drops or even ANR if called on main thread.
Textures are recommended to be pre-compressed (ASTC/ETC2).
Single texture memory limit: 256MB (includes mipmaps).
File access time affects loading duration.
Security considerations
Ensure the file is accessible and has the necessary permissions.
Avoid loading models from files that may contain sensitive data.
Avoid loading models from files that are not intended for public consumption.
Return
The root entity of the loaded scene.
Parameters
The file containing the 3D model to load. The path must be accessible. Supported file formats:
USD variants:
.usdz,.usda,.usdc.GLTF variants:
.glb,.gltf.
See also
loadSuspend(File) for non-blocking alternative.
Throws
If loading fails due to invalid format, missing assets, exceeding memory limits, and more.
Synchronously loads a 3D model from a content provider URI and returns its root entity.
WARNING:
This method performs blocking I/O. While it can be called on the main thread, with unstable content-provider response or high system load it may cause jank or even ANR.
Prefer the async API
loadSuspend(...). If you must use a sync call, execute it off the main thread or in a coroutine context such aswithContext(Dispatchers.IO).
For complex or high-resolution resources that require significant processing time, it is strongly recommended to leverage coroutines for loading. This approach prevents blocking the main thread, ensuring a responsive and fluid user experience.
To load a .gltf model, make sure that all data is stored in a single .gltf file. While for Entity.load(uriString: String) and Entity.load(file: File), you can also load a .gltf model stored in a folder (in this case, the actual data is stored in the .bin file, instead of the .gltf file).
Usage
Recommended to call within a coroutine context (preferably not Dispatchers.Main):
val entity = withContext(Dispatchers.IO) {
Entity.load(
contentResolver,
Uri.parse("content://com.example.provider/models/box.glb")
)
}Performance notes
This is a blocking I/O operation. Heavy operations block the calling thread.
Large models may cause frame drops or even ANR if called on main thread.
The content URI is loaded through the in-memory path. The full model data is read before loading and may be temporarily retained in memory by the loading job. Loading multiple large models from content URIs in parallel can significantly increase peak memory usage and may cause an OutOfMemoryError.
For remote models, large models, or list/grid experiences that load multiple models, prefer copying the data to an app cache file first, then call load with a
file://URI or load with a File. For pages that may start many large loads at once, consider limiting concurrent model loading to fit the device memory budget.Textures are recommended to be pre-compressed (ASTC/ETC2).
Single texture memory limit: 256MB (includes mipmaps).
Content provider response time affects loading duration.
Security considerations
Ensure the content provider has the necessary permissions to access the specified URI.
Avoid loading models from URIs that may contain sensitive data.
Return
The root entity of the loaded scene.
Parameters
The ContentResolver for accessing the content provider.
The content Uri pointing to the 3D model data. Only supports content:// URIs. For other schemes such as asset:// and file:// URIs, use load(uriString: String) instead.
See also
loadSuspend(ContentResolver, Uri) for non-blocking alternative.
Throws
If loading fails due to invalid data, unsupported format, exceeding memory limits, and more.
If the caller does not have permission to access the content provider.
Synchronously loads a 3D model from an InputStream and returns its root entity.
WARNING:
This method performs blocking I/O. While it can be called on the main thread, if the stream source or storage is unstable it may cause jank or even ANR.
Prefer the async API
loadSuspend(...). If you must use a sync call, execute it off the main thread or in a coroutine context such aswithContext(Dispatchers.IO).
For complex or high-resolution resources that require significant processing time, it is strongly recommended to leverage coroutines for loading. This approach prevents blocking the main thread, ensuring a responsive and fluid user experience.
Supported Formats
All ModelFormat variants supported by the engine.
Format must match the actual stream content.
To load a
.gltfmodel, make sure that all data is stored in a single.gltffile. While forEntity.load(uriString: String)andEntity.load(file: File), you can also load a.gltfmodel stored in a folder (in this case, the actual data is stored in the.binfile, instead of the.gltffile).
Usage
Recommended to call within a coroutine context (preferably not Dispatchers.Main):
val entity = withContext(Dispatchers.IO) {
context.assets.open("models/box.usdz").use { inputStream ->
Entity.load(inputStream, ModelFormat.USD)
}
}Performance Notes
This is a blocking I/O operation. Heavy operations block the calling thread.
Large models may cause frame drops or even ANR if called on main thread.
This API loads through the in-memory path. The full stream is read before loading and may be temporarily retained in memory by the loading job. Loading multiple large streams in parallel can significantly increase peak memory usage and may cause an OutOfMemoryError.
For remote models, large models, or list/grid experiences that load multiple models, prefer downloading or copying the data to an app cache file first, then call load with a
file://URI or load with a File. For pages that may start many large loads at once, consider limiting concurrent model loading to fit the device memory budget.Textures are recommended to be pre-compressed (ASTC/ETC2).
Single texture memory limit: 256MB (includes mipmaps).
Resource Management
The caller is responsible for opening/closing the InputStream.
For automatic resource cleanup, use
.use { }block as shown in example.
Return
The root entity of the loaded scene.
Parameters
The InputStream containing the raw model data.
The ModelFormat of the provided data (must match actual content).
Throws
If loading fails due to invalid data, unsupported format, exceeding memory limits exceeded, and more.
Synchronously loads a 3D model from an AssetFileDescriptor and returns its root entity.
Compared with load from an InputStream, this overload reads the model data directly from the asset's file descriptor and avoids buffering the entire file in JVM memory.
When to use this overload
Prefer this API when:
The model is large (typically tens / hundreds of MB), where a
byte[]-based load would risk an OutOfMemoryError or visible GC jank.You are loading Gaussian Splatting scenes (
.ply/.spz), large.usdz, or any asset packaged uncompressed in the APK.The model already lives behind an AssetFileDescriptor coming from
AssetManager.openFd(...),ContentResolver.openAssetFileDescriptor(...),DocumentFile, Storage Access Framework, or other APIs that return AFDs natively.
Advantages over the byte-array / InputStream APIs
Near-zero JVM heap footprint during loading — the bytes never travel through a ByteArray.
Lower CPU and GC pressure: no full read-then-copy step before handing data to the engine.
Faster time-to-first-frame for large assets, since the engine consumes data on demand.
Plays well with cross-process / cross-app resource handoff (
content://, SAF, third-party file pickers).
WARNING:
This method is blocking. Although it can be called from the main thread, large models or slow storage may still cause jank or even ANR.
Prefer the async API loadSuspend with the same signature. If you must use this sync call, run it off the main thread, e.g. inside
withContext(Dispatchers.IO).
Supported Formats
All ModelFormat variants supported by the engine (
USD/GLTF/OBJ/STL/PLY/SPZ).The format argument MUST match the actual content of the descriptor; the SDK cannot infer the format from an AFD (there is no filename to look at).
Required AAB / APK Configuration
The asset behind the descriptor must be stored uncompressed inside the APK. For sources like AssetManager.openFd(path), that means the file extension must be present in the application's android.androidResources.noCompress list. Typical entries when working with this API are .ply, .spz and .usdz. Without this configuration, opening the descriptor itself will fail with a FileNotFoundException from the framework — before this method even runs.
AssetFileDescriptor Requirements
The descriptor must report a known, positive length (i.e.
afd.declaredLength != AssetFileDescriptor.UNKNOWN_LENGTHand> 0). Streaming AFDs that have no declared length (typical for someContentProvider.openFileimplementations) are not supported here — fall back to load with an InputStream, or copy the data to an app cache file first and use load with a File.Do not share the same descriptor across concurrent load calls.
Usage
Recommended to call within a coroutine context (preferably not Dispatchers.Main):
val entity = withContext(Dispatchers.IO) {
context.assets.openFd("models/scene.spz").use { afd ->
Entity.load(afd, ModelFormat.SPZ)
}
}Resource Management
The caller opens and closes the AssetFileDescriptor. Using
.use { }as shown above is recommended.It is safe to close the descriptor as soon as this method returns; the loaded entity does not depend on the descriptor staying open.
Performance Notes
Avoiding the JVM-heap copy only optimizes the loading phase. After loading completes, the runtime cost (GPU / CPU / VRAM) of the resulting entity is the same as for any other load API.
Texture limits still apply: a single texture (including its mipmaps) cannot exceed 256 MB. Pre-compress textures (ASTC / ETC2) when possible.
When opening cross-app
content://URIs, be prepared to handle SecurityException / unknown-length AFDs at the call site.
Return
The root entity of the loaded scene, attached to the scene graph.
Parameters
An AssetFileDescriptor pointing to the raw model data.
The ModelFormat of the data referenced by afd (must match actual content).
Throws
If loading fails due to invalid data, unsupported format, an AFD with unknown / non-positive length, exceeding memory limits, or other engine errors.
If reading the descriptor fails (the underlying file cannot be opened or mapped); IO errors are propagated to the caller as-is rather than being wrapped.
Synchronously loads a 3D model from the specified AssetBundle and returns its root entity.
WARNING:
This method performs blocking I/O. While it can be called on the main thread, with large bundles or unstable device/storage performance it may cause jank or even ANR.
Prefer the async API
loadSuspend(...). If you must use a sync call, execute it off the main thread or in a coroutine context such aswithContext(Dispatchers.IO).
For complex or high-resolution resources that require significant processing time, it is strongly recommended to leverage coroutines for loading. This approach prevents blocking the main thread, ensuring a responsive and fluid user experience.
Supported file
AssetBundles (
.bundle) will be automatically packaged intoasset://when:Spatial Tools dependency is properly configured;
Spatial Editor project is properly configured;
Both bundle name and model name are exactly matched;
Gradle build pipeline completes successfully.
Usage
Recommended to call within a coroutine context (preferably not Dispatchers.Main):
val entity = withContext(Dispatchers.IO) {
AssetBundle.load("asset://main.bundle").use { bundle ->
Entity.load("character_model", bundle)
}
}Performance Notes
This is a blocking I/O operation. Heavy operations block the calling thread.
Large models may cause frame drops if called on main thread;
Textures are recommended to be pre-compressed (ASTC/ETC2);
Single texture memory limit: 256MB (includes mipmaps);
The AssetBundle should be closed after use (prefer
.use {}block);
Error Handling & Requirements
Model Name must exactly match USD "Scene" names (case-sensitive) in the corresponding Spatial Editor project.
Bundle name must match SpatialPackConfig settings in app's build.gradle.
Return
The root entity of the loaded scene.
Parameters
The name of the model asset in the bundle (case-sensitive).
The loaded AssetBundle containing the model resources.
See also
for bundle loading procedure.
Throws
If loading fails due to missing model, invalid format, exceeding memory limits, and more.