I've always been drawn to the gap between "beautifully animated hero sections on Awwwards" and "what most of us actually ship." The tooling just isn't there — you either write custom shaders from scratch, or you settle for a static gradient. I wanted something in between: drop-in animated backgrounds that look premium, install in one command, and don't tank performance. That's why I built kam-ui.
What kam-ui Is
kam-ui is a shadcn-compatible registry of motion-rich React background components. 11 components ranging from pure CSS animations to WebGL shaders, all installable with:
npx shadcn@latest add https://ui.philippekam.dev/r/<component>.jsonThe registry includes:
- CSS-only components — Radiant Veil (focal-point drift), Chromatic Leaks (four corner radials with Lissajous paths), Halo Ring (breathing radial band)
- WebGL shader components — Shimmer Ring (simplex noise deformation), Crown Glow (Lovable-style arc), Chromatic Field (domain-warp with chromatic aberration), Solar Flare (procedural sun with corona), Mesh Gradient (Stripe-style liquid blobs)
- Science-grade specimens — Atmospheric Sky (Rayleigh/Mie scattering, day/night cycle, crepuscular rays), Milky Way (ESA Gaia DR2 panorama on a sky dome), Black Hole (Bruneton beam-tracing shader with relativistic accretion disc)
Every component is self-contained, typed, and ships with the same props pattern: color, speed, className, and component-specific controls.
The Tech Stack
Component Runtime
- React 19 with TypeScript — all components are
'use client'and work in Next.js, Remix, Vite, or any React setup - Tailwind CSS v4 for styling, with
clsx+tailwind-mergefor className composition - OGL (lightweight WebGL library) for shader components — ~15KB vs Three.js's ~150KB
Documentation Site
- Astro 6 for static generation — each component page is server-rendered with React islands for the live playground
- Shiki for syntax highlighting in the source code panels
- Custom live playground with prop controls, background colour picker, and real-time component rendering
Distribution
- shadcn registry format — a build script generates JSON manifests under
public/r/with inline source, dependency declarations, and file targets - Components resolve
registryDependenciesautomatically — shared utilities (kam-utils,kam-containment) install alongside any component
Architecture Decisions
The Containment System
Every component uses a shared containment.ts library that handles three cross-cutting concerns:
- Visibility-gated rendering —
useInViewpausesrAF/ WebGL loops when a component scrolls out of view. No invisible GPU work. - Adaptive performance —
useAutoPerformanceQualitydetects device capability and drops resolution or disables effects on low-end hardware. Components accept aqualityprop ('auto' | 'low' | 'medium' | 'high'). - Reduced motion —
usePrefersReducedMotionrespectsprefers-reduced-motion: reduce. Animations freeze or simplify gracefully.
This pattern means every component is safe to drop into a production page without worrying about performance cliffs or accessibility violations.
Why OGL Over Three.js
For background components, Three.js is overkill. OGL gives you a WebGL program, a mesh, and a render loop in ~15KB. No scene graph, no material system, no post-processing pipeline. The shader components need:
- A fullscreen quad
- A fragment shader
- A handful of uniforms (
time,resolution,mouse,color)
OGL handles that with minimal abstraction. The shader source stays readable — it's just GLSL with a thin TypeScript wrapper.
Registry Build Pipeline
The build-registry.mjs script runs before every dev and build:
// For each component, emit a shadcn-compatible JSON manifest
{
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
"name": "chromatic-field",
"type": "registry:component",
"title": "Chromatic Field",
"description": "Procedural organic domain-warp field...",
"dependencies": ["clsx@^2.1.1", "tailwind-merge@^3.5.0", "ogl@^1.0.11"],
"registryDependencies": [
"https://ui.philippekam.dev/r/kam-utils.json",
"https://ui.philippekam.dev/r/kam-containment.json"
],
"files": [{ "path": "components/kam/chromatic-field.tsx", "content": "..." }]
}The Black Hole component is special — it ships 7 files (component TSX, 3 TypeScript modules, 3 GLSL shaders) all bundled into a single registry JSON. The shadcn CLI resolves everything in one command.
The Harder Components
Atmospheric Sky
This one simulates real atmospheric scattering. The fragment shader implements:
- Rayleigh scattering for blue sky / orange sunset transitions
- Mie scattering for the sun's halo and crepuscular rays
- Procedural cirrus clouds from layered noise
- Star field with twinkling that fades as the sun rises
- Sun bloom with physically-motivated falloff
The sun position animates through a day/night cycle. You control timeOfDay, sunSpeed, cloudDensity, and starDensity via props.
Black Hole
The most complex component. It's based on Eric Bruneton's black_hole_shader (BSD-3-Clause) — a beam-tracing approach to Schwarzschild black hole rendering. The implementation includes:
- Precomputed deflection textures (
.datfiles) for gravitational lensing - Relativistic accretion disc shading with Doppler shift
- HDR rendering with tone mapping
- WebGL2 float texture extensions
The shader source alone is three GLSL files. The TypeScript layer handles texture loading, uniform management, and the physics model. All of it ships through the registry as a single install command.
Mesh Gradient
The Stripe-inspired liquid gradient. Four colour blobs drift on simplex-noise paths, blending with cubic hermite falloff for those premium soft edges. The key insight is that the noise function drives both position and size — the blobs don't just translate, they breathe and morph. A subtle film grain pass adds analog texture.
The Docs Site
The documentation is an Astro static site with an editorial design — Instrument Serif for headings, JetBrains Mono for code, dark-first palette. Each component page includes:
- Live playground — the component renders at full size with real-time prop controls (sliders, colour pickers, toggles)
- Source tab — Shiki-highlighted TypeScript source with copy button
- Registry install — the
npx shadcn@latest addcommand, ready to copy - Props reference — auto-generated from the component's TypeScript types
- Dependencies panel — lists npm packages and registry dependencies
The playground uses client:visible so Astro only hydrates the React island when it scrolls into view — the rest of the page is zero-JS static HTML.
What's Next
The current registry is all backgrounds. I'm planning to expand into:
- Text effects — animated reveals, gradient text, glitch effects
- Cursor followers — magnetic buttons, custom cursors, trail effects
- Scroll animations — parallax sections, scroll-triggered transitions
The architecture supports it — the containment system, registry build pipeline, and docs site are all component-agnostic. Adding a new category is just a new entry in componentRegistry.ts and a page template.
Check it out: ui.philippekam.dev | GitHub