<!-- Generated from hooks/use-viewer-camera.mdx; edit the MDX source. -->

Package: @liveroom-tech/react-immersive@5.2.0
Canonical: https://react-immersive.liveroom.dev/docs/hooks/use-viewer-camera

# `useViewerCamera`

Provides declarative initial framing, live camera state, named presets, and camera movement helpers without direct `CameraControls` calls.

## Usage

```tsx
import { ModelViewer, useViewerCamera } from "@liveroom-tech/react-immersive";

const camera = useViewerCamera({
  initialPosition: [0, 2, 8],
  initialTarget: [0, 1.2, 0],
  presets: {
    detail: { position: [2, 1.2, 2.5], target: [0, 1.1, 0], fov: 35 },
  },
});

const {
  cameraState,
  resetView,
  focusObject,
  fitScene,
  setCameraTarget,
  lookAt,
  orbitTo,
  dollyTo,
  savePreset,
  goToPreset,
  handleCameraChange,
  handleViewerReady,
} = camera;

<ModelViewer
  onCameraChange={handleCameraChange}
  onViewerReady={handleViewerReady}
  ...
/>
```

## Returns

| Name                 | Type                                                 | Description                                                                   |
| -------------------- | ---------------------------------------------------- | ----------------------------------------------------------------------------- |
| `cameraState`        | `ViewerCameraState \| null`                          | Latest camera `position`, `target`, `fov`, `zoom`                             |
| `cameraPresets`      | `Record<string, ViewerCameraPreset>`                 | Current named views                                                           |
| `resetView`          | `() => Promise<boolean>`                             | Resets the controls to their initial saved state                              |
| `focusObject`        | `(id: string) => Promise<boolean>`                   | Fits the camera to a binding by key, `binding.id`, or `binding.modelObjectId` |
| `fitScene`           | `() => Promise<boolean>`                             | Fits the camera to the whole loaded scene                                     |
| `setCameraTarget`    | `(target, transition?) => Promise<boolean>`          | Sets the camera target to a given `[x, y, z]`                                 |
| `setCameraState`     | `(state, transition?) => Promise<boolean>`            | Restores a complete camera state                                              |
| `lookAt`             | `(position, target, transition?) => Promise<boolean>`  | Moves the camera position and target together                                 |
| `orbitTo`            | `(azimuth, polar, transition?) => Promise<boolean>`    | Orbits to angles in degrees (azimuth 0 = front, 90 = right; polar 0 = straight down, 90 = level) |
| `dollyTo`            | `(distance, transition?) => Promise<boolean>`          | Moves to a distance from the current target                                   |
| `savePreset`         | `(name: string) => ViewerCameraState \| null`          | Saves the current view under a name                                           |
| `goToPreset`         | `(name, transition?) => Promise<boolean>`               | Moves to a named view                                                         |
| `handleCameraChange` | `(state: ViewerCameraState) => void` | Callback to pass to `onCameraChange`                                          |
| `handleViewerReady`  | `(viewer: ViewerReadyState) => void`                 | Pass to `onViewerReady`, or compose with `useViewerConnection`                 |

## Example

```tsx
<button onClick={() => resetView()}>Reset Camera</button>
<button onClick={() => focusObject("some-object-id")}>Focus Object</button>
<button onClick={() => fitScene()}>Fit Scene</button>
<button onClick={() => setCameraTarget([0, 0, 0])}>Target Origin</button>
<button onClick={() => lookAt([4, 2, 6], [0, 1, 0])}>Three-quarter view</button>
<button onClick={() => orbitTo(90, 60)}>View from the right</button>
<button onClick={() => dollyTo(4)}>Move closer</button>
<button onClick={() => savePreset("custom")}>Save View</button>
<button onClick={() => goToPreset("custom")}>Restore View</button>

<pre>{JSON.stringify(cameraState, null, 2)}</pre>
```

Each initial position or target is optional and is applied once for every loaded model. Set `initialTransition: true` to animate into it. The default is `false`. `cameraPresets` contains the current named preset record.

## Viewer-ready capture methods

`ViewerReadyState` includes `captureImage`, `captureVideo`, and `invalidate`.
Compose `camera` with [`useViewerConnection`](https://react-immersive.liveroom.dev/docs/hooks/use-viewer-connection)
to capture PNGs or record cinematic/turntable video while keeping camera controls
connected. After [WebGL recovery](https://react-immersive.liveroom.dev/docs/reference/model-viewer#webgl-context-recovery),
`handleViewerReady` reconnects to the rebuilt viewer.
