# Plenum — Animated UI Component for React

> R3F z-axis gallery fly-through: frames mounted on fresnel-edged glass panes float down a corridor in an alternating left/right rhythm; wheel, drag or arrow keys fly the camera through with eased banking while passing panes dissolve and fog swallows the distance. Click or Enter glides square-on to a pane, Escape returns. Idle drift loops seamlessly via recycled panes; offscreen-paused, reduced-motion-safe, CSS fallback.

- Page: https://crucibleui.com/components/utility/plenum
- Category: [utility](https://crucibleui.com/components/utility)
- Tier: pro (one-time purchase, see https://crucibleui.com/pricing)
- Engine: r3f
- npm dependencies: three, @react-three/fiber

## Install

```bash
npx shadcn@latest add @crucible/plenum
```

Pro install requires adding the token-bearing `@crucible` registry to components.json (issued at https://crucibleui.com/account after purchase).

Import from `@/components/crucible/plenum`.

## Props (`PlenumProps`)

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `items?` | `PlenumItem[]` | `eight seeded procedural plates. Loops seamlessly` | Frames hung along the corridor. |
| `speed?` | `number` | `1` | Multiplier for the idle drift and for scroll / drag fly-through speed. |
| `spacing?` | `number` | `1.15` | Distance between consecutive panes along the corridor, in pane widths (≈1.7 units each). |
| `fog?` | `number` | `0.45` | Depth fog, 0 (clear to the end of the corridor) → 1 (dense haze). |
| `interactive?` | `boolean` | `true` | Wheel / drag to fly, click a pane to focus it. Keyboard always works. |
| `paused?` | `boolean` | `false` | Freeze the idle drift and the intro; steps and focus still ease on demand. |
| `label?` | `string` | `"Gallery"` | Accessible name for the gallery. |
| `children?` | `React.ReactNode` | — | Overlay content laid over the stage (pointer events pass through to the corridor). |
| `className?` | `string` | — | Extra classes for the root element. |
| `ref?` | `React.Ref<PlenumHandle>` | — | Imperative handle: `next()`, `prev()`, `focus(i)`, `release()`. |

## Usage example

```tsx
"use client";

import { Plenum } from "@/components/crucible/plenum";

export default function PlenumDemo() {
  return (
    <div className="relative isolate flex h-full min-h-[360px] w-full items-center justify-center overflow-hidden rounded-xl bg-neutral-950">
      <div
        aria-hidden
        className="pointer-events-none absolute inset-0 -z-10 bg-[radial-gradient(ellipse_at_50%_42%,rgba(148,163,184,0.12),transparent_65%)]"
      />
      <Plenum className="absolute inset-0">
        <p className="relative z-10 pt-5 text-center text-sm text-neutral-500">
          Scroll or use arrows to fly through.
        </p>
      </Plenum>
    </div>
  );
}
```

## Accessibility & performance

Honors `prefers-reduced-motion` with a designed static frame or fade (never a blank box) and passes `className` through. Pauses offscreen and on hidden tabs, clamps device pixel ratio, and tears down its GL/canvas context on unmount.
