{
  "schemaVersion": 1,
  "id": "sorting-ballet",
  "version": "1.0.0",
  "status": "published",
  "kind": "object",
  "title": "Sorting Ballet",
  "summary": "A row of rainbow bars sorts itself as a dance, every swap a hop, then un-sorts again. Loops perfectly.",
  "description": "A row of rainbow bars that sorts itself as a dance. A sorting algorithm (insertion, bubble, selection or quick sort) runs on a shuffled row; every swap is two bars hopping past each other in an arc, one over and one under. When the row is in order a wave of lift runs along it, then the same dance is played backwards until the row is shuffled again. Choose the number of bars, the algorithm, where the rainbow starts, how high the bars hop, the seed that shuffles the row, the backdrop colour and whether the camera sways.",
  "role": "Object (3D, three.js): the favourite algorithm visualisation, as a satisfying studio loop.",
  "collections": [
    "satisfying",
    "hypnotic-loops",
    "kinetic-text"
  ],
  "tags": [
    "sorting",
    "sorting algorithm",
    "bars",
    "rainbow",
    "data",
    "algorithm",
    "insertion sort",
    "quick sort",
    "bubble sort",
    "studio",
    "loop",
    "3d"
  ],
  "synonyms": [
    "sorting visualisation",
    "algorithm animation",
    "bubble sort",
    "insertion sort",
    "quicksort",
    "bars swapping"
  ],
  "useCases": [
    "A computer science or algorithms explainer",
    "A data or developer brand scene",
    "A satisfying rainbow loop"
  ],
  "featured": null,
  "publishedAt": "2026-10-06",
  "implementation": {
    "target": "three",
    "runtime": "browser",
    "language": "javascript",
    "module": "esm",
    "entry": "src/sorting-ballet.js",
    "exports": [
      {
        "name": "createSortingBallet",
        "signature": "createSortingBallet({ bars?, algorithm?, hue?, hop?, seed? }) => { group, swaps, setProgress(progress), dispose() }",
        "description": "The row of instanced bars (about 15 wide) resting on y = 0; `swaps` is the number of swaps the algorithm needs; needs an environment map."
      },
      {
        "name": "sortingSwaps",
        "signature": "sortingSwaps(values, algorithm?) => [slotA, slotB][]",
        "description": "The list of swaps that sorts a row of numbers with the chosen algorithm."
      }
    ],
    "reusable": [
      "src/sorting-ballet.js"
    ],
    "demo": "demo.js",
    "harness": "index.html"
  },
  "dependencies": [
    {
      "id": "three",
      "version": "0.185.1",
      "reason": "Renderer, geometry and shader materials."
    },
    {
      "id": "chrome-material",
      "version": "1.1.0",
      "scope": "demo",
      "reason": "Studio environment light, backdrop and contact shadow."
    },
    {
      "id": "apw-runtime",
      "version": "1.0.0",
      "scope": "demo",
      "reason": "Demo harness."
    }
  ],
  "params": [
    {
      "key": "bars",
      "label": "Bars",
      "type": "integer",
      "min": 12,
      "max": 48,
      "step": 1,
      "default": 24
    },
    {
      "key": "algorithm",
      "label": "Algorithm",
      "type": "select",
      "default": "insertion",
      "options": [
        {
          "value": "insertion",
          "label": "Insertion sort"
        },
        {
          "value": "bubble",
          "label": "Bubble sort"
        },
        {
          "value": "selection",
          "label": "Selection sort"
        },
        {
          "value": "quick",
          "label": "Quick sort"
        }
      ]
    },
    {
      "key": "hue",
      "label": "Rainbow start",
      "type": "number",
      "min": 0,
      "max": 1,
      "step": 0.05,
      "default": 0
    },
    {
      "key": "hop",
      "label": "Hop height",
      "type": "number",
      "min": 0.4,
      "max": 2,
      "step": 0.1,
      "default": 1
    },
    {
      "key": "seed",
      "label": "Seed",
      "type": "integer",
      "min": 1,
      "max": 999,
      "step": 1,
      "default": 9
    },
    {
      "key": "background",
      "label": "Backdrop",
      "type": "color",
      "default": "#1a1d2a"
    },
    {
      "key": "orbit",
      "label": "Camera sway",
      "type": "boolean",
      "default": true
    }
  ],
  "presets": [
    {
      "id": "default",
      "label": "Insertion, 24 bars",
      "params": {}
    },
    {
      "id": "quick",
      "label": "Quick sort, 32 bars",
      "params": {
        "algorithm": "quick",
        "bars": 32,
        "hue": 0.5,
        "background": "#1a2230"
      }
    },
    {
      "id": "selection",
      "label": "Selection, big hops",
      "params": {
        "algorithm": "selection",
        "bars": 16,
        "hop": 1.8,
        "background": "#2a1a24"
      }
    },
    {
      "id": "bubble",
      "label": "Bubble, many bars",
      "params": {
        "algorithm": "bubble",
        "bars": 18,
        "hue": 0.2,
        "seed": 31
      }
    }
  ],
  "output": {
    "width": 1080,
    "height": 1080,
    "fps": 30,
    "durationSeconds": 20,
    "posterSeconds": 10,
    "alpha": false,
    "motion": "procedural",
    "loop": {
      "seamless": true,
      "cycleSeconds": 20,
      "method": "The sort runs forward over the first half of the loop, the row holds in order for a moment with a wave of lift, and the same swaps are played backwards over the second half, so the row is back to its shuffled start at the last frame."
    },
    "seed": {
      "param": "seed",
      "behavior": "Seed shuffles the row: same seed, same shuffle and same swaps."
    }
  },
  "composition": {
    "inputs": "Time within the loop; the bars, algorithm, rainbow start, hop height, seed, backdrop and camera sway.",
    "outputs": "A full frame rendered in 3D with a studio environment.",
    "coordinates": "The bars stand on y = 0, about 15 wide and up to 4.8 tall; swapping bars hop in an arc and slide ±0.9 in depth to pass each other.",
    "lighting": "A warm key light with a shadow map, a floor and the studio environment.",
    "timing": "setProgress(progress) replays the swaps up to the current moment (at most a few hundred); frames render in any order.",
    "compatibleWith": [
      "chrome-material",
      "orbit-camera",
      "kinetic-title",
      "number-reveal"
    ],
    "notes": [
      "Bubble sort needs the most swaps; the dance runs at a steady rate of swaps per second, so more bars make a faster dance."
    ]
  },
  "reuse": [
    "CS explainer: Insertion, 24 bars.",
    "Fast and busy: Bubble, many bars.",
    "Calm: Selection, big hops."
  ],
  "integration": {
    "newProject": "Create a WebGLRenderer with a studio environment and a shadow-casting light, add createSortingBallet().group and call row.setProgress(progress) each frame.",
    "existingProject": "Copy src/sorting-ballet.js; add the group to your scene with an environment map."
  },
  "performance": {
    "notes": "One instanced draw call of up to 48 bars with a shadow map; replaying up to a thousand swaps per frame on the CPU: under a millisecond.",
    "limits": "Software WebGL renders in about a second a frame."
  },
  "limitations": [
    "The dance speed depends on the number of swaps: bubble sort with many bars is very fast.",
    "Only swaps are shown, not the comparisons."
  ],
  "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/sorting-ballet (MIT) and rebuilt for AI Pixel Wizard in October 2026 as an original studio object: precomputed swap lists for four algorithms replayed at a steady rate with hopping bars, a lift wave when sorted and the same dance in reverse on an exact loop.",
  "changelog": [
    {
      "version": "1.0.0",
      "date": "2026-10-05",
      "notes": "Initial release."
    }
  ]
}
