Add shared-data and bundle invalidation signals, and have handles publish them automatically for SAB and graph mutations. Document the raw core worker protocol in a dedicated VitePress site and simplify the glTF import and picking example. Amp-Thread-ID: https://ampcode.com/threads/T-01a01ff8-b91f-724f-8952-f07c6b5042fd Co-authored-by: Heaust Azure <heaust.azure@gmail.com>
3.2 KiB
Core boundary
@yawn/core deliberately contains no scene types and no WGSL. It owns two things:
- a 64-byte-aligned arena of named f32/u32/i32 SOA rows in one
SharedArrayBuffer; - render-graph compilation, up-front WebGPU loadouts, transient resource aliasing, render bundles, and the paced render loop.
infrequent worker messages hot shared mutations
┌──────────────────────────────┐ ┌──────────────────────┐
│ create/delete rows │ │ transforms │
│ allocate/delete object slot │ │ cameras/materials │
│ compile/switch graph │ │ lights/app data │
│ play/pause/set FPS │ │ signals + row data │
└──────────────┬───────────────┘ └──────────┬───────────┘
└─────────────────┬─────────────────────┘
▼
┌─────────────────┐
│ Rust/WASM core │
└─────────────────┘
Use core directly
import { YawnCore } from "@yawn/core";
const core = new YawnCore(canvas, { arenaBytes: 64 * 1024 * 1024 });
await core.ready;
const values = await core.createRows({
name: "application.values",
rows: 1024,
stride: 16,
format: "f32",
});
const id = await core.allocateObject("application.values");
values.row(id).set([1, 2, 3, 4]);
Graph frontends serialize plain data to (yawn-graph 1 ...). Named after edges preserve DAG fan-out; Rust sorts passes, detects cycles, culls unused declarations, aliases compatible transient lifetimes, merges compatible render passes into bundles, and allocates the active loadout. Unchanged persistent textures survive loadout rebuilds.
The Scene addon is one such frontend. It is replaceable and has no privileged core API.
Profile physical GPU passes
const stop = core.onProfile((frame) => {
console.table(frame.passes); // name + GPU milliseconds
});
const supported = await core.setProfiler(true);
// Later:
await core.setProfiler(false);
stop();
new YawnCore(canvas, { debug: true }) enables the same timestamp-query mode at startup. Samples are read back asynchronously, so profiling does not serialize the GPU queue. Timings describe physical GPU passes and actual compiled draw counts; compatible indexed draws over consecutive instances collapse into one command. The sidebar also reports canvas size and wall-clock readback latency.
The saved Forward benchmark playground renders 138 logical objects and 4.5 million triangles. Add &grid=32 to lower geometry density or &overdraw=1 to stack the objects while diagnosing depth and fragment cost.