AI Generate Overlay
A "thinking" overlay for AI-driven UI — source image blurs out under a shimmering dot grid while a glassy pill pulses, then the new image fades in on top.
The overlay you reach for any time you need to communicate "the model is working on it." The source image blurs from 0px to ~20px, a screen-blended SVG dot pattern shimmers in over the top with a tiny Math.sin(frame / 6) jitter, and a pill-shaped indicator with a backdrop-filtered glass background pulses in the center. When the spring-driven reveal fires, the generated image fades in over the blurred source and the pill (and grid) fades back out. Every layer is driven by the current frame so it renders deterministically — no setInterval, no random flicker.
Installation
$ pnpm dlx shadcn@latest add @remocn/ai-generate-overlayUsage
// src/Root.tsx
import { Composition } from "remotion";
import { AIGenerateOverlay } from "@/components/remocn/ai-generate-overlay";
const AIGenerateOverlayScene = () => (
<AIGenerateOverlay
maxBlur={20}
blurStartFrame={20}
blurPeakFrame={40}
revealStartFrame={110}
pillText="Generating…"
accent="#a78bfa"
/>
);
export const RemotionRoot = () => (
<Composition
id="AIGenerateOverlay"
component={AIGenerateOverlayScene}
durationInFrames={180}
fps={30}
width={1280}
height={720}
/>
);Props
| Prop | Type | Default | Description |
|---|---|---|---|
maxBlur | number | 20 | Peak blur radius in pixels applied to the source image. |
blurStartFrame | number | 20 | Frame at which the blur ramp and dot grid begin. |
blurPeakFrame | number | 40 | Frame at which the blur reaches `maxBlur` and the dot grid is fully on. |
revealStartFrame | number | 110 | Frame at which the spring-driven generated-image fade-in fires. |
pillText | string | "Generating…" | Label shown inside the centered glass pill. Trailing dots animate automatically. |
accent | string | "#a78bfa" | Accent color used for the pill's status dot and glow shadow. |
background | string | "#050505" | Page background visible behind both image layers. |
sourceImageBg | string | warm linear-gradient | CSS background for the source ("original") image layer. Pass any gradient or color. |
generatedImageBg | string | cool radial+linear | CSS background for the generated image layer that fades in. |
dotColor | string | "#ffffff" | Fill color of the SVG dot grid. |
dotSize | number | 1.2 | Radius of each dot in the grid. |
dotSpacing | number | 20 | Pattern tile size — controls the spacing between dots. |
speed | number | 1 | Playback speed multiplier for all timing values. |
className | string | — | Optional className passed to the root container. |
Notes
The dot grid jitter is Math.sin(frame / 6) * 0.05 — a pure function of the current frame. Don't be tempted to reach for Math.random() or setInterval; both will introduce mismatched output between preview and final render.
The defaults render two CSS gradients so the component is dependency-free, but in practice you'll pass sourceImageBg/generatedImageBg as url(...) strings (loaded via staticFile() in your scene) so the blur is applied to a real photo.
filter: blur(20px) on a viewport-sized layer is one of the costlier CSS effects. Keep the blurred layer on its own absolutely-positioned <div> (as it is here) so the browser can promote it and avoid re-layouting the rest of the scene each frame.