@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,322 @@
1
+ import { Mobject } from '../../mobjects/Mobject';
2
+ import { Parallel } from '../animations/composition';
3
+ import { MANIM_FRAME_HEIGHT } from './types';
4
+ /**
5
+ * CameraFrame represents the viewport window in world space.
6
+ * Extends Mobject (not VMobject - no visual representation).
7
+ * Its transform properties define what the camera shows:
8
+ * - scale(2) = zoom OUT (larger frame = see more)
9
+ * - scale(0.5) = zoom IN (smaller frame = see less)
10
+ *
11
+ * The CameraFrame is the primary way to control camera animations in Anima.
12
+ * Access it via `scene.frame` or `scene.camera.frame`.
13
+ *
14
+ * @example
15
+ * // Zoom in over 1 second
16
+ * this.play(this.frame.zoomIn(2).duration(1));
17
+ *
18
+ * @example
19
+ * // Pan to center on an object
20
+ * this.play(this.frame.centerOn(circle).duration(0.5));
21
+ *
22
+ * @example
23
+ * // Fit multiple objects in view
24
+ * this.play(this.frame.fitTo([obj1, obj2, obj3]).duration(1));
25
+ */
26
+ export class CameraFrame extends Mobject {
27
+ baseWidth;
28
+ baseHeight = MANIM_FRAME_HEIGHT;
29
+ bounds;
30
+ /**
31
+ * Creates a new CameraFrame with the specified viewport dimensions.
32
+ *
33
+ * @param config - Configuration options
34
+ * @param config.pixelWidth - Width of the viewport in pixels (default: 1920)
35
+ * @param config.pixelHeight - Height of the viewport in pixels (default: 1080)
36
+ *
37
+ * @example
38
+ * const frame = new CameraFrame({ pixelWidth: 1920, pixelHeight: 1080 });
39
+ */
40
+ constructor(config = {}) {
41
+ super();
42
+ const pixelWidth = config.pixelWidth ?? 1920;
43
+ const pixelHeight = config.pixelHeight ?? 1080;
44
+ this.baseWidth = this.baseHeight * (pixelWidth / pixelHeight);
45
+ this.setOpacity(1);
46
+ }
47
+ /**
48
+ * The current width of the frame in world units, accounting for scale.
49
+ * @returns The frame width multiplied by the current scale.x
50
+ */
51
+ get width() {
52
+ return this.baseWidth * this.scale.x;
53
+ }
54
+ /**
55
+ * The current height of the frame in world units, accounting for scale.
56
+ * @returns The frame height multiplied by the current scale.y
57
+ */
58
+ get height() {
59
+ return this.baseHeight * this.scale.y;
60
+ }
61
+ /**
62
+ * Sets the scale of the camera frame.
63
+ * Overrides Mobject.setScale to prevent zero or negative scales.
64
+ *
65
+ * @param sx - Scale factor for the x-axis (must be positive)
66
+ * @param sy - Scale factor for the y-axis (must be positive)
67
+ * @returns This CameraFrame for method chaining
68
+ * @throws Error if sx or sy is zero or negative
69
+ *
70
+ * @example
71
+ * frame.setScale(2, 2); // Zoom out 2x
72
+ * frame.setScale(0.5, 0.5); // Zoom in 2x
73
+ */
74
+ setScale(sx, sy) {
75
+ if (sx <= 0 || sy <= 0) {
76
+ throw new Error('CameraFrame scale must be positive to prevent division by zero');
77
+ }
78
+ return super.setScale(sx, sy);
79
+ }
80
+ /**
81
+ * Sets bounds that limit how far the camera can pan.
82
+ * When bounds are set, the camera position is clamped to stay within them,
83
+ * accounting for the frame size so edges don't go outside bounds.
84
+ *
85
+ * @param minX - Minimum x coordinate
86
+ * @param minY - Minimum y coordinate
87
+ * @param maxX - Maximum x coordinate
88
+ * @param maxY - Maximum y coordinate
89
+ * @returns This CameraFrame for method chaining
90
+ *
91
+ * @example
92
+ * // Limit camera to a 100x100 world area
93
+ * frame.setBounds(0, 0, 100, 100);
94
+ */
95
+ setBounds(minX, minY, maxX, maxY) {
96
+ this.bounds = { minX, maxX, minY, maxY };
97
+ return this;
98
+ }
99
+ /**
100
+ * Removes any bounds restrictions on camera movement.
101
+ *
102
+ * @returns This CameraFrame for method chaining
103
+ *
104
+ * @example
105
+ * frame.clearBounds(); // Camera can now pan freely
106
+ */
107
+ clearBounds() {
108
+ this.bounds = undefined;
109
+ return this;
110
+ }
111
+ /**
112
+ * Checks if the camera has bounds set.
113
+ *
114
+ * @returns True if bounds are set, false otherwise
115
+ */
116
+ hasBounds() {
117
+ return this.bounds !== undefined;
118
+ }
119
+ /**
120
+ * Gets the current bounds configuration.
121
+ *
122
+ * @returns The bounds object or undefined if no bounds are set
123
+ */
124
+ getBounds() {
125
+ return this.bounds;
126
+ }
127
+ /**
128
+ * Sets the position of the camera frame.
129
+ * Overrides Mobject.pos to clamp position within bounds if set.
130
+ *
131
+ * @param x - The x coordinate in world space
132
+ * @param y - The y coordinate in world space
133
+ * @returns This CameraFrame for method chaining
134
+ *
135
+ * @example
136
+ * frame.pos(5, 3); // Move camera center to (5, 3)
137
+ */
138
+ pos(x, y) {
139
+ if (this.bounds) {
140
+ const halfWidth = this.width / 2;
141
+ const halfHeight = this.height / 2;
142
+ const clampedX = Math.max(this.bounds.minX + halfWidth, Math.min(this.bounds.maxX - halfWidth, x));
143
+ const clampedY = Math.max(this.bounds.minY + halfHeight, Math.min(this.bounds.maxY - halfHeight, y));
144
+ return super.pos(clampedX, clampedY);
145
+ }
146
+ return super.pos(x, y);
147
+ }
148
+ // ========== Camera-Specific FluentAPI Methods ==========
149
+ /**
150
+ * Smoothly zoom the camera in by the given factor.
151
+ * Internally scales the frame down, which makes objects appear larger.
152
+ *
153
+ * @param factor - Zoom multiplier. 2 = objects appear 2x larger (default: 2)
154
+ * @returns FluentAnimation that can be chained with .duration() and .ease()
155
+ * @throws Error if factor is zero or negative
156
+ *
157
+ * @example
158
+ * // Zoom in 2x over 1 second
159
+ * this.play(this.frame.zoomIn(2).duration(1));
160
+ *
161
+ * @example
162
+ * // Zoom in 3x with easing
163
+ * this.play(this.frame.zoomIn(3).duration(1.5).ease(easeInOutQuad));
164
+ */
165
+ zoomIn(factor = 2) {
166
+ if (factor <= 0) {
167
+ throw new Error('zoom factor must be positive');
168
+ }
169
+ return this.scaleTo(1 / factor);
170
+ }
171
+ /**
172
+ * Smoothly zoom the camera out by the given factor.
173
+ * Internally scales the frame up, which makes objects appear smaller.
174
+ *
175
+ * @param factor - Zoom multiplier. 2 = objects appear 2x smaller (default: 2)
176
+ * @returns FluentAnimation that can be chained with .duration() and .ease()
177
+ * @throws Error if factor is zero or negative
178
+ *
179
+ * @example
180
+ * // Zoom out 2x over 1 second
181
+ * this.play(this.frame.zoomOut(2).duration(1));
182
+ *
183
+ * @example
184
+ * // Zoom out to show more of the scene
185
+ * this.play(this.frame.zoomOut(4).duration(2).ease(easeOutCubic));
186
+ */
187
+ zoomOut(factor = 2) {
188
+ if (factor <= 0) {
189
+ throw new Error('zoom factor must be positive');
190
+ }
191
+ return this.scaleTo(factor);
192
+ }
193
+ /**
194
+ * Move the camera to center on a target Mobject.
195
+ * The camera will smoothly pan so the target is at the center of the frame.
196
+ *
197
+ * @param target - The Mobject to center on
198
+ * @returns FluentAnimation that can be chained with .duration() and .ease()
199
+ * @throws Error if target is null or undefined
200
+ *
201
+ * @example
202
+ * // Center on a circle over 0.5 seconds
203
+ * this.play(this.frame.centerOn(circle).duration(0.5));
204
+ *
205
+ * @example
206
+ * // Pan to focus on different objects in sequence
207
+ * await this.play(this.frame.centerOn(obj1).duration(1));
208
+ * await this.play(this.frame.centerOn(obj2).duration(1));
209
+ */
210
+ centerOn(target) {
211
+ if (!target) {
212
+ throw new Error('centerOn() requires a Mobject target, but received null or undefined');
213
+ }
214
+ return this.moveTo(target.position.x, target.position.y);
215
+ }
216
+ /**
217
+ * Zoom in/out while keeping a specific world point fixed on screen.
218
+ * Like pinch-to-zoom behavior where the pinch point stays stationary.
219
+ *
220
+ * Uses the formula: C' = P * (1 - factor) + C * factor
221
+ * Where P = point, C = current center, factor = zoom factor.
222
+ *
223
+ * @param factor - Scale multiplier. Less than 1 for zoom in, greater than 1 for zoom out
224
+ * @param point - World coordinates to keep fixed on screen
225
+ * @returns Parallel animation combining move and scale
226
+ * @throws Error if factor is zero or negative
227
+ *
228
+ * @example
229
+ * // Zoom in 2x on a specific point
230
+ * this.play(frame.zoomToPoint(0.5, { x: 5, y: 5 }).duration(1));
231
+ *
232
+ * @example
233
+ * // Zoom out while keeping an object's position fixed
234
+ * this.play(frame.zoomToPoint(2, circle.position).duration(1));
235
+ */
236
+ zoomToPoint(factor, point) {
237
+ if (factor <= 0) {
238
+ throw new Error('zoom factor must be positive');
239
+ }
240
+ const currentX = this.position.x;
241
+ const currentY = this.position.y;
242
+ const currentScale = this.scale.x;
243
+ const newX = point.x * (1 - factor) + currentX * factor;
244
+ const newY = point.y * (1 - factor) + currentY * factor;
245
+ const newScale = currentScale * factor;
246
+ const moveAnim = this.moveTo(newX, newY).toAnimation();
247
+ const scaleAnim = this.scaleTo(newScale).toAnimation();
248
+ return new Parallel([moveAnim, scaleAnim]);
249
+ }
250
+ /**
251
+ * Automatically frame one or more objects with optional margin.
252
+ * Calculates the bounding box of all targets and animates the camera
253
+ * to show them all with the specified margin around them.
254
+ *
255
+ * @param targets - Single Mobject or array of Mobjects to frame
256
+ * @param margin - Padding around the objects in world units (default: 0.5)
257
+ * @returns FluentAnimation that can be chained with .duration() and .ease()
258
+ * @throws Error if targets array is empty
259
+ *
260
+ * @example
261
+ * // Fit a single object with default margin
262
+ * this.play(this.frame.fitTo(circle).duration(1));
263
+ *
264
+ * @example
265
+ * // Fit multiple objects with custom margin
266
+ * this.play(this.frame.fitTo([obj1, obj2, obj3], 1.0).duration(1.5));
267
+ *
268
+ * @example
269
+ * // Show all objects in the scene
270
+ * this.play(this.frame.fitTo(allObjects, 0).duration(2));
271
+ */
272
+ fitTo(targets, margin = 0.5) {
273
+ const targetArray = Array.isArray(targets) ? targets : [targets];
274
+ if (targetArray.length === 0) {
275
+ throw new Error('fitTo() requires at least one target');
276
+ }
277
+ const bounds = this.calculateBounds(targetArray);
278
+ const requiredWidth = bounds.width + margin * 2;
279
+ const requiredHeight = bounds.height + margin * 2;
280
+ const scaleX = requiredWidth / this.baseWidth;
281
+ const scaleY = requiredHeight / this.baseHeight;
282
+ let targetScale = Math.max(scaleX, scaleY);
283
+ if (targetScale < 1) {
284
+ targetScale = 1;
285
+ }
286
+ const moveAnim = this.moveTo(bounds.centerX, bounds.centerY).toAnimation();
287
+ const scaleAnim = this.scaleTo(targetScale).toAnimation();
288
+ const parallelAnim = new Parallel([moveAnim, scaleAnim]);
289
+ this.getQueue().enqueueAnimation(parallelAnim);
290
+ return this;
291
+ }
292
+ calculateBounds(targets) {
293
+ let minX = Infinity;
294
+ let maxX = -Infinity;
295
+ let minY = Infinity;
296
+ let maxY = -Infinity;
297
+ for (const target of targets) {
298
+ if (this.hasGetBoundingBox(target)) {
299
+ const box = target.getBoundingBox();
300
+ minX = Math.min(minX, box.minX);
301
+ maxX = Math.max(maxX, box.maxX);
302
+ minY = Math.min(minY, box.minY);
303
+ maxY = Math.max(maxY, box.maxY);
304
+ }
305
+ else {
306
+ const pos = target.position;
307
+ minX = Math.min(minX, pos.x);
308
+ maxX = Math.max(maxX, pos.x);
309
+ minY = Math.min(minY, pos.y);
310
+ maxY = Math.max(maxY, pos.y);
311
+ }
312
+ }
313
+ const width = maxX - minX;
314
+ const height = maxY - minY;
315
+ const centerX = (minX + maxX) / 2;
316
+ const centerY = (minY + maxY) / 2;
317
+ return { minX, maxX, minY, maxY, width, height, centerX, centerY };
318
+ }
319
+ hasGetBoundingBox(obj) {
320
+ return typeof obj.getBoundingBox === 'function';
321
+ }
322
+ }
@@ -0,0 +1,4 @@
1
+ export { Camera } from './Camera';
2
+ export { CameraFrame } from './CameraFrame';
3
+ export { MANIM_FRAME_HEIGHT } from './types';
4
+ export type { CameraConfig, ResolvedCameraConfig } from './types';
@@ -0,0 +1,3 @@
1
+ export { Camera } from './Camera';
2
+ export { CameraFrame } from './CameraFrame';
3
+ export { MANIM_FRAME_HEIGHT } from './types';
@@ -0,0 +1,17 @@
1
+ export declare const MANIM_FRAME_HEIGHT = 8;
2
+ /**
3
+ * Configuration options for Camera.
4
+ */
5
+ export interface CameraConfig {
6
+ /** Pixel width for aspect ratio calculation. Default: 1920 */
7
+ readonly pixelWidth?: number;
8
+ /** Pixel height for aspect ratio calculation. Default: 1080 */
9
+ readonly pixelHeight?: number;
10
+ }
11
+ /**
12
+ * Resolved camera configuration with all defaults applied.
13
+ */
14
+ export interface ResolvedCameraConfig {
15
+ readonly pixelWidth: number;
16
+ readonly pixelHeight: number;
17
+ }
@@ -0,0 +1 @@
1
+ export const MANIM_FRAME_HEIGHT = 8.0;
@@ -0,0 +1,12 @@
1
+ import type { Animation } from '../animations/Animation';
2
+ import type { Mobject } from '../../mobjects/Mobject';
3
+ /**
4
+ * Error thrown when an animation is applied to an object that is not in the scene.
5
+ * This typically happens when using transformative animations (MoveTo, Rotate, Scale)
6
+ * without first adding the object to the scene or using an introductory animation.
7
+ */
8
+ export declare class AnimationTargetNotInSceneError extends Error {
9
+ readonly animationName: string;
10
+ readonly targetType: string;
11
+ constructor(animation: Animation, target: Mobject);
12
+ }
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Error thrown when an animation is applied to an object that is not in the scene.
3
+ * This typically happens when using transformative animations (MoveTo, Rotate, Scale)
4
+ * without first adding the object to the scene or using an introductory animation.
5
+ */
6
+ export class AnimationTargetNotInSceneError extends Error {
7
+ animationName;
8
+ targetType;
9
+ constructor(animation, target) {
10
+ const animName = animation.constructor.name;
11
+ const targetType = target.constructor.name;
12
+ super(`Cannot apply '${animName}' animation to ${targetType}: target is not in scene.\n` +
13
+ `\n` +
14
+ `This animation requires the target to already exist in the scene ` +
15
+ `because it transforms an existing object rather than introducing a new one.\n` +
16
+ `\n` +
17
+ `Solutions:\n` +
18
+ ` 1. Call scene.add(target) before this animation\n` +
19
+ ` 2. Use an introductory animation first:\n` +
20
+ ` - FadeIn: Fades the object in from transparent\n` +
21
+ ` - Create: Draws the object's path progressively\n` +
22
+ ` - Draw: Draws border then fills\n` +
23
+ ` - Write: Draws text progressively\n` +
24
+ `\n` +
25
+ `Example:\n` +
26
+ ` // Option 1: Use add() for immediate visibility\n` +
27
+ ` scene.add(circle);\n` +
28
+ ` scene.play(new MoveTo(circle, 2, 0));\n` +
29
+ `\n` +
30
+ ` // Option 2: Use introductory animation\n` +
31
+ ` scene.play(new FadeIn(circle));\n` +
32
+ ` scene.play(new MoveTo(circle, 2, 0));`);
33
+ this.name = 'AnimationTargetNotInSceneError';
34
+ this.animationName = animName;
35
+ this.targetType = targetType;
36
+ }
37
+ }
@@ -0,0 +1 @@
1
+ export { AnimationTargetNotInSceneError } from './AnimationErrors';
@@ -0,0 +1 @@
1
+ export { AnimationTargetNotInSceneError } from './AnimationErrors';
@@ -0,0 +1,23 @@
1
+ /**
2
+ * A 2D vector class representing a point or direction in 2D space.
3
+ */
4
+ export declare class Vector2 {
5
+ readonly x: number;
6
+ readonly y: number;
7
+ constructor(x: number, y: number);
8
+ add(other: Vector2): Vector2;
9
+ subtract(other: Vector2): Vector2;
10
+ multiply(scalar: number): Vector2;
11
+ dot(other: Vector2): number;
12
+ /** Magnitude (length) of the vector. */
13
+ length(): number;
14
+ /** Returns a normalized unit vector. Returns ZERO for zero-length vectors. */
15
+ normalize(): Vector2;
16
+ lerp(other: Vector2, t: number): Vector2;
17
+ equals(other: Vector2, tolerance?: number): boolean;
18
+ static readonly ZERO: Vector2;
19
+ static readonly UP: Vector2;
20
+ static readonly DOWN: Vector2;
21
+ static readonly LEFT: Vector2;
22
+ static readonly RIGHT: Vector2;
23
+ }
@@ -0,0 +1,46 @@
1
+ /**
2
+ * A 2D vector class representing a point or direction in 2D space.
3
+ */
4
+ export class Vector2 {
5
+ x;
6
+ y;
7
+ constructor(x, y) {
8
+ this.x = x;
9
+ this.y = y;
10
+ }
11
+ add(other) {
12
+ return new Vector2(this.x + other.x, this.y + other.y);
13
+ }
14
+ subtract(other) {
15
+ return new Vector2(this.x - other.x, this.y - other.y);
16
+ }
17
+ multiply(scalar) {
18
+ return new Vector2(this.x * scalar, this.y * scalar);
19
+ }
20
+ dot(other) {
21
+ return this.x * other.x + this.y * other.y;
22
+ }
23
+ /** Magnitude (length) of the vector. */
24
+ length() {
25
+ return Math.sqrt(this.x * this.x + this.y * this.y);
26
+ }
27
+ /** Returns a normalized unit vector. Returns ZERO for zero-length vectors. */
28
+ normalize() {
29
+ const len = this.length();
30
+ if (len === 0) {
31
+ return Vector2.ZERO;
32
+ }
33
+ return this.multiply(1 / len);
34
+ }
35
+ lerp(other, t) {
36
+ return this.multiply(1 - t).add(other.multiply(t));
37
+ }
38
+ equals(other, tolerance = 1e-6) {
39
+ return Math.abs(this.x - other.x) < tolerance && Math.abs(this.y - other.y) < tolerance;
40
+ }
41
+ static ZERO = new Vector2(0, 0);
42
+ static UP = new Vector2(0, -1);
43
+ static DOWN = new Vector2(0, 1);
44
+ static LEFT = new Vector2(-1, 0);
45
+ static RIGHT = new Vector2(1, 0);
46
+ }
@@ -0,0 +1 @@
1
+ export { Vector2 } from './Vector2';
@@ -0,0 +1 @@
1
+ export { Vector2 } from './Vector2';
@@ -0,0 +1,38 @@
1
+ import { Vector2 } from '../Vector2/Vector2';
2
+ import type { PathCommand } from './types';
3
+ /**
4
+ * A class representing a Bezier path, capable of storing standard path commands
5
+ * (move, line, quadratic curve, cubic curve, close).
6
+ */
7
+ export declare class BezierPath {
8
+ private commands;
9
+ private currentPoint;
10
+ private startPoint;
11
+ private cachedLength;
12
+ private segmentLengths;
13
+ private segmentCDF;
14
+ /** Invalidates the cached length data. Called after any path modification. */
15
+ private invalidateCache;
16
+ /** Builds the cache if not already valid. */
17
+ private ensureCache;
18
+ /** Starts a new subpath at the specified point. */
19
+ moveTo(point: Vector2): void;
20
+ lineTo(point: Vector2): void;
21
+ quadraticTo(control: Vector2, end: Vector2): void;
22
+ cubicTo(control1: Vector2, control2: Vector2, end: Vector2): void;
23
+ closePath(): void;
24
+ getCommands(): PathCommand[];
25
+ getLength(): number;
26
+ /** Returns the point on the path at the normalized position t (0-1). */
27
+ getPointAt(t: number): Vector2;
28
+ getTangentAt(t: number): Vector2;
29
+ getPoints(count: number): Vector2[];
30
+ getPointCount(): number;
31
+ clone(): BezierPath;
32
+ /** Returns a new BezierPath where all segments are converted to Cubic curves. */
33
+ toCubic(): BezierPath;
34
+ static interpolate(path1: BezierPath, path2: BezierPath, t: number): BezierPath;
35
+ /** Matches the number of points/commands in two paths for morphing. */
36
+ static matchPoints(path1: BezierPath, path2: BezierPath): [BezierPath, BezierPath];
37
+ private static fromCommands;
38
+ }