# `Frame.camera`

> Contract 2.0.0 · package sha256 `a857eca95b35921109faf997094bb4192f12527d9d0fcd4be7e97f06425bad6e` · generated from `configurator-runtime.d.ts` by `services/onsite-scripter/scripts/build-contract-docs.mjs`; edit the source, not this file.

Method of [`Frame`](Frame.md) · stable · since 2.0.0

```ts
camera(view: ((CameraView | LookAtView) & {
  fovDeg?: number;
}) | null): void;
```

A transient camera view for the frame being drawn: no commit, no 'committed' event, no undo
step. [`camera.state`](Camera.state.md) and 'camera:changed' report it. While it holds, the runtime's own camera
input and damping don't move the camera; null (or removing the hook) returns to the committed
view. Use it to lock the camera to a path every frame; [`camera.set`](Camera.set.md) in a hook would commit 60
times a second. Write it from an 'update' hook, so every 'late' hook reads the camera it sets;
written in a 'late' hook it still applies to the frame being drawn, but the 'late' hooks that
ran before it read the camera without it. A capture uses the last drawn frame's view. Its
`fovDeg` holds this frame's vertical field of view too, so a zoom that follows the pointer
(a panorama's wheel, pinch or slider) commits no lens per event; without it the committed
lens draws.

## Example

Imports: values (`has`, `validate`, the `Holo*Error` classes, the pure helpers) from `@holostep-configurators/runtime-client`, types from `@holostep-configurators/runtime-client/contract`, `/math` and `/testing` names from those entries; `boot` from the runtime module the root's `loadRuntimeAtFloor` resolves to. A type your page defines is your app's: declare it there, never import it from the package.

Compiled under the contract's strict settings (`examples/declaration/15-Frame.camera.ts`):

```ts
import type { CameraView, Session } from '@holostep-configurators/runtime-client/contract';
declare const session: Session;
declare const signal: AbortSignal;
// A turntable locked to a baked camera path; the app's 2D frames follow the same clock.
declare function viewOnPath(timeMs: number): CameraView;
declare function showFrameFor(timeMs: number): void;
// Aborting `signal` removes the hook, and the committed view returns.
session.onFrame((frame) => {
  frame.camera(viewOnPath(frame.timeMs));                  // this frame only: no commit
  showFrameFor(frame.timeMs);
}, { continuous: true, signal });
```

## Generic-API test (spec 3.1)

| Rule | Result |
| --- | --- |
| 1. Neutral name | pass: `camera` names no product |
| 2. A precedent | pass: [Unity MonoBehaviour.LateUpdate](https://docs.unity3d.com/ScriptReference/MonoBehaviour.LateUpdate.html) (row `G35`); [Babylon.js PhotoDome](https://github.com/BabylonJS/Babylon.js/blob/master/packages/dev/core/src/Helpers/photoDome.ts) (row `K22`) |
| 3. Two apps, or labs | pass: 2 apps (ledger: app-b4ae2fce25, app-ddfb017681; fleet cross-check: app-b4ae2fce25, app-ddfb017681) |
| 4. The cheaper fix first | decided per need in Appendix B: rows `G35`, `K22`, `K41` at tier app, stable (a member only where no rule, data, asset or app code serves the need) |
