Optional ReadonlydeformingOptional ReadonlydiagnosticsRead the GPU top level's refit stats back (counters, warnings). Default false: no readbacks frame after frame.
Optional ReadonlyfirstBuilds the first trees instead of the GPU H-PLOC, whatever the device's features: for unit tests in Node.
Optional ReadonlygpuFirst trees from the GPU (H-PLOC) on a device with subgroups. Default true; false: tinybvh only.
Optional ReadonlygpuCap each GPU build batch's bytes (inputs, scratch and outputs) and build
the batches one after another (see the file comment). Default 256 MiB
(DEFAULT_GPU_MAX_BATCH_BYTES). Infinity turns the cap off: one
batch for all of an update's meshes, as big as the device allows (the
path before the cap).
The batches go on between updates (each is copied out in its own
submit), but their trees reach rays at the next SceneTrees.update,
as any tree does.
Optional ReadonlygpuTrees deeper than this are refused, with a fallbackReason: a GPU tree leaves the mesh to tinybvh, a tinybvh
tree leaves it on the tree it has (or none). Default GPU_TREE_MAX_DEPTH, which keeps every placed tree
within the trace stack.
Optional ReadonlygpuQuantized scenes: H-PLOC writes the first trees' nodes quantized in its
emit pass (HplocOptions.quantizeOnEmit), so a batch holds 32-byte
nodes and a frame slot per mesh instead of 64-byte nodes, and no
quantize pass runs as the trees are copied in. The trees are the same,
bit for bit. Deforming meshes' builds stay f32 (their refit needs an
f32 copy). Default true (since 2026-11-15: Sponza's build 41.6 to
35.1 ms on the RTX 3060, an uncapped peak 1,482.6 to 1,307.3 MiB);
false runs the quantize pass instead. gpuTreeOutputs: 'adopt' needs
it. A copying scene still takes f32 trees from a first-tree builder
that doesn't write quantized nodes, and packs them on the way in.
Ignored by f32 scenes.
Optional ReadonlygpuHow GPU trees reach the scene's buffers: 'copy' (default) or 'adopt'
(see the file comment). Any node and triangle format: a quantized scene
adopts H-PLOC batches that wrote quantized nodes themselves
(gpuQuantizeOnEmit, the default), and an indexed
scene's builds leave room for each mesh's header.
Optional Readonlyholdtinybvh's trees wait instead of replacing a mesh's GPU tree, until SceneTrees.releaseRefinements. A mesh with no tree yet still takes tinybvh's. For tools that check a scene mid-swap. Default false.
Optional ReadonlylabelPrefix for GPU object labels.
Optional ReadonlymergeMerge static instances at the first update (see the file comment).
Default true. Only instances added with static: true before the first
update are merged; every other instance is untouched. false keeps
static instances as ordinary ones.
Optional ReadonlynodeThe node format (docs/internals/design/compressed-nodes.md): 'quantized'
(the default, DEFAULT_NODE_FORMAT: 32 bytes per node, plus a 32-byte
frame slot per mesh before its root) or 'f32' (64 bytes per node). The
walk that reads the scene must be built with the same nodeFormat
(SceneTrees.nodeFormat; the walk's default is quantized too). tinybvh trees come
quantized from the workers (deforming meshes' come f32: their refit
keeps an f32 copy, and they are packed when placed); GPU trees are
built f32 and packed by a compute pass on their way into the storage
(or written quantized by H-PLOC, gpuQuantizeOnEmit). Independent of triangleLeaves.
A coordinate of magnitude 2^100 or more, or a non-finite one, makes a quantized box empty on that axis (hits there are lost).
Optional ReadonlyonCalled as each mesh's builds go: a build requested, started (a GPU
batch submitted, a worker taking the tinybvh build) and finished, per
mesh and builder (see SceneBuildEvent). onTree says when a
finished tree is placed.
Optional ReadonlyonCalled when a tree is placed (a mesh's first, or a swap).
Optional ReadonlyparentsWhich trees carry parents (4 bytes per node; only a refit reads them).
'always': every GPU batch writes its parents output and
every tinybvh tree comes with its parents array. 'refit' (P9 lever 7):
GPU batches are built without the parents output (deforming meshes'
read-back layouts get theirs from their nodes, on the CPU), and tinybvh
builds of meshes that don't deform leave their parents out. Same trees.
Default 'refit' since 2026-11-15.
Optional ReadonlypositionIndexed: 'vec4' (the default, 16 bytes per vertex) or 'packed' (12) positions.
Optional ReadonlypositionsIndexed scenes: the app's own positions buffer, bound as the walk's
positions (buffers.positions) instead of the scene's copy, which is
then never made (docs/internals/design/indexed-leaves.md, option A). It
must hold every mesh's vertices as f32, in the positionLayout
stride ('vec4': 16 bytes per vertex, 'packed': 12), each mesh's from
the vertexBase given to addMesh, with exactly the bits of the
geometry given there (the trees are built from that geometry; the walk
reads this buffer), and STORAGE usage. Its vertices are the meshes'
own, so the scene neither welds them (weld is false, and true
throws), nor merges static instances (mergeStaticInstances is false,
and true throws: a merged group's world-space vertices are not in it),
nor takes deforming meshes (their refit writes its pose into the
scene's copy). The app keeps the buffer alive and unchanged while the
scene uses it. Default: none (the scene's copy).
Optional ReadonlyquantizeQuantized scenes: how GPU trees are packed on their way into the
storage. 'per-tree' records one quantize pass per tree,
each with its own mesh table and uniform; 'batched' gathers every tree
an update (or a capped batch's own copy) places and records one pass,
with one job per batch's node buffer. Same nodes bit for bit; fewer
buffers, bind groups and passes (P9, docs/internals/design/memory.md).
Default 'batched' since 2026-11-15 (Sponza: 7 passes, not 132).
Optional ReadonlyrefineDefault true: every mesh is also built by tinybvh, and its tree replaces
the GPU's (the swap). False is the GPU-only mode: with a GPU builder,
tinybvh builds only the meshes the GPU can't give a usable tree (too
big, too deep, a batch that failed), and the GPU trees stay. Each mesh's
geometry is kept until its GPU tree is placed (for that fallback). Without
a GPU builder (no subgroups, gpuFirstTrees: false) tinybvh builds
every mesh either way: the declared fallback.
Optional ReadonlyrefitDeforming meshes' refits: 'per-mesh' gives each its own
primitive-box buffer (32 bytes per triangle); 'shared' gives them one,
sized for the largest deforming mesh, used in turn (every refit is
recorded one after another in the update's pass). Same boxes, same trees.
Default 'shared' since 2026-11-15.
Optional ReadonlytimestampsTime each GPU build batch's compute pass with timestamp queries, where
the device has timestamp-query: counts.gpuBuildTimestampMs sums them
(counts.gpuBuildMs is submit-to-stats wall time either way). Default
false: one small query set and readback per batch when on.
Optional Readonlytop'auto' (default): the GPU top level with subgroups, the CPU one without. 'cpu': always the CPU top level.
Optional ReadonlytransferMove each mesh's geometry arrays into the worker instead of copying them (the caller's arrays are empty afterwards). Default false. Merged groups' geometry is the scene's own and always moves.
Optional ReadonlytriangleThe triangle format (docs/internals/design/indexed-leaves.md): 'records' (the
default, 48 bytes per triangle) or 'indexed' (16 bytes per triangle,
plus the scene's own positions, buffers.positions, or the app's,
positionsBuffer). The walk that reads the scene must be built
with the same triangleLeaves and positionLayout.
Optional ReadonlytrimTrim the node buffer whenever the scene is quiet (no build running or
waiting, every tree placed) and the buffer holds more than its trees:
the trees are packed to the front of a buffer of their exact size (see
SceneTrees.trim). Default: true with gpuTreeOutputs: 'adopt'
(the batch's one node per triangle goes: Sponza settles at 448.1 MiB,
not 613.6), false with 'copy' (the buffer keeps its growth room;
a trim would save about 10 MiB for a copy of every node).
Optional ReadonlywarnWhere problems are reported once (a GPU build that failed, a refit repaired). Default console.warn.
Optional ReadonlyweldIndexed: weld each mesh's vertices by exact bits when it is added (not deforming meshes'). It changes no coordinate, so rays see the same triangles, and saves position memory. Default true.
Optional ReadonlyworkersThe worker pool for tinybvh builds, or options for one this scene makes
(and disposes). A pool the scene makes ends workers idle for
SCENE_WORKER_IDLE_TIMEOUT_MS (30 s) unless the options set
idleTimeoutMs: 256 MiB of tinybvh memory back once a load is over,
for a few milliseconds of worker start on the next build.
What a deforming mesh keeps on the CPU for SceneTrees.setPoseCpu once its tree is placed:
'full'keeps the tree's layout as it came (nodes, 48-byte records, parents);'compact'keeps the nodes and parents and 4 bytes per triangle (its original triangle, and the flags and padding words only where any is non-zero), and rebuilds the records a pose needs (compactPoseLayout). Same poses bit for bit. Default'compact'since 2026-11-15.