zero-dependency library

vanilla.waves

Use the 35 wave formulas to change a bar's height, a colour or an element's position. The math comes from p5.waves; a shared DOM loop updates your HTML elements.

35waves
0dependencies
1shared loop

Math and DOM engine

wave() and createSampler() use the math from p5.waves. vanilla.waves removes the p5 prototype hook and adds a DOM engine.

PortRuntimeDraws with
p5.wavesp5.jsa <canvas>
processing.wavesJava / Processing 4the Processing surface
vanilla.wavesplain DOM, zero depsany HTML element - bars, dots, text, opacity

Load the library

One tag pulls the math plus the DOM engine. Mark an element with data-wv; one shared 30 fps loop animates every marked element and pauses the ones offscreen.

<!-- one tag: math + DOM engine -->
<script src="https://cdn.jsdelivr.net/gh/seb-prjcts-be/vanilla.waves@v0.3.1/vanilla.waves.min.js"></script>
<div data-wv="eq" data-seed="13"></div>

DOM examples

The sampler returns a number. You can use it for height, position, a character or opacity.

equalizer

sampler → scaleY

Each bar reads the sampler at a different position. With shift enabled, the meter moves between wave formulas.

// each bar: a sampler value → scaleY
v = 0.08 + s.sample(i * 0.55, t) * 0.92;
bar.style.transform = 'scaleY(' + v + ')';

wave line

sampler → translateY

One sampler traced across position, drawn as a row of dots. The row is the live waveform, complete with shift and morph.

// dots trace the waveform
v = s.sample(i * 0.18, t);
dot.style.transform = 'translateY(' + v*38 + 'px)';

text loader

wave → character

A 4×4 grid where each cell picks a glyph from a wave value.

// value → index into a character ramp
idx = floor((v + 1) / 2 * text.length);
cell.textContent = text[idx];

tone field

wave → opacity

A grid of ink cells whose opacity is a sampler value. Structured like noise, but it breathes and re-forms as the wave shifts.

// each cell: value → opacity
v = (s.sample(c*0.4, t + r*0.5) + 1) / 2;
cell.style.opacity = 0.06 + v * 0.94;
All examples → How the engine works →

35 shapes, four pools

The library includes sines, sawteeth, stepped waves and noise-based shapes. These previews trace them live in SVG.

00
classic sine
06
mountain peaks
09
batman
18
triangle
15
wobble sine
24
noise
See all 35 waves →

Use your own loop

Skip the engine entirely if you want. A sampler is one value in, one number out - point it at any DOM property in your own loop.

// same numbers as p5.waves - drive anything
const s = VanillaWaves.createSampler({ shift: true, range: [-50, 50] });

function tick(now) {
  el.style.transform = 'translateY(' + s.sample(0, now/1000) + 'px)';
  requestAnimationFrame(tick);
}
requestAnimationFrame(tick);
Full guide → GitHub →