Skip to content

Suppose for example you want to go really fancy and didn't want to just show a old boring slider, instead you want some waves, we have got you covered. useWave hook takes care of all that, its just a wrapper of waversurfer.js

Here's classic example of creating Wsj.com style based wave animation wave

See how he came up with this custom renderer function in this article

tsx
import { renderWsjWaveform } from "./render"
export function Wsj() {
  const containerRef = React.useRef<HTMLDivElement>(null)
  const { isWaveReady } = useWave({
    container: containerRef,
    progressColor: "#f50",
    renderFunction: renderWsjWaveform
  })
  return (
    <div>
      <a className="hover:text-black hover:bg-neutral-100 hover:px-2" href="https://wsj.com">
        wsj.com
      </a>
      {!isWaveReady && <LoaderCircle className="size-5 animate-spin" />}
      <div className="mt-2" ref={containerRef} />
    </div>
  )
}
ts
export function renderWsjWaveform(channels: Array<Float32Array | number[]>, ctx: CanvasRenderingContext2D) {
  const { width, height } = ctx.canvas
  const scale = channels[0].length / width
  const step = 10

  ctx.translate(0, height / 2)
  ctx.strokeStyle = ctx.fillStyle
  ctx.beginPath()

  for (let i = 0; i < width; i += step * 2) {
    const index = Math.floor(i * scale)
    const value = Math.abs(channels[0][index])
    let x = i
    let y = value * height

    ctx.moveTo(x, 0)
    ctx.lineTo(x, y)
    ctx.arc(x + step / 2, y, step / 2, Math.PI, 0, true)
    ctx.lineTo(x + step, 0)

    x = x + step
    y = -y
    ctx.moveTo(x, 0)
    ctx.lineTo(x, y)
    ctx.arc(x + step / 2, y, step / 2, Math.PI, 0, false)
    ctx.lineTo(x + step, 0)
  }

  ctx.stroke()
  ctx.closePath()
}

TIP

Remember don't inline the renderFunction parameter of useWave hook since it will result in stack overflow.

tsx
useWave({
    container: containerRef,
    progressColor: "#f50",
    // don't inline the function directly since this will result in max depth stack trace
    renderFunction: (channels: Array<Float32Array | number[]>, ctx: CanvasRenderingContext2D) => {
      ...
    } 
  })

just a timepass anyways