A plain function, mounted the Svelte way
onMount may return a cleanup function, which is exactly where destroy() belongs. Build the renderer once with the canvas Svelte bound for you, and the shader background is running.
Reactive params, no recompile
setParams never recompiles a pipeline, so a reactive statement can push component state at the renderer as fast as it changes — bind a range input to speed and drag it live.
SvelteKit and the server
The renderer is browser-only, and onMount only runs in the browser — so SvelteKit's server rendering needs no guard at all. The framework docs show the same shape for Astro and plain JavaScript.
<script lang="ts">
import { onMount } from "svelte";
import { createShaderRenderer, type ShaderRenderer } from "shadertown";
let canvas: HTMLCanvasElement;
let renderer: ShaderRenderer | undefined;
export let speed = 0.4;
onMount(() => {
renderer = createShaderRenderer(canvas, {
shader: "aurora",
params: { speed },
});
return () => renderer?.destroy();
});
$: renderer?.setParams({ speed });
</script>
<canvas bind:this={canvas}></canvas>