Load a scene document
Run the scene from the last page from a scene document instead of Kotlin: save it as a resource, load it with SceneLoader, and hand it to the scene runtime.
components: camera · light · mesh_renderer · spin_control
Vulkan
WebGPU
A scene document is a *.scene.json file that describes ECS entities as data. It is the file
AwakeKt Studio saves, and it describes the same content as the scene DSL, so a scene can move
between the two. This page builds on Your first scene and reuses its Turntable
system and GameRenderPlan.
Save the document
Save the scene from the last page as src/commonMain/resources/scenes/first.scene.json:
{
"version": 1,
"name": "first-scene",
"nodes": [
{
"name": "camera",
"components": [
{
"component": "camera",
"eye": { "x": 0.0, "y": 1.5, "z": 4.0 },
"center": { "x": 0.0, "y": 0.5, "z": 0.0 },
"fovYDegrees": 45.0
}
]
},
{
"name": "sun",
"components": [
{
"component": "light",
"type": "Directional",
"direction": { "x": 0.4, "y": 0.8, "z": 0.4 }
}
]
},
{
"name": "cube",
"transform": { "position": { "x": 0.0, "y": 0.5, "z": 0.0 } },
"components": [
{ "component": "mesh_renderer", "mesh": "cube", "material": "lit" },
{ "component": "spin_control", "speed": 1.0 }
]
}
]
}
The document has a schema version and a list of nodes. Each node becomes one entity: its name,
an optional transform, and components, each tagged with its component id.
Load it
Load the document in onReady and switch the scene to it:
import com.awakekt.awake.asset.shaderpack.LitShadowUniformLayout
import com.awakekt.awake.core.geometry.generate.generate
import com.awakekt.awake.engine.bootstrap.dsl.app
import com.awakekt.awake.engine.platform.lifecycle.AwakeAppLifecycle
import com.awakekt.awake.render.renderer.createMaterial
import com.awakekt.awake.scene.authoring.scene
import com.awakekt.awake.scene.document.SceneLoader
import com.awakekt.awake.scene.runtime.attachRenderableComponents
fun firstDocumentScene(): AwakeAppLifecycle = app {
window {
title = "Hello AwakeKt"
size(1280, 720)
}
scene("first-scene") {
assets {
mesh("cube") { renderer.createMesh(generate { cube(size = 1f, colored = true) }) }
material("lit") { renderer.createMaterial(LitShadowUniformLayout) }
}
frameSystem("turntable") { Turntable() }
onReady {
val document = SceneLoader.loadFromResource("scenes/first.scene.json")
val scene = sceneManager.switchTo(document)
// Each mesh_renderer names a mesh and a material; build them from assets { }.
scene.attachRenderableComponents { request -> requireAssetLibrary().resolve(this, request) }
}
}
}
Launch it from desktopMain as before:
Run it: the window shows the same spinning cube as the scene DSL version, frame for frame. Here is
what onReady did:
SceneLoader.loadFromResourcereads and decodes the file. On desktop it reads from the classpath; in the browser it fetches the path relative to the page.sceneManager.switchTochecks the document, then creates one entity per node and one ECS component per component id. It tears down whatever scene it loaded before.- A
mesh_rendereronly names a mesh and a material.attachRenderableComponentslooks each name up inassets { }and adds theMeshRenderer.
The assets { } names are the link between the two: the document says "mesh": "cube" and
"material": "lit", and the app declares both.
How it works
The scene document and the scene DSL are two ways to write the same ECS content. Loading a
document does not start a second engine: the entities land in the scene runtime's World, and the
same Turntable, TransformSystem, and RenderSystem3D run over them.
If you already hold the document when you build the app, scene(document) inside scene { } loads
it and resolves its meshes in one call. To decode a string you already have, use
SceneLoader.decode(text).
Documents are checked before they load
switchTo rejects a document that breaks a rule, such as a camera whose far is not greater
than its near, with a SceneValidationException listing every problem and the node it is on.
A document whose version is newer than this engine supports throws
SceneSchemaVersionException.
Older component ids
Documents written with camelCase ids (meshRenderer, spinControl, pbrMaterial,
prefabLink) still load: SceneLoader rewrites them to the snake_case ids. Write new
documents with snake_case ids.
See also
- Your first scene for the same scene in the scene DSL.
- Scene document schema and scene document components for every field and component id.
- Run in the browser: the next step.