Preload, budgets, and async loading.
Asset groups & streaming
Loading one file at a time works until a whole Skyforge level arrives at once. An asset group is a named set of assets and scenes loaded together under a memory and time budget, so a level fill never stalls a frame or blows the platform's memory.
What a group is
A group is an authored *.asset-group.json document listing roots (what to load) and a budget (memory and per-frame upload targets). Roots are asset:// or scene:// URIs. Loading a scene:// root pulls in the assets referenced by that scene, its HUD, and expanded prefabs.
{
"format_version": 1,
"id": "asset-group://skyforge_outpost",
"roots": [
"asset://levels/skyforge_outpost",
"scene://game/skyforge_outpost"
],
"budget": {
"resident_mb": 192,
"decoded_mb": 384,
"upload_ms_per_frame": 3
}
}
format_version— required on every authored document.id— stable group ID.roots— array ofasset://andscene://URIs to resolve and load as one batch.budget.resident_mb— cap in megabytes on memory kept resident.budget.decoded_mb— cap in megabytes on decoded (pre-upload) memory.budget.upload_ms_per_frame— milliseconds of GPU upload work allowed per frame.
upload_ms_per_frame bounds upload work per update; the memory budgets make oversized groups visible. Measure actual memory with Assets.memory_report() before choosing values.
Startup preload versus on-demand
The project document's assets array is startup preload only — the few things needed before the first frame (the title font, a placeholder). It does not load every project asset automatically. Everything else loads when a group asks for it, when its scene loads, or when script code calls Assets.load.
{
"format_version": 1,
"name": "skyforge",
"assets": [
"asset://fonts/skyforge_ui",
"asset://textures/skyforge_placeholder"
]
}
Only these two load at startup. A weapon texture referenced by a prefab loads when that prefab's scene loads. Keeping the startup array tiny is how Skyforge reaches its first frame quickly.
Scene transitions
A scene transition prepares an implicit group from its scene:// root. The authored scene, HUD, expanded prefabs, and their asset dependencies become ready before activation at a frame boundary. A failed preparation leaves the active scene in place. An authored group is optional; scene references do not need to be repeated in a startup group.
local Scene = require("demi.scene")
Scene.prepare("scene://game/skyforge_outpost") -- prepares the scene and its referenced assets
function Game:on_update()
if Scene.is_prepared() then
Scene.activate() -- swap only when every root is ready
end
end
Scene.prepare / Scene.is_prepared / Scene.activate follow the two-phase pattern from Scene & prefab API. The scene keeps its acquired assets until it is unloaded; shared assets stay resident while another owner still uses them.
Loading a group from script
The same demi.assets API loads an individual asset:// resource or an asset-group:// batch. Keep the returned request ID while waiting or cancelling.
local Assets = require("demi.assets")
local Game = {}
local request, err = Assets.load("asset-group://skyforge_outpost")
if not request or request == 0 then error(err) end
function Game:on_update()
if not Assets.is_ready(request) then
local p = Assets.progress(request)
-- p.stage and p.fraction describe this request
end
end
return Game
Assets.load(uri) returns a request ID and an error string. Assets.is_ready(request) returns a boolean. Assets.progress(request) returns a table with stage, fraction, byte counts, and any error. Call Assets.unload(uri) when this owner no longer needs the group. The full load API is in Assets, time & timers.
Next steps
- Importers — getting sources into
asset://IDs first. - Cooking — turning the group's assets into platform output.
- Scene & prefab API — prepare/activate across a level change.