Camera

The scene camera, reached at scene.camera. It's a Node, so the full transform surface works — position, eulerAngles, lookAt, forward. On top of that it exposes projection reads and screen→world ray helpers for picking.

You never construct one: every Scene creates its own camera (overlays share the parent's). In an ARScene the camera is driven by device tracking — read it, don't place it.

At a glance

TypeScript
scene.camera.position = [0, 2, 4]
scene.camera.lookAt([0, 0.5, 0])

scene.addEventListener('touchstart', ev => {
  const ray = scene.camera.getRay(ev.clientX, ev.clientY)
  const hit = Physics.raycast(ray.origin, ray.dir)
  if (hit) console.log('tapped', hit.node?.name)
})

Projection

TypeScript
camera.fov               // vertical field of view, DEGREES — settable (default 60)
camera.near              // near clip distance, settable (default 0.01)
camera.far               // far clip distance = view range, settable (default 1000)
camera.setProjection({ fov: 45, far: 5000 })   // any subset, one call

camera.horizontalFov     // horizontal field of view, degrees (read-only, derived from fov + aspect)
camera.displaySize       // [width, height] of the 3D viewport, px (read-only)
camera.projectionMatrix  // Float32Array(16), live — the host updates it in place on resize/fov change

The aspect ratio stays host-owned: you set the lens, the host keeps it across every resize. Nothing nearer than near or further than far draws, so far is the scene's view range — raise it for open worlds. Shadows keep their own (shorter) range, so a long view distance costs nothing in shadow sharpness.

In a scene file the same three live on the camera block:

TypeScript
camera: { position: [0, 6, 12], target: [0, 0, 0], fov: 45 }   // top-level block
nodes: { cam: { camera: { fov: 45, far: 5000 } } }             // …or the camera NODE (it wins)

Hosts that predate the projection call keep the fixed defaults — setting it there is inert, not an error. See docs/parity/MATRIX.md (gl-camera-projection).

Exposure

TypeScript
camera.exposureCompensation = -2          // stops: +1 doubles the scene's brightness, −2 quarters it
camera.setExposure({ iso: 400 })          // the physical camera: aperture (f-stops), shutterSpeed (s), iso, compensation

The default is f/16 · 1/125 s · ISO 100 — EV100 15, bright sunlight, the exposure every light intensity in these docs is tuned against — and exposureCompensation (default 0) is the one knob most games need on top of it: a dark interior, a white-out, or eye adaptation — when the sun swings into view, drop it a couple of stops over ~0.15 s and let it recover over a second or two. The sun stays at the display's peak (its scene value is far above the tone curve's shoulder) while everything else goes dark, which is what makes it read as blinding; on an HDR display (device.hdr) doubly so. Cheap to set every frame.

Scene-referred light — sun, sky, IBL, lit surfaces — follows the exposure. Particle emissive is post-exposure (1 = white on screen) and does not, so a muzzle flash or a fireball keeps its on-screen brightness while the world around it darkens.

Hosts that predate the call keep the fixed default. See docs/parity/MATRIX.md (gl-camera-exposure).

Screen → world rays

TypeScript
camera.getViewDirection(screenX, screenY): Vec3   // world-space ray direction through a screen point
camera.getRay(screenX, screenY): Ray              // origin = camera.worldPosition, dir = view direction

Screen coordinates are logical px — the same space as ev.clientX / ev.clientY. getRay pairs directly with Physics.raycast for tap-picking; Ray is documented in ray-plane-noise.

Note

there is no worldToScreen helper — the inverse projection is only available raw, via projectionMatrix + the camera's worldMatrix.

Pitfalls

TypeScript
// ✗ moving the camera in an ARScene — tracking overwrites it every frame
arScene.camera.position = [0, 2, 4]
// ✓ move the WORLD instead: parent content under scene.root and place that

See also

  • Scene — where the camera comes from; overlays share it
  • Node — the inherited transform surface (position, lookAt, forward)
  • 3D physics & shapes — raycasting the rays you build here
  • Ray, Plane, Noise — the Ray returned by getRay