shadertown

Config

Pin the parameters you chose in a typed, reviewable file.

A shader that looks right is a set of numbers. defineShader is where those numbers live.

// shaders/shader.config.ts
import { defineShader } from "shadertown";

export const hero = defineShader({
  shader: "aurora",
  params: {
    speed: 0.42,
    exposure: 1.6,
    bloom: 1.1,
    colorA: "#0b3d2e",
    colorC: "#a78bfa",
  },
  play: "visible",
});
import { ShaderCanvas } from "shadertown/react";
import { hero } from "./shaders/shader.config";

<ShaderCanvas preset={hero} />;

It is typed against the shader

params is checked against the control names that shader actually exposes. Writing exposure under shader: "voronoi" is a type error, because Voronoi has no exposure. It has jitter, edge, depth and drift.

Only the differences

Every detail page exports the diff against the registry defaults, not the full parameter set. That keeps presets short and lets a shader's defaults improve later without silently changing a look you already signed off.

Project config

// shadertown.config.ts
import { defineShadertownConfig } from "shadertown";

export default defineShadertownConfig({
  outDir: "src/shaders",
  registry: "https://www.shadertown.com",
  license: "SHADERTOWN_KEY",
});

The CLI reads this file. license is the name of the environment variable holding your key, never the key itself.

presets is the fourth field: a named map of defineShader results, so a project refers to presets.hero rather than repeating a slug.

defineShader itself takes shader, params, play, quality and a free-text note, which exported presets use to explain themselves. quality is { dpr?, fps?, tier? }: a resolution ceiling, a frame-rate cap, and a pinned quality tier. Leave tier out and the preset follows the page's setQualityTier, which defaults to auto.