# Sync Grid: Model Output

> One prompt, four fictional video models. The clips run 7 to 21 seconds and line up by percentage, so halfway is halfway in all of them. Stack them and move up and down to flip between outputs on the same frame.

A shadcn/ui block from the [@keyframeui](https://keyframeui.com) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/keyframeui/sync-grid-models-demo).

- Page, with a live preview: https://shadcn.exchange/r/keyframeui/sync-grid-models-demo
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/keyframeui/sync-grid-models-demo-light-c25ab422faa1cad8.png
- Registry item: https://keyframeui.com/r/sync-grid-models-demo.json
- Categories: video, comparison, scrubbing, motion
- Listed: 2026-10-14, source last changed 2026-10-15

## Install

```bash
npx shadcn@latest add https://keyframeui.com/r/sync-grid-models-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/sync-grid.json`

## Notes from the registry

Live preview, examples and props: https://keyframeui.com/components/sync-grid#sync-grid-models-demo

## Files

### `registry/demos/sync-grid-models-demo.tsx`

```tsx
import { SyncGrid, SyncGridItem } from "@/components/ui/sync-grid";

const prompt = "A paper boat drifting down a rain-soaked street";

// Four clips of different lengths, lined up by percentage: halfway through
// one is halfway through all of them.
const outputs = [
  { model: "Bramble 2", clip: 49029, time: "38s", cost: "$0.09" },
  { model: "Fernlight XL", clip: 17291, time: "1m 12s", cost: "$0.31" },
  { model: "Quarry", clip: 28088, time: "54s", cost: "$0.18" },
  { model: "Nimbus v4", clip: 31551, time: "27s", cost: "$0.06" },
];

const video = (id: number) => `https://assets.mixkit.co/videos/${id}/${id}-720.mp4`;
const poster = (id: number) => `https://assets.mixkit.co/videos/${id}/${id}-thumb-720-0.jpg`;

export function SyncGridModelsDemo() {
  return (
    <div className="w-full max-w-3xl">
      <div className="mb-4 flex items-center gap-3 rounded-2xl border border-zinc-200 bg-white px-3 py-2.5 shadow-sm dark:border-zinc-800 dark:bg-zinc-900">
        <span className="grid size-7 shrink-0 place-items-center rounded-lg bg-zinc-950 text-white dark:bg-white dark:text-zinc-950">
          <SparkIcon />
        </span>
        <p className="min-w-0 flex-1 truncate text-sm text-zinc-900 dark:text-zinc-100">{prompt}</p>
        <span className="hidden shrink-0 font-mono text-[11px] text-zinc-500 sm:block">4 outputs · 16:9</span>
      </div>

      <SyncGrid columns={2} duration={12}>
        {outputs.map((output) => (
          <SyncGridItem key={output.model} label={output.model} src={video(output.clip)} poster={poster(output.clip)}>
            <div className="absolute top-9 left-2.5 flex gap-1">
              <Stat>{output.time}</Stat>
              <Stat>{output.cost}</Stat>
            </div>
          </SyncGridItem>
        ))}
      </SyncGrid>
    </div>
  );
}

function Stat({ children }: { children: React.ReactNode }) {
  return (
    <span className="rounded-full bg-black/45 px-1.5 py-0.5 font-mono text-[10px] text-white/90 tabular-nums backdrop-blur-md">
      {children}
    </span>
  );
}

function SparkIcon() {
  return (
    <svg viewBox="0 0 16 16" aria-hidden className="size-3.5 fill-current">
      <path d="M8 1.5c.3 2.9 1.6 4.2 4.5 4.5-2.9.3-4.2 1.6-4.5 4.5-.3-2.9-1.6-4.2-4.5-4.5 2.9-.3 4.2-1.6 4.5-4.5ZM12.5 10c.15 1.4.75 2 2 2.1-1.25.15-1.85.75-2 2.15-.15-1.4-.75-2-2.1-2.15 1.35-.1 1.95-.7 2.1-2.1Z" />
    </svg>
  );
}
```
