# Noise Grain Vignette — Animated React Background

> Flickering film grain over a warm centre glow with darkened corners, like a projected still; grain jumps in steps, never tweens.

- Category: [Backgrounds](https://pixelpapa.com/components/backgrounds.md)
- Tags: background, noise, grain, vignette, film
- Dependencies: none (plus React and Tailwind CSS v4)
- Last updated: 2026-11-13
- Live preview: https://pixelpapa.com/components/backgrounds/bg-noise-grain-vignette

## Install

```bash
npx shadcn@latest add "https://pixelpapa.com/r/bg-noise-grain-vignette.json"
```

The file is written to `components/pixelpapa/bg-noise-grain-vignette.tsx`. To install manually, copy the source below into your project. It imports `cn` from `@/lib/utils`, which every shadcn project has.

## Source

```tsx
"use client";

import type { ReactNode } from "react";
import { cn } from "@/lib/utils";

type NoiseGrainVignetteProps = {
  children?: ReactNode;
  className?: string;
  /** Grain strength, 0–1. */
  grain?: number;
  /** Corner darkness, 0–1. */
  vignette?: number;
  /** Colour of the glow behind the content. Any CSS colour. */
  glow?: string;
  /** Flicker the grain. Turn off for a static texture. */
  animated?: boolean;
};

const NOISE =
  "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.8' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 .5 0 0 0 0 .5 0 0 0 0 .5 0 0 0 1.4 -.25'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E\")";

export function NoiseGrainVignette({
  children,
  className,
  grain = 0.5,
  vignette = 0.5,
  glow = "var(--primary)",
  animated = true,
}: NoiseGrainVignetteProps) {
  return (
    <div className={cn("relative isolate overflow-hidden bg-background", className)}>
      <style>{`
        @keyframes pp-bg-noise-grain-vignette-jitter {
          0% { transform: translate3d(0, 0, 0); }
          12% { transform: translate3d(-6%, 4%, 0); }
          25% { transform: translate3d(5%, -7%, 0); }
          37% { transform: translate3d(-3%, -4%, 0); }
          50% { transform: translate3d(7%, 6%, 0); }
          62% { transform: translate3d(-7%, 2%, 0); }
          75% { transform: translate3d(3%, 7%, 0); }
          87% { transform: translate3d(-5%, -6%, 0); }
          100% { transform: translate3d(0, 0, 0); }
        }
        @media (prefers-reduced-motion: reduce) {
          .pp-bg-noise-grain-vignette-grain { animation: none !important; }
        }
      `}</style>
      <div aria-hidden className="pointer-events-none absolute inset-0 -z-10">
        {/* Glow: one large ellipse above centre, one small hot core. */}
        <div
          className="absolute inset-0 opacity-25 dark:opacity-35"
          style={{ background: `radial-gradient(60% 55% at 50% 42%, ${glow}, transparent 70%)` }}
        />
        <div
          className="absolute inset-0 opacity-20 dark:opacity-25"
          style={{ background: `radial-gradient(24% 22% at 50% 44%, ${glow}, transparent 70%)` }}
        />
        {/* Vignette: ink-coloured in light mode, pure black in dark. */}
        <div
          className="absolute inset-0 [--pp-vignette:oklch(0.3_0.06_265)] dark:[--pp-vignette:black]"
          style={{
            opacity: vignette,
            background:
              "radial-gradient(ellipse 75% 70% at 50% 45%, transparent 45%, color-mix(in oklch, var(--pp-vignette) 45%, transparent) 90%, var(--pp-vignette) 145%)",
          }}
        />
        {/* Grain: an oversized tile that jumps between offsets, so no two frames line up. */}
        <div
          className="pp-bg-noise-grain-vignette-grain absolute -inset-[20%] mix-blend-multiply dark:mix-blend-screen"
          style={{
            opacity: grain,
            backgroundImage: NOISE,
            backgroundSize: "220px 220px",
            animation: animated ? "pp-bg-noise-grain-vignette-jitter 0.9s steps(1) infinite" : undefined,
          }}
        />
      </div>
      {children}
    </div>
  );
}

export default function NoiseGrainVignetteDemo() {
  return (
    <NoiseGrainVignette className="flex min-h-screen w-full flex-col items-center justify-center px-6">
      <p className="font-mono text-xs tracking-[0.35em] text-muted-foreground uppercase">Reel 03 · 35mm · 1.85:1</p>
      <h2 className="mt-6 max-w-3xl text-center font-serif text-6xl leading-[1.02] tracking-tight text-foreground sm:text-8xl">
        The long <em className="text-primary">quiet</em> between takes
      </h2>
      <p className="mt-6 max-w-md text-center text-muted-foreground">
        A short film about a lighthouse keeper, a broken radio and the forty minutes before the tide comes back.
      </p>
      <div className="mt-9 flex items-center gap-6 font-mono text-xs tracking-widest text-muted-foreground uppercase">
        <span>Written by Ines Okafor</span>
        <span className="h-3 w-px bg-border" />
        <span>Premieres 14 March</span>
      </div>
    </NoiseGrainVignette>
  );
}
```

## AI prompt

```text
Add the "Noise Grain Vignette" component from PixelPapa UI to this project.

What it is: Flickering film grain over a warm centre glow with darkened corners, like a projected still; grain jumps in steps, never tweens.
Category: Backgrounds. Depends on: no extra packages.

1. Install it with the shadcn CLI:
   npx shadcn@latest add "https://pixelpapa.com/r/bg-noise-grain-vignette.json"
   (If the CLI is unavailable, fetch that URL, write files[0].content to components/pixelpapa/bg-noise-grain-vignette.tsx and install the listed dependencies.)
2. Import it from "@/components/pixelpapa/bg-noise-grain-vignette" and place it where I describe below.
3. Keep its animation timings and accessibility attributes. Replace the demo copy and data with content that fits my product, and use my existing theme tokens (bg-background, text-foreground, bg-primary, border-border) rather than hard-coded colours.

Where to use it: <describe the page and position here>
```

## More backgrounds

- [Animated Grid Lines](https://pixelpapa.com/components/backgrounds/bg-animated-grid-lines.md) (Pro): A perspective floor of grid lines that scrolls toward the viewer forever, with light pulses racing down a few of the lines.
- [Aurora Background](https://pixelpapa.com/components/backgrounds/aurora-background.md): Slow drifting colour ribbons behind your content, built from blurred gradients with no canvas.
- [Beams Light Rays](https://pixelpapa.com/components/backgrounds/bg-beams-light-rays.md) (Pro): Soft light rays fan out from above and sway a few degrees while breathing in brightness, with dust motes drifting through them.
- [Dot Grid Spotlight](https://pixelpapa.com/components/backgrounds/bg-dot-grid-spotlight.md) (Pro): A quiet dot grid where a soft light trails the cursor and swells the dots it passes over; it wanders on its own when idle.
- [Flow Field](https://pixelpapa.com/components/backgrounds/bg-flow-field.md) (Pro): Hundreds of canvas particles ride a slowly shifting vector field and leave fading silk trails in your theme colours.
- [Gradient Mesh Blobs](https://pixelpapa.com/components/backgrounds/bg-gradient-mesh-blobs.md): Five saturated blobs wander on separate looping paths and melt into a mesh gradient, while one extra blob follows the cursor on a spring.
