@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,343 @@
1
+ import { Matrix3x3 } from '../core/math/matrix/Matrix3x3';
2
+ import { Vector2 } from '../core/math/Vector2/Vector2';
3
+ import { Animation } from '../core/animations/Animation';
4
+ import { FadeIn, FadeOut } from '../core/animations/fade';
5
+ import { MoveTo, Rotate, Scale } from '../core/animations/transform';
6
+ import { Parallel, Sequence } from '../core/animations/composition';
7
+ import { isPrebuilt } from '../core/animations/types';
8
+ /**
9
+ * Manages a queue of animations for fluent chaining.
10
+ * This is an internal implementation detail of Mobject's fluent API.
11
+ */
12
+ class AnimationQueue {
13
+ target;
14
+ queue = [];
15
+ constructor(target) {
16
+ this.target = target;
17
+ }
18
+ enqueueAnimation(animation) {
19
+ this.queue.push({ animation });
20
+ }
21
+ setLastDuration(seconds) {
22
+ if (seconds <= 0) {
23
+ throw new Error('Duration must be positive');
24
+ }
25
+ const last = this.queue[this.queue.length - 1];
26
+ if (!last)
27
+ return;
28
+ if (isPrebuilt(last)) {
29
+ last.animation.duration(seconds);
30
+ }
31
+ else {
32
+ last.config.durationSeconds = seconds;
33
+ }
34
+ }
35
+ setLastEasing(easing) {
36
+ const last = this.queue[this.queue.length - 1];
37
+ if (!last)
38
+ return;
39
+ if (isPrebuilt(last)) {
40
+ last.animation.ease(easing);
41
+ }
42
+ else {
43
+ last.config.easing = easing;
44
+ }
45
+ }
46
+ isEmpty() {
47
+ return this.queue.length === 0;
48
+ }
49
+ popLastAnimation() {
50
+ const last = this.queue.pop();
51
+ if (!last)
52
+ return null;
53
+ if (isPrebuilt(last)) {
54
+ return last.animation;
55
+ }
56
+ const anim = last.factory(this.target);
57
+ anim.duration(last.config.durationSeconds);
58
+ if (last.config.easing) {
59
+ anim.ease(last.config.easing);
60
+ }
61
+ if (last.config.delaySeconds !== undefined) {
62
+ anim.delay(last.config.delaySeconds);
63
+ }
64
+ return anim;
65
+ }
66
+ toAnimation() {
67
+ if (this.queue.length === 0) {
68
+ throw new Error('toAnimation() called with an empty animation queue.');
69
+ }
70
+ const animations = [];
71
+ for (const entry of this.queue) {
72
+ if (isPrebuilt(entry)) {
73
+ animations.push(entry.animation);
74
+ }
75
+ else {
76
+ const anim = entry.factory(this.target);
77
+ anim.duration(entry.config.durationSeconds);
78
+ if (entry.config.easing) {
79
+ anim.ease(entry.config.easing);
80
+ }
81
+ if (entry.config.delaySeconds !== undefined) {
82
+ anim.delay(entry.config.delaySeconds);
83
+ }
84
+ animations.push(anim);
85
+ }
86
+ }
87
+ this.queue.length = 0;
88
+ if (animations.length === 1 && animations[0]) {
89
+ return animations[0];
90
+ }
91
+ return new Sequence(animations);
92
+ }
93
+ getTotalDuration() {
94
+ let total = 0;
95
+ for (const entry of this.queue) {
96
+ if (isPrebuilt(entry)) {
97
+ total += entry.animation.getDuration() + entry.animation.getDelay();
98
+ }
99
+ else {
100
+ total += entry.config.durationSeconds;
101
+ if (entry.config.delaySeconds !== undefined) {
102
+ total += entry.config.delaySeconds;
103
+ }
104
+ }
105
+ }
106
+ return total;
107
+ }
108
+ }
109
+ /**
110
+ * Base class for all mathematical objects.
111
+ * Manages position, rotation, scale, and opacity via a local transformation matrix.
112
+ * Includes fluent animation API for chainable animations.
113
+ */
114
+ export class Mobject {
115
+ localMatrix;
116
+ opacityValue;
117
+ animQueue = null;
118
+ savedStates = [];
119
+ parent = null;
120
+ constructor() {
121
+ this.localMatrix = Matrix3x3.identity();
122
+ this.opacityValue = 0;
123
+ }
124
+ getQueue() {
125
+ if (!this.animQueue) {
126
+ this.animQueue = new AnimationQueue(this);
127
+ }
128
+ return this.animQueue;
129
+ }
130
+ // ========== Transform Properties ==========
131
+ get matrix() {
132
+ return this.localMatrix;
133
+ }
134
+ getWorldMatrix() {
135
+ if (this.parent === null) {
136
+ return this.localMatrix;
137
+ }
138
+ return this.parent.getWorldMatrix().multiply(this.localMatrix);
139
+ }
140
+ get position() {
141
+ const m = this.localMatrix.values;
142
+ return new Vector2(m[2], m[5]);
143
+ }
144
+ get rotation() {
145
+ const m = this.localMatrix.values;
146
+ return Math.atan2(m[3], m[0]);
147
+ }
148
+ get scale() {
149
+ const m = this.localMatrix.values;
150
+ const sx = Math.sqrt(m[0] * m[0] + m[3] * m[3]);
151
+ const sy = Math.sqrt(m[1] * m[1] + m[4] * m[4]);
152
+ return new Vector2(sx, sy);
153
+ }
154
+ get opacity() {
155
+ return this.opacityValue;
156
+ }
157
+ // ========== Immediate State Setters ==========
158
+ pos(x, y) {
159
+ const newValues = new Float32Array(this.localMatrix.values);
160
+ newValues[2] = x;
161
+ newValues[5] = y;
162
+ this.localMatrix = new Matrix3x3(newValues);
163
+ return this;
164
+ }
165
+ show() {
166
+ this.opacityValue = 1;
167
+ return this;
168
+ }
169
+ hide() {
170
+ this.opacityValue = 0;
171
+ return this;
172
+ }
173
+ setOpacity(value) {
174
+ this.opacityValue = Math.max(0, Math.min(1, value));
175
+ return this;
176
+ }
177
+ setRotation(angle) {
178
+ const m = this.localMatrix.values;
179
+ const posX = m[2];
180
+ const posY = m[5];
181
+ const currentScale = this.scale;
182
+ const cos = Math.cos(angle);
183
+ const sin = Math.sin(angle);
184
+ const newValues = new Float32Array(9);
185
+ newValues[0] = cos * currentScale.x;
186
+ newValues[1] = -sin * currentScale.y;
187
+ newValues[2] = posX;
188
+ newValues[3] = sin * currentScale.x;
189
+ newValues[4] = cos * currentScale.y;
190
+ newValues[5] = posY;
191
+ newValues[8] = 1;
192
+ this.localMatrix = new Matrix3x3(newValues);
193
+ return this;
194
+ }
195
+ setScale(sx, sy) {
196
+ const m = this.localMatrix.values;
197
+ const posX = m[2];
198
+ const posY = m[5];
199
+ const currentRotation = this.rotation;
200
+ const cos = Math.cos(currentRotation);
201
+ const sin = Math.sin(currentRotation);
202
+ const newValues = new Float32Array(9);
203
+ newValues[0] = cos * sx;
204
+ newValues[1] = -sin * sy;
205
+ newValues[2] = posX;
206
+ newValues[3] = sin * sx;
207
+ newValues[4] = cos * sy;
208
+ newValues[5] = posY;
209
+ newValues[8] = 1;
210
+ this.localMatrix = new Matrix3x3(newValues);
211
+ return this;
212
+ }
213
+ applyMatrix(m) {
214
+ this.localMatrix = m.multiply(this.localMatrix);
215
+ return this;
216
+ }
217
+ // ========== State Save/Restore ==========
218
+ saveState() {
219
+ const pos = this.position;
220
+ const scl = this.scale;
221
+ this.savedStates.push({
222
+ position: new Vector2(pos.x, pos.y),
223
+ scale: new Vector2(scl.x, scl.y),
224
+ rotation: this.rotation,
225
+ });
226
+ return this;
227
+ }
228
+ getSavedState() {
229
+ return this.savedStates[this.savedStates.length - 1];
230
+ }
231
+ clearSavedStates() {
232
+ this.savedStates = [];
233
+ return this;
234
+ }
235
+ /**
236
+ * Animates back to the last saved state.
237
+ * Pops the saved state from the stack.
238
+ * @throws Error if no state was previously saved
239
+ */
240
+ restore(durationSeconds) {
241
+ const state = this.savedStates.pop();
242
+ if (!state) {
243
+ throw new Error('restore() called but no state was saved. Call saveState() first.');
244
+ }
245
+ const moveAnim = new MoveTo(this, state.position.x, state.position.y);
246
+ const scaleAnim = new Scale(this, state.scale.x, state.scale.y);
247
+ const rotateAnim = new Rotate(this, state.rotation - this.rotation);
248
+ if (durationSeconds !== undefined) {
249
+ moveAnim.duration(durationSeconds);
250
+ scaleAnim.duration(durationSeconds);
251
+ rotateAnim.duration(durationSeconds);
252
+ }
253
+ const parallelAnim = new Parallel([moveAnim, scaleAnim, rotateAnim]);
254
+ this.getQueue().enqueueAnimation(parallelAnim);
255
+ return this;
256
+ }
257
+ // ========== Fluent Animation API ==========
258
+ createAnimation(animation, durationSeconds) {
259
+ if (durationSeconds !== undefined) {
260
+ animation.duration(durationSeconds);
261
+ }
262
+ return animation;
263
+ }
264
+ // ========== Unified Fluent Animation API ==========
265
+ // These methods work for both sequential chaining AND parallel usage
266
+ fadeIn(durationSeconds) {
267
+ const animation = this.createAnimation(new FadeIn(this), durationSeconds);
268
+ this.getQueue().enqueueAnimation(animation);
269
+ return this;
270
+ }
271
+ fadeOut(durationSeconds) {
272
+ const animation = this.createAnimation(new FadeOut(this), durationSeconds);
273
+ this.getQueue().enqueueAnimation(animation);
274
+ return this;
275
+ }
276
+ moveTo(x, y, durationSeconds) {
277
+ const animation = this.createAnimation(new MoveTo(this, x, y), durationSeconds);
278
+ this.getQueue().enqueueAnimation(animation);
279
+ return this;
280
+ }
281
+ rotate(angle, durationSeconds) {
282
+ const animation = this.createAnimation(new Rotate(this, angle), durationSeconds);
283
+ this.getQueue().enqueueAnimation(animation);
284
+ return this;
285
+ }
286
+ scaleTo(factor, durationSeconds) {
287
+ const animation = this.createAnimation(new Scale(this, factor), durationSeconds);
288
+ this.getQueue().enqueueAnimation(animation);
289
+ return this;
290
+ }
291
+ scaleToXY(factorX, factorY, durationSeconds) {
292
+ const animation = this.createAnimation(new Scale(this, factorX, factorY), durationSeconds);
293
+ this.getQueue().enqueueAnimation(animation);
294
+ return this;
295
+ }
296
+ duration(seconds) {
297
+ this.getQueue().setLastDuration(seconds);
298
+ return this;
299
+ }
300
+ ease(easing) {
301
+ this.getQueue().setLastEasing(easing);
302
+ return this;
303
+ }
304
+ toAnimation() {
305
+ return this.getQueue().toAnimation();
306
+ }
307
+ getQueuedDuration() {
308
+ return this.getQueue().getTotalDuration();
309
+ }
310
+ hasQueuedAnimations() {
311
+ return !this.getQueue().isEmpty();
312
+ }
313
+ /**
314
+ * Queues multiple animations to run in parallel (simultaneously).
315
+ * Automatically handles both Animation objects and mobject method calls.
316
+ * @example
317
+ * circle.fadeIn(1).parallel(
318
+ * circle.moveTo(100, 50),
319
+ * circle.rotate(Math.PI)
320
+ * ).fadeOut(1);
321
+ */
322
+ parallel(...items) {
323
+ if (items.length === 0) {
324
+ return this;
325
+ }
326
+ // Convert any mobjects to animations by extracting and removing their last queued animation
327
+ const animations = items.map(item => {
328
+ if (item instanceof Animation) {
329
+ return item;
330
+ }
331
+ else {
332
+ // item is a Mobject - pop its last queued animation (removes it to avoid double-counting)
333
+ const anim = item.getQueue().popLastAnimation();
334
+ if (!anim) {
335
+ throw new Error('No animation found on mobject for parallel execution');
336
+ }
337
+ return anim;
338
+ }
339
+ });
340
+ this.getQueue().enqueueAnimation(new Parallel(animations));
341
+ return this;
342
+ }
343
+ }
@@ -0,0 +1,51 @@
1
+ import { VMobject } from '../VMobject';
2
+ import { Color } from '../../core/math/color/Color';
3
+ import type { CornerPosition, Direction, Edge } from './layout';
4
+ /**
5
+ * A collection of VMobjects that can be manipulated as a single unit.
6
+ * Uses Scene Graph hierarchy: transforms on parent are inherited by children
7
+ * via getWorldMatrix() calculation, not by mutating child matrices.
8
+ */
9
+ export declare class VGroup extends VMobject {
10
+ protected children: VMobject[];
11
+ constructor(...mobjects: VMobject[]);
12
+ get length(): number;
13
+ add(...mobjects: VMobject[]): this;
14
+ remove(mobject: VMobject): this;
15
+ clear(): this;
16
+ getChildren(): VMobject[];
17
+ get(index: number): VMobject | undefined;
18
+ pos(x: number, y: number): this;
19
+ show(): this;
20
+ hide(): this;
21
+ /**
22
+ * Sets the opacity for this VGroup and all children.
23
+ * @param value - The opacity value (0-1).
24
+ * @returns this for chaining.
25
+ */
26
+ setOpacity(value: number): this;
27
+ /**
28
+ * Sets the stroke color and width for this VGroup and all children.
29
+ * @param color - The stroke color.
30
+ * @param width - The stroke width. Default is 2.
31
+ * @returns this for chaining.
32
+ */
33
+ stroke(color: Color, width?: number): this;
34
+ /**
35
+ * Sets the fill color and opacity for this VGroup and all children.
36
+ * @param color - The fill color.
37
+ * @param opacity - The fill opacity. Default is 1 (fully opaque).
38
+ * @returns this for chaining.
39
+ */
40
+ fill(color: Color, opacity?: number): this;
41
+ getBoundingBox(): {
42
+ minX: number;
43
+ maxX: number;
44
+ minY: number;
45
+ maxY: number;
46
+ };
47
+ center(): this;
48
+ toCorner(corner: CornerPosition, buff?: number): this;
49
+ arrange(direction?: Direction, buff?: number, shouldCenter?: boolean): this;
50
+ alignTo(target: VMobject, edge: Edge): this;
51
+ }
@@ -0,0 +1,142 @@
1
+ import { VMobject } from '../VMobject';
2
+ import { centerGroup, toCorner, arrangeChildren, alignToTarget } from './layout';
3
+ /**
4
+ * A collection of VMobjects that can be manipulated as a single unit.
5
+ * Uses Scene Graph hierarchy: transforms on parent are inherited by children
6
+ * via getWorldMatrix() calculation, not by mutating child matrices.
7
+ */
8
+ export class VGroup extends VMobject {
9
+ children = [];
10
+ constructor(...mobjects) {
11
+ super();
12
+ this.add(...mobjects);
13
+ }
14
+ get length() {
15
+ return this.children.length;
16
+ }
17
+ add(...mobjects) {
18
+ for (const mob of mobjects) {
19
+ if (!this.children.includes(mob)) {
20
+ mob.parent = this;
21
+ this.children.push(mob);
22
+ }
23
+ }
24
+ return this;
25
+ }
26
+ remove(mobject) {
27
+ const index = this.children.indexOf(mobject);
28
+ if (index > -1) {
29
+ mobject.parent = null;
30
+ this.children.splice(index, 1);
31
+ }
32
+ return this;
33
+ }
34
+ clear() {
35
+ for (const child of this.children) {
36
+ child.parent = null;
37
+ }
38
+ this.children = [];
39
+ return this;
40
+ }
41
+ getChildren() {
42
+ return [...this.children];
43
+ }
44
+ get(index) {
45
+ return this.children[index];
46
+ }
47
+ // Note: applyMatrix is NOT overridden - transforms stay on this group's local matrix.
48
+ // Children inherit via getWorldMatrix() during rendering.
49
+ pos(x, y) {
50
+ // Directly set position on local matrix, don't propagate to children
51
+ return super.pos(x, y);
52
+ }
53
+ show() {
54
+ super.show();
55
+ for (const child of this.children) {
56
+ child.show();
57
+ }
58
+ return this;
59
+ }
60
+ hide() {
61
+ super.hide();
62
+ for (const child of this.children) {
63
+ child.hide();
64
+ }
65
+ return this;
66
+ }
67
+ /**
68
+ * Sets the opacity for this VGroup and all children.
69
+ * @param value - The opacity value (0-1).
70
+ * @returns this for chaining.
71
+ */
72
+ setOpacity(value) {
73
+ super.setOpacity(value);
74
+ for (const child of this.children) {
75
+ child.setOpacity(value);
76
+ }
77
+ return this;
78
+ }
79
+ /**
80
+ * Sets the stroke color and width for this VGroup and all children.
81
+ * @param color - The stroke color.
82
+ * @param width - The stroke width. Default is 2.
83
+ * @returns this for chaining.
84
+ */
85
+ stroke(color, width = 2) {
86
+ super.stroke(color, width);
87
+ for (const child of this.children) {
88
+ child.stroke(color, width);
89
+ }
90
+ return this;
91
+ }
92
+ /**
93
+ * Sets the fill color and opacity for this VGroup and all children.
94
+ * @param color - The fill color.
95
+ * @param opacity - The fill opacity. Default is 1 (fully opaque).
96
+ * @returns this for chaining.
97
+ */
98
+ fill(color, opacity = 1) {
99
+ super.fill(color, opacity);
100
+ for (const child of this.children) {
101
+ child.fill(color, opacity);
102
+ }
103
+ return this;
104
+ }
105
+ getBoundingBox() {
106
+ if (this.children.length === 0) {
107
+ return super.getBoundingBox();
108
+ }
109
+ let minX = Infinity;
110
+ let maxX = -Infinity;
111
+ let minY = Infinity;
112
+ let maxY = -Infinity;
113
+ for (const child of this.children) {
114
+ const bounds = child.getBoundingBox();
115
+ if (bounds.minX < minX)
116
+ minX = bounds.minX;
117
+ if (bounds.maxX > maxX)
118
+ maxX = bounds.maxX;
119
+ if (bounds.minY < minY)
120
+ minY = bounds.minY;
121
+ if (bounds.maxY > maxY)
122
+ maxY = bounds.maxY;
123
+ }
124
+ return { minX, maxX, minY, maxY };
125
+ }
126
+ center() {
127
+ centerGroup(this);
128
+ return this;
129
+ }
130
+ toCorner(corner, buff = 0.0) {
131
+ toCorner(this, corner, buff);
132
+ return this;
133
+ }
134
+ arrange(direction = 'RIGHT', buff = 0.25, shouldCenter = true) {
135
+ arrangeChildren(this, direction, buff, shouldCenter);
136
+ return this;
137
+ }
138
+ alignTo(target, edge) {
139
+ alignToTarget(this, target, edge);
140
+ return this;
141
+ }
142
+ }
@@ -0,0 +1,3 @@
1
+ export { VGroup } from './VGroup';
2
+ export { centerGroup, toCorner, arrangeChildren, alignToTarget } from './layout';
3
+ export type { CornerPosition, Direction, Edge } from './layout';
@@ -0,0 +1,2 @@
1
+ export { VGroup } from './VGroup';
2
+ export { centerGroup, toCorner, arrangeChildren, alignToTarget } from './layout';
@@ -0,0 +1,20 @@
1
+ import { VGroup } from './VGroup';
2
+ import { VMobject } from '../VMobject';
3
+ import { Camera } from '../../core/camera';
4
+ export type CornerPosition = 'TOP_LEFT' | 'TOP_RIGHT' | 'BOTTOM_LEFT' | 'BOTTOM_RIGHT';
5
+ export type Direction = 'RIGHT' | 'LEFT' | 'UP' | 'DOWN';
6
+ export type Edge = 'TOP' | 'BOTTOM' | 'LEFT' | 'RIGHT';
7
+ /** Centers a VGroup's bounding box at the origin (0, 0). */
8
+ export declare function centerGroup(group: VGroup): VGroup;
9
+ /**
10
+ * Moves a VGroup's bounding box to a corner of the frame.
11
+ * @param group The VGroup to position
12
+ * @param corner Which corner to move to
13
+ * @param buff Buffer/margin from the corner
14
+ * @param camera Camera providing frame dimensions (defaults to 1920x1080)
15
+ */
16
+ export declare function toCorner(group: VGroup, corner: CornerPosition, buff?: number, camera?: Camera): VGroup;
17
+ /** Arranges children in a line along the specified direction. */
18
+ export declare function arrangeChildren(group: VGroup, direction?: Direction, buff?: number, shouldCenter?: boolean): VGroup;
19
+ /** Aligns a VGroup to a target VMobject's edge. */
20
+ export declare function alignToTarget(group: VGroup, target: VMobject, edge: Edge): VGroup;