Files
yawn/docs/guide/scene-and-sab.md
T
Ampandheaust 0e6d7e367c Render only when shared state changes
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>
2026-08-21 04:02:33 +00:00

2.0 KiB

Scene and shared data

Think of every handle as an array index, not an object mirrored into core. Node.position, Node.quaternion, and Node.scale are views into separate flat SOA arrays.

Direct transform movement

import { Node } from "@yawn/handles";

const pivot = new Node(scene, { position: [0, 1, 0] });
await pivot.ready;

canvas.addEventListener("pointermove", (event) => {
  pivot.position[0] += event.movementX * 0.002;
  pivot.position[1] -= event.movementY * 0.002;
});

The pointer handler sends no messages. The typed-array view points directly into the arena shared with the render worker. The camera helpers use this same pattern; see Cameras and controls.

Add an application-specific row

const particles = await scene.ensureRows("particleVelocity", 10_000, 16, "f32");
particles.row(42).set([1, 0, 0, 0]);

Rows are 16-byte-stride-aligned and arena allocations are 64-byte aligned. Formats are f32, u32, or i32.

Timing and render signals

Core always creates signals as:

[deltaTime, frameCount, elapsedTime, targetFps, skipRender, sabDirty, bundleDirty, 0]
const signals = scene.array("signals").row(0);
signals[4] = 1; // keep timing, skip GPU work
signals[4] = 0; // resume and request a frame

The handles layer sets sabDirty for writes made through scene.array(...) and its node, camera, mesh, material, and light APIs. It sets bundleDirty before rebuilding a graph whose recorded pipeline, bindings, geometry, or draw commands changed. Core clears sabDirty when it starts a frame; switching to the replacement loadout clears bundleDirty and requests a fresh frame.

Use messages for rare control changes (setFps, graph updates, allocation); use SAB writes for existing hot state. Code using @yawn/core directly must set signals[5] = 1 after completing its own row writes.

<script setup> import Playground from "../.vitepress/Playground.vue"; </script>