# Bass Pulse — `bass-pulse@1.0.0`

A speaker cone kicks on every beat and rings of pressure race outwards, bending a neon grid. Loops perfectly.

A deep bass note made visible: at every beat the cone of a speaker at the centre kicks and a ring of pressure leaves it, racing outwards, thinning and fading, bending the neon grid of the floor behind it and splitting into its colours at its edge. Several rings are always in flight, so the whole screen throbs in rhythm. Choose the colours (neon, fire, ice or mono), the beats per loop, how many rings are in flight, their punch, thickness and decay, and how much the grid bends.

- Kind: background; status: published; digest sha256:2d8e3029463a95c73d8797e65ab42f57f36a2521c0f39ca5968047b73953dd12
- Role: Background (WebGL shader, full frame): a rhythmic, bass-heavy backdrop for music, club, gaming and title content.
- Implementation: three; entry `src/bass-pulse.js`
- Files: https://aipixelwizard.com/registry/bass-pulse/1.0.0/<path> (`LICENSE`, `asset.json`, `demo.js`, `index.html`, `src/bass-pulse.js`)
- Manifest JSON: https://aipixelwizard.com/api/v1/visuals/bass-pulse/versions/1.0.0
- Runnable demo: https://aipixelwizard.com/registry/bass-pulse/1.0.0/index.html (open over http; it imports sibling packages by relative path)
- Dependencies (exact): `three@0.185.1` (source) — Renderer, geometry and shader materials.; `apw-runtime@1.0.0` (demo) — Demo harness.

## Exports
- `createBassPulse({ beats?, rings?, palette?, punch?, thickness?, decay?, warp? }) => { scene, camera, setSize(width, height), update(time, loopSeconds), dispose() }` — The speaker, rings and grid 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 filmic tone mapping.
- `PALETTES: { neon, fire, ice, mono }` — Core, fringe and grid colours (sRGB hex).

## Parameters
- `beats` (integer 2–16, default 8) — Beats per loop
- `rings` (integer 3–12, default 6) — Rings in flight
- `palette` (select one of neon | fire | ice | mono, default "neon") — Colours
- `punch` (number 0.5–2, default 1) — Punch
- `thickness` (number 0.01–0.08, default 0.025) — Ring thickness
- `decay` (number 0.2–1.2, default 0.6) — Decay: How fast a ring fades.
- `warp` (number 0–2, default 1) — Grid bend

## Composition
- Inputs: Time within the loop; the beats, rings, colours, punch, thickness, decay and grid bend.
- Outputs: A full frame, drawn by one shader on a full-screen quad.
- Coordinates: Centred on the frame, 1 = the frame's half-height; rings travel out to 1.35.
- Lighting: Self-lit; the bloom gives the glow.
- Timing: update(time, loopSeconds) sets the loop phase; frames render in any order.
- Works with: kinetic-title, number-reveal
- Each ring is a Gaussian band whose centre is 1.35·(1 − (1 − a)^2.2), whose width grows with age a and whose brightness decays; red and blue are sampled slightly inside and outside it for the colour fringe.

## Output and loop
- 1080×1080, 30 fps, 8 s, procedural
- Seamless loop: yes — Rings are born at every beat and a whole number of beats make a loop; ring i has age fract((beat + i) / rings), so the set of ring ages after the loop is the set before and everything else is a function of the beat's fractional part.
- Verified 2026-10-06 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, createBassPulse() and createBloomPass(renderer, { width, height }); call pulse.setSize(width, height), then each frame pulse.update(time, loopSeconds) and bloom.render(pulse.scene, pulse.camera).

Existing project: Copy src/bass-pulse.js; render pulse.scene with pulse.camera into a render target (or through the bloom pass) as a backdrop.

Reuse ideas:
- Club or DJ title: Neon, eight beats.
- Heavy intro: Fire, heavy.
- Product backdrop: Mono, wide rings.

## Limitations
- The rhythm is a regular count, not driven by audio.
- The rings are circles in a plane, not a simulation of a pressure wave.

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

Provenance: Adapted from the owner's threejs-sketches/audio-musical/bass-pulse (MIT) and rebuilt for AI Pixel Wizard in October 2026 as an original shader: beat-born rings with chromatic fringes bending a neon grid, a kicking speaker cone and an exact loop.

