Installation
pnpm dlx shadcn@latest add https://dithercn.dev/r/flow-field.jsonUsage
import { FlowField } from "@/components/dithercn/flow-field";
export function Hero() {
return (
<section className="relative isolate min-h-[480px]">
<FlowField className="absolute inset-0 -z-10" />
<h1>Your headline</h1>
</section>
);
}The wind is a steady breeze along angle, bent by slow swirls that drift downwind and change shape as they go. The streamlines are the level lines of its stream function, so they never cross, and they bunch together where the wind runs fast. Bright streaks travel along each line at their own pace, with a crisp head and a tail that fades behind it. Streaks in fast wind are brighter than those in still air, and the prevailing direction veers a few degrees back and forth over time. The swirls keep their size in pixels, so a narrow box shows a smaller piece of the same wind rather than a squashed one.
Examples
Weather map
variant="lines" draws every streamline in the first colour after the paper, and the streaks run through the rest of the palette as they brighten, so the colour reads as wind speed. More density and turbulence, and a higher scale for smaller swirls, fill the box with eddies, and levels={19} puts each of the four colours on an exact step.
Behind a headline
Fewer lines, a low turbulence and long trails give a calm, even breeze. Two soft tints of the ink keep the brightest streak well below full contrast, so the text reads on top.
Props
| Prop | Type | Default |
|---|---|---|
| variant streaks draws only the travelling dashes. lines also draws every streamline underneath them. | Type: "streaks" | "lines" | Default "streaks" |
| density How tightly the streamlines pack. 2 packs twice as many in. | Type: number | Default 1 |
| trail Length of each streak's fading tail, as a share of the gap between streaks, from 0.1 to 1. | Type: number | Default 0.55 |
| turbulence How much the wind meanders and curls into eddies, from 0 (a straight, steady wind) to 2. | Type: number | Default 1 |
| scale Size of the swirls. Higher values pack more, smaller ones in. | Type: number | Default 1 |
| angle Direction the wind blows towards, in degrees as in CSS: 0 points up, 90 right. | Type: number | Default 70 |
| intensity The brightest tone, from 0 to 1. Lower it to sit text on top. | Type: number | Default 1 |
| palette Colours from paper to ink: palette names such as "blue", CSS variable names, or any CSS colour. Streamlines take the second colour; streaks brighten through the rest. | Type: [DitherColor, DitherColor, ...DitherColor[]] | Default Paper, a tint of --dither-ink, then --dither-ink |
| matrix The threshold pattern. See Dither engine. | Type: "bayer2" | "bayer4" | "bayer8" | "blue-noise" | Default "bayer8" |
| cell Size of one dither cell in CSS pixels. | Type: number | Default --dither-cell |
| speed How fast the wind blows and the swirls drift. | Type: number | Default 1 |
| animate false stops the motion: a still frame if it starts off, the current frame if it was moving. | Type: boolean | Default true |
| className Size and position. The wind fills this box. | Type: string | Default – |
Notes
- It is decorative and hidden from assistive technology. Put real text on top of it, not inside it.
- With reduced motion turned on, it draws one still frame and stops.
- It pauses when scrolled out of view or when the tab is hidden, and releases its WebGL context when far offscreen. Without WebGL it shows straight CSS lines along the wind in the same colours, cut into dashes, spaced by
densityand with tails as long astrailsets. - It samples the stream function three times per cell, at 30 fps and one pixel per dither cell. See Performance.