Beautiful, interactive shader gradients for any div element. Built with Three.js and WebGL shaders.
📖 Full Documentation | 🎨 Live Demo | 🛠️ Color Customizer
- Features
- Installation
- Quick Start
- Understanding the Color Palette
- API Reference
- Presets
- Framework Integration
- CDN Usage
- Usage Examples
- Tips & Best Practices
- Resources
- Development
- Contributing
- License
- Credits
- 44 beautiful preset gradients with smooth animations
- NEW v2.0: Advanced gradient controls with domain warping and turbulence
- Custom color API for creating unique gradients
- Simple, declarative API
- Framework agnostic (React, Vue, Svelte, vanilla JS)
- Automatic container resizing
- Lightweight (~98KB) with Three.js as peer dependency
- CDN support for no-build workflows
- Fine-grained control over animation, effects, and gradient flow
npm install frosted-canvas threeNote: Three.js is a peer dependency to keep the package lightweight (~98KB instead of ~698KB) and prevent duplicate installations.
import FrostedCanvas from 'frosted-canvas';
// Initialize with a preset gradient
const frost = new FrostedCanvas('#container', { preset: 0 });<div id="container" style="width: 100%; height: 400px;"></div>import FrostedCanvas from 'frosted-canvas';
// Generate a static (non-animated) background
const frost = new FrostedCanvas('#container', {
preset: 0,
static: true
});import FrostedCanvas from 'frosted-canvas';
const frost = new FrostedCanvas('#container');
// Create your own gradient
frost.setColors({
paletteA: [0.9, 0.2, 0.5], // Pink
paletteB: [0.5, 0.5, 0.5], // Gray
paletteC: [1.0, 0.8, 0.3], // Yellow
paletteD: [0.1, 0.3, 0.6], // Blue
});function hexToRgb(hex) {
const r = parseInt(hex.slice(1, 3), 16) / 255;
const g = parseInt(hex.slice(3, 5), 16) / 255;
const b = parseInt(hex.slice(5, 7), 16) / 255;
return [r, g, b];
}
frost.setColors({
paletteA: hexToRgb('#FF6B6B'),
paletteC: hexToRgb('#4ECDC4'),
});The shader uses a cosine-based formula to generate beautiful procedural gradients. Each gradient is controlled by 4 color palettes (A, B, C, D):
The Formula:
color(t) = a + b · cos[2π(c·t+d)]
The Palettes:
- Palette A (Offset): Base color offset - shifts the entire color range
- Palette B (Amplitude): Color intensity - controls how vibrant colors are
- Palette C (Frequency): Color variation - controls how colors transition
- Palette D (Phase): Color shift - offsets the color wave
Each palette takes RGB values from 0 to 1:
[1.0, 0.0, 0.0]= Red[0.0, 1.0, 0.0]= Green[0.0, 0.0, 1.0]= Blue[0.5, 0.5, 0.5]= Mid Gray
Learn more: YouTube explanation | Full theory
Version 2.0 introduces powerful new controls for creating more organic and dynamic gradients:
domainWarpStrength (0-0.5): Warps the coordinate space using layered noise for organic, flowing distortions. Higher values create more dramatic warping effects.
frost.setConfig({ domainWarpStrength: 0.25 }); // Moderate organic flowturbulence (0-1.0): Adds fractal Brownian motion (FBM) with 5 octaves of noise for additional complexity and detail. Creates layered, turbulent effects.
frost.setConfig({ turbulence: 0.5 }); // Add fractal detailgradientAngle (0-6.28): Rotates the gradient direction in radians (0° to 360°). Allows dynamic gradient rotation.
frost.setConfig({ gradientAngle: Math.PI / 4 }); // 45 degree rotationcolorSpread (0.1-3.0): Controls how spread out colors are across the gradient. Lower values create tighter color bands, higher values stretch and repeat colors.
frost.setConfig({ colorSpread: 1.5 }); // Wider color distributionflowSpeed (0-1.0): Independent animation speed for the domain warping flow, separate from the main animation speed for more control.
frost.setConfig({ flowSpeed: 0.6 }); // Faster flowing motionfrost.setConfig({
domainWarpStrength: 0.4,
turbulence: 0.8,
flowSpeed: 0.5,
colorSpread: 2.0,
gradientAngle: Math.PI / 6,
});new FrostedCanvas(container, options);Parameters:
container(string | HTMLElement) - CSS selector or DOM elementoptions(object) - Configuration options
Options:
| Option | Type | Default | Description |
|---|---|---|---|
preset |
number | 0 | Starting preset (0-43) |
showGUI |
boolean | false | Show debug controls |
autoResize |
boolean | true | Auto-resize on container changes |
static |
boolean | false | Generate static (non-animated) background |
Change to a different preset gradient (0-43).
frost.setPreset(3);Set custom RGB colors (values 0-1).
frost.setColors({
paletteA: [0.9, 0.65, 1.0], // Offset
paletteB: [0.5, 0.5, 0.5], // Amplitude
paletteC: [1.0, 0.7, 0.4], // Frequency
paletteD: [0.0, 0.15, 0.2], // Phase
});Adjust animation, effects, and gradient controls.
frost.setConfig({
// Animation & Noise
noiseScale: 0.3, // 0.1-3.0: Size of noise patterns
noiseStrength: 0.35, // 0-1.0: Intensity of distortion
animationSpeed: 0.5, // 0-0.5: Speed of animation
grainIntensity: 0.03, // 0-0.2: Film grain effect
vignetteStrength: 3.0, // 0-3.0: Edge darkening
// Advanced Gradient Controls (v2.0+)
domainWarpStrength: 0.15, // 0-0.5: Organic coordinate warping
turbulence: 0.2, // 0-1.0: Fractal noise complexity
gradientAngle: 0.0, // 0-6.28: Rotation angle in radians
colorSpread: 1.0, // 0.1-3.0: Color distribution
flowSpeed: 0.3, // 0-1.0: Independent flow animation speed
});Get current color values.
const colors = frost.getColors();
// Returns: { paletteA: [...], paletteB: [...], paletteC: [...], paletteD: [...] }Get current configuration.
const config = frost.getConfig();
// Returns: { noiseScale: 0.3, noiseStrength: 0.35, ... }Clean up resources and remove canvas.
frost.destroy();44 preset gradients are available (indexed 0-43).
| Index | Name | Description |
|---|---|---|
| 0 | Molten Peach | Warm molten peach with lively motion |
| 1 | Paper Koi | Gentle paper-like pastels with pond tones |
| 2 | Sunset Bloom | Warm orange center with soft grain |
| 3 | Aurora Glow | The northern lights |
| 4 | Deep Ocean | Muted teals and deep blues, calm motion |
| 5 | Slate Grain | High-grain monochrome, cinematic |
| 10 | Coral Reef | Bright coral / teal interplay |
| 13 | Forest Mist | Subtle greens and cool fog |
| 14 | Solar Flare | Fiery amber with fast motion |
| 15 | Arctic Dawn | Pale blues, crisp and calm |
| 20 | Candy Cloud | Playful pinks and blues |
| 30 | Cosmic Bloom | Galactic gradients with soft pulsation |
| 43 | Mystic Flow | Ethereal flowing gradients with organic warping (v2.0 showcase) |
Molten Peach, Paper Koi, Sunset Bloom, Aurora Glow, Deep Ocean, Slate Grain, Peach Mirage, Crimson Dusk, Watermelon, Electric Indigo, Coral Reef, Lemon Zest, Midnight Velvet, Forest Mist, Solar Flare, Arctic Dawn, Vintage Sepia, Lavender Haze, Moss Grove, Copper Sunset, Candy Cloud, Meteor Storm, Tropical Night, Dusty Rose, Slate Storm, Glacial Drift, Amber Glow, Neon Canyon, Petrol Dream, Saffron Mist, Cosmic Bloom, Porcelain Dawn, Obsidian Fade, Rose Quartz, Velvet Plum, Horizon Teal, Dusty Denim, Brass Ember, Iris Bloom, Celadon Whisper, Starling Night, Polar Mint, Silent Harbor, Mystic Flow.
import { useEffect, useRef } from 'react';
import FrostedCanvas from 'frosted-canvas';
function Hero() {
const containerRef = useRef(null);
const frostRef = useRef(null);
useEffect(() => {
frostRef.current = new FrostedCanvas(containerRef.current, {
preset: 0,
});
return () => frostRef.current?.destroy();
}, []);
return (
<div ref={containerRef} style={{ width: '100%', height: '100vh' }}>
<h1>Your Content</h1>
</div>
);
}<template>
<div ref="container" class="background">
<h1>Your Content</h1>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
import FrostedCanvas from 'frosted-canvas';
const container = ref(null);
let frost = null;
onMounted(() => {
frost = new FrostedCanvas(container.value, { preset: 0 });
});
onUnmounted(() => frost?.destroy());
</script>
<style scoped>
.background {
width: 100%;
height: 100vh;
}
</style><script>
import { onMount, onDestroy } from 'svelte';
import FrostedCanvas from 'frosted-canvas';
let container;
let frost;
onMount(() => {
frost = new FrostedCanvas(container, { preset: 0 });
});
onDestroy(() => {
if (frost) frost.destroy();
});
</script>
<div bind:this={container} class="background">
<h1>Your Content</h1>
</div>
<style>
.background {
width: 100%;
height: 100vh;
}
</style>'use client';
import { useEffect, useRef } from 'react';
import FrostedCanvas from 'frosted-canvas';
export default function Hero() {
const containerRef = useRef(null);
const frostRef = useRef(null);
useEffect(() => {
if (containerRef.current && !frostRef.current) {
frostRef.current = new FrostedCanvas(containerRef.current, {
preset: 0,
});
}
return () => {
if (frostRef.current) {
frostRef.current.destroy();
frostRef.current = null;
}
};
}, []);
return (
<div ref={containerRef} style={{ width: '100%', height: '100vh' }}>
<h1>Next.js + Frosted Canvas</h1>
</div>
);
}<div id="background" style="width: 100%; height: 100vh;"></div>
<script type="module">
import FrostedCanvas from 'frosted-canvas';
new FrostedCanvas('#background', { preset: 0 });
</script>For projects without a build step:
<!DOCTYPE html>
<html>
<head>
<style>
#background {
width: 100%;
height: 100vh;
}
</style>
</head>
<body>
<div id="background"></div>
<script type="importmap">
{
"imports": {
"three": "https://unpkg.com/three@0.181.0/build/three.module.js",
"three/": "https://unpkg.com/three@0.181.0/"
}
}
</script>
<script type="module">
import FrostedCanvas from 'https://unpkg.com/frosted-canvas/dist/frosted-canvas.es.js';
new FrostedCanvas('#background', { preset: 0 });
</script>
</body>
</html><div class="hero" id="hero-bg">
<div class="hero-content">
<h1>Welcome</h1>
</div>
</div>
<script type="module">
import FrostedCanvas from 'frosted-canvas';
new FrostedCanvas('#hero-bg', { preset: 0 });
</script><div class="card" id="card-bg">
<div class="card-content">
<h2>Card Title</h2>
</div>
</div>
<script type="module">
import FrostedCanvas from 'frosted-canvas';
new FrostedCanvas('#card-bg', { preset: 5 });
</script><div id="bg">
<button onclick="frost.setPreset(0)">Sunset</button>
<button onclick="frost.setPreset(3)">Aurora</button>
<button onclick="frost.setPreset(14)">Solar Flare</button>
</div>
<script type="module">
import FrostedCanvas from 'frosted-canvas';
window.frost = new FrostedCanvas('#bg', { preset: 0 });
</script>frost.setColors({
paletteA: [0.9, 0.65, 1.0],
paletteB: [0.5, 0.5, 0.5],
paletteC: [1.0, 0.7, 0.4],
paletteD: [0.0, 0.15, 0.2],
});frost.setColors({
paletteA: [0.5, 0.8, 1.0],
paletteB: [0.5, 0.5, 0.5],
paletteC: [1.0, 1.0, 0.5],
paletteD: [0.0, 0.1, 0.2],
});frost.setColors({
paletteA: [0.8, 0.5, 1.0],
paletteB: [0.5, 0.5, 0.5],
paletteC: [1.0, 0.5, 0.8],
paletteD: [0.3, 0.2, 0.5],
});- Start with a preset: Use
frost.setPreset(0)then tweak from there - Keep Palette B moderate: Values around 0.5 work best for amplitude
- Experiment with Palette C: This creates the most dramatic changes
- Use complementary colors: Colors opposite on the color wheel create vibrant gradients
- Test different noise settings: Lower noiseScale = larger patterns
- Adjust animation speed: Slower speeds (0.1-0.3) are often more elegant
Use static: true when:
- You want better performance (no animation loop)
- Creating print-ready or screenshot-friendly designs
- Building static hero sections or cards
- Reducing battery consumption on mobile devices
- You need a beautiful gradient without motion
- Container must have explicit width and height
- Call
destroy()when removing the component to clean up resources - Use
autoResize: truefor responsive containers - Multiple instances on the same page are supported
// Save current state
const myPreset = {
colors: frost.getColors(),
config: frost.getConfig(),
};
localStorage.setItem('myGradient', JSON.stringify(myPreset));
// Load later
const saved = JSON.parse(localStorage.getItem('myGradient'));
frost.setColors(saved.colors);
frost.setConfig(saved.config);- Live Demo - See all presets in action
- Full Documentation - Complete documentation
- Color Customizer - Interactive tool to create custom gradients
- GitHub Repository - Source code
- npm Package - npm registry
# Install dependencies
npm install
# Start development server
npm run dev
# Build library for npm
npm run build
# Build demo site
npm run build:demoContributions are welcome! Please feel free to submit a Pull Request.
MIT License - see LICENSE for details.
- Built with Three.js v0.181.0
- Color palette theory by Íñigo Quílez
- Created by SahilK-027