Graphs
Each block is the whole file — copy it into x.manic and run manic x.manic (live) or --record out (video).
graph
Labelled nodes + edges, drawn on; reflowing links.
// Graph — the algo kit's `graph` builtin (Manim's Graph/DiGraph). Nodes are
// labelled circles; `a-b` is an undirected edge, `a>b` a directed arrow. Tag
// broadcast (`draw(g.edges)`, `flash(g.nodes, …)`) animates whole groups.
//
// manic examples/graph.manic
// manic examples/graph.manic --record out --fps 60
title("Graph");
canvas(1280, 720);
text(head, (640, 118), "a directed graph, traversed");
display(head); color(head, cyan); size(head, 34); hidden(head);
text(cap, (640, 664), ""); color(cap, dim); size(cap, 22);
// six vertices in a circle; directed edges (a>b)
graph(g, "a b c d e f",
"a>b b>c c>d d>e e>f f>a a>d b>e",
circular, (640, 384), 210);
// nodes fade in (hidden→show); edges trace on (untraced→draw)
hidden(g.nodes);
untraced(g.edges);
show(head, 0.5);
say(cap, "drop in the vertices");
show(g.nodes, 0.4); // broadcasts over every node
say(cap, "connect the directed edges");
draw(g.edges, 0.6); // broadcasts over every edge
section("Traversal");
say(cap, "walk a > b > c > d");
seq {
flash(g.a, magenta);
flash(g.b, magenta);
flash(g.c, magenta);
flash(g.d, magenta);
}
say(cap, "highlight the visited path");
par {
recolor(g.a, lime, 0.4);
recolor(g.b, lime, 0.4);
recolor(g.c, lime, 0.4);
recolor(g.d, lime, 0.4);
}
wait(1.2);
graph_moving
Drag a vertex and its incident edges follow.
// Moving Graph — vertices move and the edges reflow to follow them
// (Manim's MovingVertices / MovingDiGraph). Also exercises layout reveal,
// per-node moves, tag-broadcast recolour, and a highlight sweep.
//
// manic examples/graph_moving.manic
// manic examples/graph_moving.manic --record out --fps 60
//
// Node ids are g.1 … g.4 ; edge ids g.1-2 etc ; tags g.nodes / g.edges.
title("Moving Graph");
canvas(1280, 720);
text(head, (640, 118), "edges follow their vertices");
display(head); color(head, cyan); size(head, 34); hidden(head);
text(cap, (640, 664), ""); color(cap, dim); size(cap, 22);
// four vertices, five undirected edges, circular to start
graph(g, "1 2 3 4", "1-2 2-3 3-4 1-3 1-4", circular, (640, 384), 150);
hidden(g.nodes);
untraced(g.edges);
// --- reveal ---
show(head, 0.5);
say(cap, "a small graph");
show(g.nodes, 0.4);
draw(g.edges, 0.6);
wait(0.5);
// --- case 1: fling the vertices to the corners; edges reflow live ---
section("Moving vertices");
say(cap, "move each vertex — the edges stretch to follow");
par {
move(g.1, (360, 250), 1.2, overshoot);
move(g.2, (920, 250), 1.2, overshoot);
move(g.3, (920, 520), 1.2, overshoot);
move(g.4, (360, 520), 1.2, overshoot);
}
wait(0.8);
// --- case 2: orbit two vertices past each other ---
say(cap, "swap two vertices");
par {
move(g.2, (360, 520), 1.0, smooth);
move(g.4, (920, 250), 1.0, smooth);
}
wait(0.8);
// --- case 3: pull one vertex around; incident edges track it ---
say(cap, "drag one vertex around");
seq {
move(g.1, (640, 150), 0.7, smooth);
move(g.1, (1080, 384), 0.7, smooth);
move(g.1, (640, 620), 0.7, smooth);
move(g.1, (360, 250), 0.7, smooth);
}
wait(0.6);
// --- case 4: recolour the whole graph via tag broadcast, then highlight ---
section("Styling");
say(cap, "recolour every edge, then highlight a node");
recolor(g.edges, cyan, 0.5);
flash(g.1, magenta);
par {
recolor(g.1, lime, 0.4);
pulse(g.1);
}
wait(1.5);
bfs_dfs
The same graph, queue vs stack, with live frontier readouts.
// Graph Traversal — BFS vs DFS, the classic side-by-side. They're the SAME
// algorithm; only the frontier differs: BFS uses a QUEUE (explore level by
// level), DFS uses a STACK (dive deep first). `bfs(g, start)` / `dfs(g, start)`
// read the graph's adjacency, run the traversal, and animate the textbook
// states — discovered (cyan) -> current (magenta) -> done (lime) — with tree
// edges lighting up and live `queue:` / `stack:` + `visited:` readouts.
//
// manic examples/bfs_dfs.manic
title("Graph Traversal");
canvas("16:9");
text(head, (cx, 56), "BFS vs DFS: same graph, queue vs stack");
display(head); color(head, cyan); size(head, 26); hidden(head);
text(cap, (cx, 690), ""); color(cap, dim); size(cap, 24);
graph(gr, "a b c d e f g", "a-b a-c b-d b-e c-f c-g", circular, (cx, 320), 200, 30);
show(head, 0.5);
wait(0.4);
section("BFS");
say(cap, "BFS explores level by level, using a QUEUE");
bfs(gr, a);
say(cap, "queue order: a, then b c, then d e f g");
wait(0.8);
section("DFS");
par { recolor(gr.nodes, panel, 0.4); recolor(gr.edges, dim, 0.4); }
say(gr.frontier, "stack:");
say(gr.visited, "visited:");
say(cap, "DFS dives deep down one branch, using a STACK");
dfs(gr, a);
say(cap, "the stack drove it depth-first before backtracking");
wait(1.2);
dijkstra
Weighted edges, settling distances, a shortest-path tree.
// Dijkstra — single-source shortest paths on a WEIGHTED graph. Give edges a
// weight with `a-b:w` (drawn as a midpoint label). `dijkstra(g, start)` reads the
// weights, then runs the classic loop: repeatedly settle the nearest unsettled
// node (magenta -> lime), relaxing its edges and lowering neighbours' distances.
// Each node shows its best-known distance (inf -> the final shortest distance),
// and the shortest-path-tree edges stay lit at the end.
//
// manic examples/dijkstra.manic
title("Dijkstra");
canvas("16:9");
text(head, (cx, 58), "shortest paths: settle the nearest node, relax its edges");
display(head); color(head, cyan); size(head, 25); hidden(head);
text(cap, (cx, 690), ""); color(cap, dim); size(cap, 24);
graph(g, "a b c d e f",
"a-b:2 a-c:5 b-c:1 b-d:4 c-e:3 d-e:1 d-f:2 e-f:6",
circular, (cx, 350), 210, 30);
show(head, 0.5);
say(cap, "each node shows its best distance: start 0, the rest inf");
wait(0.7);
section("Relax");
say(cap, "settle the nearest node, then relax every edge leaving it");
dijkstra(g, a);
say(cap, "settled distances are final; the lime edges form the shortest-path tree");
wait(1.4);