# 3D camera module and API

AsukaDesigner exposes one engine-neutral camera contract. Integrations use degrees and world coordinates; Babylon `alpha` / `beta` values never leak into the public API.

## Camera module

Register the built-in module in a 3D layout with the id `camera`:

```js
{
  kind: 'camera',
  label: 'Camera',
  icon: 'camera',
  type: 'floating',
  supportedEngines: ['3d']
}
```

The module contains three sections:

- **Camera limits** controls minimum/maximum tilt and the permitted horizontal rotation.
- **Current camera** edits the current orbit, distance, target and field of view.
- **Variation camera views** captures, previews and removes a camera preset for any recursive Product 3D variation.

`maxTurn` is measured on each side of `turnCenter`. For example, `maxTurn: 60` and `turnCenter: 90` allow turns from 30° to 150°. Use `180` for a complete orbit.

## Init options

```js
const designer = createAsukaDesigner(container, {
  engines: {
    '3d': {
      camera: {
        minTilt: 0,
        maxTilt: 75,
        maxTurn: 90,
        turnCenter: 90,
      },
    },
  },
});
```

The limits are persisted per 3D view. Existing low-level beta options remain accepted, but new integrations should use the degree-based properties above.

## Camera API

All module operations are also available from `designer.util.camera`.

### Read and move the camera

```js
const view = designer.util.camera.get();

designer.util.camera.set({
  turn: 115,
  tilt: 28,
  distance: 4.2,
  target: [0, 0.8, 0],
  fov: 45,
}, {
  animate: true,
  duration: 500,
});
```

### Read and update limits

```js
const limits = designer.util.camera.getLimits();

designer.util.camera.setLimits({
  minTilt: -5,
  maxTilt: 70,
  maxTurn: 80,
  turnCenter: 100,
});
```

### Variation camera presets

```js
// Capture the current camera on one variation.
designer.util.camera.save('shoe-element', 'laces-red');

// Read the saved camera without moving.
const saved = designer.util.camera.getSaved('shoe-element', 'laces-red');

// Move to the saved camera.
designer.util.camera.load('shoe-element', 'laces-red', {
  animate: true,
  duration: 520,
});

// Remove the preset.
designer.util.camera.clear('shoe-element', 'laces-red');
```

The Elements and Variations modules automatically load the closest camera preset in the selected recursive path. A leaf preset overrides its parent group preset. When no preset exists, the existing automatic part-focus behavior is preserved.

## Variation data

Camera presets are ordinary serializable variation data:

```js
{
  id: 'laces-red',
  name: 'Red',
  camera: {
    turn: 125,
    tilt: 22,
    distance: 2.8,
    target: [0.15, 0.65, 0],
    fov: 42,
  },
}
```

This data is included in normal element/state exports. No module is required at runtime when presets are configured through the API or supplied directly in the element catalog.

## Public types

```ts
import type {
  AsukaCameraView,
  AsukaCameraLimits,
  AsukaCameraMoveOptions,
  AsukaCameraApi,
} from 'asuka-designer';
```
