Scene geometry


The @use-gpu/scene package provides a classic 3D scene hierarchy with matrix transforms. Unlike most 3D engines, this is just one use-case of Use.GPU, which can be bypassed entirely, or composed with other parts.

A basic scene looks like:

return (
    <Node position={[1, 2, 3]} rotation={[0, 1, 0]}>
      <Mesh mesh={mesh} shaded />

Use <Node> to apply and nest matrix transforms, which are applied from parent to child. These take the classic position, rotation and scale attributes, though you can also use quaternion and matrix for more advanced use.

Use <Mesh> to render individual triangle meshes, or <Instances> to render multiple copies of one mesh.


A mesh is a dictionary of any of the attributes that can be given to <FaceLayer>, i.e. positions, uvs, indices, ... Each is a StorageSource. You can load these using <Data> or any other data-driven geometry component.

There are also a handful of pre-fab geometries available:

These return a Geometry object. This is just a wrapper around attributes along with their fields schema. This can be passed to <GeometryData> to create a dictionary of StorageSource in one go.

This is best done via a <Gather>, so you gather up related resources up-front, e.g. a texture:

const geometry = useOne(() => makeBoxGeometry({ width: 2 }));

return (
      <GeometryData geometry={geometry} />,
      <ImageTexture url="/textures/test.png" />,
    ]) => (
        <PBRMaterial albedoMap={texture}>


To render many copies of the same mesh, use <Instances>. This takes a render prop that receives a contextual <Instance> component type:

    render={(Instance) => (<>
      <Instance position={[1, 2, 3]} />
      <Instance position={[3, 4, 5]} />

Each instance can be transformed directly like a <Node>, but you can also wrap them in additional nodes if needed.


You can "escape" from the scene model, using a <Primitive>. This will gather the combined matrix transform and provide it as a TransformContext to its children. Thus it can be applied to other geometry layers, or combined with non-matrix transforms.

A <Mesh> is in fact just a convenient wrapper consisting of a <FaceLayer> inside a <Primitive>.


Meshes can be wrapped inside material components such as <BasicMaterial> and <PBRMaterial> to style them. These take properties for color, emissive, texture, normal map, etc.

These materials use the more fundamental <ShaderFlatMaterial> and <ShaderLitMaterial> components, for respectively unlit and lit geometry. They take custom shader functions to make arbitrary materials.