# Black Box: Stack

> A backend platform's three parts as a list beside the box. Point at a row and its face opens; leave the list and the box walks it again.

A shadcn/ui block from the [@keyframeui](https://keyframeui.com/?utm_source=shadcn.exchange) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/keyframeui/black-box-stack-demo).

- Page, with a live preview: https://shadcn.exchange/r/keyframeui/black-box-stack-demo
- Screenshot: https://shadcn.exchange/shot/keyframeui/black-box-stack-demo/light.png
- Registry item: https://keyframeui.com/r/black-box-stack-demo.json
- Categories: 3d, hero, ai, diagram
- Listed: 2026-11-02, source last changed 2026-11-02

## Install

```bash
npx shadcn@latest add https://shadcn.exchange/r/keyframeui/black-box-stack-demo.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- Registry items: `https://keyframeui.com/r/black-box.json`

## Notes from the registry

Live preview, examples and props: https://keyframeui.com/components/black-box#black-box-stack-demo

## Files

### `registry/demos/black-box-stack-demo.tsx`

```tsx
"use client";

import * as React from "react";

import { cn } from "@/lib/utils";
import { BlackBox, type BlackBoxFace } from "@/components/ui/black-box";

// A backend platform's three parts, as a list that opens the box and a box that walks the list.
const LAYERS: (BlackBoxFace & { stat: string })[] = [
  {
    id: "functions",
    label: "Functions",
    detail: "TypeScript or Python, deployed on every push, warm in 38 ms.",
    stat: "38 ms cold start",
    icon: (
      <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={1.6} strokeLinecap="round" strokeLinejoin="round">
        <path d="M9 7 4 12l5 5M15 7l5 5-5 5" />
      </svg>
    ),
  },
  {
    id: "queues",
    label: "Queues",
    detail: "Retries, delays and fan-out without a broker to babysit.",
    stat: "1.2M jobs a day",
    icon: (
      <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={1.6} strokeLinecap="round" strokeLinejoin="round">
        <path d="M4 7h16M4 12h11M4 17h6" />
      </svg>
    ),
  },
  {
    id: "postgres",
    label: "Postgres",
    detail: "A branch of your database for every preview, merged with the code.",
    stat: "Branch per preview",
    icon: (
      <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={1.6} strokeLinecap="round" strokeLinejoin="round">
        <ellipse cx="12" cy="6" rx="7" ry="2.5" />
        <path d="M5 6v6c0 1.4 3.1 2.5 7 2.5s7-1.1 7-2.5V6M5 12v6c0 1.4 3.1 2.5 7 2.5s7-1.1 7-2.5v-6" />
      </svg>
    ),
  },
];

export function BlackBoxStackDemo() {
  const [value, setValue] = React.useState<string | null>(null);
  const [holding, setHolding] = React.useState(false);
  const [picked, setPicked] = React.useState(false);

  return (
    <div className="w-full max-w-4xl @container [--black-box-light:#ff5a1f]">
      <div className="grid items-center gap-x-10 gap-y-2 @[40rem]:grid-cols-[minmax(0,0.9fr)_minmax(0,1.1fr)]">
        <div>
          <p className="text-xs font-medium tracking-[0.08em] text-[#e2470f] uppercase dark:text-[#ff7a45]">Lattice platform</p>
          <h3 className="mt-3 text-3xl font-semibold tracking-[-0.03em] text-balance text-zinc-950 dark:text-white">
            Your whole backend, in one box.
          </h3>
          <ol
            className="mt-7 border-t border-zinc-950/10 dark:border-white/10"
            onPointerLeave={() => setHolding(false)}
            onFocus={() => setHolding(true)}
            onBlur={(event) => {
              if (!event.currentTarget.contains(event.relatedTarget as Node)) setHolding(false);
            }}
          >
            {LAYERS.map((layer, i) => {
              const on = value === layer.id;
              return (
                <li key={layer.id} className="border-b border-zinc-950/10 dark:border-white/10">
                  <button
                    type="button"
                    aria-pressed={on}
                    onPointerEnter={(event) => {
                      if (event.pointerType !== "mouse") return;
                      setHolding(true);
                      setValue(layer.id);
                    }}
                    onFocus={() => setValue(layer.id)}
                    onClick={() => {
                      setPicked(true);
                      setValue(layer.id);
                    }}
                    className="group relative flex w-full gap-4 py-4 text-left outline-none focus-visible:ring-2 focus-visible:ring-[#ff5a1f] focus-visible:ring-offset-2 focus-visible:ring-offset-white dark:focus-visible:ring-offset-zinc-950"
                  >
                    <span
                      aria-hidden
                      className={cn(
                        "absolute top-4 bottom-4 -left-px w-0.5 origin-top rounded-full bg-[#ff5a1f] transition-[opacity,transform] duration-200 ease-[cubic-bezier(0.23,1,0.32,1)]",
                        on ? "scale-y-100 opacity-100" : "scale-y-50 opacity-0",
                      )}
                    />
                    <span className="pl-4 font-mono text-xs leading-6 text-zinc-400 tabular-nums dark:text-zinc-500">
                      0{i + 1}
                    </span>
                    <span className="min-w-0 flex-1">
                      <span className="flex items-baseline justify-between gap-3">
                        <span
                          className={cn(
                            "text-[15px] leading-6 font-medium tracking-[-0.01em] transition-colors duration-200",
                            on ? "text-zinc-950 dark:text-white" : "text-zinc-500 dark:text-zinc-400",
                          )}
                        >
                          {layer.label}
                        </span>
                        <span className="shrink-0 font-mono text-[11px] text-zinc-400 tabular-nums dark:text-zinc-500">
                          {layer.stat}
                        </span>
                      </span>
                      <span className="mt-1 block text-[13px] leading-5 text-pretty text-zinc-500 dark:text-zinc-400">
                        {layer.detail}
                      </span>
                    </span>
                  </button>
                </li>
              );
            })}
          </ol>
        </div>

        <BlackBox
          faces={LAYERS}
          value={value}
          onValueChange={(id) => setValue(id)}
          autoplay={!holding && !picked}
          labels={false}
          aria-label="Lattice's three parts"
        />
      </div>
    </div>
  );
}
```
