Camera
3D viewpoint and projection
What is Camera3D?
Camera3D defines the viewpoint from which a scene is rendered. Unlike most 3D libraries where cameras are separate from scene items, in Uzay cameras are items that live in the scene, which means they can be reactive too.
Every View requires a camera. Without one, you can't render the scene.
Basic Usage
const camera = scene.create("camera3d", {
position: vec3(10, 10, 10),
lookAt: vec3(0, 0, 0),
});
// Use this camera for the view
const view = new View3D(scene, camera.id, containerElement);Camera Position and Target
The camera's view is defined by two vectors:
position: Where the camera is located in 3D spacelookAt: The point the camera is aimed at
// Looking at the origin from the front-right
scene.create("camera3d", {
position: vec3(10, 5, 10),
lookAt: vec3(0, 0, 0),
});
// Top-down view
scene.create("camera3d", {
position: vec3(0, 20, 0),
lookAt: vec3(0, 0, 0),
});
// Front view
scene.create("camera3d", {
position: vec3(0, 0, 15),
lookAt: vec3(0, 0, 0),
});Zoom
The zoom property scales the view:
// Default zoom
scene.create("camera3d", {
position: vec3(10, 10, 10),
lookAt: vec3(0, 0, 0),
zoom: 1,
});
// Zoomed in (objects appear larger)
scene.create("camera3d", {
position: vec3(10, 10, 10),
lookAt: vec3(0, 0, 0),
zoom: 2,
});
// Zoomed out (objects appear smaller)
scene.create("camera3d", {
position: vec3(10, 10, 10),
lookAt: vec3(0, 0, 0),
zoom: 0.5,
});Field of View
The fov property controls the vertical field of view in degrees:
// Wide angle (more visible, more distortion)
scene.create("camera3d", {
position: vec3(10, 10, 10),
lookAt: vec3(0, 0, 0),
fov: 90,
});
// Narrow angle (telephoto look)
scene.create("camera3d", {
position: vec3(10, 10, 10),
lookAt: vec3(0, 0, 0),
fov: 30,
});Projection Mode (Incomplete)
Camera3D includes a projection field for future support of multiple projection modes.
"perspective"is fully supported."orthogonal"is not implemented yet inView3D.
If you set projection: "orthogonal", Uzay currently logs a warning and falls back to perspective rendering.
Clipping Planes
Objects closer than near or farther than far are not rendered:
scene.create("camera3d", {
position: vec3(10, 10, 10),
lookAt: vec3(0, 0, 0),
near: 0.1, // Don't render objects closer than 0.1 units
far: 1000, // Don't render objects farther than 1000 units
});Adjust these if you see objects disappearing unexpectedly.
Multiple Cameras
You can create multiple cameras and switch between them:
const frontCamera = scene.create("camera3d", {
position: vec3(0, 0, 20),
lookAt: vec3(0, 0, 0),
});
const topCamera = scene.create("camera3d", {
position: vec3(0, 20, 0),
lookAt: vec3(0, 0, 0),
});
const sideCamera = scene.create("camera3d", {
position: vec3(20, 0, 0),
lookAt: vec3(0, 0, 0),
});
// Start with front camera
const view = new View3D(scene, frontCamera.id, container);
// Switch to top view
view.changeActiveCam(topCamera.id);Examples
Since cameras are scene items, their properties can be atoms. Camera sync is bidirectional: atom changes update the Three.js camera, and orbit control interactions update the atoms.
const cameraY = scene.atom(10);
const camera = scene.create("camera3d", {
position: scene.atom((get) => vec3(10, get(cameraY), 10)),
lookAt: vec3(0, 0, 0),
});
// Camera smoothly moves up
function animate() {
cameraY.set(cameraY.get() + 0.01);
requestAnimationFrame(animate);
}
animate();Camera Following an Item
const targetPos = scene.atom(vec3(0, 0, 0));
// A point that moves
const point = scene.create("point3d", {
coords: targetPos,
color: "gold",
});
// Camera that follows the point
const camera = scene.create("camera3d", {
position: scene.atom((get) => {
const target = get(targetPos);
return Vec3.add(target, vec3(5, 5, 5)); // Offset from target
}),
lookAt: targetPos,
});Bidirectional Sync with UI
When you pass writable atoms for position or lookAt, orbit control interactions (rotating, panning) write back to those atoms. This lets you build UI that stays in sync with user interactions:
const camX = scene.atom(10);
const camY = scene.atom(10);
const camZ = scene.atom(10);
const cameraPosAtom = scene.atom(
(get) => vec3(get(camX), get(camY), get(camZ)),
(_get, set, next: Vec3) => {
set(camX, next.x);
set(camY, next.y);
set(camZ, next.z);
},
);
const camera = scene.create("camera3d", {
position: cameraPosAtom,
lookAt: vec3(0, 0, 0),
});
// Subscribe to see orbit changes reflected in individual atoms
camX.sub(() => console.log("Camera X:", camX.get()));If position or lookAt is a read-only derived atom, writeback is skipped gracefully.
Orbit Controls
Views come with built-in orbit controls that let users interact with the camera:
- Left-click + drag: Rotate around the
lookAtpoint - Right-click + drag: Pan the camera
- Scroll: Zoom in/out
Each of these can be independently enabled or disabled via camera properties:
// Rotation only, no panning or zooming
scene.create("camera3d", {
position: vec3(10, 10, 10),
lookAt: vec3(0, 0, 0),
enableOrbit: true,
enablePan: false,
enableZoom: false,
});Since these are atoms, you can toggle them reactively:
const canOrbit = scene.atom(true);
const camera = scene.create("camera3d", {
position: vec3(10, 10, 10),
lookAt: vec3(0, 0, 0),
enableOrbit: canOrbit,
});
// Disable orbiting later
canOrbit.set(false);API Reference
Options
| Property | Type | Default | Description |
|---|---|---|---|
position | Vec3 | { x: 10, y: 10, z: 10 } | Camera location |
lookAt | Vec3 | { x: 0, y: 0, z: 0 } | Point the camera aims at |
projection | "perspective" | "orthogonal" | "perspective" | Projection mode ("orthogonal" currently warns and falls back to perspective) |
enableOrbit | boolean | true | Enable rotation (left-click drag) |
enablePan | boolean | true | Enable panning (right-click drag) |
enableZoom | boolean | true | Enable zooming (scroll) |
fov | number | 60 | Vertical field of view (degrees) |
zoom | number | 1 | Zoom level |
near | number | 0.1 | Near clipping plane |
far | number | 1000 | Far clipping plane |
Returned Item
| Field | Type | Description |
|---|---|---|
id | string | Unique identifier (pass to View3D) |
position | BoundAtom<Vec3> | Position atom |
lookAt | BoundAtom<Vec3> | Target atom |
projection | BoundAtom<"perspective" | "orthogonal"> | Projection atom |
enableOrbit | BoundAtom<boolean> | Orbit toggle atom |
enablePan | BoundAtom<boolean> | Pan toggle atom |
enableZoom | BoundAtom<boolean> | Zoom toggle atom |
fov | BoundAtom<number> | FOV atom |
zoom | BoundAtom<number> | Zoom atom |
near | BoundAtom<number> | Near plane atom |
far | BoundAtom<number> | Far plane atom |