# Typing heatmap
> Typing test over a pixel keyboard where each key flashes, ripples to its neighbours, builds heat with use and turns red on a miss.
- Element: `<px-keys>`
- React: `import { PxKeys } from "@/components/lumesec/px-keys"`
- Collection: Pixel Lab (https://elements.lumesec.ai/components/pixel-lab)
- Registry item: https://elements.lumesec.ai/r/px-keys.json
- Page: https://elements.lumesec.ai/components/pixel-lab/keys



Live preview: https://elements.lumesec.ai/view/px-keys

```html
<script type="module" src="https://elements.lumesec.ai/cdn/px-keys.js"></script>

<px-keys></px-keys>
```

## Installation

```bash
npx shadcn@latest add @lumesec/px-keys
```

First time with the @lumesec registry? Register it once, or install by URL:

```bash
npx shadcn@latest registry add @lumesec=https://elements.lumesec.ai/r/{name}.json
npx shadcn@latest add https://elements.lumesec.ai/r/px-keys.json
```

## Usage

React:

```tsx
import { PxKeys } from "@/components/lumesec/px-keys";

export function Example() {
  return (
    <PxKeys />
  );
}
```

HTML:

```html
<script type="module" src="https://elements.lumesec.ai/cdn/px-keys.js"></script>

<px-keys></px-keys>
```

## Behaviour

A typing test over a pixel keyboard. Each key flashes and ripples to its neighbours, builds up heat the more you use it, and turns red on a miss.

## API reference

### Events

Events bubble and cross the shadow boundary unless the description says otherwise.

| Event  | React prop | Detail                              | Description                                                                          |
| ------ | ---------- | ----------------------------------- | ------------------------------------------------------------------------------------ |
| `done` | `onDone`   | `{ wpm: number, accuracy: number }` | Fires when the typed text matches the target line. `accuracy` is a whole percentage. |

### Methods

Call them on the element, for example through a React ref.

| Method    | Description                                                                                   |
| --------- | --------------------------------------------------------------------------------------------- |
| `reset()` | Clears the input, the timer, the score and the key heat, re-enables the field and focuses it. |

## Keyboard

| Keys                                | Action                                                                                             |
| ----------------------------------- | -------------------------------------------------------------------------------------------------- |
| Printable characters (in the input) | Flash the matching key and count the keystroke; a wrong character flashes red and lowers accuracy. |

## Accessibility

* The target line has `aria-label="Type this: pixels glow when you type them"`; the input has `aria-label="Typing test"`.
* The keyboard canvas has `role="img"` and `aria-label="Keyboard heatmap"`.
* The WPM and accuracy line is an `aria-live="polite"` region. The input is disabled once the line is complete; Reset is a native button.
* Reduced motion: only the completion sparks and the rolling status text are suppressed; key flashes and ripples still play.

## Theming

The element reads your shadcn theme tokens through its shadow root, so light and dark follow your theme. The accent comes from `--lumesec`. See [Theming](/docs/theming).

This component reads `--border`, `--card`, `--destructive`, `--foreground`, `--lumesec`, `--lumesec-success` and `--muted-foreground`.

To restyle only LumeSec elements, set the matching `--ui-*` overrides: `--ui-accent`, `--ui-border`, `--ui-danger`, `--ui-fg`, `--ui-mono`, `--ui-muted`, `--ui-ok` and `--ui-surface`.

## Notes

* The target sentence is fixed demo content. WPM counts correct keystrokes divided by five per minute from the first key.
* The heatmap covers letters and the space bar; the key letters are drawn in the page font. Reset also clears the key heat. The canvas is 104px tall.


