{
  "schemaVersion": 1,
  "id": "music-visualizer",
  "version": "1.0.0",
  "status": "published",
  "kind": "object",
  "title": "Music Visualizer",
  "summary": "A round equaliser: two rings of glowing bars around a pulsing orb, kicking on every beat, with a ring of light running out across the floor. Loops perfectly.",
  "description": "A round equaliser. Two rings of glowing bars stand round a pulsing orb: the low notes at the top and bottom of the rings and the high notes at the sides, so the picture is a mirror image like a real spectrum drawn round a circle. A kick on every beat throws the bass bars up, snares and melody lines ripple through the rest, and a ring of light leaves the orb on each beat and runs out across the floor. There is no audio: the spectrum is a formula of the beat. Choose the number of bars, the colours (rainbow, neon, fire or mono), the beats per loop, how hard the bass kicks and whether the camera circles.",
  "role": "Object (3D, three.js): an audio-style visual for music, podcast and event content that needs no audio file.",
  "collections": [
    "backgrounds",
    "hypnotic-loops",
    "particles"
  ],
  "tags": [
    "music visualizer",
    "equalizer",
    "audio spectrum",
    "beat",
    "bars",
    "glow",
    "neon",
    "sound",
    "party",
    "loop",
    "3d"
  ],
  "synonyms": [
    "equaliser",
    "audio visualiser",
    "spectrum analyzer",
    "sound bars",
    "beat visualizer",
    "radial equalizer"
  ],
  "useCases": [
    "A music, podcast or radio title scene",
    "A party, club or event visual",
    "A beat-driven backdrop without any audio"
  ],
  "featured": null,
  "publishedAt": "2026-10-05",
  "implementation": {
    "target": "three",
    "runtime": "browser",
    "language": "javascript",
    "module": "esm",
    "entry": "src/music-visualizer.js",
    "exports": [
      {
        "name": "createEqualiser",
        "signature": "createEqualiser({ bars?, palette?, beats?, punch? }) => { group, setProgress(progress), dispose() }",
        "description": "The two rings of bars, the orb, the halo and the floor, about 11 across, resting on y = 0; render through createBloomPass."
      },
      {
        "name": "createBloomPass",
        "signature": "createBloomPass(renderer, { width, height, glow?, exposure?, grain? }) => { render(scene, camera, output?), dispose() }",
        "description": "A small bloom with an anti-aliased, depth-tested scene target."
      },
      {
        "name": "PALETTES",
        "signature": "PALETTES: { rainbow, neon, fire, mono }",
        "description": "Colour schemes round the rings."
      }
    ],
    "reusable": [
      "src/music-visualizer.js"
    ],
    "demo": "demo.js",
    "harness": "index.html"
  },
  "dependencies": [
    {
      "id": "three",
      "version": "0.185.1",
      "reason": "Renderer, geometry and basic materials."
    },
    {
      "id": "apw-runtime",
      "version": "1.0.0",
      "scope": "demo",
      "reason": "Demo harness."
    }
  ],
  "params": [
    {
      "key": "bars",
      "label": "Bars per ring",
      "type": "integer",
      "min": 24,
      "max": 120,
      "step": 2,
      "default": 64
    },
    {
      "key": "palette",
      "label": "Colours",
      "type": "select",
      "default": "rainbow",
      "options": [
        {
          "value": "rainbow",
          "label": "Rainbow"
        },
        {
          "value": "neon",
          "label": "Neon"
        },
        {
          "value": "fire",
          "label": "Fire"
        },
        {
          "value": "mono",
          "label": "Mono"
        }
      ]
    },
    {
      "key": "beats",
      "label": "Beats per loop",
      "type": "integer",
      "min": 4,
      "max": 16,
      "step": 2,
      "default": 8
    },
    {
      "key": "punch",
      "label": "Bass punch",
      "type": "number",
      "min": 0.4,
      "max": 1.8,
      "step": 0.1,
      "default": 1
    },
    {
      "key": "orbit",
      "label": "Camera circles",
      "type": "boolean",
      "default": true
    }
  ],
  "presets": [
    {
      "id": "default",
      "label": "Rainbow, eight beats",
      "params": {}
    },
    {
      "id": "neon",
      "label": "Neon, fast",
      "params": {
        "palette": "neon",
        "beats": 16,
        "bars": 80
      }
    },
    {
      "id": "fire",
      "label": "Fire, heavy bass",
      "params": {
        "palette": "fire",
        "punch": 1.7,
        "beats": 8
      }
    },
    {
      "id": "mono",
      "label": "Mono, slow",
      "params": {
        "palette": "mono",
        "beats": 4,
        "punch": 0.7
      }
    }
  ],
  "output": {
    "width": 1080,
    "height": 1080,
    "fps": 30,
    "durationSeconds": 16,
    "posterSeconds": 2,
    "alpha": false,
    "motion": "procedural",
    "loop": {
      "seamless": true,
      "cycleSeconds": 16,
      "method": "The kick, the snare and the melody lines are functions of the beat with whole numbers of beats and cycles per loop, and the camera makes one full circle per loop, so the last frame meets the first."
    },
    "seed": null
  },
  "composition": {
    "inputs": "Time within the loop; the bars, colours, beats, punch and camera.",
    "outputs": "A full frame rendered in 3D through an anti-aliased bloom.",
    "coordinates": "The rings of radius 3.0 and 4.2 are centred on the origin on y = 0; the orb floats at y = 1.2; the camera looks down at about 36°.",
    "lighting": "Self-lit bars and orb; the bloom gives the glow.",
    "timing": "setProgress(progress) sets every bar's height from the beat; frames render in any order.",
    "compatibleWith": [
      "kinetic-title",
      "number-reveal"
    ],
    "notes": [
      "Two instanced bar sets with instance colours; the spectrum is mirrored left-right by taking the cosine of the angle."
    ]
  },
  "reuse": [
    "Podcast or radio: Rainbow, eight beats.",
    "Club: Neon, fast.",
    "Hard hitting: Fire, heavy bass."
  ],
  "integration": {
    "newProject": "Create a WebGLRenderer, createEqualiser() and createBloomPass(renderer, { width, height }); each frame call eq.setProgress(progress) and bloom.render(scene, camera).",
    "existingProject": "Copy src/music-visualizer.js; add eq.group to your scene and render it through createBloomPass."
  },
  "performance": {
    "notes": "One instanced draw of up to 240 bars plus a few meshes and the bloom: about 2 ms a frame on an integrated Intel GPU.",
    "limits": "Software WebGL renders in about two seconds a frame."
  },
  "limitations": [
    "The spectrum is a formula, not driven by audio: to react to real sound feed the bar heights from an analyser.",
    "Neighbouring bars touch at the highest bar counts."
  ],
  "license": {
    "spdx": "MIT",
    "notice": "Copyright (c) 2026 AI Pixel Wizard. Released under the MIT License. See LICENSE in this folder.",
    "thirdParty": []
  },
  "provenance": "Adapted from the owner's threejs-sketches/data-information/music-visualizer (MIT) and rebuilt for AI Pixel Wizard in October 2026 as an original scene: a formula-driven radial spectrum with kick and snare envelopes, a pulsing orb and an expanding ring of light, through a bloom, on an exact loop.",
  "changelog": [
    {
      "version": "1.0.0",
      "date": "2026-10-05",
      "notes": "Initial release."
    }
  ]
}
