RemotionUI

Animated Noise Grain

Film grain that boils, without generating noise per frame. Install with npx remotion-ui@latest add animated-noise-grain.

PrimitivePrimitives

animated-noise-grain30fps · 960×540
Install
$ npx remotion-ui@latest add animated-noise-grain

An emulsion pass for anything that looks too clean.

import { AnimatedNoiseGrain } from "@/remotion/primitives/animated-noise-grain";

<AnimatedNoiseGrain opacity={0.18}>
  <YourScene />
</AnimatedNoiseGrain>

Pass children to grain a subtree, or drop it into a stack with no children to grain everything beneath it.

How the noise is made once

The noise itself is a single stitched feTurbulence tile baked into a data URI. The browser rasterises that URL the first time it decodes it and then caches it like any other image — and because the URL depends only on props, never on frame, a 300-frame render rasterises it once.

What changes every step is where the tile is sampled from and which way it is flipped: a hashed sub-tile offset plus one of four mirrorings. The tile stitches, so the offset wraps invisibly, and the flip breaks the translation so the eye reads new grain rather than a sliding texture.

What that saves

Rendering this page's 120-frame preview at 960x540:

VariantWall clockCPU
No grain7.5s20s
Grain, cached tile (shipped)15.7s78s
Grain, feTurbulence re-seeded every frame27.8s144s

Two things to read out of that. Regenerating the noise per frame nearly doubles the render again — which is the whole reason for the cached tile. And grain is not free even when it is cached: it takes the encoder from a 206 kB file to a 15.1 MB one, because noise is incompressible. Most of the gap between the first two rows is H.264, not rendering. Budget for the bitrate, not just the frames.

Blend mode matters more than opacity

overlay is the default and the right choice over footage — it pivots around mid grey and leaves the extremes alone. Over a near-black plate it does nothing at all, because there is nothing to modulate. Use screen there: it lifts the blacks, which is both what makes the grain visible and what grain does in the shadows of a real print.

This is worth knowing because the failure is silent. The first cut of this page's preview measured as a completely static frame while the component was working perfectly.

Stock

holdInFrames is the film-stock control. Grain that changes on every frame of a 30fps render looks like video noise; holding each pattern for two frames gives the coarser chatter of film shot at 15fps.

size and density set the grain's coarseness. vignette adds a second, edge-masked pass, because real film grain is heaviest away from the centre — an even field of grain reads as a digital filter.

For phosphor rather than emulsion, see scanline-crt. The two stack.

The noise is one stitched `feTurbulence` tile baked into a data URI, so the browser rasterises it once for the whole render. Per-frame variation comes from a hashed sub-tile offset plus one of four mirrorings — never from regenerating noise. Rendering the preview costs about 3% more per frame than the same frame without it.

Agent notes

Install first, then import the copied source component locally. AI guide →

Import
@/remotion/primitives/animated-noise-grain
  • Use when: frame-level motion primitives and reusable animation wrappers.
  • Customize: opacity, size, density, detail, plus copied source for timing, layout, colors, and typography.
  • Rule: do not import this component from the remotion-ui npm package; it is copied into your project.

Usage

Example
import { AnimatedNoiseGrain } from "@/remotion/primitives/animated-noise-grain"; <AnimatedNoiseGrain opacity={0.18}> <YourScene /> </AnimatedNoiseGrain>

API Reference

PropTypeDescription
childrenReactNodeContent the grain sits over. Omit to use it as a bare overlay.
opacitynumberGrain strength. Film sits around 0.12-0.25; above 0.4 reads as damage.
sizenumberTile size on screen, in px. Larger grain is coarser and cheaper.
densitynumberNoise frequency inside the tile. Higher is finer.
detailnumberOctaves of noise. 1 is smooth, 4 is gritty.
holdInFramesnumberFrames each pattern is held. 2 gives the 15fps chatter of film.
blendModeCSS mix-blend-modeHow the grain composites. Use `screen` over a near-black plate — overlay pivots on mid grey and does nothing to blacks.
coloredbooleanKeep the noise coloured instead of desaturating it to silver.
vignettenumberExtra grain in the corners, where film grain actually lives.
seednumberChanges the pattern without changing any other prop.

Related

On this page