> For the complete documentation index, see [llms.txt](https://mango-5m.gitbook.io/mango5m-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://mango-5m.gitbook.io/mango5m-docs/resources/mango-prison/configuration/cctv-cameras.md).

# CCTV Cameras

The camera network — placing cameras in game, the models, what breaks them, and every tuning value in config/cctv.lua.

Every camera in Mango Corrections is a **real prop in the world**. Guards watch the feeds from the terminal's CCTV page; prisoners can watch the camera itself, and shoot it out.

Placements live in the prison database, so there is **no SQL to install** — place a camera in game and it is there after the next restart.

## Placing a camera

Cameras are installed with a developer tool. The command is registered **server-side**, so a modified client cannot open it:

```cfg
add_ace group.admin command.prisoncam allow
```

With `Config.Developer = true` the command is open to **everyone**, no ace needed — see [Developer Mode](/mango5m-docs/resources/mango-prison/developer-guide/developer-mode.md). Rename the command with `Config.CCTV.placeCommand`.

`/prisoncam` spawns a translucent camera two metres ahead of you:

| Key             | Action                                   |
| --------------- | ---------------------------------------- |
| `W` `A` `S` `D` | Move, relative to your camera            |
| `↑` `↓`         | Raise / lower the mount                  |
| `←` `→`         | **Aim** — swing where it looks           |
| `Q` / `E`       | **Tilt** down / up (clamped to −85°…45°) |
| `R`             | Lock or unlock the aim from the model    |
| `G`             | Cycle the camera model                   |
| `SHIFT` / `ALT` | Fast (×4) / fine (×¼)                    |
| `SPACE`         | Through-the-lens preview                 |
| `ENTER`         | Name it and save                         |
| `X`             | Cancel                                   |

A blue line and endpoint dot show where the camera is looking. `SPACE` is the reliable way to judge framing — the aim line alone can look right while the shot is off.

### Aim vs. mount

By default the housing turns with the aim: swing the view and the model swings with it. Press `R` and the model **stays where it is** while the arrows swing only the lens — that is how you bolt a camera flat against a wall and still point it down a corridor.

The two headings are stored separately (`heading` for the lens, `mountHeading` for the prop), so a saved camera renders at its mount angle and watches along its aim. `modelHeadingOffset` (default `180.0`) corrects for the fact that the props render backwards from their aim direction.

{% hint style="info" %}
A warning pill appears the moment the ghost leaves the prison boundary, and the server refuses the save outright — **cameras only exist inside the walls**. The boundary is `Config.Zones.boundary`.
{% endhint %}

## Camera models

Seven ship in `Config.CCTV.models`, cycled with `[G]` during placement:

**Dome** · **Bullet** · **PTZ** · **Traffic** · **Covert Mini** · **Bank Cam** · **CCTV**

The list is plain config, so adding your own is one line:

```lua
{ id = 'wall', label = 'Wall Box', prop = `prop_cctv_cam_07a` },
```

Each camera remembers what it was placed with, and the terminal shows it in the **MODEL** column. A camera whose model id no longer exists falls back to the first entry rather than failing to render.

## Watching a feed

The terminal's **CCTV** page (key `C`) lists every camera with its name, model, the zone it watches and its status. **VIEW** hands the screen over to a scripted camera at the lens, with a CRT scanline look over the image (`viewerTimecycle` — set it to `''` for a clean picture).

| Key     | Action                        |
| ------- | ----------------------------- |
| `←` `→` | Switch between online cameras |
| `X`     | Back to the terminal          |

The **LOCATION** column is worked out from `Config.Zones` — whichever named zone the camera sits in, or `Grounds` if it sits in none.

{% hint style="info" %}
**Distant feeds.** A scripted camera does not stream the world by itself, so a wing on the far side of the prison would otherwise open on bare terrain. Opening a feed pulls the world in around the camera first — `streamLoadRadius` (180 m) and `streamLoadMs` (3000 ms). Raise the wait if distant feeds still open on unloaded scenery.
{% endhint %}

## Breaking a camera

Cameras stream in as real props within `streamRadius` of a player, and keep their collision, so **they can be shot out**. A destroyed camera:

* goes **OFFLINE** for `offlineMinutes` (10 by default), shown with a live countdown on the terminal
* disappears from the viewer's rotation until it recovers
* pings every on-duty guard, when `alertGuards` is on
* is written to the audit log and the `cctv` Discord channel

Service restores itself — nothing has to tick, because status is computed from the timestamp on every read.

A "camera destroyed" report is only believed from a client **actually near that camera** (`breakReportRadius`, 130 m), and only for a camera that is currently online.

## Solitary cameras

A camera named **`Solitary Cell 3`** — or `Solitary Cell #3` — belongs to solitary cell 3. It is **hidden from the CCTV page** and appears on that cell's record on the [Solitary page](/mango5m-docs/resources/mango-prison/features/the-prison-terminal.md) instead, with its own VIEW button that shows only that cell rather than cycling the network.

Matching is case-insensitive and tolerates the `#`. Anything else — `Solitary Hall 3`, `Solitary Cell 3 North` — is an ordinary camera and stays on the CCTV page.

## Managing cameras

From the terminal's CCTV page:

* **RENAME** — up to 40 characters. Renaming a camera to `Solitary Cell 5` moves it to that cell's page with no other action needed
* **REMOVE** — grade-gated like the other destructive actions

Both are logged.

## Every setting

| Setting              | Default                | Does                                                    |
| -------------------- | ---------------------- | ------------------------------------------------------- |
| `enabled`            | `true`                 | The whole system                                        |
| `placeCommand`       | `'prisoncam'`          | The placement command (and the ace name)                |
| `models`             | 7 entries              | Camera props, cycled with `[G]`                         |
| `modelHeadingOffset` | `180.0`                | Correction between the prop's facing and its aim        |
| `offlineMinutes`     | `10`                   | Downtime after a camera is destroyed                    |
| `lensOffset`         | `0.35`                 | How far forward of the prop the viewer's lens sits      |
| `fov`                | `70.0`                 | Viewer field of view                                    |
| `viewerTimecycle`    | `'scanline_cam_cheap'` | CRT look over the feed; `''` for clean                  |
| `streamRadius`       | `120.0`                | How close a player must be for the prop to exist        |
| `streamInterval`     | `3000`                 | How often streaming is re-evaluated (ms)                |
| `breakCheckInterval` | `500`                  | Break polling, only while a prop is streamed in (ms)    |
| `streamLoadRadius`   | `180.0`                | World pulled in around a camera you open                |
| `streamLoadMs`       | `3000`                 | How long to wait for it                                 |
| `breakReportRadius`  | `130.0`                | How near a client must be for its break report to count |
| `alertGuards`        | `true`                 | Ping on-duty guards when a camera goes down             |
