Amp-Thread-ID: https://ampcode.com/threads/T-01a01380-b478-77d0-84a0-102880a5c5ae Co-authored-by: Heaust Azure <heaust.azure@gmail.com>
3.1 KiB
Your first scene
This tutorial composes Yawn the same way an application does: create the worker transport, wait for shared render data, compile a graph, import an asset, and activate the prepared loadout.
1. Start core
Create one renderer worker and transfer an OffscreenCanvas to it. YawnCore is deliberately transport-oriented; your bootstrap owns canvas sizing and worker construction.
import { YawnCore } from "@yawn/core";
const canvas = document.querySelector("canvas");
canvas.width = Math.round(canvas.clientWidth * devicePixelRatio);
canvas.height = Math.round(canvas.clientHeight * devicePixelRatio);
const offscreen = canvas.transferControlToOffscreen();
const worker = new Worker(new URL("./render-worker.js", import.meta.url), {
type: "module",
});
const core = new YawnCore({ worker });
worker.postMessage({ type: "init", canvas: offscreen }, [offscreen]);
await core.ready;
ready resolves after core receives the standard SOA descriptors. From that point, core.array("camera.state") and the other built-in columns are safe to access.
2. Compile a graph
The optional default-pipelines addon supplies scene WGSL. A JSO graph places those declarations beside graph nodes, then the graph addon serializes the canonical AST for core.
import { loadGraph } from "@yawn/render-graph-js";
import { defaultPipelines } from "@yawn/default-pipelines";
const graph = {
id: "main",
revision: 1,
pipelines: defaultPipelines,
nodes: completeSceneNodes,
};
const compiled = await loadGraph(core, graph);
Compilation validates the DAG, removes dead work, computes transient resource lifetimes, aliases compatible resources, and allocates the resulting loadout before returning its ID.
3. Import render data
The glTF addon fetches and parses in its own worker. It asks core for a fixed shared upload array, writes the packet into that SAB, then sends only the array ID and byte count for the commit.
import { GltfImporter } from "@yawn/gltf-import";
import { MeshHandles } from "@yawn/mesh-handles";
const importer = new GltfImporter(core);
const result = await importer.load("/assets/scene.glb");
const handles = new MeshHandles(core);
const meshes = handles.fromImportedScene(result);
importer.dispose();
4. Activate the loadout
Switching is transactional from the application's perspective: the previously active loadout keeps rendering until the prepared graph becomes active.
await core.switchCompiledGraph(compiled.compiledId);
meshes[0].defaultInstance.setTransform(nextTransform); // direct SAB write
Use messages for setup and teardown. Use shared writes for values that are already present and can change every frame.
Next steps
- Learn why these boundaries exist in How Yawn fits together.
- Author graphs with plain objects, a fluent builder, or FXNode.
- Add custom shared columns in Core and render data.
- Use familiar objects in Conventional handles.