Mischief

72 / Scenes

Shader Surface

Four shader backdrops -- caustics, metal, plasma and ripple -- each taking its two colours from your theme, so the same surface arrives dark in a dark application and light in a light one.

plasma

Installation

Copy the source into your project, or keep it behind a package.

npx shadcn@latest add Tinkerers-Labs/mischief-ui/shader-surface
import { ShaderSurface } from "mischief-ui/shader-surface"

Or paste it in yourself. The source imports the shared cn helper from @/lib/utils, so point that at your own copy.

registry/default/shader-surface/shader-surface.tsx
"use client" import * as React from "react"import {  RenderSurface,  createQuadProgram,  useThemeColors,  type QuadProgram,  type SurfaceColor,} from "@/registry/default/render-surface/render-surface"import { cn } from "@/lib/utils" export type ShaderSurfaceVariant = "caustics" | "metal" | "plasma" | "ripple" 

Usage

export function Hero() {
  return (
    <ShaderSurface variant="caustics" className="rounded-xl">
      <div className="px-8 py-16 text-center">
        <h1>Caustics</h1>
      </div>
    </ShaderSurface>
  )
}

Two colours is the whole palette

Every variant mixes between exactly two colours, both read from the theme. That constraint is what lets one component cover four quite different looks without any of them fighting the application they were installed into. The default pair is --background and --primary, which means the surface already matches the page before it is configured.

Because the colours are read rather than compiled in, switching the application to dark mode recolours the shader on the next frame. There is no second set of values to keep in step.

<ShaderSurface variant="metal" base="--card" tint="--ring" scale={5} />

Choosing between them

  • caustics: light through moving water. Busy, and best behind very little text.
  • metal: slow bands with a sharp highlight. Reads as a material rather than as weather.
  • plasma: soft blended cloud. The quietest of the four, the safest behind a paragraph, and the default for that reason.
  • ripple: rings leaving the centre. Directional, so it wants something at the middle to have come from.

When WebGL is not available

If the context or the program cannot be created, the surface draws nothing and the box keeps its ordinary background and children. A shader that will not compile should cost a reader a plain panel, not a broken one.

API

variant"caustics" | "metal" | "plasma" | "ripple"Which shader to run. Defaults to "plasma", the quietest of the four.
basestringThe colour the surface settles to. Defaults to "--background".
tintstringThe colour the light in it takes. Defaults to "--primary".
speednumberMultiplies time. Defaults to 1.
scalenumberSize of the pattern. Larger is busier. Defaults to 3.
pausedbooleanHolds the surface still.

Accessibility

The canvas is decoration and is hidden from assistive technology. Children sit above it as ordinary markup. Under reduced motion a single frame is drawn and time never advances, so the pattern is there and nothing in it moves.