@redwilly/anima 0.1.23 → 0.1.25

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.
package/dist/index.d.ts CHANGED
@@ -1,34 +1,4 @@
1
1
  import { Glyph as Glyph$1 } from 'fontkit';
2
- import { Canvas } from '@napi-rs/canvas';
3
-
4
- /**
5
- * A class representing a color with Red, Green, Blue, and Alpha components.
6
- * RGB values are in the range [0, 255].
7
- * Alpha value is in the range [0, 1].
8
- */
9
- declare class Color {
10
- readonly r: number;
11
- readonly g: number;
12
- readonly b: number;
13
- readonly a: number;
14
- constructor(r: number, g: number, b: number, a?: number);
15
- /**
16
- * Creates a Color from a hex string.
17
- * Supports formats: #RRGGBB, #RGB, #RRGGBBAA, #RGBA.
18
- */
19
- static fromHex(hex: string): Color;
20
- static fromHSL(h: number, s: number, l: number, a?: number): Color;
21
- toHex(): string;
22
- toRGBA(): string;
23
- lerp(other: Color, t: number): Color;
24
- static readonly WHITE: Color;
25
- static readonly BLACK: Color;
26
- static readonly RED: Color;
27
- static readonly GREEN: Color;
28
- static readonly BLUE: Color;
29
- static readonly YELLOW: Color;
30
- static readonly TRANSPARENT: Color;
31
- }
32
2
 
33
3
  /**
34
4
  * A 2D vector class representing a point or direction in 2D space.
@@ -77,6 +47,80 @@ declare class Matrix3x3 {
77
47
  static readonly IDENTITY: Matrix3x3;
78
48
  }
79
49
 
50
+ /**
51
+ * A class representing a color with Red, Green, Blue, and Alpha components.
52
+ * RGB values are in the range [0, 255].
53
+ * Alpha value is in the range [0, 1].
54
+ */
55
+ declare class Color {
56
+ readonly r: number;
57
+ readonly g: number;
58
+ readonly b: number;
59
+ readonly a: number;
60
+ constructor(r: number, g: number, b: number, a?: number);
61
+ /**
62
+ * Creates a Color from a hex string.
63
+ * Supports formats: #RRGGBB, #RGB, #RRGGBBAA, #RGBA.
64
+ */
65
+ static fromHex(hex: string): Color;
66
+ static fromHSL(h: number, s: number, l: number, a?: number): Color;
67
+ toHex(): string;
68
+ toRGBA(): string;
69
+ lerp(other: Color, t: number): Color;
70
+ static readonly WHITE: Color;
71
+ static readonly BLACK: Color;
72
+ static readonly RED: Color;
73
+ static readonly GREEN: Color;
74
+ static readonly BLUE: Color;
75
+ static readonly YELLOW: Color;
76
+ static readonly TRANSPARENT: Color;
77
+ }
78
+
79
+ type PathCommandType = 'Move' | 'Line' | 'Quadratic' | 'Cubic' | 'Close';
80
+ interface PathCommand {
81
+ type: PathCommandType;
82
+ end: Vector2;
83
+ control1?: Vector2;
84
+ control2?: Vector2;
85
+ }
86
+
87
+ /**
88
+ * A class representing a Bezier path, capable of storing standard path commands
89
+ * (move, line, quadratic curve, cubic curve, close).
90
+ */
91
+ declare class BezierPath {
92
+ private commands;
93
+ private currentPoint;
94
+ private startPoint;
95
+ private cachedLength;
96
+ private segmentLengths;
97
+ private segmentCDF;
98
+ /** Invalidates the cached length data. Called after any path modification. */
99
+ private invalidateCache;
100
+ /** Builds the cache if not already valid. */
101
+ private ensureCache;
102
+ /** Starts a new subpath at the specified point. */
103
+ moveTo(point: Vector2): void;
104
+ lineTo(point: Vector2): void;
105
+ quadraticTo(control: Vector2, end: Vector2): void;
106
+ cubicTo(control1: Vector2, control2: Vector2, end: Vector2): void;
107
+ closePath(): void;
108
+ getCommands(): PathCommand[];
109
+ getLength(): number;
110
+ /** Returns the point on the path at the normalized position t (0-1). */
111
+ getPointAt(t: number): Vector2;
112
+ getTangentAt(t: number): Vector2;
113
+ getPoints(count: number): Vector2[];
114
+ getPointCount(): number;
115
+ clone(): BezierPath;
116
+ /** Returns a new BezierPath where all segments are converted to Cubic curves. */
117
+ toCubic(): BezierPath;
118
+ static interpolate(path1: BezierPath, path2: BezierPath, t: number): BezierPath;
119
+ /** Matches the number of points/commands in two paths for morphing. */
120
+ static matchPoints(path1: BezierPath, path2: BezierPath): [BezierPath, BezierPath];
121
+ private static fromCommands;
122
+ }
123
+
80
124
  /**
81
125
  * Type signature for an easing function.
82
126
  * Maps a progress value t ∈ [0, 1] to an eased value.
@@ -264,107 +308,6 @@ declare function unregisterEasing(name: string): boolean;
264
308
  /** Clears all registered custom easings (useful for testing). */
265
309
  declare function clearRegistry(): void;
266
310
 
267
- /**
268
- * Manages a queue of animations for fluent chaining.
269
- * This is an internal implementation detail of Mobject's fluent API.
270
- */
271
- declare class AnimationQueue {
272
- private readonly target;
273
- private readonly queue;
274
- constructor(target: Mobject);
275
- enqueueAnimation(animation: Animation<Mobject>): void;
276
- setLastDuration(seconds: number): void;
277
- setLastEasing(easing: EasingFunction): void;
278
- setLastDelay(seconds: number): void;
279
- isEmpty(): boolean;
280
- popLastAnimation(): Animation<Mobject> | null;
281
- toAnimation(): Animation<Mobject>;
282
- getTotalDuration(): number;
283
- }
284
- interface MobjectState {
285
- position: Vector2;
286
- scale: Vector2;
287
- rotation: number;
288
- }
289
- /**
290
- * Base class for all mathematical objects.
291
- * Manages position, rotation, scale, and opacity via a local transformation matrix.
292
- * Includes fluent animation API for chainable animations.
293
- */
294
- declare class Mobject {
295
- protected localMatrix: Matrix3x3;
296
- protected opacityValue: number;
297
- protected animQueue: AnimationQueue | null;
298
- private savedStates;
299
- parent: Mobject | null;
300
- constructor();
301
- protected getQueue(): AnimationQueue;
302
- get matrix(): Matrix3x3;
303
- getWorldMatrix(): Matrix3x3;
304
- get position(): Vector2;
305
- get rotation(): number;
306
- get scale(): Vector2;
307
- get opacity(): number;
308
- pos(x: number, y: number): this;
309
- show(): this;
310
- hide(): this;
311
- setOpacity(value: number): this;
312
- setRotation(angle: number): this;
313
- setScale(sx: number, sy: number): this;
314
- applyMatrix(m: Matrix3x3): this;
315
- saveState(): this;
316
- getSavedState(): MobjectState | undefined;
317
- clearSavedStates(): this;
318
- /**
319
- * Animates back to the last saved state.
320
- * Pops the saved state from the stack.
321
- * @throws Error if no state was previously saved
322
- */
323
- restore(durationSeconds?: number): this & {
324
- toAnimation(): Animation<Mobject>;
325
- };
326
- private createAnimation;
327
- fadeIn(durationSeconds?: number): this & {
328
- toAnimation(): Animation<Mobject>;
329
- };
330
- fadeOut(durationSeconds?: number): this & {
331
- toAnimation(): Animation<Mobject>;
332
- };
333
- moveTo(x: number, y: number, durationSeconds?: number): this & {
334
- toAnimation(): Animation<Mobject>;
335
- };
336
- rotate(angle: number, durationSeconds?: number): this & {
337
- toAnimation(): Animation<Mobject>;
338
- };
339
- scaleTo(factor: number, durationSeconds?: number): this & {
340
- toAnimation(): Animation<Mobject>;
341
- };
342
- scaleToXY(factorX: number, factorY: number, durationSeconds?: number): this & {
343
- toAnimation(): Animation<Mobject>;
344
- };
345
- duration(seconds: number): this;
346
- ease(easing: EasingFunction): this;
347
- delay(seconds: number): this;
348
- toAnimation(): Animation<Mobject>;
349
- getQueuedDuration(): number;
350
- hasQueuedAnimations(): boolean;
351
- /**
352
- * Queues multiple animations to run in parallel (simultaneously).
353
- * Automatically handles both Animation objects and mobject method calls.
354
- * @example
355
- * circle.fadeIn(1).parallel(
356
- * circle.moveTo(100, 50),
357
- * circle.rotate(Math.PI)
358
- * ).fadeOut(1);
359
- */
360
- parallel(...items: (Animation<Mobject> | Mobject)[]): this;
361
- /**
362
- * Computes a CRC32 hash of this mobject's full state.
363
- * Used by the segment cache to detect changes.
364
- */
365
- computeHash(): number;
366
- }
367
-
368
311
  /**
369
312
  * Configuration options for animations.
370
313
  */
@@ -385,134 +328,38 @@ interface AnimationConfig {
385
328
  type AnimationLifecycle = 'introductory' | 'transformative' | 'exit';
386
329
 
387
330
  /**
388
- * Abstract base class for all animations.
389
- * Provides configuration for duration, easing, and delay.
390
- * Subclasses must specify their lifecycle category.
331
+ * Executes animations in parallel, all starting at the same time.
332
+ * Total duration equals the maximum of all child animation durations.
333
+ *
334
+ * This is a composition animation - its lifecycle is determined by its children.
335
+ * By default, uses 'transformative' lifecycle if children are mixed.
336
+ *
337
+ * All children are initialized together before any interpolation begins,
338
+ * ensuring they all capture state at the same moment.
391
339
  */
392
- declare abstract class Animation<T extends Mobject = Mobject> {
393
- protected readonly target: T;
394
- protected durationSeconds: number;
395
- protected easingFn: EasingFunction;
396
- protected delaySeconds: number;
340
+ declare class Parallel extends Animation<Mobject> {
341
+ private readonly children;
342
+ private readonly maxChildDuration;
397
343
  /**
398
- * The lifecycle category of this animation.
399
- * Determines how Scene.play() handles scene registration and validation.
344
+ * The lifecycle of Parallel is 'introductory' only if ALL children are introductory.
345
+ * Otherwise, it defaults to 'transformative'.
400
346
  */
401
- abstract readonly lifecycle: AnimationLifecycle;
402
- constructor(target: T);
403
- duration(seconds: number): this;
404
- ease(easing: EasingFunction): this;
405
- delay(seconds: number): this;
347
+ readonly lifecycle: AnimationLifecycle;
348
+ constructor(animations: Animation[]);
406
349
  getDuration(): number;
407
- getDelay(): number;
408
- getEasing(): EasingFunction;
409
- getTarget(): T;
410
- getConfig(): AnimationConfig;
411
- abstract interpolate(progress: number): void;
350
+ getChildren(): readonly Animation[];
412
351
  /**
413
- * Ensures the animation is initialized before interpolation.
414
- * Called before first update to capture start state.
415
- * Default: no-op. Override in subclasses that need lazy initialization.
352
+ * Ensures all children are initialized together.
353
+ * This captures start state for all parallel animations at the same moment.
416
354
  */
417
355
  ensureInitialized(): void;
418
- /**
419
- * Resets the animation to its uninitialized state.
420
- * Allows animations to be replayed or looped.
421
- */
422
356
  reset(): void;
423
- update(progress: number): void;
424
357
  /**
425
- * Hashes the animation type, config, and target state.
426
- * Subclass-specific behavior is captured through the target's hash,
427
- * since animations mutate the target.
358
+ * Interpolates all child animations at the given progress.
359
+ * Each child's progress is scaled based on its duration relative to the container.
428
360
  */
429
- computeHash(): number;
430
- }
431
-
432
- /**
433
- * Represents an animation scheduled at a specific time on the Timeline.
434
- */
435
- interface ScheduledAnimation {
436
- /** The animation to play */
437
- readonly animation: Animation;
438
- /** Start time in seconds from timeline beginning */
439
- readonly startTime: number;
440
- }
441
- /**
442
- * Configuration options for Timeline.
443
- */
444
- interface TimelineConfig {
445
- /** Whether the timeline loops. Default: false */
446
- readonly loop?: boolean;
447
- }
448
-
449
- /**
450
- * Timeline schedules and controls playback of animations.
451
- * Animations can be scheduled at specific times and the timeline
452
- * provides seek/state access for non-linear playback.
453
- */
454
- declare class Timeline {
455
- private readonly scheduled;
456
- private readonly config;
457
- private currentTime;
458
- constructor(config?: TimelineConfig);
459
- /**
460
- * Schedule an animation to start at a specific time.
461
- * @param animation The animation to schedule
462
- * @param startTime Start time in seconds (default: 0)
463
- */
464
- schedule(animation: Animation, startTime?: number): this;
465
- /**
466
- * Schedule multiple animations to play in sequence.
467
- * First animation starts at the given startTime, subsequent
468
- * animations start after the previous one ends.
469
- * @param animations Animations to schedule sequentially
470
- * @param startTime Start time for the first animation (default: 0)
471
- */
472
- scheduleSequence(animations: Animation[], startTime?: number): this;
473
- /**
474
- * Schedule multiple animations to play in parallel.
475
- * All animations start at the same time.
476
- * @param animations Animations to schedule in parallel
477
- * @param startTime Start time for all animations (default: 0)
478
- */
479
- scheduleParallel(animations: Animation[], startTime?: number): this;
480
- /**
481
- * Get all scheduled animations with resolved timing information.
482
- */
483
- private getResolved;
484
- /**
485
- * Get total duration of the timeline.
486
- * Returns the end time of the last animation to finish.
487
- */
488
- getTotalDuration(): number;
489
- /**
490
- * Seek to a specific time and update all animations.
491
- * @param time Time in seconds to seek to
492
- */
493
- seek(time: number): void;
494
- /**
495
- * Get the timeline state at a specific time without modifying the
496
- * current playhead position.
497
- * @param time Time in seconds
498
- */
499
- getStateAt(time: number): void;
500
- /**
501
- * Get the current time of the timeline.
502
- */
503
- getCurrentTime(): number;
504
- /**
505
- * Get all scheduled animations.
506
- */
507
- getScheduled(): readonly ScheduledAnimation[];
508
- /**
509
- * Check if timeline is configured to loop.
510
- */
511
- isLooping(): boolean;
512
- /**
513
- * Clear all scheduled animations.
514
- */
515
- clear(): void;
361
+ interpolate(progress: number): void;
362
+ update(progress: number): void;
516
363
  }
517
364
 
518
365
  /**
@@ -555,686 +402,764 @@ declare class Sequence extends Animation<Mobject> {
555
402
  }
556
403
 
557
404
  /**
558
- * Executes animations in parallel, all starting at the same time.
559
- * Total duration equals the maximum of all child animation durations.
560
- *
561
- * This is a composition animation - its lifecycle is determined by its children.
562
- * By default, uses 'transformative' lifecycle if children are mixed.
563
- *
564
- * All children are initialized together before any interpolation begins,
565
- * ensuring they all capture state at the same moment.
405
+ * Abstract base class for animations that introduce an object to the scene.
566
406
  */
567
- declare class Parallel extends Animation<Mobject> {
568
- private readonly children;
569
- private readonly maxChildDuration;
570
- /**
571
- * The lifecycle of Parallel is 'introductory' only if ALL children are introductory.
572
- * Otherwise, it defaults to 'transformative'.
573
- */
407
+ declare abstract class IntroductoryAnimation<T extends Mobject = Mobject> extends Animation<T> {
574
408
  readonly lifecycle: AnimationLifecycle;
575
- constructor(animations: Animation[]);
576
- getDuration(): number;
577
- getChildren(): readonly Animation[];
409
+ }
410
+ /**
411
+ * Abstract base class for animations that transform an existing scene object.
412
+ */
413
+ declare abstract class TransformativeAnimation<T extends Mobject = Mobject> extends Animation<T> {
414
+ readonly lifecycle: AnimationLifecycle;
415
+ protected initialized: boolean;
578
416
  /**
579
- * Ensures all children are initialized together.
580
- * This captures start state for all parallel animations at the same moment.
417
+ * Captures the start state from the target.
418
+ * Called once when the animation first becomes active.
581
419
  */
420
+ protected abstract captureStartState(): void;
582
421
  ensureInitialized(): void;
583
422
  reset(): void;
584
- /**
585
- * Interpolates all child animations at the given progress.
586
- * Each child's progress is scaled based on its duration relative to the container.
587
- */
423
+ }
424
+ /**
425
+ * Abstract base class for animations that exit/remove an object from the scene.
426
+ */
427
+ declare abstract class ExitAnimation<T extends Mobject = Mobject> extends Animation<T> {
428
+ readonly lifecycle: AnimationLifecycle;
429
+ }
430
+
431
+ /**
432
+ * Animation that first draws the stroke progressively, then fades in the fill.
433
+ * - First 50%: stroke draws progressively
434
+ * - Second 50%: fill fades in
435
+ *
436
+ * - Single VMobject: stroke then fill
437
+ * - VGroup: all children animate together
438
+ * - Text (VGroup of Glyphs): Glyphs animate sequentially for handwriting effect
439
+ *
440
+ * This is an introductory animation - it auto-registers the target with the scene.
441
+ */
442
+ declare class Draw<T extends VMobject = VMobject> extends IntroductoryAnimation<T> {
443
+ private readonly originalPaths;
444
+ private readonly originalOpacity;
445
+ private readonly originalStrokeColor;
446
+ private readonly originalStrokeWidth;
447
+ private readonly originalFillColor;
448
+ private readonly originalFillOpacity;
449
+ private readonly childStates;
450
+ /** Glyph states for Text children, keyed by the Text VMobject reference. */
451
+ private readonly glyphStates;
452
+ constructor(target: T);
453
+ private createState;
588
454
  interpolate(progress: number): void;
589
- update(progress: number): void;
455
+ private interpolateVGroup;
456
+ private interpolateGlyphs;
457
+ /** Interpolates a single VMobject: stroke (0-0.5), then fill (0.5-1). */
458
+ private interpolateVMobject;
590
459
  }
591
460
 
592
461
  /**
593
- * Configuration options for CameraFrame.
462
+ * Animation that progressively removes a VMobject by erasing the path.
463
+ * Reverse of Write animation - at progress 0, full object is visible;
464
+ * at progress 1, nothing is visible.
465
+ *
466
+ * Supports VGroup (including Text): animates each child's paths progressively.
467
+ *
468
+ * This is an exit animation - the target must already be in the scene.
469
+ *
470
+ * @example
471
+ * scene.play(new Write(text));
472
+ * scene.play(new Unwrite(text)); // Text is erased progressively
594
473
  */
595
- interface CameraFrameConfig {
596
- /** Width of the viewport in pixels. Defaults to 1920. */
597
- pixelWidth?: number;
598
- /** Height of the viewport in pixels. Defaults to 1080. */
599
- pixelHeight?: number;
474
+ declare class Unwrite<T extends VMobject = VMobject> extends ExitAnimation<T> {
475
+ private readonly isVGroup;
476
+ /** For non-VGroup targets: original paths on the target itself. */
477
+ private readonly originalPaths;
478
+ private readonly originalOpacity;
479
+ private readonly originalFillOpacity;
480
+ /** For VGroup targets: original state of each child. */
481
+ private readonly childStates;
482
+ constructor(target: T);
483
+ interpolate(progress: number): void;
484
+ /** Interpolates a single VMobject (non-VGroup). */
485
+ private interpolateVMobject;
486
+ /** Interpolates a VGroup by animating each child's paths. */
487
+ private interpolateVGroup;
600
488
  }
489
+
601
490
  /**
602
- * Camera bounds that limit how far the camera can pan.
491
+ * Animation that progressively draws VMobject paths from start to end.
492
+ *
493
+ * - Single VMobject: paths draw progressively
494
+ * - VGroup: all children animate together with same progress
495
+ * - Text (VGroup of Glyphs): Glyphs animate sequentially for handwriting effect
496
+ *
497
+ * This is an introductory animation - it auto-registers the target with the scene.
603
498
  */
604
- interface Bounds {
605
- minX: number;
606
- maxX: number;
607
- minY: number;
608
- maxY: number;
499
+ declare class Write<T extends VMobject = VMobject> extends IntroductoryAnimation<T> {
500
+ private readonly originalPaths;
501
+ private readonly originalOpacity;
502
+ private readonly originalStrokeColor;
503
+ private readonly originalStrokeWidth;
504
+ private readonly originalFillColor;
505
+ private readonly originalFillOpacity;
506
+ private readonly childStates;
507
+ /** Glyph states for Text children, keyed by the Text VMobject reference. */
508
+ private readonly glyphStates;
509
+ constructor(target: T);
510
+ private createState;
511
+ interpolate(progress: number): void;
512
+ private interpolateVGroup;
513
+ private interpolateGlyphs;
514
+ /** Applies progress to a single VMobject, updating its paths and style. */
515
+ private applyProgress;
609
516
  }
517
+
610
518
  /**
611
- * CameraFrame represents the viewport window in world space.
612
- * Extends Mobject (not VMobject - no visual representation).
613
- * Its transform properties define what the camera shows:
614
- * - scale(2) = zoom OUT (larger frame = see more)
615
- * - scale(0.5) = zoom IN (smaller frame = see less)
519
+ * Animation that fades a Mobject in by increasing its opacity from 0 to 1.
616
520
  *
617
- * The CameraFrame is the primary way to control camera animations in Anima.
618
- * Access it via `scene.frame` or `scene.camera.frame`.
521
+ * This is an introductory animation - it auto-registers the target with the scene.
522
+ * You do not need to call scene.add() before using FadeIn.
619
523
  *
620
524
  * @example
621
- * // Zoom in over 1 second
622
- * this.play(this.frame.zoomIn(2).duration(1));
525
+ * const circle = new Circle(1);
526
+ * scene.play(new FadeIn(circle)); // Circle is auto-registered and faded in
527
+ */
528
+ declare class FadeIn<T extends Mobject = Mobject> extends IntroductoryAnimation<T> {
529
+ private readonly startOpacity;
530
+ constructor(target: T);
531
+ interpolate(progress: number): void;
532
+ }
533
+
534
+ /**
535
+ * Animation that fades a Mobject out by decreasing its opacity to 0.
623
536
  *
624
- * @example
625
- * // Pan to center on an object
626
- * this.play(this.frame.centerOn(circle).duration(0.5));
537
+ * This is an exit animation - the target must already be in the scene.
538
+ * The starting opacity is captured when the animation first runs,
539
+ * not when it's constructed, so it correctly fades from the current opacity.
627
540
  *
628
541
  * @example
629
- * // Fit multiple objects in view
630
- * this.play(this.frame.fitTo([obj1, obj2, obj3]).duration(1));
542
+ * scene.add(circle);
543
+ * scene.play(new FadeOut(circle)); // Circle fades out
631
544
  */
632
- declare class CameraFrame extends Mobject {
633
- private readonly baseWidth;
634
- private readonly baseHeight;
635
- private bounds?;
636
- /**
637
- * Creates a new CameraFrame with the specified viewport dimensions.
638
- *
639
- * @param config - Configuration options
640
- * @param config.pixelWidth - Width of the viewport in pixels (default: 1920)
641
- * @param config.pixelHeight - Height of the viewport in pixels (default: 1080)
642
- *
643
- * @example
644
- * const frame = new CameraFrame({ pixelWidth: 1920, pixelHeight: 1080 });
645
- */
646
- constructor(config?: CameraFrameConfig);
647
- /**
648
- * The current width of the frame in world units, accounting for scale.
649
- * @returns The frame width multiplied by the current scale.x
650
- */
651
- get width(): number;
545
+ declare class FadeOut<T extends Mobject = Mobject> extends ExitAnimation<T> {
546
+ private startOpacity;
547
+ interpolate(progress: number): void;
548
+ }
549
+
550
+ /**
551
+ * Animation that moves a Mobject from its current position to a destination.
552
+ * Uses linear interpolation between start and end positions.
553
+ *
554
+ * This is a transformative animation - the target must already be in the scene.
555
+ * Start position is captured lazily when animation becomes active.
556
+ *
557
+ * @example
558
+ * scene.add(circle); // or use FadeIn first
559
+ * scene.play(new MoveTo(circle, 2, 0)); // Move to (2, 0)
560
+ */
561
+ declare class MoveTo<T extends Mobject = Mobject> extends TransformativeAnimation<T> {
562
+ private startPosition;
563
+ private readonly endPosition;
564
+ constructor(target: T, destination: Vector2);
565
+ constructor(target: T, x: number, y: number);
566
+ protected captureStartState(): void;
567
+ interpolate(progress: number): void;
568
+ /** Returns the target position of the move animation. */
569
+ getDestination(): Vector2;
570
+ }
571
+
572
+ /**
573
+ * Animation that rotates a Mobject by a specified angle.
574
+ * Uses linear interpolation between start and end rotation.
575
+ *
576
+ * This is a transformative animation - the target must already be in the scene.
577
+ * Start rotation is captured lazily when animation becomes active.
578
+ *
579
+ * @example
580
+ * scene.add(square);
581
+ * scene.play(new Rotate(square, Math.PI / 4)); // Rotate 45 degrees
582
+ */
583
+ declare class Rotate<T extends Mobject = Mobject> extends TransformativeAnimation<T> {
584
+ private startRotation;
585
+ private endRotation;
586
+ private readonly angle;
587
+ constructor(target: T, angle: number);
588
+ protected captureStartState(): void;
589
+ interpolate(progress: number): void;
590
+ /** Returns the total rotation angle in radians. */
591
+ getAngle(): number;
592
+ }
593
+
594
+ /**
595
+ * Animation that scales a Mobject to a target scale factor.
596
+ * Uses linear interpolation between start and end scale.
597
+ *
598
+ * This is a transformative animation - the target must already be in the scene.
599
+ * Start scale is captured lazily when animation becomes active.
600
+ *
601
+ * @example
602
+ * scene.add(circle);
603
+ * scene.play(new Scale(circle, 2)); // Scale to 2x
604
+ */
605
+ declare class Scale<T extends Mobject = Mobject> extends TransformativeAnimation<T> {
606
+ private startScale;
607
+ private readonly endScale;
608
+ constructor(target: T, factor: number);
609
+ constructor(target: T, factorX: number, factorY: number);
610
+ protected captureStartState(): void;
611
+ interpolate(progress: number): void;
612
+ /** Returns the scale factor. */
613
+ getFactor(): number;
614
+ }
615
+
616
+ /**
617
+ * Manages a queue of animations for fluent chaining.
618
+ * This is an internal implementation detail of Mobject's fluent API.
619
+ */
620
+ declare class AnimationQueue {
621
+ private readonly target;
622
+ private readonly queue;
623
+ constructor(target: Mobject);
624
+ enqueueAnimation(animation: Animation<Mobject>): void;
625
+ setLastDuration(seconds: number): void;
626
+ setLastEasing(easing: EasingFunction): void;
627
+ setLastDelay(seconds: number): void;
628
+ isEmpty(): boolean;
629
+ popLastAnimation(): Animation<Mobject> | null;
630
+ toAnimation(): Animation<Mobject>;
631
+ getTotalDuration(): number;
632
+ }
633
+ interface MobjectState {
634
+ position: Vector2;
635
+ scale: Vector2;
636
+ rotation: number;
637
+ }
638
+ /**
639
+ * Base class for all mathematical objects.
640
+ * Manages position, rotation, scale, and opacity via a local transformation matrix.
641
+ * Includes fluent animation API for chainable animations.
642
+ */
643
+ declare class Mobject {
644
+ protected localMatrix: Matrix3x3;
645
+ protected opacityValue: number;
646
+ protected animQueue: AnimationQueue | null;
647
+ private savedStates;
648
+ parent: Mobject | null;
649
+ constructor();
650
+ protected getQueue(): AnimationQueue;
651
+ get matrix(): Matrix3x3;
652
+ getWorldMatrix(): Matrix3x3;
653
+ get position(): Vector2;
654
+ get rotation(): number;
655
+ get scale(): Vector2;
656
+ get opacity(): number;
657
+ pos(x: number, y: number): this;
658
+ show(): this;
659
+ hide(): this;
660
+ setOpacity(value: number): this;
661
+ setRotation(angle: number): this;
662
+ setScale(sx: number, sy: number): this;
663
+ applyMatrix(m: Matrix3x3): this;
664
+ saveState(): this;
665
+ getSavedState(): MobjectState | undefined;
666
+ clearSavedStates(): this;
652
667
  /**
653
- * The current height of the frame in world units, accounting for scale.
654
- * @returns The frame height multiplied by the current scale.y
668
+ * Animates back to the last saved state.
669
+ * Pops the saved state from the stack.
670
+ * @throws Error if no state was previously saved
655
671
  */
656
- get height(): number;
672
+ restore(durationSeconds?: number): this & {
673
+ toAnimation(): Animation<Mobject>;
674
+ };
675
+ fadeIn(durationSeconds?: number): this & {
676
+ toAnimation(): Animation<Mobject>;
677
+ };
678
+ fadeOut(durationSeconds?: number): this & {
679
+ toAnimation(): Animation<Mobject>;
680
+ };
681
+ moveTo(x: number, y: number, durationSeconds?: number): this & {
682
+ toAnimation(): Animation<Mobject>;
683
+ };
684
+ rotate(angle: number, durationSeconds?: number): this & {
685
+ toAnimation(): Animation<Mobject>;
686
+ };
687
+ scaleTo(factor: number, durationSeconds?: number): this & {
688
+ toAnimation(): Animation<Mobject>;
689
+ };
690
+ scaleToXY(factorX: number, factorY: number, durationSeconds?: number): this & {
691
+ toAnimation(): Animation<Mobject>;
692
+ };
693
+ duration(seconds: number): this;
694
+ ease(easing: EasingFunction): this;
695
+ delay(seconds: number): this;
696
+ toAnimation(): Animation<Mobject>;
697
+ getQueuedDuration(): number;
698
+ hasQueuedAnimations(): boolean;
657
699
  /**
658
- * Sets the scale of the camera frame.
659
- * Overrides Mobject.setScale to prevent zero or negative scales.
660
- *
661
- * @param sx - Scale factor for the x-axis (must be positive)
662
- * @param sy - Scale factor for the y-axis (must be positive)
663
- * @returns This CameraFrame for method chaining
664
- * @throws Error if sx or sy is zero or negative
665
- *
700
+ * Queues multiple animations to run in parallel (simultaneously).
701
+ * Automatically handles both Animation objects and mobject method calls.
666
702
  * @example
667
- * frame.setScale(2, 2); // Zoom out 2x
668
- * frame.setScale(0.5, 0.5); // Zoom in 2x
703
+ * circle.fadeIn(1).parallel(
704
+ * circle.moveTo(100, 50),
705
+ * circle.rotate(Math.PI)
706
+ * ).fadeOut(1);
669
707
  */
670
- setScale(sx: number, sy: number): this;
708
+ parallel(...items: (Animation<Mobject> | Mobject)[]): this;
671
709
  /**
672
- * Sets bounds that limit how far the camera can pan.
673
- * When bounds are set, the camera position is clamped to stay within them,
674
- * accounting for the frame size so edges don't go outside bounds.
675
- *
676
- * @param minX - Minimum x coordinate
677
- * @param minY - Minimum y coordinate
678
- * @param maxX - Maximum x coordinate
679
- * @param maxY - Maximum y coordinate
680
- * @returns This CameraFrame for method chaining
681
- *
682
- * @example
683
- * // Limit camera to a 100x100 world area
684
- * frame.setBounds(0, 0, 100, 100);
710
+ * Computes a CRC32 hash of this mobject's full state.
711
+ * Used by the segment cache to detect changes.
685
712
  */
686
- setBounds(minX: number, minY: number, maxX: number, maxY: number): this;
713
+ computeHash(): number;
714
+ }
715
+
716
+ /**
717
+ * A Mobject that is defined by one or more BezierPaths.
718
+ * Supports stroke and fill styling, plus VMobject-specific fluent animations.
719
+ *
720
+ * Default behavior: visible with white stroke, no fill.
721
+ * - Stroke: white, width 2 (visible by default)
722
+ * - Fill: not rendered by default (fillOpacity = 0)
723
+ *
724
+ * When .fill(color) is called, the default stroke is disabled unless
725
+ * .stroke(color, width) was called explicitly.
726
+ *
727
+ * Use .stroke(color, width) to add a stroke.
728
+ * Use .fill(color) to add a fill (opacity defaults to 1).
729
+ */
730
+ declare class VMobject extends Mobject {
731
+ protected pathList: BezierPath[];
732
+ /** Stroke color. Only rendered if strokeWidth > 0. */
733
+ protected strokeColor: Color;
734
+ /** Stroke width. Default 2 for visibility. */
735
+ protected strokeWidth: number;
736
+ /** Fill color. Only rendered if fillOpacity > 0. */
737
+ protected fillColor: Color;
738
+ /** Fill opacity. Default 0 means no fill is rendered. */
739
+ protected fillOpacity: number;
740
+ /** Tracks whether stroke() was explicitly called. */
741
+ protected strokeExplicitlySet: boolean;
742
+ constructor();
743
+ get paths(): BezierPath[];
744
+ set paths(value: BezierPath[]);
687
745
  /**
688
- * Removes any bounds restrictions on camera movement.
689
- *
690
- * @returns This CameraFrame for method chaining
691
- *
692
- * @example
693
- * frame.clearBounds(); // Camera can now pan freely
746
+ * Gets the stroke color.
694
747
  */
695
- clearBounds(): this;
748
+ getStrokeColor(): Color;
696
749
  /**
697
- * Checks if the camera has bounds set.
698
- *
699
- * @returns True if bounds are set, false otherwise
750
+ * Gets the stroke width.
700
751
  */
701
- hasBounds(): boolean;
752
+ getStrokeWidth(): number;
702
753
  /**
703
- * Gets the current bounds configuration.
704
- *
705
- * @returns The bounds object or undefined if no bounds are set
754
+ * Gets the fill color.
706
755
  */
707
- getBounds(): Bounds | undefined;
756
+ getFillColor(): Color;
708
757
  /**
709
- * Sets the position of the camera frame.
710
- * Overrides Mobject.pos to clamp position within bounds if set.
711
- *
712
- * @param x - The x coordinate in world space
713
- * @param y - The y coordinate in world space
714
- * @returns This CameraFrame for method chaining
715
- *
716
- * @example
717
- * frame.pos(5, 3); // Move camera center to (5, 3)
758
+ * Gets the fill opacity.
718
759
  */
719
- pos(x: number, y: number): this;
760
+ getFillOpacity(): number;
720
761
  /**
721
- * Smoothly zoom the camera in by the given factor.
722
- * Internally scales the frame down, which makes objects appear larger.
723
- *
724
- * @param factor - Zoom multiplier. 2 = objects appear 2x larger (default: 2)
725
- * @returns FluentAnimation that can be chained with .duration() and .ease()
726
- * @throws Error if factor is zero or negative
727
- *
728
- * @example
729
- * // Zoom in 2x over 1 second
730
- * this.play(this.frame.zoomIn(2).duration(1));
731
- *
732
- * @example
733
- * // Zoom in 3x with easing
734
- * this.play(this.frame.zoomIn(3).duration(1.5).ease(easeInOutQuad));
762
+ * Adds a new path to the VMobject.
763
+ * @param path - The BezierPath to add.
764
+ * @returns this for chaining.
735
765
  */
736
- zoomIn(factor?: number): this & {
737
- toAnimation(): Animation<Mobject>;
738
- };
766
+ addPath(path: BezierPath): this;
739
767
  /**
740
- * Smoothly zoom the camera out by the given factor.
741
- * Internally scales the frame up, which makes objects appear smaller.
742
- *
743
- * @param factor - Zoom multiplier. 2 = objects appear 2x smaller (default: 2)
744
- * @returns FluentAnimation that can be chained with .duration() and .ease()
745
- * @throws Error if factor is zero or negative
746
- *
747
- * @example
748
- * // Zoom out 2x over 1 second
749
- * this.play(this.frame.zoomOut(2).duration(1));
750
- *
751
- * @example
752
- * // Zoom out to show more of the scene
753
- * this.play(this.frame.zoomOut(4).duration(2).ease(easeOutCubic));
768
+ * Sets the stroke color and width.
769
+ * @param color - The stroke color.
770
+ * @param width - The stroke width. Default is 2.
771
+ * @returns this for chaining.
754
772
  */
755
- zoomOut(factor?: number): this & {
756
- toAnimation(): Animation<Mobject>;
757
- };
773
+ stroke(color: Color, width?: number): this;
758
774
  /**
759
- * Move the camera to center on a target Mobject.
760
- * The camera will smoothly pan so the target is at the center of the frame.
761
- *
762
- * @param target - The Mobject to center on
763
- * @returns FluentAnimation that can be chained with .duration() and .ease()
764
- * @throws Error if target is null or undefined
765
- *
766
- * @example
767
- * // Center on a circle over 0.5 seconds
768
- * this.play(this.frame.centerOn(circle).duration(0.5));
769
- *
770
- * @example
771
- * // Pan to focus on different objects in sequence
772
- * await this.play(this.frame.centerOn(obj1).duration(1));
773
- * await this.play(this.frame.centerOn(obj2).duration(1));
775
+ * Sets the fill color and opacity.
776
+ * If stroke was not explicitly set, the default stroke is disabled.
777
+ * @param color - The fill color.
778
+ * @param opacity - The fill opacity. Defaults to the color's alpha value.
779
+ * @returns this for chaining.
774
780
  */
775
- centerOn(target: Mobject): this & {
776
- toAnimation(): Animation<Mobject>;
781
+ fill(color: Color, opacity?: number): this;
782
+ getPoints(): PathCommand[];
783
+ setPoints(commands: PathCommand[]): this;
784
+ private getPointsAsVectors;
785
+ getBoundingBox(): {
786
+ minX: number;
787
+ maxX: number;
788
+ minY: number;
789
+ maxY: number;
777
790
  };
778
791
  /**
779
- * Zoom in/out while keeping a specific world point fixed on screen.
780
- * Like pinch-to-zoom behavior where the pinch point stays stationary.
781
- *
782
- * Uses the formula: C' = P * (1 - factor) + C * factor
783
- * Where P = point, C = current center, factor = zoom factor.
784
- *
785
- * @param factor - Scale multiplier. Less than 1 for zoom in, greater than 1 for zoom out
786
- * @param point - World coordinates to keep fixed on screen
787
- * @returns Parallel animation combining move and scale
788
- * @throws Error if factor is zero or negative
789
- *
790
- * @example
791
- * // Zoom in 2x on a specific point
792
- * this.play(frame.zoomToPoint(0.5, { x: 5, y: 5 }).duration(1));
793
- *
794
- * @example
795
- * // Zoom out while keeping an object's position fixed
796
- * this.play(frame.zoomToPoint(2, circle.position).duration(1));
792
+ * Progressively draws the VMobject's paths from start to end.
793
+ * Preserves fill throughout the animation.
794
+ * @param durationSeconds - Animation duration in seconds.
795
+ * @returns this for chaining.
797
796
  */
798
- zoomToPoint(factor: number, point: {
799
- x: number;
800
- y: number;
801
- }): Parallel;
802
- /**
803
- * Automatically frame one or more objects with optional margin.
804
- * Calculates the bounding box of all targets and animates the camera
805
- * to show them all with the specified margin around them.
806
- *
807
- * @param targets - Single Mobject or array of Mobjects to frame
808
- * @param margin - Padding around the objects in world units (default: 0.5)
809
- * @returns FluentAnimation that can be chained with .duration() and .ease()
810
- * @throws Error if targets array is empty
811
- *
812
- * @example
813
- * // Fit a single object with default margin
814
- * this.play(this.frame.fitTo(circle).duration(1));
815
- *
816
- * @example
817
- * // Fit multiple objects with custom margin
818
- * this.play(this.frame.fitTo([obj1, obj2, obj3], 1.0).duration(1.5));
819
- *
820
- * @example
821
- * // Show all objects in the scene
822
- * this.play(this.frame.fitTo(allObjects, 0).duration(2));
797
+ write(durationSeconds?: number): this & {
798
+ toAnimation(): Animation<Mobject>;
799
+ };
800
+ /**
801
+ * Progressively removes the VMobject's paths (reverse of write).
802
+ * @param durationSeconds - Animation duration in seconds.
803
+ * @returns this for chaining.
823
804
  */
824
- fitTo(targets: Mobject | Mobject[], margin?: number): this & {
805
+ unwrite(durationSeconds?: number): this & {
825
806
  toAnimation(): Animation<Mobject>;
826
807
  };
827
- private calculateBounds;
828
- private hasGetBoundingBox;
808
+ /**
809
+ * First draws the stroke progressively (0-50%), then fades in the fill (50-100%).
810
+ * @param durationSeconds - Animation duration in seconds.
811
+ * @returns this for chaining.
812
+ */
813
+ draw(durationSeconds?: number): this & {
814
+ toAnimation(): Animation<Mobject>;
815
+ };
816
+ /**
817
+ * Extends parent hash with VMobject-specific state:
818
+ * stroke/fill colors, widths, opacity, and path geometry.
819
+ */
820
+ computeHash(): number;
829
821
  }
830
822
 
831
823
  /**
832
- * Configuration options for Camera.
824
+ * Configuration options for CameraFrame.
833
825
  */
834
- interface CameraConfig {
835
- /** Pixel width for aspect ratio calculation. Default: 1920 */
836
- readonly pixelWidth?: number;
837
- /** Pixel height for aspect ratio calculation. Default: 1080 */
838
- readonly pixelHeight?: number;
826
+ interface CameraFrameConfig {
827
+ /** Width of the viewport in pixels. Defaults to 1920. */
828
+ pixelWidth?: number;
829
+ /** Height of the viewport in pixels. Defaults to 1080. */
830
+ pixelHeight?: number;
839
831
  }
840
832
  /**
841
- * Resolved camera configuration with all defaults applied.
833
+ * Camera bounds that limit how far the camera can pan.
842
834
  */
843
- interface ResolvedCameraConfig {
844
- readonly pixelWidth: number;
845
- readonly pixelHeight: number;
835
+ interface Bounds {
836
+ minX: number;
837
+ maxX: number;
838
+ minY: number;
839
+ maxY: number;
846
840
  }
847
-
848
841
  /**
849
- * Camera manages the view into the scene.
850
- * Uses CameraFrame (a Mobject) to store transform state, enabling camera animations.
842
+ * CameraFrame represents the viewport window in world space.
843
+ * Extends Mobject (not VMobject - no visual representation).
844
+ * Its transform properties define what the camera shows:
845
+ * - scale(2) = zoom OUT (larger frame = see more)
846
+ * - scale(0.5) = zoom IN (smaller frame = see less)
851
847
  *
852
- * The Camera provides both instant manipulation methods (panTo, zoomTo) and
853
- * access to the CameraFrame for fluent animation APIs.
848
+ * The CameraFrame is the primary way to control camera animations in Anima.
849
+ * Access it via `scene.frame` or `scene.camera.frame`.
854
850
  *
855
851
  * @example
856
- * // Instant camera manipulation
857
- * camera.zoomTo(2);
858
- * camera.panTo(new Vector2(5, 3));
852
+ * // Zoom in over 1 second
853
+ * this.play(this.frame.zoomIn(2).duration(1));
859
854
  *
860
855
  * @example
861
- * // Animated camera movement via frame
862
- * this.play(this.frame.zoomIn(2).duration(1));
856
+ * // Pan to center on an object
863
857
  * this.play(this.frame.centerOn(circle).duration(0.5));
858
+ *
859
+ * @example
860
+ * // Fit multiple objects in view
861
+ * this.play(this.frame.fitTo([obj1, obj2, obj3]).duration(1));
864
862
  */
865
- declare class Camera {
866
- private readonly config;
867
- /** The CameraFrame that stores the camera's transform state. Use this for animations. */
868
- readonly frame: CameraFrame;
863
+ declare class CameraFrame extends Mobject {
864
+ private readonly baseWidth;
865
+ private readonly baseHeight;
866
+ private bounds?;
869
867
  /**
870
- * Creates a new Camera with the specified viewport dimensions.
868
+ * Creates a new CameraFrame with the specified viewport dimensions.
871
869
  *
872
870
  * @param config - Configuration options
873
871
  * @param config.pixelWidth - Width of the viewport in pixels (default: 1920)
874
872
  * @param config.pixelHeight - Height of the viewport in pixels (default: 1080)
875
- */
876
- constructor(config?: CameraConfig);
877
- get frameHeight(): number;
878
- get frameWidth(): number;
879
- get frameYRadius(): number;
880
- get frameXRadius(): number;
881
- get pixelWidth(): number;
882
- get pixelHeight(): number;
883
- get position(): Vector2;
884
- get zoom(): number;
885
- get rotation(): number;
886
- pan(delta: Vector2): this;
887
- panTo(position: Vector2): this;
888
- zoomTo(level: number): this;
889
- rotateTo(angle: number): this;
890
- getViewMatrix(): Matrix3x3;
891
- /**
892
- * Transforms a world-space position to screen-space (pixel) coordinates.
893
- *
894
- * Screen coordinates have origin at top-left, with x increasing right
895
- * and y increasing downward.
896
- *
897
- * @param pos - Position in world coordinates
898
- * @returns Position in screen coordinates (pixels)
899
- *
900
- * @example
901
- * const screenPos = camera.worldToScreen(circle.position);
902
- * console.log(`Circle is at pixel (${screenPos.x}, ${screenPos.y})`);
903
- */
904
- worldToScreen(pos: Vector2): Vector2;
905
- /**
906
- * Transforms a screen-space (pixel) position to world coordinates.
907
- * This is the inverse of worldToScreen.
908
- *
909
- * @param pos - Position in screen coordinates (pixels, origin at top-left)
910
- * @returns Position in world coordinates
911
- *
912
- * @example
913
- * // Convert a mouse click position to world coordinates
914
- * const worldPos = camera.screenToWorld(new Vector2(mouseX, mouseY));
915
- */
916
- screenToWorld(pos: Vector2): Vector2;
917
- /**
918
- * Checks if a world-space position is currently visible within the camera frame.
919
- *
920
- * @param pos - Position in world coordinates to check
921
- * @returns True if the position is within the visible frame bounds
922
873
  *
923
874
  * @example
924
- * if (camera.isInView(object.position)) {
925
- * console.log('Object is visible');
926
- * }
927
- */
928
- isInView(pos: Vector2): boolean;
929
- reset(): this;
930
- /**
931
- * Hashes camera config and the CameraFrame's full transform state.
932
- */
933
- computeHash(): number;
934
- }
935
-
936
- /**
937
- * Configuration options for Scene.
938
- */
939
- interface SceneConfig {
940
- /** Pixel width of the scene. Default: 1920 */
941
- readonly width?: number;
942
- /** Pixel height of the scene. Default: 1080 */
943
- readonly height?: number;
944
- /** Background color. Default: BLACK */
945
- readonly backgroundColor?: Color;
946
- /** Frames per second. Default: 60 */
947
- readonly frameRate?: number;
948
- }
949
-
950
- /**
951
- * A Segment represents one independent rendering unit,
952
- * corresponding to a single play() or wait() call.
953
- *
954
- * Its hash is a holistic CRC32 composition of the camera state,
955
- * all current mobjects, and the animations for this segment.
956
- */
957
- interface Segment {
958
- /** Zero-based index in the scene's segment list. */
959
- readonly index: number;
960
- /** Start time in seconds. */
961
- readonly startTime: number;
962
- /** End time in seconds. */
963
- readonly endTime: number;
964
- /** Animations scheduled in this segment (empty for wait segments). */
965
- readonly animations: readonly Animation[];
966
- /** CRC32 hash of camera + mobjects + animations at this point. */
967
- readonly hash: number;
968
- }
969
-
970
- /**
971
- * Scene is the core container that manages Mobjects and coordinates animations.
972
- * It provides both a simple API for playing animations and access to the
973
- * underlying Timeline and Camera for advanced control.
974
- */
975
- declare class Scene {
976
- private readonly config;
977
- private readonly mobjects;
978
- private readonly timeline;
979
- private readonly _camera;
980
- private readonly segmentList;
981
- private playheadTime;
982
- constructor(config?: SceneConfig);
983
- get camera(): Camera;
984
- get frame(): CameraFrame;
985
- /** Get scene width in pixels. */
986
- getWidth(): number;
987
- /** Get scene height in pixels. */
988
- getHeight(): number;
989
- /** Get scene background color. */
990
- getBackgroundColor(): Color;
991
- /** Get scene frame rate. */
992
- getFrameRate(): number;
993
- /**
994
- * Add mobjects to the scene and make them immediately visible.
995
- * Use this for static elements or backgrounds that should be visible
996
- * before any animations begin.
997
- */
998
- add(...mobjects: Mobject[]): this;
999
- /**
1000
- * Remove mobjects from the scene.
875
+ * const frame = new CameraFrame({ pixelWidth: 1920, pixelHeight: 1080 });
1001
876
  */
1002
- remove(...mobjects: Mobject[]): this;
877
+ constructor(config?: CameraFrameConfig);
1003
878
  /**
1004
- * Check if a mobject is registered with this scene.
879
+ * The current width of the frame in world units, accounting for scale.
880
+ * @returns The frame width multiplied by the current scale.x
1005
881
  */
1006
- has(mobject: Mobject): boolean;
882
+ get width(): number;
1007
883
  /**
1008
- * Get all mobjects in the scene.
884
+ * The current height of the frame in world units, accounting for scale.
885
+ * @returns The frame height multiplied by the current scale.y
1009
886
  */
1010
- getMobjects(): readonly Mobject[];
887
+ get height(): number;
1011
888
  /**
1012
- * Schedule animations to play at the current playhead position.
1013
- *
1014
- * Accepts either Animation objects or Mobjects with queued fluent animations.
1015
- * When a Mobject is passed, its queued animation chain is automatically extracted.
889
+ * Sets the scale of the camera frame.
890
+ * Overrides Mobject.setScale to prevent zero or negative scales.
1016
891
  *
1017
- * - Introductory animations (FadeIn, Create, Draw, Write) auto-register
1018
- * their targets with the scene if not already present.
1019
- * - Transformative animations (MoveTo, Rotate, Scale) require the target
1020
- * to already be in the scene, otherwise an error is thrown.
892
+ * @param sx - Scale factor for the x-axis (must be positive)
893
+ * @param sy - Scale factor for the y-axis (must be positive)
894
+ * @returns This CameraFrame for method chaining
895
+ * @throws Error if sx or sy is zero or negative
1021
896
  *
1022
897
  * @example
1023
- * // ProAPI style
1024
- * this.play(new FadeIn(circle), new MoveTo(rect, 2, 0));
1025
- *
1026
- * // FluentAPI style
1027
- * circle.fadeIn(1).moveTo(2, 0, 1);
1028
- * this.play(circle);
1029
- *
1030
- * // Mixed
1031
- * circle.fadeIn(1);
1032
- * this.play(circle, new FadeIn(rect));
898
+ * frame.setScale(2, 2); // Zoom out 2x
899
+ * frame.setScale(0.5, 0.5); // Zoom in 2x
1033
900
  */
1034
- play(...items: Array<Animation | Mobject>): this;
901
+ setScale(sx: number, sy: number): this;
1035
902
  /**
1036
- * Add a delay before the next play() call.
1037
- * @param seconds Number of seconds to wait
903
+ * Sets bounds that limit how far the camera can pan.
904
+ * When bounds are set, the camera position is clamped to stay within them,
905
+ * accounting for the frame size so edges don't go outside bounds.
906
+ *
907
+ * @param minX - Minimum x coordinate
908
+ * @param minY - Minimum y coordinate
909
+ * @param maxX - Maximum x coordinate
910
+ * @param maxY - Maximum y coordinate
911
+ * @returns This CameraFrame for method chaining
912
+ *
913
+ * @example
914
+ * // Limit camera to a 100x100 world area
915
+ * frame.setBounds(0, 0, 100, 100);
1038
916
  */
1039
- wait(seconds: number): this;
917
+ setBounds(minX: number, minY: number, maxX: number, maxY: number): this;
1040
918
  /**
1041
- * Get the current playhead time.
919
+ * Removes any bounds restrictions on camera movement.
920
+ *
921
+ * @returns This CameraFrame for method chaining
922
+ *
923
+ * @example
924
+ * frame.clearBounds(); // Camera can now pan freely
1042
925
  */
1043
- getCurrentTime(): number;
926
+ clearBounds(): this;
1044
927
  /**
1045
- * Get the total duration of all scheduled animations.
928
+ * Checks if the camera has bounds set.
929
+ *
930
+ * @returns True if bounds are set, false otherwise
1046
931
  */
1047
- getTotalDuration(): number;
932
+ hasBounds(): boolean;
1048
933
  /**
1049
- * Get the underlying Timeline for advanced control.
1050
- * Use this for direct manipulation of animation timing.
934
+ * Gets the current bounds configuration.
935
+ *
936
+ * @returns The bounds object or undefined if no bounds are set
1051
937
  */
1052
- getTimeline(): Timeline;
938
+ getBounds(): Bounds | undefined;
1053
939
  /**
1054
- * Get the Camera for view control and frame dimensions.
1055
- * Camera calculates Manim-compatible frame dimensions from pixel resolution.
940
+ * Sets the position of the camera frame.
941
+ * Overrides Mobject.pos to clamp position within bounds if set.
942
+ *
943
+ * @param x - The x coordinate in world space
944
+ * @param y - The y coordinate in world space
945
+ * @returns This CameraFrame for method chaining
946
+ *
947
+ * @example
948
+ * frame.pos(5, 3); // Move camera center to (5, 3)
1056
949
  */
1057
- getCamera(): Camera;
950
+ pos(x: number, y: number): this;
1058
951
  /**
1059
- * Get the list of segments emitted by play() and wait() calls.
1060
- * Used by the Renderer for cache-aware segmented rendering.
952
+ * Smoothly zoom the camera in by the given factor.
953
+ * Internally scales the frame down, which makes objects appear larger.
954
+ *
955
+ * @param factor - Zoom multiplier. 2 = objects appear 2x larger (default: 2)
956
+ * @returns FluentAnimation that can be chained with .duration() and .ease()
957
+ * @throws Error if factor is zero or negative
958
+ *
959
+ * @example
960
+ * // Zoom in 2x over 1 second
961
+ * this.play(this.frame.zoomIn(2).duration(1));
962
+ *
963
+ * @example
964
+ * // Zoom in 3x with easing
965
+ * this.play(this.frame.zoomIn(3).duration(1.5).ease(easeInOutQuad));
1061
966
  */
1062
- getSegments(): readonly Segment[];
967
+ zoomIn(factor?: number): this & {
968
+ toAnimation(): Animation<Mobject>;
969
+ };
1063
970
  /**
1064
- * Validates and registers animation targets based on lifecycle.
1065
- * Handles composition animations (Sequence, Parallel) by processing children.
971
+ * Smoothly zoom the camera out by the given factor.
972
+ * Internally scales the frame up, which makes objects appear smaller.
973
+ *
974
+ * @param factor - Zoom multiplier. 2 = objects appear 2x smaller (default: 2)
975
+ * @returns FluentAnimation that can be chained with .duration() and .ease()
976
+ * @throws Error if factor is zero or negative
977
+ *
978
+ * @example
979
+ * // Zoom out 2x over 1 second
980
+ * this.play(this.frame.zoomOut(2).duration(1));
981
+ *
982
+ * @example
983
+ * // Zoom out to show more of the scene
984
+ * this.play(this.frame.zoomOut(4).duration(2).ease(easeOutCubic));
1066
985
  */
1067
- private validateAndRegisterAnimation;
986
+ zoomOut(factor?: number): this & {
987
+ toAnimation(): Animation<Mobject>;
988
+ };
1068
989
  /**
1069
- * Checks if a Mobject is in the scene.
1070
- * An object is "in scene" if:
1071
- * - It's directly registered in this.mobjects, OR
1072
- * - Any ancestor in its parent chain is registered
990
+ * Move the camera to center on a target Mobject.
991
+ * The camera will smoothly pan so the target is at the center of the frame.
1073
992
  *
1074
- * This respects the scene graph hierarchy - children of registered
1075
- * VGroups are implicitly in scene via their parent.
993
+ * @param target - The Mobject to center on
994
+ * @returns FluentAnimation that can be chained with .duration() and .ease()
995
+ * @throws Error if target is null or undefined
996
+ *
997
+ * @example
998
+ * // Center on a circle over 0.5 seconds
999
+ * this.play(this.frame.centerOn(circle).duration(0.5));
1000
+ *
1001
+ * @example
1002
+ * // Pan to focus on different objects in sequence
1003
+ * await this.play(this.frame.centerOn(obj1).duration(1));
1004
+ * await this.play(this.frame.centerOn(obj2).duration(1));
1076
1005
  */
1077
- isInScene(mobject: Mobject): boolean;
1006
+ centerOn(target: Mobject): this & {
1007
+ toAnimation(): Animation<Mobject>;
1008
+ };
1078
1009
  /**
1079
- * Gets children of composition animations (Sequence, Parallel).
1080
- * Returns empty array for non-composition animations.
1010
+ * Zoom in/out while keeping a specific world point fixed on screen.
1011
+ * Like pinch-to-zoom behavior where the pinch point stays stationary.
1012
+ *
1013
+ * Uses the formula: C' = P * (1 - factor) + C * factor
1014
+ * Where P = point, C = current center, factor = zoom factor.
1015
+ *
1016
+ * @param factor - Scale multiplier. Less than 1 for zoom in, greater than 1 for zoom out
1017
+ * @param point - World coordinates to keep fixed on screen
1018
+ * @returns Parallel animation combining move and scale
1019
+ * @throws Error if factor is zero or negative
1020
+ *
1021
+ * @example
1022
+ * // Zoom in 2x on a specific point
1023
+ * this.play(frame.zoomToPoint(0.5, { x: 5, y: 5 }).duration(1));
1024
+ *
1025
+ * @example
1026
+ * // Zoom out while keeping an object's position fixed
1027
+ * this.play(frame.zoomToPoint(2, circle.position).duration(1));
1081
1028
  */
1082
- private getAnimationChildren;
1029
+ zoomToPoint(factor: number, point: {
1030
+ x: number;
1031
+ y: number;
1032
+ }): Animation;
1083
1033
  /**
1084
- * Computes a holistic CRC32 hash for a segment.
1085
- * Includes camera state, all current mobjects, animations, and timing.
1034
+ * Automatically frame one or more objects with optional margin.
1035
+ * Calculates the bounding box of all targets and animates the camera
1036
+ * to show them all with the specified margin around them.
1037
+ *
1038
+ * @param targets - Single Mobject or array of Mobjects to frame
1039
+ * @param margin - Padding around the objects in world units (default: 0.5)
1040
+ * @returns FluentAnimation that can be chained with .duration() and .ease()
1041
+ * @throws Error if targets array is empty
1042
+ *
1043
+ * @example
1044
+ * // Fit a single object with default margin
1045
+ * this.play(this.frame.fitTo(circle).duration(1));
1046
+ *
1047
+ * @example
1048
+ * // Fit multiple objects with custom margin
1049
+ * this.play(this.frame.fitTo([obj1, obj2, obj3], 1.0).duration(1.5));
1050
+ *
1051
+ * @example
1052
+ * // Show all objects in the scene
1053
+ * this.play(this.frame.fitTo(allObjects, 0).duration(2));
1086
1054
  */
1087
- private computeSegmentHash;
1088
- }
1089
-
1090
- type PathCommandType = 'Move' | 'Line' | 'Quadratic' | 'Cubic' | 'Close';
1091
- interface PathCommand {
1092
- type: PathCommandType;
1093
- end: Vector2;
1094
- control1?: Vector2;
1095
- control2?: Vector2;
1096
- }
1097
-
1098
- /**
1099
- * A class representing a Bezier path, capable of storing standard path commands
1100
- * (move, line, quadratic curve, cubic curve, close).
1101
- */
1102
- declare class BezierPath {
1103
- private commands;
1104
- private currentPoint;
1105
- private startPoint;
1106
- private cachedLength;
1107
- private segmentLengths;
1108
- private segmentCDF;
1109
- /** Invalidates the cached length data. Called after any path modification. */
1110
- private invalidateCache;
1111
- /** Builds the cache if not already valid. */
1112
- private ensureCache;
1113
- /** Starts a new subpath at the specified point. */
1114
- moveTo(point: Vector2): void;
1115
- lineTo(point: Vector2): void;
1116
- quadraticTo(control: Vector2, end: Vector2): void;
1117
- cubicTo(control1: Vector2, control2: Vector2, end: Vector2): void;
1118
- closePath(): void;
1119
- getCommands(): PathCommand[];
1120
- getLength(): number;
1121
- /** Returns the point on the path at the normalized position t (0-1). */
1122
- getPointAt(t: number): Vector2;
1123
- getTangentAt(t: number): Vector2;
1124
- getPoints(count: number): Vector2[];
1125
- getPointCount(): number;
1126
- clone(): BezierPath;
1127
- /** Returns a new BezierPath where all segments are converted to Cubic curves. */
1128
- toCubic(): BezierPath;
1129
- static interpolate(path1: BezierPath, path2: BezierPath, t: number): BezierPath;
1130
- /** Matches the number of points/commands in two paths for morphing. */
1131
- static matchPoints(path1: BezierPath, path2: BezierPath): [BezierPath, BezierPath];
1132
- private static fromCommands;
1055
+ fitTo(targets: Mobject | Mobject[], margin?: number): this & {
1056
+ toAnimation(): Animation<Mobject>;
1057
+ };
1058
+ private calculateBounds;
1059
+ private hasGetBoundingBox;
1133
1060
  }
1134
1061
 
1135
1062
  /**
1136
- * A Mobject that is defined by one or more BezierPaths.
1137
- * Supports stroke and fill styling, plus VMobject-specific fluent animations.
1138
- *
1139
- * Default behavior: visible with white stroke, no fill.
1140
- * - Stroke: white, width 2 (visible by default)
1141
- * - Fill: not rendered by default (fillOpacity = 0)
1142
- *
1143
- * When .fill(color) is called, the default stroke is disabled unless
1144
- * .stroke(color, width) was called explicitly.
1145
- *
1146
- * Use .stroke(color, width) to add a stroke.
1147
- * Use .fill(color) to add a fill (opacity defaults to 1).
1063
+ * Configuration options for Camera.
1148
1064
  */
1149
- declare class VMobject extends Mobject {
1150
- protected pathList: BezierPath[];
1151
- /** Stroke color. Only rendered if strokeWidth > 0. */
1152
- protected strokeColor: Color;
1153
- /** Stroke width. Default 2 for visibility. */
1154
- protected strokeWidth: number;
1155
- /** Fill color. Only rendered if fillOpacity > 0. */
1156
- protected fillColor: Color;
1157
- /** Fill opacity. Default 0 means no fill is rendered. */
1158
- protected fillOpacity: number;
1159
- /** Tracks whether stroke() was explicitly called. */
1160
- protected strokeExplicitlySet: boolean;
1161
- constructor();
1162
- get paths(): BezierPath[];
1163
- set paths(value: BezierPath[]);
1164
- /**
1165
- * Gets the stroke color.
1166
- */
1167
- getStrokeColor(): Color;
1168
- /**
1169
- * Gets the stroke width.
1170
- */
1171
- getStrokeWidth(): number;
1172
- /**
1173
- * Gets the fill color.
1174
- */
1175
- getFillColor(): Color;
1176
- /**
1177
- * Gets the fill opacity.
1178
- */
1179
- getFillOpacity(): number;
1180
- /**
1181
- * Adds a new path to the VMobject.
1182
- * @param path - The BezierPath to add.
1183
- * @returns this for chaining.
1184
- */
1185
- addPath(path: BezierPath): this;
1186
- /**
1187
- * Sets the stroke color and width.
1188
- * @param color - The stroke color.
1189
- * @param width - The stroke width. Default is 2.
1190
- * @returns this for chaining.
1191
- */
1192
- stroke(color: Color, width?: number): this;
1065
+ interface CameraConfig {
1066
+ /** Pixel width for aspect ratio calculation. Default: 1920 */
1067
+ readonly pixelWidth?: number;
1068
+ /** Pixel height for aspect ratio calculation. Default: 1080 */
1069
+ readonly pixelHeight?: number;
1070
+ }
1071
+ /**
1072
+ * Resolved camera configuration with all defaults applied.
1073
+ */
1074
+ interface ResolvedCameraConfig {
1075
+ readonly pixelWidth: number;
1076
+ readonly pixelHeight: number;
1077
+ }
1078
+
1079
+ /**
1080
+ * Camera manages the view into the scene.
1081
+ * Uses CameraFrame (a Mobject) to store transform state, enabling camera animations.
1082
+ *
1083
+ * The Camera provides both instant manipulation methods (panTo, zoomTo) and
1084
+ * access to the CameraFrame for fluent animation APIs.
1085
+ *
1086
+ * @example
1087
+ * // Instant camera manipulation
1088
+ * camera.zoomTo(2);
1089
+ * camera.panTo(new Vector2(5, 3));
1090
+ *
1091
+ * @example
1092
+ * // Animated camera movement via frame
1093
+ * this.play(this.frame.zoomIn(2).duration(1));
1094
+ * this.play(this.frame.centerOn(circle).duration(0.5));
1095
+ */
1096
+ declare class Camera {
1097
+ private readonly config;
1098
+ /** The CameraFrame that stores the camera's transform state. Use this for animations. */
1099
+ readonly frame: CameraFrame;
1193
1100
  /**
1194
- * Sets the fill color and opacity.
1195
- * If stroke was not explicitly set, the default stroke is disabled.
1196
- * @param color - The fill color.
1197
- * @param opacity - The fill opacity. Defaults to the color's alpha value.
1198
- * @returns this for chaining.
1101
+ * Creates a new Camera with the specified viewport dimensions.
1102
+ *
1103
+ * @param config - Configuration options
1104
+ * @param config.pixelWidth - Width of the viewport in pixels (default: 1920)
1105
+ * @param config.pixelHeight - Height of the viewport in pixels (default: 1080)
1199
1106
  */
1200
- fill(color: Color, opacity?: number): this;
1201
- getPoints(): PathCommand[];
1202
- setPoints(commands: PathCommand[]): this;
1203
- private getPointsAsVectors;
1204
- getBoundingBox(): {
1205
- minX: number;
1206
- maxX: number;
1207
- minY: number;
1208
- maxY: number;
1209
- };
1107
+ constructor(config?: CameraConfig);
1108
+ get frameHeight(): number;
1109
+ get frameWidth(): number;
1110
+ get frameYRadius(): number;
1111
+ get frameXRadius(): number;
1112
+ get pixelWidth(): number;
1113
+ get pixelHeight(): number;
1114
+ get position(): Vector2;
1115
+ get zoom(): number;
1116
+ get rotation(): number;
1117
+ pan(delta: Vector2): this;
1118
+ panTo(position: Vector2): this;
1119
+ zoomTo(level: number): this;
1120
+ rotateTo(angle: number): this;
1121
+ getViewMatrix(): Matrix3x3;
1210
1122
  /**
1211
- * Progressively draws the VMobject's paths from start to end.
1212
- * Preserves fill throughout the animation.
1213
- * @param durationSeconds - Animation duration in seconds.
1214
- * @returns this for chaining.
1123
+ * Transforms a world-space position to screen-space (pixel) coordinates.
1124
+ *
1125
+ * Screen coordinates have origin at top-left, with x increasing right
1126
+ * and y increasing downward.
1127
+ *
1128
+ * @param pos - Position in world coordinates
1129
+ * @returns Position in screen coordinates (pixels)
1130
+ *
1131
+ * @example
1132
+ * const screenPos = camera.worldToScreen(circle.position);
1133
+ * console.log(`Circle is at pixel (${screenPos.x}, ${screenPos.y})`);
1215
1134
  */
1216
- write(durationSeconds?: number): this & {
1217
- toAnimation(): Animation<Mobject>;
1218
- };
1135
+ worldToScreen(pos: Vector2): Vector2;
1219
1136
  /**
1220
- * Progressively removes the VMobject's paths (reverse of write).
1221
- * @param durationSeconds - Animation duration in seconds.
1222
- * @returns this for chaining.
1137
+ * Transforms a screen-space (pixel) position to world coordinates.
1138
+ * This is the inverse of worldToScreen.
1139
+ *
1140
+ * @param pos - Position in screen coordinates (pixels, origin at top-left)
1141
+ * @returns Position in world coordinates
1142
+ *
1143
+ * @example
1144
+ * // Convert a mouse click position to world coordinates
1145
+ * const worldPos = camera.screenToWorld(new Vector2(mouseX, mouseY));
1223
1146
  */
1224
- unwrite(durationSeconds?: number): this & {
1225
- toAnimation(): Animation<Mobject>;
1226
- };
1147
+ screenToWorld(pos: Vector2): Vector2;
1227
1148
  /**
1228
- * First draws the stroke progressively (0-50%), then fades in the fill (50-100%).
1229
- * @param durationSeconds - Animation duration in seconds.
1230
- * @returns this for chaining.
1149
+ * Checks if a world-space position is currently visible within the camera frame.
1150
+ *
1151
+ * @param pos - Position in world coordinates to check
1152
+ * @returns True if the position is within the visible frame bounds
1153
+ *
1154
+ * @example
1155
+ * if (camera.isInView(object.position)) {
1156
+ * console.log('Object is visible');
1157
+ * }
1231
1158
  */
1232
- draw(durationSeconds?: number): this & {
1233
- toAnimation(): Animation<Mobject>;
1234
- };
1159
+ isInView(pos: Vector2): boolean;
1160
+ reset(): this;
1235
1161
  /**
1236
- * Extends parent hash with VMobject-specific state:
1237
- * stroke/fill colors, widths, opacity, and path geometry.
1162
+ * Hashes camera config and the CameraFrame's full transform state.
1238
1163
  */
1239
1164
  computeHash(): number;
1240
1165
  }
@@ -1297,665 +1222,708 @@ declare class VGroup extends VMobject {
1297
1222
  computeHash(): number;
1298
1223
  }
1299
1224
 
1300
- declare class Arc extends VMobject {
1301
- readonly radius: number;
1302
- readonly startAngle: number;
1303
- readonly endAngle: number;
1304
- constructor(radius?: number, startAngle?: number, endAngle?: number);
1305
- private generatePath;
1306
- }
1307
-
1308
- declare class Circle extends Arc {
1309
- constructor(radius?: number);
1310
- }
1311
-
1312
- declare class Line extends VMobject {
1313
- readonly start: Vector2;
1314
- readonly end: Vector2;
1315
- constructor(x1?: number, y1?: number, x2?: number, y2?: number);
1316
- private generatePath;
1317
- }
1318
-
1319
- declare class Polygon extends VMobject {
1320
- readonly vertices: Vector2[];
1321
- constructor(...points: Array<[number, number]>);
1322
- private generatePath;
1323
- }
1324
-
1325
- declare class Rectangle extends Polygon {
1326
- readonly width: number;
1327
- readonly height: number;
1328
- constructor(width?: number, height?: number);
1329
- }
1330
-
1331
- declare class Arrow extends Line {
1332
- readonly tipLength: number;
1333
- readonly tipAngle: number;
1334
- constructor(x1?: number, y1?: number, x2?: number, y2?: number, tipLength?: number, tipAngle?: number);
1335
- private addTip;
1336
- }
1337
-
1338
- /**
1339
- * A VMobject representing a single glyph character.
1340
- * Converts fontkit glyph path to BezierPath for rendering.
1341
- */
1342
- declare class Glyph extends VMobject {
1343
- readonly character: string;
1344
- readonly glyphId: number;
1345
- constructor(fontkitGlyph: Glyph$1, character: string, scale: number, offsetX: number, offsetY: number);
1346
- }
1347
-
1348
- /**
1349
- * A VGroup of vectorized glyphs created from a text string using fontkit.
1350
- * Each character becomes a Glyph VMobject that can be individually animated.
1351
- *
1352
- * Uses VMobject's fill/stroke as the source of truth (same as geometry).
1353
- * Default: white fill, white stroke width 2.
1354
- */
1355
- declare class Text extends VGroup {
1356
- readonly text: string;
1357
- private fontSize;
1358
- private fontPath;
1359
- constructor(text: string, fontPath?: string, options?: {
1360
- fontSize?: number;
1361
- });
1362
- private buildGlyphs;
1363
- /** Propagates this Text's fill/stroke to all Glyph children. */
1364
- private propagate;
1365
- stroke(color: Color, width?: number): this;
1366
- fill(color: Color, opacity?: number): this;
1367
- getFontSize(): number;
1368
- getGlyph(index: number): Glyph | undefined;
1369
- }
1370
-
1371
- /** Unique identifier for graph nodes. */
1372
- type GraphNodeId = string;
1373
- /** Configuration for creating a graph node. */
1374
- interface NodeConfig {
1375
- position?: {
1376
- x: number;
1377
- y: number;
1378
- };
1379
- radius?: number;
1380
- strokeColor?: Color;
1381
- strokeWidth?: number;
1382
- fillColor?: Color;
1383
- fillOpacity?: number;
1384
- }
1385
- /** Configuration for creating a graph edge. */
1386
- interface EdgeConfig {
1387
- strokeColor?: Color;
1388
- strokeWidth?: number;
1389
- curved?: boolean;
1390
- }
1391
- /** Supported layout algorithms. */
1392
- type LayoutType = 'force-directed' | 'tree' | 'circular';
1393
- /** Configuration for graph layout algorithms. */
1394
- interface LayoutConfig {
1395
- radius?: number;
1396
- levelHeight?: number;
1397
- siblingSpacing?: number;
1398
- iterations?: number;
1399
- springLength?: number;
1400
- repulsion?: number;
1401
- attraction?: number;
1402
- damping?: number;
1403
- minDistance?: number;
1404
- }
1405
-
1406
1225
  /**
1407
- * A graph node represented as a circular VMobject.
1408
- * Supports customizable radius, stroke, and fill styling.
1226
+ * Abstract base class for all animations.
1227
+ * Provides configuration for duration, easing, and delay.
1228
+ * Subclasses must specify their lifecycle category.
1409
1229
  */
1410
- declare class GraphNode extends VMobject {
1411
- readonly id: GraphNodeId;
1412
- private nodeRadius;
1413
- constructor(id: GraphNodeId, config?: NodeConfig);
1414
- get radius(): number;
1230
+ declare abstract class Animation<T extends Mobject = Mobject> {
1231
+ protected readonly target: T;
1232
+ protected durationSeconds: number;
1233
+ protected easingFn: EasingFunction;
1234
+ protected delaySeconds: number;
1235
+ /**
1236
+ * The lifecycle category of this animation.
1237
+ * Determines how Scene.play() handles scene registration and validation.
1238
+ */
1239
+ abstract readonly lifecycle: AnimationLifecycle;
1240
+ constructor(target: T);
1241
+ duration(seconds: number): this;
1242
+ ease(easing: EasingFunction): this;
1243
+ delay(seconds: number): this;
1244
+ getDuration(): number;
1245
+ getDelay(): number;
1246
+ getEasing(): EasingFunction;
1247
+ getTarget(): T;
1248
+ getConfig(): AnimationConfig;
1249
+ abstract interpolate(progress: number): void;
1415
1250
  /**
1416
- * Generates a circular BezierPath approximation using cubic Bezier curves.
1417
- * Uses the standard 4-point circle approximation with control point factor ~0.5523.
1251
+ * Ensures the animation is initialized before interpolation.
1252
+ * Called before first update to capture start state.
1253
+ * Default: no-op. Override in subclasses that need lazy initialization.
1418
1254
  */
1419
- private generateCirclePath;
1420
- getCenter(): Vector2;
1421
- }
1422
-
1423
- /**
1424
- * A graph edge represented as a BezierPath connecting two nodes.
1425
- * Supports straight or curved edges with customizable styling.
1426
- */
1427
- declare class GraphEdge extends VMobject {
1428
- readonly source: GraphNodeId;
1429
- readonly target: GraphNodeId;
1430
- private sourceNode;
1431
- private targetNode;
1432
- private curved;
1433
- constructor(sourceNode: GraphNode, targetNode: GraphNode, config?: EdgeConfig);
1255
+ ensureInitialized(): void;
1434
1256
  /**
1435
- * Recalculates the edge path based on current node positions.
1436
- * Call this when nodes move to update the edge connection.
1257
+ * Resets the animation to its uninitialized state.
1258
+ * Allows animations to be replayed or looped.
1437
1259
  */
1438
- updatePath(): void;
1439
- getPath(): BezierPath | undefined;
1260
+ reset(): void;
1261
+ update(progress: number): void;
1440
1262
  /**
1441
- * Updates node references (used when nodes are replaced).
1263
+ * Hashes the animation type, config, and target state.
1264
+ * Subclass-specific behavior is captured through the target's hash,
1265
+ * since animations mutate the target.
1442
1266
  */
1443
- setNodes(sourceNode: GraphNode, targetNode: GraphNode): void;
1267
+ computeHash(): number;
1444
1268
  }
1445
1269
 
1446
1270
  /**
1447
- * A graph structure containing nodes and edges.
1448
- * Manages nodes as VMobjects and edges as BezierPath curves.
1449
- * Supports multiple layout algorithms for automatic positioning.
1271
+ * Animation that morphs a VMobject from its current shape to a target shape.
1272
+ * Uses BezierPath interpolation for smooth path transitions.
1273
+ *
1274
+ * This is a transformative animation - the source must already be in the scene.
1275
+ * The target VMobject is used only as a shape template and is NOT added to the scene.
1276
+ * Source paths are captured lazily when animation becomes active.
1277
+ *
1278
+ * @example
1279
+ * scene.add(circle);
1280
+ * scene.play(new MorphTo(circle, square)); // circle morphs into square's shape
1450
1281
  */
1451
- declare class Graph extends VGroup {
1452
- private nodes;
1453
- private edges;
1454
- constructor();
1455
- /** Adds a node to the graph. */
1456
- addNode(id: GraphNodeId, config?: NodeConfig): GraphNode;
1457
- /** Removes a node and all connected edges from the graph. */
1458
- removeNode(id: GraphNodeId): this;
1459
- getNode(id: GraphNodeId): GraphNode | undefined;
1460
- getNodes(): GraphNode[];
1461
- addEdge(sourceId: GraphNodeId, targetId: GraphNodeId, config?: EdgeConfig): GraphEdge | undefined;
1462
- removeEdge(sourceId: GraphNodeId, targetId: GraphNodeId): this;
1463
- private removeEdgeInternal;
1464
- getEdgePath(sourceId: GraphNodeId, targetId: GraphNodeId): ReturnType<GraphEdge['getPath']>;
1465
- getEdges(): GraphEdge[];
1466
- /** Applies a layout algorithm to reposition all nodes. */
1467
- layout(type: LayoutType, config?: LayoutConfig): this;
1468
- updateEdges(): this;
1282
+ declare class MorphTo<T extends VMobject = VMobject> extends TransformativeAnimation<T> {
1283
+ private sourcePaths;
1284
+ private readonly targetPaths;
1285
+ constructor(source: T, target: VMobject);
1286
+ protected captureStartState(): void;
1287
+ interpolate(progress: number): void;
1288
+ private getEmptyPath;
1469
1289
  }
1470
1290
 
1471
1291
  /**
1472
- * Abstract base class for animations that introduce an object to the scene.
1473
- *
1474
- * Introductory animations:
1475
- * - Automatically register the target with the scene if not already present
1476
- * - Do not require the target to be in the scene beforehand
1477
- * - Typically animate opacity or drawing from 0 to visible
1478
- *
1479
- * Examples: FadeIn, Write, Draw, GrowFromCenter, SpinIn
1292
+ * Supported value types for keyframe interpolation.
1480
1293
  */
1481
- declare abstract class IntroductoryAnimation<T extends Mobject = Mobject> extends Animation<T> {
1482
- readonly lifecycle: AnimationLifecycle;
1294
+ type KeyframeValue = number;
1295
+ /**
1296
+ * A single keyframe with a normalized time position [0,1] and value.
1297
+ */
1298
+ interface Keyframe<T extends KeyframeValue = KeyframeValue> {
1299
+ /** Normalized time position in [0, 1]. */
1300
+ readonly time: number;
1301
+ /** The value at this keyframe. */
1302
+ readonly value: T;
1303
+ /** Optional easing function for interpolation TO this keyframe. */
1304
+ readonly easing?: EasingFunction;
1483
1305
  }
1306
+ /**
1307
+ * Interpolation function for a specific value type.
1308
+ * Takes start value, end value, and progress [0,1], returns interpolated value.
1309
+ */
1310
+ type InterpolatorFn<T> = (start: T, end: T, progress: number) => T;
1484
1311
 
1485
1312
  /**
1486
- * Abstract base class for animations that transform an existing scene object.
1487
- *
1488
- * Transformative animations:
1489
- * - Require the target to already be registered with the scene
1490
- * - Throw an error if the target is not in the scene
1491
- * - Operate on objects that are already visible or have been introduced
1492
- * - Use lazy initialization to capture start state when animation becomes active
1493
- *
1494
- * Examples: MoveTo, Rotate, Scale, MorphTo, Transform
1313
+ * Manages a sequence of keyframes for animating a single property.
1314
+ * Keyframes are stored sorted by time and interpolated on demand.
1495
1315
  */
1496
- declare abstract class TransformativeAnimation<T extends Mobject = Mobject> extends Animation<T> {
1497
- readonly lifecycle: AnimationLifecycle;
1498
- protected initialized: boolean;
1316
+ declare class KeyframeTrack<T extends KeyframeValue = number> {
1317
+ private keyframes;
1318
+ private readonly interpolator;
1499
1319
  /**
1500
- * Captures the start state from the target.
1501
- * Called once when the animation first becomes active.
1320
+ * Creates a new KeyframeTrack with the specified interpolator.
1321
+ * Defaults to linear number interpolation.
1502
1322
  */
1503
- protected abstract captureStartState(): void;
1504
- ensureInitialized(): void;
1505
- reset(): void;
1323
+ constructor(interpolator?: InterpolatorFn<T>);
1324
+ /**
1325
+ * Adds a keyframe at the specified normalized time.
1326
+ * Time must be in [0, 1]. Replaces existing keyframe at same time.
1327
+ */
1328
+ addKeyframe(time: number, value: T, easing?: EasingFunction): this;
1329
+ removeKeyframe(time: number): boolean;
1330
+ /**
1331
+ * Gets the keyframe at the specified time.
1332
+ * Returns undefined if no keyframe exists at that time.
1333
+ */
1334
+ getKeyframe(time: number): Keyframe<T> | undefined;
1335
+ /** All keyframes sorted by time. */
1336
+ getKeyframes(): ReadonlyArray<Keyframe<T>>;
1337
+ /** Interpolated value at normalized time (uses target keyframe easing). */
1338
+ getValueAt(time: number): T;
1339
+ getKeyframeCount(): number;
1506
1340
  }
1507
1341
 
1508
1342
  /**
1509
- * Abstract base class for animations that exit/remove an object from the scene.
1510
- *
1511
- * Exit animations:
1512
- * - Require the target to already be registered with the scene
1513
- * - Throw an error if the target is not in the scene
1514
- * - Typically animate opacity or scale to 0
1515
- * - May optionally auto-remove the target from the scene after completion
1516
- *
1517
- * Examples: FadeOut, ShrinkToCenter, Uncreate
1343
+ * Property setter function type for applying values to a Mobject.
1518
1344
  */
1519
- declare abstract class ExitAnimation<T extends Mobject = Mobject> extends Animation<T> {
1520
- readonly lifecycle: AnimationLifecycle;
1521
- }
1522
-
1345
+ type PropertySetter<T extends Mobject, V> = (target: T, value: V) => void;
1523
1346
  /**
1524
- * Animation that fades a Mobject in by increasing its opacity from 0 to 1.
1525
- *
1526
- * This is an introductory animation - it auto-registers the target with the scene.
1527
- * You do not need to call scene.add() before using FadeIn.
1347
+ * Animation that interpolates multiple property tracks via keyframes.
1348
+ * Each track controls a single property and is interpolated independently.
1528
1349
  *
1529
- * @example
1530
- * const circle = new Circle(1);
1531
- * scene.play(new FadeIn(circle)); // Circle is auto-registered and faded in
1350
+ * This is a transformative animation - the target must already be in the scene.
1532
1351
  */
1533
- declare class FadeIn<T extends Mobject = Mobject> extends IntroductoryAnimation<T> {
1534
- private readonly startOpacity;
1535
- constructor(target: T);
1352
+ declare class KeyframeAnimation<T extends Mobject = Mobject> extends Animation<T> {
1353
+ private readonly tracks;
1354
+ readonly lifecycle: AnimationLifecycle;
1355
+ /**
1356
+ * Adds a named keyframe track with its property setter.
1357
+ * The setter is called during interpolation to apply values to the target.
1358
+ */
1359
+ addTrack<V extends KeyframeValue>(name: string, track: KeyframeTrack<V>, setter: PropertySetter<T, V>): this;
1360
+ /** Gets a track by name. */
1361
+ getTrack<V extends KeyframeValue>(name: string): KeyframeTrack<V> | undefined;
1362
+ /** All track names. */
1363
+ getTrackNames(): string[];
1364
+ /**
1365
+ * Interpolates all tracks at the given progress and applies values to target.
1366
+ */
1536
1367
  interpolate(progress: number): void;
1537
1368
  }
1538
1369
 
1539
1370
  /**
1540
- * Animation that fades a Mobject out by decreasing its opacity to 0.
1541
- *
1542
- * This is an exit animation - the target must already be in the scene.
1543
- * The starting opacity is captured when the animation first runs,
1544
- * not when it's constructed, so it correctly fades from the current opacity.
1545
- *
1546
- * @example
1547
- * scene.add(circle);
1548
- * scene.play(new FadeOut(circle)); // Circle fades out
1371
+ * Configuration options for the Follow animation.
1549
1372
  */
1550
- declare class FadeOut<T extends Mobject = Mobject> extends ExitAnimation<T> {
1551
- private startOpacity;
1552
- interpolate(progress: number): void;
1373
+ interface FollowConfig {
1374
+ /**
1375
+ * Offset from the target's position. The camera will track
1376
+ * (target.position + offset) instead of the exact target position.
1377
+ * @default Vector2.ZERO
1378
+ */
1379
+ offset?: Vector2;
1380
+ /**
1381
+ * Damping factor for smooth following (0 to 1).
1382
+ * - 0 = instant snap to target (no smoothing)
1383
+ * - 0.9 = very smooth, slow following
1384
+ * Higher values create a more "laggy" camera that takes longer to catch up.
1385
+ * @default 0
1386
+ */
1387
+ damping?: number;
1553
1388
  }
1554
-
1555
1389
  /**
1556
- * Animation that moves a Mobject from its current position to a destination.
1557
- * Uses linear interpolation between start and end positions.
1558
- *
1559
- * This is a transformative animation - the target must already be in the scene.
1560
- * Start position is captured lazily when animation becomes active.
1390
+ * Animation that makes a CameraFrame track a target Mobject's position over time.
1391
+ * Unlike MoveTo which captures position once, Follow reads the target position
1392
+ * every frame, allowing the camera to track moving objects.
1561
1393
  *
1562
1394
  * @example
1563
- * scene.add(circle); // or use FadeIn first
1564
- * scene.play(new MoveTo(circle, 2, 0)); // Move to (2, 0)
1565
- */
1566
- declare class MoveTo<T extends Mobject = Mobject> extends TransformativeAnimation<T> {
1567
- private startPosition;
1568
- private readonly endPosition;
1569
- constructor(target: T, destination: Vector2);
1570
- constructor(target: T, x: number, y: number);
1571
- protected captureStartState(): void;
1572
- interpolate(progress: number): void;
1573
- /** Returns the target position of the move animation. */
1574
- getDestination(): Vector2;
1575
- }
1576
-
1577
- /**
1578
- * Animation that rotates a Mobject by a specified angle.
1579
- * Uses linear interpolation between start and end rotation.
1395
+ * // Basic follow - camera snaps to target position
1396
+ * this.play(new Follow(this.frame, movingCircle).duration(5));
1580
1397
  *
1581
- * This is a transformative animation - the target must already be in the scene.
1582
- * Start rotation is captured lazily when animation becomes active.
1398
+ * @example
1399
+ * // Smooth follow with damping
1400
+ * this.play(new Follow(this.frame, player, { damping: 0.8 }).duration(10));
1583
1401
  *
1584
1402
  * @example
1585
- * scene.add(square);
1586
- * scene.play(new Rotate(square, Math.PI / 4)); // Rotate 45 degrees
1403
+ * // Follow with offset (camera leads the target)
1404
+ * this.play(new Follow(this.frame, car, {
1405
+ * offset: new Vector2(2, 0), // Camera 2 units ahead
1406
+ * damping: 0.5
1407
+ * }).duration(10));
1587
1408
  */
1588
- declare class Rotate<T extends Mobject = Mobject> extends TransformativeAnimation<T> {
1589
- private startRotation;
1590
- private endRotation;
1591
- private readonly angle;
1592
- constructor(target: T, angle: number);
1593
- protected captureStartState(): void;
1409
+ declare class Follow extends Animation<CameraFrame> {
1410
+ readonly lifecycle: AnimationLifecycle;
1411
+ private readonly followTarget;
1412
+ private readonly offset;
1413
+ private readonly damping;
1414
+ /**
1415
+ * Creates a new Follow animation.
1416
+ *
1417
+ * @param frame - The CameraFrame to animate
1418
+ * @param target - The Mobject to follow
1419
+ * @param config - Configuration options
1420
+ * @throws Error if frame is null or undefined
1421
+ * @throws Error if target is null or undefined
1422
+ *
1423
+ * @example
1424
+ * const follow = new Follow(scene.frame, player, { damping: 0.7 });
1425
+ * this.play(follow.duration(10));
1426
+ */
1427
+ constructor(frame: CameraFrame, target: Mobject, config?: FollowConfig);
1428
+ /**
1429
+ * Updates the camera position each frame to track the target.
1430
+ * @param progress - Animation progress (0 to 1)
1431
+ */
1594
1432
  interpolate(progress: number): void;
1595
- /** Returns the total rotation angle in radians. */
1596
- getAngle(): number;
1597
1433
  }
1598
1434
 
1599
1435
  /**
1600
- * Animation that scales a Mobject to a target scale factor.
1601
- * Uses linear interpolation between start and end scale.
1602
- *
1603
- * This is a transformative animation - the target must already be in the scene.
1604
- * Start scale is captured lazily when animation becomes active.
1605
- *
1606
- * @example
1607
- * scene.add(circle);
1608
- * scene.play(new Scale(circle, 2)); // Scale to 2x
1436
+ * Configuration options for the Shake animation.
1609
1437
  */
1610
- declare class Scale<T extends Mobject = Mobject> extends TransformativeAnimation<T> {
1611
- private startScale;
1612
- private readonly endScale;
1613
- constructor(target: T, factor: number);
1614
- constructor(target: T, factorX: number, factorY: number);
1615
- protected captureStartState(): void;
1616
- interpolate(progress: number): void;
1617
- /** Returns the scale factor. */
1618
- getFactor(): number;
1438
+ interface ShakeConfig {
1439
+ /**
1440
+ * Maximum displacement distance in world units.
1441
+ * Higher values create more violent shaking.
1442
+ * @default 0.2
1443
+ */
1444
+ intensity?: number;
1445
+ /**
1446
+ * Number of oscillations per second.
1447
+ * Higher values create faster, more frantic shaking.
1448
+ * @default 10
1449
+ */
1450
+ frequency?: number;
1451
+ /**
1452
+ * Controls how quickly the shake diminishes over time.
1453
+ * - 0 = no decay (constant intensity throughout)
1454
+ * - 1 = linear decay
1455
+ * - Higher values = faster decay (shake fades quickly)
1456
+ * @default 1
1457
+ */
1458
+ decay?: number;
1619
1459
  }
1620
-
1621
1460
  /**
1622
- * Animation that morphs a VMobject from its current shape to a target shape.
1623
- * Uses BezierPath interpolation for smooth path transitions.
1461
+ * Camera shake effect animation.
1462
+ * Creates procedural displacement using layered sine waves to simulate
1463
+ * impacts, explosions, or earthquakes.
1624
1464
  *
1625
- * This is a transformative animation - the source must already be in the scene.
1626
- * The target VMobject is used only as a shape template and is NOT added to the scene.
1627
- * Source paths are captured lazily when animation becomes active.
1465
+ * The shake automatically returns to the original position when complete.
1628
1466
  *
1629
1467
  * @example
1630
- * scene.add(circle);
1631
- * scene.play(new MorphTo(circle, square)); // circle morphs into square's shape
1468
+ * // Basic shake effect
1469
+ * this.play(new Shake(this.frame).duration(0.5));
1470
+ *
1471
+ * @example
1472
+ * // Intense explosion shake with quick decay
1473
+ * this.play(new Shake(this.frame, {
1474
+ * intensity: 0.5,
1475
+ * frequency: 20,
1476
+ * decay: 2
1477
+ * }).duration(0.3));
1478
+ *
1479
+ * @example
1480
+ * // Subtle earthquake with slow decay
1481
+ * this.play(new Shake(this.frame, {
1482
+ * intensity: 0.1,
1483
+ * frequency: 5,
1484
+ * decay: 0.5
1485
+ * }).duration(3));
1632
1486
  */
1633
- declare class MorphTo<T extends VMobject = VMobject> extends TransformativeAnimation<T> {
1634
- private sourcePaths;
1635
- private readonly targetPaths;
1636
- constructor(source: T, target: VMobject);
1487
+ declare class Shake extends TransformativeAnimation<CameraFrame> {
1488
+ private originalPosition;
1489
+ private readonly intensity;
1490
+ private readonly frequency;
1491
+ private readonly decay;
1492
+ private readonly seedX;
1493
+ private readonly seedY;
1494
+ /**
1495
+ * Creates a new Shake animation.
1496
+ *
1497
+ * @param frame - The CameraFrame to shake
1498
+ * @param config - Configuration options for intensity, frequency, and decay
1499
+ *
1500
+ * @example
1501
+ * const shake = new Shake(scene.frame, { intensity: 0.3 });
1502
+ * this.play(shake.duration(0.5));
1503
+ */
1504
+ constructor(frame: CameraFrame, config?: ShakeConfig);
1505
+ /**
1506
+ * Captures the original position before shake begins.
1507
+ */
1637
1508
  protected captureStartState(): void;
1509
+ /**
1510
+ * Applies procedural shake displacement each frame.
1511
+ * @param progress - Animation progress (0 to 1)
1512
+ */
1638
1513
  interpolate(progress: number): void;
1639
- private getEmptyPath;
1514
+ /**
1515
+ * Generates pseudo-random noise using layered sine waves.
1516
+ * @param t - Time value
1517
+ * @param seed - Random seed for variation
1518
+ * @returns Noise value between -1 and 1
1519
+ */
1520
+ private noise;
1640
1521
  }
1641
1522
 
1642
1523
  /**
1643
- * Animation that first draws the stroke progressively, then fades in the fill.
1644
- * - First 50%: stroke draws progressively
1645
- * - Second 50%: fill fades in
1646
- *
1647
- * - Single VMobject: stroke then fill
1648
- * - VGroup: all children animate together
1649
- * - Text (VGroup of Glyphs): Glyphs animate sequentially for handwriting effect
1650
- *
1651
- * This is an introductory animation - it auto-registers the target with the scene.
1524
+ * Represents an animation scheduled at a specific time on the Timeline.
1652
1525
  */
1653
- declare class Draw<T extends VMobject = VMobject> extends IntroductoryAnimation<T> {
1654
- private readonly originalPaths;
1655
- private readonly originalOpacity;
1656
- private readonly originalStrokeColor;
1657
- private readonly originalStrokeWidth;
1658
- private readonly originalFillColor;
1659
- private readonly originalFillOpacity;
1660
- private readonly childStates;
1661
- /** Glyph states for Text children, keyed by the Text VMobject reference. */
1662
- private readonly glyphStates;
1663
- constructor(target: T);
1664
- private createState;
1665
- interpolate(progress: number): void;
1666
- private interpolateVGroup;
1667
- private interpolateGlyphs;
1668
- /** Interpolates a single VMobject: stroke (0-0.5), then fill (0.5-1). */
1669
- private interpolateVMobject;
1526
+ interface ScheduledAnimation {
1527
+ /** The animation to play */
1528
+ readonly animation: Animation;
1529
+ /** Start time in seconds from timeline beginning */
1530
+ readonly startTime: number;
1670
1531
  }
1671
-
1672
1532
  /**
1673
- * Animation that progressively draws VMobject paths from start to end.
1674
- *
1675
- * - Single VMobject: paths draw progressively
1676
- * - VGroup: all children animate together with same progress
1677
- * - Text (VGroup of Glyphs): Glyphs animate sequentially for handwriting effect
1678
- *
1679
- * This is an introductory animation - it auto-registers the target with the scene.
1533
+ * Configuration options for Timeline.
1680
1534
  */
1681
- declare class Write<T extends VMobject = VMobject> extends IntroductoryAnimation<T> {
1682
- private readonly originalPaths;
1683
- private readonly originalOpacity;
1684
- private readonly originalStrokeColor;
1685
- private readonly originalStrokeWidth;
1686
- private readonly originalFillColor;
1687
- private readonly originalFillOpacity;
1688
- private readonly childStates;
1689
- /** Glyph states for Text children, keyed by the Text VMobject reference. */
1690
- private readonly glyphStates;
1691
- constructor(target: T);
1692
- private createState;
1693
- interpolate(progress: number): void;
1694
- private interpolateVGroup;
1695
- private interpolateGlyphs;
1696
- /** Applies progress to a single VMobject, updating its paths and style. */
1697
- private applyProgress;
1535
+ interface TimelineConfig {
1536
+ /** Whether the timeline loops. Default: false */
1537
+ readonly loop?: boolean;
1698
1538
  }
1699
1539
 
1700
1540
  /**
1701
- * Animation that progressively removes a VMobject by erasing the path.
1702
- * Reverse of Write animation - at progress 0, full object is visible;
1703
- * at progress 1, nothing is visible.
1704
- *
1705
- * Supports VGroup (including Text): animates each child's paths progressively.
1706
- *
1707
- * This is an exit animation - the target must already be in the scene.
1708
- *
1709
- * @example
1710
- * scene.play(new Write(text));
1711
- * scene.play(new Unwrite(text)); // Text is erased progressively
1541
+ * Timeline schedules and controls playback of animations.
1542
+ * Animations can be scheduled at specific times and the timeline
1543
+ * provides seek/state access for non-linear playback.
1712
1544
  */
1713
- declare class Unwrite<T extends VMobject = VMobject> extends ExitAnimation<T> {
1714
- private readonly isVGroup;
1715
- /** For non-VGroup targets: original paths on the target itself. */
1716
- private readonly originalPaths;
1717
- private readonly originalOpacity;
1718
- private readonly originalFillOpacity;
1719
- /** For VGroup targets: original state of each child. */
1720
- private readonly childStates;
1721
- constructor(target: T);
1722
- interpolate(progress: number): void;
1723
- /** Interpolates a single VMobject (non-VGroup). */
1724
- private interpolateVMobject;
1725
- /** Interpolates a VGroup by animating each child's paths. */
1726
- private interpolateVGroup;
1545
+ declare class Timeline {
1546
+ private readonly scheduled;
1547
+ private readonly config;
1548
+ private currentTime;
1549
+ constructor(config?: TimelineConfig);
1550
+ /**
1551
+ * Schedule an animation to start at a specific time.
1552
+ * @param animation The animation to schedule
1553
+ * @param startTime Start time in seconds (default: 0)
1554
+ */
1555
+ schedule(animation: Animation, startTime?: number): this;
1556
+ /**
1557
+ * Schedule multiple animations to play in sequence.
1558
+ * First animation starts at the given startTime, subsequent
1559
+ * animations start after the previous one ends.
1560
+ * @param animations Animations to schedule sequentially
1561
+ * @param startTime Start time for the first animation (default: 0)
1562
+ */
1563
+ scheduleSequence(animations: Animation[], startTime?: number): this;
1564
+ /**
1565
+ * Schedule multiple animations to play in parallel.
1566
+ * All animations start at the same time.
1567
+ * @param animations Animations to schedule in parallel
1568
+ * @param startTime Start time for all animations (default: 0)
1569
+ */
1570
+ scheduleParallel(animations: Animation[], startTime?: number): this;
1571
+ /**
1572
+ * Get all scheduled animations with resolved timing information.
1573
+ */
1574
+ private getResolved;
1575
+ /**
1576
+ * Get total duration of the timeline.
1577
+ * Returns the end time of the last animation to finish.
1578
+ */
1579
+ getTotalDuration(): number;
1580
+ /**
1581
+ * Seek to a specific time and update all animations.
1582
+ * @param time Time in seconds to seek to
1583
+ */
1584
+ seek(time: number): void;
1585
+ /**
1586
+ * Get the timeline state at a specific time without modifying the
1587
+ * current playhead position.
1588
+ * @param time Time in seconds
1589
+ */
1590
+ getStateAt(time: number): void;
1591
+ /**
1592
+ * Get the current time of the timeline.
1593
+ */
1594
+ getCurrentTime(): number;
1595
+ /**
1596
+ * Get all scheduled animations.
1597
+ */
1598
+ getScheduled(): readonly ScheduledAnimation[];
1599
+ /**
1600
+ * Check if timeline is configured to loop.
1601
+ */
1602
+ isLooping(): boolean;
1603
+ /**
1604
+ * Clear all scheduled animations.
1605
+ */
1606
+ clear(): void;
1727
1607
  }
1728
1608
 
1729
1609
  /**
1730
- * Supported value types for keyframe interpolation.
1731
- */
1732
- type KeyframeValue = number;
1733
- /**
1734
- * A single keyframe with a normalized time position [0,1] and value.
1610
+ * Configuration options for Scene.
1735
1611
  */
1736
- interface Keyframe<T extends KeyframeValue = KeyframeValue> {
1737
- /** Normalized time position in [0, 1]. */
1738
- readonly time: number;
1739
- /** The value at this keyframe. */
1740
- readonly value: T;
1741
- /** Optional easing function for interpolation TO this keyframe. */
1742
- readonly easing?: EasingFunction;
1612
+ interface SceneConfig {
1613
+ /** Pixel width of the scene. Default: 1920 */
1614
+ readonly width?: number;
1615
+ /** Pixel height of the scene. Default: 1080 */
1616
+ readonly height?: number;
1617
+ /** Background color. Default: BLACK */
1618
+ readonly backgroundColor?: Color;
1619
+ /** Frames per second. Default: 60 */
1620
+ readonly frameRate?: number;
1743
1621
  }
1622
+
1744
1623
  /**
1745
- * Interpolation function for a specific value type.
1746
- * Takes start value, end value, and progress [0,1], returns interpolated value.
1624
+ * A Segment represents one independent rendering unit,
1625
+ * corresponding to a single play() or wait() call.
1626
+ *
1627
+ * Its hash is a holistic CRC32 composition of the camera state,
1628
+ * all current mobjects, and the animations for this segment.
1747
1629
  */
1748
- type InterpolatorFn<T> = (start: T, end: T, progress: number) => T;
1630
+ interface Segment {
1631
+ /** Zero-based index in the scene's segment list. */
1632
+ readonly index: number;
1633
+ /** Start time in seconds. */
1634
+ readonly startTime: number;
1635
+ /** End time in seconds. */
1636
+ readonly endTime: number;
1637
+ /** Animations scheduled in this segment (empty for wait segments). */
1638
+ readonly animations: readonly Animation[];
1639
+ /** CRC32 hash of camera + mobjects + animations at this point. */
1640
+ readonly hash: number;
1641
+ }
1749
1642
 
1750
1643
  /**
1751
- * Manages a sequence of keyframes for animating a single property.
1752
- * Keyframes are stored sorted by time and interpolated on demand.
1644
+ * Scene is the core container that manages Mobjects and coordinates animations.
1645
+ * It provides both a simple API for playing animations and access to the
1646
+ * underlying Timeline and Camera for advanced control.
1753
1647
  */
1754
- declare class KeyframeTrack<T extends KeyframeValue = number> {
1755
- private keyframes;
1756
- private readonly interpolator;
1648
+ declare class Scene {
1649
+ private readonly config;
1650
+ private readonly mobjects;
1651
+ private readonly timeline;
1652
+ private readonly _camera;
1653
+ private readonly segmentList;
1654
+ private playheadTime;
1655
+ constructor(config?: SceneConfig);
1656
+ get camera(): Camera;
1657
+ get frame(): CameraFrame;
1658
+ /** Get scene width in pixels. */
1659
+ getWidth(): number;
1660
+ /** Get scene height in pixels. */
1661
+ getHeight(): number;
1662
+ /** Get scene background color. */
1663
+ getBackgroundColor(): Color;
1664
+ /** Get scene frame rate. */
1665
+ getFrameRate(): number;
1757
1666
  /**
1758
- * Creates a new KeyframeTrack with the specified interpolator.
1759
- * Defaults to linear number interpolation.
1667
+ * Add mobjects to the scene and make them immediately visible.
1668
+ * Use this for static elements or backgrounds that should be visible
1669
+ * before any animations begin.
1760
1670
  */
1761
- constructor(interpolator?: InterpolatorFn<T>);
1671
+ add(...mobjects: Mobject[]): this;
1762
1672
  /**
1763
- * Adds a keyframe at the specified normalized time.
1764
- * Time must be in [0, 1]. Replaces existing keyframe at same time.
1673
+ * Remove mobjects from the scene.
1765
1674
  */
1766
- addKeyframe(time: number, value: T, easing?: EasingFunction): this;
1767
- removeKeyframe(time: number): boolean;
1675
+ remove(...mobjects: Mobject[]): this;
1768
1676
  /**
1769
- * Gets the keyframe at the specified time.
1770
- * Returns undefined if no keyframe exists at that time.
1677
+ * Check if a mobject is registered with this scene.
1771
1678
  */
1772
- getKeyframe(time: number): Keyframe<T> | undefined;
1773
- /** All keyframes sorted by time. */
1774
- getKeyframes(): ReadonlyArray<Keyframe<T>>;
1775
- /** Interpolated value at normalized time (uses target keyframe easing). */
1776
- getValueAt(time: number): T;
1777
- getKeyframeCount(): number;
1679
+ has(mobject: Mobject): boolean;
1680
+ /**
1681
+ * Get all mobjects in the scene.
1682
+ */
1683
+ getMobjects(): readonly Mobject[];
1684
+ /**
1685
+ * Schedule animations to play at the current playhead position.
1686
+ *
1687
+ * Accepts either Animation objects or Mobjects with queued fluent animations.
1688
+ * When a Mobject is passed, its queued animation chain is automatically extracted.
1689
+ *
1690
+ * - Introductory animations (FadeIn, Create, Draw, Write) auto-register
1691
+ * their targets with the scene if not already present.
1692
+ * - Transformative animations (MoveTo, Rotate, Scale) require the target
1693
+ * to already be in the scene, otherwise an error is thrown.
1694
+ *
1695
+ * @example
1696
+ * // ProAPI style
1697
+ * this.play(new FadeIn(circle), new MoveTo(rect, 2, 0));
1698
+ *
1699
+ * // FluentAPI style
1700
+ * circle.fadeIn(1).moveTo(2, 0, 1);
1701
+ * this.play(circle);
1702
+ *
1703
+ * // Mixed
1704
+ * circle.fadeIn(1);
1705
+ * this.play(circle, new FadeIn(rect));
1706
+ */
1707
+ play(...items: Array<Animation | Mobject>): this;
1708
+ /**
1709
+ * Add a delay before the next play() call.
1710
+ * @param seconds Number of seconds to wait
1711
+ */
1712
+ wait(seconds: number): this;
1713
+ /**
1714
+ * Get the current playhead time.
1715
+ */
1716
+ getCurrentTime(): number;
1717
+ /**
1718
+ * Get the total duration of all scheduled animations.
1719
+ */
1720
+ getTotalDuration(): number;
1721
+ /**
1722
+ * Get the underlying Timeline for advanced control.
1723
+ * Use this for direct manipulation of animation timing.
1724
+ */
1725
+ getTimeline(): Timeline;
1726
+ /**
1727
+ * Get the Camera for view control and frame dimensions.
1728
+ * Camera calculates Manim-compatible frame dimensions from pixel resolution.
1729
+ */
1730
+ getCamera(): Camera;
1731
+ /**
1732
+ * Get the list of segments emitted by play() and wait() calls.
1733
+ * Used by the Renderer for cache-aware segmented rendering.
1734
+ */
1735
+ getSegments(): readonly Segment[];
1736
+ /**
1737
+ * Validates and registers animation targets based on lifecycle.
1738
+ * Handles composition animations (Sequence, Parallel) by processing children.
1739
+ */
1740
+ private validateAndRegisterAnimation;
1741
+ /**
1742
+ * Checks if a Mobject is in the scene.
1743
+ * An object is "in scene" if:
1744
+ * - It's directly registered in this.mobjects, OR
1745
+ * - Any ancestor in its parent chain is registered
1746
+ *
1747
+ * This respects the scene graph hierarchy - children of registered
1748
+ * VGroups are implicitly in scene via their parent.
1749
+ */
1750
+ isInScene(mobject: Mobject): boolean;
1751
+ /**
1752
+ * Computes a holistic CRC32 hash for a segment.
1753
+ * Includes camera state, all current mobjects, animations, and timing.
1754
+ */
1755
+ private computeSegmentHash;
1756
+ }
1757
+
1758
+ declare class Arc extends VMobject {
1759
+ readonly radius: number;
1760
+ readonly startAngle: number;
1761
+ readonly endAngle: number;
1762
+ constructor(radius?: number, startAngle?: number, endAngle?: number);
1763
+ private generatePath;
1764
+ }
1765
+
1766
+ declare class Line extends VMobject {
1767
+ readonly start: Vector2;
1768
+ readonly end: Vector2;
1769
+ constructor(x1?: number, y1?: number, x2?: number, y2?: number);
1770
+ private generatePath;
1771
+ }
1772
+
1773
+ declare class Arrow extends Line {
1774
+ readonly tipLength: number;
1775
+ readonly tipAngle: number;
1776
+ constructor(x1?: number, y1?: number, x2?: number, y2?: number, tipLength?: number, tipAngle?: number);
1777
+ private addTip;
1778
+ }
1779
+
1780
+ declare class Circle extends Arc {
1781
+ constructor(radius?: number);
1782
+ }
1783
+
1784
+ declare class Polygon extends VMobject {
1785
+ readonly vertices: Vector2[];
1786
+ constructor(...points: Array<[number, number]>);
1787
+ private generatePath;
1788
+ }
1789
+
1790
+ declare class Rectangle extends Polygon {
1791
+ readonly width: number;
1792
+ readonly height: number;
1793
+ constructor(width?: number, height?: number);
1778
1794
  }
1779
1795
 
1780
1796
  /**
1781
- * Property setter function type for applying values to a Mobject.
1797
+ * A VMobject representing a single glyph character.
1798
+ * Converts fontkit glyph path to BezierPath for rendering.
1782
1799
  */
1783
- type PropertySetter<T extends Mobject, V> = (target: T, value: V) => void;
1800
+ declare class Glyph extends VMobject {
1801
+ readonly character: string;
1802
+ readonly glyphId: number;
1803
+ constructor(fontkitGlyph: Glyph$1, character: string, scale: number, offsetX: number, offsetY: number);
1804
+ }
1805
+
1784
1806
  /**
1785
- * Animation that interpolates multiple property tracks via keyframes.
1786
- * Each track controls a single property and is interpolated independently.
1807
+ * A VGroup of vectorized glyphs created from a text string using fontkit.
1808
+ * Each character becomes a Glyph VMobject that can be individually animated.
1787
1809
  *
1788
- * This is a transformative animation - the target must already be in the scene.
1810
+ * Uses VMobject's fill/stroke as the source of truth (same as geometry).
1811
+ * Default: white fill, white stroke width 2.
1789
1812
  */
1790
- declare class KeyframeAnimation<T extends Mobject = Mobject> extends Animation<T> {
1791
- private readonly tracks;
1792
- readonly lifecycle: AnimationLifecycle;
1793
- /**
1794
- * Adds a named keyframe track with its property setter.
1795
- * The setter is called during interpolation to apply values to the target.
1796
- */
1797
- addTrack<V extends KeyframeValue>(name: string, track: KeyframeTrack<V>, setter: PropertySetter<T, V>): this;
1798
- /** Gets a track by name. */
1799
- getTrack<V extends KeyframeValue>(name: string): KeyframeTrack<V> | undefined;
1800
- /** All track names. */
1801
- getTrackNames(): string[];
1802
- /**
1803
- * Interpolates all tracks at the given progress and applies values to target.
1804
- */
1805
- interpolate(progress: number): void;
1813
+ declare class Text extends VGroup {
1814
+ readonly text: string;
1815
+ private fontSize;
1816
+ private fontPath;
1817
+ constructor(text: string, fontPath?: string, options?: {
1818
+ fontSize?: number;
1819
+ });
1820
+ private buildGlyphs;
1821
+ /** Propagates this Text's fill/stroke to all Glyph children. */
1822
+ private propagate;
1823
+ stroke(color: Color, width?: number): this;
1824
+ fill(color: Color, opacity?: number): this;
1825
+ getFontSize(): number;
1826
+ getGlyph(index: number): Glyph | undefined;
1806
1827
  }
1807
1828
 
1808
- /**
1809
- * Configuration options for the Follow animation.
1810
- */
1811
- interface FollowConfig {
1812
- /**
1813
- * Offset from the target's position. The camera will track
1814
- * (target.position + offset) instead of the exact target position.
1815
- * @default Vector2.ZERO
1816
- */
1817
- offset?: Vector2;
1818
- /**
1819
- * Damping factor for smooth following (0 to 1).
1820
- * - 0 = instant snap to target (no smoothing)
1821
- * - 0.9 = very smooth, slow following
1822
- * Higher values create a more "laggy" camera that takes longer to catch up.
1823
- * @default 0
1824
- */
1829
+ /** Unique identifier for graph nodes. */
1830
+ type GraphNodeId = string;
1831
+ /** Configuration for creating a graph node. */
1832
+ interface NodeConfig {
1833
+ position?: {
1834
+ x: number;
1835
+ y: number;
1836
+ };
1837
+ radius?: number;
1838
+ strokeColor?: Color;
1839
+ strokeWidth?: number;
1840
+ fillColor?: Color;
1841
+ fillOpacity?: number;
1842
+ }
1843
+ /** Configuration for creating a graph edge. */
1844
+ interface EdgeConfig {
1845
+ strokeColor?: Color;
1846
+ strokeWidth?: number;
1847
+ curved?: boolean;
1848
+ }
1849
+ /** Supported layout algorithms. */
1850
+ type LayoutType = 'force-directed' | 'tree' | 'circular';
1851
+ /** Configuration for graph layout algorithms. */
1852
+ interface LayoutConfig {
1853
+ radius?: number;
1854
+ levelHeight?: number;
1855
+ siblingSpacing?: number;
1856
+ iterations?: number;
1857
+ springLength?: number;
1858
+ repulsion?: number;
1859
+ attraction?: number;
1825
1860
  damping?: number;
1861
+ minDistance?: number;
1826
1862
  }
1863
+
1827
1864
  /**
1828
- * Animation that makes a CameraFrame track a target Mobject's position over time.
1829
- * Unlike MoveTo which captures position once, Follow reads the target position
1830
- * every frame, allowing the camera to track moving objects.
1831
- *
1832
- * @example
1833
- * // Basic follow - camera snaps to target position
1834
- * this.play(new Follow(this.frame, movingCircle).duration(5));
1835
- *
1836
- * @example
1837
- * // Smooth follow with damping
1838
- * this.play(new Follow(this.frame, player, { damping: 0.8 }).duration(10));
1839
- *
1840
- * @example
1841
- * // Follow with offset (camera leads the target)
1842
- * this.play(new Follow(this.frame, car, {
1843
- * offset: new Vector2(2, 0), // Camera 2 units ahead
1844
- * damping: 0.5
1845
- * }).duration(10));
1865
+ * A graph node represented as a circular VMobject.
1866
+ * Supports customizable radius, stroke, and fill styling.
1846
1867
  */
1847
- declare class Follow extends Animation<CameraFrame> {
1848
- readonly lifecycle: AnimationLifecycle;
1849
- private readonly followTarget;
1850
- private readonly offset;
1851
- private readonly damping;
1852
- /**
1853
- * Creates a new Follow animation.
1854
- *
1855
- * @param frame - The CameraFrame to animate
1856
- * @param target - The Mobject to follow
1857
- * @param config - Configuration options
1858
- * @throws Error if frame is null or undefined
1859
- * @throws Error if target is null or undefined
1860
- *
1861
- * @example
1862
- * const follow = new Follow(scene.frame, player, { damping: 0.7 });
1863
- * this.play(follow.duration(10));
1864
- */
1865
- constructor(frame: CameraFrame, target: Mobject, config?: FollowConfig);
1868
+ declare class GraphNode extends VMobject {
1869
+ readonly id: GraphNodeId;
1870
+ private nodeRadius;
1871
+ constructor(id: GraphNodeId, config?: NodeConfig);
1872
+ get radius(): number;
1866
1873
  /**
1867
- * Updates the camera position each frame to track the target.
1868
- * @param progress - Animation progress (0 to 1)
1874
+ * Generates a circular BezierPath approximation using cubic Bezier curves.
1875
+ * Uses the standard 4-point circle approximation with control point factor ~0.5523.
1869
1876
  */
1870
- interpolate(progress: number): void;
1877
+ private generateCirclePath;
1878
+ getCenter(): Vector2;
1871
1879
  }
1872
1880
 
1873
1881
  /**
1874
- * Configuration options for the Shake animation.
1882
+ * A graph edge represented as a BezierPath connecting two nodes.
1883
+ * Supports straight or curved edges with customizable styling.
1875
1884
  */
1876
- interface ShakeConfig {
1877
- /**
1878
- * Maximum displacement distance in world units.
1879
- * Higher values create more violent shaking.
1880
- * @default 0.2
1881
- */
1882
- intensity?: number;
1885
+ declare class GraphEdge extends VMobject {
1886
+ readonly source: GraphNodeId;
1887
+ readonly target: GraphNodeId;
1888
+ private sourceNode;
1889
+ private targetNode;
1890
+ private curved;
1891
+ constructor(sourceNode: GraphNode, targetNode: GraphNode, config?: EdgeConfig);
1883
1892
  /**
1884
- * Number of oscillations per second.
1885
- * Higher values create faster, more frantic shaking.
1886
- * @default 10
1893
+ * Recalculates the edge path based on current node positions.
1894
+ * Call this when nodes move to update the edge connection.
1887
1895
  */
1888
- frequency?: number;
1896
+ updatePath(): void;
1897
+ getPath(): BezierPath | undefined;
1889
1898
  /**
1890
- * Controls how quickly the shake diminishes over time.
1891
- * - 0 = no decay (constant intensity throughout)
1892
- * - 1 = linear decay
1893
- * - Higher values = faster decay (shake fades quickly)
1894
- * @default 1
1899
+ * Updates node references (used when nodes are replaced).
1895
1900
  */
1896
- decay?: number;
1901
+ setNodes(sourceNode: GraphNode, targetNode: GraphNode): void;
1897
1902
  }
1903
+
1898
1904
  /**
1899
- * Camera shake effect animation.
1900
- * Creates procedural displacement using layered sine waves to simulate
1901
- * impacts, explosions, or earthquakes.
1902
- *
1903
- * The shake automatically returns to the original position when complete.
1904
- *
1905
- * @example
1906
- * // Basic shake effect
1907
- * this.play(new Shake(this.frame).duration(0.5));
1908
- *
1909
- * @example
1910
- * // Intense explosion shake with quick decay
1911
- * this.play(new Shake(this.frame, {
1912
- * intensity: 0.5,
1913
- * frequency: 20,
1914
- * decay: 2
1915
- * }).duration(0.3));
1916
- *
1917
- * @example
1918
- * // Subtle earthquake with slow decay
1919
- * this.play(new Shake(this.frame, {
1920
- * intensity: 0.1,
1921
- * frequency: 5,
1922
- * decay: 0.5
1923
- * }).duration(3));
1905
+ * A graph structure containing nodes and edges.
1906
+ * Manages nodes as VMobjects and edges as BezierPath curves.
1907
+ * Supports multiple layout algorithms for automatic positioning.
1924
1908
  */
1925
- declare class Shake extends TransformativeAnimation<CameraFrame> {
1926
- private originalPosition;
1927
- private readonly intensity;
1928
- private readonly frequency;
1929
- private readonly decay;
1930
- private readonly seedX;
1931
- private readonly seedY;
1932
- /**
1933
- * Creates a new Shake animation.
1934
- *
1935
- * @param frame - The CameraFrame to shake
1936
- * @param config - Configuration options for intensity, frequency, and decay
1937
- *
1938
- * @example
1939
- * const shake = new Shake(scene.frame, { intensity: 0.3 });
1940
- * this.play(shake.duration(0.5));
1941
- */
1942
- constructor(frame: CameraFrame, config?: ShakeConfig);
1943
- /**
1944
- * Captures the original position before shake begins.
1945
- */
1946
- protected captureStartState(): void;
1947
- /**
1948
- * Applies procedural shake displacement each frame.
1949
- * @param progress - Animation progress (0 to 1)
1950
- */
1951
- interpolate(progress: number): void;
1952
- /**
1953
- * Generates pseudo-random noise using layered sine waves.
1954
- * @param t - Time value
1955
- * @param seed - Random seed for variation
1956
- * @returns Noise value between -1 and 1
1957
- */
1958
- private noise;
1909
+ declare class Graph extends VGroup {
1910
+ private nodes;
1911
+ private edges;
1912
+ constructor();
1913
+ /** Adds a node to the graph. */
1914
+ addNode(id: GraphNodeId, config?: NodeConfig): GraphNode;
1915
+ /** Removes a node and all connected edges from the graph. */
1916
+ removeNode(id: GraphNodeId): this;
1917
+ getNode(id: GraphNodeId): GraphNode | undefined;
1918
+ getNodes(): GraphNode[];
1919
+ addEdge(sourceId: GraphNodeId, targetId: GraphNodeId, config?: EdgeConfig): GraphEdge | undefined;
1920
+ removeEdge(sourceId: GraphNodeId, targetId: GraphNodeId): this;
1921
+ private removeEdgeInternal;
1922
+ getEdgePath(sourceId: GraphNodeId, targetId: GraphNodeId): ReturnType<GraphEdge['getPath']>;
1923
+ getEdges(): GraphEdge[];
1924
+ /** Applies a layout algorithm to reposition all nodes. */
1925
+ layout(type: LayoutType, config?: LayoutConfig): this;
1926
+ updateEdges(): this;
1959
1927
  }
1960
1928
 
1961
1929
  /**
@@ -2093,88 +2061,4 @@ declare class Renderer {
2093
2061
  private renderSegmentToFile;
2094
2062
  }
2095
2063
 
2096
- /**
2097
- * Renders individual frames from a Scene.
2098
- * Responsible for drawing mobjects to a canvas at a specific point in time.
2099
- */
2100
- declare class FrameRenderer {
2101
- private readonly scene;
2102
- private readonly width;
2103
- private readonly height;
2104
- constructor(scene: Scene, width: number, height: number);
2105
- /**
2106
- * Calculates the matrix that transforms Manim world coordinates to screen pixels.
2107
- *
2108
- * Manim coordinate system:
2109
- * - Origin at center of screen
2110
- * - Y-axis points up
2111
- * - frameHeight = 8.0 units
2112
- *
2113
- * Screen coordinate system:
2114
- * - Origin at top-left
2115
- * - Y-axis points down
2116
- * - Width x Height pixels
2117
- */
2118
- private calculateWorldToScreenMatrix;
2119
- /**
2120
- * Renders a single frame at the specified time.
2121
- */
2122
- renderFrame(time: number): Canvas;
2123
- /**
2124
- * Gets the canvas dimensions.
2125
- */
2126
- getDimensions(): {
2127
- width: number;
2128
- height: number;
2129
- };
2130
- }
2131
-
2132
- /**
2133
- * Tracks rendering progress and reports updates via callback.
2134
- */
2135
- declare class ProgressReporter {
2136
- private readonly totalFrames;
2137
- private readonly onProgress?;
2138
- private readonly startTime;
2139
- private currentFrame;
2140
- constructor(totalFrames: number, onProgress?: ProgressCallback);
2141
- /**
2142
- * Report progress for the current frame.
2143
- */
2144
- reportFrame(frameIndex: number): void;
2145
- /**
2146
- * Report rendering complete.
2147
- */
2148
- complete(): void;
2149
- }
2150
-
2151
- /** Protocol for objects that contribute to segment hashing. */
2152
- interface Hashable {
2153
- computeHash(): number;
2154
- }
2155
-
2156
- /**
2157
- * Manages a disk-based cache of rendered segment partial files.
2158
- *
2159
- * Each segment is stored as a video file keyed by its CRC32 hash.
2160
- * On re-render, segments whose hashes match an existing file are skipped.
2161
- */
2162
- declare class SegmentCache {
2163
- private readonly cacheDir;
2164
- constructor(cacheDir: string);
2165
- /** Ensure the cache directory exists. */
2166
- init(): Promise<void>;
2167
- /** Check if a rendered segment file exists for the given hash. */
2168
- has(hash: number): boolean;
2169
- /** Get the absolute file path for a segment hash. */
2170
- getPath(hash: number): string;
2171
- /** Get the cache directory path. */
2172
- getDir(): string;
2173
- /**
2174
- * Remove cached files that are not in the active set.
2175
- * Call after a full render to clean up stale segments.
2176
- */
2177
- prune(activeHashes: Set<number>): Promise<void>;
2178
- }
2179
-
2180
- export { Animation, type AnimationConfig, Arc, Arrow, Camera, type CameraConfig, CameraFrame, Circle, Color, Draw, type EasingFunction, type EdgeConfig, FadeIn, FadeOut, Follow, FrameRenderer, Glyph, Graph, GraphEdge, GraphNode, type GraphNodeId, type Hashable, type Keyframe, KeyframeAnimation, KeyframeTrack, type LayoutConfig, type LayoutType, Line, Mobject, MorphTo, MoveTo, type NodeConfig, Parallel, Polygon, type ProgressCallback, ProgressReporter, Rectangle, type RenderConfig, type RenderFormat, type RenderProgress, type RenderQuality, Renderer, Resolution, type ResolvedCameraConfig, Rotate, Scale, Scene, type SceneConfig, type ScheduledAnimation, type Segment, SegmentCache, Sequence, Shake, Text, Timeline, type TimelineConfig, Unwrite, VGroup, VMobject, Vector2, Write, clearRegistry, smooth as defaultEasing, doubleSmooth, easeInBack, easeInBounce, easeInCirc, easeInCubic, easeInElastic, easeInExpo, easeInOutBack, easeInOutBounce, easeInOutCirc, easeInOutCubic, easeInOutElastic, easeInOutExpo, easeInOutQuad, easeInOutQuart, easeInOutQuint, easeInOutSine, easeInQuad, easeInQuart, easeInQuint, easeInSine, easeOutBack, easeOutBounce, easeOutCirc, easeOutCubic, easeOutElastic, easeOutExpo, easeOutQuad, easeOutQuart, easeOutQuint, easeOutSine, exponentialDecay, getEasing, hasEasing, linear, lingering, notQuiteThere, registerEasing, runningStart, rushFrom, rushInto, slowInto, smooth, thereAndBack, thereAndBackWithPause, unregisterEasing, wiggle };
2064
+ export { Animation, type AnimationConfig, Arc, Arrow, Camera, type CameraConfig, CameraFrame, Circle, Color, Draw, type EasingFunction, type EdgeConfig, FadeIn, FadeOut, Follow, Glyph, Graph, GraphEdge, GraphNode, type GraphNodeId, type Keyframe, KeyframeAnimation, KeyframeTrack, type LayoutConfig, type LayoutType, Line, Mobject, MorphTo, MoveTo, type NodeConfig, Parallel, Polygon, type ProgressCallback, Rectangle, type RenderConfig, type RenderFormat, type RenderProgress, type RenderQuality, Renderer, Resolution, type ResolvedCameraConfig, Rotate, Scale, Scene, type SceneConfig, type ScheduledAnimation, Sequence, Shake, Text, Timeline, type TimelineConfig, Unwrite, VGroup, VMobject, Vector2, Write, clearRegistry, smooth as defaultEasing, doubleSmooth, easeInBack, easeInBounce, easeInCirc, easeInCubic, easeInElastic, easeInExpo, easeInOutBack, easeInOutBounce, easeInOutCirc, easeInOutCubic, easeInOutElastic, easeInOutExpo, easeInOutQuad, easeInOutQuart, easeInOutQuint, easeInOutSine, easeInQuad, easeInQuart, easeInQuint, easeInSine, easeOutBack, easeOutBounce, easeOutCirc, easeOutCubic, easeOutElastic, easeOutExpo, easeOutQuad, easeOutQuart, easeOutQuint, easeOutSine, exponentialDecay, getEasing, hasEasing, linear, lingering, notQuiteThere, registerEasing, runningStart, rushFrom, rushInto, slowInto, smooth, thereAndBack, thereAndBackWithPause, unregisterEasing, wiggle };