# Keypad

A raked bench entry pad on a scanned matrix: the key that is down and the cell the scan is reading are two different things, and both are drawn.

> 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/robot-keypad.json
```

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

## Notes

- The matrix is scanned, not wired one line per key: one row is energized and the columns are read across it. The cell being read is outlined and the key that is down is pressed, because they are not the same thing and a drawing that conflates them is lying about how a keypad works.
- The rake is the mechanism, not the styling. A key face flat on the bench presses straight into a front camera and shows nothing; tipped up, the same travel moves the cap down the screen. Set `rake={0}` and you can see the machine lose its own legibility, honestly.
- Each cap is a box standing on the face and pressing along its normal, so the travel is truthful from every camera rather than being a vertical nudge that only works in one of them.
- It checks nothing. There is no code comparison, no lockout, no attempt counter, no timing and no encoding: `outcome` is the answer it has been told to give.
- From `plan` the camera stands past the far edge of the deck, so the legends read away from you. That is what looking at a keypad over its own top edge does, and it is the same projection every other machine in the set uses.
- An original archetype. No manufacturer, product line, wordmark or key set is reproduced here or in the demo.

## Usage

```tsx
import { RobotKeypad } from "@/components/ui/robot-keypad"

<RobotKeypad code="4813" outcome="granted" />

// Controlled, or a pad you can scrub through the entry.
<RobotKeypad typed={0.45} rows={4} columns={3} rake={22} showScan />
<RobotKeypad interactive onTypedChange={setTyped} />
```

## Props

| name | type | default | description |
| --- | --- | --- | --- |
| `view` | `"plan" | "front" | "profile" | "iso"` | `"front"` | Where the camera stands. One keypad, four projections: straight down, straight on, side elevation, or three-quarter from above. |
| `typed` | `number` | — | Controlled position through the entry, 0 to 1. Omit it and the keys run behavior. It is `typed` rather than `stroke` because `stroke` is an SVG attribute. |
| `behavior` | `"entry" | "scan" | "idle" | "static"` | `"entry"` | Work through the entry and answer it, run the matrix scan with nothing pressed, or sit with the backlight on. |
| `code` | `string` | `"4813"` | The characters it enters, in order. Anything not on a cap is dropped rather than mapped onto a key nobody asked for. |
| `outcome` | `"granted" | "denied"` | `"granted"` | What it answers with once the entry is in. It compares nothing — this is the answer, not the result of a check. |
| `rows` | `number` | `4` | Rows in the matrix, rounded and clamped to 3–5. |
| `columns` | `number` | `3` | Columns in the matrix, rounded and clamped to 3–4. A fourth column gets lettered keys, so no legend is ever drawn twice. |
| `rake` | `number` | `22` | How far the key face is tipped up from the bench, degrees, clamped 0–40. Geometry: it sets the wedge's back height, and it is what makes a press visible head on. |
| `showScan` | `boolean` | `false` | Draw the row rails and outline the cell the scan is reading. Blueprint draws them anyway. |
| `speed` | `number` | `0.3` | Entries per second. |
| `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` | `false` | Drag across the face to scrub the entry, or arrow-key it a digit at a time. |
| `onTypedChange` | `(typed: number) => void` | — | Position through the entry throughout a drag or a key press. |
| `onEntryChange` | `(digits: number) => void` | — | How many digits have been taken, when that changes — never once per frame. |
| `label` | `string` | — | Caption below the state readout. |
| `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. |
| `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/robot-keypad.tsx`
