# Liminal Meridians — generative animated background

A self-contained JS library that brings the Liminal Meridians algorithm to any element on a page. **9.4 KB minified, 4 KB gzipped, zero dependencies.**

→ **[Live demo](demo.html)** &nbsp;·&nbsp; **[Landing page](index.html)**

## Install

Download `liminal-meridians.min.js`, drop it next to your HTML, link to it. That's the whole install.

```html
<script src="liminal-meridians.min.js"></script>
```

> **Not yet on npm / jsDelivr / unpkg.** The package is configured for npm publishing (see [Hosting & distribution](#hosting--distribution) below), but has not been published. Once it is, `npm install liminal-meridians` and the jsDelivr/unpkg URLs will work automatically. Until then, self-host the file.

## Quick start

```html
<script src="liminal-meridians.min.js"></script>

<div class="liminal-meridians" style="width:100%;height:400px;">
    Your content here — sits on top of the animation.
</div>
```

That's it. The library auto-initializes any element with the `liminal-meridians` class on DOM ready, and watches for new ones added later via `MutationObserver`.

## Configuration

All parameters can be set via `data-*` attributes:

```html
<div class="liminal-meridians"
     data-seed="42"
     data-particles="3000"
     data-threshold="1.5"
     data-color-a="#3d6a93"
     data-color-b="#e8915a"
     data-color-c="#fef3d4"
     data-bg="#0a0e1a">
</div>
```

| Attribute | Default | Range | Meaning |
|---|---|---|---|
| `data-seed` | `12345` | any int ≥ 1 | Determinism — same seed = same artwork |
| `data-particles` | `2500` | 500–8000 | Density (auto-scales with element area) |
| `data-field-a-scale` | `0.0022` | 0.0008–0.006 | Coarse-weave noise frequency |
| `data-field-b-scale` | `0.008` | 0.003–0.02 | Fine-grain noise frequency |
| `data-blend-scale` | `0.0014` | 0.0005–0.004 | Regime-boundary frequency |
| `data-threshold` | `1.1` | 0–2.5 | Meridian sharpness |
| `data-speed` | `1.2` | 0.3–3.0 | Flow speed |
| `data-trail` | `3.0` | 0–14 | Trail persistence (higher = denser deposits) |
| `data-color-a` | `#3d6a93` | hex | Cool regime color |
| `data-color-b` | `#e8915a` | hex | Warm regime color |
| `data-color-c` | `#fef3d4` | hex | Meridian glow color |
| `data-bg` | `#0a0e1a` | hex | Background |

## Programmatic API

```js
// Create on any element
const inst = LiminalMeridians.create(myElement, { seed: 7, threshold: 2 });

// Update parameters live (rebuilds fields, preserves animation)
inst.update({ colorA: '#ff0066', particles: 4000 });

// Get the instance attached to an element
LiminalMeridians.get(myElement);

// Initialize all matching elements (already done automatically)
LiminalMeridians.initAll('.my-custom-selector');

// Tear it all down
LiminalMeridians.destroyAll();
```

Each instance also exposes `start()`, `stop()`, and `destroy()`.

## What it does automatically

- **`ResizeObserver`** — rebuilds the simulation when the element changes size, with a 120ms debounce
- **`IntersectionObserver`** — pauses `requestAnimationFrame` when the element scrolls off-screen, saving CPU
- **`MutationObserver`** — initializes elements added to the DOM after the script ran
- **`prefers-reduced-motion`** — detected automatically; renders a single warmup frame, then idles
- **`devicePixelRatio`** — capped at 1.5× to balance crispness and performance on high-DPI screens

## Browser support

Anywhere `<canvas>` and `requestAnimationFrame` are available — every modern browser. The various `*Observer` APIs degrade gracefully if missing (no auto-resize / auto-pause / auto-init for new elements, but the simulation still runs).

## Performance notes

- Each instance owns its own canvas, particle pool, and noise field cache. Multiple instances on a page each run independently.
- The particle count auto-scales with element area at ~`particles / 1.44M px²` so density is consistent across small cards and large heroes.
- A 1200×600 hero element with default settings runs ~1500 particles, which is comfortably 60fps on a mid-range laptop.

## Hosting & distribution

This repo doubles as a deployable static website (`index.html` landing + `demo.html` playground) and as a publishable npm package.

**Current status:**

- **Static site** — deployed to Sevalla (Kinsta) from GitLab `studio350-playground/liminal-meridians`, auto-deploying on push to `main`. No build step, no install command; files served from the repo root as-is.
- **npm / CDN** — not yet published. The `package.json` is preconfigured with `main`, `unpkg`, and `jsdelivr` fields pointing at `liminal-meridians.min.js`, so running `npm publish` from this directory will make `npm install liminal-meridians` and the jsDelivr/unpkg URLs work automatically (both auto-mirror anything on npm).

**To publish to npm when ready:** bump `version` in `package.json`, regenerate `liminal-meridians.min.js` if the source changed, update the version string at the bottom of `liminal-meridians.js`, then `npm publish`. jsDelivr and unpkg light up on their own within minutes.

## License

MIT.
