Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Shaders

Pro

Warped Noise Shader for React

Marbled swirls drawn on the GPU, like ink folding through milk: hot pink, deep plum and near-white, flowing slowly. For React with Base UI, when a hero or a creative page wants rich, liquid color that never repeats.

Framework

Warped Noise Shader fills its box with marbled, smoky swirls, like ink folding through milk. It's fractal noise warped through two more layers of itself, so the folds bunch up into dark ribbons with fine filaments along their edges, while the open water between them rises to pale pink and near-white. A five-color ramp, from deep plum through hot pink to milk, colors the result, and every layer drifts on its own slow current. A WGSL fragment shader on WebGPU draws every pixel each frame, for about a millisecond of GPU time.

Use it behind a hero, a creative portfolio or a launch that wants liquid color with no visible pattern. For the plain fractal noise without the folding, use Noise Shader; for rising plumes, Smoke Shader; for ink in plain CSS, with no GPU, the Ink background. It runs only while it's on screen, holds a still frame with reduced motion, and shows a soft gradient of the same colors in browsers without WebGPU.

Preview width

Installation

Part of Pro
Pro unlocks the code and one-line install of every Pro button and text effect, plus the MCP for your AI editor.
Have Pro already? Sign in to open it.Opens here as soon as you're Pro.

Usage

import { WarpedNoiseShader } from "@/components/ui/warped-noise-shader";
<WarpedNoiseShader className="flex min-h-[32rem] items-center justify-center">
  <div className="rounded-xl bg-black/60 px-8 py-6">
    <h1 className="text-5xl font-semibold text-white">Fluid by design</h1>
  </div>
</WarpedNoiseShader>

Warped Noise Shader is a container: your content sits on top of the swirls, in normal flow. It fills its own box, so give it a height or content. For a backdrop behind the whole page, render it empty with className="fixed inset-0 -z-10". The swirls run from near-black plum to near-white, so neither white nor black text reads on them bare: put copy on a panel, like the bg-black/60 one above, which keeps white text above 6:1 everywhere.

Demos

Lagoon

colors replaces the ramp: five CSS colors, from the dense folds to the brightest swirls. Here it runs from deep teal to mint and white. Keep the first color the darkest and the last the lightest, so the folds stay dark and the open swirls bright.

Preview width

In a card

warp={2} folds the noise harder, so the swirls tighten into fine marbling that reads at card size. quality={0.5} renders at half resolution: the field is soft, so you can't tell, and the GPU does a quarter of the work.

Preview width

Performance

About 1.1 ms of GPU time a frame at 1280×720 on an M2 Max laptop; slower GPUs take several times longer. quality={0.5} renders a quarter of the pixels, and the soft swirls look the same. The animation stops when the shader scrolls out of view, and the browser pauses it in a hidden tab. Every shader on a page shares one GPU device and one frame loop, and vgpu (about 50 KB gzipped) loads only when the first one mounts.

Browser support

The shader needs WebGPU: Chrome and Edge, Safari 26 and later, and Firefox on Windows and macOS. Elsewhere, and until the first frame, the box shows a CSS gradient of the same colors, so the layout never jumps. data-state on the root reads unsupported there, if you want to style around it. See Shader Canvas.

Accessibility

The swirls are decoration: they're hidden from assistive tech and let every click through to your content. With reduced motion it draws one still frame and stops. Nothing flashes: the folds drift and change over seconds. Text needs a panel: on the bare swirls, white text drops below 1.7:1 on the brightest twentieth of the frame and black text below 1.3:1 on the darkest. A bg-black/60 panel keeps white text above 6:1 everywhere.

FAQ

What is domain warping?

Instead of reading the noise at each pixel's own position, the shader first moves that position by another noise, and that noise was itself read at a moved position. The result is noise folded into itself: smooth areas stretch into ribbons, and the fine detail gathers along the folds, the way ink spreads through milk.

What does warp do?

warp sets how far each layer moves the next, from 0 to 3. At 0 the noise is plain soft clouds; at 1 it folds into smoky swirls; from 2 up it tightens into fine marbling. scale sets how big the swirls are, from 0.3 (one huge fold across the box) to 3 (many small ones), measured across the width.

How do I change the colors?

colors takes five CSS colors, from the dense folds to the brightest swirls, var(--primary) included, and they follow a theme switch. Keep them in order from dark to light. brightness scales the whole result, from 0.5 to 1.5; above 1 the light swirls clip to white.

Why does it look the same on light and dark pages?

It's opaque: the shader paints every pixel, so the page behind it never shows through. The ramp is the shader's own look in both color schemes. To follow your theme, pass theme colors to colors.

Will it slow my page down?

It costs about 1.1 ms of GPU time a frame at 1280×720 on a laptop: five layers of fractal noise per pixel, light for a shader. The CPU only sets a few numbers each frame, and it stops when it's off screen. On a slow GPU or a large screen, quality={0.5} renders a quarter of the pixels and looks the same.

What happens in browsers without WebGPU?

The box keeps its CSS gradient, pink with a plum shadow and a pale highlight in your colors, so the page still looks finished. Nothing errors: the root's data-state reads unsupported.

Credits

Inspired by trinketMage's warped noise (opens in a new tab) on Shadertoy. The code is ours, written from the general technique: Inigo Quilez's domain warping (opens in a new tab), on value noise with an integer hash (lowbias32, by Chris Wellons, public domain). The composition, the drift and the color ramp are new.

API Reference

WarpedNoiseShader

data-slot="warped-noise-shader"

PropType
brightness?number

Overall brightness, from 0.5 (dim) to 1.5 (bright). @default 1.

Default
1
colors?[string, string, string, string, string]

The colour ramp, five CSS colours from the dense folds to the brightest swirls. @default ["#2a0634", "#7a0d5c", "#e8177d", "#f78fdc", "#fff3fa"].

Type
[string, string, string, string, string]
Default
DEFAULT_COLORS
fallback?string

What shows until the first frame and in browsers without WebGPU: a CSS background value (gradients, sizes, a colour) that looks like the shader. It can use the colour props' --shader-<field> variables.

interactive?boolean

Whether u.pointer follows the pointer. @default false.

paused?boolean

Holds the current frame. @default false.

quality?number

Render scale, from 0.25 to 1, of the screen's pixels (capped at 2×). @default 1.

scale?number

How big the swirls are, from 0.3 (one huge fold) to 3 (many small ones). @default 1.

Default
1
speed?number

Animation speed: 1 is normal, 0 holds the frame. @default 1.

time?number

A fixed moment, in seconds: draws it and doesn't animate.

warp?number

How far the noise folds into itself, from 0 (soft clouds) to 3 (tight marbling). @default 1.

Default
1
render?ReactElement | ((props: object, state: object) => ReactElement)

Replace the host element or compose it with another component.

Type
ReactElement | ((props: object, state: object) => ReactElement)
className?string

Forwarded to the part.

All 101 shaders