animora 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. animora/__init__.py +189 -0
  2. animora/algorithms/__init__.py +65 -0
  3. animora/algorithms/backtracking.py +124 -0
  4. animora/algorithms/dynamic_programming.py +81 -0
  5. animora/algorithms/graph_traversal.py +125 -0
  6. animora/algorithms/pathfinding.py +244 -0
  7. animora/algorithms/search.py +97 -0
  8. animora/algorithms/sorting.py +336 -0
  9. animora/algorithms/trace.py +82 -0
  10. animora/animations/__init__.py +10 -0
  11. animora/cli/__init__.py +21 -0
  12. animora/cli/doctor.py +154 -0
  13. animora/cli/main.py +59 -0
  14. animora/cli/new.py +84 -0
  15. animora/cli/preview.py +83 -0
  16. animora/cli/render.py +97 -0
  17. animora/cli/templates/basic_scene.py.template +27 -0
  18. animora/components/__init__.py +27 -0
  19. animora/components/arrow.py +111 -0
  20. animora/components/connector.py +116 -0
  21. animora/components/dataviz/__init__.py +23 -0
  22. animora/components/dsa/__init__.py +38 -0
  23. animora/components/group.py +121 -0
  24. animora/components/label.py +100 -0
  25. animora/components/panel.py +131 -0
  26. animora/components/primitives/__init__.py +23 -0
  27. animora/components/shape.py +243 -0
  28. animora/components/text.py +104 -0
  29. animora/core/__init__.py +23 -0
  30. animora/core/animation.py +74 -0
  31. animora/core/component.py +181 -0
  32. animora/core/config.py +110 -0
  33. animora/core/scene.py +80 -0
  34. animora/datastructures/__init__.py +42 -0
  35. animora/datastructures/array.py +226 -0
  36. animora/datastructures/bst.py +339 -0
  37. animora/datastructures/graph.py +275 -0
  38. animora/datastructures/hash_table.py +242 -0
  39. animora/datastructures/heap.py +198 -0
  40. animora/datastructures/linked_list.py +245 -0
  41. animora/datastructures/queue.py +193 -0
  42. animora/datastructures/stack.py +193 -0
  43. animora/datastructures/tree.py +216 -0
  44. animora/dataviz/__init__.py +23 -0
  45. animora/dataviz/axes.py +146 -0
  46. animora/dataviz/bar_chart.py +179 -0
  47. animora/dataviz/histogram.py +156 -0
  48. animora/dataviz/line_chart.py +137 -0
  49. animora/dataviz/scatter_plot.py +130 -0
  50. animora/dataviz/table.py +170 -0
  51. animora/layout/__init__.py +30 -0
  52. animora/layout/base.py +63 -0
  53. animora/layout/circular.py +87 -0
  54. animora/layout/flow.py +105 -0
  55. animora/layout/graph.py +100 -0
  56. animora/layout/grid.py +90 -0
  57. animora/layout/horizontal.py +72 -0
  58. animora/layout/tree.py +179 -0
  59. animora/layout/vertical.py +72 -0
  60. animora/py.typed +1 -0
  61. animora/theme/__init__.py +48 -0
  62. animora/theme/builtin.py +156 -0
  63. animora/theme/context.py +51 -0
  64. animora/theme/theme.py +148 -0
  65. animora-0.1.0.dist-info/METADATA +326 -0
  66. animora-0.1.0.dist-info/RECORD +69 -0
  67. animora-0.1.0.dist-info/WHEEL +4 -0
  68. animora-0.1.0.dist-info/entry_points.txt +2 -0
  69. animora-0.1.0.dist-info/licenses/LICENSE +21 -0
animora/__init__.py ADDED
@@ -0,0 +1,189 @@
1
+ """Animora: High-level declarative animation framework built on Manim.
2
+
3
+ Democratizing the creation of high-quality educational, technical,
4
+ mathematical, and algorithmic animations.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from animora.algorithms.backtracking import n_queens, n_queens_trace
10
+ from animora.algorithms.dynamic_programming import fibonacci_dp, fibonacci_dp_trace
11
+ from animora.algorithms.graph_traversal import bfs, bfs_trace, dfs, dfs_trace
12
+ from animora.algorithms.pathfinding import (
13
+ a_star,
14
+ a_star_trace,
15
+ dijkstra,
16
+ dijkstra_trace,
17
+ )
18
+ from animora.algorithms.search import binary_search, binary_search_trace
19
+ from animora.algorithms.sorting import (
20
+ bubble_sort,
21
+ bubble_sort_trace,
22
+ insertion_sort,
23
+ insertion_sort_trace,
24
+ merge_sort,
25
+ merge_sort_trace,
26
+ quick_sort,
27
+ quick_sort_trace,
28
+ selection_sort,
29
+ selection_sort_trace,
30
+ )
31
+ from animora.algorithms.trace import (
32
+ OperationStep,
33
+ OperationTrace,
34
+ OperationType,
35
+ )
36
+ from animora.components.arrow import Arrow
37
+ from animora.components.connector import Connector
38
+ from animora.components.group import Group
39
+ from animora.components.label import Label
40
+ from animora.components.panel import Panel
41
+ from animora.components.shape import Shape, ShapeType
42
+ from animora.components.text import Text
43
+ from animora.core.animation import Animation
44
+ from animora.core.component import Component
45
+ from animora.core.config import BoundingBox, ComponentConfig
46
+ from animora.core.scene import Scene
47
+ from animora.datastructures.array import Array, ArrayListModel
48
+ from animora.datastructures.bst import BST, BSTModel, BSTNode
49
+ from animora.datastructures.graph import Graph, GraphModel
50
+ from animora.datastructures.hash_table import HashEntry, HashTable, HashTableChainingModel
51
+ from animora.datastructures.heap import Heap, HeapModel
52
+ from animora.datastructures.linked_list import LinkedList, LinkedListModel, ListNode
53
+ from animora.datastructures.queue import Queue, QueueModel
54
+ from animora.datastructures.stack import Stack, StackModel
55
+ from animora.datastructures.tree import GenericTreeModel, Tree, TreeNode
56
+ from animora.dataviz.axes import Axes
57
+ from animora.dataviz.bar_chart import BarChart
58
+ from animora.dataviz.histogram import Histogram
59
+ from animora.dataviz.line_chart import LineChart
60
+ from animora.dataviz.scatter_plot import ScatterPlot
61
+ from animora.dataviz.table import Table
62
+ from animora.layout.base import BaseLayout, LayoutItem, LayoutResult
63
+ from animora.layout.circular import CircularLayout
64
+ from animora.layout.flow import FlowLayout
65
+ from animora.layout.graph import GraphLayout
66
+ from animora.layout.grid import GridLayout
67
+ from animora.layout.horizontal import HorizontalLayout
68
+ from animora.layout.tree import TreeLayout
69
+ from animora.layout.vertical import VerticalLayout
70
+ from animora.theme.builtin import (
71
+ Cyberpunk,
72
+ DefaultTheme,
73
+ ModernDark,
74
+ Monokai,
75
+ PaperLight,
76
+ )
77
+ from animora.theme.context import (
78
+ get_active_theme,
79
+ set_active_theme,
80
+ use_theme,
81
+ )
82
+ from animora.theme.theme import (
83
+ AnimationTiming,
84
+ ColorPalette,
85
+ CornerRadius,
86
+ SpacingScale,
87
+ StrokeScale,
88
+ Theme,
89
+ Typography,
90
+ )
91
+
92
+ __version__ = "0.1.0"
93
+
94
+ __all__: list[str] = [
95
+ "BST",
96
+ "Animation",
97
+ "AnimationTiming",
98
+ "Array",
99
+ "ArrayListModel",
100
+ "Arrow",
101
+ "Axes",
102
+ "BSTModel",
103
+ "BSTNode",
104
+ "BarChart",
105
+ "BaseLayout",
106
+ "BoundingBox",
107
+ "CircularLayout",
108
+ "ColorPalette",
109
+ "Component",
110
+ "ComponentConfig",
111
+ "Connector",
112
+ "CornerRadius",
113
+ "Cyberpunk",
114
+ "DefaultTheme",
115
+ "FlowLayout",
116
+ "GenericTreeModel",
117
+ "Graph",
118
+ "GraphLayout",
119
+ "GraphModel",
120
+ "GridLayout",
121
+ "Group",
122
+ "HashEntry",
123
+ "HashTable",
124
+ "HashTableChainingModel",
125
+ "Heap",
126
+ "HeapModel",
127
+ "Histogram",
128
+ "HorizontalLayout",
129
+ "Label",
130
+ "LayoutItem",
131
+ "LayoutResult",
132
+ "LineChart",
133
+ "LinkedList",
134
+ "LinkedListModel",
135
+ "ListNode",
136
+ "ModernDark",
137
+ "Monokai",
138
+ "OperationStep",
139
+ "OperationTrace",
140
+ "OperationType",
141
+ "Panel",
142
+ "PaperLight",
143
+ "Queue",
144
+ "QueueModel",
145
+ "ScatterPlot",
146
+ "Scene",
147
+ "Shape",
148
+ "ShapeType",
149
+ "SpacingScale",
150
+ "Stack",
151
+ "StackModel",
152
+ "StrokeScale",
153
+ "Table",
154
+ "Text",
155
+ "Theme",
156
+ "Tree",
157
+ "TreeLayout",
158
+ "TreeNode",
159
+ "Typography",
160
+ "VerticalLayout",
161
+ "__version__",
162
+ "a_star",
163
+ "a_star_trace",
164
+ "bfs",
165
+ "bfs_trace",
166
+ "binary_search",
167
+ "binary_search_trace",
168
+ "bubble_sort",
169
+ "bubble_sort_trace",
170
+ "dfs",
171
+ "dfs_trace",
172
+ "dijkstra",
173
+ "dijkstra_trace",
174
+ "fibonacci_dp",
175
+ "fibonacci_dp_trace",
176
+ "get_active_theme",
177
+ "insertion_sort",
178
+ "insertion_sort_trace",
179
+ "merge_sort",
180
+ "merge_sort_trace",
181
+ "n_queens",
182
+ "n_queens_trace",
183
+ "quick_sort",
184
+ "quick_sort_trace",
185
+ "selection_sort",
186
+ "selection_sort_trace",
187
+ "set_active_theme",
188
+ "use_theme",
189
+ ]
@@ -0,0 +1,65 @@
1
+ """Algorithm visualizations and operation tracing for Animora.
2
+
3
+ Provides educational animations and discrete operation traces for searching,
4
+ sorting, graph traversals, pathfinding, dynamic programming, and backtracking.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from animora.algorithms.backtracking import n_queens, n_queens_trace
10
+ from animora.algorithms.dynamic_programming import fibonacci_dp, fibonacci_dp_trace
11
+ from animora.algorithms.graph_traversal import bfs, bfs_trace, dfs, dfs_trace
12
+ from animora.algorithms.pathfinding import (
13
+ a_star,
14
+ a_star_trace,
15
+ dijkstra,
16
+ dijkstra_trace,
17
+ )
18
+ from animora.algorithms.search import binary_search, binary_search_trace
19
+ from animora.algorithms.sorting import (
20
+ bubble_sort,
21
+ bubble_sort_trace,
22
+ insertion_sort,
23
+ insertion_sort_trace,
24
+ merge_sort,
25
+ merge_sort_trace,
26
+ quick_sort,
27
+ quick_sort_trace,
28
+ selection_sort,
29
+ selection_sort_trace,
30
+ )
31
+ from animora.algorithms.trace import (
32
+ OperationStep,
33
+ OperationTrace,
34
+ OperationType,
35
+ )
36
+
37
+ __all__: list[str] = [
38
+ "OperationStep",
39
+ "OperationTrace",
40
+ "OperationType",
41
+ "a_star",
42
+ "a_star_trace",
43
+ "bfs",
44
+ "bfs_trace",
45
+ "binary_search",
46
+ "binary_search_trace",
47
+ "bubble_sort",
48
+ "bubble_sort_trace",
49
+ "dfs",
50
+ "dfs_trace",
51
+ "dijkstra",
52
+ "dijkstra_trace",
53
+ "fibonacci_dp",
54
+ "fibonacci_dp_trace",
55
+ "insertion_sort",
56
+ "insertion_sort_trace",
57
+ "merge_sort",
58
+ "merge_sort_trace",
59
+ "n_queens",
60
+ "n_queens_trace",
61
+ "quick_sort",
62
+ "quick_sort_trace",
63
+ "selection_sort",
64
+ "selection_sort_trace",
65
+ ]
@@ -0,0 +1,124 @@
1
+ """Backtracking algorithm visualization with animated state decision trees (N-Queens)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING
6
+
7
+ from animora.algorithms.trace import OperationTrace, OperationType
8
+ from animora.core.animation import Animation
9
+ from animora.dataviz.table import Table
10
+ from animora.theme.context import get_active_theme
11
+
12
+ if TYPE_CHECKING:
13
+ pass
14
+
15
+
16
+ # -----------------------------------------------------------------------------
17
+ # 1. Pure Algorithm Logic with Operation Tracing (Dual-Correctness)
18
+ # -----------------------------------------------------------------------------
19
+ def n_queens_trace(n: int = 4) -> tuple[list[list[int]], OperationTrace]:
20
+ """Solve N-Queens backtracking problem, recording placements and backtracks.
21
+
22
+ Returns (solutions, operation_trace) where each solution is a list of column
23
+ indices for each row.
24
+ """
25
+ trace = OperationTrace()
26
+ solutions: list[list[int]] = []
27
+ board: list[int] = [-1] * n
28
+
29
+ def _is_safe(row: int, col: int) -> bool:
30
+ for prev_row in range(row):
31
+ prev_col = board[prev_row]
32
+ # Column conflict or diagonal conflict
33
+ if prev_col == col or abs(prev_col - col) == abs(prev_row - row):
34
+ return False
35
+ return True
36
+
37
+ def _solve(row: int) -> None:
38
+ if row == n:
39
+ solutions.append(list(board))
40
+ trace.add_step(
41
+ OperationType.HIGHLIGHT,
42
+ f"Valid N-Queens solution found: {list(board)}",
43
+ targets=tuple(enumerate(board)),
44
+ solution=list(board),
45
+ )
46
+ return
47
+
48
+ for col in range(n):
49
+ trace.add_step(
50
+ OperationType.TRY_CHOICE,
51
+ f"Try placing Queen at row {row}, column {col}",
52
+ targets=(row, col),
53
+ row=row,
54
+ col=col,
55
+ )
56
+
57
+ if _is_safe(row, col):
58
+ board[row] = col
59
+ _solve(row + 1)
60
+ # Backtrack
61
+ board[row] = -1
62
+ trace.add_step(
63
+ OperationType.BACKTRACK,
64
+ f"Backtrack from row {row}, column {col}",
65
+ targets=(row, col),
66
+ row=row,
67
+ col=col,
68
+ )
69
+ else:
70
+ trace.add_step(
71
+ OperationType.BACKTRACK,
72
+ f"Conflict detected at row {row}, column {col}",
73
+ targets=(row, col),
74
+ row=row,
75
+ col=col,
76
+ )
77
+
78
+ _solve(0)
79
+ return solutions, trace
80
+
81
+
82
+ # -----------------------------------------------------------------------------
83
+ # 2. Animation Generator Orchestration
84
+ # -----------------------------------------------------------------------------
85
+ def n_queens(
86
+ n: int = 4,
87
+ table: Table | None = None,
88
+ run_time: float | None = None,
89
+ ) -> list[Animation]:
90
+ """Generate animations for N-Queens backtracking exploration."""
91
+ active_theme = get_active_theme()
92
+ duration = run_time or active_theme.timing.fast
93
+
94
+ _solutions, trace = n_queens_trace(n)
95
+ animations: list[Animation] = []
96
+
97
+ if table is not None:
98
+ for step in trace:
99
+ if step.op_type == OperationType.TRY_CHOICE:
100
+ r, c = step.targets
101
+ anim = table.animate_highlight_cell(
102
+ r, c, color=active_theme.colors.warning, run_time=duration
103
+ )
104
+ animations.append(anim)
105
+ elif step.op_type == OperationType.BACKTRACK:
106
+ r, c = step.targets
107
+ anim = table.animate_highlight_cell(
108
+ r, c, color=active_theme.colors.error, run_time=duration
109
+ )
110
+ animations.append(anim)
111
+ elif step.op_type == OperationType.HIGHLIGHT:
112
+ for r, c in step.targets:
113
+ anim = table.animate_highlight_cell(
114
+ r, c, color=active_theme.colors.success, run_time=duration
115
+ )
116
+ animations.append(anim)
117
+
118
+ return animations
119
+
120
+
121
+ __all__ = [
122
+ "n_queens",
123
+ "n_queens_trace",
124
+ ]
@@ -0,0 +1,81 @@
1
+ """Dynamic Programming visualization with animated memoization table filling."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING
6
+
7
+ from animora.algorithms.trace import OperationTrace, OperationType
8
+ from animora.core.animation import Animation
9
+ from animora.dataviz.table import Table
10
+ from animora.theme.context import get_active_theme
11
+
12
+ if TYPE_CHECKING:
13
+ pass
14
+
15
+
16
+ # -----------------------------------------------------------------------------
17
+ # 1. Pure Algorithm Logic with Operation Tracing (Dual-Correctness)
18
+ # -----------------------------------------------------------------------------
19
+ def fibonacci_dp_trace(n: int) -> tuple[int, list[int], OperationTrace]:
20
+ """Compute N-th Fibonacci number using bottom-up DP, recording cell fills."""
21
+ if n < 0:
22
+ raise ValueError("n must be non-negative")
23
+ if n == 0:
24
+ trace = OperationTrace()
25
+ trace.add_step(OperationType.TABLE_FILL, "Base case: dp[0] = 0", targets=(0,), value=0)
26
+ return 0, [0], trace
27
+
28
+ dp = [0] * (n + 1)
29
+ dp[0] = 0
30
+ dp[1] = 1
31
+
32
+ trace = OperationTrace()
33
+ trace.add_step(OperationType.TABLE_FILL, "Base case: dp[0] = 0", targets=(0,), value=0)
34
+ trace.add_step(OperationType.TABLE_FILL, "Base case: dp[1] = 1", targets=(1,), value=1)
35
+
36
+ for i in range(2, n + 1):
37
+ dp[i] = dp[i - 1] + dp[i - 2]
38
+ trace.add_step(
39
+ OperationType.TABLE_FILL,
40
+ f"Compute dp[{i}] = dp[{i - 1}] ({dp[i - 1]}) + dp[{i - 2}] ({dp[i - 2]}) = {dp[i]}",
41
+ targets=(i,),
42
+ value=dp[i],
43
+ operand_a=dp[i - 1],
44
+ operand_b=dp[i - 2],
45
+ )
46
+
47
+ return dp[n], dp, trace
48
+
49
+
50
+ # -----------------------------------------------------------------------------
51
+ # 2. Animation Generator Orchestration
52
+ # -----------------------------------------------------------------------------
53
+ def fibonacci_dp(
54
+ n: int,
55
+ table: Table | None = None,
56
+ run_time: float | None = None,
57
+ ) -> list[Animation]:
58
+ """Generate animations filling a Table component cell-by-cell for DP Fibonacci."""
59
+ active_theme = get_active_theme()
60
+ duration = run_time or active_theme.timing.fast
61
+
62
+ _result, _dp_array, trace = fibonacci_dp_trace(n)
63
+ animations: list[Animation] = []
64
+
65
+ if table is not None:
66
+ for step in trace:
67
+ idx = step.targets[0]
68
+ if idx < table.num_cols:
69
+ # Row 1 is the DP values row (Row 0 is header)
70
+ anim = table.animate_highlight_cell(
71
+ 1, idx, color=active_theme.colors.success, run_time=duration
72
+ )
73
+ animations.append(anim)
74
+
75
+ return animations
76
+
77
+
78
+ __all__ = [
79
+ "fibonacci_dp",
80
+ "fibonacci_dp_trace",
81
+ ]
@@ -0,0 +1,125 @@
1
+ """Breadth-First Search (BFS) and Depth-First Search (DFS) graph traversals."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections import deque
6
+ from typing import TYPE_CHECKING, Any
7
+
8
+ from animora.algorithms.trace import OperationTrace, OperationType
9
+ from animora.core.animation import Animation
10
+ from animora.datastructures.graph import Graph, GraphModel
11
+ from animora.theme.context import get_active_theme
12
+
13
+ if TYPE_CHECKING:
14
+ pass
15
+
16
+
17
+ # -----------------------------------------------------------------------------
18
+ # 1. Breadth-First Search (BFS)
19
+ # -----------------------------------------------------------------------------
20
+ def bfs_trace(graph_model: GraphModel, start: Any) -> tuple[list[Any], OperationTrace]:
21
+ """Execute BFS traversal on GraphModel, returning (visited_order, operation_trace)."""
22
+ visited_order: list[Any] = []
23
+ trace = OperationTrace()
24
+ visited: set[Any] = {start}
25
+ queue: deque[Any] = deque([start])
26
+
27
+ trace.add_step(OperationType.VISIT_NODE, f"Start BFS at node {start}", targets=(start,))
28
+ visited_order.append(start)
29
+
30
+ while queue:
31
+ u = queue.popleft()
32
+ for v in graph_model.neighbors(u):
33
+ trace.add_step(OperationType.HIGHLIGHT_EDGE, f"Explore edge ({u}, {v})", targets=(u, v))
34
+ if v not in visited:
35
+ visited.add(v)
36
+ visited_order.append(v)
37
+ queue.append(v)
38
+ trace.add_step(OperationType.VISIT_NODE, f"Visit node {v}", targets=(v,))
39
+
40
+ return visited_order, trace
41
+
42
+
43
+ def bfs(graph: Graph, start: Any, run_time: float | None = None) -> list[Animation]:
44
+ """Generate animations for BFS on a Graph component."""
45
+ active_theme = get_active_theme()
46
+ duration = run_time or active_theme.timing.normal
47
+
48
+ _, trace = bfs_trace(graph.model, start)
49
+ animations: list[Animation] = []
50
+
51
+ for step in trace:
52
+ if step.op_type == OperationType.VISIT_NODE:
53
+ node = step.targets[0]
54
+ animations.append(
55
+ graph.animate_mark_visited(
56
+ node, color=active_theme.colors.success, run_time=duration
57
+ )
58
+ )
59
+ elif step.op_type == OperationType.HIGHLIGHT_EDGE:
60
+ u, v = step.targets
61
+ animations.append(
62
+ graph.animate_highlight_edge(
63
+ u, v, color=active_theme.colors.accent, run_time=duration
64
+ )
65
+ )
66
+
67
+ return animations
68
+
69
+
70
+ # -----------------------------------------------------------------------------
71
+ # 2. Depth-First Search (DFS)
72
+ # -----------------------------------------------------------------------------
73
+ def dfs_trace(graph_model: GraphModel, start: Any) -> tuple[list[Any], OperationTrace]:
74
+ """Execute DFS traversal on GraphModel, returning (visited_order, operation_trace)."""
75
+ visited_order: list[Any] = []
76
+ trace = OperationTrace()
77
+ visited: set[Any] = set()
78
+
79
+ def _dfs_rec(u: Any) -> None:
80
+ visited.add(u)
81
+ visited_order.append(u)
82
+ trace.add_step(OperationType.VISIT_NODE, f"Visit node {u}", targets=(u,))
83
+
84
+ for v in graph_model.neighbors(u):
85
+ trace.add_step(OperationType.HIGHLIGHT_EDGE, f"Explore edge ({u}, {v})", targets=(u, v))
86
+ if v not in visited:
87
+ _dfs_rec(v)
88
+
89
+ _dfs_rec(start)
90
+ return visited_order, trace
91
+
92
+
93
+ def dfs(graph: Graph, start: Any, run_time: float | None = None) -> list[Animation]:
94
+ """Generate animations for DFS on a Graph component."""
95
+ active_theme = get_active_theme()
96
+ duration = run_time or active_theme.timing.normal
97
+
98
+ _, trace = dfs_trace(graph.model, start)
99
+ animations: list[Animation] = []
100
+
101
+ for step in trace:
102
+ if step.op_type == OperationType.VISIT_NODE:
103
+ node = step.targets[0]
104
+ animations.append(
105
+ graph.animate_mark_visited(
106
+ node, color=active_theme.colors.success, run_time=duration
107
+ )
108
+ )
109
+ elif step.op_type == OperationType.HIGHLIGHT_EDGE:
110
+ u, v = step.targets
111
+ animations.append(
112
+ graph.animate_highlight_edge(
113
+ u, v, color=active_theme.colors.accent, run_time=duration
114
+ )
115
+ )
116
+
117
+ return animations
118
+
119
+
120
+ __all__ = [
121
+ "bfs",
122
+ "bfs_trace",
123
+ "dfs",
124
+ "dfs_trace",
125
+ ]