> For the complete documentation index, see [llms.txt](https://docs.allout.game/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.allout.game/core-engine-concepts/camera-and-post-processing.md).

# Camera & Post Processing

### Camera

Every player starts off with a camera that follows them as they move. To adjust zoom or move the camera to other places, we provide a set of APIs.

In CSL, the camera is a per-player struct on `Player`:

* **`camera.follow_player: bool`**: when `true`, the engine keeps the camera following the player.
* **`camera.position: v2`**: the camera center in world space (used when `follow_player = false`).
* **`camera.size: float`**: zoom amount. **Larger = more zoomed out** (you see more of the world).

Player component state is synchronized, so set camera fields in the player's `ao_late_update` behind `is_local_or_server()`:

```go
import "core:ao"

My_Player :: class : Player_Base {
    ao_late_update :: method(dt: float) {
        if is_local_or_server() {
            // Simple "set and forget" zoom
            camera.size = 7.0;
        }
    }
}
```

#### Custom follow (offset + smoothing)

If you want camera offsets, cutscenes, or custom smoothing, turn off `follow_player` and drive `camera.position` yourself:

```go
import "core:ao"

My_Player :: class : Player_Base {
    ao_late_update :: method(dt: float) {
        if !is_local_or_server() return;

        camera.follow_player = false;

        // Follow slightly above the player
        target_pos := entity.world_position + v2{0, 0.5};

        // Smoothly move towards the target (dt-safe)
        t := clamp(dt * 10.0, 0.0, 1.0);
        camera.position = lerp(camera.position, target_pos, t);

        // Smooth zoom
        target_size := 6.0;
        camera.size = lerp(camera.size, target_size, t);
    }
}
```

The renderer interpolates `position` and `size` between simulation frames. Their read-only previous values are available as `position_last_frame` and `size_last_frame`.

The camera also provides `is_visible` overloads for a point, `Rect`, `Sprite_Renderer`, or `Spine_Animator`. The optional `apron` argument expands the visible area.

### Post Processing

Post Processing allows you to apply visual effects to your camera like distortion, color grading, and other effects to make your game pop!

You can configure post-processing in two ways:

* **Configure in the editor**: set up the default post-processing stack via **Edit → Game Config → Post Processing**. This applies when using the default camera behavior.
* **Configure at runtime via CSL**: use the `Post_Processing` API to dynamically apply effects from your player's `ao_late_update` method.

If you enable any effect, All Out will automatically use the HDR pipeline.

#### CSL Post Processing API

Call any of the following functions each frame to apply post-processing effects. When any `Post_Processing` function is called, it **overrides** the editor defaults for that frame — so you must call every effect you want active.

| Function                               | Config Struct                 | Fields                                                     |
| -------------------------------------- | ----------------------------- | ---------------------------------------------------------- |
| `Post_Processing.bloom`                | `Bloom_Config`                | `bloom_amount: float`                                      |
| `Post_Processing.color_grade`          | `Color_Grade_Config`          | `color_filter: v3`, `saturation: float`, `contrast: float` |
| `Post_Processing.chromatic_aberration` | `Chromatic_Aberration_Config` | `channel_offsets: v3`, `focal_point: v2`                   |
| `Post_Processing.blur`                 | `Blur_Config`                 | `directions: float`, `quality: float`, `size: float`       |
| `Post_Processing.film_grain`           | `Film_Grain_Config`           | `strength: float`, `noise_scale: float`                    |
| `Post_Processing.vignette`             | `Vignette_Config`             | `radius: float`, `softness: float`                         |

Keep these calls together so multiple components do not compete over the scene-wide configuration:

```go
import "core:ao"

My_Player :: class : Player_Base {
    ao_late_update :: method(dt: float) {
        if !is_local_or_server() return;

        // Apply bloom + vignette every frame
        Post_Processing.bloom({bloom_amount = 0.04});
        Post_Processing.vignette({radius = 0.8, softness = 0.4});
    }
}
```

To return to the editor defaults, stop calling every `Post_Processing` function.
