DEV Community

Cover image for I built a Sorting Visualizer you can actually step through (bars, pointers, pseudocode & confetti)
Salman Sadik Siddiquee
Salman Sadik Siddiquee

Posted on

I built a Sorting Visualizer you can actually step through (bars, pointers, pseudocode & confetti)

In the last post I shared the 2D Array Visualizer — paste a JSON matrix, color it by value, and see how a grid maps to rows and columns.

This time I added the thing people actually asked for: a Sorting Visualizer. Not a static diagram — something you can press play on, step through one comparison at a time, and watch the algorithm think.

👉 Live: visualizer-gold.vercel.app/algorithms/sorting
Code: github.com/salsadsid/visualizer

DSA Visualizer home page with a live, looping bubble-sort demo


Why another sorting visualizer?

There are plenty out there, but most show you bars moving without connecting them to the code or the variables doing the work. When you're learning, the hard part isn't "the big bar moves right" — it's "wait, what is j right now, and why did min jump?"

So I built it around three goals:

  1. Beginner-first — every step has a plain-English sentence explaining what just happened.
  2. Show the variables — the loop counters (i, j, min) and flags (key, swapped) are drawn right on the board, not hidden in your head.
  3. Make it joyful — gradient bars, pops on every swap, and a little confetti when it finishes. Learning should feel good.

A tour of the visualizer

Press play — or take it one step at a time

Pick Bubble, Selection, or Insertion sort, then drive it however you like: play/pause, step forward and back, scrub the timeline, or change the speed from 0.5× to 4×. (Keyboard works too: Space to play/pause, / to step.)

Sorting Visualizer initial state — bars, controls, pseudocode and legend

On the right is the pseudocode, and the line that's currently executing is highlighted. That single detail is what makes the whole thing click — you see the code and its effect at the same instant.

Watch the swaps — and the variables behind them

Here's a mid-run snapshot of bubble sort. Two bars are rose-red because they're being swapped, the pseudocode is sitting on swap(a[j], a[j+1]), and below the bars you can see the live state:

  • a j pointer marking exactly which pair is being compared
  • the variable chips i = 0 and swapped = true
  • a running tally of comparisons / swaps / writes

Bubble sort mid-run: rose swap bars, a j pointer, live variables, and highlighted pseudocode

No more guessing what the indices are — they're on screen, updating every step.

Three algorithms, three personalities

Switch to selection sort and the board grows two more pointers: i (the slot being filled), min (the smallest value found so far), and j (the scanner). Watching min hop to a new bar the moment it finds something smaller is the clearest way I know to get selection sort.

Selection sort showing i, min and j pointers under the bars

Notice the stats too: selection sort racks up comparisons but barely any swaps — that's its whole personality (fewest writes of the three).

…and a little celebration

When the array is fully sorted, the bars turn green and 🎉 confetti rains over the board. It's a tiny thing, but finishing a run feels like an accomplishment.

Sorted! All bars green with a confetti burst

Bring your own data

Don't just watch the demo — feed it your own numbers. There are one-click presets (random, reversed, nearly-sorted, few-unique, already-sorted), a size slider, and a 🎲 Shuffle button.

Best of all, you can type or paste your own array right into the input — [5, 3, 8, 1, 9, 2], a bare 5 3 8 1, or even a multi-line list copied straight from your editor all work. Want to see how bubble sort behaves on an already-sorted list, or watch insertion sort fly through a nearly-sorted one? Paste it and hit play.

And because it's a learning tool, the validation is friendly: drop in a decimal or an out-of-range value and it nudges you with a playful, plain-English hint ("Whoa, 100 is off the charts! 📏 …") instead of a cryptic error.


Learn the algorithms (the short version)

Every visualizer also ships with a built-in learning panel right below the bars — a tabbed Concept · Use cases · Complexity breakdown, plus ready-to-copy implementations in C++, Python, JavaScript & TypeScript. So once a sort clicks visually, the theory and the real code are one scroll away. Here's the gist:

All three are comparison sorts (they only compare pairs), in-place (O(1) extra memory), and O(n²) on average — perfect for learning and for small or nearly-sorted data.

🫧 Bubble sort

Repeatedly walk the list and swap any adjacent pair that's out of order, so big values "bubble" to the right. If a whole pass makes no swaps, it stops early.

Best Average Worst Space Stable
O(n) O(n²) O(n²) O(1)

🎯 Selection sort

Each pass finds the smallest remaining value and drops it into the next slot. Always O(n²), but does the fewest swaps (≤ n−1) — handy when writes are expensive.

Best Average Worst Space Stable
O(n²) O(n²) O(n²) O(1)

📥 Insertion sort

Grow a sorted prefix one element at a time, sliding each new key into place — exactly how you sort a hand of cards. The best real-world performer of the three on small or nearly-sorted data, and it powers the base case of hybrid sorts like Timsort and introsort.

Best Average Worst Space Stable
O(n) O(n²) O(n²) O(1)

How it works under the hood

The trick that keeps this maintainable: algorithms don't touch the DOM. Each sort is a plain function that records a list of snapshots — one per meaningful moment — and the UI just plays that list back.

A snapshot (a "step") looks like this:

Step = {
  array,        // the working array at this moment
  highlights,   // { [index]: "compare" | "swap" | "min" | "key" | "shift" | "sorted" }
  pointers,     // { i, j, min }      → drawn as ▲ markers under the bars
  vars,         // { key, swapped }   → shown as chips
  line,         // which pseudocode line is active
  message,      // the plain-English narration
  stats,        // { comparisons, swaps, writes }
}
Enter fullscreen mode Exit fullscreen mode

So bubble sort is just a generator that pushes steps as it goes (simplified — the
recorder snapshots the array, stats, pointers and "sorted" indices on every push,
whose first argument is the pseudocode line to highlight):

function bubble(values) {
  const a = values.slice();
  const r = makeRecorder(a);

  for (let i = 0; i < a.length - 1; i++) {
    let swapped = false;
    r.vars.i = i;
    for (let j = 0; j < a.length - 1 - i; j++) {
      r.pointers.j = j;
      r.stats.comparisons++;
      // line 3 = "if a[j] > a[j+1]"
      r.push(3, `Compare ${a[j]} and ${a[j + 1]}`, {
        [j]: "compare",
        [j + 1]: "compare",
      });

      if (a[j] > a[j + 1]) {
        [a[j], a[j + 1]] = [a[j + 1], a[j]];
        swapped = true;
        r.vars.swapped = true;
        r.stats.swaps += 1;
        r.stats.writes += 2;
        // line 4 = "swap(a[j], a[j+1])"
        r.push(4, "Swapped!", { [j]: "swap", [j + 1]: "swap" });
      }
    }
    if (!swapped) break; // a clean pass → already sorted, stop early
  }
  return r.steps;
}
Enter fullscreen mode Exit fullscreen mode

A small usePlayer hook owns the timeline (current index, play/pause, speed), and shared components render whatever the current step says:

const player = usePlayer(steps);
const step = player.step;

<BarChart array={step.array} highlights={step.highlights} pointers={step.pointers} />
<VarChips vars={step.vars} />
<Pseudocode lines={pseudocode} activeLine={step.line} />
<StatsRow stats={step.stats} message={step.message} />
<PlayerControls player={player} />
Enter fullscreen mode Exit fullscreen mode

The payoff: adding a new algorithm is just writing a new step generator. The bars, pointers, pseudocode highlighting, scrubber, and stats all come for free. That's how counting sort, merge sort, and friends will land next.

The Algorithms hub — Sorting shipped, more on the way

The whole thing is built with Next.js 16, React 19, and Tailwind CSS 4, runs entirely in the browser (no backend), supports light/dark themes, and respects prefers-reduced-motion so all the motion turns off if you've asked your OS to reduce it.


What's next

On the roadmap: counting sort & frequency arrays, then merge/quick sort, binary search, and the core array techniques (prefix sums, two pointers, sliding window) — each as its own step-through visualizer.

If you want to see how a sort actually works (or send it to someone who's learning), give it a spin:

I'd love feedback — which algorithm should I visualize next? Drop a comment 👇

Top comments (0)