Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Shaders

Pro

Chiffon Shader for React

Sheer chiffon drawn on the GPU: blush, lilac and ivory layers billowing in a slow breeze before a soft window light. For React with Base UI, when a bridal, beauty or wellness page wants a light, airy hero.

Framework

Chiffon Shader hangs three sheer layers of chiffon, blush, lilac and ivory, in front of a soft window light, and lets a slow breeze from the left billow them. Each layer is translucent: you see the room and the other layers through it, tinted by its color, and it turns denser and brighter where it folds back on itself, glowing most where the window shines through. Where layers overlap, their fine weave beats into a delicate moiré. A WGSL fragment shader on WebGPU draws the three sheets back to front, for about a millisecond of GPU time.

Use it as the hero of a bridal, beauty, wellness or fashion page: it's one of the few light shaders, made for a light page. For heavy, opaque satin, use Drapery Shader; for soft silk color in plain CSS, with no GPU, the Silk background. It runs only while it's on screen, holds a still frame with reduced motion, and shows a soft CSS gradient of the same layers 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 { ChiffonShader } from "@/components/ui/chiffon-shader";
<ChiffonShader className="flex min-h-[32rem] items-center justify-center">
  <h1 className="text-5xl font-semibold text-zinc-900">Made to be worn</h1>
</ChiffonShader>

Chiffon Shader is a container: your content sits on top of the layers, 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". It's light in both color schemes, so use dark text: near-black stays above 7:1 everywhere on it. With a dark backgroundColor, as in the night demo, switch to light text.

Demos

At night

backgroundColor="#120f18" turns the room dark. The window goes dark with it, and the layers glow only where light shines through them, brightest in their folds; intensity={1.4} turns that backlight up.

Preview width

In a card

layers={2} keeps the blush and lilac layers and drops the ivory one, so a small box stays simple, and wind={0.6} slows the breeze. It keeps full quality: the weave is a few pixels fine, and at half resolution it fades out.

Preview width

Performance

About 1 ms of GPU time a frame at 1280×720 on an M2 Max laptop, with three layers; fewer layers cost less. quality={0.5} renders a quarter of the pixels, but the weave then fades out, so the moiré goes with it. 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 soft CSS bands of the same colors on the room's color, 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 layers 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 layers billow over seconds, and the weave fades out before it can shimmer. Dark text reads everywhere on the default look: near-black text stays above 9:1 on 99% of the frame and above 7:1 on the deepest fold; white text doesn't read on it.

FAQ

How are the layers drawn?

Each layer is a sheet that streams in from the left and fans out, displaced by ripples that travel with the wind and a slow simplex billow. Its opacity comes from how steeply it turns away from you, 1 − exp(−σ / |n.z|), so folds read as thicker cloth. The three sheets are blended back to front: each tints what's behind it and adds its own light, more where the window shines through.

Where does the moiré come from?

Each layer carries a weave: two fine cosine gratings, 4 CSS pixels apart, that ride on its folds. Where two layers overlap, their gratings sit at slightly different angles and spacings, and they beat into soft moiré bands, as real sheers do. moire sets how clearly the weave shows, from 0 (smooth) to 1. Where a grating would get finer than a pixel, it fades out instead of flickering.

What do layers, wind and intensity do?

layers shows 1, 2 or 3 sheets, front first. wind sets the breeze, from 0 (the layers hang still) to 2 (gusty), and intensity how brightly the window light shines through them, from 0 to 2.

Can I change the colors?

Yes: colors takes three CSS colors, front layer first, and backgroundColor sets the room behind them, var(--background) included. Pale tints keep the chiffon sheer; a dark room turns it into a night scene where only the backlit folds glow.

Will it slow my page down?

It costs about 1 ms of GPU time a frame at 1280×720 on a laptop, and the CPU only sets a few numbers each frame. It stops when it's off screen. On a slow GPU, layers={2} costs less; quality={0.5} saves more but loses the weave.

What happens in browsers without WebGPU?

The box keeps its CSS gradient, soft bands of your layer colors over the room's color, so the page still looks finished. Nothing errors: the root's data-state reads unsupported.

API Reference

ChiffonShader

data-slot="chiffon-shader"

PropType
backgroundColor?string

The room behind the layers. Any CSS colour. @default "#f4ece6".

Default
"#f4ece6"
colors?[string, string, string]

The layers' tints, front to back. Any CSS colours. @default ["#f6c6cf", "#c9b8f0", "#fff3e6"].

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.

intensity?number

How brightly the window light shines through the layers, from 0 to 2. @default 1.

Default
1
interactive?boolean

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

layers?1 | 2 | 3

How many layers, from 1 to 3: the first colours, front first. @default 3.

Type
1 | 2 | 3
Default
3
moire?number

How clearly the fine weave shows, and its moiré where layers overlap, from 0 to 1. @default 0.3.

Default
0.3
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.

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.

wind?number

How hard the breeze blows, from 0 (still) to 2 (gusty). @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