Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Shaders

Free

Fluted Glass Shader for React

Soft coral and violet color drifting behind a panel of reeded glass, each rib squeezing and mirroring what's behind it, drawn on the GPU. For React with Base UI, when a SaaS hero or a pricing card wants the fluted-glass look in your own colors.

Framework

Fluted Glass Shader drifts three soft color fields, coral, violet and a peach glow, behind a panel of vertical reeded glass. Each rib is a small cylinder lens: it squeezes a wide slice of the color beneath it into its own width and flips it toward its edges, so a smooth gradient breaks into ribbed bands. A soft groove shadow sits between the ribs and a thin highlight runs down each one. A WGSL fragment shader on WebGPU draws every pixel each frame: the colors blend in OKLab, so their mixes stay bright rather than muddy, and red, green and blue bend by slightly different amounts, which fringes the rib edges.

Use it behind a SaaS hero, a launch page or a pricing card, and pass your brand's colors. For clear drops that bend a ruled page instead, use Liquid Glass Shader; for the bare color fields with no glass, in plain CSS, the Mesh Gradient background. It runs only while it's on screen, holds a still frame with reduced motion, and shows the same colors behind a CSS rib pattern in browsers without WebGPU.

Preview width

Installation

Sign in to get your install command
Free with an account. It carries your token, so the CLI installs everything in one go.

Usage

import { FlutedGlassShader } from "@/components/ui/fluted-glass-shader";
<FlutedGlassShader className="flex min-h-[32rem] items-center justify-center">
  <h1 className="text-5xl font-semibold text-white">Ship faster</h1>
</FlutedGlassShader>

Fluted Glass Shader is a container: your content sits on top of the glass, 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".

On the default dark ground, use white text. It reads at 10:1 on half the frame, but the peach and coral glows are bright: over them white falls to about 2:1, so keep white for large headlines there, or set the copy on a panel. In the lower 40% of the box, white keeps about 4.5:1 or better on 99% of pixels. On a light backgroundColor, use dark text.

Demos

In a card

colors takes your theme's variables, here var(--chart-1), var(--chart-3) and var(--chart-5), and the glass follows a theme switch. ribs={16} sets wider ribs for a small surface; the ribs are counted across the box, so they keep their number at any size.

Preview width

Horizontal, on light

angle={90} turns the ribs horizontal, like a frosted partition, and backgroundColor="#f6f1ea" sets the colors on warm paper. The fields blend over the ground in OKLab, so the light version stays clean and pastel.

Preview width

Performance

About 0.2 ms of GPU time a frame at 1280×720 on an M2 Max laptop; slower GPUs take several times longer. The rib edges are crisp, so it renders at full resolution; quality={0.5} softens them. 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 behind vertical ribs, 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 glass is decoration: it's hidden from assistive tech and lets every click through to your content. With reduced motion it draws one still frame and stops. Nothing flashes: the colors drift across the ribs over tens of seconds. For text contrast, see Usage: white text reads on the dark ground and the violet, less so on the coral and peach glows.

FAQ

Can I use my brand colors?

Yes. colors takes up to three CSS colors, theme variables included, such as ["var(--primary)", "var(--chart-2)", "#ffc48a"]; with fewer, they repeat. backgroundColor sets the ground, and intensity the saturation, from 0 (grey) to 2. Theme variables follow a theme switch.

How do I change the ribs?

ribs sets how many fit across the box, from 8 (wide flutes) to 96 (fine reeding), and angle their direction in degrees, 0 vertical and 90 horizontal. refraction sets how hard each rib bends the color, from 0 (flat glass, just grooves) to 2.

What do frost and dispersion do?

frost scatters each pixel's view a little, which gives the glass a fine frosted grain, from 0 (clear) to 1. dispersion bends red, green and blue by slightly different amounts, which puts thin rainbow fringes on the rib edges, from 0 to 1.

Can the ribs refract my page content?

No. The shader draws its own color fields and bends those: WebGPU can't read the HTML behind the canvas. For a fluted panel over real content, CSS backdrop-filter with a repeating gradient mask is the closest you'll get.

Will it slow my page down?

It costs about 0.2 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. ribs doesn't change the cost; the resolution does.

What happens in browsers without WebGPU?

The box keeps its CSS gradient: the same three colors, in your colors and backgroundColor, behind vertical ribs. Nothing errors: the root's data-state reads unsupported.

API Reference

FlutedGlassShader

data-slot="fluted-glass-shader"

PropType
angle?number

The direction of the ribs in degrees, from -90 to 90: 0 is vertical, 90 horizontal. @default 0.

Default
0
backgroundColor?string

The ground behind the colour. Any CSS colour. @default "#120f1a".

Default
"#120f1a"
colors?string[]

The three colour fields behind the glass, any CSS colours; fewer repeat. @default ["#ff6a3d", "#7c5cff", "#ffc48a"].

Default
COLORS
dispersion?number

The rainbow split at each rib's edges, from 0 (none) to 1. @default 0.25.

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

frost?number

A frosted grain in the glass, from 0 (clear) to 1. @default 0.2.

Default
0.2
intensity?number

Colour saturation, from 0 (grey) to 2 (vivid). @default 1.

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

refraction?number

How strongly each rib squeezes and mirrors the colour, from 0 (flat) to 2. @default 1.

Default
1
ribs?number

How many ribs fit across the box, from 8 to 96. @default 32.

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

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