AnimatedWash
neon-ui/animated-washFreeComponent
WebGL grain-gradient shader wash rising from the bottom edge, colored by currentColor with a hover lift. Adapted from paper-design/shaders (Apache-2.0).
Install it
npx shadcn@latest add https://ui.neon.com/r/animated-wash.jsonSource
1"use client";23/*4 * Adapted from paper-design/shaders (GrainGradient concept)5 * https://github.com/paper-design/shaders — Apache-2.0.6 *7 * Neon UI fork: a single-purpose WebGL wash — a color gradient rising from8 * the bottom edge, dithered with animated grain. Color comes from9 * currentColor at mount (same contract as NeonLoader), so the status hue10 * or theme drives it with zero props. Hovering the nearest interactive11 * ancestor lifts and warms the field. Static under reduced motion.12 * The GLSL lives in animated-wash-shader.ts.13 */1415import { useEffect, useRef } from "react";16import type { ComponentProps } from "react";1718import { cn } from "@/lib/utils";1920import { WASH_FRAGMENT, WASH_VERTEX } from "./animated-wash-shader";2122export type AnimatedWashProps = Omit<ComponentProps<"canvas">, "children"> & {23 /** Grain refresh speed multiplier; 0 freezes the field. */24 speed?: number;25 /** 0-1 strength of the smooth gradient under the grain. */26 intensity?: number;27 /** 0-1 grain strength over the gradient. */28 noise?: number;29 /** Grain cell size in device pixels; bigger reads chunkier. */30 grainSize?: number;31};3233/** How fast the hover lift eases toward its target each frame. */34const LIFT_EASE = 0.08;3536/**37 * Seconds for a dial change to close ~63% of its gap — uniforms ease38 * toward their targets each frame, so a dragged slider glides39 * instead of snapping.40 */41const SMOOTH_TAU = 0.12;4243const parseColor = (css: string): [number, number, number] => {44 const probe = document.createElement("canvas");45 probe.width = 1;46 probe.height = 1;47 const context = probe.getContext("2d");4849 if (!context) {50 return [0, 0.9, 0.6];51 }5253 context.fillStyle = css;54 context.fillRect(0, 0, 1, 1);55 const [r, g, b] = context.getImageData(0, 0, 1, 1).data;56 return [(r ?? 0) / 255, (g ?? 0) / 255, (b ?? 0) / 255];57};5859const warnDev = (message: string) => {60 if (typeof process !== "undefined" && process.env.NODE_ENV !== "production") {61 console.warn(message);62 }63};6465const compile = (66 gl: WebGLRenderingContext,67 type: number,68 source: string69): WebGLShader | null => {70 const shader = gl.createShader(type);7172 if (!shader) {73 return null;74 }7576 gl.shaderSource(shader, source);77 gl.compileShader(shader);7879 if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {80 warnDev(81 `neon-ui: shader compile failed: ${gl.getShaderInfoLog(shader) ?? "unknown"}`82 );83 gl.deleteShader(shader);84 return null;85 }8687 return shader;88};8990// … truncated
What it pulls in
Other registry items
Files it writes
More from neon-ui
All 77 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| ActivityFeedactivity-feed | neon-ui | Components | Free | 2 deps | |
| AgentChatagent-chat | neon-ui | Components | Free | 6 deps | |
| ApiKeyListapi-key-list | neon-ui | Components | Free | 2 deps | |
| AppCardapp-card | neon-ui | Components | Free | 2 deps | |
| AppCreatorapp-creator | neon-ui | Components | Free | 2 deps | |
| AuthFormauth-form | neon-ui | Components | Free | no deps | |
| AutoscaleChartautoscale-chart | neon-ui | Components | Free | 1 dep | |
| Badgebadge | neon-ui | Components | Free | 2 deps |
