@redwilly/anima 0.1.0

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 (239) hide show
  1. package/dist/cli/SceneLoader.d.ts +22 -0
  2. package/dist/cli/SceneLoader.js +47 -0
  3. package/dist/cli/commands/export-frame.d.ts +13 -0
  4. package/dist/cli/commands/export-frame.js +60 -0
  5. package/dist/cli/commands/list-scenes.d.ts +5 -0
  6. package/dist/cli/commands/list-scenes.js +22 -0
  7. package/dist/cli/commands/preview.d.ts +5 -0
  8. package/dist/cli/commands/preview.js +11 -0
  9. package/dist/cli/commands/render.d.ts +16 -0
  10. package/dist/cli/commands/render.js +76 -0
  11. package/dist/cli/index.d.ts +2 -0
  12. package/dist/cli/index.js +63 -0
  13. package/dist/core/animations/Animation.d.ts +41 -0
  14. package/dist/core/animations/Animation.js +76 -0
  15. package/dist/core/animations/camera/Follow.d.ts +70 -0
  16. package/dist/core/animations/camera/Follow.js +69 -0
  17. package/dist/core/animations/camera/Shake.d.ts +90 -0
  18. package/dist/core/animations/camera/Shake.js +87 -0
  19. package/dist/core/animations/camera/index.d.ts +2 -0
  20. package/dist/core/animations/camera/index.js +2 -0
  21. package/dist/core/animations/categories/ExitAnimation.d.ts +17 -0
  22. package/dist/core/animations/categories/ExitAnimation.js +15 -0
  23. package/dist/core/animations/categories/IntroductoryAnimation.d.ts +16 -0
  24. package/dist/core/animations/categories/IntroductoryAnimation.js +14 -0
  25. package/dist/core/animations/categories/TransformativeAnimation.d.ts +25 -0
  26. package/dist/core/animations/categories/TransformativeAnimation.js +25 -0
  27. package/dist/core/animations/categories/index.d.ts +3 -0
  28. package/dist/core/animations/categories/index.js +3 -0
  29. package/dist/core/animations/composition/Parallel.d.ts +37 -0
  30. package/dist/core/animations/composition/Parallel.js +79 -0
  31. package/dist/core/animations/composition/Sequence.d.ts +41 -0
  32. package/dist/core/animations/composition/Sequence.js +95 -0
  33. package/dist/core/animations/composition/index.d.ts +2 -0
  34. package/dist/core/animations/composition/index.js +3 -0
  35. package/dist/core/animations/draw/Draw.d.ts +30 -0
  36. package/dist/core/animations/draw/Draw.js +122 -0
  37. package/dist/core/animations/draw/Unwrite.d.ts +30 -0
  38. package/dist/core/animations/draw/Unwrite.js +120 -0
  39. package/dist/core/animations/draw/Write.d.ts +35 -0
  40. package/dist/core/animations/draw/Write.js +119 -0
  41. package/dist/core/animations/draw/index.d.ts +3 -0
  42. package/dist/core/animations/draw/index.js +3 -0
  43. package/dist/core/animations/draw/partialPath.d.ts +6 -0
  44. package/dist/core/animations/draw/partialPath.js +138 -0
  45. package/dist/core/animations/easing/bounce.d.ts +13 -0
  46. package/dist/core/animations/easing/bounce.js +37 -0
  47. package/dist/core/animations/easing/index.d.ts +7 -0
  48. package/dist/core/animations/easing/index.js +11 -0
  49. package/dist/core/animations/easing/manim.d.ts +46 -0
  50. package/dist/core/animations/easing/manim.js +102 -0
  51. package/dist/core/animations/easing/registry.d.ts +8 -0
  52. package/dist/core/animations/easing/registry.js +25 -0
  53. package/dist/core/animations/easing/standard.d.ts +113 -0
  54. package/dist/core/animations/easing/standard.js +151 -0
  55. package/dist/core/animations/easing/types.d.ts +6 -0
  56. package/dist/core/animations/easing/types.js +0 -0
  57. package/dist/core/animations/fade/FadeIn.d.ts +17 -0
  58. package/dist/core/animations/fade/FadeIn.js +22 -0
  59. package/dist/core/animations/fade/FadeOut.d.ts +17 -0
  60. package/dist/core/animations/fade/FadeOut.js +23 -0
  61. package/dist/core/animations/fade/index.d.ts +2 -0
  62. package/dist/core/animations/fade/index.js +2 -0
  63. package/dist/core/animations/index.d.ts +11 -0
  64. package/dist/core/animations/index.js +17 -0
  65. package/dist/core/animations/keyframes/KeyframeAnimation.d.ts +33 -0
  66. package/dist/core/animations/keyframes/KeyframeAnimation.js +40 -0
  67. package/dist/core/animations/keyframes/KeyframeTrack.d.ts +31 -0
  68. package/dist/core/animations/keyframes/KeyframeTrack.js +83 -0
  69. package/dist/core/animations/keyframes/index.d.ts +4 -0
  70. package/dist/core/animations/keyframes/index.js +5 -0
  71. package/dist/core/animations/keyframes/types.d.ts +25 -0
  72. package/dist/core/animations/keyframes/types.js +6 -0
  73. package/dist/core/animations/morph/MorphTo.d.ts +22 -0
  74. package/dist/core/animations/morph/MorphTo.js +42 -0
  75. package/dist/core/animations/morph/index.d.ts +1 -0
  76. package/dist/core/animations/morph/index.js +1 -0
  77. package/dist/core/animations/transform/MoveTo.d.ts +24 -0
  78. package/dist/core/animations/transform/MoveTo.js +38 -0
  79. package/dist/core/animations/transform/Rotate.d.ts +23 -0
  80. package/dist/core/animations/transform/Rotate.js +34 -0
  81. package/dist/core/animations/transform/Scale.d.ts +23 -0
  82. package/dist/core/animations/transform/Scale.js +35 -0
  83. package/dist/core/animations/transform/index.d.ts +3 -0
  84. package/dist/core/animations/transform/index.js +3 -0
  85. package/dist/core/animations/types.d.ts +52 -0
  86. package/dist/core/animations/types.js +6 -0
  87. package/dist/core/camera/Camera.d.ts +87 -0
  88. package/dist/core/camera/Camera.js +175 -0
  89. package/dist/core/camera/CameraFrame.d.ts +242 -0
  90. package/dist/core/camera/CameraFrame.js +322 -0
  91. package/dist/core/camera/index.d.ts +4 -0
  92. package/dist/core/camera/index.js +3 -0
  93. package/dist/core/camera/types.d.ts +17 -0
  94. package/dist/core/camera/types.js +1 -0
  95. package/dist/core/errors/AnimationErrors.d.ts +12 -0
  96. package/dist/core/errors/AnimationErrors.js +37 -0
  97. package/dist/core/errors/index.d.ts +1 -0
  98. package/dist/core/errors/index.js +1 -0
  99. package/dist/core/math/Vector2/Vector2.d.ts +23 -0
  100. package/dist/core/math/Vector2/Vector2.js +46 -0
  101. package/dist/core/math/Vector2/index.d.ts +1 -0
  102. package/dist/core/math/Vector2/index.js +1 -0
  103. package/dist/core/math/bezier/BezierPath.d.ts +38 -0
  104. package/dist/core/math/bezier/BezierPath.js +264 -0
  105. package/dist/core/math/bezier/evaluators.d.ts +9 -0
  106. package/dist/core/math/bezier/evaluators.js +36 -0
  107. package/dist/core/math/bezier/index.d.ts +8 -0
  108. package/dist/core/math/bezier/index.js +6 -0
  109. package/dist/core/math/bezier/length.d.ts +5 -0
  110. package/dist/core/math/bezier/length.js +27 -0
  111. package/dist/core/math/bezier/morphing.d.ts +16 -0
  112. package/dist/core/math/bezier/morphing.js +151 -0
  113. package/dist/core/math/bezier/sampling.d.ts +7 -0
  114. package/dist/core/math/bezier/sampling.js +153 -0
  115. package/dist/core/math/bezier/split.d.ts +19 -0
  116. package/dist/core/math/bezier/split.js +44 -0
  117. package/dist/core/math/bezier/types.d.ts +8 -0
  118. package/dist/core/math/bezier/types.js +0 -0
  119. package/dist/core/math/color/Color.d.ts +28 -0
  120. package/dist/core/math/color/Color.js +60 -0
  121. package/dist/core/math/color/conversions.d.ts +17 -0
  122. package/dist/core/math/color/conversions.js +100 -0
  123. package/dist/core/math/color/index.d.ts +2 -0
  124. package/dist/core/math/color/index.js +2 -0
  125. package/dist/core/math/index.d.ts +4 -0
  126. package/dist/core/math/index.js +5 -0
  127. package/dist/core/math/matrix/Matrix3x3.d.ts +23 -0
  128. package/dist/core/math/matrix/Matrix3x3.js +91 -0
  129. package/dist/core/math/matrix/factories.d.ts +12 -0
  130. package/dist/core/math/matrix/factories.js +44 -0
  131. package/dist/core/math/matrix/index.d.ts +2 -0
  132. package/dist/core/math/matrix/index.js +2 -0
  133. package/dist/core/renderer/FrameRenderer.d.ts +37 -0
  134. package/dist/core/renderer/FrameRenderer.js +75 -0
  135. package/dist/core/renderer/ProgressReporter.d.ts +19 -0
  136. package/dist/core/renderer/ProgressReporter.js +58 -0
  137. package/dist/core/renderer/Renderer.d.ts +36 -0
  138. package/dist/core/renderer/Renderer.js +102 -0
  139. package/dist/core/renderer/drawMobject.d.ts +8 -0
  140. package/dist/core/renderer/drawMobject.js +109 -0
  141. package/dist/core/renderer/formats/index.d.ts +3 -0
  142. package/dist/core/renderer/formats/index.js +3 -0
  143. package/dist/core/renderer/formats/png.d.ts +5 -0
  144. package/dist/core/renderer/formats/png.js +7 -0
  145. package/dist/core/renderer/formats/sprite.d.ts +6 -0
  146. package/dist/core/renderer/formats/sprite.js +24 -0
  147. package/dist/core/renderer/formats/video.d.ts +8 -0
  148. package/dist/core/renderer/formats/video.js +51 -0
  149. package/dist/core/renderer/index.d.ts +7 -0
  150. package/dist/core/renderer/index.js +9 -0
  151. package/dist/core/renderer/types.d.ts +87 -0
  152. package/dist/core/renderer/types.js +13 -0
  153. package/dist/core/scene/Scene.d.ts +104 -0
  154. package/dist/core/scene/Scene.js +225 -0
  155. package/dist/core/scene/index.d.ts +2 -0
  156. package/dist/core/scene/index.js +1 -0
  157. package/dist/core/scene/types.d.ts +23 -0
  158. package/dist/core/scene/types.js +0 -0
  159. package/dist/core/serialization/animation.d.ts +23 -0
  160. package/dist/core/serialization/animation.js +176 -0
  161. package/dist/core/serialization/easingLookup.d.ts +13 -0
  162. package/dist/core/serialization/easingLookup.js +65 -0
  163. package/dist/core/serialization/index.d.ts +23 -0
  164. package/dist/core/serialization/index.js +29 -0
  165. package/dist/core/serialization/mobject.d.ts +23 -0
  166. package/dist/core/serialization/mobject.js +248 -0
  167. package/dist/core/serialization/prettyPrint.d.ts +12 -0
  168. package/dist/core/serialization/prettyPrint.js +16 -0
  169. package/dist/core/serialization/primitives.d.ts +24 -0
  170. package/dist/core/serialization/primitives.js +98 -0
  171. package/dist/core/serialization/registry.d.ts +29 -0
  172. package/dist/core/serialization/registry.js +39 -0
  173. package/dist/core/serialization/scene.d.ts +28 -0
  174. package/dist/core/serialization/scene.js +114 -0
  175. package/dist/core/serialization/types.d.ts +152 -0
  176. package/dist/core/serialization/types.js +6 -0
  177. package/dist/core/timeline/Timeline.d.ts +70 -0
  178. package/dist/core/timeline/Timeline.js +144 -0
  179. package/dist/core/timeline/index.d.ts +5 -0
  180. package/dist/core/timeline/index.js +4 -0
  181. package/dist/core/timeline/types.d.ts +29 -0
  182. package/dist/core/timeline/types.js +0 -0
  183. package/dist/index.d.ts +18 -0
  184. package/dist/index.js +22 -0
  185. package/dist/mobjects/Mobject.d.ts +98 -0
  186. package/dist/mobjects/Mobject.js +343 -0
  187. package/dist/mobjects/VGroup/VGroup.d.ts +51 -0
  188. package/dist/mobjects/VGroup/VGroup.js +142 -0
  189. package/dist/mobjects/VGroup/index.d.ts +3 -0
  190. package/dist/mobjects/VGroup/index.js +2 -0
  191. package/dist/mobjects/VGroup/layout.d.ts +20 -0
  192. package/dist/mobjects/VGroup/layout.js +139 -0
  193. package/dist/mobjects/VMobject.d.ts +106 -0
  194. package/dist/mobjects/VMobject.js +216 -0
  195. package/dist/mobjects/geometry/Arc.d.ts +8 -0
  196. package/dist/mobjects/geometry/Arc.js +46 -0
  197. package/dist/mobjects/geometry/Arrow.d.ts +7 -0
  198. package/dist/mobjects/geometry/Arrow.js +34 -0
  199. package/dist/mobjects/geometry/Circle.d.ts +4 -0
  200. package/dist/mobjects/geometry/Circle.js +10 -0
  201. package/dist/mobjects/geometry/Line.d.ts +8 -0
  202. package/dist/mobjects/geometry/Line.js +19 -0
  203. package/dist/mobjects/geometry/Point.d.ts +5 -0
  204. package/dist/mobjects/geometry/Point.js +11 -0
  205. package/dist/mobjects/geometry/Polygon.d.ts +7 -0
  206. package/dist/mobjects/geometry/Polygon.js +21 -0
  207. package/dist/mobjects/geometry/Rectangle.d.ts +6 -0
  208. package/dist/mobjects/geometry/Rectangle.js +18 -0
  209. package/dist/mobjects/geometry/index.d.ts +7 -0
  210. package/dist/mobjects/geometry/index.js +7 -0
  211. package/dist/mobjects/graph/Graph.d.ts +28 -0
  212. package/dist/mobjects/graph/Graph.js +119 -0
  213. package/dist/mobjects/graph/GraphEdge.d.ts +26 -0
  214. package/dist/mobjects/graph/GraphEdge.js +64 -0
  215. package/dist/mobjects/graph/GraphNode.d.ts +19 -0
  216. package/dist/mobjects/graph/GraphNode.js +63 -0
  217. package/dist/mobjects/graph/index.d.ts +5 -0
  218. package/dist/mobjects/graph/index.js +5 -0
  219. package/dist/mobjects/graph/layouts/circular.d.ts +8 -0
  220. package/dist/mobjects/graph/layouts/circular.js +23 -0
  221. package/dist/mobjects/graph/layouts/forceDirected.d.ts +9 -0
  222. package/dist/mobjects/graph/layouts/forceDirected.js +102 -0
  223. package/dist/mobjects/graph/layouts/index.d.ts +3 -0
  224. package/dist/mobjects/graph/layouts/index.js +3 -0
  225. package/dist/mobjects/graph/layouts/tree.d.ts +9 -0
  226. package/dist/mobjects/graph/layouts/tree.js +99 -0
  227. package/dist/mobjects/graph/types.d.ts +35 -0
  228. package/dist/mobjects/graph/types.js +0 -0
  229. package/dist/mobjects/index.d.ts +6 -0
  230. package/dist/mobjects/index.js +6 -0
  231. package/dist/mobjects/text/Glyph.d.ts +11 -0
  232. package/dist/mobjects/text/Glyph.js +72 -0
  233. package/dist/mobjects/text/Text.d.ts +19 -0
  234. package/dist/mobjects/text/Text.js +76 -0
  235. package/dist/mobjects/text/index.d.ts +4 -0
  236. package/dist/mobjects/text/index.js +3 -0
  237. package/dist/mobjects/text/types.d.ts +12 -0
  238. package/dist/mobjects/text/types.js +8 -0
  239. package/package.json +51 -0
@@ -0,0 +1,7 @@
1
+ export * from './Arc';
2
+ export * from './Circle';
3
+ export * from './Line';
4
+ export * from './Point';
5
+ export * from './Polygon';
6
+ export * from './Rectangle';
7
+ export * from './Arrow';
@@ -0,0 +1,7 @@
1
+ export * from './Arc';
2
+ export * from './Circle';
3
+ export * from './Line';
4
+ export * from './Point';
5
+ export * from './Polygon';
6
+ export * from './Rectangle';
7
+ export * from './Arrow';
@@ -0,0 +1,28 @@
1
+ import { VGroup } from '../VGroup';
2
+ import { GraphNode } from './GraphNode';
3
+ import { GraphEdge } from './GraphEdge';
4
+ import type { GraphNodeId, NodeConfig, EdgeConfig, LayoutType, LayoutConfig } from './types';
5
+ /**
6
+ * A graph structure containing nodes and edges.
7
+ * Manages nodes as VMobjects and edges as BezierPath curves.
8
+ * Supports multiple layout algorithms for automatic positioning.
9
+ */
10
+ export declare class Graph extends VGroup {
11
+ private nodes;
12
+ private edges;
13
+ constructor();
14
+ /** Adds a node to the graph. */
15
+ addNode(id: GraphNodeId, config?: NodeConfig): GraphNode;
16
+ /** Removes a node and all connected edges from the graph. */
17
+ removeNode(id: GraphNodeId): this;
18
+ getNode(id: GraphNodeId): GraphNode | undefined;
19
+ getNodes(): GraphNode[];
20
+ addEdge(sourceId: GraphNodeId, targetId: GraphNodeId, config?: EdgeConfig): GraphEdge | undefined;
21
+ removeEdge(sourceId: GraphNodeId, targetId: GraphNodeId): this;
22
+ private removeEdgeInternal;
23
+ getEdgePath(sourceId: GraphNodeId, targetId: GraphNodeId): ReturnType<GraphEdge['getPath']>;
24
+ getEdges(): GraphEdge[];
25
+ /** Applies a layout algorithm to reposition all nodes. */
26
+ layout(type: LayoutType, config?: LayoutConfig): this;
27
+ updateEdges(): this;
28
+ }
@@ -0,0 +1,119 @@
1
+ import { VGroup } from '../VGroup';
2
+ import { GraphNode } from './GraphNode';
3
+ import { GraphEdge } from './GraphEdge';
4
+ import { circularLayout, treeLayout, forceDirectedLayout } from './layouts';
5
+ /**
6
+ * A graph structure containing nodes and edges.
7
+ * Manages nodes as VMobjects and edges as BezierPath curves.
8
+ * Supports multiple layout algorithms for automatic positioning.
9
+ */
10
+ export class Graph extends VGroup {
11
+ nodes = new Map();
12
+ edges = [];
13
+ constructor() {
14
+ super();
15
+ }
16
+ /** Adds a node to the graph. */
17
+ addNode(id, config = {}) {
18
+ if (this.nodes.has(id)) {
19
+ const existing = this.nodes.get(id);
20
+ if (existing)
21
+ return existing;
22
+ }
23
+ const node = new GraphNode(id, config);
24
+ this.nodes.set(id, node);
25
+ this.add(node);
26
+ return node;
27
+ }
28
+ /** Removes a node and all connected edges from the graph. */
29
+ removeNode(id) {
30
+ const node = this.nodes.get(id);
31
+ if (!node)
32
+ return this;
33
+ // Remove connected edges
34
+ const connectedEdges = this.edges.filter(e => e.source === id || e.target === id);
35
+ for (const edge of connectedEdges) {
36
+ this.removeEdgeInternal(edge);
37
+ }
38
+ // Remove node
39
+ this.nodes.delete(id);
40
+ this.remove(node);
41
+ return this;
42
+ }
43
+ getNode(id) {
44
+ return this.nodes.get(id);
45
+ }
46
+ getNodes() {
47
+ return Array.from(this.nodes.values());
48
+ }
49
+ addEdge(sourceId, targetId, config = {}) {
50
+ const sourceNode = this.nodes.get(sourceId);
51
+ const targetNode = this.nodes.get(targetId);
52
+ if (!sourceNode || !targetNode) {
53
+ return undefined;
54
+ }
55
+ const existing = this.edges.find(e => (e.source === sourceId && e.target === targetId) ||
56
+ (e.source === targetId && e.target === sourceId));
57
+ if (existing)
58
+ return existing;
59
+ const edge = new GraphEdge(sourceNode, targetNode, config);
60
+ this.edges.push(edge);
61
+ this.add(edge);
62
+ return edge;
63
+ }
64
+ removeEdge(sourceId, targetId) {
65
+ const edge = this.edges.find(e => (e.source === sourceId && e.target === targetId) ||
66
+ (e.source === targetId && e.target === sourceId));
67
+ if (edge) {
68
+ this.removeEdgeInternal(edge);
69
+ }
70
+ return this;
71
+ }
72
+ removeEdgeInternal(edge) {
73
+ const index = this.edges.indexOf(edge);
74
+ if (index > -1) {
75
+ this.edges.splice(index, 1);
76
+ this.remove(edge);
77
+ }
78
+ }
79
+ getEdgePath(sourceId, targetId) {
80
+ const edge = this.edges.find(e => (e.source === sourceId && e.target === targetId) ||
81
+ (e.source === targetId && e.target === sourceId));
82
+ return edge?.getPath();
83
+ }
84
+ getEdges() {
85
+ return [...this.edges];
86
+ }
87
+ /** Applies a layout algorithm to reposition all nodes. */
88
+ layout(type, config = {}) {
89
+ const nodeArray = this.getNodes();
90
+ let positions;
91
+ switch (type) {
92
+ case 'circular':
93
+ positions = circularLayout(nodeArray, config);
94
+ break;
95
+ case 'tree':
96
+ positions = treeLayout(nodeArray, this.edges, config);
97
+ break;
98
+ case 'force-directed':
99
+ positions = forceDirectedLayout(nodeArray, this.edges, config);
100
+ break;
101
+ default:
102
+ positions = new Map();
103
+ }
104
+ for (const [id, position] of positions) {
105
+ const node = this.nodes.get(id);
106
+ if (node) {
107
+ node.pos(position.x, position.y);
108
+ }
109
+ }
110
+ this.updateEdges();
111
+ return this;
112
+ }
113
+ updateEdges() {
114
+ for (const edge of this.edges) {
115
+ edge.updatePath();
116
+ }
117
+ return this;
118
+ }
119
+ }
@@ -0,0 +1,26 @@
1
+ import { VMobject } from '../VMobject';
2
+ import { BezierPath } from '../../core/math/bezier/BezierPath';
3
+ import type { GraphNodeId, EdgeConfig } from './types';
4
+ import type { GraphNode } from './GraphNode';
5
+ /**
6
+ * A graph edge represented as a BezierPath connecting two nodes.
7
+ * Supports straight or curved edges with customizable styling.
8
+ */
9
+ export declare class GraphEdge extends VMobject {
10
+ readonly source: GraphNodeId;
11
+ readonly target: GraphNodeId;
12
+ private sourceNode;
13
+ private targetNode;
14
+ private curved;
15
+ constructor(sourceNode: GraphNode, targetNode: GraphNode, config?: EdgeConfig);
16
+ /**
17
+ * Recalculates the edge path based on current node positions.
18
+ * Call this when nodes move to update the edge connection.
19
+ */
20
+ updatePath(): void;
21
+ getPath(): BezierPath | undefined;
22
+ /**
23
+ * Updates node references (used when nodes are replaced).
24
+ */
25
+ setNodes(sourceNode: GraphNode, targetNode: GraphNode): void;
26
+ }
@@ -0,0 +1,64 @@
1
+ import { VMobject } from '../VMobject';
2
+ import { BezierPath } from '../../core/math/bezier/BezierPath';
3
+ import { Vector2 } from '../../core/math/Vector2/Vector2';
4
+ import { Color } from '../../core/math/color/Color';
5
+ /**
6
+ * A graph edge represented as a BezierPath connecting two nodes.
7
+ * Supports straight or curved edges with customizable styling.
8
+ */
9
+ export class GraphEdge extends VMobject {
10
+ source;
11
+ target;
12
+ sourceNode;
13
+ targetNode;
14
+ curved;
15
+ constructor(sourceNode, targetNode, config = {}) {
16
+ super();
17
+ this.source = sourceNode.id;
18
+ this.target = targetNode.id;
19
+ this.sourceNode = sourceNode;
20
+ this.targetNode = targetNode;
21
+ this.curved = config.curved ?? false;
22
+ // Apply styling
23
+ this.strokeColor = config.strokeColor ?? Color.WHITE;
24
+ this.strokeWidth = config.strokeWidth ?? 2;
25
+ this.fillColor = Color.TRANSPARENT;
26
+ this.fillOpacity = 0;
27
+ this.updatePath();
28
+ }
29
+ /**
30
+ * Recalculates the edge path based on current node positions.
31
+ * Call this when nodes move to update the edge connection.
32
+ */
33
+ updatePath() {
34
+ const startPos = this.sourceNode.getCenter();
35
+ const endPos = this.targetNode.getCenter();
36
+ const path = new BezierPath();
37
+ path.moveTo(startPos);
38
+ if (this.curved) {
39
+ // Create a curved path using quadratic Bezier
40
+ const mid = startPos.lerp(endPos, 0.5);
41
+ const direction = endPos.subtract(startPos);
42
+ const perpendicular = new Vector2(-direction.y, direction.x).normalize();
43
+ const curveOffset = direction.length() * 0.2;
44
+ const controlPoint = mid.add(perpendicular.multiply(curveOffset));
45
+ path.quadraticTo(controlPoint, endPos);
46
+ }
47
+ else {
48
+ // Straight line
49
+ path.lineTo(endPos);
50
+ }
51
+ this.pathList = [path];
52
+ }
53
+ getPath() {
54
+ return this.pathList[0];
55
+ }
56
+ /**
57
+ * Updates node references (used when nodes are replaced).
58
+ */
59
+ setNodes(sourceNode, targetNode) {
60
+ this.sourceNode = sourceNode;
61
+ this.targetNode = targetNode;
62
+ this.updatePath();
63
+ }
64
+ }
@@ -0,0 +1,19 @@
1
+ import { VMobject } from '../VMobject';
2
+ import { Vector2 } from '../../core/math/Vector2/Vector2';
3
+ import type { GraphNodeId, NodeConfig } from './types';
4
+ /**
5
+ * A graph node represented as a circular VMobject.
6
+ * Supports customizable radius, stroke, and fill styling.
7
+ */
8
+ export declare class GraphNode extends VMobject {
9
+ readonly id: GraphNodeId;
10
+ private nodeRadius;
11
+ constructor(id: GraphNodeId, config?: NodeConfig);
12
+ get radius(): number;
13
+ /**
14
+ * Generates a circular BezierPath approximation using cubic Bezier curves.
15
+ * Uses the standard 4-point circle approximation with control point factor ~0.5523.
16
+ */
17
+ private generateCirclePath;
18
+ getCenter(): Vector2;
19
+ }
@@ -0,0 +1,63 @@
1
+ import { VMobject } from '../VMobject';
2
+ import { BezierPath } from '../../core/math/bezier/BezierPath';
3
+ import { Vector2 } from '../../core/math/Vector2/Vector2';
4
+ const DEFAULT_RADIUS = 0.25;
5
+ /**
6
+ * A graph node represented as a circular VMobject.
7
+ * Supports customizable radius, stroke, and fill styling.
8
+ */
9
+ export class GraphNode extends VMobject {
10
+ id;
11
+ nodeRadius;
12
+ constructor(id, config = {}) {
13
+ super();
14
+ this.id = id;
15
+ this.nodeRadius = config.radius ?? DEFAULT_RADIUS;
16
+ // Apply initial position
17
+ if (config.position) {
18
+ this.pos(config.position.x, config.position.y);
19
+ }
20
+ // Apply styling only if explicitly provided in config
21
+ // If not provided, VMobject defaults apply (no stroke, no fill)
22
+ if (config.strokeColor !== undefined) {
23
+ this.strokeColor = config.strokeColor;
24
+ }
25
+ if (config.strokeWidth !== undefined) {
26
+ this.strokeWidth = config.strokeWidth;
27
+ }
28
+ if (config.fillColor !== undefined) {
29
+ this.fillColor = config.fillColor;
30
+ }
31
+ if (config.fillOpacity !== undefined) {
32
+ this.fillOpacity = config.fillOpacity;
33
+ }
34
+ this.generateCirclePath();
35
+ }
36
+ get radius() {
37
+ return this.nodeRadius;
38
+ }
39
+ /**
40
+ * Generates a circular BezierPath approximation using cubic Bezier curves.
41
+ * Uses the standard 4-point circle approximation with control point factor ~0.5523.
42
+ */
43
+ generateCirclePath() {
44
+ const path = new BezierPath();
45
+ const r = this.nodeRadius;
46
+ const k = 0.5522847498; // Magic number for circle approximation
47
+ // Start at the right-most point
48
+ path.moveTo(new Vector2(r, 0));
49
+ // Top-right quadrant
50
+ path.cubicTo(new Vector2(r, r * k), new Vector2(r * k, r), new Vector2(0, r));
51
+ // Top-left quadrant
52
+ path.cubicTo(new Vector2(-r * k, r), new Vector2(-r, r * k), new Vector2(-r, 0));
53
+ // Bottom-left quadrant
54
+ path.cubicTo(new Vector2(-r, -r * k), new Vector2(-r * k, -r), new Vector2(0, -r));
55
+ // Bottom-right quadrant
56
+ path.cubicTo(new Vector2(r * k, -r), new Vector2(r, -r * k), new Vector2(r, 0));
57
+ path.closePath();
58
+ this.pathList = [path];
59
+ }
60
+ getCenter() {
61
+ return this.position;
62
+ }
63
+ }
@@ -0,0 +1,5 @@
1
+ export { Graph } from './Graph';
2
+ export { GraphNode } from './GraphNode';
3
+ export { GraphEdge } from './GraphEdge';
4
+ export * from './types';
5
+ export * from './layouts';
@@ -0,0 +1,5 @@
1
+ export { Graph } from './Graph';
2
+ export { GraphNode } from './GraphNode';
3
+ export { GraphEdge } from './GraphEdge';
4
+ export * from './types';
5
+ export * from './layouts';
@@ -0,0 +1,8 @@
1
+ import { Vector2 } from '../../../core/math/Vector2/Vector2';
2
+ import type { GraphNode } from '../GraphNode';
3
+ import type { LayoutConfig } from '../types';
4
+ /**
5
+ * Arranges nodes in a circular layout.
6
+ * Nodes are evenly distributed around a circle of the specified radius.
7
+ */
8
+ export declare function circularLayout(nodes: GraphNode[], config?: LayoutConfig): Map<string, Vector2>;
@@ -0,0 +1,23 @@
1
+ import { Vector2 } from '../../../core/math/Vector2/Vector2';
2
+ const DEFAULT_RADIUS = 3;
3
+ /**
4
+ * Arranges nodes in a circular layout.
5
+ * Nodes are evenly distributed around a circle of the specified radius.
6
+ */
7
+ export function circularLayout(nodes, config = {}) {
8
+ const positions = new Map();
9
+ const radius = config.radius ?? DEFAULT_RADIUS;
10
+ const count = nodes.length;
11
+ if (count === 0)
12
+ return positions;
13
+ for (let i = 0; i < count; i++) {
14
+ const angle = (2 * Math.PI * i) / count - Math.PI / 2;
15
+ const x = radius * Math.cos(angle);
16
+ const y = radius * Math.sin(angle);
17
+ const node = nodes[i];
18
+ if (node) {
19
+ positions.set(node.id, new Vector2(x, y));
20
+ }
21
+ }
22
+ return positions;
23
+ }
@@ -0,0 +1,9 @@
1
+ import { Vector2 } from '../../../core/math/Vector2/Vector2';
2
+ import type { GraphNode } from '../GraphNode';
3
+ import type { GraphEdge } from '../GraphEdge';
4
+ import type { LayoutConfig } from '../types';
5
+ /**
6
+ * Applies force-directed layout using spring simulation.
7
+ * Nodes repel each other while edges act as springs.
8
+ */
9
+ export declare function forceDirectedLayout(nodes: GraphNode[], edges: GraphEdge[], config?: LayoutConfig): Map<string, Vector2>;
@@ -0,0 +1,102 @@
1
+ import { Vector2 } from '../../../core/math/Vector2/Vector2';
2
+ const DEFAULT_ITERATIONS = 50;
3
+ const DEFAULT_SPRING_LENGTH = 1.5;
4
+ const DEFAULT_REPULSION = 1.0;
5
+ const DEFAULT_ATTRACTION = 0.1;
6
+ const DEFAULT_DAMPING = 0.85;
7
+ const DEFAULT_MIN_DISTANCE = 0.01;
8
+ /**
9
+ * Applies force-directed layout using spring simulation.
10
+ * Nodes repel each other while edges act as springs.
11
+ */
12
+ export function forceDirectedLayout(nodes, edges, config = {}) {
13
+ const positions = new Map();
14
+ const iterations = config.iterations ?? DEFAULT_ITERATIONS;
15
+ const springLength = config.springLength ?? DEFAULT_SPRING_LENGTH;
16
+ const repulsion = config.repulsion ?? DEFAULT_REPULSION;
17
+ const attraction = config.attraction ?? DEFAULT_ATTRACTION;
18
+ const damping = config.damping ?? DEFAULT_DAMPING;
19
+ const minDistance = config.minDistance ?? DEFAULT_MIN_DISTANCE;
20
+ if (nodes.length === 0)
21
+ return positions;
22
+ // Initialize node states with current positions or random
23
+ const states = new Map();
24
+ for (let i = 0; i < nodes.length; i++) {
25
+ const node = nodes[i];
26
+ if (node) {
27
+ // Start with a circular distribution to avoid overlap
28
+ const angle = (2 * Math.PI * i) / nodes.length;
29
+ const initialPos = new Vector2(Math.cos(angle) * 2, Math.sin(angle) * 2);
30
+ states.set(node.id, {
31
+ position: initialPos,
32
+ velocity: Vector2.ZERO
33
+ });
34
+ }
35
+ }
36
+ // Build edge lookup
37
+ const edgeSet = new Set();
38
+ for (const edge of edges) {
39
+ edgeSet.add(`${edge.source}-${edge.target}`);
40
+ edgeSet.add(`${edge.target}-${edge.source}`);
41
+ }
42
+ // Run simulation
43
+ for (let iter = 0; iter < iterations; iter++) {
44
+ const forces = new Map();
45
+ // Initialize forces
46
+ for (const node of nodes) {
47
+ forces.set(node.id, Vector2.ZERO);
48
+ }
49
+ // Calculate repulsion forces between all node pairs
50
+ for (let i = 0; i < nodes.length; i++) {
51
+ for (let j = i + 1; j < nodes.length; j++) {
52
+ const nodeA = nodes[i];
53
+ const nodeB = nodes[j];
54
+ if (!nodeA || !nodeB)
55
+ continue;
56
+ const stateA = states.get(nodeA.id);
57
+ const stateB = states.get(nodeB.id);
58
+ if (!stateA || !stateB)
59
+ continue;
60
+ const delta = stateA.position.subtract(stateB.position);
61
+ const distance = Math.max(delta.length(), minDistance);
62
+ const force = delta.normalize().multiply(repulsion / (distance * distance));
63
+ const forceA = forces.get(nodeA.id) ?? Vector2.ZERO;
64
+ const forceB = forces.get(nodeB.id) ?? Vector2.ZERO;
65
+ forces.set(nodeA.id, forceA.add(force));
66
+ forces.set(nodeB.id, forceB.subtract(force));
67
+ }
68
+ }
69
+ // Calculate attraction forces along edges
70
+ for (const edge of edges) {
71
+ const stateA = states.get(edge.source);
72
+ const stateB = states.get(edge.target);
73
+ if (!stateA || !stateB)
74
+ continue;
75
+ const delta = stateB.position.subtract(stateA.position);
76
+ const distance = delta.length();
77
+ const displacement = distance - springLength;
78
+ const force = delta.normalize().multiply(displacement * attraction);
79
+ const forceA = forces.get(edge.source) ?? Vector2.ZERO;
80
+ const forceB = forces.get(edge.target) ?? Vector2.ZERO;
81
+ forces.set(edge.source, forceA.add(force));
82
+ forces.set(edge.target, forceB.subtract(force));
83
+ }
84
+ // Apply forces and update positions
85
+ for (const node of nodes) {
86
+ const state = states.get(node.id);
87
+ const force = forces.get(node.id);
88
+ if (!state || !force)
89
+ continue;
90
+ state.velocity = state.velocity.add(force).multiply(damping);
91
+ state.position = state.position.add(state.velocity);
92
+ }
93
+ }
94
+ // Collect final positions
95
+ for (const node of nodes) {
96
+ const state = states.get(node.id);
97
+ if (state) {
98
+ positions.set(node.id, state.position);
99
+ }
100
+ }
101
+ return positions;
102
+ }
@@ -0,0 +1,3 @@
1
+ export { circularLayout } from './circular';
2
+ export { treeLayout } from './tree';
3
+ export { forceDirectedLayout } from './forceDirected';
@@ -0,0 +1,3 @@
1
+ export { circularLayout } from './circular';
2
+ export { treeLayout } from './tree';
3
+ export { forceDirectedLayout } from './forceDirected';
@@ -0,0 +1,9 @@
1
+ import { Vector2 } from '../../../core/math/Vector2/Vector2';
2
+ import type { GraphNode } from '../GraphNode';
3
+ import type { GraphEdge } from '../GraphEdge';
4
+ import type { LayoutConfig } from '../types';
5
+ /**
6
+ * Arranges nodes in a hierarchical tree layout.
7
+ * Assumes edges represent parent-child relationships.
8
+ */
9
+ export declare function treeLayout(nodes: GraphNode[], edges: GraphEdge[], config?: LayoutConfig): Map<string, Vector2>;
@@ -0,0 +1,99 @@
1
+ import { Vector2 } from '../../../core/math/Vector2/Vector2';
2
+ const DEFAULT_LEVEL_HEIGHT = 1.5;
3
+ const DEFAULT_SIBLING_SPACING = 1.0;
4
+ /**
5
+ * Builds a tree structure from nodes and edges.
6
+ * Assumes directed edges from parent to child.
7
+ */
8
+ function buildTree(nodes, edges) {
9
+ if (nodes.length === 0)
10
+ return undefined;
11
+ const hasIncoming = new Set();
12
+ for (const edge of edges) {
13
+ hasIncoming.add(edge.target);
14
+ }
15
+ const nodeMap = new Map();
16
+ for (const node of nodes) {
17
+ nodeMap.set(node.id, node);
18
+ }
19
+ // Build adjacency list (parent -> children)
20
+ const childrenMap = new Map();
21
+ for (const edge of edges) {
22
+ const children = childrenMap.get(edge.source) ?? [];
23
+ children.push(edge.target);
24
+ childrenMap.set(edge.source, children);
25
+ }
26
+ let rootId;
27
+ for (const node of nodes) {
28
+ if (!hasIncoming.has(node.id)) {
29
+ rootId = node.id;
30
+ break;
31
+ }
32
+ }
33
+ if (!rootId && nodes[0]) {
34
+ rootId = nodes[0].id;
35
+ }
36
+ if (!rootId)
37
+ return undefined;
38
+ // Build tree recursively
39
+ function buildNode(id, depth) {
40
+ const children = (childrenMap.get(id) ?? [])
41
+ .map(childId => buildNode(childId, depth + 1));
42
+ const width = children.length === 0
43
+ ? 1
44
+ : children.reduce((sum, c) => sum + c.width, 0);
45
+ return { id, children, depth, x: 0, width };
46
+ }
47
+ return buildNode(rootId, 0);
48
+ }
49
+ /**
50
+ * Recursively assigns x positions to tree nodes.
51
+ */
52
+ function assignPositions(node, leftBound, spacing) {
53
+ if (node.children.length === 0) {
54
+ node.x = leftBound + node.width * spacing / 2;
55
+ return;
56
+ }
57
+ let currentLeft = leftBound;
58
+ for (const child of node.children) {
59
+ assignPositions(child, currentLeft, spacing);
60
+ currentLeft += child.width * spacing;
61
+ }
62
+ // Center parent over children
63
+ const firstChild = node.children[0];
64
+ const lastChild = node.children[node.children.length - 1];
65
+ if (firstChild && lastChild) {
66
+ node.x = (firstChild.x + lastChild.x) / 2;
67
+ }
68
+ }
69
+ /**
70
+ * Collects all positions from the tree.
71
+ */
72
+ function collectPositions(node, levelHeight, positions) {
73
+ positions.set(node.id, new Vector2(node.x, node.depth * levelHeight));
74
+ for (const child of node.children) {
75
+ collectPositions(child, levelHeight, positions);
76
+ }
77
+ }
78
+ /**
79
+ * Arranges nodes in a hierarchical tree layout.
80
+ * Assumes edges represent parent-child relationships.
81
+ */
82
+ export function treeLayout(nodes, edges, config = {}) {
83
+ const positions = new Map();
84
+ const levelHeight = config.levelHeight ?? DEFAULT_LEVEL_HEIGHT;
85
+ const siblingSpacing = config.siblingSpacing ?? DEFAULT_SIBLING_SPACING;
86
+ const tree = buildTree(nodes, edges);
87
+ if (!tree)
88
+ return positions;
89
+ assignPositions(tree, 0, siblingSpacing);
90
+ collectPositions(tree, levelHeight, positions);
91
+ const allX = Array.from(positions.values()).map(p => p.x);
92
+ const minX = Math.min(...allX);
93
+ const maxX = Math.max(...allX);
94
+ const centerOffset = (minX + maxX) / 2;
95
+ for (const [id, pos] of positions) {
96
+ positions.set(id, new Vector2(pos.x - centerOffset, pos.y));
97
+ }
98
+ return positions;
99
+ }
@@ -0,0 +1,35 @@
1
+ import { Color } from '../../core/math/color/Color';
2
+ /** Unique identifier for graph nodes. */
3
+ export type GraphNodeId = string;
4
+ /** Configuration for creating a graph node. */
5
+ export interface NodeConfig {
6
+ position?: {
7
+ x: number;
8
+ y: number;
9
+ };
10
+ radius?: number;
11
+ strokeColor?: Color;
12
+ strokeWidth?: number;
13
+ fillColor?: Color;
14
+ fillOpacity?: number;
15
+ }
16
+ /** Configuration for creating a graph edge. */
17
+ export interface EdgeConfig {
18
+ strokeColor?: Color;
19
+ strokeWidth?: number;
20
+ curved?: boolean;
21
+ }
22
+ /** Supported layout algorithms. */
23
+ export type LayoutType = 'force-directed' | 'tree' | 'circular';
24
+ /** Configuration for graph layout algorithms. */
25
+ export interface LayoutConfig {
26
+ radius?: number;
27
+ levelHeight?: number;
28
+ siblingSpacing?: number;
29
+ iterations?: number;
30
+ springLength?: number;
31
+ repulsion?: number;
32
+ attraction?: number;
33
+ damping?: number;
34
+ minDistance?: number;
35
+ }
File without changes
@@ -0,0 +1,6 @@
1
+ export * from './Mobject';
2
+ export * from './VMobject';
3
+ export * from './VGroup';
4
+ export * from './geometry';
5
+ export * from './text';
6
+ export * from './graph';
@@ -0,0 +1,6 @@
1
+ export * from './Mobject';
2
+ export * from './VMobject';
3
+ export * from './VGroup';
4
+ export * from './geometry';
5
+ export * from './text';
6
+ export * from './graph';