Write the algorithm, get the animation - instrumented data structures that compile your real Python code into interactive HTML visualizations.
Project description
granim
Write the algorithm. Get the animation.
granim instruments its data structures so that running your normal Python code produces an interactive, self-contained HTML animation — nodes appear as you build, arrows flip as you reverse, frontiers light up in parallel, and debug mode shows every variable hopping between nodes.
import granim as ga
@ga.animate(debug=True)
def reverse(node):
if node is None or node.next is None:
return node
new_head = reverse(node.next)
node.next.next = node
node.next = None
return new_head
reverse(ga.linked_list([1, 2, 3, 4, 5]).head) # -> reverse.html, opens in browser
That's the entire integration: one decorator, one constructor. The recursion walks
to null while the call stack panel fills; on the way back, each arrow visibly
reverses (granim classifies node.next.next = node as an edge flip, not a
delete+add).
What you get
- Automatic steps — each loop iteration is one animation beat; same-line mutations (a BFS frontier) merge into one parallel beat. No annotations.
- Debug mode (
debug=True) — all locals in a side panel, plus on-canvas badges: node-valued variables dock to their node, ints near an array become index pointers (lo/hi/midunder the cells). - Five structures —
ga.array,ga.matrix,ga.linked_list,ga.tree,ga.graph, all usable (and unit-testable) without recording. Matrix cells animate values (m[i][j] = v) and colors (m[i][j].state = "visited"). - Your own classes —
@ga.node(value="val")instruments any class without inheritance: node-valued fields become labeled edges, the value field animates, everything else is plain storage. Ad-hoc fields on granim nodes work too (node.random,node.childarc underneath with their name on them).@ga.containerdoes the same for wrappers (queues, custom lists):head/tail-style fields render as floating badges and root the garbage pass, so dropped nodes dim out. - Auto layout — tidy trees (Buchheim), layered DAGs, force-directed graphs, snake-wrapped lists; positions stay stable between steps instead of jumping.
- One file out — interactive player (play/pause/step/scrub/speed) in a single offline HTML file. Jupyter renders inline automatically.
- Zero dependencies.
Examples
examples/ doubles as the acceptance suite:
| file | shows off |
|---|---|
binary_search.py |
auto index badges, comparison pulses |
reverse_recursive.py |
call stack + arrows flipping on unwind |
reverse_iterative.py |
prev/cur/nxt badges hopping |
bst.py |
tidy tree re-flowing as nodes attach |
bfs.py |
parallel frontier steps, state coloring |
dedup.py |
unlinked nodes dim out (reachability pass) |
floyd.py |
tortoise/hare badges meeting; cycle arc |
flood_fill.py |
matrix: values + colors spreading, deep recursion |
dijkstra.py |
weighted edges, frontier/visited/done coloring |
quicksort.py |
pivot glow, swaps, sorted cells locking in |
edit_distance.py |
DP table filling, dependency-cell pulses |
custom_node.py |
@ga.node on a user-owned class (LeetCode 138) |
queue.py |
@ga.container: head/tail badges, dequeued nodes dim |
Run any of them: PYTHONPATH=src python examples/bfs.py → open the HTML next to it.
Tests
python tests/run_tests.py # pure-python pipeline tests (pytest also works)
node tests/verify_html.js # replays each example's timeline, checks end state
Design
docs/PLAN.md holds the rationale, docs/SPEC.md the contracts. The short version:
structures emit a small vocabulary of semantic events; a step builder groups them
into beats (line-scoped via a trace limited to your function); a pure compiler
classifies edge flips, computes layout keyframes, and serializes a timeline that
a dependency-free JS player animates. The trace can only ever coarsen steps —
animation truth comes from the structures.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file granim_viz-0.1.0.tar.gz.
File metadata
- Download URL: granim_viz-0.1.0.tar.gz
- Upload date:
- Size: 41.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1b976ea72708abe6c1be9dc0cdf4fec646d1c133f49601e6c0c3985bdc1c0888
|
|
| MD5 |
d8b4f24456115bfdc1b80c407385d00f
|
|
| BLAKE2b-256 |
8b5b084a6345c096102f4584e6b32c6a49b1ac8b212dd4eb00e4d3c56f96ebac
|
File details
Details for the file granim_viz-0.1.0-py3-none-any.whl.
File metadata
- Download URL: granim_viz-0.1.0-py3-none-any.whl
- Upload date:
- Size: 42.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d77f8b09ef58a1ce115eff0e77fd3e0cded879a415dd60970741f8396aeb3748
|
|
| MD5 |
a80e3c91de422f754ca5c8ab1a24f209
|
|
| BLAKE2b-256 |
3d20a89d9d7055336cd24607c14c8332ef31d607c9126affec947df00348036a
|