44 interactive lessons that teach data structures & algorithms by animating them — from "I've never written code" to A*, Dijkstra and dynamic programming. No account. No paywall. No videos.
Most DSA resources hand you a wall of text and a finished code block, and expect the algorithm to assemble itself in your head. That works if you can already run code in your head. If you can't, you get stuck — and you conclude you're "bad at algorithms."
You're not. You just can't see it.
Every lesson here starts in plain English with a real-world analogy, then lets you watch the algorithm execute, one step at a time, at your own pace, on your own numbers. The code highlights the line it's running. The variables show what it's holding in its head. A plain sentence explains each step as it happens.
Nothing is pre-recorded. Every animation is generated by actually running the algorithm.
git clone https://github.com/sumitsingh4411/VisualDSA.git
cd VisualDSA
npm install
npm run dev # → http://localhost:3000npm test # 613 tests — the engine, every algorithm, the content
npm run typecheck # strict TypeScript
npm run build # every page prerenders to static HTMLNo database, no API keys, no .env to fill in. It runs offline.
Every one of the 44 lessons has all seven of these — none are stubs:
| Start here | The idea in plain English, written for someone who has never coded |
| Picture it | A real-world analogy before any code appears |
| Watch it run | The interactive visualization — play, pause, step, scrub, and type your own input |
| What it costs | Big-O, with a chart of how it actually grows |
| Common traps | The mistakes people really make (off-by-one, the <=, the missing base case) |
| Check yourself | A quiz that explains why, right or wrong |
| Practice | Hand-picked LeetCode problems that use exactly this technique |
The code panel shows JavaScript, Python, Java and C++, all four lined up line-for-line — and the highlighted line follows the animation no matter which tab you pick.
44 lessons · 8 levels · ~7.5 hours · 1,139 animation steps
The row of boxes everything is built on.
| Lesson | The idea |
|---|---|
| Arrays & Memory | The row of numbered boxes that everything else is built on |
| Strings | A string is an array of characters. Everything else follows |
| 2D Arrays | The grid is a fiction. Memory is one flat line — and that's why row-major is fast |
| Hash Map | Turn a key straight into a location — the structure behind almost everything |
| Sets | A hash map that threw away the values — "seen this before?", instantly |
Finding one thing among many — the slow honest way, then the fast clever way.
| Lesson | The idea |
|---|---|
| Linear Search | Check every box until you find it. Simple, honest, slow |
| Binary Search | Throw away half the list with every single question |
| Ternary Search | Cut into thirds instead of halves — and discover it's actually slower |
Putting things in order, and discovering that how you do it matters enormously.
| Lesson | The idea |
|---|---|
| Bubble Sort | Compare neighbours, swap if wrong. Repeat until calm |
| Selection Sort | Find the smallest. Put it in front. Repeat |
| Insertion Sort | How you actually sort a hand of cards, without being taught |
| Merge Sort | Split until it's trivial, then merge back in order |
| Quick Sort | Pick a pivot, split around it, let the halves sort themselves |
| Heap Sort | Turn the array into a heap, then keep taking the biggest off the top |
| Shell Sort | Insertion sort, but values may leap instead of crawl |
| Counting Sort | Sorts without comparing anything — that's how it beats n log n |
| Radix Sort | Sort by the last digit first. It sounds backwards, and it's the only way it works |
Two structures that differ by one decision — and become completely different tools.
| Lesson | The idea |
|---|---|
| Stack | Last in, first out. The undo button of data structures |
| Queue | First in, first out. Fairness, as a data structure |
| Deque | A queue open at both ends — a stack and a queue in one |
| Circular Queue | A queue in a fixed array that never shuffles — the pointers go round instead |
Giving up instant access to buy cheap insertion. The first real trade-off.
| Lesson | The idea |
|---|---|
| Linked List | No shelves, no addresses — just a chain of notes saying "next" |
| Doubly Linked List | One extra pointer per node — and the singly linked list's worst flaw disappears |
| Circular Linked List | The tail points back at the head. There is no end — and that's the point |
When a list isn't enough and your data starts to branch.
| Lesson | The idea |
|---|---|
| Binary Search Tree | Keeps one promise — smaller left, bigger right — so it can search fast |
| Tree Traversals | Three ways to visit every node — and why the order matters |
| Heap & Priority Queue | A tree that always keeps the biggest thing on top, ready to grab |
| AVL Tree | A search tree that refuses to become a list — it rotates itself level again |
| Segment Tree | Every node stores the answer for a whole range — so a range query stops early |
| Trie | Words that start the same share the same path — so autocomplete is free |
Anything connected to anything: maps, friendships, the internet itself.
| Lesson | The idea |
|---|---|
| Breadth-First Search | Explore a network in rings, nearest first — using a queue |
| Depth-First Search | Plunge down one path to the end, then back up and try the next |
| Topological Sort | Put jobs in an order where nothing happens before what it depends on |
| Dijkstra's Shortest Path | The cheapest route through a weighted map — always finish the nearest place first |
| Bellman–Ford | Slower than Dijkstra, and it can do the one thing Dijkstra can't |
| A* Search | Dijkstra with a sense of direction — it guesses what's left, and aims |
| Union-Find | "Are these two connected?" — in effectively constant time |
The moves that unlock the hard problems.
| Lesson | The idea |
|---|---|
| Recursion & the Call Stack | A function that calls itself — and the pile of calls that piles up |
| Two Pointers | Two markers moving toward each other turn an O(n²) search into O(n) |
| Sliding Window | Reuse the last answer instead of recomputing |
| Monotonic Stack | A stack kept in order — one new value answers many old questions at once |
| Greedy Algorithms | Always take the best-looking option right now — and sometimes that's provably optimal |
| Backtracking | Guess, explore, and when it dead-ends — put it back exactly as it was |
| Dynamic Programming | Solve each small problem once, write the answer down, never solve it again |
📊 Big-O cheat sheet — all 44, best / average / worst / space
| Algorithm | Best | Average | Worst | Space |
|---|---|---|---|---|
| Arrays & Memory | O(1) to read | O(n) to insert | O(n) to insert | O(n) |
| Strings | O(1) index | O(n) to scan | O(n) to scan | O(1) |
| 2D Arrays | O(1) to read a cell | O(r × c) to scan | O(r × c) | O(r × c) |
| Hash Map | O(1) | O(1) | O(n) | O(n) |
| Sets | O(1) | O(1) | O(n) | O(n) |
| Linear Search | O(1) | O(n) | O(n) | O(1) |
| Binary Search | O(1) | O(log n) | O(log n) | O(1) |
| Ternary Search | O(1) | O(log n) | O(log n) | O(1) |
| Bubble Sort | O(n) | O(n²) | O(n²) | O(1) |
| Selection Sort | O(n²) | O(n²) | O(n²) | O(1) |
| Insertion Sort | O(n) | O(n²) | O(n²) | O(1) |
| Merge Sort | O(n log n) | O(n log n) | O(n log n) | O(n) |
| Quick Sort | O(n log n) | O(n log n) | O(n²) | O(log n) |
| Heap Sort | O(n log n) | O(n log n) | O(n log n) | O(1) |
| Shell Sort | O(n log n) | ≈ O(n^1.3) | O(n²) | O(1) |
| Counting Sort | O(n + k) | O(n + k) | O(n + k) | O(k) |
| Radix Sort | O(d × n) | O(d × n) | O(d × n) | O(n + b) |
| Stack | O(1) push | O(1) pop | O(1) peek | O(n) |
| Queue | O(1) enqueue | O(1) dequeue | O(n) if built badly | O(n) |
| Deque | O(1) | O(1) | O(1) | O(n) |
| Circular Queue | O(1) | O(1) | O(1) | O(capacity) |
| Linked List | O(1) insert at head | O(n) to find | O(n) to reach the tail | O(n) |
| Doubly Linked List | O(1) delete a known node | O(n) to find | O(n) to find | O(n) |
| Circular Linked List | O(1) insert at head | O(n) to find | O(n) full lap | O(n) |
| Binary Search Tree | O(log n) | O(log n) | O(n) | O(n) |
| Tree Traversals | O(n) | O(n) | O(n) | O(n) |
| Heap & Priority Queue | O(1) | O(log n) | O(log n) | O(n) |
| AVL Tree | O(log n) | O(log n) | O(log n) | O(n) |
| Segment Tree | O(log n) query | O(log n) update | O(n) to build | O(n) |
| Trie | O(L) | O(L) | O(L) | O(total characters) |
| Breadth-First Search | O(V + E) | O(V + E) | O(V + E) | O(V) |
| Depth-First Search | O(V + E) | O(V + E) | O(V + E) | O(V) |
| Topological Sort | O(V + E) | O(V + E) | O(V + E) | O(V) |
| Dijkstra's Shortest Path | O(E log V) | O(E log V) | O(E log V) | O(V) |
| Bellman–Ford | O(E) | O(V × E) | O(V × E) | O(V) |
| A* Search | O(E) | O(E log V) | O(E log V) | O(V) |
| Union-Find | O(1) | O(α(n)) | O(α(n)) | O(n) |
| Recursion & the Call Stack | O(n) | O(n) | O(n) | O(n) |
| Two Pointers | O(1) | O(n) | O(n) | O(1) |
| Sliding Window | O(n) | O(n) | O(n) | O(1) |
| Monotonic Stack | O(n) | O(n) | O(n) | O(n) |
| Greedy Algorithms | O(n log n) | O(n log n) | O(n log n) | O(1) |
| Backtracking | O(n!) | O(n!) | O(n!) | O(n) |
| Dynamic Programming | O(n·k) | O(n·k) | O(n·k) | O(n) |
Every row is read from the lesson itself — the table and the site cannot disagree.
|
Roadmap — the whole curriculum as one winding trail, coloured cool→warm as difficulty rises. Your progress fills it in. |
Topics — already know what you want? Search all 44 and jump straight there. |
|
Problems — 106 hand-picked LeetCode problems, each mapped to the lesson that teaches it. Learn the technique, then go solve it. |
Paths — you've learned DSA, now what? Four honest directions: interviews, competitive programming, ICPC, real-world dev. |
An algorithm is not an animation. It's a generator that yields immutable snapshots.
Every algorithm is a plain TypeScript generator that yields a Frame at each meaningful
step:
type Frame = {
data; // the array / tree / graph at this instant
pointers; // named cursors: i, low, mid, head
highlights; // which index is comparing / swapping / sorted / found
codeLine; // which source line is executing right now
variables; // what the algorithm is holding in its head
explanation; // one plain sentence — this is also the dry-run row
stats; // running comparison / swap counts
};runAlgorithm() drains the generator into a Frame[]. From there, every feature in the
UI is just a view over one index into that array:
| Feature | How it works |
|---|---|
| play / pause / step / scrub | index++, index--, drag the index |
| the written dry run | frames.map(f => f.explanation) |
| the synced code highlight | frames[index].codeLine |
| live variables & pointers | frames[index].variables |
| the custom-input playground | re-run the generator on new input |
| the timeline "fingerprint" | one coloured tick per frame |
Because the stage, the code panel, the variables and the walkthrough all read the same index, they can never disagree about which step you're on. That's the whole trick.
The architecture exists so new topics are cheap. Three steps, and you never touch a component:
- Write the generator in
src/lib/algorithms/….yieldaFrameat each step, setcodeLineto the matching line of your source andexplanationto one plain sentence. - Write a test next to it. Assert the output is correct and that the teaching claim holds — a sort that reports the wrong complexity is a bug in the lesson, not just the code.
- Add a content module in
src/lib/content/lessons/implementingLesson: intro, analogy, four-language code, complexity, common traps, quiz, practice problems. Register it insrc/lib/content/index.ts.
The player, controls, dry run, code sync, complexity chart, quiz and playground all light
up automatically. Only a genuinely new visual shape costs a component — one file in
viz/, one case in viz/Stage.tsx. There are 11 so far: bars, array, stack, queue, list,
call stack, tree, trie, graph, grid, hash.
For a teaching tool, the animation must not lie. The generators are pure functions, so the suite asserts the pedagogy directly — not just "did it sort":
- bubble sort really costs
n(n−1)/2comparisons on reversed input - insertion sort really is
O(n)on already-sorted input — its entire selling point - binary search really finds any value among 1024 items in ≤ 11 looks, while linear search takes 1024
- Dijkstra really returns
A→C→G = 14, not the shorter-looking route - no frame ever emits an out-of-range pointer, or a
codeLinepast the end of its own source
613 tests. If an animation lied, a test would fail.
One honest caveat, learned the hard way: these tests assert frames, not layout. They once passed while every sorting bar silently rendered at zero height, because a CSS percentage had no parent to measure against. Frame correctness is not pixel correctness — open a browser.
src/
lib/engine/ Frame types, runAlgorithm(), usePlayer() state machine
lib/algorithms/ pure generators — sorting, searching, structures, graphs, DP
lib/content/ typed lesson modules + the curriculum registry
components/viz/ one component per data shape; renders a Frame, nothing more
components/player/ controls, timeline, synced code, variables, dry run
components/lesson/ lesson sections (analogy, complexity, traps, quiz, playground)
components/landing/ hero, particle field, the roadmap trail, FAQ
components/paths/ the post-DSA guides
store/ Zustand + localStorage: XP, streak, completion, bookmarks
Next.js 16 (App Router) · React 19 · TypeScript (strict) · Tailwind v4 · Framer Motion · Zustand · Lucide · Vitest
No backend, accounts, database, live code execution, AI tutor, audio or PWA. Progress lives in your browser, so there's no signup wall between a curious visitor and their first lesson — the trade-off is that progress is per-device.
These were scoped out on purpose, to spend the effort making the visualizations extraordinary instead. The architecture leaves clean room to add them later.
Deployed on Vercel at visualdsa.nextjoblist.com.
Import the repo, add the domain, ship — there is nothing to configure. A production build
already resolves to that origin, and canonical URLs, sitemap.xml, robots.txt and all
Open Graph images derive from it.
Changing the domain later, or deploying your own copy? Either edit PRODUCTION_URL in
src/lib/site.ts, or override it without touching code:
NEXT_PUBLIC_SITE_URL=https://your-domain.com npm run buildNew lessons, better analogies, clearer explanations and bug fixes are all welcome — see Adding a lesson. The one rule: if the animation teaches it, a test must assert it.
Built for the person who was told they're bad at algorithms.





