@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,139 @@
1
+ import { Matrix3x3 } from '../../core/math/matrix/Matrix3x3';
2
+ import { Camera } from '../../core/camera';
3
+ /** Default camera for layout functions when none is provided. */
4
+ const defaultCamera = new Camera();
5
+ /** Centers a VGroup's bounding box at the origin (0, 0). */
6
+ export function centerGroup(group) {
7
+ const bounds = group.getBoundingBox();
8
+ const centerX = (bounds.minX + bounds.maxX) / 2;
9
+ const centerY = (bounds.minY + bounds.maxY) / 2;
10
+ const translation = Matrix3x3.translation(-centerX, -centerY);
11
+ // Apply translation to all children directly (not to group)
12
+ for (const child of group.getChildren()) {
13
+ child.applyMatrix(translation);
14
+ }
15
+ return group;
16
+ }
17
+ /**
18
+ * Moves a VGroup's bounding box to a corner of the frame.
19
+ * @param group The VGroup to position
20
+ * @param corner Which corner to move to
21
+ * @param buff Buffer/margin from the corner
22
+ * @param camera Camera providing frame dimensions (defaults to 1920x1080)
23
+ */
24
+ export function toCorner(group, corner, buff = 0.0, camera = defaultCamera) {
25
+ const bounds = group.getBoundingBox();
26
+ const width = bounds.maxX - bounds.minX;
27
+ const height = bounds.maxY - bounds.minY;
28
+ const frameXRadius = camera.frameXRadius;
29
+ const frameYRadius = camera.frameYRadius;
30
+ let targetX = 0;
31
+ let targetY = 0;
32
+ switch (corner) {
33
+ case 'TOP_LEFT':
34
+ targetX = -frameXRadius + width / 2 + buff;
35
+ targetY = -frameYRadius + height / 2 + buff;
36
+ break;
37
+ case 'TOP_RIGHT':
38
+ targetX = frameXRadius - width / 2 - buff;
39
+ targetY = -frameYRadius + height / 2 + buff;
40
+ break;
41
+ case 'BOTTOM_LEFT':
42
+ targetX = -frameXRadius + width / 2 + buff;
43
+ targetY = frameYRadius - height / 2 - buff;
44
+ break;
45
+ case 'BOTTOM_RIGHT':
46
+ targetX = frameXRadius - width / 2 - buff;
47
+ targetY = frameYRadius - height / 2 - buff;
48
+ break;
49
+ }
50
+ const currentCenterX = (bounds.minX + bounds.maxX) / 2;
51
+ const currentCenterY = (bounds.minY + bounds.maxY) / 2;
52
+ const shiftX = targetX - currentCenterX;
53
+ const shiftY = targetY - currentCenterY;
54
+ const translation = Matrix3x3.translation(shiftX, shiftY);
55
+ // Apply translation to all children directly
56
+ for (const child of group.getChildren()) {
57
+ child.applyMatrix(translation);
58
+ }
59
+ return group;
60
+ }
61
+ /** Arranges children in a line along the specified direction. */
62
+ export function arrangeChildren(group, direction = 'RIGHT', buff = 0.25, shouldCenter = true) {
63
+ const children = group.getChildren();
64
+ if (children.length === 0)
65
+ return group;
66
+ let previousChild = children[0];
67
+ for (let i = 1; i < children.length; i++) {
68
+ const child = children[i];
69
+ const prevBounds = previousChild.getBoundingBox();
70
+ const childBounds = child.getBoundingBox();
71
+ let shiftX = 0;
72
+ let shiftY = 0;
73
+ if (direction === 'RIGHT') {
74
+ const targetLeft = prevBounds.maxX + buff;
75
+ const currentLeft = childBounds.minX;
76
+ shiftX = targetLeft - currentLeft;
77
+ const prevCenterY = (prevBounds.minY + prevBounds.maxY) / 2;
78
+ const childCenterY = (childBounds.minY + childBounds.maxY) / 2;
79
+ shiftY = prevCenterY - childCenterY;
80
+ }
81
+ else if (direction === 'LEFT') {
82
+ const targetRight = prevBounds.minX - buff;
83
+ const currentRight = childBounds.maxX;
84
+ shiftX = targetRight - currentRight;
85
+ const prevCenterY = (prevBounds.minY + prevBounds.maxY) / 2;
86
+ const childCenterY = (childBounds.minY + childBounds.maxY) / 2;
87
+ shiftY = prevCenterY - childCenterY;
88
+ }
89
+ else if (direction === 'DOWN') {
90
+ const targetTop = prevBounds.maxY + buff;
91
+ const currentTop = childBounds.minY;
92
+ shiftY = targetTop - currentTop;
93
+ const prevCenterX = (prevBounds.minX + prevBounds.maxX) / 2;
94
+ const childCenterX = (childBounds.minX + childBounds.maxX) / 2;
95
+ shiftX = prevCenterX - childCenterX;
96
+ }
97
+ else if (direction === 'UP') {
98
+ const targetBottom = prevBounds.minY - buff;
99
+ const currentBottom = childBounds.maxY;
100
+ shiftY = targetBottom - currentBottom;
101
+ const prevCenterX = (prevBounds.minX + prevBounds.maxX) / 2;
102
+ const childCenterX = (childBounds.minX + childBounds.maxX) / 2;
103
+ shiftX = prevCenterX - childCenterX;
104
+ }
105
+ child.applyMatrix(Matrix3x3.translation(shiftX, shiftY));
106
+ previousChild = child;
107
+ }
108
+ if (shouldCenter) {
109
+ centerGroup(group);
110
+ }
111
+ return group;
112
+ }
113
+ /** Aligns a VGroup to a target VMobject's edge. */
114
+ export function alignToTarget(group, target, edge) {
115
+ const targetBounds = target.getBoundingBox();
116
+ const myBounds = group.getBoundingBox();
117
+ let shiftX = 0;
118
+ let shiftY = 0;
119
+ switch (edge) {
120
+ case 'TOP':
121
+ shiftY = targetBounds.minY - myBounds.minY;
122
+ break;
123
+ case 'BOTTOM':
124
+ shiftY = targetBounds.maxY - myBounds.maxY;
125
+ break;
126
+ case 'LEFT':
127
+ shiftX = targetBounds.minX - myBounds.minX;
128
+ break;
129
+ case 'RIGHT':
130
+ shiftX = targetBounds.maxX - myBounds.maxX;
131
+ break;
132
+ }
133
+ const translation = Matrix3x3.translation(shiftX, shiftY);
134
+ // Apply translation to all children directly
135
+ for (const child of group.getChildren()) {
136
+ child.applyMatrix(translation);
137
+ }
138
+ return group;
139
+ }
@@ -0,0 +1,106 @@
1
+ import { Mobject } from './Mobject';
2
+ import type { Animation } from '../core/animations/Animation';
3
+ import { BezierPath } from '../core/math/bezier/BezierPath';
4
+ import type { PathCommand } from '../core/math/bezier/types';
5
+ import { Color } from '../core/math/color/Color';
6
+ /**
7
+ * A Mobject that is defined by one or more BezierPaths.
8
+ * Supports stroke and fill styling, plus VMobject-specific fluent animations.
9
+ *
10
+ * Default behavior: visible with white stroke, no fill.
11
+ * - Stroke: white, width 2 (visible by default)
12
+ * - Fill: not rendered by default (fillOpacity = 0)
13
+ *
14
+ * When .fill(color) is called, the default stroke is disabled unless
15
+ * .stroke(color, width) was called explicitly.
16
+ *
17
+ * Use .stroke(color, width) to add a stroke.
18
+ * Use .fill(color) to add a fill (opacity defaults to 1).
19
+ */
20
+ export declare class VMobject extends Mobject {
21
+ protected pathList: BezierPath[];
22
+ /** Stroke color. Only rendered if strokeWidth > 0. */
23
+ protected strokeColor: Color;
24
+ /** Stroke width. Default 2 for visibility. */
25
+ protected strokeWidth: number;
26
+ /** Fill color. Only rendered if fillOpacity > 0. */
27
+ protected fillColor: Color;
28
+ /** Fill opacity. Default 0 means no fill is rendered. */
29
+ protected fillOpacity: number;
30
+ /** Tracks whether stroke() was explicitly called. */
31
+ protected strokeExplicitlySet: boolean;
32
+ constructor();
33
+ get paths(): BezierPath[];
34
+ set paths(value: BezierPath[]);
35
+ /**
36
+ * Gets the stroke color.
37
+ */
38
+ getStrokeColor(): Color;
39
+ /**
40
+ * Gets the stroke width.
41
+ */
42
+ getStrokeWidth(): number;
43
+ /**
44
+ * Gets the fill color.
45
+ */
46
+ getFillColor(): Color;
47
+ /**
48
+ * Gets the fill opacity.
49
+ */
50
+ getFillOpacity(): number;
51
+ /**
52
+ * Adds a new path to the VMobject.
53
+ * @param path - The BezierPath to add.
54
+ * @returns this for chaining.
55
+ */
56
+ addPath(path: BezierPath): this;
57
+ /**
58
+ * Sets the stroke color and width.
59
+ * @param color - The stroke color.
60
+ * @param width - The stroke width. Default is 2.
61
+ * @returns this for chaining.
62
+ */
63
+ stroke(color: Color, width?: number): this;
64
+ /**
65
+ * Sets the fill color and opacity.
66
+ * If stroke was not explicitly set, the default stroke is disabled.
67
+ * @param color - The fill color.
68
+ * @param opacity - The fill opacity. Defaults to the color's alpha value.
69
+ * @returns this for chaining.
70
+ */
71
+ fill(color: Color, opacity?: number): this;
72
+ getPoints(): PathCommand[];
73
+ setPoints(commands: PathCommand[]): this;
74
+ private getPointsAsVectors;
75
+ getBoundingBox(): {
76
+ minX: number;
77
+ maxX: number;
78
+ minY: number;
79
+ maxY: number;
80
+ };
81
+ /**
82
+ * Progressively draws the VMobject's paths from start to end.
83
+ * Preserves fill throughout the animation.
84
+ * @param durationSeconds - Animation duration in seconds.
85
+ * @returns this for chaining.
86
+ */
87
+ write(durationSeconds?: number): this & {
88
+ toAnimation(): Animation<Mobject>;
89
+ };
90
+ /**
91
+ * Progressively removes the VMobject's paths (reverse of write).
92
+ * @param durationSeconds - Animation duration in seconds.
93
+ * @returns this for chaining.
94
+ */
95
+ unwrite(durationSeconds?: number): this & {
96
+ toAnimation(): Animation<Mobject>;
97
+ };
98
+ /**
99
+ * First draws the stroke progressively (0-50%), then fades in the fill (50-100%).
100
+ * @param durationSeconds - Animation duration in seconds.
101
+ * @returns this for chaining.
102
+ */
103
+ draw(durationSeconds?: number): this & {
104
+ toAnimation(): Animation<Mobject>;
105
+ };
106
+ }
@@ -0,0 +1,216 @@
1
+ import { Mobject } from './Mobject';
2
+ import { BezierPath } from '../core/math/bezier/BezierPath';
3
+ import { Color } from '../core/math/color/Color';
4
+ import { Write, Unwrite, Draw } from '../core/animations/draw';
5
+ /**
6
+ * A Mobject that is defined by one or more BezierPaths.
7
+ * Supports stroke and fill styling, plus VMobject-specific fluent animations.
8
+ *
9
+ * Default behavior: visible with white stroke, no fill.
10
+ * - Stroke: white, width 2 (visible by default)
11
+ * - Fill: not rendered by default (fillOpacity = 0)
12
+ *
13
+ * When .fill(color) is called, the default stroke is disabled unless
14
+ * .stroke(color, width) was called explicitly.
15
+ *
16
+ * Use .stroke(color, width) to add a stroke.
17
+ * Use .fill(color) to add a fill (opacity defaults to 1).
18
+ */
19
+ export class VMobject extends Mobject {
20
+ pathList = [];
21
+ /** Stroke color. Only rendered if strokeWidth > 0. */
22
+ strokeColor = Color.WHITE;
23
+ /** Stroke width. Default 2 for visibility. */
24
+ strokeWidth = 2;
25
+ /** Fill color. Only rendered if fillOpacity > 0. */
26
+ fillColor = Color.TRANSPARENT;
27
+ /** Fill opacity. Default 0 means no fill is rendered. */
28
+ fillOpacity = 0;
29
+ /** Tracks whether stroke() was explicitly called. */
30
+ strokeExplicitlySet = false;
31
+ constructor() {
32
+ super();
33
+ }
34
+ get paths() {
35
+ return this.pathList;
36
+ }
37
+ set paths(value) {
38
+ this.pathList = value;
39
+ }
40
+ /**
41
+ * Gets the stroke color.
42
+ */
43
+ getStrokeColor() {
44
+ return this.strokeColor;
45
+ }
46
+ /**
47
+ * Gets the stroke width.
48
+ */
49
+ getStrokeWidth() {
50
+ return this.strokeWidth;
51
+ }
52
+ /**
53
+ * Gets the fill color.
54
+ */
55
+ getFillColor() {
56
+ return this.fillColor;
57
+ }
58
+ /**
59
+ * Gets the fill opacity.
60
+ */
61
+ getFillOpacity() {
62
+ return this.fillOpacity;
63
+ }
64
+ /**
65
+ * Adds a new path to the VMobject.
66
+ * @param path - The BezierPath to add.
67
+ * @returns this for chaining.
68
+ */
69
+ addPath(path) {
70
+ this.pathList.push(path);
71
+ return this;
72
+ }
73
+ /**
74
+ * Sets the stroke color and width.
75
+ * @param color - The stroke color.
76
+ * @param width - The stroke width. Default is 2.
77
+ * @returns this for chaining.
78
+ */
79
+ stroke(color, width = 2) {
80
+ this.strokeColor = color;
81
+ this.strokeWidth = width;
82
+ this.strokeExplicitlySet = true;
83
+ return this;
84
+ }
85
+ /**
86
+ * Sets the fill color and opacity.
87
+ * If stroke was not explicitly set, the default stroke is disabled.
88
+ * @param color - The fill color.
89
+ * @param opacity - The fill opacity. Defaults to the color's alpha value.
90
+ * @returns this for chaining.
91
+ */
92
+ fill(color, opacity) {
93
+ this.fillColor = color;
94
+ this.fillOpacity = opacity ?? color.a;
95
+ // Disable default stroke when fill is set (unless stroke was explicitly set)
96
+ if (!this.strokeExplicitlySet) {
97
+ this.strokeWidth = 0;
98
+ }
99
+ return this;
100
+ }
101
+ getPoints() {
102
+ const commands = [];
103
+ for (const path of this.pathList) {
104
+ commands.push(...path.getCommands());
105
+ }
106
+ return commands;
107
+ }
108
+ setPoints(commands) {
109
+ if (commands.length === 0) {
110
+ this.pathList = [];
111
+ return this;
112
+ }
113
+ const path = new BezierPath();
114
+ for (const cmd of commands) {
115
+ switch (cmd.type) {
116
+ case 'Move':
117
+ path.moveTo(cmd.end);
118
+ break;
119
+ case 'Line':
120
+ path.lineTo(cmd.end);
121
+ break;
122
+ case 'Quadratic':
123
+ if (cmd.control1) {
124
+ path.quadraticTo(cmd.control1, cmd.end);
125
+ }
126
+ break;
127
+ case 'Cubic':
128
+ if (cmd.control1 && cmd.control2) {
129
+ path.cubicTo(cmd.control1, cmd.control2, cmd.end);
130
+ }
131
+ break;
132
+ case 'Close':
133
+ path.closePath();
134
+ break;
135
+ }
136
+ }
137
+ this.pathList = [path];
138
+ return this;
139
+ }
140
+ getPointsAsVectors() {
141
+ const points = [];
142
+ for (const cmd of this.getPoints()) {
143
+ if (cmd.control1)
144
+ points.push(cmd.control1);
145
+ if (cmd.control2)
146
+ points.push(cmd.control2);
147
+ points.push(cmd.end);
148
+ }
149
+ return points;
150
+ }
151
+ getBoundingBox() {
152
+ const points = this.getPointsAsVectors();
153
+ const worldMatrix = this.getWorldMatrix();
154
+ if (points.length === 0) {
155
+ const pos = this.position;
156
+ return { minX: pos.x, maxX: pos.x, minY: pos.y, maxY: pos.y };
157
+ }
158
+ let minX = Infinity;
159
+ let maxX = -Infinity;
160
+ let minY = Infinity;
161
+ let maxY = -Infinity;
162
+ for (const point of points) {
163
+ const transformed = worldMatrix.transformPoint(point);
164
+ if (transformed.x < minX)
165
+ minX = transformed.x;
166
+ if (transformed.x > maxX)
167
+ maxX = transformed.x;
168
+ if (transformed.y < minY)
169
+ minY = transformed.y;
170
+ if (transformed.y > maxY)
171
+ maxY = transformed.y;
172
+ }
173
+ return { minX, maxX, minY, maxY };
174
+ }
175
+ // ========== VMobject-Specific Fluent Animation API ==========
176
+ /**
177
+ * Progressively draws the VMobject's paths from start to end.
178
+ * Preserves fill throughout the animation.
179
+ * @param durationSeconds - Animation duration in seconds.
180
+ * @returns this for chaining.
181
+ */
182
+ write(durationSeconds) {
183
+ const animation = new Write(this);
184
+ if (durationSeconds !== undefined) {
185
+ animation.duration(durationSeconds);
186
+ }
187
+ this.getQueue().enqueueAnimation(animation);
188
+ return this;
189
+ }
190
+ /**
191
+ * Progressively removes the VMobject's paths (reverse of write).
192
+ * @param durationSeconds - Animation duration in seconds.
193
+ * @returns this for chaining.
194
+ */
195
+ unwrite(durationSeconds) {
196
+ const animation = new Unwrite(this);
197
+ if (durationSeconds !== undefined) {
198
+ animation.duration(durationSeconds);
199
+ }
200
+ this.getQueue().enqueueAnimation(animation);
201
+ return this;
202
+ }
203
+ /**
204
+ * First draws the stroke progressively (0-50%), then fades in the fill (50-100%).
205
+ * @param durationSeconds - Animation duration in seconds.
206
+ * @returns this for chaining.
207
+ */
208
+ draw(durationSeconds) {
209
+ const animation = new Draw(this);
210
+ if (durationSeconds !== undefined) {
211
+ animation.duration(durationSeconds);
212
+ }
213
+ this.getQueue().enqueueAnimation(animation);
214
+ return this;
215
+ }
216
+ }
@@ -0,0 +1,8 @@
1
+ import { VMobject } from '../VMobject';
2
+ export declare class Arc extends VMobject {
3
+ readonly radius: number;
4
+ readonly startAngle: number;
5
+ readonly endAngle: number;
6
+ constructor(radius?: number, startAngle?: number, endAngle?: number);
7
+ private generatePath;
8
+ }
@@ -0,0 +1,46 @@
1
+ import { VMobject } from '../VMobject';
2
+ import { BezierPath } from '../../core/math/bezier/BezierPath';
3
+ import { Vector2 } from '../../core/math/Vector2/Vector2';
4
+ export class Arc extends VMobject {
5
+ radius;
6
+ startAngle;
7
+ endAngle;
8
+ constructor(radius = 1.0, startAngle = 0, endAngle = Math.PI / 2) {
9
+ super();
10
+ this.radius = radius;
11
+ this.startAngle = startAngle;
12
+ this.endAngle = endAngle;
13
+ this.generatePath();
14
+ }
15
+ generatePath() {
16
+ const path = new BezierPath();
17
+ const sweepAngle = this.endAngle - this.startAngle;
18
+ const absSweep = Math.abs(sweepAngle);
19
+ // Split into segments of at most 90 degrees to maintain accuracy
20
+ const maxSegmentAngle = Math.PI / 2;
21
+ const numSegments = Math.max(1, Math.ceil(absSweep / maxSegmentAngle));
22
+ const stepAngle = sweepAngle / numSegments;
23
+ // k = (4/3) * tan(theta/4)
24
+ const k = (4 / 3) * Math.tan(stepAngle / 4);
25
+ let currentAngle = this.startAngle;
26
+ // Start point
27
+ const startX = this.radius * Math.cos(currentAngle);
28
+ const startY = this.radius * Math.sin(currentAngle);
29
+ path.moveTo(new Vector2(startX, startY));
30
+ for (let i = 0; i < numSegments; i++) {
31
+ const alpha = currentAngle;
32
+ const nextAngle = currentAngle + stepAngle;
33
+ // P3 is next point
34
+ const p3 = new Vector2(this.radius * Math.cos(nextAngle), this.radius * Math.sin(nextAngle));
35
+ // Control points
36
+ // P1 = P0 + tangent(alpha) * R * k
37
+ // Tangent vector rotated 90 deg from radius: (-sin, cos)
38
+ const cp1 = new Vector2(this.radius * Math.cos(alpha), this.radius * Math.sin(alpha)).add(new Vector2(-Math.sin(alpha), Math.cos(alpha)).multiply(this.radius * k));
39
+ // P2 = P3 - tangent(nextAngle) * R * k
40
+ const cp2 = p3.subtract(new Vector2(-Math.sin(nextAngle), Math.cos(nextAngle)).multiply(this.radius * k));
41
+ path.cubicTo(cp1, cp2, p3);
42
+ currentAngle += stepAngle;
43
+ }
44
+ this.pathList = [path];
45
+ }
46
+ }
@@ -0,0 +1,7 @@
1
+ import { Line } from './Line';
2
+ export declare class Arrow extends Line {
3
+ readonly tipLength: number;
4
+ readonly tipAngle: number;
5
+ constructor(x1?: number, y1?: number, x2?: number, y2?: number, tipLength?: number, tipAngle?: number);
6
+ private addTip;
7
+ }
@@ -0,0 +1,34 @@
1
+ import { Line } from './Line';
2
+ import { Vector2 } from '../../core/math/Vector2/Vector2';
3
+ import { BezierPath } from '../../core/math/bezier/BezierPath';
4
+ export class Arrow extends Line {
5
+ tipLength;
6
+ tipAngle;
7
+ constructor(x1 = 0, y1 = 0, x2 = 1, y2 = 0, tipLength = 0.25, tipAngle = Math.PI / 6) {
8
+ super(x1, y1, x2, y2);
9
+ this.tipLength = tipLength;
10
+ this.tipAngle = tipAngle;
11
+ this.addTip();
12
+ }
13
+ addTip() {
14
+ const direction = this.end.subtract(this.start);
15
+ if (direction.length() === 0)
16
+ return;
17
+ const normalizedDir = direction.normalize();
18
+ const angle = Math.atan2(normalizedDir.y, normalizedDir.x);
19
+ // Calculate tip vertices
20
+ // The tip points backwards from the end
21
+ const angle1 = angle + Math.PI - this.tipAngle;
22
+ const angle2 = angle + Math.PI + this.tipAngle;
23
+ const p1 = this.end.add(new Vector2(Math.cos(angle1), Math.sin(angle1)).multiply(this.tipLength));
24
+ const p2 = this.end.add(new Vector2(Math.cos(angle2), Math.sin(angle2)).multiply(this.tipLength));
25
+ const tipPath = new BezierPath();
26
+ tipPath.moveTo(this.end);
27
+ tipPath.lineTo(p1);
28
+ tipPath.lineTo(p2);
29
+ tipPath.closePath();
30
+ this.addPath(tipPath);
31
+ // Ensure the tip is filled
32
+ this.fillOpacity = 1;
33
+ }
34
+ }
@@ -0,0 +1,4 @@
1
+ import { Arc } from './Arc';
2
+ export declare class Circle extends Arc {
3
+ constructor(radius?: number);
4
+ }
@@ -0,0 +1,10 @@
1
+ import { Arc } from './Arc';
2
+ export class Circle extends Arc {
3
+ constructor(radius = 1.0) {
4
+ super(radius, 0, Math.PI * 2);
5
+ // Ensure path is closed for a full circle
6
+ if (this.pathList.length > 0) {
7
+ this.pathList[0].closePath();
8
+ }
9
+ }
10
+ }
@@ -0,0 +1,8 @@
1
+ import { VMobject } from '../VMobject';
2
+ import { Vector2 } from '../../core/math/Vector2/Vector2';
3
+ export declare class Line extends VMobject {
4
+ readonly start: Vector2;
5
+ readonly end: Vector2;
6
+ constructor(x1?: number, y1?: number, x2?: number, y2?: number);
7
+ private generatePath;
8
+ }
@@ -0,0 +1,19 @@
1
+ import { VMobject } from '../VMobject';
2
+ import { BezierPath } from '../../core/math/bezier/BezierPath';
3
+ import { Vector2 } from '../../core/math/Vector2/Vector2';
4
+ export class Line extends VMobject {
5
+ start;
6
+ end;
7
+ constructor(x1 = 0, y1 = 0, x2 = 1, y2 = 0) {
8
+ super();
9
+ this.start = new Vector2(x1, y1);
10
+ this.end = new Vector2(x2, y2);
11
+ this.generatePath();
12
+ }
13
+ generatePath() {
14
+ const path = new BezierPath();
15
+ path.moveTo(this.start);
16
+ path.lineTo(this.end);
17
+ this.pathList = [path];
18
+ }
19
+ }
@@ -0,0 +1,5 @@
1
+ import { Circle } from './Circle';
2
+ import { Vector2 } from '../../core/math/Vector2/Vector2';
3
+ export declare class Point extends Circle {
4
+ constructor(location?: Vector2);
5
+ }
@@ -0,0 +1,11 @@
1
+ import { Circle } from './Circle';
2
+ import { Vector2 } from '../../core/math/Vector2/Vector2';
3
+ import { Color } from '../../core/math/color/Color';
4
+ export class Point extends Circle {
5
+ constructor(location = Vector2.ZERO) {
6
+ super(0.05); // Small radius
7
+ this.fill(Color.WHITE, 1.0);
8
+ this.stroke(Color.WHITE, 0); // No stroke usually for points, or just fill
9
+ this.pos(location.x, location.y);
10
+ }
11
+ }
@@ -0,0 +1,7 @@
1
+ import { VMobject } from '../VMobject';
2
+ import { Vector2 } from '../../core/math/Vector2/Vector2';
3
+ export declare class Polygon extends VMobject {
4
+ readonly vertices: Vector2[];
5
+ constructor(vertices: Vector2[]);
6
+ private generatePath;
7
+ }
@@ -0,0 +1,21 @@
1
+ import { VMobject } from '../VMobject';
2
+ import { BezierPath } from '../../core/math/bezier/BezierPath';
3
+ export class Polygon extends VMobject {
4
+ vertices;
5
+ constructor(vertices) {
6
+ super();
7
+ this.vertices = vertices;
8
+ this.generatePath();
9
+ }
10
+ generatePath() {
11
+ if (this.vertices.length === 0)
12
+ return;
13
+ const path = new BezierPath();
14
+ path.moveTo(this.vertices[0]);
15
+ for (let i = 1; i < this.vertices.length; i++) {
16
+ path.lineTo(this.vertices[i]);
17
+ }
18
+ path.closePath();
19
+ this.pathList = [path];
20
+ }
21
+ }
@@ -0,0 +1,6 @@
1
+ import { Polygon } from './Polygon';
2
+ export declare class Rectangle extends Polygon {
3
+ readonly width: number;
4
+ readonly height: number;
5
+ constructor(width?: number, height?: number);
6
+ }
@@ -0,0 +1,18 @@
1
+ import { Polygon } from './Polygon';
2
+ import { Vector2 } from '../../core/math/Vector2/Vector2';
3
+ export class Rectangle extends Polygon {
4
+ width;
5
+ height;
6
+ constructor(width = 2.0, height = 1.0) {
7
+ const halfW = width / 2;
8
+ const halfH = height / 2;
9
+ super([
10
+ new Vector2(-halfW, -halfH), // Top-Left
11
+ new Vector2(halfW, -halfH), // Top-Right
12
+ new Vector2(halfW, halfH), // Bottom-Right
13
+ new Vector2(-halfW, halfH) // Bottom-Left
14
+ ]);
15
+ this.width = width;
16
+ this.height = height;
17
+ }
18
+ }