Loading .world Scenes in the Background

LoadWorldAsync lets a game continue updating and rendering its current world while Blitz3D+ reads and prepares another one. The returned handle is a normal world handle, but it cannot be selected, rendered, updated, or used for audio until WorldReady is true. Loading is independent of the GUI event system.

The normal loading loop

loadingWorld=CreateWorld()
SetWorld loadingWorld
camera=CreateCamera()
PositionEntity camera,0,0,-5
spinner=CreateCube()

nextWorld=LoadWorldAsync("levels/level2.world")

While Not WorldReady(nextWorld)
    state=WorldLoadState(nextWorld)
    If state=WORLD_LOAD_FAILED Then RuntimeError WorldLoadError(nextWorld)
    If state=WORLD_LOAD_CANCELLED Then RuntimeError "Load cancelled"

    TurnEntity spinner,.4,.8,.2
    UpdateWorld
    RenderWorld
    Text 20,20,"Loading "+(WorldLoadProgress(nextWorld)/10.0)+"%"
    Text 20,44,WorldLoadStage(nextWorld)
    Flip
Wend

SetWorld nextWorld
SetAudioWorld nextWorld
FreeWorld loadingWorld

Flip, FlipCanvas, Delay, and WaitTimer service budgeted main-thread finalization automatically. Loops without those commands can call UpdateAsyncLoads. The automatic calls share one deadline for the current presentation or wait boundary. The default finalization budget is 2 milliseconds and can be changed with SetAsyncLoadBudget.

By default the runtime permits 8 simultaneous world loads and caps aggregate in-flight source data at 256 MiB, decoded CPU data at 512 MiB, upload staging at 128 MiB, and ready resources at 512 MiB on Win32 or 1 GiB on Win64. Deployments and automated stress tests may override those values before startup with BLITZ3D_ASYNC_MAX_LOADS, BLITZ3D_ASYNC_SOURCE_BYTES, BLITZ3D_ASYNC_DECODED_BYTES, BLITZ3D_ASYNC_UPLOAD_STAGING_BYTES, and BLITZ3D_ASYNC_READY_BYTES. Memory values are byte counts. A load that would exceed a limit fails with the requested, retained, and limit values in WorldLoadError.

Load states and cancellation

ConstantMeaning
WORLD_LOAD_READY (0)The world is fully published and selectable.
WORLD_LOAD_QUEUED (1)The worker request has been accepted.
WORLD_LOAD_READING (2)The source manifest is being read and validated.
WORLD_LOAD_DECODING (3)Required assets are being decoded.
WORLD_LOAD_FINALIZING (4)Main-thread resources and entities are being created under the time budget.
WORLD_LOAD_FAILED (5)The load ended with an actionable error.
WORLD_LOAD_CANCELLED (6)Cancellation completed without publishing a partial world.

WORLD_LOAD_DEFAULT is 0 and WORLD_LOAD_NO_STREAMING is 1. Asset-kind queries return WORLD_ASSET_KIND_MODEL (1), TEXTURE (2), HEIGHTMAP (3), SOUND (4), or SHADER (5). Use the named constants in programs; the numeric values are documented for logs, tools, and saved diagnostics.

CancelWorldLoad is cooperative. Poll until the state becomes cancelled, or call FreeWorld to invalidate a loading handle immediately and release its work when the worker unwinds. A failed or cancelled load never changes the selected graphics or audio world.

The .world version 1 format

A .world file is strict UTF-8 JSON. Relative asset paths are resolved from the file containing them, not from the process working directory. A document can contain placed entities, an asset-only preload list, or both.

{
  "format": "blitz3d.world",
  "version": 1,
  "id": "level.castle",
  "settings": {
    "ambient": [64,72,96],
    "collisions": [
      {"sourceType":1,"destinationType":11,
       "method":"polygon","response":"slide"}
    ]
  },
  "assets": [
    {"id":"height","kind":"heightmap","source":"height.bmp","loading":"required"},
    {"id":"ground","kind":"texture","source":"ground.jpg","loading":"required"},
    {"id":"castle","kind":"model","source":"castle.glb","loading":"required"}
  ],
  "entities": [
    {
      "id":"land",
      "transform":{"position":[-1000,-100,-1000],"scale":[7.8125,100,7.8125]},
      "components":[
        {"type":"terrain","heightmap":"height","detail":750,"morph":true,
         "shading":true,"material":{"mode":"legacy","texture":"ground",
         "textureScale":[10,10]}},
        {"type":"collision","entityType":11,"pickMode":"polygon"}
      ]
    },
    {"id":"keep","components":[{"type":"model","asset":"castle"}]}
  ],
  "extensions": {}
}

Coordinates and transforms

World sources use Blitz3D's native left-handed local coordinate space: positive X is right, positive Y is up, and positive Z is forward. Values are ordinary Blitz units; version 1 performs no hidden unit conversion. A transform defaults to position [0,0,0], scale [1,1,1], and an identity quaternion [0,0,0,1]. Quaternion order is x,y,z,w; the loader rejects a zero/non-finite quaternion and normalizes every valid one. Scale follows ScaleEntity, including finite zero or negative components.

Model assets are decoded in their normal Blitz import space and do not inherit the mutable process-wide LoaderMatrix setting. Put an editor-authored conversion in the entity transform instead. This keeps a world deterministic even when its worker starts later than submission.

Assets

KindVersion 1 preparation
modelB3D, X, 3DS, glTF, or GLB geometry and dependencies; use options.animated for an animated hierarchy.
textureCPU image decode followed by main-thread canvas creation; options.flags matches LoadTexture.
heightmapImmutable 16-bit samples used to construct an independent mutable terrain.
soundRIFF/WAVE decode; options.spatial selects 3D sound behavior.
shaderSource/dependency preparation on a worker and pipeline creation on the main thread.

loading is required, streaming, or manual. Required assets gate WorldReady and may be referenced by placed entities. Streaming assets start automatically after the manifest is prepared and are reported by WorldStreaming. Manual assets begin when FindWorldAsset first resolves them; poll WorldAssetReady and WorldAssetError before using a typed accessor.

Entities and terrain

Entities have stable IDs, optional parent IDs, local position/rotation/scale, visibility, enabled state, string metadata, and components. Version 1 supports model, terrain, camera, light, listener, collision, and marker components. FindWorldEntity returns a published entity by ID. WorldEntityMetadata reads authoring metadata without scanning entity names.

Terrain supports a required heightmap, detail, morphing, shading, LOD ranges, legacy texture scaling, and layered terrain materials. Once the world is ready, the result is an ordinary terrain: TerrainY, TerrainHeight, collisions, and ModifyTerrain work as normal. A material uses either the legacy members (texture and a positive textureScale) or the layers members, never both. Layered materials contain one to four textures with positive uvScale values. Version 1 maps these to the uniform scale accepted by TerrainLayer, so both components must match. More than one layer requires a splatMap. Sharing a heightmap never shares later terrain deformation.

Asset-only preload manifests

preload=LoadWorldAsync("asset-preload.world")
While Not WorldReady(preload)
    If WorldLoadState(preload)=WORLD_LOAD_FAILED Then RuntimeError WorldLoadError(preload)
    Flip
Wend

modelAsset=FindWorldAsset(preload,"ship")
textureAsset=FindWorldAsset(preload,"ship-paint")
ship=CreateWorldAsset(modelAsset)
paint=WorldAssetTexture(textureAsset)
EntityTexture ship,paint

Typed texture, sound, and shader accessors return ordinary public handles. They remain valid after the source world is freed and must be released with the matching FreeTexture, FreeSound, or FreeShader. A created model entity belongs to its destination world. Compatible texture loads and compatible assets requested by several worlds reuse ready shared data where their options match.

Optional streaming

WorldReady does not wait for assets declared streaming. Use WorldStreaming and WorldStreamingProgress if the game wants to show their progress. Pass WORLD_LOAD_NO_STREAMING to disable automatic optional streaming. Required content and manually requested assets are unaffected.

Validation and authoring

The shipped b3dworldc command validates the same format used by the runtime:

b3dworldc level.world
b3dworldc --no-files editor-draft.world
b3dworldc --quiet worlds/*.world

The machine-readable contract is installed as world/world-v1.schema.json. Runtime validation additionally rejects duplicate keys, malformed UTF-8, non-finite values, excessive nesting and document sizes, invalid references, parent cycles, unsupported required extensions, and missing dependencies.

Editor round trips

An editor may normalize whitespace and property order, but it must preserve the order of asset, entity, component, layer, and collision arrays because that order is observable. It must keep explicit IDs stable, retain unknown optional properties and the complete JSON value of every unknown optional namespaced extension, and refuse to silently discard an unknown extension whose required member is true.

Keep relative asset paths relative to the .world file; do not replace them with workstation-specific absolute paths. Emit strict UTF-8 JSON, finite numbers, unique object keys, and quaternion components in x,y,z,w order. Saving must not copy runtime terrain deformation or other gameplay state back into the authoring source. Run b3dworldc after every save and treat the runtime validator as authoritative where JSON Schema cannot express duplicate keys, finite-number rules, path resolution, or cross-reference semantics.

Troubleshooting

Complete samples

Back to Guides