# Changelog

Notable changes to the `shadertown` package. The site is versioned by its
deploys, not by this file.

This project follows [semantic versioning](https://semver.org). Before 1.0 the
minor number carries breaking changes, so pin it if that matters to you.

## 0.20.2 — 2026-09-12

- Give Blossom three layers of curved petals, fine veins, overlap shadows,
  and a textured pollen head.
- Render Caldera as a raised volcanic island with a recessed lava pool,
  moonlit basalt, molten channels, and drifting embers.
- Refine Shore with cellular foam, translucent shallows, wave troughs,
  and a drying wet-sand margin.

## 0.20.1 — 2026-09-12

- Redraw Pixel Isle with turquoise shallows, sandy beaches, textured grass,
  and shaded rocks. Seeds vary island count, placement, size, and orientation.
- Give Starfield a distant star layer, outward depth motion, round star cores,
  and tapered warp trails. Update its default motion and purple palette.

## 0.20.0 — 2026-09-10

- Add `chromatic-city`, colorful stepped columns with cast shadows, contact
  shading, and individual eased height changes.
- Seed terrain, towers, and square widths, with curated randomization ranges
  and four palettes. Tune the camera, relief, terrace count, and block gaps.
- Add a two-pass miniature renderer with adjustable top and bottom blur and
  a sharp central focus band. Set size variation or blur to zero to disable it.

## 0.19.1 — 2026-09-09

- Brighten Strata’s shelf surfaces and edge lighting while retaining dark
  recesses. Preserve palette brightness when blending warm and cool colors.

## 0.19.0 — 2026-09-09

- Add `strata`, animated contour shelves with recessed depth, rounded edge
  lighting, and three color palettes.
- Tune the shape seed, depth point, rotation, stretch, and layer count.
  Curated randomization ranges preserve shading and readable layers.

## 0.18.0 — 2026-09-09

- `ShaderCanvas` draws a shadertown credit in a corner of the canvas, as a
  visible link in the server-rendered HTML. `setBadge(false)` removes it from
  every canvas on the page, `badge={false}` from one, and `badge="top-left"` —
  or `setBadgePosition` — moves it between the four corners. Free shader
  sources now ship a licence that asks for the credit; a paid licence lifts the
  condition. Nothing in the runtime checks a licence or contacts a server.
- **Breaking:** `ShaderCanvas` wraps its canvas in a `span`, and `className` and
  `style` now apply to that wrapper rather than to the canvas. The canvas fills
  the wrapper, so a parent-sized layout is unchanged; a rule that targeted the
  canvas element itself may need moving. The wrapper is present whether or not
  the credit is drawn.
- `toConfigSource`, `toReactSource`, `toVanillaSource` and `toExampleSource`
  take an optional `SnippetOptions`, and emit a licence notice unless it says
  `creditRequired: false`. `toFreeLicense` is new beside `toLicense`.

## 0.17.0 — 2026-09-09

- Add `liquid-light`, a glass wave with layered refraction, studio reflections,
  procedural floor caustics, and independent geometry, material, and motion controls.
- Smooth highlights with temporal antialiasing and reset frame history when
  parameters, quality, size, or time change. Cap internal resolution to keep
  the glass passes bounded on large displays.
- Expand the shared Params buffer from 128 to 160 bytes with slots `h` through
  `n`, preserving existing field offsets. Custom renderers must allocate the
  larger buffer; SDK renderers handle this automatically.

## 0.16.0 — 2026-09-07

- Give Meadow curated randomization ranges for readable lighting, grass size,
  density, and motion while keeping the full manual control ranges.

- Rebuild `meadow` as a landscape graph: ray-marched mountains, pine instances,
  drifting valley mist, textured silver grass, airborne seeds, foreground blur,
  and HDR bloom. Foliage uses built-in atlases, curved grass strips, mip filtering,
  and MSAA. Curved leaves, varied plumes, cloud shadows, and a cached terrain
  height field add depth; the distant scene renders at half resolution.
  Its existing `flowers` parameter now controls grass density. Refresh its
  golden-hour palette, catalogue poster, and social card. Expose the atlas data
  URLs through `shadertown/assets` for custom renderers.
- Feature Meadow in Archipelago’s former overview position. Archipelago remains
  available in the catalogue.

## 0.15.0 — 2026-09-05

One shader after a photograph: a floor of black stone with light in the steps.

### Refined

- Basalt uses broad plateaus, warm corner reflections, fine stone texture and
  distance focus. Independent columns, rows and step height tune its geometry;
  nonzero layout seeds rearrange drops from foreground to distance. Seed 0
  preserves the reference composition.
- Optional `NumericControl.randomRange` bounds Randomise without restricting
  manual sliders. Basalt uses restrained ranges and curated colour presets.
- Three additional shared control slots (`e`, `f`, `g`) occupy the padding
  before the colour fields, preserving their offsets and uniform buffer size.

### Added

- **`basalt`.** A camera over a paving of dark slabs laid in running bond, the
  grid turned so the seams run away on the diagonal, and the floor cut into a
  few broad terraces that climb toward the top right of the frame. Along the
  nose of a step some seams carry a strip of light: a thin hot core with a
  narrow warm halo that lights the riser below it, runs down the corner where
  the riser turns, and lays a satin reflection over the tread in front. The
  light travels along the strips in slow pulses, the camera drifts sideways,
  and a strip under the pointer burns brighter. Lit,
  Pulse, Sheen and Haze are its controls, Relief rides the warp slot, Scale is
  the size of a slab, and it ships four presets. Family `spatial`, cost
  heavy. Seventy-four shaders in total.
- **The `masonry` graph.** A fifth graph flavour: one instanced draw lays every
  slab as a box into an HDR target with depth and 4x MSAA, a focus pass blurs
  by the camera distance the geometry stored, and the shared bloom chain and
  tone mapping finish the image. The variant supplies the grid, the heights
  and the material; the prelude owns the camera, the boxes and the focus.

## 0.14.0 — 2026-09-05

One shader of metal and glass, drawn through a fourth flavour of render graph.

### Added

- **`alloy`.** Broad brushed-metal ribbons twist through a cool, softly lit
  studio, their fine grooves catching warm gold reflections, and glass spheres
  float between the folds and reflect the ribbons around them. Ribbon width,
  Brushing, Glass spheres and Warm light are its own controls, Twist rides on
  the warp slot, Zoom frames the camera, and it ships four presets. Family
  `spatial`, cost heavy. Seventy-three shaders in total.
- **The `studio` graph.** A fourth graph flavour: a compute pass bounds the
  ribbon patches, a shadow map and an antialiased HDR geometry pass draw the
  ribbons, a glass pass traces reflection and refraction against those
  patches, then depth of field, the shared bloom chain and tone mapping finish
  the image. `toReadme` documents its passes for custom renderers.

### Changed

- **Graph flavours may opt into tone mapping.** The present pass now runs a
  per-flavour hook; the particle, drafting and glow graphs keep their response.

## 0.13.0 — 2026-09-05

Auto judges a phone by its GPU, not by being a phone.

### Changed

- **The device check uses detect-gpu.** `@pmndrs/detect-gpu` is now a
  dependency, imported after the first frame is on screen, the way vgpu's
  `adaptive-quality` example does it. Blocklisted GPUs and benchmark tiers 0
  and 1 ask for Low; a software adapter still does so at once. The rule that
  sent every mobile device to Low is gone: it put an iPhone 14 on Low before
  it had drawn a frame, when its GPU benchmarks at the top tier. A GPU the
  tables do not know keeps High and leaves the verdict to the frame rate.

### Added

- **`configureQuality({ benchmarksUrl })`.** Serve detect-gpu's benchmark
  tables from your own origin instead of unpkg. Call it before the first
  canvas mounts.

## 0.12.0 — 2026-09-05

Two quality tiers, and an Auto that picks between them.

### Added

- **Two tiers.** Low clamps the device pixel ratio to 1 and halves the
  iteration counts every shader marks as cost — march steps, noise octaves,
  blur taps, rays — so a raymarch costs half on Low and not merely a quarter
  of the pixels. All 72 shaders draw on both,
  Gossamer and Louvres included.
- **`setQualityTier(tier)`.** One setting for the page: `auto`, `high` or
  `low`, default `auto`. Every canvas follows it live, so a settings menu
  calls it once and the whole page swaps. `qualityTier()` reads it and
  `onQualityTier()` hears it change. A canvas that names `quality.tier` of
  its own — on `<ShaderCanvas>`, `defineShader` or `createShaderRenderer` —
  pins that tier and ignores the page's.
- **Auto.** The default. Starts on High and drops to Low once, when the device
  class, a battery under 30% off the charger, or two seconds of presented
  frames under 80% of the refresh rate ask for it. Every signal is advisory
  and page-wide: the verdict is shared by every canvas on the page and
  remembered for the ones created after. Ported from vgpu's
  `adaptive-quality` example, without its detect-gpu dependency.
- **`onQualityChange`** on `<ShaderCanvas>`, `onQuality` on the renderer
  options, and `renderer.quality` / `renderer.setTier()`: what was asked,
  what is on screen, and why. The swap is a new surface and one uniform,
  never a recompile.
- **`st_steps(n)` and `st_low()`** in the shared prelude, and a `quality`
  field on `Params`. `st_fbm2`, `st_fbm3`, `st_ridge2` and `st_srcBlur` scale
  their own loops with the tier.

## 0.11.0 — 2026-09-04

Two shaders after two ReactBits backgrounds, each given its own name, look
and controls.

### Added

- **`gossamer`.** After ReactBits' Ghost Fibers. A stack of layers, each a
  field of fine parallel threads folded by a wave and twisted about the
  centre, every layer half as bright as the one before and on its own clock,
  so the threads drift over one another without repeating. A soft haze lies
  between them in the second colour, a pool of light sits at the heart, and
  the whole weave turns slowly. Drawn through the `glow` graph, so the threads
  bleed the way a cobweb does with the light behind it. Layers, Wave,
  Sharpness and Haze are its own controls, Twist rides on the warp slot, and
  it ships four presets.
- **`louvres`.** After ReactBits' Gradient Blinds. A three-stop gradient laid
  across the frame at an angle and cut into a run of slats, each shaded across
  its own width like a louvre turned toward the light. A spotlight rides on
  the pointer: inside it the gradient shows through, outside it the slats fall
  to dark. The gradient drifts slowly along its own axis. Slats, Angle,
  Spotlight and Softness are its own controls, Bend rides on the warp slot,
  and it ships four presets. Seventy-two shaders in total.

## 0.10.0 — 2026-09-02

Four shaders of light, and the small render graph that blooms them.

### Added

- **`filament`.** A handful of glowing threads gather to a point and fan
  toward the edges like fibres drawn from a spool, each a slow sine that
  grades from the first colour to the last and burns through to the core where
  they cross. The pinch leans toward the pointer and the threads brighten under
  it.
- **`spectra`.** A stack of bands bent by a field of crossed sines, a pulse
  travelling down them, and each colour channel reading the bands a little
  offset from the others, so every edge fringes into spectra. Scanlines over
  the top; the pulse tightens under the pointer.
- **`shafts`.** God rays from a source just above the frame: the light on
  each bearing is drifting noise over the angle, carved into a handful of
  broad soft beams that fade with distance and fall to dark at the foot. The
  pointer is a thing held in the light, blocking the beams and throwing a
  shadow that softens the further it falls.
- **`billow`.** A sea of soft waves — two crossed sines with a slow swell —
  raymarched from a low camera into fog, the crests catching a third colour by
  height, the camera turning a little with the pointer. Seventy shaders in
  total, and a new `light` family.
- **The `glow` graph flavour.** One full-screen scene pass into an HDR target,
  then the shared bloom chain and present. A variant supplies `st_scene(uv)`
  and returns linear colour with, in alpha, how much of the pixel is light the
  chain may bleed. `fs_brightAlpha` — the alpha-gated bloom gate the drafting
  flavour introduced as `fs_brightPlate` — moves into the shared graph prelude
  so both flavours use it, and `st_toLinear` joins it there.

## 0.9.0 — 2026-09-02

A shader that draws your logo up as a technical plate, an `{ svg }` source to
feed it, and a second flavour of render graph to draw it through.

### Added

- **`blueprint`.** The layer measured and drawn up the way a draughtsman would:
  the ink outlined at a set weight, hatched inside at forty-five degrees, and
  dimensioned below and beside with ticks, extension lines and its size in
  pixels, lettered in the browser's monospace face from a glyph atlas the
  runtime draws once. Behind it a grained mat under a grid ruled heavier every
  fourth line, with construction lines meeting at the pointer. The
  measuring happens on the GPU every frame — a bounds reduction boxes the ink,
  a jump flood turns the box into a distance field — so the plate follows
  whatever the layer becomes. Sixty-six shaders in total, and a new `drafting`
  family.
- **The `{ svg }` source.** `source={{ svg: "/logo.svg" }}` (a URL or the
  markup itself) rasterises the drawing through an `<img>` at the `width` you
  choose, so the layer is as sharp as the canvas rather than as sharp as the
  file declares, and works in browsers that will not decode an SVG into a
  bitmap directly. Every opaque pixel is filled with `color` (white by
  default) over `background` (black), so a coloured logo arrives as the same
  silhouette a text source produces; `color: null` keeps its own colours.
- **Graph flavours.** A graph shader's folder now names its flavour:
  `graph/particles/` for the five particle fields, `graph/drafting/` for the
  plate. The shared prelude (`vs_fullscreen`, the bloom chain, `fs_main`) is
  one file, each flavour's passes are another, and a flavour prelude that opens
  with `// @reads-source` binds a layer. `shaderReadsSource` and
  `shaderGraphs` join the generated module, and `ShaderGraph.bindSource` is
  how the renderer hands a layer to the passes inside a graph that read it.

### Changed

- **`isSourceShader` answers the question it is named for.** It is true for
  every shader that wants a `source` — the fourteen source-kind shaders and
  now `blueprint` — where before it was a synonym for `shaderKind() ===
  "source"`. Ask it before handing over a layer; ask `shaderKind` how the
  shader is driven.
- **The shared graph bindings moved to 20 and up.** `blurU`, `bloomU`, the
  scene, blur and bloom textures and `linearSampler` sat at 2 to 14 in every
  particle field's WGSL; they now sit at 20 to 30 so a flavour has room below
  them for a source layer. Nothing changes through `ShaderCanvas` or the
  runtime. A vendored copy of a particle field keeps working as vendored; a
  fresh `shadertown add` writes the new numbers.
## 0.8.2 — 2026-09-02

### Fixed

- **The five graph shaders keep one picture at every canvas size.** Their point
  size was in device pixels and their grid is a fixed 256 by 256, so a point
  covered a smaller share of a bigger canvas: `dunes`, `ferro`, `chladni`,
  `maelstrom` and `pulsar` read as a dense field on a small card and thinned
  out to specks on a fullscreen hero — and, at twice the pixels, to half the
  light. The point now grows with the canvas above 240 device pixels of
  height, which is what a catalogue card draws at, and never shrinks below the
  two pixels it already was. A card is untouched; everything larger now shows
  the same picture it does. Measured on the site's own stills, `dunes` at
  1000 by 625 went from 3% of full brightness to 15%, and `ferro` from 3% to
  12% — the difference between a black rectangle and a picture.

### Changed

- **`ferro` shows its crown before the pointer has moved.** A pointer that has
  never moved reports the exact centre of the frame, and this camera
  unprojects the centre to the horizon, so the crown of spikes the shader is
  named for rose two hundred world units away and read as a smudge of light. It
  now rests low in the frame, near enough to the camera to see. Any pointer a
  reader actually moves is honoured exactly as before.

## 0.8.1 — 2026-09-01

### Changed

- **`pulsar` opens on a picture instead of a white blob.** Its exposure was
  set as if the globe were a thin field of points, but sixty-five thousand
  additive splats share a small circle of screen there, so the core burned out
  and took the whole sphere with it — a saturated white ball on grey, with none
  of the surface visible. Intensity drops from 2.29 to 0.7 and saturation comes
  back up from 0.06 to 1.1, so the dotted surface, the green rim and the pulled
  side all read. The vignette deepens to settle it into the dark. The Bands
  well also sat at 0, which meant the sweeping light the shader is named for
  never appeared until you moved a slider; it now opens at 0.45.

## 0.8.0 — 2026-09-01

Five shaders that are render graphs rather than a single pass, a mesh gradient
rebuilt from the ground up, and a fluid solve that costs half of what it did.

### Added

- **The `graph` shader kind.** A graph shader is a whole render graph in one
  WGSL module: a displacement field, an instanced particle draw into an HDR
  scene, a five-level bloom chain, and a present pass that ends in the shared
  post chain. The runtime encodes those passes into the frame ahead of the
  present pass, rebuilds the screen targets on resize, and eases the pointer
  so a crown or a lean follows the hand instead of teleporting under it.
  Through `ShaderCanvas` or `createShaderRenderer` nothing changes on your
  side; `shaderKind()` answers `"graph"`, and the README that
  `shadertown add` writes names each stage's entry point for anyone wiring
  the WGSL into their own renderer.
- **Five `particles` shaders drawn through it.** `chladni` (standing-wave
  figures, sand gathering on the nodes), `dunes` (a ridged sand sea on the
  wind), `maelstrom` (a log-spiral whirlpool), `ferro` (a ferrofluid crown
  under the pointer) and `pulsar` (a breathing globe that leans toward the
  cursor). Sixty-five shaders in total.

### Changed

- **`mesh-gradient` is rewritten, and its controls change.** Four colour
  spots drift on slow orbits with inverse-power falloff, a centre swirl that
  decays outward, two-octave simplex distortion, and a weighted OKLab blend in
  linear light, so midpoints stay vivid instead of greying out. There is no
  dark backdrop left to cover, so the `softness`, `spread` and `coverage`
  params are gone and `swirl` takes their place; `warp` is relabelled
  Distortion. A preset that still sets the old three no longer type-checks,
  and the runtime ignores them. New default palette.
- **`fluid` draws one stroke, at half the cost.** Splats deposit along the
  segment the pointer covered this frame, so a fast stroke draws one unbroken
  line instead of a trail of beads. The force and ink splats ride inside the
  advection passes that already hold the field, eight warm-started Jacobi
  sweeps replace twenty, and the step drops from 28 dispatches to 14. A speed
  ceiling keeps a flung pointer at maximum Force from blowing up the solve, and
  the warm-up loop steps at 24 Hz, so vorticity confinement no longer grinds
  the resting frame into grid-scale speckle.
- **Catalogue order.** `ferro` and `dunes` take the places `plasma` and
  `liquid-metal` held near the front of `shaderNames`; those two move to
  where the particle fields sit.

## 0.7.0 — 2026-09-01

Fifteen shaders that draw places instead of patterns, in two new families.
The `pixel` family is real pixel art — every cell a whole number of device
pixels, every colour one of a handful of stops, every move a whole cell on a
sprite-sheet clock. The `scene` family paints islands, water and skies at
hero quality: a marched ocean, rolling grassland, an atoll from above.

### Added

- **Five `pixel` shaders.** `pixel-sea` is a 16-bit seascape with a dithered
  sky and the sun's reflection breaking into dashes; `pixel-isle` generates
  one to three islands per seed, one hard biome per cell; `pixel-clouds`
  marches terraced clouds past a hard sun; `pixel-fire` reproduces the Doom
  fire's statistics without its feedback buffer; `pixel-rain` rains on a
  sleeping skyline, one lit window at a time. All five share
  `st_pixelSize()`, a new prelude helper that keeps every virtual cell a
  whole number of device pixels.
- **Ten `scene` shaders.** Islands: `lagoon` (an atoll from above),
  `archipelago` (a nautical chart on a slow drift), `island` (sea to the
  horizon, land in the haze), `shore` (the swash zone from above), and
  `caldera` (a volcano at night, lit by its own veins). Heroes: `meadow`
  (a silhouette flower field at golden hour), `blossom` (one flower, drawn
  large, with a true phyllotaxis seed head), `hills` (grassland marched as a
  heightfield), `swell` (open ocean marched so waves hide waves), and
  `cumulus` (fair-weather cloud shaded by one extra sample).
- **Colour presets.** A shader may declare `presets` — curated colour trios
  with names. All fifteen new shaders ship four each. On the site, Randomise
  picks between a shader's presets instead of rolling hues, and the picker
  offers them as one-click starting points; every well stays individually
  editable, and the share URL still carries plain colours.

### Changed

- **A canvas compiles when it is nearly in view.** `ShaderCanvas` used to
  build its renderer the moment it mounted, so a page of cards paid for every
  pipeline on load whether or not the reader ever scrolled that far. It now
  waits until the canvas is within a screen of the viewport, and holds the
  renderer once built — scrolling back over a card redraws it rather than
  recompiling. `play` is unchanged and still decides when a built renderer
  animates. A browser with no `IntersectionObserver` starts every canvas at
  once, as before.

### Fixed

- **Lazy canvases start in the right play state.** A canvas with
  `play="always"` no longer draws one frozen frame when it first comes near the
  viewport. Hover, visible, and reduced-motion modes keep their existing
  behaviour.
- **One request per source image, however many canvases read it.** A grid
  whose shaders share a photograph fetched that photograph once per canvas,
  all in flight together and none of them able to use the others' response.
  The fetch is now shared per URL; each canvas still decodes its own bitmap.

## 0.6.0 — 2026-08-30

The CLI learns to talk to coding agents. `npx shadertown mcp` serves the
catalogue over the Model Context Protocol, so an agent can search shaders,
read every control with its range and meaning, and vendor tuned source into
the project it is working on — through the same registry route and the same
licence rules as `shadertown add`.

### Added

- **`shadertown mcp`.** A dependency-free MCP server over stdio with four
  tools: `search_shaders`, `get_shader`, `install_shader`, and
  `account_status`. Discovery and control schemas are answered locally from
  the registry this package already ships; installing goes through
  `/r/<slug>.json`, so Free shaders vendor for anyone and Professional
  source asks for the paid plan exactly as the CLI does. Connect an agent
  with `npx add-mcp "npx -y shadertown@latest mcp" -n shadertown`.

## 0.5.0 — 2026-08-30

Three shaders that remember: a `compute` kind whose state lives in GPU
buffers and steps forward before every draw, so what you see is a
simulation answering the pointer, not a picture pretending to.

### Added

- **`particles`.** 131,072 embers riding a curl-noise wind, deposited into a
  long exposure that never quite forgets — trails are history and colour is
  speed. The pointer is a vortex; push its charge below zero and the swarm
  scatters instead.
- **`fluid`.** The incompressible Navier–Stokes equations, solved for real:
  semi-Lagrangian advection, twenty warm-started pressure sweeps, vorticity
  confinement, and dye on a grid finer than the velocity that carries it.
  Drag to splat force and ink together; idle, it throws plumes of its own.
- **`cloth`.** A verlet sheet of two and a half thousand points relaxing
  twelve distance constraints in parallel, hung from its pins in a two-speed
  wind. With no vertex pipeline in the runtime it rasterises itself through
  an atomic depth buffer, and the pointer carries an invisible sphere the
  folds drape around.
- The `compute` shader kind behind them. The runtime allocates each shader's
  storage buffers, dispatches its `@compute` entry points ahead of the draw,
  and rebinds what the fragment stage reads — through `ShaderCanvas` or
  `createShaderRenderer` nothing changes on your side. Forty-five shaders in
  total.

### Changed

- Grain now defaults to 0 across the whole catalogue. It was a texture
  everything arrived wearing; it is now an effect you reach for.



Ten shaders built around input: six that answer the pointer, four made for
text, and a `{ text }` source so the text ones have something to answer.

### Added

- **Pointer shaders.** `eyes` (a wall of eyes that follow the cursor and blink
  on their own clocks), `tesla` (a plasma globe whose filament seeks the
  pointer, clamped to the glass), `magnet` (field lines of three charges, one
  riding the pointer — closed forms, nothing traced), `torch` (a guttering
  light in your hand over a rock heightfield, lit off its own derivative),
  `parallax` (five ridgelines the pointer pans, each by its own depth), and
  `gravity` (a starfield lensed by a mass at the cursor, Einstein ring
  included). All six carry themselves with the pointer at rest, so a card is
  never a dead frame.
- **Text shaders.** `neon-sign` (the layer's luma boundary bent into tube and
  lit), `ascii` (the layer redrawn from a ten-glyph density ramp — the font is
  packed into ten integers, so a vendored copy needs no assets), `shatter`
  (voronoi shards whose contents fly from the pointer; the progress slider is
  a scrubber at speed 0, same contract as reveal), and `melt` (the layer runs
  downhill, and the pointer is the heat). Forty-two shaders in total.
- **`{ text }` sources.** `source={{ text: "OPEN" }}` renders a line of text
  to an offscreen canvas — newlines break lines, `font` is one CSS shorthand,
  half an em of margin left all round — and reads it like any image. Type:
  `ShaderSourceText`.

### Changed

- **The free tier now covers every family.** Twelve of the forty-two shaders
  hand over their source to anyone — one from each of the ten families, plus
  `radiance` and `eyes`, kept as second representatives of traced light and
  pointer interaction. New to the list: `mesh-gradient`, `julia`,
  `film-grain`, `lens`, `shockwave`, `eyes` and `ascii`.

### Compatibility

The `Params` block at `@group(0) @binding(0)` is unchanged, byte for byte, and
the source bindings are the same three that 0.2.0 added. `ShaderSourceInput`
widens to accept `{ text }`; every value it accepted before is still accepted.

## 0.3.0 — 2026-08-29

Four shaders that light a scene instead of colouring one, taken from four
[vgpu](https://vgpu.sh) examples: two of them trace light through geometry, one
mounts it on an edge, and one bends it through glass.

### Added

- **`radiance`.** Two-dimensional global illumination in a single fragment.
  Every pixel fans rays into an analytic room of lamps and turning bars and
  marches each one back to its source, so the shadows are cast rather than
  drawn. The pointer is the brightest lamp in it. Free tier.
- **`lumen`.** A lattice of dots where each dot emits and occludes. Every dot
  is the same size, so the nearest one to any point is the nearest lattice
  node and the distance to the whole field is exact — which is what makes a
  ray affordable enough to cross a dozen cells.
- **`beacon`.** A triangle of LEDs over a reflecting floor. The glow is
  analytic off each edge and each emitter, so it holds its shape at any zoom,
  and the floor is the same field read at the mirrored point.
- **`orb`.** A liquid blob in a sphere of glass. The sphere is solved rather
  than marched; the blob is lobes joined by a smooth minimum, refined onto its
  own surface before it is shaded, and antialiased off the settled distance.

### Changed

- **`reveal` is now free**, alongside `radiance`. Five of the thirty-two
  shaders hand over their source to anyone.

### Compatibility

The `Params` block at `@group(0) @binding(0)` is unchanged, byte for byte. All
four are generative, so they declare no bindings beyond it and a shader
vendored under 0.1.0 or 0.2.0 runs here unmodified.

## 0.2.0 — 2026-08-29

Ten shaders that read a layer instead of inventing one, filling the four
categories the catalogue could not reach: glass, distortion, image effects and
transitions.

### Added

- **Source shaders.** `glass`, `lens`, `bloom`, `shockwave`, `swirl`, `flow`,
  `duotone`, `edges`, `mosaic`, `reveal`. Twenty-eight shaders in total.
- **`source`** on `<ShaderCanvas>` and `createShaderRenderer`. Takes a URL, an
  `ImageBitmap`, an `<img>`, a `<canvas>`, an `OffscreenCanvas`, a `<video>`
  (re-uploaded only while it plays), or `{ shader, params }` to stack one
  shadertown shader on another. Handing a source to a generative shader is
  ignored rather than an error, so swapping the shader behind one canvas keeps
  working.
- **`ShaderRenderer.setSource()`**, which swaps the layer without rebuilding
  the pipeline.
- **`shaderKind(name)`**, **`isSourceShader(name)`** and
  **`defaultSourceOf(name)`**. Kind comes from the folder the WGSL lives in, so
  it cannot disagree with the bindings the shader declares.
- Four families: `optical`, `distortion`, `image`, `transition`.
- Types: `ShaderKind`, `ShaderSourceInput`, `ShaderSourceImage`,
  `ShaderSourceLayer`.

### Changed

- Exported snippets and the generated per-shader README now describe the source
  bindings. A vendored `edges.wgsl` does nothing without something to read, and
  the files that ship with it say so.

### Compatibility

The `Params` block at `@group(0) @binding(0)` is unchanged, byte for byte. A
source shader adds a texture, a sampler and a `Source` uniform at bindings 1 to
3; a generative shader declares none of them and keeps the layout it has always
had. `Source` is its own uniform block rather than four more fields on `Params`
for exactly this reason — a shader vendored under 0.1.0 runs unmodified here.

The reverse does not hold. A source shader vendored from 0.2.0 needs a runtime
that can bind a texture for it, so it faults on 0.1.0 with an incomplete bind
group. Upgrade the package before running one.

## 0.1.0 — 2026-08-29

First release. Eighteen fullscreen WebGPU shaders drawn by
[vgpu](https://vgpu.sh), sharing one uniform block so the runtime can swap a
shader without touching a binding.

- `<ShaderCanvas>` and `useShaderRenderer` for React, `createShaderRenderer`
  for everything else.
- `defineShader` presets, typed against each shader's own controls.
- A shared post chain — vibrancy, grain, vignette — that behaves identically
  across the catalogue.
- `shadertown add <slug>`, which vendors the WGSL, a typed preset, an example
  and a licence into your repo.
