---
title: scene
description: Creates a root node for a scene tree. Any node can act as a root; `scene()` names the intent and tags the node with `kind: "scene"`.
---

# scene



## Import

```ts
import { scene } from "vgpu/scene";
```

## Signature

```ts
declare function scene(options?: import("vgpu/scene").NodeOptions): import("vgpu/scene").SceneNode;
```

## Examples

```ts
import { box, group, mesh, scene, unlitMaterial } from "vgpu/scene";

const root = scene();
const spinner = group({ label: "spinner" });
root.add(spinner);
spinner.add(mesh(box({ size: 1 }), unlitMaterial({ color: [0.2, 0.5, 1] })));
```

## Notes

* The tree is pure JS state — no GPU resources. Rendering binds a tree later (`gpu.scene()`, phase 2).
* **See also:** `group`, `mesh`, `SceneNode`.

***

# group

Creates a plain transform node used to group children.

## Import

```ts
import { group } from "vgpu/scene";
```

## Signature

```ts
declare function group(options?: import("vgpu/scene").NodeOptions): import("vgpu/scene").SceneNode;
```

## Examples

```ts
import { group } from "vgpu/scene";

const rig = group({ position: [0, 2, 0], rotation: [0, Math.PI / 4, 0] });
rig.set({ rotation: [0, Math.PI / 2, 0] });
```

## Notes

* Children inherit the group's transform through `worldMatrix`.
* **See also:** `scene`, `mesh`, `SceneNode`, `NodeOptions`.

***

# mesh

Creates a renderable node: a pure geometry descriptor paired with a material.

## Import

```ts
import { mesh } from "vgpu/scene";
```

## Signature

```ts
declare function mesh(
  geometry: import("vgpu/scene").SceneGeometry,
  material?: import("vgpu/scene").SceneMaterial,
  options?: import("vgpu/scene").NodeOptions,
): import("vgpu/scene").MeshNode;
```

## Parameters

| Param    | Type            | Required | Default            | Notes                                                  |
| -------- | --------------- | -------- | ------------------ | ------------------------------------------------------ |
| geometry | `SceneGeometry` | ✔        | —                  | Pure descriptor from `box()`, `sphere()`, `plane()`, … |
| material | `SceneMaterial` | ✖        | `normalMaterial()` | Shading descriptor; swap by assigning `node.material`. |
| options  | `NodeOptions`   | ✖        | `{}`               | Initial transform, label, visibility, children.        |

**Returns:** `MeshNode` with `kind: "mesh"`.
**Throws:** `VGPU-SCENE-VALUE-INVALID` for malformed transform options.

## Examples

```ts
import { lambertMaterial, mesh, sphere } from "vgpu/scene";

const ball = mesh(sphere({ radius: 0.5 }), lambertMaterial({ color: [0.9, 0.4, 0.2] }), {
  position: [0, 0.5, 0],
});
ball.set({ rotation: [0, 1, 0] });
```

## Notes

* This is the scene-tree `mesh()`; the low-level vertex-buffer API remains `geometry(gpu, ...)` on the main `vgpu` entrypoint.
* **See also:** `MeshNode`, `SceneMaterial`, `SceneGeometry`, `group`.

***

# MeshNode

Class returned by `mesh()`. Extends `SceneNode` with `geometry` and `material` fields the renderer keys its caches by.

## Import

```ts
import type { MeshNode } from "vgpu/scene";
```

## Signature

```ts
declare class MeshNode {
  geometry: import("vgpu/scene").SceneGeometry;
  material: import("vgpu/scene").SceneMaterial;
}
```

## Examples

```ts
import { box, mesh, unlitMaterial } from "vgpu/scene";

const node = mesh(box());
node.material = unlitMaterial({ color: [1, 0, 0] });
```

## Notes

* Both fields are swappable; identity changes re-key renderer caches (phase 2).
* **See also:** `mesh`, `SceneNode`.

***

# SceneNode

Base scene-tree node: a TRS transform with parent/children links. Mutation goes through `set()` so world matrices recompute lazily and only for dirty subtrees; exposed arrays keep a stable identity and are updated in place.

## Import

```ts
import { SceneNode } from "vgpu/scene";
```

## Signature

```ts
declare class SceneNode {
  set(values: import("vgpu/scene").NodeTransformValues): this;
  lookAt(target: import("vgpu/scene").Vec3Like, up?: import("vgpu/scene").Vec3Like): this;
  add(...children: SceneNode[]): this;
  remove(...children: SceneNode[]): this;
  removeFromParent(): this;
  traverse(visit: (node: SceneNode) => void): void;
  readonly kind: import("vgpu/scene").SceneNodeKind;
  readonly parent: SceneNode | null;
  readonly children: readonly SceneNode[];
  readonly position: Float32Array;
  readonly quaternion: Float32Array;
  readonly scale: Float32Array;
  readonly localMatrix: Float32Array;
  readonly worldMatrix: Float32Array;
  readonly worldPosition: Float32Array;
  visible: boolean;
  label: string | undefined;
}
```

**Returns:** Not directly constructed in user code; use `scene()`, `group()`, `mesh()`, cameras, or lights.
**Throws:** `VGPU-SCENE-CYCLE` when `add()` would create a cycle; `VGPU-SCENE-VALUE-INVALID` for malformed vectors.

## Examples

```ts
import { group } from "vgpu/scene";

const parent = group({ position: [1, 0, 0] });
const child = group({ position: [0, 1, 0] });
parent.add(child);

const world = child.worldMatrix; // stable identity
parent.set({ position: [2, 0, 0] });
void world; // same array, refreshed on next read
```

## Notes

* `position`/`quaternion`/`scale`/`worldMatrix` return the internal arrays: safe to bind, but mutate only via `set()` so dirty tracking stays exact.
* `lookAt()` orients the node's -Z axis at a world-space target and compensates for parent transforms.
* `add()` reparents nodes that already have a parent.
* **See also:** `group`, `mesh`, `NodeTransformValues`, `SceneCamera`.

***

# NodeOptions

Options accepted by node factories: all of `NodeTransformValues` plus initial `children`.

## Import

```ts
import type { NodeOptions } from "vgpu/scene";
```

## Signature

```ts
interface NodeOptions {
  readonly position?: import("vgpu/scene").Vec3Like;
  readonly rotation?: import("vgpu/scene").Vec3Like;
  readonly quaternion?: import("vgpu/scene").QuatLike;
  readonly scale?: number | import("vgpu/scene").Vec3Like;
  readonly visible?: boolean;
  readonly label?: string;
  readonly children?: readonly import("vgpu/scene").SceneNode[];
}
```

## Examples

```ts
import { group, mesh, box } from "vgpu/scene";

const rig = group({ label: "rig", children: [mesh(box())] });
void rig;
```

## Notes

* **See also:** `NodeTransformValues`, `group`, `scene`.

***

# NodeTransformValues

Transform and flag values accepted by `node.set()`.

## Import

```ts
import type { NodeTransformValues } from "vgpu/scene";
```

## Signature

```ts
interface NodeTransformValues {
  readonly position?: import("vgpu/scene").Vec3Like;
  readonly rotation?: import("vgpu/scene").Vec3Like;
  readonly quaternion?: import("vgpu/scene").QuatLike;
  readonly scale?: number | import("vgpu/scene").Vec3Like;
  readonly visible?: boolean;
  readonly label?: string;
}
```

## Parameters

| Field      | Type                 | Required | Default     | Notes                                                                      |
| ---------- | -------------------- | -------- | ----------- | -------------------------------------------------------------------------- |
| position   | `Vec3Like`           | ✖        | `[0, 0, 0]` | Local position.                                                            |
| rotation   | `Vec3Like`           | ✖        | —           | Intrinsic XYZ Euler angles in radians. Ignored when `quaternion` is given. |
| quaternion | `QuatLike`           | ✖        | identity    | Local rotation (x, y, z, w).                                               |
| scale      | `number \| Vec3Like` | ✖        | `1`         | Uniform number or per-axis vector.                                         |
| visible    | `boolean`            | ✖        | `true`      | Invisible nodes (and their subtrees) are skipped by the renderer.          |
| label      | `string`             | ✖        | —           | Used in error `where` strings and debugging.                               |

## Examples

```ts
import { group } from "vgpu/scene";

group().set({ position: [0, 1, 0], rotation: [0, Math.PI, 0], scale: 2 });
```

## Notes

* **See also:** `SceneNode`, `NodeOptions`, `Vec3Like`, `QuatLike`.

***

# Vec3Like

Three-component vector input accepted by scene-tree setters: tuples, plain arrays, or typed arrays.

## Import

```ts
import type { Vec3Like } from "vgpu/scene";
```

## Signature

```ts
type Vec3Like = readonly [number, number, number] | readonly number[] | Float32Array;
```

## Examples

```ts
import type { Vec3Like } from "vgpu/scene";

const up: Vec3Like = [0, 1, 0];
```

## Notes

* Setters copy the input; mutating it afterwards does not affect the node.
* **See also:** `QuatLike`, `NodeTransformValues`.

***

# QuatLike

Quaternion input (x, y, z, w) accepted by scene-tree setters.

## Import

```ts
import type { QuatLike } from "vgpu/scene";
```

## Signature

```ts
type QuatLike = readonly [number, number, number, number] | readonly number[] | Float32Array;
```

## Examples

```ts
import type { QuatLike } from "vgpu/scene";

const identity: QuatLike = [0, 0, 0, 1];
```

## Notes

* **See also:** `Vec3Like`, `NodeTransformValues`.

***

# SceneNodeKind

Discriminator for scene-tree node types, used by renderers and traversal code.

## Import

```ts
import type { SceneNodeKind } from "vgpu/scene";
```

## Signature

```ts
type SceneNodeKind =
  | "scene"
  | "group"
  | "mesh"
  | "perspective-camera"
  | "orthographic-camera"
  | "directional-light"
  | "ambient-light";
```

## Examples

```ts
import { scene, mesh, box, type SceneNode } from "vgpu/scene";

const root = scene({ children: [mesh(box())] });
const meshes: SceneNode[] = [];
root.traverse((node) => {
  if (node.kind === "mesh") meshes.push(node);
});
```

## Notes

* **See also:** `SceneNode`, `traverse` on `SceneNode`.


---

For a semantic overview of all documentation, see [/sitemap.md](/sitemap.md)

For an index of all available documentation, see [/llms.txt](/llms.txt)

For agent-facing discovery, including API and MCP surfaces, see [/agents.md](/agents.md)