Guides

Short, focused recipes. Built for shipping.

Hero background

Build a subtle, layered hero backdrop that stays performant.

Learn more

Scroll-reactive parallax

Tie wave amplitude and wavelength to scroll position.

Learn more

Audio-driven waves

Use WebAudio input to drive intensity and color.

Learn more

Quality presets

Balance memory and clarity for battery, balanced, and quality modes.

Learn more

Hero background

Atmosphere, not distraction.

const gen = new SineWaveGenerator({
  el: "#hero",
  autoResize: true,
  waves: [
    { amplitude: 16, wavelength: 220, speed: 0.6 },
    { amplitude: 10, wavelength: 160, speed: 0.4 }
  ]
});

gen.start();

Purpose

Give the page depth and calm motion without competing with copy.

Why it works

Two slow waves create parallax at low contrast. The eye reads the motion as atmosphere, not content.

How to apply

  • Keep amplitude under 20px to avoid stealing attention.
  • Use two wavelengths for depth (e.g., 220 + 160).
  • Lower stroke opacity to 0.15–0.4 for softness.
  • Set autoResize: true for responsive headers.
Learn more

Scroll-reactive parallax

Motion that tracks progress.

window.addEventListener("scroll", () => {
  const progress = scrollY / (docHeight - innerHeight);
  wave.amplitude = 10 + 30 * progress;
  wave.wavelength = 140 + 240 * (1 - progress);
});

Purpose

Let users “feel” progression without extra UI.

Why it works

Amplitude increases while wavelength tightens, so the motion intensifies naturally as users move through the page.

How to apply

  • Throttle updates with requestAnimationFrame.
  • Clamp progress to 0–1 for stable motion.
  • Use a reduced-motion fallback (slow or pause).
Learn more

Audio-driven waves

Sound in, motion out.

Idle
const analyser = audioCtx.createAnalyser();
analyser.fftSize = 128;
// Map frequency bins to wave intensity.

Purpose

Turn audio energy into visual rhythm.

Why it works

The analyser hands you a fresh energy reading many times a second — steady enough that the wave doesn't jitter, fast enough that it still feels live.

How to apply

  • Start audio on a user gesture to satisfy mobile policies.
  • Normalize 0–255 data into 0–1 amplitudes.
  • Use light smoothing for natural motion.
Learn more

Quality presets

Fidelity when you want it. Battery when you need it.

Quality preset: balanced
gen.setQualityPreset("balanced");
gen.setQualityPreset("quality");
gen.setQualityPreset("battery");

Purpose

Keep visuals consistent across devices with one switch.

Why it works

Pixel ratio is the single biggest lever on canvas cost — it sets how many actual pixels get redrawn every frame, not just how many you see on screen.

How to apply

  • Use balanced as the default.
  • Switch to battery on mobile or low power.
  • Offer quality for hero moments.
Learn more

Responsive resize

Stays sharp when its container changes, not just the window.

const gen = new SineWaveGenerator({ el: canvas, autoResize: true });

gen.start();
// No manual ResizeObserver needed — autoResize already watches
// the canvas element itself, not just the window.

Purpose

Keep the canvas crisp in layouts that resize independently.

Why it works

autoResize observes the canvas element's own box size via ResizeObserver, in addition to the window resize event, catching layout-driven changes a window listener alone would miss.

How to apply

  • Leave autoResize on (the default).
  • Cap maxPixelRatio on high-DPI displays to control memory.
  • Delete any manual resize wiring you may already have.
Learn more