# raea/3d

> raea's scene layer: models, physics, splats, matchmoves, instancing, custom shader passes and 3D text.

`raea/3d` holds what a scene uses beyond Bevy's own components: glTF models (`<Model>`, `<Part>`), physics and soft
bodies (`<Physics>`, `<Body>`, `<Goo>`), Gaussian splats (`<Splat>`), matchmoves, instancing and scattering, grass,
fire, decals, 3D text, and custom shader passes (`<FramePass>`, `<MeshPass>`, `<Compute>`). It also re-exports the
primitives and effects most scenes need, so a quick scene can import from one path. Bevy's camera, lights,
materials and meshes are under [`raea/camera`](camera.md), [`raea/light`](light.md), [`raea/pbr`](pbr.md) and
[`raea/mesh`](mesh.md), named as Bevy names them.

```tsx
import { AbsoluteFill, staticFile } from "raea";
import { Model, Physics } from "raea/3d";
import { Camera3d } from "raea/camera";
import { DirectionalLight } from "raea/light";
import { Transform } from "raea/transform";

function Scene() {
  return (
    <AbsoluteFill style={{ background: "#14161c" }}>
      <Camera3d transform={Transform.fromXyz(0, 1.6, 5).lookingAt([0, 0.5, 0])} />
      <DirectionalLight transform={Transform.fromXyz(3, 5, 4).lookingAt([0, 0, 0])} illuminance={11200} shadow_maps_enabled />
      <Model src={staticFile("media/chair.glb")} />
    </AbsoluteFill>
  );
}
```

See [3D](../../guides/3d.md) for building, lighting and checking a scene.


```ts
import { about, AmbientOcclusion, AntiAliasing, Atmosphere } from "raea/3d"
```

`raea/3d` exports 70 components, 4 hooks, 26 functions, 3 classes, 12 values, 126 types. Source: [sdk/raea/src/3d.tsx](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/src/3d.tsx).

## Components

### `AmbientOcclusion`

Screen-space ambient occlusion: creases, corners and the ground under things darken where the sky's and the room's
light can't reach. It darkens ambient and environment light (an <AmbientLight>, an <Environment>), not the direct
light of a sun or a lamp. Turns multisampling off, so the edges are smoothed by SMAA instead (see <AntiAliasing>).
Put it inside the Canvas3D, once; the first frame's holds for the piece.

Bevy: `bevy_pbr::ssao::ScreenSpaceAmbientOcclusion`.

Takes [`AmbientOcclusionProps`](#ambientocclusionprops)'s props.

### `AntiAliasing`

How the 3D's edges are smoothed. Put it inside the Canvas3D, once; the first frame's holds for the piece.

Bevy: `bevy_anti_alias::smaa::Smaa`, `bevy_anti_alias::fxaa::Fxaa`.

Takes [`AntiAliasingProps`](#antialiasingprops)'s props.

### `Atmosphere`

A procedural sky: Bevy's physically based atmosphere (Earth's air), drawn behind everything and lit by the
DirectionalLights, so a sun low on the horizon makes a sunset. Inside the Canvas3D, once.

Bevy: `bevy_light::Atmosphere`.

Takes [`AtmosphereProps`](#atmosphereprops)'s props.

### `BevyComponent`

A Bevy component on the part it's inside (a Mesh, a Model, an ImagePlane, a light or the camera), applied through the
TypeRegistry: how a compiled-in Bevy plugin is driven (sdk/raea/docs/bevy-plugins.md), and how any of Bevy's own
reflected components reaches a part in every build. Agents use the generated, typed wrappers (one per component), not this directly.

| Prop | Type | What it does |
| --- | --- | --- |
| `type` (required) | `string` | the component's reflected type path, as Bevy's TypeRegistry names it ("avian3d::dynamics::rigid_body::RigidBody") |
| `value` | `unknown` | its value as Bevy's reflect serde reads it: a struct an object (fields left out take the type's default, when it has one), a newtype its inner value, an enum "Unit" or { Variant:... }, a Vec3 [x, y, z] |
| `from` | `number` | the frame it's added on (0, the start, by default); a plugin steps after it from that frame |

Used in: [ui/widgets/viewport_node](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/ui/widgets/viewport_node.tsx), [3d/3d_shapes](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/3d/3d_shapes.tsx), [3d/3d_scene](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/3d/3d_scene.tsx), [shader/automatic_instancing](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/shader/automatic_instancing.tsx), [shader/storage_buffer](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/shader/storage_buffer.tsx), [shader/shader_prepass](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/shader/shader_prepass.tsx), [shader/array_texture](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/shader/array_texture.tsx), [shader/gpu_component_array_buffer](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/shader/gpu_component_array_buffer.tsx), and 6 more.

### `BevyResource`

A Bevy resource (a plugin's settings: gravity), applied through the TypeRegistry. Inside the Canvas3D.

| Prop | Type | What it does |
| --- | --- | --- |
| `type` (required) | `string` | the resource's Rust type path, as the TypeRegistry names it |
| `value` (required) | `unknown` | its value as Bevy reflects it (JSON) |

Used in: [shader_advanced/deferred_raymarch](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/shader_advanced/deferred_raymarch.tsx).

### `Bloom`

Glow around bright parts (emissive materials, strong highlights). Put it inside the Canvas3D.

Bevy: `bevy_post_process::bloom::settings::Bloom`.

Takes [`BloomProps`](#bloomprops)'s props.

Used in: [3d/bloom_3d](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/3d/bloom_3d.tsx), [3d/mesh_ray_cast](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/3d/mesh_ray_cast.tsx).

### `Body`

A rigid body inside <Physics>: drawn where the simulation has it this frame.

| Prop | Type | What it does |
| --- | --- | --- |
| `name` (required) | `string` | the body's name, unique in its <Physics>: the bake keys its track by it |
| `src` | `string` | a glTF's nodes as the body (drawn as a <Part>, its collider their hull) |
| `nodes` | `string[]` | the glTF nodes that make the body |
| `shape` | `Shape` | "hull" (default for nodes), "box" (their bounds), "mesh" (exact triangles, fixed bodies only), or a shape |
| `centre` | `Vec3` | where a given shape's centre stands at rest, world (a nodes' body: the middle of their bounds) |
| `fixed` | `boolean` | it never moves: a floor, a wall, a table |
| `mass` | `number` | kg (else volume x density) |
| `density` | `number` | kg/m³ (1000) |
| `friction` | `number` | 0 slides, 1 grips (0.5) |
| `restitution` | `number` | 0 lands dead, 1 bounces back fully (0.2) |
| `velocity` | `Vec3` | m/s at the start, world |
| `angularVelocity` | `Vec3` | radians a second at the start, world |
| `linearDamping` | `number` | how fast its motion bleeds off (0) |
| `angularDamping` | `number` | how fast its spin bleeds off (0.05) |
| `release` | `number` | seconds: held where it is until then (a cup sits until it's knocked) |
| `impulses` | `Impulse[]` | kicks at given seconds: an impulse, where it's applied, and a torque |
| `path` | `(t: number) => { position: Vec3; quaternion: Quat }` | a kinematic mover: its rigid motion from rest at t seconds (see `about`); it pushes the others |
| `material` | `PartMaterial` | drawn as the body's nodes are, or by its children (inside its motion: draw them where it stands at rest) |
| `glitch` | `Glitch \| ((t: number) => Glitch \| undefined)` | how its part breaks up, or a function of seconds giving that |
| `castShadow` | `boolean` | it casts shadows |
| `children` | `ReactNode` | what draws the body, in place of its nodes |

### `BufferMesh`

A mesh from its own vertex buffers, as the geometry of a <Mesh> (Bevy's Mesh built from attributes): a terrain from
a height field, a procedural shape, a ribbon, an imported point list. Drawn as flat triangles, or with indices and
normals as Bevy's indexed Mesh.

Bevy: `bevy_mesh::mesh::Mesh`.

Takes [`BufferMeshProps`](#buffermeshprops)'s props.

Used in: [shader_advanced/specialized_mesh_pipeline](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/shader_advanced/specialized_mesh_pipeline.tsx).

### `Canvas3D`

Only for `layered`: the 3D is drawn in the page's order, at the box of the nearest positioned element around it
(the whole frame when there's none; B3 H7), at that box's size and aspect:

 <div style={{ position: "absolute", left: 100, top: 50, width: 200, height: 150 }}>
   <Canvas3D layered><Camera3d transform={...} /><Mesh3d>...</Mesh3d></Canvas3D>
 </div>
Without `layered` it is its children, as written straight in the page.

Takes [`Canvas3DProps`](#canvas3dprops)'s props.

Used in: [ui/images/image_node](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/ui/images/image_node.tsx), [ui/images/ui_texture_slice_flip_and_tile](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/ui/images/ui_texture_slice_flip_and_tile.tsx), [ui/images/image_node_resizing](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/ui/images/image_node_resizing.tsx), [ui/images/ui_texture_atlas_slice](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/ui/images/ui_texture_atlas_slice.tsx), [ui/images/ui_texture_slice](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/ui/images/ui_texture_slice.tsx), [ui/images/ui_texture_atlas](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/ui/images/ui_texture_atlas.tsx), [ui/layout/grid](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/ui/layout/grid.tsx), [ui/layout/ghost_nodes](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/ui/layout/ghost_nodes.tsx), and 94 more.

### `Capsule`

A capsule (Bevy's Capsule3d, three.js's CapsuleGeometry): [radius, length of the straight part], standing up
(along y); its whole height is length + 2 x radius. A character's stand-in, a pill, a collider's look.

Also takes the props of [`CapsuleProps`](#capsuleprops) (`args`).

### `Capsule3d`

*From Bevy's `bevy_shape::Capsule3d`:* A 3D capsule primitive centered on the origin A three-dimensional capsule is defined as a surface at a distance (radius) from a line

Also takes the props of [`Capsule3dProps`](#capsule3dprops) (`radius`, `half_length`, `args`).

### `Compute`

A compute over the frame, in the 3D beside the camera; several run in the order written, before the cameras draw.

Rust: `raea_sys_compute::Computes`.

Takes [`ComputeProps`](#computeprops)'s props.

Used in: [shader/compute_shader_game_of_life](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/shader/compute_shader_game_of_life.tsx), [shader_advanced/compute_mesh](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/shader_advanced/compute_mesh.tsx).

### `Cone`

A cone: [radius, height], its point up (along y).

Bevy: `bevy_shape::Cone`.

Also takes the props of [`ConeProps`](#coneprops) (`args`, `radius`, `height`).

### `Cuboid`

Bevy's Cuboid: `<Cuboid half_size={[1, 0.5, 1]} />` is a Box of args [2, 1, 2].

Also takes the props of [`CuboidProps`](#cuboidprops) (`half_size`); `BoxProps` (`args`).

### `Cylinder`

[radiusTop, radiusBottom, height], standing up (along y) as three.js has it.

Bevy: `bevy_shape::Cylinder`.

Also takes the props of [`CylinderProps`](#cylinderprops) (`args`, `radius`, `half_height`).

### `Decal`

A picture pressed onto whatever surface it lies across: a label on a jar, a stain on a counter, tiles on a wall, a
sticker on a laptop (Bevy's forward decal; the camera gets a depth prepass for it). Placed and keyed like any part,
so it moves and fades with a render's clock and a game's play alike.

Bevy: `bevy_pbr::mesh_material::MeshMaterial3d<bevy_pbr::extended_material::ExtendedMaterial<bevy_pbr::pbr_material::StandardMaterial, bevy_pbr::decal::forward::ForwardDecalMaterialExt>>`.

Takes [`DecalProps`](#decalprops)'s props.

### `DepthCopy`

Inside a Camera3d: its depth buffer copied each frame, after its prepass and before its main pass, into a depth
image a Material samples (Bevy's shader_advanced/render_depth_to_texture, whose depth-only camera has Bevy's
DepthPrepass, RenderTarget::None and Msaa off).

Rust: `raea_sys_phase::DepthCopy`.

| Prop | Type | What it does |
| --- | --- | --- |
| `image` (required) | `string` | the depth image, "render:NAME:WxH:depth": the camera's depth is copied into it, and a Material's texture of that name is it (a texture_depth_2d with a sampler_comparison) |

Used in: [shader_advanced/render_depth_to_texture](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/shader_advanced/render_depth_to_texture.tsx).

### `DepthOfField`

A lens's depth of field: what's nearer or farther than the camera's `focus` blurs. Put it inside the Canvas3D;
pull focus by animating the camera's `focus`. Inside a Camera3d it is Bevy's component on the camera, its
focal_distance the camera's focus.

Bevy: `bevy_post_process::dof::DepthOfField`.

Takes [`DepthOfFieldProps`](#depthoffieldprops)'s props.

### `Echoes`

Copies of a part trailing it: `count` echoes at offsets `step` apart (metres; or a function of the echo's number),
in a flat glowing `material`, so a fork "duplicates" along a line.

| Prop | Type | What it does |
| --- | --- | --- |
| `count` (required) | `number` | how many echoes trail the part |
| `step` (required) | `Vec3 \| ((k: number) => Vec3)` | metres between one echo and the next, or a function of the echo's number (1, 2,...) giving its offset |
| `echo` | `PartMaterial` | the echoes' material (the part's by default): a flat glowing one reads as copies |

Also takes the props of [`PartProps`](#partprops).

### `Entities`

A world's entities drawn by the engine (no React element per entity): every entity with a Mesh component ({shape:
a Manifold expression or a Solid's expr, color, roughness, metalness}) and a Transform ({x, y, z, rx, ry, rz in
radians, scale}) is a mesh, placed in world space (a child's Transform is in its parent's). Give it the world at the
frame: `<Entities world={game.at(useCurrentFrame())} />`. Needs the engine's tables.

| Prop | Type | What it does |
| --- | --- | --- |
| `world` (required) | `{ scene(): unknown[] }` | the game's world at this frame: anything with \`scene()\` giving its entities |

### `Entity`

A bare Bevy entity: a Transform where it's placed (static) and Visibility, and nothing else until its children add
Bevy's own components through the TypeRegistry. A Handle field takes an asset path ("ball.glb#Mesh0/Primitive0",
"wood.png"), an inline asset (a StandardMaterial's fields as an object) or, for a Mesh, a Manifold shape
("shape:box(1, 1, 1)"); an Entity field takes another part's name or row id, or entity bits. So Mesh3d,
MeshMaterial3d<StandardMaterial>, Sprite, ChildOf and the rest of Bevy's components are reachable without a
hand-written element.

| Prop | Type | What it does |
| --- | --- | --- |
| `name` | `string` | what an Entity field elsewhere names it by (a ChildOf's parent, an observer's target); unique in the scene |
| `position` | `Vec3` | where it stands, metres (x, y, z) |
| `rotation` | `Vec3` | Euler XYZ in radians |
| `scale` | `Vec3 \| number` | one number, or x, y and z |
| `transform` | `{ translation?: Vec3; rotation?: [number, number, number, number]; scale?: Vec3 }` | Bevy's Transform (Transform.fromXyz(..).withRotation(..)), in place of position, rotation and scale: the entity is then a parent whose children (meshes, lights, models, other entities) move with it, as Bevy's ChildOf children do (the old Group) |
| `pass` | `string` | with `transform`: the composition pass of every part inside that doesn't name its own (Mesh's `pass`) |
| `children` | `ReactNode` | its Bevy components (<BevyComponent>, or the generated wrappers in raea/bevy-own); with `transform`, also the parts it carries |

Used in: [ui/widgets/viewport_node](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/ui/widgets/viewport_node.tsx), [3d/3d_shapes](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/3d/3d_shapes.tsx), [3d/atmospheric_fog](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/3d/atmospheric_fog.tsx), [3d/3d_scene](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/3d/3d_scene.tsx), [3d/parenting](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/3d/parenting.tsx), [stress_tests/many_foxes](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/stress_tests/many_foxes.tsx), [camera/projection_zoom](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/camera/projection_zoom.tsx), [animation/animated_transform](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/animation/animated_transform.tsx), and 4 more.

### `Environment`

Light from all around, out of a panorama: soft light from the sky and reflections of it in every glossy or metal
surface (image-based lighting), and with `background` the panorama as the sky. Put it inside the Canvas3D, once a
frame; its src, intensity, rotation and background may change from frame to frame (a cut from a hall to a street).
Bevy's EnvironmentMapLight with maps already filtered is <EnvironmentMapLight>.
Its panorama is filtered by Bevy's generator and, with `background`, drawn as the sky (engine/render
environment.rs):

Bevy: `bevy_light::probe::GeneratedEnvironmentMapLight. Bevy's Skybox from its own cubemap is <Skybox>.`.

Takes [`EnvironmentProps`](#environmentprops)'s props.

### `EnvironmentMapLight`

Bevy's EnvironmentMapLight with its own prefiltered maps, as Bevy's examples put one on the camera: light from all around and its reflections, from cubemaps already filtered (an <Environment> filters a panorama
itself). Put it inside the Canvas3D, once; the first frame's holds.

Bevy: `bevy_light::probe::EnvironmentMapLight`.

Takes [`EnvironmentMapLightProps`](#environmentmaplightprops)'s props.

### `Fire`

A fire: a flame drawn as a volume, its tongues rising, curling and tearing off as it burns, with a flickering light
on its surroundings. Every pixel of it is a function of the frame (rising 3D noise in a tapering envelope), so a
render of any frame equals its play. Stand it on its fuel (a pyre, a brazier); put embers and smoke round it
yourself.

Bevy: `bevy_pbr::mesh_material::MeshMaterial3d<raea_render::engine::fire::FireMaterial>`.

Takes [`FireProps`](#fireprops)'s props.

### `Fisheye`

A fisheye lens on the camera: a pass over the 3D after tone mapping (the page over it stays straight). Every value
animates per frame; a lens's vignette and colour fringes are <Grade>'s. Put it inside the Canvas3D.

Takes [`FisheyeProps`](#fisheyeprops)'s props.

### `Fog`

Distance fog: far things fade into `color`. Inside the <Camera3d> it is Bevy's DistanceFog on that camera, with all of
Bevy's fields (an atmospheric falloff, the sun's colour); inside the Canvas3D it fogs the scene's camera by near, far
or density.

Bevy: `bevy_pbr::fog::DistanceFog`.

Takes [`FogProps`](#fogprops)'s props.

Used in: [3d/fog](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/3d/fog.tsx), [3d/atmospheric_fog](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/3d/atmospheric_fog.tsx).

### `FogVolume`

A box of air that light shows in: dust in a sunbeam, smoke, a haze of blood. Needs a <VolumetricFog> in the
Canvas3D; lights marked `volumetric` throw shafts through it, and every light's glow fills it softly. A part, so it
keeps its name across frames: animate its density, colour and placement.

Bevy: `bevy_light::volumetric::FogVolume`.

Takes [`FogVolumeProps`](#fogvolumeprops)'s props.

### `FramePass`

A full-screen pass over the scene camera's frame, beside the camera; several run in the order written. With a
frame <Look> they run on its cells, before the look's composite.

Rust: `raea_sys_framepass::FramePasses`.

Takes [`FramePassProps`](#framepassprops)'s props.

Used in: [shader_advanced/custom_post_processing](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/shader_advanced/custom_post_processing.tsx), [shader_advanced/fullscreen_material](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/shader_advanced/fullscreen_material.tsx).

### `GBufferPass`

Inside a Camera3d with Bevy's DepthPrepass and DeferredPrepass: your shader over the whole view, written into the
deferred G-buffer after the deferred prepass (depth compared GreaterEqual), so Bevy's deferred lighting lights it as
any surface, and into the shadow maps of the camera's lights (Bevy's shader_advanced/deferred_raymarch).

Rust: `raea_sys_phase::GBufferPass`.

| Prop | Type | What it does |
| --- | --- | --- |
| `shader` (required) | `string` | the shader file, compiled as written: staticFile("shaders/x.wesl"). Its entry points take Bevy's FullscreenVertexOutput; bind group 0 is the view uniform (binding 0) and Globals (binding 1) |
| `fragment` | `string` | the entry point writing the G-buffer: its deferred vec4<u32> (location 0), its lighting pass id u32 (location 1) and its frag_depth ("fragment") |
| `shadow` | `string` | the entry point writing a shadow view's frag_depth, so it casts shadows; none when left out |

Used in: [shader_advanced/deferred_raymarch](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/shader_advanced/deferred_raymarch.tsx).

### `Gizmo`

Debug lines drawn by Bevy's gizmo renderer (a retained bevy_gizmos Gizmo and its GizmoAsset), placed like a part:
a path, a bounding box, an axis, a ray. They cast and take no light, and draw over nothing unless depthBias says.

Bevy: `bevy_gizmos::retained::Gizmo`.

Takes [`GizmoProps`](#gizmoprops)'s props.

Used in: [shader_advanced/render_depth_to_texture](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/shader_advanced/render_depth_to_texture.tsx).

### `Goo`

Objects melting into goo: the bake drawn by the frame (nothing before `from`).

| Prop | Type | What it does |
| --- | --- | --- |
| `name` | `string` | the entity's name, for picking and the inspector |
| `seconds` (required) | `number` | how long, seconds, from `from` (a frame of the enclosing Sequence) |
| `from` | `number` | the frame of the enclosing Sequence the bake starts at (0) |
| `objects` (required) | `GooObject[]` | what goes in: solids that melt and liquids that pour |
| `colliders` | `{ box: { min: Vec3; max: Vec3 }; friction?: number }[]` | static boxes the goo lies on and runs off (world) |
| `cups` | `GooCup[]` | hollow cylinders on a pose track (a mug lifted and tipped) that carry the goo and pour it (tools/goo's cups): radius inside, height foot to rim, base (the inside floor's height), wall, friction, and poses [t,...the cup's frame to world, 16 numbers column-major], t in seconds from the goo's start, its axis +y |
| `surface` | `{ blur?: number; level?: number; flat?: number; maxTris?: number }` | the surface drawn round the particles: blur (grid nodes, 1), iso level (of the rest density, 0.33) and flat (the blur across over the blur up, 1); a wider, flatter blur and a lower level close a thin spill into one sheet. maxTris (120000): past it the grid coarsens, which drops a film one particle thick; a wide one needs more |
| `solver` | `"mpm" \| "sph"` | "mpm" (the default: goo, melting things) or "sph": thin liquids that pour, splash and spread (coffee dumped on a counter, water from a tap), simulated by SPlisHSPlasH (tools/goo/sph.py); each object a liquid, from a cup, a block, a filled glTF or an emitter |
| `sph` | `{ radius?: number; viscosity?: number; tension?: number; tensionBoundary?: number; tens…` | the sph solver's settings: particle radius (m, 0.001), viscosity (0.002), surface tension (0: off; at millimetre particles the solver alone holds a spill 4-5 mm deep, as coffee is, and even 30 beads it into a ball) with how much the liquid wets what it lies on (0.5) and its damping (0.05), the largest time step (s, 0.001) |
| `obstacles` | `{ src: string; nodes?: string[]; transform?: number[]; poses?: number[][] }[]` | sph: glTF meshes the liquid runs over and around (all their meshes, or the named nodes, moved by `transform`), standing, or moved along `poses` like a cup's ([t, 16 numbers column-major], from where the glTF has them) |
| `fps` | `number` | the bake's own frame rate (the composition's by default): one bake shared by compositions at different rates |
| `bounds` | `{ min: Vec3; max: Vec3 }` | the box it lives in: goo leaving it is gone |
| `dx` | `number` | grid cell, metres (0.005): finer is slower and smoother |
| `seed` | `number` | the random seed the particles are placed with: the same seed bakes the same goo (0) |
| `gravity` | `Vec3` | gravity, m/s² (0, -9.81, 0) |
| `roughness` | `number` | the surface: glossy, a little light through it |
| `clearcoat` | `number` | 0..1 clear varnish over the surface |
| `subsurface` | `number` | 0..1 light let through the surface |
| `color` | `string` | the goo's colour where an object gives none |

### `Grade`

The camera's colour grade (lift, gamma, gain and saturation per range of light, before tone mapping), a lens
vignette and colour fringes: one grade over every scene, so a film looks of a piece. Put it inside the Canvas3D.

Bevy: `bevy_render::view::ColorGrading`, `bevy_post_process::effect_stack::chromatic_aberration::ChromaticAberration`, `bevy_post_process::effect_stack::vignette::Vignette`.

Takes [`GradeProps`](#gradeprops)'s props.

### `Grass`

A field of grass over `area`, made by the engine from the ground's functions (sampled once at `resolution`).

| Prop | Type | What it does |
| --- | --- | --- |
| `name` | `string` | the entity's name, for picking, the inspector and world.* |
| `area` (required) | `PlanBox` | the ground the field covers: a box on the plan (x, z, metres) |
| `height` (required) | `(x: number, z: number) => number` | the ground's height at (x, z): the clumps stand on it, tilted to its slope |
| `density` (required) | `number \| ((x: number, z: number) => number)` | clumps per square metre at (x, z) (0: bare) |
| `patch` | `(x: number, z: number) => number` | which of `tints` the point (x, z) belongs to (0 everywhere without it) |
| `size` | `(x: number, z: number) => number` | a multiple of the clumps' size at (x, z) (1 without it) |
| `tints` | `[string, string][]` | each patch's root and tip colours: ["#2c4a1a", "#5f8a2c"] |
| `highlight` | `string` | the tips' highlight colour ("#f2e7a0") and how much of it each tip takes (0.22) |
| `highlightMix` | `number` | how much of the highlight each tip takes (0.22) |
| `blades` | `number` | blades in a clump (14), their height in metres (0.3; each 0.55 to 1.3 times it), width range ([0.034, 0.05]) |
| `bladeHeight` | `number` | their height in metres (0.3; each 0.55 to 1.3 times it) |
| `width` | `[number, number]` | a blade's width range, metres ([0.034, 0.05]) |
| `spread` | `number` | how far from its clump's centre a blade stands (0.06 m), and how far it leans over its height ([0.2, 0.7]) |
| `lean` | `[number, number]` | how far a blade leans over its height ([0.2, 0.7]) |
| `scale` | `[number, number]` | each clump's scale, a random pick between these ([0.85, 1.35]), times `size` |
| `seed` | `number` | which randomness places the clumps |
| `resolution` | `number` | grid points a metre the functions are sampled at (2) |
| `tile` | `number` | a tile's side in metres (4) |
| `lod` | `GrassLod[]` | the steps of detail, nearest first (the engine's: every clump within 5 m, half of them in 8 blades to 14 m, a fifth in 5 blades beyond) |
| `shadow` | `boolean` | cast shadows (false) |

### `ImagePlane`

A picture on a flat card in the scene, unlit (a poster, a screen, a sprite).

Bevy: `bevy_image::image::Image`.

Takes [`ImagePlaneProps`](#imageplaneprops)'s props.

### `Instances`

One glTF (or one mesh) drawn at many placements, loaded once and drawn by the GPU as instances: a meadow's grass
and flowers, a forest, a suburb's houses. `<Instances src={staticFile("daisy.glb")} at={scatter({...})} />`. The
copies share one surface and can't play a clip.

Bevy: `bevy_pbr::render::mesh::MeshPipeline (automatic batching of entities sharing a mesh and material)`.

Takes [`InstancesProps`](#instancesprops)'s props.

### `LensDistortion`

Barrel or pincushion distortion (Brown-Conrady k1, k2) on the camera, a pass after tone mapping as Fisheye's.
Put it inside the Canvas3D.

Bevy: `bevy_post_process::LensDistortion`.

Takes [`LensDistortionProps`](#lensdistortionprops)'s props.

### `Look`

The whole frame drawn as a model's look draws its model: every part of the scene in the one grain, its bloom,
fog and blur inside it. Put it inside the Canvas3D. mode="paint" or "cartoon" draws every standard material as
paint (engine/render paint.rs):

Bevy: `bevy_pbr::mesh_material::MeshMaterial3d<bevy_pbr::extended_material::ExtendedMaterial<bevy_pbr::pbr_material::StandardMaterial, raea_render::engine::paint::Paint>>`.

Takes [`LookProps`](#lookprops)'s props.

### `Matchmove`

Footage with real 3D standing in it: the clip behind, its camera solved and followed, the subject in front. Fills
the frame (its camera's view is the frame's); its children are the 3D in the shot's world, lights included.

Takes [`MatchmoveProps`](#matchmoveprops)'s props.

### `MeshPass`

The mesh it's inside drawn again by your shader, in a phase of its own after the camera's main opaque pass: onto
the colour target, with no depth test unless `depth`, back faces culled (Bevy's shader_advanced/custom_render_phase). It
reads the mesh's colours at location 1 under VERTEX_COLORS when the mesh has them.

Rust: `raea_sys_phase::MeshPass`.

| Prop | Type | What it does |
| --- | --- | --- |
| `shader` (required) | `string` | the shader file, compiled as written: staticFile("shaders/x.wesl"). Its vertex input is the mesh's position at location 0 (a vec4 `compressed_position` under VERTEX_POSITIONS_COMPRESSED), its bind groups Bevy's mesh view (0) and mesh (2) |
| `vertex` | `string` | its entry points (Bevy's default names) |
| `fragment` | `string` | the fragment entry point's name |
| `depth` | `boolean` | whether it tests and writes the view's depth (GreaterEqual), as a mesh in Bevy's opaque phase does (Bevy's shader_advanced/specialized_mesh_pipeline); without, it draws over everything |

Used in: [shader_advanced/specialized_mesh_pipeline](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/shader_advanced/specialized_mesh_pipeline.tsx), [shader_advanced/custom_render_phase](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/shader_advanced/custom_render_phase.tsx).

### `MeshSequence`

A baked simulation, one mesh a frame.

Takes [`MeshSequenceProps`](#meshsequenceprops)'s props.

### `MeshShaderPass`

Inside a Camera3d: your task and mesh shaders make primitives on the GPU and your fragment shader draws them into
the view's colour and depth (compared GreaterEqual) after the main opaque pass (Bevy's
shader_advanced/mesh_shader_intro). It needs a GPU with mesh shaders, as Apple silicon's Metal has; elsewhere it
draws nothing and says so.

Rust: `raea_sys_phase::MeshShaderPass`.

| Prop | Type | What it does |
| --- | --- | --- |
| `task` | `string` | the task (amplification) shader file, compiled as written; none when left out, and the draw's workgroups are the mesh shader's |
| `mesh` (required) | `string` | the mesh shader file, compiled as written: it makes the primitives the fragment shader draws |
| `fragment` (required) | `string` | the fragment shader file, compiled as written. Each file has the one entry point of its stage; bind group 0 is Globals (binding 0) and the view uniform (binding 1) in all three, and a file's `import super::NAME` reads NAME.wesl beside it |
| `groups` | `[number, number, number]` | the draw's workgroup count, [x, y, z] (draw_mesh_tasks); [1, 1, 1] when left out |

Used in: [shader_advanced/mesh_shader_intro](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/shader_advanced/mesh_shader_intro.tsx).

### `Model`

A glTF model. Its clips are the file's (@bevy bevy_animation::AnimationClip), played by `animation`, blended by
`animations` or composed by `graph`, each built by the engine into its AnimationGraph
(@bevy bevy_animation::graph::AnimationGraph; engine/render scene3d.rs). `look` draws the model in its own grain
(engine/render look.rs):

Bevy: `bevy_pbr::mesh_material::MeshMaterial3d<raea_render::engine::look::LookMaterial>`.

| Prop | Type | What it does |
| --- | --- | --- |
| `src` (required) | `string` | a glTF file in the media folder: staticFile("models/shoe.glb") |
| `name` | `string` | the entity's name, for picking and the inspector |
| `sampler` | `SamplerSpec` | how its own glTF textures are read: { filter: "nearest" } for hard pixels, whatever the file says; a <MeshStandardMaterial> child's maps take their own `sampler` |
| `pass` | `string` | the composition pass it draws in ("scene" by default): a frame-wide effect told to skip a pass (<Look skip>, <Outline skip>, <Bloom skip>, <Grade skip>) leaves its pixels as drawn, and <Look passes> gives one its own paint; a piece names at most three passes besides "scene"; keyed per frame |
| `cloth` | `{ src: string; frame: number }` | a skinned model's own vertices replaced each frame by a baked cloth simulation (docs/cloth.md K2): `src` a.rseq of the model's vertices in its bind pose, in the glTF's order (raea/body tools/cloth.ts --bind), `frame` the one drawn (keyed per frame). The skin poses them, so its materials, alpha, morphs and bones are kept. |
| `attach` | `{ to: string; bone: string }` | fixed to another model's bone (`to`: that model's name; `bone`: the node's name in its glTF, "Head"): it follows the bone's animated pose, and its position, rotation and scale are in the bone's space (a glTF's armature is often scaled, so a hat may need scale 0.01) |
| `bones` | `Record<string, string>` | a skinned model's joints placed where other models are, by name: `{ pelvis: "hero-pelvis",... }` puts the joint named pelvis wherever the model named hero-pelvis is each frame (its position and rotation; shrink it to hide it: scale 0.001, not 0, which takes the skin with it), so a ragdoll's bodies move one skin that bends at its joints rather than rigid pieces. The model's own placement stays at the origin. |
| `position` | `Vec3` | where it stands, metres (x, y, z) |
| `rotation` | `Vec3` | radians |
| `scale` | `number \| Vec3` | one number, or x, y and z |
| `allowOverlap` | `boolean` | it may pass through other parts on purpose (a blade into a body, a ghost through a wall): raea's clipping check leaves it out |
| `posed` | `boolean` | set at an angle on purpose (a bowl knocked over, a mug on its side): `raea scene lint` doesn't call it tilted |
| `animation` | `string \| number` | a clip to play: its name in the file, or its index |
| `screens` | `ModelScreens` | live pictures on its materials, by the glTF material's name: `{ monitor_screen: <Screen resolution={[384, 272]}> <Game /></Screen> }` (or a bare `<Game />` for the defaults). Each mesh with that material shows the screen, the picture fitted to the mesh's texture coordinates and stood upright |
| `hide` | `string[]` | nodes of the glTF hidden, by name (a robot's painted-on eyes under the screen that replaces them) |
| `nodes` | `Record<string, { translation?: Vec3; rotation?: [number, number, number, number]; scale…` | glTF nodes' local transforms, by name, set each frame (a joint turned by hand: Bevy's gltf_skinned_mesh turns GltfNode2). Bevy's loader names an unnamed node GltfNode{index}. A part left out stays as the file has it; give the same nodes and parts every frame |
| `grid` | `{ cell: number; major?: number; color?: string; toon?: boolean }` | graph paper over the model's surfaces, as MeshStandardMaterial's `grid`, but drawn in the model's own texture coordinates (taken as metres), so the lines stay on the surface as it moves; no outlines. `toon`: its light in three flat bands (toon shading) |
| `animations` | `{ clip: string \| number; time?: number; weight?: number }[]` | several clips blended by weight (Bevy's AnimationGraph): each its name or index, its time in seconds (the Sequence's time by default) and weight (1 by default). A transition is weights moved over frames (interpolate one down as the next comes up); a layer is a second clip at a lower weight. Up to 4; not with `animation` |
| `graph` | `AnimGraphNode` | an authored animation graph (Bevy's AnimationGraph): a clip node, or a blend (its children's weights normalised) or an additive node (each child times its weight, added on) over children; any node may leave the subtrees of the bones in its `mask` alone (a wave on the arm over a walk: { add: [{ clip: "walk" }, { clip: "wave", mask: ["leg_l", "leg_r"] }] }). Weights and clip times may change every frame. Up to 16 nodes; not with animation or animations |
| `morphs` | `Record<string, number> \| number[]` | morph target (blend shape) weights, 0 to 1: by target name ({ smile: 0.8 }) or index ([0.8, 0]); up to 64. The names are fixed when the model is made: pass the same set every frame (0 for a target at rest) |
| `time` | `number` | seconds into the clip (by default the Sequence's time: frame / fps); the clip loops unless loop={false} |
| `loop` | `boolean` | false plays the clip once and holds its last pose |
| `scene` | `number` | which of the file's scenes (0 by default) |
| `look` | `"solid" \| "pixel" \| "site"` | how the model itself is drawn (the rest of the scene is unchanged): "solid" (its own surfaces, the default), "pixel" (pixel art: a cell per `pixelSize` frame pixels, outlined in `edgeColor`) or "site" (raea.io's grain: the cells' light ordered-dithered into the site's six greys). It may change from frame to frame. |
| `flat` | `boolean` | its surfaces without light: shape and colour alone, like a drawing (the site look keeps the light: its grain is made of it) |
| `shadow` | `boolean` | false: its meshes cast no shadow (true by default) |
| `receiveShadow` | `boolean` | false: no shadow falls on its meshes, its own included (true by default): a furry coat of many cards that would otherwise speckle itself in the shadow maps |
| `pixelSize` | `number` | a cell's size in frame pixels for the pixel and site looks (6 by default) |
| `edgeColor` | `string` | the pixel look's one-cell outline, a hex colour ("#000000" by default), or "none" |
| `theme` | `"dark" \| "light"` | the site look's greys: "dark" (light ink on black, the default) or "light" |
| `lift` | `number` | the site look's ink: lift + light * gain, before the dither (0.28 and 0.9 by default; on the light greys light is inverted, 0.35 and 0.75) |
| `gain` | `number` | the site look's ink gain: lift + light * gain (0.9 by default, 0.75 on the light greys) |
| `children` | `ReactNode` | <MeshToonMaterial> children: toon surfaces over the model's own materials (all of them, or one each by name); <MeshStandardMaterial> children: its materials (all, or one each by `material`) given the colour, texture or finish each gives, the rest kept |

Used in: [3d/lightmaps](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/3d/lightmaps.tsx), [3d/split_screen](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/3d/split_screen.tsx), [3d/atmospheric_fog](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/3d/atmospheric_fog.tsx), [stress_tests/many_foxes](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/stress_tests/many_foxes.tsx), [camera/projection_zoom](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/camera/projection_zoom.tsx), [animation/animated_mesh](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/animation/animated_mesh.tsx), [gltf/gltf_skinned_mesh](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/gltf/gltf_skinned_mesh.tsx), [gltf/load_gltf](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/gltf/load_gltf.tsx), and 1 more.

### `MotionBlur`

Motion blur from each part's and the camera's motion over the frame before (Bevy's MotionBlur): with it, each frame
is drawn after the one before it, so a frame's blur is the same in a render, a seek and play. A frame without it has
none. Put it inside the Canvas3D.

Bevy: `bevy_post_process::motion_blur::MotionBlur`.

Takes [`MotionBlurProps`](#motionblurprops)'s props.

### `Outline`

Ink lines where the scene's depth steps or its surfaces turn, drawn before bloom and tone mapping; under a <Look>
a cell wide (Return of the Obra Dinn's line). Put it inside the Canvas3D.

Takes [`OutlineProps`](#outlineprops)'s props.

### `Part`

A glTF's nodes drawn on their own, where they stood, moved by a rigid motion, glitched by the frame's values.

| Prop | Type | What it does |
| --- | --- | --- |
| `name` | `string` | the entity's name (the first node's by default) |
| `src` (required) | `string` | the glTF (staticFile("x.glb")) and the nodes that make the part |
| `nodes` (required) | `string[]` | the glTF nodes that make the part |
| `position` | `Vec3` | a rigid motion from where it stands in the file (see `about`): position, and a quaternion [x, y, z, w] |
| `quaternion` | `Quat` | its turn as a quaternion [x, y, z, w] (see `about`) |
| `scale` | `number` | a uniform scale (1) |
| `material` | `PartMaterial` | a material over the part's own (colour, glow, opacity) |
| `glitch` | `Glitch` | how the part breaks up this frame: explode, scramble, jitter, snap, smear |
| `castShadow` | `boolean` | it casts shadows |

### `PhaseItem`

Your own pipeline drawing your own buffers in each camera's Opaque3d phase.

Rust: `raea_sys_phase::PhaseItem`.

| Prop | Type | What it does |
| --- | --- | --- |
| `shader` (required) | `string` | the shader file, compiled as written: staticFile("shaders/x.wesl") |
| `vertex` | `string` | its entry points (Bevy's default names) |
| `fragment` | `string` | the fragment entry point's name |
| `stride` (required) | `number` | the vertex buffer: each vertex `stride` bytes, its 32-bit words in order (a u32 pad of 0 is a 0) |
| `attributes` (required) | `PhaseAttribute[]` | the vertex buffer's attributes |
| `words` (required) | `number[]` | the vertex buffer's 32-bit words, every vertex's in order |
| `indices` (required) | `number[]` | the index buffer (u32), drawn whole |
| `depth` | `{ write?: boolean; compare?: "Never" \| "Less" \| "Equal" \| "LessEqual" \| "Greater" \| "No…` | its depth state: whether it writes depth, and its compare (Bevy's CompareFunction by name; Bevy's opaque default, Greater, when left out) |
| `aabb` (required) | `{ center: [number, number, number]; half_extents: [number, number, number] }` | its bounds, so the camera sees it (Bevy's Aabb): a centre and half extents |
| `position` | `[number, number, number]` | where it is (a bare Entity's place) |

Used in: [shader_advanced/custom_phase_item](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/shader_advanced/custom_phase_item.tsx).

### `Physics`

Rigid bodies, simulated once and played back by the frame: the <Body>s among its children (directly, or in
fragments). Before `from` and after `seconds` they hold their first and last poses.

| Prop | Type | What it does |
| --- | --- | --- |
| `seconds` (required) | `number` | how long to simulate, seconds |
| `gravity` | `Vec3` | m/s² (0, -9.81, 0) |
| `substeps` | `number` | steps per frame (8) |
| `colliders` | `{ min: Vec3; max: Vec3; friction?: number; restitution?: number }[]` | static boxes (world, metres): the floor, the table top |
| `from` | `number` | the frame (of the enclosing Sequence) the simulation starts on (0); before it everything is at rest |
| `children` | `ReactNode` | the <Body> elements to simulate, and anything else to draw |

### `Plane3d`

*From Bevy's `bevy_shape::Plane3d`:* A bounded plane in 3D space. It forms a surface starting from the origin with a defined height and width.

Takes [`Plane3dProps`](#plane3dprops)'s props.

### `Plate`

Footage behind the 3D: the clip's frame filling the camera's whole view (its `view` when it has one), on the far
side of everything, unlit. Give the scene `<ToneMapping mode="none" />` to keep its colours exact. <Matchmove> is
the usual way in.

Takes [`PlateProps`](#plateprops)'s props.

### `Refinish`

Every <Model> inside re-covered: each of its glTF materials (all, or the one each names by `material`) given the
colour, texture or finish each gives, the rest of it kept (a run of cabinets painted, the doors and drawers with them;
`map: null` takes the wood's picture off). A model's own <MeshStandardMaterial> children go first.

| Prop | Type | What it does |
| --- | --- | --- |
| `materials` (required) | `MeshStandardMaterialProps[]` | the finishes, each a <MeshStandardMaterial>'s props, over every glTF material or the one its `material` names |
| `children` | `ReactNode` | the models refinished |

### `RichText`

Text in the 3D world: every glyph a real lit, shaded entity (bevy_rich_text3d's mesh over its glyph atlas, a
StandardMaterial of its own), laid out as one line of shaped text (kerning, spans of other fonts and sizes) and
then moved, turned, scaled, recoloured, faded and revealed glyph by glyph with the motion code 2D uses: the named
moves staggered (`enter="rise" each={2}`), a typewriter's `reveal`, or a `glyph` function of the frame.

 <RichText name="title" size={0.6} enter="pop" each={3}>Hello <Span color="#ffd400" weight={900}>world</Span></RichText>
 <RichText glyph={(g) => ({ position: [0, Math.sin(frame / 6 + g.index) * 0.05, 0] })}>WAVE</RichText>

Takes [`RichTextProps`](#richtextprops)'s props.

### `Scene`

A world drawn at the current frame: its `mesh` rows (shape, x y z, rot_x rot_y rot_z in radians, scale, color,
rough, metal), `camera` (x y z, look_x look_y look_z, fov), `light` (x y z, intensity) and `ambient` (intensity)
rows as the 3D elements above. Inside a Canvas3D.

| Prop | Type | What it does |
| --- | --- | --- |
| `world` (required) | `World` | the world whose rows are drawn; its systems run up to the current frame |

### `Screen`

A live picture on a surface in the 3D scene: a nested composition or game (its children, or `src`, a video) at its
own resolution, drawn as a CRT (scanlines, mask, glow, the glass) or flat. Inside a Canvas3D on its own it's a
free-standing quad; on a model, give it to the Model: `<Model src={...} screens={{ monitor_screen: <Screen
resolution={[384, 272]}><Game /></Screen> }} />`. A screen doesn't light the room: put a dim light of its colour in
front of it.

Bevy: `bevy_pbr::mesh_material::MeshMaterial3d<raea_render::engine::screen::CrtMaterial>`.

| Prop | Type | What it does |
| --- | --- | --- |
| `name` | `string` | what the screen is called; screens on one page need different names ("screen" by default) |
| `position` | `Vec3` | a free-standing screen's place: a quad of `size` metres ([1.6] wide by default, its height from the resolution) |
| `rotation` | `Vec3` | radians |
| `scale` | `number \| Vec3` | its scale: one number, or x, y and z |
| `size` | `[number] \| [number, number]` | [width] or [width, height] in metres ([1.6], its height from the resolution) |
| `pass` | `string` | the composition pass it draws in (Mesh's `pass`; "scene" by default): `pass="ui"` with <Look skip={["ui"]}> keeps a page crisp under a paint look |

Also takes the props of [`ScreenSource`](#screensource).

### `ShaderInstances`

The mesh it's inside drawn once per instance in one draw, by your shader, in the camera's Transparent3d phase, a
vertex buffer of your words stepped per instance (Bevy's shader_advanced/custom_shader_instancing). Its instances
aren't in the mesh's bounds: give the mesh Bevy's NoFrustumCulling (<BevyComponent type="bevy_camera::visibility::NoFrustumCulling" value={{}} />).

Rust: `raea_sys_phase::ShaderInstances`.

| Prop | Type | What it does |
| --- | --- | --- |
| `shader` (required) | `string` | the shader file, compiled as written: staticFile("shaders/x.wesl"). Its vertex reads the mesh's position, normal and uv at locations 0 to 2 and the instance's attributes at theirs; its bind groups are Bevy's mesh pipeline's |
| `stride` (required) | `number` | each instance's bytes (a multiple of 4) |
| `attributes` (required) | `PhaseAttribute[]` | what the shader reads of an instance: Bevy's VertexFormat, its byte offset and |
| `words` (required) | `number[]` | every instance's 32-bit words in order, `stride / 4` of them each |

Used in: [shader_advanced/custom_shader_instancing](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/shader_advanced/custom_shader_instancing.tsx).

### `ShaderMesh`

A mesh drawn by a material written here in WESL or WGSL: one generic Bevy material
(rdb's ShaderMaterial, an AsBindGroup of 16 uniform slots and 4 textures) whose fragment shader is this source, so
a dissolve, a toon ramp, a hologram or a procedural pattern needs no Rust. Uniforms may change from frame to frame
(they're set again on any frame where they change); the shader isn't compiled again (#28).

Bevy: `bevy_pbr::mesh_material::MeshMaterial3d<raea_sys_material::shader_material::ShaderMaterial>`.

Takes [`ShaderMeshProps`](#shadermeshprops)'s props.

### `Shadows`

Shadow quality for every light in the Canvas3D: map size, the sun's cascades, biases, filtering. Put it inside the
Canvas3D, once; the first frame's holds for the piece. mapSize sets both shadow maps' size, filter the camera's
filtering, and the cascade props the sun's cascades (engine/render scene3d.rs):

Bevy: `bevy_light::directional_light::DirectionalLightShadowMap`, `bevy_light::point_light::PointLightShadowMap`, `bevy_light::ShadowFilteringMethod`, `bevy_light::cascade::CascadeShadowConfig`.

Takes [`ShadowsProps`](#shadowsprops)'s props.

Used in: [3d/shadow_caster_receiver](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/3d/shadow_caster_receiver.tsx), [3d/atmospheric_fog](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/3d/atmospheric_fog.tsx), [gltf/load_gltf](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/gltf/load_gltf.tsx), [shader_advanced/deferred_raymarch](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/shader_advanced/deferred_raymarch.tsx).

### `Shape2D`

A flat shape in 2D, over the 3D, in one colour: Bevy's Mesh2d with a ColorMaterial (raea-sys-sprite). Put it
inside the Canvas3D.

Bevy: `bevy_sprite_render::mesh2d::color_material::ColorMaterial`, `bevy_sprite_render::mesh2d::material::MeshMaterial2d<bevy_sprite_render::mesh2d::color_material::ColorMaterial>`, `bevy_mesh::components::Mesh2d`.

Takes [`Shape2DProps`](#shape2dprops)'s props.

### `Skybox`

Bevy's Skybox: a cubemap drawn behind everything, as Bevy's examples put one on the camera. Put it inside the
Canvas3D, once; its brightness and rotation may change each frame (an <Environment>'s `background` is the sky of
a panorama raea filters).

Bevy: `bevy_light::probe::Skybox`.

Takes [`SkyboxProps`](#skyboxprops)'s props.

### `Span`

A run of a <RichText>'s text in its own font, weight, size or colour. Only inside a <RichText>.

Takes [`SpanProps`](#spanprops)'s props.

### `Sphere`

Also takes the props of [`SphereProps`](#sphereprops) (`args`, `radius`, `ico`, `uv`).

Used in: [3d/bloom_3d](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/3d/bloom_3d.tsx).

### `Splat`

A gaussian splat: a reconstructed scene or object, drawn back to front for the frame's camera, behind any mesh in
front of it, through the frame's look. Animate it with reveal, assemble, disperse, explode, wave, twist, morph and
pulse, all values of the frame.

Bevy: `bevy_pbr::mesh_material::MeshMaterial3d<raea_render::engine::splat::SplatMaterial>`, `bevy_pbr::mesh_material::MeshMaterial3d<raea_render::engine::splat::SplatMask>`.

Takes [`SplatProps`](#splatprops)'s props.

### `Sprite`

A picture in 2D, over the 3D: Bevy's Sprite, drawn as a quad with its sprite material, a sprite sheet's cells cut
by a texture atlas (raea-sys-sprite). Put it inside the Canvas3D.

Bevy: `bevy_sprite::sprite::Sprite`, `bevy_sprite_render::sprite_mesh::sprite_mesh_material::SpriteMeshMaterial`, `bevy_sprite_render::mesh2d::material::MeshMaterial2d<bevy_sprite_render::sprite_mesh::sprite_mesh_material::SpriteMeshMaterial>`, `bevy_sprite_render::sprite_mesh::sprite_extended_material::SpriteMaterial`, `bevy_image::texture_atlas::TextureAtlasLayout`.

Takes [`SpriteProps`](#spriteprops)'s props.

Used in: [camera/pan_camera_controller](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/camera/pan_camera_controller.tsx), [camera/2d_on_ui](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/camera/2d_on_ui.tsx), [shader/compute_shader_game_of_life](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/shader/compute_shader_game_of_life.tsx), [shader/sprite_material](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/shader/sprite_material.tsx), [2d/rotation](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/2d/rotation.tsx), [2d/move_sprite](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/2d/move_sprite.tsx), [2d/sprite_slice](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/2d/sprite_slice.tsx), [2d/rotate_to_cursor](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/2d/rotate_to_cursor.tsx), and 8 more.

### `SurfaceShader`

One shader over every lit standard surface in the scene that has none of its own (meshes, Models' materials,
Characters), so the whole scene shares one look. Unlit, toon, paint, flat and looked
surfaces and ShaderMesh keep theirs. In the 3D beside the camera; one per scene.

Bevy: `bevy_pbr::mesh_material::MeshMaterial3d<bevy_pbr::extended_material::ExtendedMaterial<bevy_pbr::pbr_material::StandardMaterial, raea_sys_shader::ShaderExt>>`.

Takes [`SurfaceShaderSpec`](#surfaceshaderspec)'s props.

### `Text3D`

Solid 3D letters (Manifold's text3d), as a Mesh's geometry: `<Mesh><Text3D size={0.6}>SALE</Text3D>...</Mesh>`.

Takes [`Text3DProps`](#text3dprops)'s props.

### `ThreeShaderMaterial`

A three.js shader on the mesh it's in, as it is: a ShaderMaterial's GLSL (or a node material's WGSL) with its
uniforms, drawn by raea's engine with three's built-ins. `<R3F>` makes these from an R3F scene's materials.

Takes [`ThreeShaderMaterialProps`](#threeshadermaterialprops)'s props.

### `ToneMapping`

The camera's tone mapping and exposure. Put it inside the Canvas3D.

Bevy: `bevy_render::view::Tonemapping`, `bevy_camera::camera::Exposure`.

Takes [`ToneMappingProps`](#tonemappingprops)'s props.

Used in: [3d/rotate_environment_map](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/3d/rotate_environment_map.tsx), [3d/bloom_3d](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/3d/bloom_3d.tsx), [3d/mesh_ray_cast](https://github.com/shinyobjectz/raea/blob/main/sdk/raea/bench/bevy-parity/3d/mesh_ray_cast.tsx).

### `Torus`

*From Bevy's `bevy_shape::Torus`:* A torus primitive, often representing a ring or donut shape The set of points some distance from a circle centered at the origin

Also takes the props of [`TorusProps`](#torusprops) (`args`, `major_radius`, `minor_radius`).

### `Volume`

A simulated volume: density and heat in a box, put in by its sources and puffs, lifted by heat, weighed down,
carried by the wind and its own curls, drawn lit and shadowed by itself. Smoke, a cloud or a contrail is a choice of
these (examples/volumes).
Simulated and raymarched by engine/render volume.rs:

Bevy: `bevy_pbr::mesh_material::MeshMaterial3d<raea_render::engine::volume::VolumeMaterial>`.

Takes [`VolumeProps`](#volumeprops)'s props.

### `VolumetricFog`

Volumetric fog on the camera: light in the air, drawn inside every <FogVolume>, with shafts from the lights marked
`volumetric`. Put it inside the Canvas3D, once; without it fog volumes draw nothing.

Bevy: `bevy_light::volumetric::VolumetricFog`, `bevy_light::volumetric::VolumetricLight`.

Takes [`VolumetricFogProps`](#volumetricfogprops)'s props.

### `ZFight`

The part drawn twice in the same place, the second a hair turned, in another material: the two surfaces fight
for the depth buffer and flicker in stripes (z-fighting), stronger with `amount` (radians, ~0.002).

| Prop | Type | What it does |
| --- | --- | --- |
| `amount` (required) | `number` | radians the second copy is turned (~0.002): more is stronger stripes |
| `other` | `PartMaterial` | the second copy's material |

Also takes the props of [`PartProps`](#partprops).

## Hooks

### `useBake`

The bake for these props (made once and kept).

```ts
function useBake(props: PhysicsProps): Baked
```

### `useGoo`

The goo's bake for these props (made once and kept), and the frame (of the enclosing Sequence) at which each
object's own part should go, the goo having taken it over.

```ts
function useGoo(p: GooProps): GooBake & { gone: (name: string) => boolean; frame: number; }
```

### `useMatchmove`

The solve and this frame's camera, inside a <Matchmove>.

```ts
function useMatchmove(): MatchmoveState
```

### `usePhysics`

Inside <Physics>: the bake and the frame in it.

```ts
function usePhysics(): { baked: Baked; frame: number; t: number; }
```

## Functions

### `about`

A rigid motion of a part about a point (`about`, its rest centre): turn by q there, then move by `move`. As a
<Motion>/<Part> position and quaternion.

```ts
function about(about: Vec3, q: Quat, move?: Vec3): { position: Vec3; quaternion: Quat; }
```

### `bodyPose`

A body's rigid motion from rest at the current frame.

```ts
function bodyPose(baked: Baked, name: string, k: number): { position: Vec3; quaternion: Quat; }
```

### `checkMatchmove`

Checks a Matchmove's props; throws a TypeError or RangeError naming the prop.

```ts
function checkMatchmove(p: MatchmoveProps): void
```

### `checkPass`

A part's composition pass, checked: a name, letters first (up to 32 of letters, digits, _ and -).

```ts
function checkPass(owner: string, pass: unknown): void
```

### `clipEvents`

The clip events that fire between two frames (Bevy's AnimationClip events, as data): an event `time` seconds into
the clip fires on the frame whose clip time first reaches it, that is when it lies in (prev, now], once per loop
when the clip loops (`duration` its length). Give the previous frame's clip time and this frame's, as a <Model>'s
`time` runs; on the first frame pass prev -1 so an event at 0 fires.

```ts
function clipEvents<E extends { time: number; }>(events: E[], prev: number, now: number, duration: number, loop?: boolean): E[]
```

### `dofOf`

Bevy's DepthOfField fields as the old ones; their defaults are Bevy's (f/1, where the old one is f/2.8)

```ts
function dofOf(owner: string, props: DepthOfFieldProps): DepthOfFieldProps
```

### `eulerOf`

A part's Euler angles of a quaternion: a composition's `rotation` [x, y, z] is composed as three.js composes it,
Quat::from_euler(EulerRot::XYZ, x, y, z) (runtime/scene `local`; the YXZ rot_x/rot_y/rot_z of
raea-render's rows are read back from the world matrix), so this is that order's inverse.

```ts
function eulerOf(q: [number, number, number, number]): Vec3
```

### `gooSpec`

The spec tools/goo bakes for these props at the composition's `fps`: what `physics goo SPEC.json` takes, and the bake's
key, so a script can bake (or check) a goo without rendering.

```ts
function gooSpec(p: GooProps, fps: number): Record<string, unknown>
```

### `hash01`

0..1 from integers, the same on every run

```ts
function hash01(...xs: number[]): number
```

### `lastBeat`

The last of `times` at or before t: its index (-1 before the first) and how long ago it was, seconds.

```ts
function lastBeat(t: number, times: readonly number[]): { index: number; since: number; time: number; }
```

### `matchmoveIndex`

The solve's frame at a time in the clip: the latest at or before it, clamped to the solve.

```ts
function matchmoveIndex(solve: MatchmoveSolve, time: number): number
```

### `matchmoveView`

The footage's view in a frame of another shape: the whole view's size (the footage scaled to cover the frame, times
zoom) and the frame's window in it, in frame pixels.

```ts
function matchmoveView(footage: { width: number; height: number; }, frame: { width: number; height: number; }, crop?: number | [number, number], zoom?: number): { width: number; height: number; x: number; y: number; }
```

### `part`

glTF nodes cut out as their own file, standing where they stood (made once, kept in the asset store).

```ts
function part(src: string, nodes: string[], material?: PartMaterial): PartInfo
```

### `physicsRequest`

The simulation's request: every body's props as Rapier takes them, events in frames.

```ts
function physicsRequest(props: PhysicsProps, fps: number): Record<string, unknown>
```

### `pick`

The nearest part under the pointer, or null. `size` is the frame's (useVideoConfig's width and height), whose
pixels the pointer is in.

```ts
function pick(pointer: { x: number; y: number; }, camera: PickCamera, parts: readonly Pickable[], size: { width: number; height: number; }): Hit | null
```

### `place`

```ts
function place(o: { objects: Record<string, V3 | PlaceObject>; rules: PlaceRule[]; room?: { min: [number, number]; max: [number, number]; } | undefined; }): Layout
```

### `pointerRay`

The pointer's ray: from the camera through the pointer (x, y in the frame's pixels, y down), as the engine draws it
(Bevy's looking_at, with +Z for up when the camera looks straight up or down, as rdb does).

```ts
function pointerRay(pointer: { x: number; y: number; }, camera: PickCamera, size: { width: number; height: number; }): { origin: Vec3; direction: Vec3; }
```

### `quatAxis`

The quaternion [x, y, z, w] turning `angle` radians about `axis`, as Bevy's Quat::from_axis_angle.

```ts
function quatAxis(axis: Vec3, angle: number): Quat
```

### `quatMul`

The product a × b of two quaternions [x, y, z, w], `b` applied first, as Bevy's Quat * Quat.

```ts
function quatMul(a: Quat, b: Quat): Quat
```

### `samplerSpec`

A sampler checked (a TypeError or RangeError naming the owner and the part).

```ts
function samplerSpec(owner: string, s: SamplerSpec): SamplerSpec
```

### `scatter`

Points scattered over an area for an <Instances>: seeded (the same layout every frame and every run), at least
`spacing` apart, clear of `avoid` and `clearOf`, on the ground `y` gives, kept by `density`. A spatial hash keeps
thousands quick. Call it once at module level, not per frame.

```ts
function scatter(o: ScatterOptions): Instance[]
```

### `snapPose`

Positions snapped to a grid (`step` metres): a physics engine's position quantised.

```ts
function snapPose(p: Vec3, step: number): Vec3
```

### `surfaceShader`

A surface shader checked and given as the row's spec (its source, uniforms, textures).

```ts
function surfaceShader(owner: string, sh: SurfaceShaderSpec, hook?: RegExp, hooks?: string): Record<string, unknown>
```

### `surfaceTurn`

The turn that takes +y to `normal`, with the picture's top (a decal's -z) toward world up on a wall, toward -z on a
floor, turned `spin` about the normal: a quaternion [x, y, z, w].

```ts
function surfaceTurn(normal: Vec3, spin?: number): [number, number, number, number]
```

### `teleport`

A position that jumps to a new seeded spot on each beat in `times` (within `radius`, metres, on the axes `axes`
scales) and holds it, back home `hold` seconds after the beat (Infinity: until the next).

```ts
function teleport(t: number, times: readonly number[], o: { radius: number; seed?: number; hold?: number; axes?: Vec3; }): Vec3
```

### `toHex`

A colour as the 3D renderer takes it (#rrggbb): hex, rgb()/rgba() or a common name; CSS variables throw.

```ts
function toHex(owner: string, k: string, v: unknown): string
```

## Classes

### `CrossSection`

A 2D shape (Manifold's CrossSection), held by value: its contours (counter-clockwise solid, clockwise holes),
area and bounds. Offset, combine and move it, then extrude or revolve it into a Solid.

| Member | What it does |
| --- | --- |
| `CrossSection.from(a: SectionAnswer): CrossSection` | From an engine answer (a slice, a projection, an operation). |
| `CrossSection.of(polygons: Polygons): CrossSection` | Contours, overlaps merged and self-crossings resolved (Manifold's positive fill rule). |
| `.polygons: Polygons` | its contours, each a list of [x, y] points: counter-clockwise solid, clockwise holes |
| `.area: number` | its area, m² |
| `.contours: number` | how many contours it has |
| `.bounds: { min: [number, number]; max: [number, number]; }` | its bounding box's low and high corners |
| `.union(...others: CrossSection[]): CrossSection` | This and the others together. |
| `.minus(...others: CrossSection[]): CrossSection` | This with the others cut away. |
| `.intersect(...others: CrossSection[]): CrossSection` | Only where this and every other overlap. |
| `.hull(...others: CrossSection[]): CrossSection` | The convex hull of this and the others. |
| `.offset(delta: number, o?: { join?: JoinType \| undefined; miterLimit?: number \| undefined; segments?: number \| undefined; }): CrossSection` | Grown outward by `delta` (shrunk when negative), corners joined round (default), square, miter or bevel. |
| `.minkowski(other: CrossSection): CrossSection` | Swept by another shape (the 2D Minkowski sum). |
| `.simplify(epsilon?: number): CrossSection` | Fewer points: those within `epsilon` of a straight line dropped. |
| `.move(x: number, y: number): CrossSection` | Moved by (x, y). |
| `.rotate(degrees: number): CrossSection` | Turned by `degrees` about the origin. |
| `.scale(x: number, y?: number): CrossSection` | Scaled uniformly, or per axis. |
| `.mirror(nx: number, ny: number): CrossSection` | Mirrored across the line through the origin with this normal. |
| `.warp(fn: (x: number, y: number) => [number, number]): CrossSection` | Every point moved by `fn`, then re-unioned (crossings resolved). |
| `.decompose(): CrossSection[]` | Its separate pieces (each outline with its holes). |
| `.isEmpty(): boolean` | Whether nothing is left. |
| `.extrude(height: number, o?: { divisions?: number \| undefined; twist?: number \| undefined; scaleTop?: [number, number] \| undefined; }): Solid` | Extruded along z into a Solid (see manifold.extrude). |
| `.revolve(o?: { degrees?: number \| undefined; segments?: number \| undefined; }): Solid` | Revolved about the z axis into a Solid (see manifold.revolve). |

### `Field`

A signed distance field (negative inside), as the text raea-core-sdf reads. Y is up; sizes are metres.

| Member | What it does |
| --- | --- |
| `new Field(text: string)` | A field from its text, as raea-core-sdf reads it. |
| `.text: string` | the field as the text raea-core-sdf reads |
| `.move(x: number, y: number, z: number): Field` | The field moved by (x, y, z) metres. |
| `.rotate(x: number, y: number, z: number): Field` | Degrees about x, then y, then z (as a Solid's rotate). |
| `.scale(s: number): Field` | The field scaled by `s` about its origin. |
| `.mirrorX(): Field` | Both sides: the field and its mirror across x = 0 (a body's left and right from one). |
| `.round(r: number): Field` | Grown outward by r, every edge rounded by it. |
| `.shell(t: number): Field` | Hollow: a skin 2t thick on the surface. |
| `.displace(amp: number, freq: number, octaves?: number, seed?: number): Field` | Roughened by fractal noise: `amp` metres, `freq` cycles a metre (bark, rock, a lumpy creature). |
| `.solid(step?: number \| undefined): Solid` | The field meshed (marching tetrahedra, `step` metres a cell: by default a 96th of its size) as a closed solid. |

### `Solid`

A handle to a native solid. Free it when done with many (or let the run end).

| Member | What it does |
| --- | --- |
| `new Solid(id: number, expr: string)` | A handle to native solid `id`, which `expr` rebuilds; the shape functions make these, rarely you. |
| `.id: number` | the native solid's handle |
| `.expr: string` | the expression that rebuilds this solid (what a mesh row draws) |
| `.union(...others: Solid[]): Solid` | This and the others together. |
| `.minus(...others: Solid[]): Solid` | This with the others cut away. |
| `.intersect(...others: Solid[]): Solid` | Only where this and every other overlap. |
| `.hull(...others: Solid[]): Solid` | The convex hull of this and the others. |
| `.move(x: number, y: number, z: number): Solid` | Moved by (x, y, z). |
| `.rotate(x: number, y: number, z: number): Solid` | Turned by x, y and z degrees. |
| `.scale(s: number, y?: number \| undefined, z?: number \| undefined): Solid` | Scaled uniformly, or per axis. |
| `.volume(): number` | Its volume. |
| `.bounds(): Bounds` | Its bounding box. |
| `.triangles(): number` | How many triangles its mesh has. |
| `.isEmpty(): boolean` | Whether nothing is left (a boolean that removed everything). |
| `.slice(z: number): Section` | Its cross-section at height z (in a space-time mask, z is the frame). |
| `.mirror(nx: number, ny: number, nz: number): Solid` | Mirrored across the plane through the origin with this normal. |
| `.transform(m: number[]): Solid` | Transformed by a 3x4 matrix given column by column (x axis, y axis, z axis, translation). |
| `.trim(nx: number, ny: number, nz: number, offset?: number): Solid` | What's on the normal's side of the plane n. p = offset. |
| `.splitByPlane(nx: number, ny: number, nz: number, offset?: number): [Solid, Solid]` | Cut in two by the plane n. p = offset: [the normal's side, the other side]. |
| `.split(cutter: Solid): [Solid, Solid]` | Cut in two by another solid: [inside it, outside it]. |
| `.refine(n: number): Solid` | Each triangle cut into n x n. |
| `.smooth(o?: { angle?: number \| undefined; smoothness?: number \| undefined; refine?: number \| undefined; }): Solid` | Edges sharper than `angle` degrees kept, the rest rounded (smoothness 0..1 for the sharp ones too), then refined. |
| `.minkowski(other: Solid): Solid` | This swept by another solid (the Minkowski sum): rounded by a sphere, thickened by a box. |
| `.minkowskiDiff(other: Solid): Solid` | This eroded by another solid (the Minkowski difference). |
| `.mesh(): { verts: Float32Array<ArrayBufferLike>; tris: Uint32Array<ArrayBufferLike>; }` | Its triangles: positions (x y z) and indices by threes. |
| `.warp(fn: (x: number, y: number, z: number) => [number, number, number]): Solid` | Every vertex moved by `fn` (the topology kept): a bend, a twist, a wave. |
| `.simplify(tolerance: number): Solid` | The mesh coarsened: vertices closer than `tolerance` merged where the shape allows. |
| `.refineToLength(length: number): Solid` | Refined until no edge is longer than `length`. |
| `.refineToTolerance(tolerance: number): Solid` | Refined until its smoothed surface is within `tolerance` of the true curve. |
| `.crossSection(z: number): CrossSection` | Its cross-section at height z as a CrossSection (to offset, combine or extrude again). |
| `.project(): CrossSection` | Its silhouette seen from above (+z), on the x-y plane. |
| `.decompose(): Solid[]` | Its disconnected pieces, each a Solid. |
| `.minGap(other: Solid, searchLength: number): number` | The smallest gap between this and another, looking no further than `searchLength` (which it answers when nothing is closer). |
| `.rayCast(from: Vec3, to: Vec3): { distance: number; position: Vec3; normal: Vec3; }[]` | Where the segment from `from` to `to` crosses the surface, nearest first (distance 0..1 along it). |
| `.area(): number` | Its surface area. |
| `.genus(): number` | Its genus (how many holes go through it: a torus has 1). |
| `.export(path: string, format?: "obj" \| "glb" \| undefined): number` | Written as OBJ or glTF binary (by the extension, or `format`); the file's size. |
| `.free(): void` | Let the engine drop it. |

## Values

### `ATTRIBUTE_COLOR`

Bevy's Mesh::ATTRIBUTE_COLOR: a vertex's linear RGBA colour (id 5, Float32x4)

### `ATTRIBUTE_NORMAL`

Bevy's Mesh::ATTRIBUTE_NORMAL: a vertex's normal (id 1, Float32x3)

### `ATTRIBUTE_POSITION`

Bevy's Mesh::ATTRIBUTE_* (ids 0 to 5), as a Material's vertex buffer names them.

### `ATTRIBUTE_TANGENT`

Bevy's Mesh::ATTRIBUTE_TANGENT: a vertex's tangent, its w the bitangent's sign (id 4, Float32x4)

### `ATTRIBUTE_UV_0`

Bevy's Mesh::ATTRIBUTE_UV_0: a vertex's first texture coordinates (id 2, Float32x2)

### `ATTRIBUTE_UV_1`

Bevy's Mesh::ATTRIBUTE_UV_1: a vertex's second texture coordinates, as a lightmap's (id 3, Float32x2)

### `crossSection`

2D shapes as CrossSections, made natively.

### `grow`

Generated growth as Solids, built natively: `tree`, `loft`, `terrain`, `boulder`, `rosette` and the rest. Draw one
with `<Mesh shape={solid}>`; cut, join, measure and place it like any other Solid.

### `manifold`

### `MeshVertexAttribute`

A vertex attribute: its name, its unique id (a high random one for your own, as Bevy asks, so it sorts after the
built-in ones) and its format. MeshVertexAttribute.new("BlendColor", 988540917, "Float32x4") is Bevy's
MeshVertexAttribute::new; Mesh's own are ATTRIBUTE_POSITION and the rest.

Bevy: `bevy_mesh::MeshVertexAttribute`.

### `outline`

2D outlines for extrude and revolve.

### `sdf`

## Types

### `AlphaMode2d`

bevy_sprite_render's AlphaMode2d

```ts
type AlphaMode2d = "Opaque" | "Blend" | { Mask: number }
```

### `AmbientOcclusionProps`

| Field | Type | What it is |
| --- | --- | --- |
| `quality` | `"low" \| "medium" \| "high" \| "ultra"` | how many samples a pixel takes: "low" (4), "medium" (8, the default), "high" (18), "ultra" (54) |
| `thickness` | `number` | how thick, in metres, a surface is taken to be behind what the camera sees (0.25 by default): larger darkens more behind thin things |

### `Animate3d`

A 3D node's declared animation: tracks by property, or a move.

```ts
type Animate3d = Record<string, TrackSpec | TrackSpec[] | Keys> | Move
```

### `AnimGraphNode`

A node of a <Model graph>.

```ts
type AnimGraphNode = | { clip: string | number; time?: number; weight?: number; mask?: string[] } | { blend: AnimGraphNode[]; weight?: number; mask?: string[] } | { add: AnimGraphNode[]; weight?: number; mask?: string[] }
```

### `AntiAliasingProps`

| Field | Type | What it is |
| --- | --- | --- |
| `mode` (required) | `"msaa" \| "smaa" \| "fxaa" \| "none"` | "msaa" (4x multisampling, the default), "smaa" (morphological, high preset: the default with AmbientOcclusion, which can't multisample), "fxaa" (cheapest, softest) or "none". Each draws a frame from that frame alone, so a render equals its play (temporal anti-aliasing isn't offered: it needs the frames before) |

### `AtmosphereProps`

| Field | Type | What it is |
| --- | --- | --- |
| `light` | `boolean` | it lights the scene too, as a sky does (ambient and reflections from the sky it draws) |
| `groundAlbedo` | `number` | the ground's brightness the air's scattering sees, 0..1 (0.3 by default) |

### `Baked`

| Field | Type | What it is |
| --- | --- | --- |
| `fps` (required) | `number` | the frame rate it was baked at |
| `frames` (required) | `number` | how many frames it holds |
| `file` (required) | `string` | the bake's file in the asset store |
| `bodies` (required) | `Record<string, { p: number[]; q: number[]; centre: Vec3 }>` | each body's track by name: positions and quaternions a frame, flat, and its rest centre |

### `BevyComponentProps`

The props of [`BevyComponent`](#bevycomponent), tabled there.

### `BevyParts`

What a light or camera holds: Bevy's own reflected components on it (<BevyComponent>, or a generated wrapper such
as bevy_light's ShadowFilteringMethod or bevy_pbr's ScreenSpaceReflections), applied through Bevy's TypeRegistry.

| Field | Type | What it is |
| --- | --- | --- |
| `children` | `ReactNode` | Bevy components on it: <BevyComponent>, or a generated wrapper |
| `layers` | `number[]` | a camera: the render layers it draws ([0] by default); a light: the layers it lights (Bevy's RenderLayers) |

### `BloomProps`

| Field | Type | What it is |
| --- | --- | --- |
| `intensity` | `number` | 1 is a natural glow, 2 strong; 0 none |
| `threshold` | `number` | only what's brighter than this glows (0 = everything a little; 1 = only emissive parts and highlights) |
| `skip` | `string[]` | composition passes (a part's `pass`) left out of it: they neither glow nor take the glow |
| `passes` | `Record<string, number>` | each named pass's share of it, 0 (as skip) to 1 (all of it, as "scene" has) |

### `BodyProps`

The props of [`Body`](#body), tabled there.

### `Bounds`

| Field | Type | What it is |
| --- | --- | --- |
| `min` (required) | `Vec3` | the low corner |
| `max` (required) | `Vec3` | the high corner |

### `BufferMeshProps`

| Field | Type | What it is |
| --- | --- | --- |
| `positions` (required) | `number[]` | x, y, z of each vertex |
| `indices` | `number[]` | three vertex indices a triangle (counter-clockwise seen from its front); without them each three positions are one. With normals too it is Bevy's indexed Mesh, its index buffer kept, as a compute that writes a mesh expects |
| `normals` | `number[]` | x, y, z of each vertex's normal (without them each face is flat, facing its front) |
| `uvs` | `number[]` | u, v of each vertex (without them a picture map is projected onto the mesh's bounds) |
| `colors` | `number[] \| string[]` | each vertex's colour: r, g, b, a (linear, 0 to 1) per vertex, or one "#rrggbb" per vertex; the material's colour is multiplied by it (Bevy's ATTRIBUTE_COLOR), so leave the material white to see them as given |
| `attributes` | `Record<string, { size: number; values: number[] }>` | a mesh's own attributes beyond those, for a three.js shader that reads them (<ThreeShaderMaterial>): each one's size (1 to 4 numbers a vertex) and values, per vertex |

### `Canvas3DProps`

| Field | Type | What it is |
| --- | --- | --- |
| `layered` | `boolean` | the 3D takes its place in the page's tree order instead of lying under the whole page: page elements before the Canvas3D (and the backgrounds of the elements holding it) are under the 3D, showing wherever it has nothing, and hidden by its parts; positioned elements after it are over it. The 3D's background is transparent. Put the Canvas3D straight in a full-frame AbsoluteFill. |
| `clearColor` | `string` | only with `layered`: the 3D clears to this CSS colour instead of transparent, so its translucent parts blend over it in linear light, as Bevy's do over its ClearColor (a Bevy 2D scene's rgb(43, 44, 47)), not over the page in sRGB. The 3D then lies under the whole page, as Bevy's camera output lies under all its UI (a GlobalZIndex(-1) too). |
| `children` | `ReactNode` | the 3D scene: cameras, lights and parts |

### `Capsule3dProps`

Bevy's Capsule3d: radius and half_length, the straight part's half (0.5 each by Bevy's default), standing up.

| Field | Type | What it is |
| --- | --- | --- |
| `radius` | `number` | metres (0.5) |
| `half_length` | `number` | half the straight part's length, metres (0.5) |
| `args` | `[number, number]` | [radius, length of the straight part] |

### `CapsuleProps`

| Field | Type | What it is |
| --- | --- | --- |
| `args` | `[number, number]` | [radius, length of the straight part] ([0.5, 1]) |

### `ComputeProps`

A compute shader (raea-sys-compute). Its source has one `@compute` entry point and reads `time()` (seconds),
`u_NAME()` for each uniform, each buffer as `NAME: array<f32>` (read and written) and each image as
`NAME: texture_storage_2d<rgba8unorm, write>`.

| Field | Type | What it is |
| --- | --- | --- |
| `file` | `string` | a shader file compiled as written, staticFile("shaders/x.wesl"), in place of wesl: its `@group(0)` storage textures and uniforms its own, as a Bevy example's render-graph node binds them |
| `entry` | `string \| null` | a file's entry point this frame (null or left out: nothing dispatched), as a node picks its pipeline |
| `bind` | `Record<string, string>` | a file's storage textures this frame, each an image's key ({ input: "a", output: "b" }), as a node picks its bind group (a ping-pong swaps them frame by frame) |
| `wesl` | `string` | the source in WESL (a superset of WGSL) |
| `wgsl` | `string` | the same in plain WGSL |
| `workgroups` (required) | `number[]` | how many workgroups a frame dispatches: [x], [x, y] or [x, y, z] |
| `uniforms` | `Record<string, number \| number[] \| string \| Record<string, number \| number[] \| string \|…` | up to 16, as a surface shader's; a file's struct field may be { start: NAME } or { end: NAME }: the range of the mesh buffer NAME binds in its slab, in its array's elements (compute_mesh's `range.start * 8`) |
| `buffers` | `Record<string, { size: number } \| number[] \| StorageValue \| MeshSlab>` | up to 4, the compute's own, kept from frame to frame: { size } (that many f32s, zeroed) or its first contents. A file's: each `var<storage>` it declares, its first contents in its type's layout or a mesh's slab |
| `images` | `Record<string, string \| { src: string; sampler?: SamplerSpec }>` | up to 4 "render:NAME" (or "render:NAME:WxH") images it writes, which any shader's texture reads by that name (a file's may be { src, sampler }: the sampler it is drawn with) |
| `defs` | `ShaderDefs` | shader defs, as a surface shader's |

### `ConeProps`

| Field | Type | What it is |
| --- | --- | --- |
| `args` | `[number, number]` | [radius, height] |
| `radius` | `number` | the base's radius, metres (0.5) |
| `height` | `number` | metres (1) |

### `CrtSettings`

How the tube draws the picture. Every value is optional; `crt={false}` on the Screen draws it flat and sharp.

| Field | Type | What it is |
| --- | --- | --- |
| `curvature` | `number` | barrel distortion, 0 (none) to about 0.3: a flat quad's stand-in for curved glass (a model's curved glass curves the picture already; 0 by default) |
| `scanlines` | `number` | how dark the gaps between scanlines are, 0 to 1 (0.55); they fade where they'd be finer than the frame's pixels |
| `mask` | `number` | how strongly the phosphor mask shows, 0 to 1 (0.35) |
| `maskKind` | `"aperture" \| "shadow" \| "none"` | "aperture" (a Trinitron's vertical stripes, the default), "shadow" (offset triads) or "none" |
| `maskSize` | `number` | mask triads per source pixel (1), or per line when `lines` is set |
| `lines` | `number` | the tube's own scanlines, top to bottom (0, the default: one per row of the picture). Set it when the picture is sharper than the tube: a 1440x1044 desktop on a 1702 monitor shows its scanlines and mask at `lines: 270`, where its own 1044 rows are finer than the frame's pixels and fade out |
| `glow` | `number` | the phosphor's halo around bright parts, 0 to 1 (0.35) |
| `convergence` | `number` | how far apart the beam's red and blue land, in source pixels, growing toward the edges (0.35) |
| `vignette` | `number` | the tube's edges and corners darkened, 0 to 1 (0.35) |
| `flicker` | `number` | brightness flicker and a faint rolling hum bar, seeded by the frame, 0 to 1 (0.04) |
| `brightness` | `number` | how strongly the picture glows (2.5 for a CRT, 1.4 flat): above 1 it blooms under a <Bloom> |
| `glass` | `string` | the dark tube's own colour, hex (a grey-green) |
| `reflect` | `number` | the glass's sheen toward grazing angles, 0 to 1 (0.5) |
| `smudge` | `number` | fingerprints, a wiped arc and dust specks on the glass, 0 (clean, the default) to 1: seen mostly in the sheen and as a faint lift of the dark glass, barely over the picture; the pattern is fixed per screen (seeded by its name), so it holds still from frame to frame. 0.3 is a lived-in set seen on a second look |
| `overscan` | `number` | the picture grown past the glass's edge, 0 to 0.3 (0) |

### `CuboidProps`

Bevy's Cuboid: half its size along each axis ([0.5, 0.5, 0.5], a 1 m cube, as Bevy's default).

| Field | Type | What it is |
| --- | --- | --- |
| `half_size` | `[number, number, number]` | half its size along x, y and z, metres ([0.5, 0.5, 0.5]) |

### `CylinderProps`

`args`, or Bevy's Cylinder fields: radius and half_height (0.5 each by Bevy's default).

| Field | Type | What it is |
| --- | --- | --- |
| `args` | `[number, number, number]` | [radius top, radius bottom, height], as three.js's args |
| `radius` | `number` | metres (0.5) |
| `half_height` | `number` | half its height, metres (0.5) |

### `DecalProps`

| Field | Type | What it is |
| --- | --- | --- |
| `src` (required) | `string` | the picture pressed onto the surface: staticFile("label.png"); its clear parts show the surface through |
| `name` | `string` | the entity's name, for picking, the inspector and world.* |
| `normalMap` | `string` | a normal map pressed with the picture: the label's relief |
| `size` | `number \| [number, number]` | width by height in metres (a number: a square) |
| `position` | `Vec3` | where it stands, metres (x, y, z) |
| `normal` | `Vec3` | which way the surface faces at the decal (out of it; [0, 1, 0], a floor or counter, by default): turns the decal so the picture lies on it, upright on a wall, its top toward -z on a floor. Instead of rotation |
| `spin` | `number` | a turn about the normal (radians) |
| `rotation` | `Vec3` | radians, the decal's +y out of the surface (rather than normal) |
| `color` | `string` | a tint times the picture (keyed: a stain darkening) |
| `opacity` | `number` | 0 to 1 (keyed: a label fading in) |
| `roughness` | `number` | 0..1, smooth to matte |
| `metalness` | `number` | 0..1, a dielectric to a metal |
| `unlit` | `boolean` | drawn in its flat colour, without light or shade |
| `fade` | `number` | how far off its plane (metres) it still lies on a surface, fading to nothing there (0.05 by default). Anything nearer the plane than this takes it, a cabinet's side or a fridge's as well as the wall: keep it small |

### `DepthCopyProps`

The props of [`DepthCopy`](#depthcopy), tabled there.

### `DepthOfFieldProps`

| Field | Type | What it is |
| --- | --- | --- |
| `aperture` | `number` | the lens's f-number: lower blurs more (1.4 dreamy, 2.8 cinematic, 8 nearly sharp); 2.8 by default |
| `mode` | `"bokeh" \| "gaussian"` | "bokeh" (round, as a real lens; the default) or "gaussian" (soft, cheaper) |
| `maxBlur` | `number` | the largest blur, in pixels of the frame (64 by default) |
| `focal_distance` | `number` | Bevy's fields, as Bevy's DepthOfField component on a Camera3d (inside it), Bevy's defaults: the distance in focus (10; the camera's `focus`), the f-number (1), the largest blur in pixels (64), "Bokeh" or "Gaussian" |
| `aperture_f_stops` | `number` | the f-number (1): lower is a shallower focus |
| `max_circle_of_confusion_diameter` | `number` | the largest blur, in px (64) |

### `EntityProps`

The props of [`Entity`](#entity), tabled there.

### `EnvironmentMapLightProps`

| Field | Type | What it is |
| --- | --- | --- |
| `diffuse_map` (required) | `string` | the prefiltered diffuse (irradiance) cubemap, a.ktx2 file: staticFile("environment_maps/pisa_diffuse_rgb9e5_zstd.ktx2") |
| `specular_map` (required) | `string` | the prefiltered specular (radiance) cubemap with its mips, a.ktx2 file |
| `intensity` | `number` | cd/m² (Bevy's default 1) |
| `rotation` | `[number, number, number, number]` | its turn, glam's Quat [x, y, z, w] (Bevy's identity): Quat.from_rotation_y(0.2 * t) turns it each frame |

### `EnvironmentProps`

| Field | Type | What it is |
| --- | --- | --- |
| `src` (required) | `string` | an equirectangular panorama in the media folder: a Radiance.hdr (Poly Haven's), an OpenEXR.exr, or an 8-bit.png/.jpg. Change it between frames to cut from one place to another |
| `intensity` | `number` | how strongly it lights the scene (1 by default: a sky about as bright as an AmbientLight of 2.5 overall); animate it, or set 0 to switch it off for a shot |
| `rotation` | `number` | a turn about the vertical axis, in radians, for both the light and the sky: puts the sun where the shot wants it |
| `background` | `boolean` | draw the panorama as the sky behind everything (off by default: light only) |
| `backgroundIntensity` | `number` | the sky's brightness, when it should differ from the light's (`intensity` by default) |

### `FireProps`

| Field | Type | What it is |
| --- | --- | --- |
| `name` | `string` | parts are matched by name across frames: name a fire that comes and goes |
| `position` | `Vec3` | the flame's foot: where it stands on its fuel |
| `scale` | `number \| Vec3` | its size in metres: one number for its height (it's half as wide), or [width, height, depth] (1 by default) |
| `intensity` | `number` | how bright its core is, as a material's emissiveIntensity (6 by default): 3 a guttering fire, 10-20 a roaring one in the dark. Values over 1 bloom under a <Bloom> |
| `color` | `string` | the flame's body (orange, "#ff7a1f", by default); its edges go deep red and its core yellow-white |
| `seed` | `number` | which flame: fires with different seeds don't flicker together (0 by default) |
| `speed` | `number` | how fast its tongues rise, 1 by default (a big fire's rise more slowly than a small one's on their own) |
| `time` | `number` | seconds on its clock (by default the Sequence's time: frame / fps) |
| `steps` | `number` | samples along each ray through it (48 by default): fewer is cheaper and blurrier |
| `opacity` | `number` | how much of what's behind it its body hides (1 by default): raise it (3-6) in daylight, where a bright wall behind would wash out a flame that only adds light |
| `light` | `number` | the light it casts on what's around it: a flickering PointLight's intensity (1 by default; 0 for none) |

### `FisheyeProps`

| Field | Type | What it is |
| --- | --- | --- |
| `strength` | `number` | 0..1 (1 by default): 0 is the camera's own picture, pixel for pixel; ramp it in and out on beats |
| `mode` | `"equidistant" \| "stereographic"` | "equidistant" (the default) or "stereographic" (gentler at the edges) |
| `fov` | `number` | the vertical field of view, in degrees, the camera widens to at strength 1 (its own by default): 100-150 for a real fisheye; the picture is still remapped corner to corner, so nothing goes black |
| `zoom` | `number` | above 1 crops in, below 1 shows past the picture's edge (see `edges`) |
| `edges` | `"clamp" \| "black"` | what shows where the lens looks past the picture: its edge pixels ("clamp", the default) or "black" |
| `animate` | `Animate3d` | declared animation of its numbers (strength, fov, k1, k2, zoom) |

### `FogColor`

a fog colour: "#rrggbb" (or #rrggbbaa), or Bevy's Srgba or LinearRgba (raea/color)

```ts
type FogColor = string | { red: number; green: number; blue: number; alpha: number }
```

### `FogFalloff`

bevy_pbr's FogFalloff as it reflects; FogFalloff's constructors (raea/pbr) make one from a visibility distance

```ts
type FogFalloff = | { Linear: { start: number; end: number } } | { Exponential: { density: number } } | { ExponentialSquared: { density: number } } | { Atmospheric: { extinction: [number, number, number]; inscattering: [number, number, number] } }
```

### `FogProps`

| Field | Type | What it is |
| --- | --- | --- |
| `color` | `FogColor` | what far things fade into: match the background |
| `near` | `number` | linear fog from `near` to `far` (in the Canvas3D 5 and 20 by default; on the camera Bevy's 0 and 100) |
| `far` | `number` | where linear fog is full, from the camera (20 in the Canvas3D, 100 on a camera) |
| `density` | `number` | or exponential fog of this density (0.05-0.3), instead of near and far |
| `falloff` | `FogFalloff` | on the camera: Bevy's FogFalloff, in place of near, far and density (Bevy's default Linear 0 to 100) |
| `directional_light_color` | `FogColor` | on the camera: the sun's colour in the fog looking towards it, its alpha its strength (Bevy's default none) |
| `directional_light_exponent` | `number` | on the camera: how tight the sun's glow is (Bevy's default 8) |

### `FogVolumeProps`

| Field | Type | What it is |
| --- | --- | --- |
| `name` | `string` | parts are matched by name across frames: name a volume that comes and goes |
| `position` | `Vec3` | the box's centre |
| `rotation` | `Vec3` | radians |
| `scale` | `number \| Vec3` | the box's size in metres: one number for a cube, or [x, y, z] (1 by default) |
| `density` | `number` | how thick the air is (0.1 by default: dusty; 0.02 a faint haze; 0.5 smoke). Animate it to let dust settle, smoke roll in or a volume vanish (0) |
| `color` | `string` | the fog's own colour, what light scattering out of it takes on (white by default; a dark red for blood in the air) |
| `absorption` | `number` | how much light it swallows (0.3 by default): higher reads as soot or smoke |
| `scattering` | `number` | how much light it throws back toward the eye (0.3 by default): higher reads as bright dust or mist |
| `anisotropy` | `number` | how far forward it scatters, -1 to 1 (0.5 by default): near 1 the shafts glow when you look toward the light |
| `falloff` | `number` | how fast it thins going up, per metre from the box's floor (0 by default: even throughout): 0.5 is a ground fog that's a third as thick two metres up. A box wide and tall with a falloff is height fog. Only <VolumetricFog mode="froxel"> draws it; the march draws the box evenly |
| `density_texture` | `string` | Bevy's density_texture: a 3D.ktx2 image in the media folder whose values scale the density through the box (a cloud, a bunny of smoke); the box draws evenly without one. Only the march draws it |

### `FramePassProps`

A shader over the whole frame. Its source defines
 fn shade(in: FullscreenVertexOutput) -> vec4<f32>
(or its own

| Field | Type | What it is |
| --- | --- | --- |
| `file` | `string` | a shader file compiled as written, staticFile("shaders/x.wesl"), in place of wesl: its `@group(0)` bindings its own, as custom_post_processing's pipeline binds them: each texture_2d<f32> the frame (the one `frame` names) or an image of `textures`, each sampler Bevy's default (nearest) or `samplers`' one, each var<uniform> its value in `uniforms` (which may change frame by frame) |
| `frame` | `string` | a file's texture that reads the frame as drawn so far |
| `entry` | `string` | a file's fragment entry point ("fragment" by default) |
| `samplers` | `Record<string, SamplerSpec>` | a file's samplers by name |
| `wesl` | `string` | the source in WESL (a superset of WGSL) |
| `wgsl` | `string` | the same in plain WGSL |
| `uniforms` | `Record<string, number \| number[] \| string \| StorageValue>` | up to 16, as a surface shader's (a file's: each var<uniform>, a struct's { field: value }) |
| `textures` | `Record<string, string \| Record<string, unknown>>` | up to 4, as a surface shader's, each read with its own sampler |
| `defs` | `ShaderDefs` | shader defs, as a surface shader's |
| `at` | `"before-tonemap" \| "after-tonemap"` | "after-tonemap" (display colours; the default) or "before-tonemap" (the HDR frame, after bloom) |
| `prepass` | `boolean \| { depth?: boolean; normal?: boolean }` | the camera's depth and normal prepasses, for depth(uv) and normal(uv) (turns its multisampling off) |

### `GBufferPassProps`

The props of [`GBufferPass`](#gbufferpass), tabled there.

### `GizmoColor`

a gizmo point's colour: "#rrggbb", linear [r, g, b, a], or Bevy's LinearRgba / Srgba (bevy3d's colours)

```ts
type GizmoColor = string | [number, number, number, number] | { red: number; green: number; blue: number; alpha?: number }
```

### `GizmoProps`

| Field | Type | What it is |
| --- | --- | --- |
| `lines` | `[Vec3, Vec3][]` | segments, each [from, to] |
| `strip` | `(Vec3 \| null)[]` | one line through these points (null breaks it) |
| `color` | `GizmoColor \| GizmoColor[]` | one colour for every point, or one per point of `lines` (two per segment) then `strip`: "#rrggbb", Bevy's LinearRgba (above 1 for HDR, as bevy_gizmos takes it) or Srgba, or linear [r, g, b, a] |
| `width` | `number` | line width in pixels (Bevy's default 2) |
| `depthBias` | `number` | -1 always in front of geometry, 0 depth-tested as it is (Bevy's GizmoLineConfig and depth_bias) |
| `position` | `Vec3` | where it stands, metres (x, y, z) |
| `rotation` | `Vec3` | its rotation, Euler angles in radians (x, y, z) |
| `scale` | `Vec3 \| number` | its scale: one number, or x, y and z |
| `name` | `string` | the entity's name, for picking, the inspector and world.* |

### `Glitch`

| Field | Type | What it is |
| --- | --- | --- |
| `explode` | `number` | triangles thrown out from the centre and turned (0 whole, 1 about the part's size away) |
| `scramble` | `number` | 0..1: that share of the vertices pulled to other vertices of the part (spikes across it) |
| `jitter` | `number` | metres of per-triangle noise |
| `snap` | `number` | metres: the vertices snapped to a grid that size |
| `smear` | `Vec3` | metres, world: the trailing side dragged back along it (motion smear) |
| `seed` | `number` | which randomness (change it on a beat for a new pattern) |

### `GlyphInfo`

What a glyph is, for a <RichText>'s `glyph` function.

| Field | Type | What it is |
| --- | --- | --- |
| `index` (required) | `number` | its place among the drawn glyphs (spaces aren't glyphs), from 0 |
| `count` (required) | `number` | how many glyphs the block has |
| `char` (required) | `string` | the character it draws |
| `word` (required) | `number` | its word's place among the words, from 0, and how many there are |
| `words` (required) | `number` | how many words the block has |
| `inWord` (required) | `number` | its place in its word, and the word's glyph count |
| `wordLength` (required) | `number` | how many glyphs its word has |
| `line` (required) | `number` | its line (by the newlines in the text), from 0 |
| `span` (required) | `number` | its run: the <Span> it's in (0 for text outside any, counted in order) |

### `GlyphStyle`

A glyph's motion this frame, about its own centre, in the block's space: added to (position, rotation),
multiplied into (scale, opacity) or replacing (color, visible) what the block's moves give it.

| Field | Type | What it is |
| --- | --- | --- |
| `position` | `Vec3` | metres, from its place in the block |
| `rotation` | `Vec3` | radians, XYZ |
| `scale` | `number \| Vec3` | multiplies its size: one number, or x, y and z |
| `color` | `string` | replaces its colour |
| `opacity` | `number` | multiplies its opacity, 0..1 |
| `visible` | `boolean` | false hides it this frame |

### `GooBake`

| Field | Type | What it is |
| --- | --- | --- |
| `file` (required) | `string` | the baked.rseq this goo plays |
| `stats` (required) | `{ objects?: { name: string; hideFrame: number }[]; [k: string]: unknown }` | what the bake measured, with each object's name and the frame its original model should go |

### `GooObject`

| Field | Type | What it is |
| --- | --- | --- |
| `name` (required) | `string` | the object's name; the bake's stats list it, with the frame its original model should go |
| `src` | `string` | a glTF's nodes (world space as they stand in it), moved by `transform` (column-major 4x4) if given; or, with no src, `cup` and `level`: a liquid filling one of the goo's cups to `level` metres above its foot |
| `nodes` | `string[]` | the glTF nodes it's made of (all of them when left out) |
| `cup` | `number` | with no src: the index of the cup in `cups` it fills |
| `level` | `number` | with no src: metres above the cup's foot it's filled to |
| `transform` | `number[]` | a column-major 4x4 that moves the glTF's nodes |
| `liquid` | `"water" \| "coffee" \| "tea" \| "milk" \| "juice" \| "oil" \| "syrup" \| "honey"` | sph: what it is ("water" by default: coffee, tea, milk, juice, oil, syrup, honey set its colour, density and viscosity), and where it comes from if not a cup or a glTF (filled): a box of it, or an emitter pouring a round stream from `at` along `dir` (down) at `speed` m/s, `radius` m (6 mm) across, from `start` to `end` seconds |
| `block` | `{ min: Vec3; max: Vec3 }` | sph: a box of liquid, world min and max corners |
| `emitter` | `{ at: Vec3; dir?: Vec3; radius?: number; speed?: number; start?: number; end?: number }` | sph: a round stream poured from `at` along `dir`, `radius` m across, at `speed` m/s, from `start` to `end` seconds |
| `start` (required) | `number` | seconds from the goo's start when it begins to soften, and how long until it runs (mpm) |
| `melt` | `number` | seconds from `start` until it runs (2) |
| `stiffness` | `number` | of the solid (3e4) and the fluid it becomes (4) |
| `viscosity` | `number` | how thick the fluid it becomes is (4) |
| `density` | `number` | its density, kg/m³ (1000) |
| `cohesion` | `number` | the share of its pressure it keeps under tension (0.6): goo holds together in strands, a liquid (0.02) barely |
| `residual` | `number` | the share of its shear stiffness a fluid keeps (0.12) and the strain it must pass to flow (0.005): 0 and 0 for a liquid |
| `yield` | `number` | the strain a fluid must pass to flow (0.005; 0 for a liquid) |
| `fill` | `"solid" \| "shell"` | "solid" fills its volume; "shell" a skin `thickness` thick (plates, petals) |
| `thickness` | `number` | with `fill: "shell"`: the skin's thickness, metres |
| `color` | `string` | its goo's colour (else its texture's) |

### `GooProps`

The props of [`Goo`](#goo), tabled there.

### `GradeProps`

| Field | Type | What it is |
| --- | --- | --- |
| `temperature` | `number` | warmer (+) or cooler (-): a shift of the CIE x chromaticity, about -0.3 to 0.3 |
| `tint` | `number` | magenta (+) or green (-) |
| `saturation` | `number` | the whole frame's saturation after tone mapping (1 keeps it) |
| `shadows` | `GradeSection` | the grade on the shadows: saturation, contrast, gamma, gain, lift |
| `midtones` | `GradeSection` | the grade on the midtones |
| `highlights` | `GradeSection` | the grade on the highlights |
| `vignette` | `number \| { intensity?: number; radius?: number; smoothness?: number; color?: string }` | the corners darkened: 0 none, 1 black; or {intensity, radius (0.75), smoothness (5), color} |
| `aberration` | `number` | a lens's colour fringes at edges, as a fraction of the frame (0.005 subtle, 0.02 strong) |
| `skip` | `string[]` | composition passes (a part's `pass`) the grade leaves as drawn: no fringes or vignette on them, and on an untonemapped camera (a paint Look's) no colour grading either |
| `passes` | `Record<string, number>` | each named pass's share of the grade, 0 (as skip) to 1 |

### `GradeSection`

| Field | Type | What it is |
| --- | --- | --- |
| `saturation` | `number` | 1 keeps the colour; 0 grey; above 1 richer |
| `contrast` | `number` | 1 keeps it; above 1 harder |
| `gamma` | `number` | 1 keeps it; above 1 darker mids |
| `gain` | `number` | a multiplier: 1 keeps it |
| `lift` | `number` | added: 0 keeps it, positive lifts the blacks |

### `GrassLod`

One step of detail: tiles nearer than `to` metres draw `keep` of their clumps (0 to 1), each with its first
`blades` blades in `segments` segments, `widen` times as wide.

| Field | Type | What it is |
| --- | --- | --- |
| `to` (required) | `number` | tiles nearer than this many metres take this step |
| `keep` (required) | `number` | the share of their clumps they draw, 0 to 1 |
| `blades` (required) | `number` | how many of each clump's blades they draw |
| `segments` (required) | `number` | segments each blade is drawn in |
| `widen` (required) | `number` | how many times as wide each blade is drawn, to fill in for the ones left out |

### `GrassProps`

The props of [`Grass`](#grass), tabled there.

### `Hit`

| Field | Type | What it is |
| --- | --- | --- |
| `name` (required) | `string` | the pickable it hit |
| `distance` (required) | `number` | metres from the camera (from its near plane's point, for an orthographic one) along the ray |
| `point` (required) | `Vec3` | where the ray first meets it, in world space |

### `ImagePlaneProps`

| Field | Type | What it is |
| --- | --- | --- |
| `src` (required) | `string` | a picture in the media folder: staticFile("poster.png") |
| `name` | `string` | the entity's name, for picking and the inspector |
| `width` | `number` | width in scene units (1 by default); height follows the picture unless given |
| `height` | `number` | in scene units (follows the picture's shape by default) |
| `position` | `Vec3` | where its centre stands, metres (x, y, z) |
| `rotation` | `Vec3` | radians |
| `scale` | `number \| Vec3` | one number, or x, y and z |
| `quaternion` | `[number, number, number, number]` | a turn as a quaternion [x, y, z, w], instead of `rotation` (a card turned to face a point) |
| `shadow` | `boolean` | false: the card casts no shadow (a cursor or a UI floating in the scene); true by default |
| `cutout` | `boolean` | the picture cut out at half alpha instead of blended: its clear parts are no surface at all (no fog on them, no sorting) and its shadow is the picture's shape, not the card's. For hard-edged pictures: a baked cloud, a sprite |
| `grid` | `[number, number]` | a sprite sheet: the picture is `[columns, rows]` frames of equal size, read left to right, top to bottom, and the card shows one cell (its height follows one cell's shape). A texture atlas of a regular grid |
| `frame` | `number` | with `grid`: which cell shows (0 is the top left; whole numbers, wrapping); animate it to play the sheet, as Bevy's TextureAtlas index does: frame={Math.floor(f / 3)} |

### `Impulse`

| Field | Type | What it is |
| --- | --- | --- |
| `t` (required) | `number` | seconds from the simulation's start |
| `impulse` | `Vec3` | N·s, world |
| `at` | `Vec3` | where it's applied (world, metres): off the centre it spins the body too |
| `torque` | `Vec3` | an angular impulse, N·m·s, world |

### `Instance`

One copy's placement in an <Instances>, in the Instances' own space (its position, rotation and scale move every
copy together). Rotation in radians, XYZ order, as everywhere.

| Field | Type | What it is |
| --- | --- | --- |
| `position` (required) | `Vec3` | where this copy stands, metres, in the Instances' space |
| `rotation` | `Vec3` | its rotation, Euler angles in radians (x, y, z) |
| `scale` | `number \| Vec3` | its scale: one number, or x, y and z |

### `InstancesProps`

| Field | Type | What it is |
| --- | --- | --- |
| `src` | `string` | a glTF file drawn at every placement: staticFile("models/house.glb"). Without it, a geometry child (or `shape`) and a material child draw a mesh at every placement |
| `at` (required) | `Instance[]` | where each copy stands. Fixed for the shot: the first frame's list is drawn on every frame (move, turn, scale, hide or recolour the whole set by the Instances' own props) |
| `name` | `string` | the entity's name, for picking, the inspector and world.* |
| `position` | `Vec3` | where it stands, metres (x, y, z) |
| `rotation` | `Vec3` | radians |
| `scale` | `number \| Vec3` | its scale: one number, or x, y and z |
| `scene` | `number` | of a glTF: which of its scenes (0 by default) |
| `shape` | `string \| Solid` | a Manifold solid or its expression for the mesh form; wins over the geometry child |
| `shadow` | `boolean` | false: the copies cast no shadow (true by default). Grass and flowers by the thousand usually want false |
| `receiveShadow` | `boolean` | false: no shadow falls on the copies |
| `pass` | `string` | the composition pass it draws in ("scene" by default) |
| `children` | `ReactNode` | the mesh form: a geometry and a material (MeshStandardMaterial, MeshPhysicalMaterial or MeshBasicMaterial). The glTF form: MeshStandardMaterial children re-covering its materials, as on a Model |

### `Layout`

```ts
type Layout = Record<string, Placed> & { readonly found: PlaceFinding[]; readonly errors: number }
```

### `LensCommon`

| Field | Type | What it is |
| --- | --- | --- |
| `edges` | `"clamp" \| "black"` | what shows where the lens looks past the picture: its edge pixels ("clamp", the default) or "black" |
| `animate` | `Animate3d` | declared animation of its numbers (strength, fov, k1, k2, zoom) |

### `LensDistortionProps`

| Field | Type | What it is |
| --- | --- | --- |
| `k1` | `number` | Brown-Conrady: r' = r (1 + k1 r^2 + k2 r^4), r a share of the half-diagonal. Above 0 barrel, below 0 pincushion |
| `k2` | `number` | the r^4 term of the distortion |
| `zoom` | `number` | by default just enough for a barrel's corners to stay inside the picture (1 for pincushion) |
| `edges` | `"clamp" \| "black"` | what shows where the lens looks past the picture: its edge pixels ("clamp", the default) or "black" |
| `animate` | `Animate3d` | declared animation of its numbers (strength, fov, k1, k2, zoom) |

### `LoftOutline`

```ts
type LoftOutline = string | [number, number][]
```

### `LookPass`

One composition pass's own paint (<Look passes>): the frame's rag, grain and palette, and its surfaces' bands, torn
shadow edge, strokes, saturation and wash; what it leaves out is the Look's.

| Field | Type | What it is |
| --- | --- | --- |
| `rag` | `number` | how far its edges wander, px (the Look's by default) |
| `grain` | `number` | its paper grain, 0 to 1 |
| `palette` | `boolean` | false: its pixels aren't snapped to the palette |
| `bands` | `number` | how many flat tones the light makes on its surfaces, 1-8 |
| `edge` | `number` | how far its cast shadows' edges tear, 0 to 0.5 |
| `stroke` | `number` | brush strokes on its surfaces, 0 to 1 |
| `saturate` | `number` | its colour past (above 1) or toward grey (below 1) its own |
| `wash` | `number` | its textures' colour taken as their patch average, 0 to 1 |

### `LookProps`

### `MatchmoveCamera`

| Field | Type | What it is |
| --- | --- | --- |
| `t` (required) | `number` | seconds into the clip |
| `position` (required) | `Vec3` | where the camera is, in the solved world (metres) |
| `quaternion` (required) | `[number, number, number, number]` | camera to world, [x, y, z, w]; the camera looks down its -Z with +Y up |
| `solved` (required) | `boolean` | false: COLMAP didn't register this frame and its pose was interpolated |

### `MatchmoveProps`

| Field | Type | What it is |
| --- | --- | --- |
| `src` (required) | `string` | the footage: staticFile("clip.mp4") |
| `from` | `number` | where in the clip the shot starts, and how long it runs (seconds; 0 = to the end) |
| `seconds` | `number` | how long the shot runs, seconds (0: to the clip's end) |
| `subject` | `[number, number, number, number]` | the subject to keep in front of the 3D and out of the solve: a box around it on the first frame, [x, y, w, h] in 0..1 of the frame (EdgeTAM tracks it from there) |
| `height` | `number` | the camera's height over the ground in metres (1.6 by default: handheld) |
| `fov` | `number` | the vertical field of view in degrees, for a shot without parallax (a tripod, a pan); a solve with structure finds its own |
| `smooth` | `number` | frames of smoothing on the solved path (1 by default; 0 for none) |
| `solve` | `MatchmoveSolve` | a solve to draw from instead of solving (`raea track CLIP -o solve.json`, imported) |
| `crop` | `number \| [number, number]` | when the frame's shape isn't the footage's (9:16 from 16:9), where the frame sits across it: 0 its left edge, 1 its right, 0.5 the middle (the default); [x, y] for both axes. It may change from frame to frame |
| `zoom` | `number` | 1 or more: a tighter window on the footage (a punch-in), still locked |
| `cutout` | `boolean` | draw the subject's cut-out over the 3D (true by default when there's a subject) |
| `toneMapping` | `"none" \| "tony" \| "aces" \| "agx" \| "neutral" \| "reinhard"` | the scene's tone mapping: "none" by default, which leaves the footage's colours as they are |
| `children` | `ReactNode` | the 3D that stands in the shot, in the solved world |

### `MatchmoveSolve`

What `raea track` writes and <Matchmove> draws from.

| Field | Type | What it is |
| --- | --- | --- |
| `mode` (required) | `"sfm" \| "rotation" \| "static"` | "sfm": a full solve with structure; "rotation": the camera only turns (too little parallax, or too few frames registered); "static": it doesn't move |
| `width` (required) | `number` | the footage's size in pixels, and its frame rate |
| `height` (required) | `number` | the footage's height in pixels |
| `fps` (required) | `number` | the footage's frame rate |
| `from` (required) | `number` | where in the clip the solve starts, seconds |
| `seconds` (required) | `number` | how long it runs, seconds |
| `frames` (required) | `number` | how many frames it solved |
| `fov` (required) | `number` | vertical field of view, degrees; focal length in pixels; the lens's radial distortion |
| `focal` (required) | `number` | the focal length in pixels, at the footage's full size |
| `k1` (required) | `number` | the lens's radial distortion |
| `registered` (required) | `number` | how many frames COLMAP registered; the rest were interpolated |
| `error` (required) | `number \| null` | mean reprojection error in pixels (null without structure) |
| `camera_height` (required) | `number` | the camera's height over the ground, metres, that set the world's scale |
| `cameras` (required) | `MatchmoveCamera[]` | the camera a frame |
| `points` (required) | `Vec3[]` | the sparse points, in the solved world |
| `ground` (required) | `{ y: number; normal: Vec3 }` | the ground plane: its height (0) and normal (+Y) |
| `cut` (required) | `string \| null` | the subject's cut-outs, a path with %04d for the frame (1-based), or null |
| `notes` (required) | `string[]` | what the solver noticed: fallbacks, an assumed field of view, interpolated frames |

### `MatchmoveState`

Each frame's state under a <Matchmove>, for the 3D inside it.

| Field | Type | What it is |
| --- | --- | --- |
| `solve` (required) | `MatchmoveSolve` | the solve it draws from |
| `index` (required) | `number` | the solve's frame shown now (0-based), and the clip's time |
| `time` (required) | `number` | the clip's time at this frame, seconds |
| `camera` (required) | `MatchmoveCamera` | the solve's camera for this frame |
| `project` (required) | `(p: Vec3) => [number, number, number]` | where a point of the solved world lands in the composition, in pixels ([x, y], and its distance in front of the camera; behind it when that's 0 or less) |

### `MeshAttribute`

One attribute's values on a mesh: one a vertex, each a number or a list of the format's size.

```ts
type MeshAttribute = [MeshVertexAttribute, (number | number[])[]]
```

### `MeshPassProps`

The props of [`MeshPass`](#meshpass), tabled there.

### `MeshSequenceProps`

| Field | Type | What it is |
| --- | --- | --- |
| `name` | `string` | the entity's name, for picking and the inspector |
| `src` (required) | `string` | a.rseq (tools/goo writes them; raea_render::meshseq) |
| `frame` (required) | `number` | which of its frames (clamped) |
| `position` | `Vec3` | where it stands, metres (x, y, z) |
| `rotation` | `Vec3` | its rotation, Euler angles in radians (x, y, z) |
| `scale` | `number` | a uniform scale |
| `color` | `string` | multiplies the vertex colours |
| `roughness` | `number` | 0..1, smooth to matte |
| `metalness` | `number` | 0..1, a dielectric to a metal |
| `clearcoat` | `number` | 0..1 strength of a clear varnish layer over the surface |
| `clearcoatRoughness` | `number` | 0..1 roughness of that clear layer |
| `reflectance` | `number` | 0..1 specular strength at normal incidence (0.5: 4%, a dielectric's) |
| `subsurface` | `number` | 0..1 light let through (diffuse transmission): a jelly's glow |
| `thickness` | `number` | how thick the mesh is, metres, for the light let through |
| `transmission` | `number` | 0..1 light let straight through and bent (a clear liquid: water, tea, juice), with its index of refraction (1.33 water) and, for a tinted one, the colour it takes after `attenuationDistance` metres through it. Screen space: it refracts what's on screen behind it, and one clear layer doesn't show another through it |
| `ior` | `number` | the index of refraction of what light passes through (1.33 water) |
| `attenuationColor` | `string` | the colour light takes after `attenuationDistance` metres through it |
| `attenuationDistance` | `number` | metres through it until light has taken `attenuationColor` |
| `opacity` | `number` | 0..1, see-through to solid |
| `map` | `string` | a picture over its texture coordinates |
| `doubleSided` | `boolean` | draw the back faces too (an open shell, a petal) |

### `MeshShaderPassProps`

The props of [`MeshShaderPass`](#meshshaderpass), tabled there.

### `MeshSlab`

A mesh's vertex or index buffer in Bevy's MeshAllocator, bound as a file's storage buffer (array<f32 | u32 | i32>)
for its compute to write (shader_advanced/compute_mesh): the mesh the part named `mesh` holds, a <BufferMesh> with
indices and normals (position, normal and uv interleaved, 8 floats a vertex).

Bevy: `bevy_render::mesh::allocator::MeshBufferSlice`.

| Field | Type | What it is |
| --- | --- | --- |
| `mesh` (required) | `string` | the mesh's name |
| `slab` (required) | `"vertices" \| "indices"` | which of its buffers: vertices or indices |

### `ModelProps`

The props of [`Model`](#model), tabled there.

### `ModelScreens`

A Model's `screens` prop: each material's screen, as a <Screen> element (its props and children) or a bare
composition element (a <Screen> of the defaults around it).

```ts
type ModelScreens = Record<string, ReactElement>
```

### `MotionBlurProps`

| Field | Type | What it is |
| --- | --- | --- |
| `shutterAngle` | `number` | the fraction of a frame the shutter is open (0.5 by default, a 180-degree shutter); above 1 smears further |
| `samples` | `number` | samples each way per pixel (4 by default) |
| `animate` | `Animate3d` | declared animation of its numbers |

### `OutlineProps`

| Field | Type | What it is |
| --- | --- | --- |
| `color` | `string` | the line's colour, a hex colour (black by default) |
| `depth` | `number` | a silhouette: how far behind the nearer surface (a fraction of its distance) a neighbour must be (0.04) |
| `normal` | `number` | a crease: how far the surface must turn between neighbours, 1 - cos of the angle (0.3, about 45 degrees; 0 for none) |
| `width` | `number` | the line's width in pixels (1 by default; a cartoon's line is about 6) |
| `far` | `number` | how far from the camera lines reach, in metres: they fade out over its last third, so a far field meeting the sky draws no line along the horizon (no limit by default) |
| `skip` | `string[]` | composition passes (a part's `pass`) drawn with no line: none on their pixels and no crease against them (a scene object's silhouette in front of one still draws, on the object) |

### `PartInfo`

| Field | Type | What it is |
| --- | --- | --- |
| `file` (required) | `string` | the part's own.glb in the asset store |
| `centre` (required) | `Vec3` | the middle of its bounds, metres, where it stands in the source file |
| `lo` (required) | `Vec3` | its bounds' low corner |
| `hi` (required) | `Vec3` | its bounds' high corner |
| `tris` (required) | `number` | how many triangles it has |

### `PartMaterial`

| Field | Type | What it is |
| --- | --- | --- |
| `missing` | `boolean` | the magenta-and-black checker of a texture that didn't load |
| `color` | `string` | a colour over its own |
| `emissive` | `string` | the colour it glows with |
| `opacity` | `number` | 0..1, see-through to solid |
| `roughness` | `number` | 0..1, smooth to matte |
| `unlit` | `boolean` | drawn in its flat colour, without light or shade |

### `PartProps`

The props of [`Part`](#part), tabled there.

### `PhaseAttribute`

A vertex attribute: Bevy's VertexFormat by name, its byte offset in a vertex and its shader

| Field | Type | What it is |
| --- | --- | --- |
| `format` (required) | `"Float32" \| "Float32x2" \| "Float32x3" \| "Float32x4" \| "Uint32" \| "Uint32x2" \| "Uint32x3…` | the attribute's VertexFormat, by name |
| `offset` (required) | `number` | its byte offset in a vertex |
| `location` (required) | `number` | its shader |

### `PhaseItemProps`

The props of [`PhaseItem`](#phaseitem), tabled there.

### `PhysicsProps`

The props of [`Physics`](#physics), tabled there.

### `Pickable`

Something the pointer can hit: an axis-aligned box or a sphere, in world space.

```ts
type Pickable = { name: string; box: { min: Vec3; max: Vec3 } } | { name: string; sphere: { center: Vec3; radius: number } }
```

### `PickCamera`

The camera as a scene sets it: a PerspectiveCamera's props (fov in degrees, vertical) or an OrthographicCamera's.

| Field | Type | What it is |
| --- | --- | --- |
| `position` | `Vec3` | where it stands, metres (x, y, z) |
| `lookAt` | `Vec3` | the point it faces |
| `fov` | `number` | vertical field of view in degrees (50 by default); ignored when `height` is set |
| `height` | `number` | an orthographic camera's view height in metres |
| `up` | `Vec3` | which way is up for it (+Y) |

### `Place2dProps`

Where a 2D part is: composition px from the frame's top left, y down (as the page's), its centre there; and its
pointer and drag handlers, called as a 3D part's are (2D parts are picked first, the top one by z).

| Field | Type | What it is |
| --- | --- | --- |
| `name` | `string` | the entity's name, for picking, the inspector and world.* |
| `x` | `number` | px from the frame's left edge to the part's centre |
| `y` | `number` | px from the frame's top edge to the part's centre, down positive |
| `rotation` | `number` | radians, clockwise (as CSS rotate) |
| `quat` | `Quat` | Bevy's rotation as it is, a quaternion [x, y, z, w] in Bevy's axes (y up, z toward the viewer), in place of `rotation`: a turn out of the frame's plane too, as a Sprite's Transform takes it (camera/2d_on_ui) |
| `scale` | `number \| [number, number]` | 1 by default; [x, y] to stretch |
| `z` | `number` | draw order among the 2D parts: higher draws over lower (0 by default) |
| `opacity` | `number` | 0 to 1 (1 by default) |
| `onClick` | `(e: Event3d) => void` | a press and release over the part |
| `onPointerDown` | `(e: Event3d) => void` | a button pressed over the part |
| `onPointerUp` | `(e: Event3d) => void` | a button released over the part |
| `onPointerOver` | `(e: Event3d) => void` | the pointer came over the part (bubbles, as the DOM's) |
| `onPointerOut` | `(e: Event3d) => void` | the pointer left the part (bubbles) |
| `onPointerEnter` | `(e: Event3d) => void` | the pointer came over the part (doesn't bubble) |
| `onPointerLeave` | `(e: Event3d) => void` | the pointer left the part (doesn't bubble) |
| `onPointerMove` | `(e: Event3d) => void` | the pointer moved over the part |
| `onWheel` | `(e: Event3d) => void` | the wheel turned over the part (`deltaX`, `deltaY`) |
| `onDragStart` | `(e: Event3d) => void` | a drag began on the part pressed |
| `onDrag` | `(e: Event3d) => void` | the part pressed is being dragged, each frame it moves |
| `onDragEnd` | `(e: Event3d) => void` | the drag of the part pressed ended |
| `onDragEnter` | `(e: Event3d) => void` | a dragged part came over this one (`dragged` names it) |
| `onDragOver` | `(e: Event3d) => void` | a dragged part is over this one |
| `onDragLeave` | `(e: Event3d) => void` | a dragged part left this one |
| `onDrop` | `(e: Event3d) => void` | a dragged part was dropped on this one |

### `Placed`

| Field | Type | What it is |
| --- | --- | --- |
| `base` (required) | `V3` | the centre of its bottom face |
| `center` (required) | `V3` | its middle, where a centred Cuboid goes |
| `yaw` (required) | `number` | its turn about y, radians (its front is +z before the turn) |
| `size` (required) | `V3` | its width, height and depth, metres |

### `PlaceFinding`

| Field | Type | What it is |
| --- | --- | --- |
| `part` (required) | `string` | the object it's about |
| `check` (required) | `string` | the rule that couldn't hold |
| `level` (required) | `string` | "ok", or how bad it is ("error" when the rule broke) |
| `says` (required) | `string` | what's wrong, in words |

### `PlaceObject`

| Field | Type | What it is |
| --- | --- | --- |
| `size` (required) | `V3` | its width, height and depth, metres |
| `at` | `V3` | a start (or, with fixed, the place) for its bottom centre |
| `yaw` | `number` | degrees |
| `fixed` | `boolean` | it stays at `at`: the rules move the others round it |

### `PlaceRule`

```ts
type PlaceRule = | { on: string; of: string } | { against: string; wall: Side } | { beside: string; of: string; side: Side; gap?: number } | { near: string; of: string; dist?: number } | { apart: string; of: string; min?: number } | { facing: string; of: string } | { align: string; of: string; axis: "x" | "z" } |…
```

### `PlanBox`

A box on the plan (x, z, metres): the room SDK's Footprint, or any { min, max }.

| Field | Type | What it is |
| --- | --- | --- |
| `min` (required) | `[number, number]` | the low corner (x, z), metres |
| `max` (required) | `[number, number]` | the high corner (x, z), metres |

### `Plane3dProps`

Bevy's Plane3d: a flat rectangle facing `normal` (Bevy's default +Y, a floor), `half_size` its half extent along
its two axes ([0.5, 0.5]), laid out as Bevy's PlaneMeshBuilder does: facing +Z it is a Plane of args
[2 x half_size]. The normal is along an axis; a tilted plane is a rotated Mesh3d.

| Field | Type | What it is |
| --- | --- | --- |
| `normal` | `Vec3` | the way it faces, along an axis (+Y by default, a floor) |
| `half_size` | `[number, number]` | half its extent along its two axes, metres ([0.5, 0.5]) |

### `PlateProps`

| Field | Type | What it is |
| --- | --- | --- |
| `src` (required) | `string` | a video in the media folder: staticFile("clip.mp4") |
| `name` | `string` | the entity's name, for picking, the inspector and world.* |
| `time` | `number` | the clip's time on this frame, in seconds (by default the Sequence's: frame / fps) |
| `k1` | `number` | the lens's radial distortion (SIMPLE_RADIAL's k1, from a solve): the plate is drawn undistorted, so the footage's straight lines are straight where the 3D's are |

### `Polygons`

A 2D outline: contours of [x, y] points (counter-clockwise for solid, clockwise for a hole).

```ts
type Polygons = [number, number][][]
```

### `RichTextProps`

| Field | Type | What it is |
| --- | --- | --- |
| `name` | `string` | what it's called across frames, and its glyphs' names over world.* (`${name}:${index}`) |
| `pass` | `string` | the composition pass it draws in ("scene" by default): a frame-wide effect told to skip a pass (<Look skip>, <Outline skip>, <Bloom skip>, <Grade skip>) leaves its pixels as drawn, and <Look passes> gives one its own paint; a piece names at most three passes besides "scene"; keyed per frame |
| `position` | `Vec3` | where the block's origin is, metres (x, y, z) |
| `rotation` | `Vec3` | the block's rotation, radians (x, y, z) |
| `scale` | `number \| Vec3` | the block's scale: one number, or x, y and z |
| `size` | `number` | the em in metres (0.5 by default) |
| `font` | `string` | a family (raea's bundled faces: Inter by default, Montserrat, Oswald, Playfair Display...; or one on this machine) |
| `weight` | `number` | 100..900 (700 by default) |
| `italic` | `boolean` | slanted (false by default) |
| `color` | `string` | each glyph's colour unless its <Span> gives one |
| `align` | `"left" \| "center" \| "right"` | where the origin is: the left edge, the middle (default) or the right edge of the lines; the block's middle vertically |
| `lineHeight` | `number` | times the em (1.2 by default) |
| `maxWidth` | `number` | wrapped at this width in metres (no wrapping by default) |
| `roughness` | `number` | 0..1, smooth to matte |
| `metalness` | `number` | 0..1, a dielectric to a metal |
| `emissive` | `string` | the colour it glows with |
| `emissiveIntensity` | `number` | how strongly it glows (1 by default; 2-10 with bloom) |
| `unlit` | `boolean` | drawn in its flat colour, without light or shade |
| `castShadow` | `boolean` | letter-shaped shadows (true by default) |
| `receiveShadow` | `boolean` | other things' shadows fall on it |
| `layers` | `number[]` | the render layers it's on ([0] by default): a camera draws only the layers it's given |
| `enter` | `MoveLike` | each glyph's (or word's) entrance: a move's name, a move or several (rise, pop, slam, slide, fade... the 2D ones, their px read at 100 an em, their degrees as degrees), `each` frames apart from `at` |
| `each` | `number` | frames between one glyph's (or word's) entrance and the next (2 by default) |
| `by` | `"letter" \| "word"` | the entrance and exit staggered by letter (default) or by word |
| `at` | `number` | the local frame the first entrance starts (0) |
| `exit` | `MoveLike` | each glyph's (or word's) exit: a move or its name, played backwards from `exitAt` |
| `exitAt` | `number` | the local frame the first exit starts; an exit needs it |
| `exitEach` | `number` | frames between exits (0: together) |
| `reveal` | `number` | how many glyphs are shown, a typewriter's count: the next one fades in over its fraction |
| `glyph` | `(g: GlyphInfo) => GlyphStyle` | each glyph's own motion this frame, from anything the frame gives (useCurrentFrame, spring, interpolate) |
| `children` | `ReactNode` | the text: strings and <Span> runs |

### `SamplerSpec`

How a texture is read (Bevy's ImageSamplerDescriptor; raea-sys-sampler). Each part is optional, over
the texture's own default. A texture file loaded with two samplers is drawn with the last (the load says so).

| Field | Type | What it is |
| --- | --- | --- |
| `filter` | `"nearest" \| "linear"` | "nearest": hard pixels; "linear": smoothed (a material map's default) |
| `mipmap` | `"nearest" \| "linear" \| "none"` | between mip levels; "none" reads the full-size texture only |
| `wrap` | `SamplerWrap \| [SamplerWrap, SamplerWrap]` | past the edge: one mode, or [u, v] |
| `anisotropy` | `number` | 1 to 16 (a map's default is 16); needs every filter linear, so nearest turns it off |

### `SamplerWrap`

```ts
type SamplerWrap = "repeat" | "clamp" | "mirror"
```

### `ScatterOptions`

| Field | Type | What it is |
| --- | --- | --- |
| `area` (required) | `PlanBox` | where the points fall: a box on the plan (x, z) |
| `count` (required) | `number` | how many (fewer when the area fills up: spacing and avoid leave no room) |
| `spacing` | `number` | the least distance between two points, metres (0: none) |
| `avoid` | `PlanBox[]` | boxes on the plan to keep clear of, grown by `margin` |
| `margin` | `number` | how far to stay off each avoided box (spacing / 2 by default) |
| `clearOf` | `Instance[]` | points kept off already-placed ones too: a second scatter (flowers) clear of the first (stones) by `spacing` |
| `seed` | `number` | 1 by default; the same seed gives the same points, every frame, render and play |
| `yaw` | `boolean \| number \| [number, number]` | each point's turn about y (radians): true (the default) any, false none, a number that one, [lo, hi] between |
| `tilt` | `number` | a lean off upright, radians: each point tipped by up to this much in a random direction (0 by default) |
| `scale` | `number \| [number, number]` | a scale, or [lo, hi] between (uniform) |
| `y` | `number \| ((x: number, z: number) => number)` | the ground's height: a number (0), or the terrain's height at (x, z) |
| `density` | `(x: number, z: number) => number` | how likely a point is kept at (x, z), 0 to 1: a density map (a path worn bare, a patch thicker by the chair) |

### `SceneProps`

The props of [`Scene`](#scene), tabled there.

### `ScreenProps`

The props of [`Screen`](#screen), tabled there.

### `ScreenSource`

| Field | Type | What it is |
| --- | --- | --- |
| `resolution` | `[number, number]` | the picture's size in pixels, [width, height] ([320, 200]); the nested composition lays out at it |
| `crt` | `boolean \| CrtSettings` | draw it as a CRT (true, the default; or its settings) or flat (false: an LCD) |
| `power` | `number` | the tube's power, 0 (off) to 1 (on, the default): animate it to switch the set on, a line opening to the picture |
| `from` | `number` | the frame of this Sequence the nested composition's frame 0 falls on (0) |
| `background` | `string` | behind the picture ("#000000"). A see-through one ("#ffffff00", "transparent", rgba(..., 0.5)) makes the screen see-through where its page paints nothing, so what's behind it in the scene shows (a flat screen: a layer of a page pulled apart in 3D); an opaque one keeps the screen opaque, which writes depth for DepthOfField |
| `brightness` | `number` | a flat screen's (`crt={false}`) light: 1, the default, draws its page at the page's own colours, unlit (scene lights don't touch it); above 1 it glows, and blooms under a <Bloom>. A tone curve on the camera bends it like the rest of the frame: give the scene <ToneMapping mode="none" /> to keep the page's colours exact. A CRT's is `crt.brightness` |
| `src` | `string` | a video to show instead of children: staticFile("clip.mp4"), filling the picture |
| `app` | `string` | an app to show instead of children: a module's path from the composition's folder ("chat.tsx"), its default export a React component given {width, height}. It runs on real react-dom in a document of its own, so npm's React libraries work on it (assistant-ui, Radix; installed with `raea add`). In play the pointer reaches it through the 3D, where it lands on the picture, and a press on it gives it the keys (the game doesn't get them) until a press elsewhere or Escape; in a render it runs on the frame's clock, so the render repeats |
| `children` | `ReactNode` | the nested composition or game |

### `Section`

A cross-section of a solid at a height: its area, how many contours, and the contours themselves.

| Field | Type | What it is |
| --- | --- | --- |
| `area` (required) | `number` | the section's area, m² |
| `contours` (required) | `number` | how many outlines it has |
| `polygons` (required) | `[number, number][][]` | the outlines, each a list of [x, y] points in the section's plane |

### `ShaderInstancesProps`

The props of [`ShaderInstances`](#shaderinstances), tabled there.

### `ShaderMeshProps`

| Field | Type | What it is |
| --- | --- | --- |
| `shape` (required) | `string \| ({ primitive: string } & Record<string, unknown>)` | its geometry: a Manifold shape ("box(1, 1, 1)") or one of Bevy's primitives ({ primitive: "Sphere", radius: 1 }) |
| `wesl` | `string` | WESL (Bevy 0.20's standard; give this or `wgsl`): a `fn shade(in: VertexOutput) -> vec4<f32>` (in.uv, in.world_position, in.world_normal), or a module with its own |
| `wgsl` | `string` | the same in plain WGSL (compiled as WESL, its superset: Bevy 0.20 has no naga_oil, so no `#import`) |
| `uniforms` | `Record<string, number \| number[] \| string>` | up to 16: a number (f32), [x, y], [x, y, z], [x, y, z, w] or "#rrggbb" (a linear vec4) |
| `textures` | `Record<string, string \| Record<string, unknown>>` | up to 4: an asset path, a picture made in code ({ width, height, pixels }) or "render:NAME"; and one array, { layers: [picture,...] } or { src, layers: N }, read as texture_2d_array<f32> tex_NAME by layer |
| `defs` | `ShaderDefs` | shader defs: each NAME a WESL condition for `@if(NAME)`, and a whole number also `constants::NAME` |
| `alpha` | `"opaque" \| "blend" \| "add" \| "premultiplied"` | how it blends: opaque, blend, add or premultiplied |
| `doubleSided` | `boolean` | draw the back faces too |
| `name` | `string` | the entity's name, for picking, the inspector and world.* |
| `position` | `Vec3` | where it stands, metres (x, y, z) |
| `rotation` | `Vec3` | its rotation, Euler angles in radians (x, y, z) |
| `scale` | `Vec3 \| number` | its scale: one number, or x, y and z |

### `ShadowsProps`

| Field | Type | What it is |
| --- | --- | --- |
| `mapSize` | `1024 \| 2048 \| 4096 \| 8192` | each shadow map's size in texels (4096 by default; 8192 is sharper still, at four times the memory and about 2-3 ms a frame at 1080p) |
| `distance` | `number` | how far from the camera the sun's shadows reach, in metres (150 by default): the shorter, the sharper they are |
| `firstCascade` | `number` | where the sun's first, sharpest cascade ends, in metres (8 by default): the distance of the nearest subject |
| `cascades` | `number` | how many cascades split the distance (4 by default, 1-4) |
| `overlap` | `number` | how much neighbouring cascades overlap, 0-1 (0.3 by default) so the seam between them doesn't show |
| `bias` | `number` | depth bias: raise it if surfaces facing the light show stripes of their own shadow (acne); too high and shadows detach from what casts them (0.02 by default for the sun, as Bevy's) |
| `normalBias` | `number` | normal bias, in texels: the same trade-off along the surface's normal (1.8 by default for the sun) |
| `filter` | `"gaussian" \| "hardware"` | "gaussian" (the default: soft, smooth edges) or "hardware" (2x2, crisper and cheaper) |

### `Shape`

```ts
type Shape = "hull" | "box" | "mesh" | { box: Vec3 } | { sphere: number } | { capsule: [number, number] }
```

### `Shape2DProps`

| Field | Type | What it is |
| --- | --- | --- |
| `shape` | `"rect" \| "circle" \| "ellipse" \| "triangle" \| "polygon"` | a rect by default; a polygon has `sides` (5 by default) |
| `size` | `[number, number]` | [width, height] in px ([100, 100] by default); a circle's and a polygon's diameter is the width |
| `sides` | `number` | a polygon's number of sides (5) |
| `color` | `string` | a CSS colour (white by default); with a texture, it tints it |
| `srgb` | `[number, number, number]` | the colour as a Bevy Srgba's [r, g, b], unrounded, over `color` (a Mesh2d's ColorMaterial gives it) |
| `texture` | `string \| { path: string; sampler: SamplerSpec }` | a picture on it, mapped by the mesh's UVs (Bevy's ColorMaterial texture), or one with its own sampler (Bevy's load_with_settings: { path, sampler: { wrap: "repeat" } }) |
| `uv_transform` | `{ scale: [number, number]; angle: number; translation: [number, number] }` | the texture's UVs scaled, turned and moved (ColorMaterial's uv_transform, glam's Affine2 as raea/transform's) |
| `alpha_mode` | `AlphaMode2d` | Bevy's AlphaMode2d: "Blend" (Bevy's default), "Opaque", or { Mask: cutoff } |
| `vertex_colors` | `[number, number, number, number][]` | one linear [r, g, b, a] per vertex of the shape's mesh (Bevy's Mesh::ATTRIBUTE_COLOR): the material's colour and texture are multiplied by them. A rect has 4 (top right, top left, bottom left, bottom right), a triangle 3. |
| `shader` | `Record<string, unknown>` | its own Material2d in place of the ColorMaterial: the spec a <Material> in a Mesh2d makes; the shape's colour, texture and alpha_mode are then the material's to draw |
| `primitive` | `Record<string, unknown>` | one of Bevy's 2D primitives in place of `shape`, its reflected fields over Bevy's default: { primitive: "Capsule2d", radius: 25, half_length: 25 }; a 2D shape given `inner` (the same shape's fields) is Bevy's Ring, or given `ring: thickness` its to_ring (raea-sys-mesh primitive_mesh). A Mesh2d's primitive child makes it. |
| `name` | `string` | the entity's name, for picking, the inspector and world.* |
| `x` | `number` | px from the frame's left edge to the part's centre |
| `y` | `number` | px from the frame's top edge to the part's centre, down positive |
| `rotation` | `number` | radians, clockwise (as CSS rotate) |
| `quat` | `Quat` | Bevy's rotation as it is, a quaternion [x, y, z, w] in Bevy's axes (y up, z toward the viewer), in place of `rotation`: a turn out of the frame's plane too, as a Sprite's Transform takes it (camera/2d_on_ui) |
| `scale` | `number \| [number, number]` | 1 by default; [x, y] to stretch |
| `z` | `number` | draw order among the 2D parts: higher draws over lower (0 by default) |
| `opacity` | `number` | 0 to 1 (1 by default) |
| `onClick` | `(e: Event3d) => void` | a press and release over the part |
| `onPointerDown` | `(e: Event3d) => void` | a button pressed over the part |
| `onPointerUp` | `(e: Event3d) => void` | a button released over the part |
| `onPointerOver` | `(e: Event3d) => void` | the pointer came over the part (bubbles, as the DOM's) |
| `onPointerOut` | `(e: Event3d) => void` | the pointer left the part (bubbles) |
| `onPointerEnter` | `(e: Event3d) => void` | the pointer came over the part (doesn't bubble) |
| `onPointerLeave` | `(e: Event3d) => void` | the pointer left the part (doesn't bubble) |
| `onPointerMove` | `(e: Event3d) => void` | the pointer moved over the part |
| `onWheel` | `(e: Event3d) => void` | the wheel turned over the part (`deltaX`, `deltaY`) |
| `onDragStart` | `(e: Event3d) => void` | a drag began on the part pressed |
| `onDrag` | `(e: Event3d) => void` | the part pressed is being dragged, each frame it moves |
| `onDragEnd` | `(e: Event3d) => void` | the drag of the part pressed ended |
| `onDragEnter` | `(e: Event3d) => void` | a dragged part came over this one (`dragged` names it) |
| `onDragOver` | `(e: Event3d) => void` | a dragged part is over this one |
| `onDragLeave` | `(e: Event3d) => void` | a dragged part left this one |
| `onDrop` | `(e: Event3d) => void` | a dragged part was dropped on this one |

### `SkyboxProps`

| Field | Type | What it is |
| --- | --- | --- |
| `image` (required) | `string` | the sky's cubemap, a.ktx2 file (Bevy's examples use the specular map: environment_maps/pisa_specular_rgb9e5_zstd.ktx2) |
| `brightness` | `number` | cd/m² (Bevy's default 0, a black sky: Bevy's examples give it 1000 to 5000) |
| `rotation` | `[number, number, number, number]` | its turn, glam's Quat [x, y, z, w] (Bevy's identity) |

### `SpanProps`

| Field | Type | What it is |
| --- | --- | --- |
| `children` | `ReactNode` | the run's text |
| `font` | `string` | a family (raea's bundled faces: Inter, Montserrat, Oswald, Playfair Display...; or one on this machine) |
| `weight` | `number` | 100..900 (the block's by default) |
| `italic` | `boolean` | slanted (the block's by default) |
| `size` | `number` | times the block's size |
| `color` | `string` | the run's colour (the block's by default) |

### `SphereProps`

`args`, or Bevy's Sphere field: radius (0.5 by Bevy's default). Its mesh is Bevy's Sphere::mesh(): an icosphere of 5
subdivisions, or `ico` of them (Bevy's `.ico(n)`, 0 to 80), or a UV sphere of `uv` = [sectors, stacks] (`.uv(s, t)`).

| Field | Type | What it is |
| --- | --- | --- |
| `args` | `[number]` | [radius], as three.js's args |
| `radius` | `number` | metres (0.5) |
| `ico` | `number` | an icosphere of this many subdivisions (5 by default; 0 to 80) |
| `uv` | `[number, number]` | a UV sphere instead: [sectors, stacks] |

### `SplatMorph`

| Field | Type | What it is |
| --- | --- | --- |
| `to` (required) | `string` | the splat file it becomes |
| `amount` (required) | `number` | 0 this splat, 1 the other (each splat flies to the one matched to it) |
| `crop` | `number` | only the other's splats this many metres from its centre (a trained scene's subject without its surroundings) |

### `SplatProps`

| Field | Type | What it is |
| --- | --- | --- |
| `name` | `string` | parts are matched by name across frames: name a splat that comes and goes |
| `src` (required) | `string` | the splat file (staticFile("x.ply")): a 3DGS.ply (spherical harmonics up to degree 3), a.splat or a.spz. A `x.ply.json` beside it (raea splat train writes one) places it: +Y up, centred, metres |
| `position` | `Vec3` | where it stands, metres (x, y, z) |
| `rotation` | `Vec3` | radians, Euler XYZ |
| `scale` | `number \| Vec3` | its scale: one number, or x, y and z |
| `splatScale` | `number` | every gaussian's size times this (1 by default): below 1 the scene breaks into points |
| `opacity` | `number` | 0..1, multiplying every gaussian's |
| `brightness` | `number` | grade: colour times brightness, saturation and contrast about mid grey, times tint |
| `saturation` | `number` | 1 as trained; 0 grey, above 1 richer |
| `contrast` | `number` | 1 as trained; about mid grey |
| `tint` | `string` | a colour every gaussian's is multiplied by |
| `reveal` | `number` | reveal 0..1: each splat scales in as a front passes it, from `revealFrom` (a point; the centre by default) outward, or along `revealAxis` (a plane sweeping through) when that's given |
| `revealFrom` | `Vec3` | the point the reveal grows outward from (the centre by default) |
| `revealAxis` | `Vec3` | a direction: the reveal sweeps a plane along it instead of growing from a point |
| `revealSoft` | `number` | how wide the front is, as a share of the sweep (0.15) |
| `revealGlow` | `number` | the front's glow (0 none, 1 bright), in `glowColor` |
| `glowColor` | `string` | the colour of reveal and pulse glows (warm white) |
| `disperse` | `number` | disperse 0..1: blown off on a curl-noise wind, the upwind side first, shrinking to specks |
| `assemble` | `number` | assemble 0..1: from a cloud of dust round the scene into its shape (1 whole) |
| `wind` | `Vec3` | the wind's direction ([1, 0.15, 0]) |
| `curl` | `number` | how much the wind curls (1) |
| `spread` | `number` | the dust cloud's radius in metres (the splat's own size, before scale; 1.6 times its size by default) |
| `explode` | `number` | explode 0..1: thrown out from the centre, falling and fading |
| `wave` | `SplatWave` | a ripple running out through the splats: amplitude, wavelength and phase |
| `twist` | `number` | radians a metre about the vertical through the centre |
| `morph` | `SplatMorph` | becomes another splat file: `to` and `amount` 0..1 |
| `pulse` | `number` | a value the composition passes (a beat's envelope 0..1): bigger by pulseScale, brighter by pulseGlow |
| `pulseScale` | `number` | how much bigger a full pulse makes it |
| `pulseGlow` | `number` | how much brighter a full pulse makes it |
| `crop` | `number` | nothing past this many metres from the centre (trims a trained scene's floaters) |
| `bands` | `number` | the light in this many flat bands (0 none); a paint or cartoon <Look> sets it |
| `paint` | `number` | 0..1: the splats themselves painted (flat bands, grown into strokes with hard edges), for a painted shot in a timeline whose frame <Look> isn't paint |
| `seed` | `number` | which randomness: the scatter, the jitter (0) |

### `SplatWave`

| Field | Type | What it is |
| --- | --- | --- |
| `amplitude` (required) | `number` | how high the ripple lifts the splats, metres |
| `wavelength` | `number` | from crest to crest, metres (1 by default) |
| `phase` | `number` | where the ripple is in its cycle, radians: animate it (frame * 0.2) to run it outward |

### `SpriteProps`

| Field | Type | What it is |
| --- | --- | --- |
| `src` (required) | `string` | a picture in the media folder: staticFile("hero.png"), or a "render:NAME" image a camera or a <Compute> draws (a frame may switch it to another by name) |
| `width` | `number` | size in px (the picture's, or one cell's, by default); one given, the other follows the picture's shape |
| `height` | `number` | in px; given alone, the width follows the picture's shape |
| `grid` | `[number, number]` | a sprite sheet: the picture is `[columns, rows]` cells of equal size, read left to right, top to bottom |
| `atlasPick` | `number` | one picture of a built atlas (TextureAtlasBuilder's sources.handle gives it with its src): its index in the atlas's list |
| `frame` | `number` | with `grid`: which cell shows (0 is the top left); animate it to play the sheet: frame={Math.floor(f / 3)} |
| `flipX` | `boolean` | mirrored left to right |
| `flipY` | `boolean` | mirrored top to bottom |
| `color` | `string` | a tint multiplied over the picture (white by default) |
| `tileX` | `boolean` | Bevy's SpriteImageMode::Tiled: the picture repeats across the sprite's width (tileX) or height (tileY) instead of stretching to it, a tile every `tileStretch` x the picture's size (1 by default): a floor, a fence, a wall. Animate width and height to show more or fewer tiles |
| `tileY` | `boolean` | tile the picture down its height instead of stretching it |
| `tileStretch` | `number` | a tile every this many times the picture's size (1) |
| `image_mode` | `SpriteImageMode` | Bevy's SpriteImageMode, as its reflected value: "Auto" (stretched to the size), { Scale: "FillCenter" } (and FillStart, FillEnd, FitCenter, FitStart, FitEnd: the picture kept to its shape, cropped or fitted), { Sliced: TextureSlicer } (nine-slice: border a number of px or { min_inset: [x, y], max_inset: [x, y] }; center_scale_mode and sides_scale_mode "Stretch" or { Tile: { stretch_value } }; max_corner_scale) or { Tiled: { tile_x, tile_y, stretch_value } }. Not with tileX or tileY |
| `sampler` | `SamplerSpec` | the picture's sampler (Bevy's load_with_settings: { filter, mipmap, wrap, anisotropy }), Bevy's default (linear) otherwise; { filter: "nearest" } is pixel art as Bevy's ImagePlugin::default_nearest() draws it |
| `children` | `ReactNode` | your own <Material> as its child: Bevy's SpriteMaterial, extending the sprite's own material (the shader reads the sprite's picture, tint and alpha with bevy_sprite_render::sprite_mesh::functions), its uniforms per frame |
| `name` | `string` | the entity's name, for picking, the inspector and world.* |
| `x` | `number` | px from the frame's left edge to the part's centre |
| `y` | `number` | px from the frame's top edge to the part's centre, down positive |
| `rotation` | `number` | radians, clockwise (as CSS rotate) |
| `quat` | `Quat` | Bevy's rotation as it is, a quaternion [x, y, z, w] in Bevy's axes (y up, z toward the viewer), in place of `rotation`: a turn out of the frame's plane too, as a Sprite's Transform takes it (camera/2d_on_ui) |
| `scale` | `number \| [number, number]` | 1 by default; [x, y] to stretch |
| `z` | `number` | draw order among the 2D parts: higher draws over lower (0 by default) |
| `opacity` | `number` | 0 to 1 (1 by default) |
| `onClick` | `(e: Event3d) => void` | a press and release over the part |
| `onPointerDown` | `(e: Event3d) => void` | a button pressed over the part |
| `onPointerUp` | `(e: Event3d) => void` | a button released over the part |
| `onPointerOver` | `(e: Event3d) => void` | the pointer came over the part (bubbles, as the DOM's) |
| `onPointerOut` | `(e: Event3d) => void` | the pointer left the part (bubbles) |
| `onPointerEnter` | `(e: Event3d) => void` | the pointer came over the part (doesn't bubble) |
| `onPointerLeave` | `(e: Event3d) => void` | the pointer left the part (doesn't bubble) |
| `onPointerMove` | `(e: Event3d) => void` | the pointer moved over the part |
| `onWheel` | `(e: Event3d) => void` | the wheel turned over the part (`deltaX`, `deltaY`) |
| `onDragStart` | `(e: Event3d) => void` | a drag began on the part pressed |
| `onDrag` | `(e: Event3d) => void` | the part pressed is being dragged, each frame it moves |
| `onDragEnd` | `(e: Event3d) => void` | the drag of the part pressed ended |
| `onDragEnter` | `(e: Event3d) => void` | a dragged part came over this one (`dragged` names it) |
| `onDragOver` | `(e: Event3d) => void` | a dragged part is over this one |
| `onDragLeave` | `(e: Event3d) => void` | a dragged part left this one |
| `onDrop` | `(e: Event3d) => void` | a dragged part was dropped on this one |

### `SurfaceDrawProps`

How a surface's alpha and faces draw (Bevy's StandardMaterial alpha_mode, alpha cutoff, double_sided and cull_mode),
from the first frame.

| Field | Type | What it is |
| --- | --- | --- |
| `alphaMode` | `"opaque" \| "blend" \| "mask" \| "add" \| "multiply" \| "premultiplied" \| "coverage"` | "opaque" (the default), "blend" (what `transparent` gives), "mask" (cut out where the alpha is under `alphaCutoff`: leaves, chain-link, a sprite's edge; no sorting), "add" (glows add up: sparks, light beams), "multiply" (darkens what's behind: stained glass, a shadow decal), "premultiplied", "coverage" (soft cut-out edges from the alpha over MSAA's samples: hair cards, foliage; needs <AntiAliasing mode="msaa">, without it draws solid) |
| `alphaCutoff` | `number` | with alphaMode="mask": the alpha under which it's cut away, 0..1 (0.5) |
| `side` | `"front" \| "back" \| "double"` | which faces draw: "front" (the default), "back" (the inside only: a sky dome, a room seen from outside), "double" (both, lit on both: a leaf, a flag, a sheet of paper) |

### `SurfaceShaderSpec`

| Field | Type | What it is |
| --- | --- | --- |
| `wesl` | `string` | the source in WESL (Bevy 0.20's shader language, a superset of WGSL) |
| `wgsl` | `string` | the same in plain WGSL |
| `fragment` | `string` | the source as an asset path (staticFile("shaders/x.wesl")), as Bevy's MaterialExtension::fragment_shader names one: read as written but for its own bindings' numbers (any, in the order declared: one uniform struct, which gets its uniforms packed in its layout, up to 4 texture_2d and their one sampler; one under |
| `uniforms` | `Record<string, number \| number[] \| string>` | up to 16: a number (f32), [x, y], [x, y, z], [x, y, z, w] or "#rrggbb" (a linear vec4) |
| `textures` | `Record<string, ShaderTexture \| ShaderTexture[]>` | up to 4: an asset path, a picture made in code ({ width, height, pixels }) or "render:NAME"; with a sampler, { src, sampler } (or a picture with its `sampler`). One more may be an array, read as texture_2d_array<f32> by layer: { layers: [picture,...] } (one size and format) or { src, layers: N } (N layers stacked top to bottom). A <Material>'s may also bind one binding_array<texture_2d<f32>>, a list of 1 to 16 pictures (Bevy's texture_binding_array; a GPU without texture binding arrays refuses it) |
| `defs` | `ShaderDefs` | shader defs: each NAME a WESL condition for `@if(NAME)` (a number is true), and a whole number also `constants::NAME`; each set of defs compiles its own pipeline |
| `own` | `OwnMaterialFields` | a <Material>'s own: what its Material methods give, and its storage buffers; set by <Material> only |
| `buffers` | `Record<string, StorageValue>` | the material's storage buffers by binding name; set by <Material> only |

### `Text3DProps`

| Field | Type | What it is |
| --- | --- | --- |
| `children` | `string` | the words, extruded |
| `text` | `string` | the words, when they aren't its child (no quotes or backslashes) |
| `size` | `number` | letter height in scene units (default 0.5) |
| `depth` | `number` | extrusion depth (default 0.2) |
| `font` | `string` | a family (Inter by default, or another of raea's bundled faces) |
| `weight` | `number` | 100..900 (800 by default) |

### `ThreeShaderMaterialProps`

| Field | Type | What it is |
| --- | --- | --- |
| `glsl` | `{ vertex: string; fragment: string; raw?: boolean; vertexColors?: boolean }` | a ShaderMaterial's GLSL, its `#include`s expanded and its `defines` as #define lines in front; `raw` for a RawShaderMaterial (which declares three's built-ins itself), `vertexColors` as the material's |
| `wgsl` | `{ vertex: string; fragment: string; uniforms?: { name: string; type: string; array?: nu…` | a node material's WGSL, as three's TSL builder writes it for raea (sdk/r3f's input/tsl.ts): the contract's `three_vertex` and `three_fragment`, its uniforms' types, the mesh attributes it reads beyond the standard four |
| `uniforms` | `Record<string, ThreeUniform>` | each uniform's value this frame |
| `textures` | `Record<string, string \| { src: string; colorSpace?: "srgb" \| "linear"; sampler?: Record…` | each sampler's picture: a file, a data URL, "render:NAME" (at most four); `colorSpace: "linear"` for one three samples raw (NoColorSpace: a distance field, a data map), "srgb" (the default) for a colour picture |
| `output` | `"display" \| "linear"` | "display": its colour is what three's canvas shows (a ShaderMaterial's); "linear": scene light, tone-mapped as the rest of the frame is (a node material's) |
| `transparent` | `boolean` | blended over what's behind it, as three's \`transparent\` |
| `blending` | `"normal" \| "additive" \| "add" \| "multiply" \| "none"` | how it blends: normal, additive (add), multiply or none |
| `side` | `"front" \| "back" \| "double"` | which faces draw: front, back or double |
| `depthWrite` | `boolean` | it writes the depth buffer |
| `depthTest` | `boolean` | it's hidden behind what's nearer |
| `alphaTest` | `number` | pixels less opaque than this are dropped |
| `time` | `[number, number, number]` | three's clock this frame: [seconds, delta, frame] |
| `color` | `string` | the colour it's drawn in where its shader can't run (named in the render's warnings) |

### `ThreeUniform`

A uniform's value: a number, a boolean, or its numbers in order (a vector's, a matrix's column by column as three's
`elements`, an array's elements one after another)

```ts
type ThreeUniform = number | boolean | number[]
```

### `ToneMappingProps`

| Field | Type | What it is |
| --- | --- | --- |
| `mode` | `"tony" \| "aces" \| "agx" \| "neutral" \| "reinhard" \| "none"` | how bright light maps to the screen: "tony" (Bevy's default), "aces" (filmic, contrasty), "agx", "neutral", "reinhard", "none" |
| `exposure` | `number` | stops brighter (+) or darker (-) than the default exposure |

### `ToonBand`

| Field | Type | What it is |
| --- | --- | --- |
| `at` (required) | `number` | where the band starts, as r: the share of the light reaching a point that it faces (0 faces none of it, 1 faces every light); the first band starts at 0 whatever this says |
| `color` | `string` | the band's colour; left out, it's mixed (in Oklab) between the shadow colour and `color` by its place |

### `ToonHighlight`

| Field | Type | What it is |
| --- | --- | --- |
| `intensity` | `number` | 0..1 (1 by default) |
| `color` | `string` | "#ffffff" by default |
| `size` | `number` | 0..1: the highlight's angular radius, up to half a radian (0.2 by default) |

### `ToonOutline`

| Field | Type | What it is |
| --- | --- | --- |
| `width` | `number` | pixels at the composition's size, the same near and far (2 by default) |
| `color` | `string` | ink colour; by default the surface colour's hue, very dark |

### `ToonRim`

| Field | Type | What it is |
| --- | --- | --- |
| `intensity` | `number` | 0..1, how much the rim colour covers the band (1 by default) |
| `color` | `string` | "#ffffff" by default |
| `width` | `number` | 0..1 of the Fresnel range from the silhouette inwards (0.3 by default) |

### `TorusProps`

`args`, or Bevy's Torus fields: major_radius (0.75) and minor_radius (0.25), the tube's.

| Field | Type | What it is |
| --- | --- | --- |
| `args` | `[number, number]` | [major radius, minor radius] |
| `major_radius` | `number` | from the centre to the middle of the tube, metres (0.75) |
| `minor_radius` | `number` | the tube's radius, metres (0.25) |

### `TreeOptions`

| Field | Type | What it is |
| --- | --- | --- |
| `height` | `number` | metres (6) |
| `trunk` | `number` | the clear trunk below the crown, a share of the height (0.35) |
| `width` | `number` | the crown's width over its height (0.9) |
| `crown` | `"dome" \| "sphere" \| "cone" \| "column" \| "umbrella" \| "vase"` | the crown's shape: dome (an oak), sphere, cone (a pine), column (a cypress), umbrella or vase |
| `points` | `number` | attraction points: more is a denser, twiggier crown (1200) |
| `step` | `number` | a growth step, a share of the height (0.03) |
| `base` | `number` | the trunk's radius at the ground (a fortieth of the height) |
| `tip` | `number` | the outer twigs' radius (0.006) |
| `tropism` | `number` | branches turn up (+) or droop (-) as they grow (0.15) |
| `leaves` | `number` | leaves per outer twig node (3; 0 is bare) |
| `leaf` | `number` | a leaf's length (0.09) |
| `sides` | `number` | sides of each branch's tube (7; 3 to 24) |
| `seed` | `number` | which randomness it uses: the same seed gives the same result |

### `Vec3`

```ts
type Vec3 = [number, number, number]
```

### `VertexFormat`

A vertex attribute's format, as Bevy's VertexFormat names it.

```ts
type VertexFormat = "Float32" | "Float32x2" | "Float32x3" | "Float32x4" | "Uint32" | "Uint32x2" | "Uint32x3" | "Uint32x4" | "Sint32" | "Sint32x4"
```

### `VolumeCommon`

| Field | Type | What it is |
| --- | --- | --- |
| `name` | `string` | parts are matched by name across frames |
| `time` | `number` | seconds on the simulation's clock (the Sequence's time, frame / fps, by default) |
| `resolution` | `number` | cells along the box's longest side (64 by default; 32 is a quarter the cost a step, 96 finer) |
| `seed` | `number` | the same seed simulates the same volume (0) |
| `colors` | `[string, string, string]` | its tones under a paint look: [lit, mid, dark] |
| `threshold` | `number` | the density its painted surface sits at (0.12): lower is fatter, higher thinner |
| `erode` | `number` | how much noise tears the painted surface's edge (0.08), and the tears' size in metres (0.6) |
| `erodeSize` | `number` | the tears' size in metres (0.6) |
| `absorb` | `number` | how much light a unit of it stops (its shadow on itself; 1.2) |
| `wind` | `Vec3` | the wind, m/s ([0, 0, 0]); how fast the volume takes it up, a second (1.2 smoke, 0.6 otherwise); the height it's full from, metres, weaker below (0: full everywhere) |
| `windPull` | `number` | how fast the volume takes up the wind, a second (1.2 smoke, 0.6 otherwise) |
| `windHeight` | `number` | the height the wind is full from, metres; weaker below (0: full everywhere) |
| `drag` | `number` | velocity the still air takes away a second (0.4) |
| `vorticity` | `number` | curl kept curling (6); a drifting turbulent force, m/s² (0), and its size in metres (2) |
| `turbulence` | `number` | a drifting turbulent force, m/s² (0) |
| `turbulenceSize` | `number` | the turbulence's size in metres (2) |
| `steps` | `number` | samples along each ray (96) |
| `shadow` | `boolean \| number` | its shadow, cast in the scene's light as a mesh's is (on by default): soft moving shadows on the ground, meshes and models under it, and, with a `volumetric` sun and a <FogVolume> under <VolumetricFog>, the sun's shafts breaking through the gaps between clouds. The shadow is where the volume has stopped half the sun; a number scales the density it sees: 1 as drawn, more reaches into its thinner parts (a fatter shadow; up to 4, a thin contrail's made to show), less keeps to the dense cores. false or 0 casts none. Under a paint look the shadow is the painted shape. Soften its edge with the sun's `softShadow` (2-4 for clouds) |

### `VolumeProps`

| Field | Type | What it is |
| --- | --- | --- |
| `position` | `Vec3` | the box's foot (the centre of its floor), metres ([0, 0, 0]) |
| `size` (required) | `Vec3` | the box it lives in, [width, height, depth] in metres: what leaves it is cut |
| `sources` | `VolumeSource[]` | where density and heat come in over time, and the puffs of density it starts with ([x, y, z, radius] in metres from the foot) |
| `puffs` | `[number, number, number, number][]` | density it starts with: [x, y, z, radius] in metres from the foot |
| `buoyancy` | `number` | heat's lift (4) and the density's weight (0.4), m/s² a unit; the heat lost a second (0.8) and the density lost a second (0.02), fractions |
| `weight` | `number` | the density's weight, m/s² a unit (0.4) |
| `cooling` | `number` | the heat lost a second, a fraction (0.8) |
| `dissipation` | `number` | the density lost a second, a fraction (0.02) |
| `fire` | `[string, string, string] \| false` | fire where it's hot: three colours [red, orange, yellow] (paint's by default), or false for none; and the heat (a fraction of the hottest source's) each colour starts at ([0.35, 0.6, 0.85]) |
| `fireAt` | `[number, number, number]` | the heat (a fraction of the hottest source's) each fire colour starts at ([0.35, 0.6, 0.85]) |
| `name` | `string` | parts are matched by name across frames |
| `time` | `number` | seconds on the simulation's clock (the Sequence's time, frame / fps, by default) |
| `resolution` | `number` | cells along the box's longest side (64 by default; 32 is a quarter the cost a step, 96 finer) |
| `seed` | `number` | the same seed simulates the same volume (0) |
| `colors` | `[string, string, string]` | its tones under a paint look: [lit, mid, dark] |
| `threshold` | `number` | the density its painted surface sits at (0.12): lower is fatter, higher thinner |
| `erode` | `number` | how much noise tears the painted surface's edge (0.08), and the tears' size in metres (0.6) |
| `erodeSize` | `number` | the tears' size in metres (0.6) |
| `absorb` | `number` | how much light a unit of it stops (its shadow on itself; 1.2) |
| `wind` | `Vec3` | the wind, m/s ([0, 0, 0]); how fast the volume takes it up, a second (1.2 smoke, 0.6 otherwise); the height it's full from, metres, weaker below (0: full everywhere) |
| `windPull` | `number` | how fast the volume takes up the wind, a second (1.2 smoke, 0.6 otherwise) |
| `windHeight` | `number` | the height the wind is full from, metres; weaker below (0: full everywhere) |
| `drag` | `number` | velocity the still air takes away a second (0.4) |
| `vorticity` | `number` | curl kept curling (6); a drifting turbulent force, m/s² (0), and its size in metres (2) |
| `turbulence` | `number` | a drifting turbulent force, m/s² (0) |
| `turbulenceSize` | `number` | the turbulence's size in metres (2) |
| `steps` | `number` | samples along each ray (96) |
| `shadow` | `boolean \| number` | its shadow, cast in the scene's light as a mesh's is (on by default): soft moving shadows on the ground, meshes and models under it, and, with a `volumetric` sun and a <FogVolume> under <VolumetricFog>, the sun's shafts breaking through the gaps between clouds. The shadow is where the volume has stopped half the sun; a number scales the density it sees: 1 as drawn, more reaches into its thinner parts (a fatter shadow; up to 4, a thin contrail's made to show), less keeps to the dense cores. false or 0 casts none. Under a paint look the shadow is the painted shape. Soften its edge with the sun's `softShadow` (2-4 for clouds) |

### `VolumeSource`

where density and heat come in: a burner, or an engine moving `at` -> `to` (a contrail)

| Field | Type | What it is |
| --- | --- | --- |
| `at` (required) | `Vec3` | where (metres from the box's foot), and where it has moved to by `until` if it moves |
| `to` | `Vec3` | where a moving source has got to by `until` |
| `from` | `number` | when it puts out, seconds ([0, Infinity]) |
| `until` | `number` | when it stops putting out, seconds (Infinity) |
| `radius` | `number` | its radius (0.5 m); the density and heat it puts out a second at its centre (4 and 4); the velocity it pushes out with, m/s ([0, 0, 0]) |
| `rate` | `number` | the density it puts out a second at its centre (4) |
| `heat` | `number` | the heat it puts out a second at its centre (4) |
| `speed` | `Vec3` | the velocity it pushes out with, m/s ([0, 0, 0]) |

### `VolumetricFogProps`

| Field | Type | What it is |
| --- | --- | --- |
| `steps` | `number` | mode="march": samples along each ray through a fog volume (64 by default): too few stair-step a shaft's edges, so 128 for a render with hard-edged shafts, or 32 with `dither`; about 0.1 ms a step at 1920x1080 on an M5 Pro |
| `dither` | `boolean` | mode="march": start each pixel's march a fraction of a step in, by a fixed noise seeded from the pixel and the frame number (false by default): the shafts' steps become fine grain instead of bands, so fewer steps look smooth. The noise is a function of the frame, so a render still equals its play |
| `resolution` | `number` | mode="march": the fraction of the frame's resolution the fog is marched at (1 by default): 0.5 marches a quarter of the pixels and puts the result over the frame guided by depth, so an edge in front of a shaft keeps no fog from what's behind it. 0.5, 1/3 or 0.25; each frame on its own, so a render still equals its play |
| `ambient` | `number` | light the fog has everywhere, lit or not (0 by default). Bevy lights a volume's whole box with it whatever its density, so the box's edges show: keep it 0, or small with the camera inside the volume |
| `ambientColor` | `string` | that light's colour (white by default) |
| `mode` | `"march" \| "froxel"` | how the fog is drawn: "froxel" (the default: every volume written into one grid of cells along the view, lit once a cell and integrated front to back once, with the `hero` lights' shafts integrated exactly along epipolar lines: no steps, no dither, its cost the grid's whatever the resolution or the number of volumes, overlapping volumes mixed as one medium, see-through surfaces fogged at their own depth) or "march" (Bevy's ray march through each volume, as before). `steps`, `dither` and `resolution` are the march's; `slices`, `tile`, `samples` and `hero` the grid's |
| `slices` | `number` | the grid's cells along the view, spaced evenly in log depth from the camera to the farthest volume (64 by default; 32 to 256) |
| `tile` | `number` | the grid's cells across the frame, in pixels a side (16 by default; 4, 8 or 16) |
| `samples` | `number` | points lit in each cell, spread along its depth (1 by default; 1 to 8): more keeps thin shadows in the grid's soft light (a hero light's shafts don't need them) |
| `hero` | `boolean` | the grid's shafts: true (the default) integrates the first two volumetric spot lights and the first two volumetric directional lights exactly, over their shadow maps texel by texel, so a blind's bars or a doorway's edge are as crisp as the shadow map: integrated at samples along lines from the light across the frame (Chen et al.'s epipolar sampling), more of them where the depth or the light changes, and each pixel read from the samples either side of it at its depth; false lights them in the grid's cells with the rest |
