_❯Mesh Gradient
An animated mesh-gradient background: three drifting colour blobs, a vignette and optional film grain, all in one fragment shader.
WebGLGLSLgradientblobsvignette
1import { useState } from "react";2import { MeshBackgroundCanvas } from "@/components/misc/mesh-background/mesh-background-canvas.component";3import { LabsDemoLayout } from "../../components/labs-experiment-frame/labs-experiment-frame.component";4import {5 ButtonGroupControl,6 ControlGroup,7 ControlPanel,8 ResetButton,9 SliderControl,10} from "../../components/labs-control/labs-control.component";11import * as styles from "./mesh-background.demo.css";1213const STATES = ["paused", "running"] as const;14type PlayState = (typeof STATES)[number];1516const DEFAULT_QUALITY = 0.45;1718export function MeshBackgroundDemo() {19 const [quality, setQuality] = useState(DEFAULT_QUALITY);20 const [state, setState] = useState<PlayState>("running");2122 const reset = () => {23 setQuality(DEFAULT_QUALITY);24 setState("running");25 };2627 return (28 <LabsDemoLayout29 stage={30 <div className={styles.stageInner}>31 <div className={styles.meshBox}>32 <MeshBackgroundCanvas quality={quality} animate={state === "running"} />33 </div>34 </div>35 }36 controls={37 <ControlPanel>38 <ControlGroup title="Animation">39 <ButtonGroupControl40 options={STATES}41 value={state}42 onChange={setState}43 formatOption={(option) => option[0].toUpperCase() + option.slice(1)}44 />45 </ControlGroup>4647 <ControlGroup title="Film grain">48 <SliderControl49 label="Quality"50 value={quality}51 min={0}52 max={0.75}53 step={0.05}54 onChange={setQuality}55 format={(value) => value.toFixed(2)}56 />57 </ControlGroup>5859 <ResetButton onReset={reset} />60 </ControlPanel>61 }62 />63 );64}