# Liquid Marble — `liquid-marble@1.0.0`

Marbled ink in four colours folding into itself, with fine veins and a soft sheen. Loops perfectly.

Swirling marbled ink: three colours folded into one another like paint on water, with fine veins of a fourth colour running through the folds and a soft sheen where the surface leans towards the light. The flow is a stack of sine warps of the picture, each running whole cycles per loop, so the marbling never stops and always comes back to where it began. Choose the colours (lapis, rose, jade or ink), how fine the marbling is, how violently it folds, how visible the veins are and the seed.

- Kind: background; status: published; digest sha256:1cf0582c22422cf474c332fe345cf0e5c32075fc2244c500f507533e96fd8ef9
- Role: Shader background (three.js): an elegant, endlessly moving marble for titles, covers and calm scenes.
- Implementation: three; entry `src/liquid-marble.js`
- Files: https://aipixelwizard.com/registry/liquid-marble/1.0.0/<path> (`LICENSE`, `asset.json`, `demo.js`, `index.html`, `src/liquid-marble.js`)
- Manifest JSON: https://aipixelwizard.com/api/v1/visuals/liquid-marble/versions/1.0.0
- Runnable demo: https://aipixelwizard.com/registry/liquid-marble/1.0.0/index.html (open over http; it imports sibling packages by relative path)
- Dependencies (exact): `three@0.185.1` (source) — Renderer and a full-screen shader material.; `apw-runtime@1.0.0` (demo) — Demo harness.

## Exports
- `createLiquidMarble({ palette?, scale?, swirl?, veins?, seed? }) => { scene, camera, setSize(width, height), update(time, loopSeconds), dispose() }` — The marble as one full-screen shader; render its scene with its camera, ideally through createBloomPass.
- `createBloomPass(renderer, { width, height, glow?, exposure?, grain? }) => { render(scene, camera, output?), dispose() }` — A small bloom with tone mapping and a fixed grain.
- `PALETTES: { lapis, rose, jade, ink }` — Base, two fold colours and the vein colour.

## Parameters
- `palette` (select one of lapis | rose | jade | ink, default "lapis") — Colours
- `scale` (number 0.8–3, default 2.4) — Fineness
- `swirl` (number 0.3–1.6, default 1) — Swirl
- `veins` (number 0–1, default 1) — Veins
- `seed` (integer 1–999, default 4) — Seed

## Composition
- Inputs: Time within the loop; the colours, fineness, swirl, veins and seed.
- Outputs: A full-frame shader image through a bloom pass.
- Coordinates: Screen-centred, ±1 vertically, scaled by the fineness; five warping passes fold the plane.
- Lighting: Self-lit with a faint sheen from the field's slope; the bloom adds softness.
- Timing: update(time, loopSeconds) sets the loop phase; frames render in any order.
- Works with: kinetic-title, number-reveal
- No textures or noise lookups: the whole look is trigonometry, which is why it loops exactly.

## Output and loop
- 1080×1080, 30 fps, 12 s, procedural
- Seamless loop: yes — Every time term in the warps is a whole number of cycles per loop, so the last frame meets the first.
- Verified 2026-10-08 in Chrome 154.0.8037.97 headless on Linux 7.0.0-38-generic (x64), Node 22.14.0 (WebGL 2 via SwiftShader (software)); deterministic: yes; loop check: Frame 0 vs end state (progress 1): mean |Δ| 0.0000, max |Δ| 0 of 255.

## Use it
New project: Create a WebGLRenderer, createLiquidMarble() and createBloomPass(renderer, { width, height }); call marble.setSize(w, h) and each frame marble.update(time, loopSeconds) then bloom.render(marble.scene, marble.camera).

Existing project: Copy src/liquid-marble.js and render marble.scene with marble.camera into your own target.

Reuse ideas:
- Luxury title: Lapis and gold.
- Soft brand: Rose, fine.
- Calm: Jade, slow folds.

## Limitations
- It is a procedural marble, not a fluid simulation: it does not react to objects.
- Very high fineness with strong swirl can alias into fine moiré.

## License
MIT. Copyright (c) 2026 AI Pixel Wizard. Released under the MIT License. See LICENSE in this folder.

Provenance: Original code written for AI Pixel Wizard in October 2026, to the catalog quality bar (docs/QUALITY.md).

