# Sentinel console

A bulkhead-mounted watch station: a gimballed optic behind a solved iris diaphragm, an identity strip, and a voice grille. The one machine in the set that is part of the ship rather than standing on the deck.

> For the complete index, see [llms.txt](https://robocn.dev/llms.txt). A Markdown version of any page is available by appending `.md` to its URL or by sending an `Accept: text/markdown` header.

## Install

```bash
bunx --bun shadcn@latest add https://robocn.dev/r/sentinel-console.json
```

Registry item: `sentinel-console` · [`https://robocn.dev/r/sentinel-console.json`](https://robocn.dev/r/sentinel-console.json)

## Notes

- Front elevation is the view it is drawn in. The console is modelled once as solids in world units — across the face, down it, and out of the wall — and projected, so the tipped cameras show real depth: how far the bezel stands proud, the speaker box behind the grille, the conduit into the back of the housing. In profile and plan the face is edge-on and its artwork is gone, which is what a wall fixture looks like from the side.
- The iris is solved. Each blade pivots about a pin on a fixed ring and carries a circular working edge, so the bore is the law of cosines in the blade swing, run backwards from the opening you asked for; the blades are drawn from that solution and overlap the way real ones do.
- The optic is a body, not a pupil: it yaws and pitches about a pivot behind its own face, between two visible trunnions, so turning it foreshortens the bezel and slides the glass across it.
- Everything else is illustrated. There is no optics model — the aperture changes no exposure and no depth of field — and the gimbal has no actuator or mechanical stops beyond the clamp on look. Nothing here listens, speaks or infers a state: voice lights cells because it was told to.
- An original archetype — a ship's sentinel console — not a character. The identity strip is generic by default and carries no name from a film.

## Usage

```tsx
import { SentinelConsole } from "@/components/ui/sentinel-console"

<SentinelConsole behavior="watch" blades={8} plate="SENTINEL 7" onApertureChange={setAperture} />
```

## Props

| name | type | default | description |
| --- | --- | --- | --- |
| `view` | `"plan" | "front" | "profile" | "iso"` | `"front"` | Where the camera stands. One console, four projections: straight down, straight on, side elevation, or three-quarter from above. |
| `aperture` | `number` | — | The opening, 0 a pinhole to 1 wide. Supplying it stops the loop; the blades are solved from it either way. |
| `behavior` | `"watch" | "listen" | "speak" | "alert" | "static"` | `"watch"` | Watch holds a bearing and swings to the next; listen opens the iris and all but stops; speak runs the grille; alert stops down hard and snaps between bearings. |
| `speed` | `number` | `0.22` | Cycles per second: one sweep of the room, one burst of speech. |
| `animate` | `boolean` | `true` | Off parks the machine at phase and stops rendering. A reduced-motion preference does the same. |
| `paused` | `boolean` | `false` | Freeze where it stands. |
| `phase` | `number` | `0` | Seconds of offset, so a row of machines breaks step. |
| `interactive` | `boolean` | `true` | Drag across the lens to work the iris, or use the arrow keys; Home closes it and End opens it. Release eases it back into the behaviour. |
| `onApertureChange` | `(aperture: number) => void` | — | The opening a drag or a key moved it to, reported in controlled mode too. |
| `look` | `Vec2 | null` | `null` | Controlled optic aim in −1..1; overrides pointer tracking. |
| `track` | `boolean` | `true` | The optic follows the page pointer while look is null. |
| `voice` | `number` | — | Lit cells in the voice grille, 0–1, filling out from the middle. Omit and the behaviour works it. |
| `blades` | `number` | `8` | Leaves in the diaphragm, clamped to 4–10. |
| `plate` | `string` | `"SENTINEL"` | The identity strip across the top of the console. |
| `showBulkhead` | `boolean` | `true` | Draw the bulkhead plate the console is set into. |
| `variant` | `"solid" | "outline" | "blueprint" | "wire"` | `"solid"` | How the machine is painted. Geometry never changes between variants. |
| `size` | `"xs" | "sm" | "md" | "lg" | "xl" | number` | `"md"` | Rendered width in pixels, or a step on the scale. |
| `signal` | `"idle" | "ready" | "warning"` | `"ready"` | The lamp on the identity strip: neutral, accent, or shell colour. |
| `label` | `string` | — | Optional technical caption under the drawing. |
| `color` | `string` | `var(--robot-shell)` | Body panels — the colour the machine reads as. |
| `accent` | `string` | `var(--robot-accent)` | Status colour: tip light, live tool, readouts. |
| `metal` | `string` | `var(--robot-metal)` | Bare machined parts: collars, bolts, tool bodies. |
| `dark` | `string` | `var(--robot-dark)` | Cast joints, base, shadow side. |
| `palette` | `Partial<RobotPalette>` | — | Override any subset of roles at once, including glow and grid. |

## Source

- `src/components/ui/sentinel-console.tsx`
