Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Shaders

Pro

Truchet Shader for React

A folded-paper mosaic drawn on the GPU: squares cut on a diagonal meet in triangles and chevrons, shaded along a gradient that sweeps across them as the grid drifts. For React with Base UI, when a hero, a launch or a brand page wants bold geometry in color.

Framework

Truchet Shader tiles the frame with Sébastien Truchet's oldest tile: a square cut on its diagonal, laid in one of four turns at random, so the halves meet in triangles, chevrons and zigzags. Each half is a facet folded up from the crease, with a linear ramp along a three-color gradient and a tilt that catches a light from the upper left, so the mosaic looks like folded paper. The gradient, indigo to rose to amber, sways slowly across the tiles while the grid drifts diagonally and turns; a WGSL fragment shader on WebGPU draws every pixel each frame, four samples per pixel, so the creases stay crisp.

Use it behind a hero, a launch or a brand page that wants bold, colorful geometry. For black-and-white line art with depth, use Truchet Kaleidoscope Shader; for woven arcs on a triangle grid, Simplex Truchet Weave Shader. It runs only while it's on screen, holds a still frame with reduced motion, and shows a CSS checker of facets over the same gradient 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 { TruchetShader } from "@/components/ui/truchet-shader";
<TruchetShader className="flex min-h-[32rem] items-center justify-center">
  <div className="rounded-xl bg-black/50 px-8 py-6 backdrop-blur-sm">
    <h1 className="text-5xl font-semibold text-white">Ship faster</h1>
  </div>
</TruchetShader>

Truchet Shader is a container: your content sits on top of the mosaic, 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 gradient runs from dark to light, so no text color reads on it bare everywhere: a bg-black/50 panel keeps white text above 4.7:1 over the whole frame, and bg-black/60 above 6.6:1; a bg-white/70 panel keeps black text above 10:1.

Demos

Lagoon

fromColor, viaColor and toColor are the gradient's three stops, here navy, teal and pale mint. scale={1.6} fits more, smaller tiles, and spread={0.6} stretches the gradient so one wide sweep crosses the frame.

Preview width

In a card

The mosaic scales with its box: the tile count follows the height. scale={0.75} makes bigger tiles that read at card size, and shading={1.5} deepens the folds. It keeps full quality: the creases are sharp and go soft at half resolution, and a card-sized box costs the GPU next to nothing.

Preview width

Performance

About 0.3 ms of GPU time a frame at 1280×720 on an M2 Max laptop, with four samples per pixel for smooth creases; slower GPUs take several times longer. quality={0.5} renders a quarter of the pixels but softens the creases, so keep it at 1 unless the GPU needs the room. 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 checker of light and dark facets over the same gradient, 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 mosaic is decoration: it's hidden from assistive tech and lets every click through to your content. With reduced motion it draws one still frame, the full gradient from indigo to amber, and stops. Nothing flashes: the tiles drift under a tile a second, and the colors sway across them over almost a minute. The pattern is busy and runs from dark to light, so keep copy on a panel: a bg-black/50 panel keeps white text above 4.7:1, and a bg-white/70 one keeps black text above 10:1.

FAQ

What are Truchet tiles?

Square tiles described by Sébastien Truchet in 1704: a square cut on its diagonal into a dark and a light half. Laid in random turns, their edges always line up, and the halves join into triangles, chevrons and zigzags. Later variants draw quarter circles instead, which make the winding paths most people know.

Why don't I see arcs?

This one uses Truchet's original diagonal tile, so it's all triangles. For arcs, use Simplex Truchet Weave Shader, which weaves them over and under on a triangle grid, or Truchet Kaleidoscope Shader, which mirrors them into a tunnel.

Can I use my own colors?

Yes: fromColor, viaColor and toColor are the gradient's three stops. They take any CSS color, var(--primary) included, and follow a theme switch. A dark first stop and a light last one give the folds the most depth. spread sets how many bands cross the frame, and shading how far each fold shifts along the gradient.

How is it anti-aliased?

Every pixel averages four samples, so the creases stay smooth at any size. There's no setting for it: it's cheap at four, and the screen's own pixel density does the rest.

Does it need an image or a texture?

No. The tile turns come from a hash of each tile's position, and everything else is math, so there's nothing to load besides the component.

Will it slow my page down?

It costs about 0.3 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, lower quality, knowing the creases go soft.

Credits

Inspired by a Truchet shader (opens in a new tab) by Xor on Shadertoy, through shadcn.io's version. This is a new shader written from the idea, not a port: Truchet's diagonal tiles shaded as folded paper, with its own tile code, hash, light, gradient, motion and colors. The hash is lowbias32 by Chris Wellons, in the public domain.

API Reference

TruchetShader

data-slot="truchet-shader"

PropType
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.

fromColor?string

The first stop of the gradient that sweeps across the tiles. Any CSS color. @default "#1d1b5e".

Default
"#1d1b5e"
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 many tiles fit the height, as a multiple of 6, from 0.5 to 3. @default 1.

Default
1
shading?number

How far each fold shifts along the gradient, from 0 (flat color bands) to 2 (every facet a full ramp). @default 1.

Default
1
speed?number

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

spread?number

How many color bands cross the frame, from 0.5 (one wide sweep) to 2. @default 1.

Default
1
time?number

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

toColor?string

The last stop of the gradient. Any CSS color. @default "#ffcf5c".

Default
"#ffcf5c"
viaColor?string

The middle stop of the gradient. Any CSS color. @default "#f2547d".

Default
"#f2547d"
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