Noise Texture Background
Drifting film-grain overlay that gives any section tactile analog warmth — texture you feel more than see
backgroundnoisegraintextureanalog
Preview
Source Code
"use client";
interface NoiseTextureBackgroundProps {
children?: React.ReactNode;
opacity?: number;
baseFrequency?: number;
animated?: boolean;
blend?: React.CSSProperties["mixBlendMode"];
className?: string;
}
export default function NoiseTextureBackground({
children,
opacity = 0.15,
baseFrequency = 0.8,
animated = true,
blend = "soft-light",
className = "",
}: NoiseTextureBackgroundProps) {
const noiseUrl = `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='${baseFrequency}' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E")`;
const css = `
@keyframes ntb-drift {
0%, 100% { transform: translate(0, 0); }
12.5% { transform: translate(-3%, 2%); }
25% { transform: translate(2%, -4%); }
37.5% { transform: translate(-4%, -2%); }
50% { transform: translate(3%, 4%); }
62.5% { transform: translate(-2%, 3%); }
75% { transform: translate(4%, -3%); }
87.5% { transform: translate(-3%, -4%); }
}
.ntb-grain {
will-change: transform;
}
@media (prefers-reduced-motion: reduce) {
.ntb-grain { animation: none !important; }
}
`;
return (
<div className={`relative overflow-hidden bg-[#12100e] ${className}`}>
<style>{css}</style>
<div
aria-hidden="true"
className="ntb-grain pointer-events-none absolute -inset-[100%]"
style={{
backgroundImage: noiseUrl,
opacity,
mixBlendMode: blend,
animation: animated ? "ntb-drift 0.8s step-end infinite" : undefined,
}}
/>
<div className="relative z-10">{children}</div>
</div>
);
}