# Ambient

> A calm, living background for glass UI: soft colour fields from the kit (pastels in Halo, a faint aurora in Pro) that drift slowly, a photo or video under a scrim, or your own layer.

Component · Navigation · Halo kit · [Live page](https://ui.twentyfirst.media/halo/components/Ambient/)

A calm, living background for glass UI: soft colour fields from the kit (pastels in Halo, a faint aurora in Pro) that drift slowly, a photo or video under a scrim, or your own layer.

- Put it first inside a container: it fills the container (or the window with `fixed`) and sits behind the content.
- With `<UIProvider surface="glass">` around it, panels, cards, tiles, the app shell and floating layers turn into glass over it; text keeps 4.5:1 over any backdrop.
- The fields drift only with `transform`, stop with motion off or reduced motion and pause off screen. `animate={false}` keeps them still.
- `colors` takes any CSS colours (brand colours, `var(--chart-1)`); by default the kit's `--ambient-1…4`, themable like every token.
- `src` shows a photo, `src` with `video` a muted looping video; children replace both with your own layer (canvas, WebGL, a map).

## Example

```tsx
import * as React from "react";
import { Ambient, Badge, Button, Panel, StatTile, UIProvider } from "@twentyfirstmedia/halo";

export default function Preview() {
  return (
    <UIProvider scope="subtree" surface="glass">
      <div
        style={{
          display: "grid",
          gridTemplateColumns: "repeat(auto-fit, minmax(min(100%, 240px), 1fr))",
          gap: 16,
          padding: 24,
          borderRadius: "var(--radius-xl)",
          overflow: "hidden",
        }}
      >
        <Ambient />
        <StatTile value="7h 42m" label="Sleep" tint="sky" delta="+18 min" />
        <StatTile value="12 days" label="Streak" tint="butter" />
        <Panel
          title="Breathe"
          subtitle="Four minutes, box breathing"
          action={<Badge tone="success">New</Badge>}
        >
          <Button variant="primary" icon="play">
            Start
          </Button>
        </Panel>
      </div>
    </UIProvider>
  );
}
```

## Props

### Ambient

| Prop | Type | Notes |
| --- | --- | --- |
| `colors?` | `string[]` | Colours of the soft fields (any CSS colour); default the kit's `--ambient-1…4`. |
| `src?` | `string` | A photo (or, with `video`, a video) instead of the fields, under a scrim that keeps it calm. |
| `video?` | `boolean` | Treat `src` as a video (muted, looping, still with motion off). |
| `animate?` | `boolean` | Let the fields drift slowly (default true). Still with motion off; paused off screen. |
| `fixed?` | `boolean` | Cover the window behind the page instead of the nearest container. |
| `children?` | `ReactNode` | Your own layer (a canvas, WebGL, a map) instead of fields or media. |
| `className?` | `string` | Extra class on the root element. |
| `style?` | `CSSProperties` | Inline style on the root element. |

### Badge

| Prop | Type | Notes |
| --- | --- | --- |
| `tone?` | `Tone` |  |
| `dot?` | `boolean` |  |
| `live?` | `boolean` |  |
| `children?` | `ReactNode` |  |
| `className?` | `string` | Extra class on the root element. |
| `style?` | `CSSProperties` | Inline style on the root element. |

### Button

| Prop | Type | Notes |
| --- | --- | --- |
| `variant?` | `"primary" \| "secondary" \| "soft" \| "ghost" \| "danger" \| "danger-solid"` |  |
| `size?` | `"md" \| "sm"` |  |
| `icon?` | `IconName` |  |
| `iconRight?` | `IconName` |  |
| `disabled?` | `boolean` |  |
| `type?` | `"button" \| "submit" \| "reset"` |  |
| `onClick?` | `(e: MouseEvent<HTMLButtonElement>) => void` |  |
| `children?` | `ReactNode` |  |
| `asChild?` | `boolean` | Render the single child element (a link, a router Link) with the button's look instead of a <button>. |
| `id?` | `string` |  |
| `name?` | `string` | Form field name and value, sent with the form when this button submits it. |
| `value?` | `string` |  |
| `form?` | `string` | The id of the form this button belongs to, when it sits outside it. |
| `title?` | `string` |  |
| `tabIndex?` | `number` |  |
| `autoFocus?` | `boolean` |  |
| `aria-label?` | `string` |  |
| `aria-labelledby?` | `string` |  |
| `aria-describedby?` | `string` |  |
| `aria-expanded?` | `boolean \| "true" \| "false"` | For disclosure and menu triggers: whether what the button controls is open. |
| `aria-controls?` | `string` |  |
| `aria-haspopup?` | `boolean \| "true" \| "false" \| "menu" \| "listbox" \| "tree" \| "grid" \| "dialog"` |  |
| `aria-pressed?` | `boolean \| "true" \| "false" \| "mixed"` | For toggle buttons. |
| `aria-current?` | `boolean \| "true" \| "false" \| "page" \| "step" \| "location" \| "date" \| "time"` |  |
| `className?` | `string` | Extra class on the root element. |
| `style?` | `CSSProperties` | Inline style on the root element. |

### Panel

| Prop | Type | Notes |
| --- | --- | --- |
| `side?` | `boolean` |  |
| `title?` | `string` |  |
| `subtitle?` | `string` |  |
| `action?` | `ReactNode` |  |
| `children?` | `ReactNode` |  |
| `surface?` | `Surface` | `"glass"`: translucent glass over what is behind (maps, 3D, video, photos); `"solid"` opts out inside a glass `UIProvider`. |
| `className?` | `string` | Extra class on the root element. |
| `style?` | `CSSProperties` | Inline style on the root element. |

### StatTile

| Prop | Type | Notes |
| --- | --- | --- |
| `value` | `ReactNode` | Required |
| `label` | `string` | Required |
| `tint?` | `Tint \| "surface" \| "placeholder"` |  |
| `delta?` | `string` |  |
| `delay?` | `number` |  |
| `className?` | `string` | Extra class on the root element. |
| `style?` | `CSSProperties` | Inline style on the root element. |
