Loading Assets
Scripts load project resources through the Loader module. Paths are always project-relative strings starting with /resources/, mirroring the folder structure in the Studio resource tree.
Path conventions
| Path pattern | Loads |
|---|---|
/resources/textures/... |
Image items (textures) |
/resources/materials/... |
Material items |
/resources/meshes/... |
Mesh items |
/resources/prefabs/... |
Prefab items |
/resources/fonts/... |
Font items (for Canvas text) |
/resources/gridmaps/... |
Grid map items |
The path is the item's location in the project, without a file extension. Use the path you see in the project view
Loader functions
All loader functions return a Promise. See Promises and Await for when to use await() vs :next().
| Function | Returns |
|---|---|
Loader.loadImage(path, options?) |
Texture item handle |
Loader.loadMaterial(path, options?) |
Material item handle |
Loader.loadMesh(path, options?) |
Mesh item handle |
Loader.loadPrefab(path, options?) |
Prefab item handle |
Loader.loadFont(path, options?) |
Font item handle |
Loader.loadGridMap(path, options?) |
Grid map item handle |
Loader.getItemCountToLoad() |
Number of items still loading (sync) |
Common options
| Option | Description |
|---|---|
waitUntilFinished |
When true, the promise resolves only after GPU/upload work is complete. Default false. |
flipY |
Image only. Flip texture vertically. Default true for 3D; use false for Canvas. |
Setup-time loading (blocking)
In init() or other one-time setup, await() keeps code linear:
local Loader = require 'engine/loader'
local Material = require 'engine/items/material'
local SgSphere = require 'engine/sceneobjects/sgsphere'
local Transform = require 'engine/math/transform'
local Vector3 = require 'engine/math/vector3'
local MyBehaviour = Class.new(Behaviour)
function MyBehaviour:init()
local wood = await(Loader.loadImage("/resources/textures/wood", {
waitUntilFinished = true,
}))
local mat = await(Material.create({ albedoMap = wood }))
self.sphere = await(SgSphere.create({
radius = 1,
material = mat,
transform = Transform.new(Vector3.new(0, 1, 0)),
}))
end
return MyBehaviour
await() pauses the current function and blocks the frame until loading finishes. That is acceptable during setup but avoid it inside update() or render() because it would block the renderer and the game essentially pauses.
Runtime loading (non-blocking) ----------------------------
Use :next() when you must keep the game responsive:
function MyBehaviour:spawnProp()
Loader.loadMesh("/resources/meshes/prop"):next(function(meshItem)
-- use meshItem with SgMesh.create or setLinkItem
end):catch(function(err)
Console.error("Failed to load prop:", err)
end)
end
Ideally you will want to load all items during :init() or even better within a Link script property which gets loaded while loading your game into memory, not during runtime.
Error handling
Chain :catch() on promises, or wrap await() in pcall:
local ok, texture = pcall(function()
return await(Loader.loadImage("/resources/textures/missing"))
end)
if not ok then
Console.error("Load failed:", texture)
end
Items vs scene objects --------------------
Loader returns Item handles (assets). To place something in the scene you still create a SceneObject — for example SgMesh.create({ mesh = meshItem }) or Prefabs for prefab items.
Link properties (Properties) can reference items assigned in the editor; Loader is for fetching items by path at runtime.
Fonts and Canvas
After Loader.loadFont("/resources/fonts/myfont"), reference the font in Canvas with the item name. Alternatively you can just link fonts to the canvas fonts section in your Project in the inspector
Further reading
- Loader — full Loader API
- Scene Graph — creating scene objects from loaded items
- Prefabs — instantiating prefabs
- Promises and Await — async patterns in depth