Shader gradient background
Flowing light in the accent color and its neighbours, drawn live with WebGL. Folds like silk, follows the pointer and the scroll, with a still picture as fallback.
Soft light that never repeats
A shader gradient lets light flow slowly in the accent color of your theme and its neighbours, drawn live with WebGL instead of a heavy video. A scrim keeps text readable on every frame, and a still picture stands in where WebGL is missing or motion is reduced.
Hero background fills a full hero panel with soft light behind a centered headline. Section band runs a full width band with figures, the light pools on the right. Featured card lets the light live in one card of a grid and marks the feature that matters most. Behind a call to action uses strong, slower light that fills the closing panel of a page.
Use the gradient once per page, a hero or a closing panel, and keep the sections between them calm. It takes your accent color by itself, so a brand change needs no new asset.
Details
What Shader gradient brings along, read from the registry and the source.
- Category
- 3D backgrounds
- Area
- Visuals
- Variants
- 4
- Version
- 1.0.0 · since 1.2.0
- File
- components/ui/shader-gradient.tsx
- Brings along
- utilskitwebgl
- npm packages
- None
- Languages
- Texts come through props
- Studio
- Adjust in code
- In collections
- 3D and motion
- Build with AI
- Over MCP in Claude, Cursor, Copilot and Codex
Props
The ShaderGradientProps interface from components/ui/shader-gradient.tsx, with the comments from the code. Also takes every prop of ShaderLayerProps.
zoomoptionalnumberSize of the folds, 1 is the designed scale, 2 twice as many
grainoptionalbooleanFine film grain against banding, default true
sheenoptionalnumberBright seams where the folds turn, default 1, 0 is off
Accessibility
Read from the source of the component.
- Needs no client state. The server writes it in full, so it reads without JavaScript too.
Motion
- No animations, it stands still from the start.
Source
The file aiw add puts into your project. From then on it is yours.
Show the file, 79 lines
'use client';
import { ACCENT_PALETTE, GLSL_NOISE, ShaderBackdrop, ShaderCanvas, type ShaderLayerProps } from '@/components/ui/webgl';
/*
* Flowing light in the accent color and its two neighbours on the color
* wheel. Domain warped noise: the noise bends its own coordinates twice, so
* the light folds like silk instead of drifting like clouds. Soft by nature,
* so it renders at half resolution and stays cheap.
*/
export interface ShaderGradientProps extends ShaderLayerProps {
/** Size of the folds, 1 is the designed scale, 2 twice as many */
zoom?: number;
/** Fine film grain against banding, default true */
grain?: boolean;
/** Bright seams where the folds turn, default 1, 0 is off */
sheen?: number;
}
const FRAG = `${GLSL_NOISE}
uniform float u_zoom;uniform float u_grain;uniform float u_sheen;
void main(){
vec2 p=(gl_FragCoord.xy-.5*u_res)/min(u_res.x,u_res.y)*1.35*u_zoom;
float t=u_time*.055;
p+=(u_mouse-.5)*.3*u_hover;
p.y+=(u_scroll-.5)*.5;
vec2 q=vec2(fbm(p+vec2(0.,t)),fbm(p+vec2(5.2,1.3)-t));
vec2 r=vec2(fbm(p+1.9*q+vec2(1.7,9.2)+.7*t),fbm(p+1.9*q+vec2(8.3,2.8)-.5*t));
float f=fbm(p+1.7*r);
vec3 c=mix(u_c0,u_c1,smoothstep(.3,.75,f));
c=mix(c,u_c2,smoothstep(.4,.85,r.x)*.85);
float s=pow(1.-abs(f*2.-1.),7.)*u_sheen;
c=mix(c,u_c3,smoothstep(.55,.95,q.y)*.5+s*.45);
float a=smoothstep(.12,.82,f*1.15+r.y*.35)*.8+.2;
a*=mix(.5,.92,u_dark)*u_intensity;
c+=(hash(gl_FragCoord.xy+fract(u_time*7.))-.5)*.035*u_grain;
a=clamp(a,0.,1.);
gl_FragColor=vec4(c*a,a);
}`;
/** The still picture: three soft pools of the same colors */
const FALLBACK = [
'radial-gradient(55% 65% at 18% 28%, color-mix(in oklab, var(--primary) 46%, transparent), transparent 72%)',
'radial-gradient(48% 60% at 82% 22%, color-mix(in oklab, oklch(from var(--primary) l c calc(h + 46)) 40%, transparent), transparent 70%)',
'radial-gradient(70% 60% at 58% 92%, color-mix(in oklab, oklch(from var(--primary) l c calc(h - 52)) 38%, transparent), transparent 72%)',
].join(', ');
/**
* Flowing gradient light behind any content. With children it renders a box
* (give it size and radius through className), without children only the
* layer for a `relative` parent.
*/
export function ShaderGradient({ intensity = 1, speed = 1, colors, interactive = true, zoom = 1, grain = true, sheen = 1, fallback, scrim = 'soft', scrimStrength, scrimColor, children, className, contentClassName, layerClassName }: ShaderGradientProps) {
return (
<ShaderBackdrop
scrim={scrim}
scrimStrength={scrimStrength}
scrimColor={scrimColor}
className={className}
contentClassName={contentClassName}
layer={
<ShaderCanvas
fragment={FRAG}
colors={colors ?? ACCENT_PALETTE}
uniforms={{ u_zoom: zoom, u_grain: grain ? 1 : 0, u_sheen: sheen }}
speed={speed}
intensity={intensity}
scale={0.5}
pointer={interactive}
fallback={fallback ?? FALLBACK}
className={layerClassName}
/>
}
>
{children}
</ShaderBackdrop>
);
}Frequent questions
How do I install Shader gradient?
With aiw add @ai-website/shader-gradient. The command puts components/ui/shader-gradient.tsx into your project, the code is yours from then on. It brings along webgl. It needs no further npm packages.
Which variants does Shader gradient have?
4 variants, Hero background, Section band, Featured card and Behind a call to action.
Can an AI assistant build with Shader gradient?
Yes. Through the MCP server of the aiw CLI, Claude, Cursor, GitHub Copilot, Windsurf, Codex and Gemini find Shader gradient with aiw_components and install it with aiw_add @ai-website/shader-gradient.