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.
| Theme | Auto Time | Colors |
|---|---|---|
pre-dawn |
05:00–08:00 | Deep purple, magenta, orange, gold |
sunrise |
08:00–11:00 | Dark purple, hot pink, orange, yellow |
daytime |
11:00–16:00 | Navy, blue, cyan, mint |
dusk |
16:00–20:00 | Dark purple, violet, lavender, light purple |
sunset |
20:00–23:00 | Deep purple, pink, coral, orange |
night |
23:00–05:00 | Near-black, dark purple, medium purple, violet |
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