# Paint Reveal: Work Grid

> A portfolio grid in grayscale, with a smaller brush on each card. Only the card under the pointer draws anything, and `autoPlay={false}` keeps the grid still on phones.

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

- Page, with a live preview: https://shadcn.exchange/r/keyframeui/paint-reveal-work-demo
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/keyframeui/paint-reveal-work-demo-light-7100fc5b327d924c.png
- Registry item: https://keyframeui.com/r/paint-reveal-work-demo.json
- Categories: image, hover, canvas
- Listed: 2026-10-15, source last changed 2026-10-15

## Install

```bash
npx shadcn@latest add https://keyframeui.com/r/paint-reveal-work-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/paint-reveal.json`

## Notes from the registry

Live preview, examples and props: https://keyframeui.com/components/paint-reveal#paint-reveal-work-demo

## Files

### `registry/demos/paint-reveal-work-demo.tsx`

```tsx
import { PaintReveal } from "@/components/ui/paint-reveal";

const projects = [
  { client: "Nordlys", kind: "Holiday homes", year: 2026, photo: "1600607687939-ce8a6c25118c" },
  { client: "Atelier Sund", kind: "Brand identity", year: 2025, photo: "1515886657613-9f3515b0c78f" },
  { client: "Kvarter", kind: "Office fit-out", year: 2025, photo: "1524758631624-e2822e304c36" },
  { client: "Fjell", kind: "Campaign", year: 2024, photo: "1506905925346-21bda4d32df4" },
];

const photo = (id: string, grade = "") =>
  `https://images.unsplash.com/photo-${id}?auto=format&fit=crop&w=900&h=675&q=80${grade}`;

export function PaintRevealWorkDemo() {
  return (
    <section className="w-full max-w-4xl">
      <div className="mb-6 flex items-end justify-between gap-6">
        <h2 className="text-2xl font-semibold tracking-tight text-zinc-900 sm:text-3xl dark:text-zinc-50">
          Selected work
        </h2>
        <a href="#" className="text-sm text-zinc-500 transition-colors hover:text-zinc-900 dark:hover:text-zinc-100">
          All projects →
        </a>
      </div>
      <ul className="grid gap-x-5 gap-y-8 sm:grid-cols-2">
        {projects.map((project) => (
          <li key={project.client}>
            <a href="#" className="group block">
              <PaintReveal
                src={photo(project.photo, "&sat=-100&con=6")}
                alt={`${project.client}: ${project.kind}`}
                revealSrc={photo(project.photo)}
                brushSize={130}
                softness={0.6}
                fadeMs={700}
                autoPlay={false}
                className="aspect-[4/3] w-full rounded-lg"
              />
              <div className="mt-3 flex items-baseline justify-between gap-4 text-sm">
                <span className="font-medium text-zinc-900 dark:text-zinc-100">{project.client}</span>
                <span className="text-zinc-500 tabular-nums">
                  {project.kind} · {project.year}
                </span>
              </div>
            </a>
          </li>
        ))}
      </ul>
    </section>
  );
}
```
