# Model morph
> Model picker where one pixel swarm morphs between a diamond, a ring and a rotating star, with speed, depth and cost bars.
- Element: `<px-model>`
- React: `import { PxModel } from "@/components/lumesec/px-model"`
- Collection: Pixel Lab (https://elements.lumesec.ai/components/pixel-lab)
- Registry item: https://elements.lumesec.ai/r/px-model.json
- Page: https://elements.lumesec.ai/components/pixel-lab/model



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

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

<px-model></px-model>
```

## Installation

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

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-model.json
```

## Usage

React:

```tsx
import { PxModel } from "@/components/lumesec/px-model";

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

HTML:

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

<px-model></px-model>
```

## Behaviour

One swarm of pixels takes a different shape per model: a sparse, jittery diamond for speed, a calm ring for balance, a dense rotating star for depth. Switching sends every pixel flying to its new place.

## API reference

### Events

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

| Event    | React prop | Detail              | Description                                                                                                       |
| -------- | ---------- | ------------------- | ----------------------------------------------------------------------------------------------------------------- |
| `change` | `onChange` | `{ model: string }` | Fires when the user picks a model. `model` is `Swift`, `Balanced` or `Deep`. Not fired for the initial selection. |

### Methods

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

| Method                  | Description                                                                 |
| ----------------------- | --------------------------------------------------------------------------- |
| `select(index: number)` | Selects model 0 (`Swift`), 1 (`Balanced`) or 2 (`Deep`) and fires `change`. |

## Keyboard

| Keys                   | Action                                                                    |
| ---------------------- | ------------------------------------------------------------------------- |
| ArrowLeft / ArrowRight | Select the previous or next model, wrapping around, and move focus to it. |

## Accessibility

* The model buttons sit in a `role="radiogroup"` with `aria-label="Model"`; each has `role="radio"` and `aria-checked`.
* Roving tabindex: only the selected option is in the tab order.
* The canvas has `role="img"` with an `aria-label` naming the model and its speed, depth and cost scores out of 10.
* Reduced motion: pixels jump straight into the new shape instead of flying; the shape's own rotation and jitter continue.

## 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 `--card`, `--foreground`, `--lumesec`, `--muted` and `--muted-foreground`.

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

## Notes

* The three models and their scores are built-in demo data: Swift (speed 10, depth 3, cost 2), Balanced (7, 7, 5) and Deep (4, 10, 9). Balanced is selected initially.
* The canvas is 212px tall.


