Files
yawn/docs/guide/first-scene.md
T

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