WebberUI

Iridescence

An iridescent shifting-wave shader background — a canvas 2D approximation of an iridescence shader, with optional mouse response.

A canvas 2D approximation of the classic iridescence shader's shifting waves, computed cell by cell and stretched with interpolation — no WebGL required.

Loading preview…
npx shadcn@latest add https://webberui.com/r/iridescence.json

Playground

Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.

1
0.1
96
<Iridescence />

Installation

npx shadcn@latest add https://webberui.com/r/iridescence.json

Or, once registries are configured in components.json, install it as @webberui/iridescence.

Usage

Put your foreground content in children, and write the layout (centering, height) on className:

import { Iridescence } from "@/components/ui/iridescence";

<Iridescence className="flex h-[360px] items-center justify-center rounded-2xl">
  <h1 className="text-4xl font-bold text-white">Hero heading</h1>
</Iridescence>

Custom tint, slower speed, and mouse response enabled:

<Iridescence
  color={[1, 1, 1]}
  speed={0.6}
  mouseReact
  amplitude={0.2}
  className="flex h-[400px] items-center justify-center rounded-2xl"
>
  <p className="text-lg text-white">The full iridescent spectrum</p>
</Iridescence>

color is an RGB tint with each channel in 0~1, and the whole image is multiplied by it: [1, 1, 1] keeps the full iridescence, and the darker it gets the more it converges on a single hue.

Props

PropTypeDefaultDescription
color[number, number, number]A cool cyan-violetOverall tint, each channel 0~1; [1, 1, 1] is full iridescence
speednumber1Wave speed multiplier
amplitudenumber0.1How strongly the mouse offset affects the pattern (applies when mouseReact is on)
mouseReactbooleanfalseWhether the pattern shifts with the mouse (mouse pointers only; touch has no effect)
detailnumber96Internal sampling edge length (px) — higher is finer but more expensive
childrenReact.ReactNodeForeground content, layered above the iridescence
classNamestringAppended to the outermost container's className

How it works

  • No WebGL. The shader output is computed cell by cell over a downsampled grid, written into ImageData, and then stretched by the canvas with h-full w-full, relying on the browser's built-in bilinear interpolation to fill it in as smooth iridescence — avoiding heavy dependencies like three.js
  • The longer edge is fixed at detail and the shorter edge scales by the container's aspect ratio, which means the sampling count adapts to the aspect ratio and the pattern never distorts
  • The drawing loop is created once on mount, and props like color / speed are read live through refs, so changing a parameter never rebuilds the loop or causes a flicker
  • A ResizeObserver watches for container size changes and reallocates the grid; on unmount it calls cancelAnimationFrame and stops observing
  • With mouseReact on, the cursor position is normalized to 0~1 and, scaled by amplitude, translates the sampling coordinates so the pattern follows along; it only applies when pointerType === "mouse"
  • The whole background canvas is pointer-events-none and sits at -z-10 beneath the content (the container has isolate to create its own stacking context), so foreground interaction is completely unaffected
  • When the user has "reduce motion" enabled at the system level, only a single static frame of iridescence is drawn, the animation loop never starts, and the DOM structure is unchanged

On this page