GPU-accelerated animated sine wave backgrounds. Works with vanilla JS and React. Built with raw WebGL2 + custom GLSL shaders. Automatic fallback chain: WebGL2 → Canvas 2D → CSS gradient → solid color.
Full documentation: DOCS.md
- Zero dependencies for vanilla JS — no Three.js, no React required
- WebGL2 GPU rendering at 60 FPS
- Automatic fallback: WebGL2 → Canvas 2D (CPU) → CSS gradient (static) → solid color (none)
- User-selectable renderer via
rendereroption orsetRenderMode()at runtime - 12 adjustable parameters (waves, speed, amplitude, frequency, opacity, thickness, blur, concentration, randomness, thickness randomness, vertical offset, rotation)
- 6 built-in color themes with automatic time-of-day selection
- Custom RGBA color picker with per-color opacity
- Glass effect, Liquid Metal effect, Split Fill mode, Bloom, Lumen, Twist
- Rotation (0–360°) around screen center
- Mouse-reactive wave distortion
- Smooth 1500ms color transitions between themes
- Film grain post-processing (WebGL only)
- React component with built-in control panel
- Responsive on mobile
- Retina / HiDPI support (capped at 2x)
npm install @redesigner/wave.jsimport { WaveBackground } from '@redesigner/wave.js'
const wave = new WaveBackground('#hero', {
theme: 'sunset',
waveCount: 12,
speed: 0.5,
})// Force Canvas 2D (no GPU)
const wave = new WaveBackground('#hero', {
renderer: 'canvas2d',
})
// Force no effects at all
const wave = new WaveBackground('#hero', {
renderer: 'none',
theme: 'night',
})wave.setRenderMode('canvas2d') // Switch to CPU rendering
wave.setRenderMode('css') // Static gradient
wave.setRenderMode('none') // Solid background color
wave.setRenderMode('webgl2') // Back to GPUwave.setParam('waveCount', 20)
wave.setParam('amplitude', 0.1)
wave.setParam('rotation', 45)
wave.setTheme('night')
wave.setColors(['#ff0000', '#00ff00', '#0000ff', '#ffff00'])
wave.setSplitFill(true)
wave.setGlass(true)
wave.setLiquidMetal(true)wave.destroy()<div id="hero" style="width: 100%; height: 100vh;"></div>
<script type="module">
import { WaveBackground } from '@redesigner/wave.js'
new WaveBackground('#hero', { theme: 'daytime' })
</script>npm install @redesigner/wave.js react react-domimport { HeroWave } from '@redesigner/wave.js/react'
function App() {
return (
<HeroWave theme="sunset">
<h1>Your content here</h1>
</HeroWave>
)
}The React component includes a built-in control panel with all sliders, color picker, effect toggles, and renderer selector.
| Prop | Type | Default | Description |
|---|---|---|---|
theme |
string |
auto (time-of-day) | Color theme name |
style |
object |
{} |
Container inline styles |
className |
string |
— | Container CSS class |
children |
ReactNode |
— | Content rendered on top of the wave background |
Creates an animated wave background in the given container.
container — DOM element or CSS selector string (e.g. '#hero').
options:
| Option | Default | Description |
|---|---|---|
renderer |
'auto' |
Renderer to use: 'auto', 'webgl2', 'canvas2d', 'css', or 'none' |
theme |
auto (time-of-day) | Color theme: 'pre-dawn', 'sunrise', 'daytime', 'dusk', 'sunset', 'night' |
waveCount |
8 |
Number of wave layers (1–100) |
speed |
0.3 |
Animation speed (0–2) |
amplitude |
0.06 |
Wave height (0–0.2) |
frequency |
2.5 |
Wave density (0.5–10) |
opacity |
0.6 |
Wave transparency (0–1) |
thickness |
1 |
Wave solid core width in px (1–100) |
blur |
30 |
Edge fade zone in px (0–200) |
concentration |
0 |
Vertical compression toward center (0–50) |
randomness |
0 |
Per-wave amplitude variation (0–1) |
thicknessRandom |
0 |
Per-wave thickness variation (0–1) |
verticalOffset |
0 |
Shift waves up/down (-0.5–0.5) |
rotation |
0 |
Rotation in degrees (0–360) |
splitFill |
false |
One-directional fill mode |
glass |
false |
Glass transparency effect (WebGL only) |
liquidMetal |
false |
Chrome/metal effect (WebGL only) |
lmLiquid |
0.07 |
Liquid Metal flow intensity (0–0.2) |
bloom |
false |
HDR bloom post-processing (WebGL only) |
bloomThreshold |
0.6 |
Luminance above which bloom kicks in (0–1) |
bloomIntensity |
1.4 |
Bloom halo strength (0–3) |
lumen |
false |
Glowing-ribbon render mode (WebGL only) |
lumenIntensity |
1 |
Lumen brightness multiplier (0–2). >1 drives a stronger bloom halo. |
twist |
false |
3D chrome/glass twisted-ribbon effect (WebGL only) |
twistAmount |
1 |
Twist intensity (0–1) |
colors |
— | Explicit 4-hex-color array. Overrides theme. |
colorOpacities |
[1,1,1,1] |
Per-color opacity array |
| Method | Description |
|---|---|
setRenderMode(mode) |
Switch renderer: 'webgl2', 'canvas2d', 'css', or 'none' |
setTheme(name) |
Switch color theme with 1500ms animated transition |
setColors(hexArray) |
Set 4 custom hex colors with animated transition |
setParam(key, value) |
Update any wave parameter instantly |
setColorOpacities(arr) |
Set per-color opacity [0-1, 0-1, 0-1, 0-1] |
setSplitFill(bool) |
Toggle split fill mode |
setGlass(bool) |
Toggle glass effect |
setLiquidMetal(bool) |
Toggle liquid metal effect |
setBloom(bool) |
Toggle HDR bloom post-processing |
setLumen(bool) |
Toggle glowing-ribbon render mode |
setTwist(bool) |
Toggle 3D chrome twist effect |
toJSON() |
Return current settings as a plain object (round-trips through new WaveBackground(el, json)) |
setConfig(obj) |
Apply a settings object at runtime — mirror of what the constructor accepts |
destroy() |
Stop animation, remove canvas, cleanup all event listeners |
| Property | Description |
|---|---|
renderMode |
Current active renderer: 'webgl2', 'canvas2d', 'css', or 'none' |
params |
Current parameter values object |
theme |
Current theme name |
| Mode | Description | GPU | Animated | Effects |
|---|---|---|---|---|
webgl2 |
Full GPU shader rendering | Yes | Yes | All (glass, liquid metal, film grain) |
canvas2d |
CPU-based line drawing | No | Yes | Waves, colors, opacity, rotation |
css |
Static CSS gradient | No | No | Theme colors as gradient |
none |
Solid background color | No | No | Background color only |
When renderer is set to 'auto' (default), the fallback chain is:
WebGL2 available? → GPU shader (60 FPS, all effects)
↓ no
Canvas 2D available? → CPU rendering (animated waves)
↓ no
CSS gradient (static theme colors)
You can check which renderer is active via wave.renderMode.
When no theme is specified, the component automatically selects based on the user's local time and re-checks every 60 seconds.
To disable auto-detection, simply pass a theme option:
// Fixed theme — no auto-switching
new WaveBackground('#hero', { theme: 'sunset' })
// React — fixed theme
<HeroWave theme="sunset">...</HeroWave>If the user manually selects a theme via the control panel, auto-detection is disabled until reset.
Everything you tune in the playground at wavejs.org is just options — and the constructor accepts them all. Two flows:
A. Inline options (no JSON):
new WaveBackground('#hero', {
theme: 'sunset', waveCount: 12, bloom: true, twist: true,
})B. Export + load JSON. Tweak the playground to taste, click Copy JSON
in the Parameters panel, paste into a config.json, and load at runtime:
// vanilla
const config = await fetch('/config.json').then(r => r.json())
const wave = new WaveBackground('#hero', config)// React
import config from './config.json'
const wave = new WaveBackground(el, config)The JSON shape matches the options 1-to-1 — no mapping layer:
{
"renderer": "webgl2",
"colors": ["#07070f", "#3730a3", "#06b6d4", "#34d399"],
"colorOpacities": [1, 1, 1, 1],
"waveCount": 4, "speed": 0.3, "amplitude": 0.08, "frequency": 2,
"thickness": 50, "blur": 6, "opacity": 1,
"bloom": false, "twist": true, "twistAmount": 1
}Round-trip at runtime: wave.toJSON() returns the current settings; wave.setConfig(obj) applies one. See examples/vanilla/from-json.html and examples/react/src/AppFromJson.jsx for working samples.
- Chrome 56+
- Firefox 51+
- Safari 15+
- Edge 79+
Fallback renderers ensure the component works even in environments without WebGL.
npm run build