shadertown

SolidJS animated backgrounds, one signal away

The renderer is a plain function, so SolidJS shaders need no binding package: onMount builds one, createEffect feeds it signals, onCleanup tears it down.

Signals in, uniforms out

setParams is cheap by design — it writes uniforms, it never recompiles. That makes it a natural sink for createEffect: read a signal inside the effect and the shader tracks it with no scheduling of your own.

The lifecycle is three lines

A ref on the canvas, a renderer in onMount, a destroy() in onCleanup so the GPU surface never leaks. There is nothing Solid-specific to learn and nothing shadertown-specific to configure.

The same catalogue as everyone else

All 77 shaders read one uniform block, so anything you tune in the browser — a SolidJS animated background included — is a params object you paste into the call. The framework docs carry the full example.

Hero.tsx
import { createEffect, createSignal, onCleanup, onMount } from "solid-js";
import { createShaderRenderer, type ShaderRenderer } from "shadertown";

export function Hero() {
  let canvas!: HTMLCanvasElement;
  let renderer: ShaderRenderer | undefined;
  const [speed, setSpeed] = createSignal(0.4);

  onMount(() => {
    renderer = createShaderRenderer(canvas, { shader: "aurora" });
    onCleanup(() => renderer?.destroy());
  });

  createEffect(() => renderer?.setParams({ speed: speed() }));

  return <canvas ref={canvas} />;
}

Tune first, mount second

Every shader runs live in the catalogue with every slider free — the params you settle on go straight into createShaderRenderer.