Same hooks, different boundaries.
webaudio-kit stays framework-light. The important choice is where to put AudioProvider so hooks run only in browser-capable React code.
Provider placement
Put AudioProvider around the controls, canvases, and hooks that need the shared master gain and analyser graph. Smaller provider islands are fine when only one screen owns audio playback.
Vite React
Wrap the client root or the audio workspace inside AudioProvider in main.tsx.
Call play from click, tap, or key handlers in normal client components.
Next App Router
Keep route files server-rendered when possible, then move AudioProvider and every hook into a client component.
The browser rule is the same, but the play handler must live inside a component marked with use client.
Plain React
Create the root with createRoot and wrap either the whole app or the smallest audio control island.
Use a real user gesture before creating or resuming AudioContext.
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { AudioProvider } from "@webaudio-kit/react";
import { App } from "./App";
createRoot(document.getElementById("root")!).render(
<StrictMode>
<AudioProvider>
<App />
</AudioProvider>
</StrictMode>,
);Next App Router client boundary
Next App Router pages and layouts are server components by default. Keep metadata, static copy, and layout code there, then move AudioProvider, audio hooks, and analyser canvases into a dedicated client component.
"use client";
import { AudioProvider, useTone } from "@webaudio-kit/react";
function ToneButton() {
const tone = useTone({ frequency: 440, gain: 0.14 });
return (
<button onClick={() => void tone.play({ durationMs: 600 })}>
{tone.isPlaying ? "Restart tone" : "Play tone"}
</button>
);
}
export function AudioControls() {
return (
<AudioProvider>
<ToneButton />
</AudioProvider>
);
}Browser autoplay impact
Browser autoplay rules apply equally to Vite, Next, and plain React. Call play() from a user gesture such as a click, tap, or key press so the provider can lazily create and resume AudioContext at the right time.
function PlayButton() {
const tone = useTone({ frequency: 660, gain: 0.12 });
return (
<button onClick={() => void tone.play({ durationMs: 500 })}>
Play
</button>
);
}Build-checked examples
The standalone examples are intentionally outside the pnpm workspace. Release checks install packed tarballs so the example apps exercise the same package exports developers install from npm.
pnpm examples:check