@redwilly/anima 0.1.24 → 0.1.26

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,6 +1,53 @@
1
1
  import { Glyph as Glyph$1 } from 'fontkit';
2
2
  import { Canvas } from '@napi-rs/canvas';
3
3
 
4
+ /**
5
+ * Unified vector type for both 2D and 3D usage.
6
+ * - 2D vectors use z = 0
7
+ * - 3D vectors use non-zero z when needed
8
+ */
9
+ declare class Vector {
10
+ readonly x: number;
11
+ readonly y: number;
12
+ readonly z: number;
13
+ constructor(x: number, y: number, z?: number);
14
+ add(other: Vector): Vector;
15
+ subtract(other: Vector): Vector;
16
+ multiply(scalar: number): Vector;
17
+ dot(other: Vector): number;
18
+ length(): number;
19
+ normalize(): Vector;
20
+ lerp(other: Vector, t: number): Vector;
21
+ equals(other: Vector, tolerance?: number): boolean;
22
+ toPlanar(): Vector;
23
+ static fromPlanar(v: Vector, z?: number): Vector;
24
+ static readonly ZERO: Vector;
25
+ static readonly UP: Vector;
26
+ static readonly DOWN: Vector;
27
+ static readonly LEFT: Vector;
28
+ static readonly RIGHT: Vector;
29
+ }
30
+
31
+ /**
32
+ * A 4x4 matrix class for 3D affine transforms and projection.
33
+ * Stored in row-major order.
34
+ */
35
+ declare class Matrix4x4 {
36
+ readonly values: Float32Array;
37
+ constructor(values: number[] | Float32Array);
38
+ multiply(other: Matrix4x4): Matrix4x4;
39
+ transformPoint(point: Vector): Vector;
40
+ transformPoint2D(point: Vector): Vector;
41
+ inverse(): Matrix4x4;
42
+ static identity(): Matrix4x4;
43
+ static translation(tx: number, ty: number, tz?: number): Matrix4x4;
44
+ static rotationX(angle: number): Matrix4x4;
45
+ static rotationY(angle: number): Matrix4x4;
46
+ static rotationZ(angle: number): Matrix4x4;
47
+ static scale(sx: number, sy: number, sz?: number): Matrix4x4;
48
+ static readonly IDENTITY: Matrix4x4;
49
+ }
50
+
4
51
  /**
5
52
  * A class representing a color with Red, Green, Blue, and Alpha components.
6
53
  * RGB values are in the range [0, 255].
@@ -30,51 +77,103 @@ declare class Color {
30
77
  static readonly TRANSPARENT: Color;
31
78
  }
32
79
 
80
+ type PathCommandType = 'Move' | 'Line' | 'Quadratic' | 'Cubic' | 'Close';
81
+ interface PathCommand {
82
+ type: PathCommandType;
83
+ end: Vector;
84
+ control1?: Vector;
85
+ control2?: Vector;
86
+ }
87
+
33
88
  /**
34
- * A 2D vector class representing a point or direction in 2D space.
89
+ * A class representing a Bezier path, capable of storing standard path commands
90
+ * (move, line, quadratic curve, cubic curve, close).
35
91
  */
36
- declare class Vector2 {
37
- readonly x: number;
38
- readonly y: number;
39
- constructor(x: number, y: number);
40
- add(other: Vector2): Vector2;
41
- subtract(other: Vector2): Vector2;
42
- multiply(scalar: number): Vector2;
43
- dot(other: Vector2): number;
44
- /** Magnitude (length) of the vector. */
45
- length(): number;
46
- /** Returns a normalized unit vector. Returns ZERO for zero-length vectors. */
47
- normalize(): Vector2;
48
- lerp(other: Vector2, t: number): Vector2;
49
- equals(other: Vector2, tolerance?: number): boolean;
50
- static readonly ZERO: Vector2;
51
- static readonly UP: Vector2;
52
- static readonly DOWN: Vector2;
53
- static readonly LEFT: Vector2;
54
- static readonly RIGHT: Vector2;
92
+ declare class BezierPath {
93
+ private commands;
94
+ private currentPoint;
95
+ private startPoint;
96
+ private cachedLength;
97
+ private segmentLengths;
98
+ private segmentCDF;
99
+ /** Invalidates the cached length data. Called after any path modification. */
100
+ private invalidateCache;
101
+ /** Builds the cache if not already valid. */
102
+ private ensureCache;
103
+ /** Starts a new subpath at the specified point. */
104
+ moveTo(point: Vector): void;
105
+ lineTo(point: Vector): void;
106
+ quadraticTo(control: Vector, end: Vector): void;
107
+ cubicTo(control1: Vector, control2: Vector, end: Vector): void;
108
+ closePath(): void;
109
+ getCommands(): PathCommand[];
110
+ getLength(): number;
111
+ /** Returns the point on the path at the normalized position t (0-1). */
112
+ getPointAt(t: number): Vector;
113
+ getTangentAt(t: number): Vector;
114
+ getPoints(count: number): Vector[];
115
+ getPointCount(): number;
116
+ clone(): BezierPath;
117
+ /** Returns a new BezierPath where all segments are converted to Cubic curves. */
118
+ toCubic(): BezierPath;
119
+ static interpolate(path1: BezierPath, path2: BezierPath, t: number): BezierPath;
120
+ /** Matches the number of points/commands in two paths for morphing. */
121
+ static matchPoints(path1: BezierPath, path2: BezierPath): [BezierPath, BezierPath];
122
+ private static fromCommands;
55
123
  }
56
124
 
57
125
  /**
58
- * A 3x3 matrix class for 2D affine transformations.
59
- * Stored in row-major order:
60
- * [ 0 1 2 ]
61
- * [ 3 4 5 ]
62
- * [ 6 7 8 ]
126
+ * Context provided to updater functions on each frame evaluation.
63
127
  */
64
- declare class Matrix3x3 {
65
- readonly values: Float32Array;
66
- constructor(values: number[] | Float32Array);
67
- multiply(other: Matrix3x3): Matrix3x3;
68
- /** Transforms a Vector2 point (assumes z=1). */
69
- transformPoint(point: Vector2): Vector2;
70
- /** @throws Error if the matrix is not invertible. */
71
- inverse(): Matrix3x3;
72
- static identity(): Matrix3x3;
73
- static translation(tx: number, ty: number): Matrix3x3;
74
- static rotation(angle: number): Matrix3x3;
75
- static scale(sx: number, sy: number): Matrix3x3;
76
- static shear(shx: number, shy: number): Matrix3x3;
77
- static readonly IDENTITY: Matrix3x3;
128
+ interface UpdaterContext {
129
+ /** Absolute scene time in seconds. */
130
+ readonly time: number;
131
+ /** Time delta from previous evaluated frame (seconds). */
132
+ readonly dt: number;
133
+ /** Monotonic frame index produced by the updater engine. */
134
+ readonly frame: number;
135
+ /** The scene currently being evaluated. */
136
+ readonly scene: Scene;
137
+ /**
138
+ * True when evaluation is discontinuous (first frame or backward seek).
139
+ * Updaters using integrators can use this to reset internal accumulators.
140
+ */
141
+ readonly discontinuous: boolean;
142
+ }
143
+ /**
144
+ * A function that mutates a mobject every evaluated frame.
145
+ */
146
+ type UpdaterFunction<T extends Mobject = Mobject> = (mobject: T, context: UpdaterContext) => void;
147
+ /**
148
+ * Public options accepted by Mobject.addUpdater.
149
+ */
150
+ interface UpdaterOptions {
151
+ /**
152
+ * Higher priority runs first. Default: 0.
153
+ * Ties are resolved by insertion order.
154
+ */
155
+ priority?: number;
156
+ /** Whether this updater starts enabled. Default: true. */
157
+ enabled?: boolean;
158
+ /** Optional descriptive label for debugging/introspection. */
159
+ name?: string;
160
+ }
161
+ /**
162
+ * Opaque handle returned from addUpdater for later removal/toggling.
163
+ */
164
+ interface UpdaterHandle {
165
+ readonly id: number;
166
+ }
167
+ /**
168
+ * Internal normalized representation stored by each mobject.
169
+ */
170
+ interface MobjectUpdaterRecord {
171
+ readonly id: number;
172
+ readonly order: number;
173
+ readonly name?: string;
174
+ readonly fn: UpdaterFunction<Mobject>;
175
+ priority: number;
176
+ enabled: boolean;
78
177
  }
79
178
 
80
179
  /**
@@ -264,107 +363,6 @@ declare function unregisterEasing(name: string): boolean;
264
363
  /** Clears all registered custom easings (useful for testing). */
265
364
  declare function clearRegistry(): void;
266
365
 
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
366
  /**
369
367
  * Configuration options for animations.
370
368
  */
@@ -385,856 +383,887 @@ interface AnimationConfig {
385
383
  type AnimationLifecycle = 'introductory' | 'transformative' | 'exit';
386
384
 
387
385
  /**
388
- * Abstract base class for all animations.
389
- * Provides configuration for duration, easing, and delay.
390
- * Subclasses must specify their lifecycle category.
386
+ * Executes animations in parallel, all starting at the same time.
387
+ * Total duration equals the maximum of all child animation durations.
388
+ *
389
+ * This is a composition animation - its lifecycle is determined by its children.
390
+ * By default, uses 'transformative' lifecycle if children are mixed.
391
+ *
392
+ * All children are initialized together before any interpolation begins,
393
+ * ensuring they all capture state at the same moment.
391
394
  */
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;
395
+ declare class Parallel extends Animation<Mobject> {
396
+ private readonly children;
397
+ private readonly maxChildDuration;
397
398
  /**
398
- * The lifecycle category of this animation.
399
- * Determines how Scene.play() handles scene registration and validation.
399
+ * The lifecycle of Parallel is 'introductory' only if ALL children are introductory.
400
+ * Otherwise, it defaults to 'transformative'.
400
401
  */
401
- abstract readonly lifecycle: AnimationLifecycle;
402
- constructor(target: T);
403
- duration(seconds: number): this;
404
- ease(easing: EasingFunction): this;
405
- delay(seconds: number): this;
402
+ readonly lifecycle: AnimationLifecycle;
403
+ constructor(animations: Animation[]);
406
404
  getDuration(): number;
407
- getDelay(): number;
408
- getEasing(): EasingFunction;
409
- getTarget(): T;
410
- getConfig(): AnimationConfig;
411
- abstract interpolate(progress: number): void;
405
+ getChildren(): readonly Animation[];
412
406
  /**
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.
407
+ * Ensures all children are initialized together.
408
+ * This captures start state for all parallel animations at the same moment.
416
409
  */
417
410
  ensureInitialized(): void;
411
+ reset(): void;
418
412
  /**
419
- * Resets the animation to its uninitialized state.
420
- * Allows animations to be replayed or looped.
413
+ * Interpolates all child animations at the given progress.
414
+ * Each child's progress is scaled based on its duration relative to the container.
421
415
  */
422
- reset(): void;
416
+ interpolate(progress: number): void;
423
417
  update(progress: number): void;
418
+ }
419
+
420
+ /**
421
+ * Executes animations in sequence, one after another.
422
+ * Total duration equals the sum of all child animation durations.
423
+ *
424
+ * This is a composition animation - its lifecycle is determined by its children.
425
+ * Only the first child is initialized when the sequence starts; subsequent
426
+ * children are initialized when they become active.
427
+ */
428
+ declare class Sequence extends Animation<Mobject> {
429
+ private readonly children;
430
+ private readonly childDurations;
431
+ private readonly totalChildDuration;
424
432
  /**
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.
433
+ * The lifecycle of Sequence is determined by its FIRST child animation.
434
+ * If the first animation is introductory, it will register the target,
435
+ * allowing subsequent transformative animations to work.
428
436
  */
429
- computeHash(): number;
437
+ readonly lifecycle: AnimationLifecycle;
438
+ constructor(animations: Animation[]);
439
+ getDuration(): number;
440
+ getChildren(): readonly Animation[];
441
+ /**
442
+ * Initializes only the first child.
443
+ * Later children are initialized when they become active in interpolate().
444
+ */
445
+ ensureInitialized(): void;
446
+ reset(): void;
447
+ /**
448
+ * Interpolates the sequence at the given progress.
449
+ * Maps global progress to the correct child animation.
450
+ *
451
+ * IMPORTANT: We only update children that have started or completed.
452
+ * Children that haven't started yet are NOT updated to avoid
453
+ * premature initialization with incorrect state.
454
+ */
455
+ interpolate(progress: number): void;
456
+ update(progress: number): void;
430
457
  }
431
458
 
432
459
  /**
433
- * Represents an animation scheduled at a specific time on the Timeline.
460
+ * Abstract base class for animations that introduce an object to the scene.
434
461
  */
435
- interface ScheduledAnimation {
436
- /** The animation to play */
437
- readonly animation: Animation;
438
- /** Start time in seconds from timeline beginning */
439
- readonly startTime: number;
462
+ declare abstract class IntroductoryAnimation<T extends Mobject = Mobject> extends Animation<T> {
463
+ readonly lifecycle: AnimationLifecycle;
440
464
  }
441
465
  /**
442
- * Configuration options for Timeline.
466
+ * Abstract base class for animations that transform an existing scene object.
443
467
  */
444
- interface TimelineConfig {
445
- /** Whether the timeline loops. Default: false */
446
- readonly loop?: boolean;
468
+ declare abstract class TransformativeAnimation<T extends Mobject = Mobject> extends Animation<T> {
469
+ readonly lifecycle: AnimationLifecycle;
470
+ protected initialized: boolean;
471
+ /**
472
+ * Captures the start state from the target.
473
+ * Called once when the animation first becomes active.
474
+ */
475
+ protected abstract captureStartState(): void;
476
+ ensureInitialized(): void;
477
+ reset(): void;
447
478
  }
448
-
449
479
  /**
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.
480
+ * Abstract base class for animations that exit/remove an object from the scene.
453
481
  */
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;
482
+ declare abstract class ExitAnimation<T extends Mobject = Mobject> extends Animation<T> {
483
+ readonly lifecycle: AnimationLifecycle;
516
484
  }
517
485
 
518
486
  /**
519
- * Executes animations in sequence, one after another.
520
- * Total duration equals the sum of all child animation durations.
487
+ * Animation that first draws the stroke progressively, then fades in the fill.
488
+ * - First 50%: stroke draws progressively
489
+ * - Second 50%: fill fades in
521
490
  *
522
- * This is a composition animation - its lifecycle is determined by its children.
523
- * Only the first child is initialized when the sequence starts; subsequent
524
- * children are initialized when they become active.
491
+ * - Single VMobject: stroke then fill
492
+ * - VGroup: all children animate together
493
+ * - Text (VGroup of Glyphs): Glyphs animate sequentially for handwriting effect
494
+ *
495
+ * This is an introductory animation - it auto-registers the target with the scene.
525
496
  */
526
- declare class Sequence extends Animation<Mobject> {
527
- private readonly children;
528
- private readonly childDurations;
529
- private readonly totalChildDuration;
530
- /**
531
- * The lifecycle of Sequence is determined by its FIRST child animation.
532
- * If the first animation is introductory, it will register the target,
533
- * allowing subsequent transformative animations to work.
534
- */
535
- readonly lifecycle: AnimationLifecycle;
536
- constructor(animations: Animation[]);
537
- getDuration(): number;
538
- getChildren(): readonly Animation[];
539
- /**
540
- * Initializes only the first child.
541
- * Later children are initialized when they become active in interpolate().
542
- */
543
- ensureInitialized(): void;
544
- reset(): void;
545
- /**
546
- * Interpolates the sequence at the given progress.
547
- * Maps global progress to the correct child animation.
548
- *
549
- * IMPORTANT: We only update children that have started or completed.
550
- * Children that haven't started yet are NOT updated to avoid
551
- * premature initialization with incorrect state.
552
- */
497
+ declare class Draw<T extends VMobject = VMobject> extends IntroductoryAnimation<T> {
498
+ private readonly originalPaths;
499
+ private readonly originalOpacity;
500
+ private readonly originalStrokeColor;
501
+ private readonly originalStrokeWidth;
502
+ private readonly originalFillColor;
503
+ private readonly originalFillOpacity;
504
+ private readonly childStates;
505
+ /** Glyph states for Text children, keyed by the Text VMobject reference. */
506
+ private readonly glyphStates;
507
+ constructor(target: T);
508
+ private createState;
553
509
  interpolate(progress: number): void;
554
- update(progress: number): void;
510
+ private interpolateVGroup;
511
+ private interpolateGlyphs;
512
+ /** Interpolates a single VMobject: stroke (0-0.5), then fill (0.5-1). */
513
+ private interpolateVMobject;
555
514
  }
556
515
 
557
516
  /**
558
- * Executes animations in parallel, all starting at the same time.
559
- * Total duration equals the maximum of all child animation durations.
517
+ * Animation that progressively removes a VMobject by erasing the path.
518
+ * Reverse of Write animation - at progress 0, full object is visible;
519
+ * at progress 1, nothing is visible.
560
520
  *
561
- * This is a composition animation - its lifecycle is determined by its children.
562
- * By default, uses 'transformative' lifecycle if children are mixed.
521
+ * Supports VGroup (including Text): animates each child's paths progressively.
563
522
  *
564
- * All children are initialized together before any interpolation begins,
565
- * ensuring they all capture state at the same moment.
523
+ * This is an exit animation - the target must already be in the scene.
524
+ *
525
+ * @example
526
+ * scene.play(new Write(text));
527
+ * scene.play(new Unwrite(text)); // Text is erased progressively
566
528
  */
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
- */
574
- readonly lifecycle: AnimationLifecycle;
575
- constructor(animations: Animation[]);
576
- getDuration(): number;
577
- getChildren(): readonly Animation[];
578
- /**
579
- * Ensures all children are initialized together.
580
- * This captures start state for all parallel animations at the same moment.
581
- */
582
- ensureInitialized(): void;
583
- 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
- */
529
+ declare class Unwrite<T extends VMobject = VMobject> extends ExitAnimation<T> {
530
+ private readonly isVGroup;
531
+ /** For non-VGroup targets: original paths on the target itself. */
532
+ private readonly originalPaths;
533
+ private readonly originalOpacity;
534
+ private readonly originalFillOpacity;
535
+ /** For VGroup targets: original state of each child. */
536
+ private readonly childStates;
537
+ constructor(target: T);
588
538
  interpolate(progress: number): void;
589
- update(progress: number): void;
539
+ /** Interpolates a single VMobject (non-VGroup). */
540
+ private interpolateVMobject;
541
+ /** Interpolates a VGroup by animating each child's paths. */
542
+ private interpolateVGroup;
590
543
  }
591
544
 
592
545
  /**
593
- * Configuration options for CameraFrame.
546
+ * Animation that progressively draws VMobject paths from start to end.
547
+ *
548
+ * - Single VMobject: paths draw progressively
549
+ * - VGroup: all children animate together with same progress
550
+ * - Text (VGroup of Glyphs): Glyphs animate sequentially for handwriting effect
551
+ *
552
+ * This is an introductory animation - it auto-registers the target with the scene.
594
553
  */
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;
554
+ declare class Write<T extends VMobject = VMobject> extends IntroductoryAnimation<T> {
555
+ private readonly originalPaths;
556
+ private readonly originalOpacity;
557
+ private readonly originalStrokeColor;
558
+ private readonly originalStrokeWidth;
559
+ private readonly originalFillColor;
560
+ private readonly originalFillOpacity;
561
+ private readonly childStates;
562
+ /** Glyph states for Text children, keyed by the Text VMobject reference. */
563
+ private readonly glyphStates;
564
+ constructor(target: T);
565
+ private createState;
566
+ interpolate(progress: number): void;
567
+ private interpolateVGroup;
568
+ private interpolateGlyphs;
569
+ /** Applies progress to a single VMobject, updating its paths and style. */
570
+ private applyProgress;
600
571
  }
572
+
601
573
  /**
602
- * Camera bounds that limit how far the camera can pan.
574
+ * Animation that fades a Mobject in by increasing its opacity from 0 to 1.
575
+ *
576
+ * This is an introductory animation - it auto-registers the target with the scene.
577
+ * You do not need to call scene.add() before using FadeIn.
578
+ *
579
+ * @example
580
+ * const circle = new Circle(1);
581
+ * scene.play(new FadeIn(circle)); // Circle is auto-registered and faded in
603
582
  */
604
- interface Bounds {
605
- minX: number;
606
- maxX: number;
607
- minY: number;
608
- maxY: number;
583
+ declare class FadeIn<T extends Mobject = Mobject> extends IntroductoryAnimation<T> {
584
+ private readonly startOpacity;
585
+ constructor(target: T);
586
+ interpolate(progress: number): void;
609
587
  }
588
+
610
589
  /**
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)
616
- *
617
- * The CameraFrame is the primary way to control camera animations in Anima.
618
- * Access it via `scene.frame` or `scene.camera.frame`.
590
+ * Animation that fades a Mobject out by decreasing its opacity to 0.
619
591
  *
620
- * @example
621
- * // Zoom in over 1 second
622
- * this.play(this.frame.zoomIn(2).duration(1));
592
+ * This is an exit animation - the target must already be in the scene.
593
+ * The starting opacity is captured when the animation first runs,
594
+ * not when it's constructed, so it correctly fades from the current opacity.
623
595
  *
624
596
  * @example
625
- * // Pan to center on an object
626
- * this.play(this.frame.centerOn(circle).duration(0.5));
627
- *
628
- * @example
629
- * // Fit multiple objects in view
630
- * this.play(this.frame.fitTo([obj1, obj2, obj3]).duration(1));
597
+ * scene.add(circle);
598
+ * scene.play(new FadeOut(circle)); // Circle fades out
631
599
  */
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;
652
- /**
653
- * The current height of the frame in world units, accounting for scale.
654
- * @returns The frame height multiplied by the current scale.y
655
- */
656
- get height(): number;
657
- /**
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
- *
666
- * @example
667
- * frame.setScale(2, 2); // Zoom out 2x
668
- * frame.setScale(0.5, 0.5); // Zoom in 2x
669
- */
670
- setScale(sx: number, sy: number): this;
671
- /**
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);
685
- */
686
- setBounds(minX: number, minY: number, maxX: number, maxY: number): this;
687
- /**
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
694
- */
695
- clearBounds(): this;
696
- /**
697
- * Checks if the camera has bounds set.
698
- *
699
- * @returns True if bounds are set, false otherwise
700
- */
701
- hasBounds(): boolean;
702
- /**
703
- * Gets the current bounds configuration.
704
- *
705
- * @returns The bounds object or undefined if no bounds are set
706
- */
707
- getBounds(): Bounds | undefined;
708
- /**
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)
718
- */
719
- pos(x: number, y: number): this;
720
- /**
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));
735
- */
736
- zoomIn(factor?: number): this & {
737
- toAnimation(): Animation<Mobject>;
738
- };
739
- /**
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));
754
- */
755
- zoomOut(factor?: number): this & {
756
- toAnimation(): Animation<Mobject>;
757
- };
758
- /**
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));
774
- */
775
- centerOn(target: Mobject): this & {
776
- toAnimation(): Animation<Mobject>;
777
- };
778
- /**
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));
797
- */
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));
823
- */
824
- fitTo(targets: Mobject | Mobject[], margin?: number): this & {
825
- toAnimation(): Animation<Mobject>;
826
- };
827
- private calculateBounds;
828
- private hasGetBoundingBox;
600
+ declare class FadeOut<T extends Mobject = Mobject> extends ExitAnimation<T> {
601
+ private startOpacity;
602
+ interpolate(progress: number): void;
829
603
  }
830
604
 
831
605
  /**
832
- * Configuration options for Camera.
606
+ * Animation that moves a Mobject from its current position to a destination.
607
+ * Uses linear interpolation between start and end positions.
608
+ *
609
+ * This is a transformative animation - the target must already be in the scene.
610
+ * Start position is captured lazily when animation becomes active.
611
+ *
612
+ * @example
613
+ * scene.add(circle); // or use FadeIn first
614
+ * scene.play(new MoveTo(circle, 2, 0)); // Move to (2, 0)
833
615
  */
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;
616
+ declare class MoveTo<T extends Mobject = Mobject> extends TransformativeAnimation<T> {
617
+ private startPosition;
618
+ private readonly endPosition;
619
+ constructor(target: T, destination: Vector);
620
+ constructor(target: T, x: number, y: number, z?: number);
621
+ protected captureStartState(): void;
622
+ interpolate(progress: number): void;
623
+ /** Returns the target position of the move animation. */
624
+ getDestination(): Vector;
839
625
  }
626
+
840
627
  /**
841
- * Resolved camera configuration with all defaults applied.
628
+ * Animation that rotates a Mobject by a specified angle.
629
+ * Uses linear interpolation between start and end rotation.
630
+ *
631
+ * This is a transformative animation - the target must already be in the scene.
632
+ * Start rotation is captured lazily when animation becomes active.
633
+ *
634
+ * @example
635
+ * scene.add(square);
636
+ * scene.play(new Rotate(square, Math.PI / 4)); // Rotate 45 degrees
842
637
  */
843
- interface ResolvedCameraConfig {
844
- readonly pixelWidth: number;
845
- readonly pixelHeight: number;
638
+ declare class Rotate<T extends Mobject = Mobject> extends TransformativeAnimation<T> {
639
+ private startRotation;
640
+ private endRotation;
641
+ private readonly angle;
642
+ constructor(target: T, angle: number);
643
+ protected captureStartState(): void;
644
+ interpolate(progress: number): void;
645
+ /** Returns the total rotation angle in radians. */
646
+ getAngle(): number;
846
647
  }
847
648
 
848
649
  /**
849
- * Camera manages the view into the scene.
850
- * Uses CameraFrame (a Mobject) to store transform state, enabling camera animations.
851
- *
852
- * The Camera provides both instant manipulation methods (panTo, zoomTo) and
853
- * access to the CameraFrame for fluent animation APIs.
650
+ * Animation that scales a Mobject to a target scale factor.
651
+ * Uses linear interpolation between start and end scale.
854
652
  *
855
- * @example
856
- * // Instant camera manipulation
857
- * camera.zoomTo(2);
858
- * camera.panTo(new Vector2(5, 3));
653
+ * This is a transformative animation - the target must already be in the scene.
654
+ * Start scale is captured lazily when animation becomes active.
859
655
  *
860
656
  * @example
861
- * // Animated camera movement via frame
862
- * this.play(this.frame.zoomIn(2).duration(1));
863
- * this.play(this.frame.centerOn(circle).duration(0.5));
657
+ * scene.add(circle);
658
+ * scene.play(new Scale(circle, 2)); // Scale to 2x
864
659
  */
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;
660
+ declare class Scale<T extends Mobject = Mobject> extends TransformativeAnimation<T> {
661
+ private startScale;
662
+ private readonly endScale;
663
+ constructor(target: T, factor: number);
664
+ constructor(target: T, factorX: number, factorY: number);
665
+ protected captureStartState(): void;
666
+ interpolate(progress: number): void;
667
+ /** Returns the scale factor. */
668
+ getFactor(): number;
669
+ }
670
+
671
+ /**
672
+ * Manages a queue of animations for fluent chaining.
673
+ * This is an internal implementation detail of Mobject's fluent API.
674
+ */
675
+ declare class AnimationQueue {
676
+ private readonly target;
677
+ private readonly queue;
678
+ constructor(target: Mobject);
679
+ enqueueAnimation(animation: Animation<Mobject>): void;
680
+ setLastDuration(seconds: number): void;
681
+ setLastEasing(easing: EasingFunction): void;
682
+ setLastDelay(seconds: number): void;
683
+ isEmpty(): boolean;
684
+ popLastAnimation(): Animation<Mobject> | null;
685
+ toAnimation(): Animation<Mobject>;
686
+ getTotalDuration(): number;
687
+ }
688
+ interface MobjectState {
689
+ position: Vector;
690
+ scale: Vector;
691
+ rotation: number;
692
+ }
693
+ /**
694
+ * Base class for all mathematical objects.
695
+ * Manages position, rotation, scale, and opacity via a local transformation matrix.
696
+ * Includes fluent animation API for chainable animations.
697
+ */
698
+ declare class Mobject {
699
+ protected localMatrix: Matrix4x4;
700
+ protected opacityValue: number;
701
+ protected animQueue: AnimationQueue | null;
702
+ protected pointCloud: Vector[];
703
+ protected submobjects: Mobject[];
704
+ private savedStates;
705
+ private logicalRotation;
706
+ private logicalScale;
707
+ private updaters;
708
+ private nextUpdaterId;
709
+ private nextUpdaterOrder;
710
+ private updatersEnabled;
711
+ parent: Mobject | null;
712
+ constructor();
713
+ protected getQueue(): AnimationQueue;
714
+ get matrix(): Matrix4x4;
715
+ getWorldMatrix(): Matrix4x4;
869
716
  /**
870
- * Creates a new Camera with the specified viewport dimensions.
871
- *
872
- * @param config - Configuration options
873
- * @param config.pixelWidth - Width of the viewport in pixels (default: 1920)
874
- * @param config.pixelHeight - Height of the viewport in pixels (default: 1080)
717
+ * Matrix used by renderer.
718
+ * Geometry-driven mobjects bake their own transform into points,
719
+ * so only ancestor matrix transforms should be applied at draw time.
875
720
  */
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;
721
+ getRenderMatrix(): Matrix4x4;
722
+ get position(): Vector;
885
723
  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;
724
+ get scale(): Vector;
725
+ get opacity(): number;
726
+ pos(x: number, y: number, z?: number): this;
727
+ show(): this;
728
+ hide(): this;
729
+ setOpacity(value: number): this;
730
+ setRotation(angle: number): this;
731
+ setScale(sx: number, sy: number): this;
732
+ applyMatrix(m: Matrix4x4): this;
733
+ addSubmobjects(...mobjects: Mobject[]): this;
734
+ removeSubmobject(mobject: Mobject): this;
735
+ clearSubmobjects(): this;
736
+ getSubmobjects(): Mobject[];
737
+ addUpdater(fn: UpdaterFunction<this>, options?: UpdaterOptions): UpdaterHandle;
738
+ removeUpdater(handleOrFn: UpdaterHandle | UpdaterFunction<this>): this;
739
+ clearUpdaters(): this;
740
+ suspendUpdaters(): this;
741
+ resumeUpdaters(): this;
742
+ enableUpdater(handleOrFn: UpdaterHandle | UpdaterFunction<this>): this;
743
+ disableUpdater(handleOrFn: UpdaterHandle | UpdaterFunction<this>): this;
744
+ hasActiveUpdaters(recursive?: boolean): boolean;
745
+ /**
746
+ * Internal API used by UpdaterEngine.
747
+ * Returns a deterministic snapshot for current-frame execution.
748
+ */
749
+ getUpdaterRecordsSnapshot(): MobjectUpdaterRecord[];
750
+ private setUpdaterEnabled;
751
+ protected setPointCloud(points: Array<Vector>): void;
752
+ protected getPointCloud(): Vector[];
753
+ saveState(): this;
754
+ getSavedState(): MobjectState | undefined;
755
+ clearSavedStates(): this;
905
756
  /**
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));
757
+ * Animates back to the last saved state.
758
+ * Pops the saved state from the stack.
759
+ * @throws Error if no state was previously saved
915
760
  */
916
- screenToWorld(pos: Vector2): Vector2;
761
+ restore(durationSeconds?: number): this & {
762
+ toAnimation(): Animation<Mobject>;
763
+ };
764
+ fadeIn(durationSeconds?: number): this & {
765
+ toAnimation(): Animation<Mobject>;
766
+ };
767
+ fadeOut(durationSeconds?: number): this & {
768
+ toAnimation(): Animation<Mobject>;
769
+ };
770
+ moveTo(destination: Vector, durationSeconds?: number): this & {
771
+ toAnimation(): Animation<Mobject>;
772
+ };
773
+ moveTo(x: number, y: number, durationSeconds?: number): this & {
774
+ toAnimation(): Animation<Mobject>;
775
+ };
776
+ moveTo(x: number, y: number, z: number, durationSeconds?: number): this & {
777
+ toAnimation(): Animation<Mobject>;
778
+ };
779
+ rotate(angle: number, durationSeconds?: number): this & {
780
+ toAnimation(): Animation<Mobject>;
781
+ };
782
+ scaleTo(factor: number, durationSeconds?: number): this & {
783
+ toAnimation(): Animation<Mobject>;
784
+ };
785
+ scaleToXY(factorX: number, factorY: number, durationSeconds?: number): this & {
786
+ toAnimation(): Animation<Mobject>;
787
+ };
788
+ duration(seconds: number): this;
789
+ ease(easing: EasingFunction): this;
790
+ delay(seconds: number): this;
791
+ toAnimation(): Animation<Mobject>;
792
+ getQueuedDuration(): number;
793
+ hasQueuedAnimations(): boolean;
917
794
  /**
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
- *
795
+ * Queues multiple animations to run in parallel (simultaneously).
796
+ * Automatically handles both Animation objects and mobject method calls.
923
797
  * @example
924
- * if (camera.isInView(object.position)) {
925
- * console.log('Object is visible');
926
- * }
798
+ * circle.fadeIn(1).parallel(
799
+ * circle.moveTo(100, 50),
800
+ * circle.rotate(Math.PI)
801
+ * ).fadeOut(1);
927
802
  */
928
- isInView(pos: Vector2): boolean;
929
- reset(): this;
803
+ parallel(...items: (Animation<Mobject> | Mobject)[]): this;
930
804
  /**
931
- * Hashes camera config and the CameraFrame's full transform state.
805
+ * Computes a CRC32 hash of this mobject's full state.
806
+ * Used by the segment cache to detect changes.
932
807
  */
933
808
  computeHash(): number;
809
+ protected applyMatrixToOwnGeometry(m: Matrix4x4): void;
810
+ protected usesGeometryTransforms(): boolean;
811
+ private collectGeometryPoints;
812
+ private getGeometryCenter;
813
+ private syncLocalMatrixFromGeometry;
814
+ private updateLogicalStateFromMatrix;
815
+ private setLocalMatrix;
934
816
  }
935
817
 
936
818
  /**
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.
819
+ * A Mobject that is defined by one or more BezierPaths.
820
+ * Supports stroke and fill styling, plus VMobject-specific fluent animations.
953
821
  *
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.
822
+ * Default behavior: visible with white stroke, no fill.
823
+ * - Stroke: white, width 2 (visible by default)
824
+ * - Fill: not rendered by default (fillOpacity = 0)
825
+ *
826
+ * When .fill(color) is called, the default stroke is disabled unless
827
+ * .stroke(color, width) was called explicitly.
828
+ *
829
+ * Use .stroke(color, width) to add a stroke.
830
+ * Use .fill(color) to add a fill (opacity defaults to 1).
974
831
  */
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;
832
+ declare class VMobject extends Mobject {
833
+ protected pathList: BezierPath[];
834
+ /** Stroke color. Only rendered if strokeWidth > 0. */
835
+ protected strokeColor: Color;
836
+ /** Stroke width. Default 2 for visibility. */
837
+ protected strokeWidth: number;
838
+ /** Fill color. Only rendered if fillOpacity > 0. */
839
+ protected fillColor: Color;
840
+ /** Fill opacity. Default 0 means no fill is rendered. */
841
+ protected fillOpacity: number;
842
+ /** Tracks whether stroke() was explicitly called. */
843
+ protected strokeExplicitlySet: boolean;
844
+ constructor();
845
+ get paths(): BezierPath[];
846
+ set paths(value: BezierPath[]);
993
847
  /**
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.
848
+ * Gets the stroke color.
997
849
  */
998
- add(...mobjects: Mobject[]): this;
850
+ getStrokeColor(): Color;
999
851
  /**
1000
- * Remove mobjects from the scene.
852
+ * Gets the stroke width.
1001
853
  */
1002
- remove(...mobjects: Mobject[]): this;
854
+ getStrokeWidth(): number;
1003
855
  /**
1004
- * Check if a mobject is registered with this scene.
856
+ * Gets the fill color.
1005
857
  */
1006
- has(mobject: Mobject): boolean;
858
+ getFillColor(): Color;
1007
859
  /**
1008
- * Get all mobjects in the scene.
860
+ * Gets the fill opacity.
1009
861
  */
1010
- getMobjects(): readonly Mobject[];
862
+ getFillOpacity(): number;
1011
863
  /**
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.
1016
- *
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.
1021
- *
1022
- * @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));
864
+ * Adds a new path to the VMobject.
865
+ * @param path - The BezierPath to add.
866
+ * @returns this for chaining.
1033
867
  */
1034
- play(...items: Array<Animation | Mobject>): this;
868
+ addPath(path: BezierPath): this;
1035
869
  /**
1036
- * Add a delay before the next play() call.
1037
- * @param seconds Number of seconds to wait
870
+ * Sets the stroke color and width.
871
+ * @param color - The stroke color.
872
+ * @param width - The stroke width. Default is 2.
873
+ * @returns this for chaining.
1038
874
  */
1039
- wait(seconds: number): this;
875
+ stroke(color: Color, width?: number): this;
1040
876
  /**
1041
- * Get the current playhead time.
877
+ * Sets the fill color and opacity.
878
+ * If stroke was not explicitly set, the default stroke is disabled.
879
+ * @param color - The fill color.
880
+ * @param opacity - The fill opacity. Defaults to the color's alpha value.
881
+ * @returns this for chaining.
1042
882
  */
1043
- getCurrentTime(): number;
883
+ fill(color: Color, opacity?: number): this;
884
+ getPoints(): PathCommand[];
885
+ setPoints(commands: PathCommand[]): this;
886
+ private getPointsAsVectors;
887
+ getBoundingBox(): {
888
+ minX: number;
889
+ maxX: number;
890
+ minY: number;
891
+ maxY: number;
892
+ };
893
+ protected applyMatrixToOwnGeometry(m: Matrix4x4): void;
1044
894
  /**
1045
- * Get the total duration of all scheduled animations.
895
+ * Progressively draws the VMobject's paths from start to end.
896
+ * Preserves fill throughout the animation.
897
+ * @param durationSeconds - Animation duration in seconds.
898
+ * @returns this for chaining.
899
+ */
900
+ write(durationSeconds?: number): this & {
901
+ toAnimation(): Animation<Mobject>;
902
+ };
903
+ /**
904
+ * Progressively removes the VMobject's paths (reverse of write).
905
+ * @param durationSeconds - Animation duration in seconds.
906
+ * @returns this for chaining.
907
+ */
908
+ unwrite(durationSeconds?: number): this & {
909
+ toAnimation(): Animation<Mobject>;
910
+ };
911
+ /**
912
+ * First draws the stroke progressively (0-50%), then fades in the fill (50-100%).
913
+ * @param durationSeconds - Animation duration in seconds.
914
+ * @returns this for chaining.
915
+ */
916
+ draw(durationSeconds?: number): this & {
917
+ toAnimation(): Animation<Mobject>;
918
+ };
919
+ /**
920
+ * Extends parent hash with VMobject-specific state:
921
+ * stroke/fill colors, widths, opacity, and path geometry.
922
+ */
923
+ computeHash(): number;
924
+ private syncPointCloudFromPaths;
925
+ }
926
+
927
+ /**
928
+ * Configuration options for CameraFrame.
929
+ */
930
+ interface CameraFrameConfig {
931
+ /** Width of the viewport in pixels. Defaults to 1920. */
932
+ pixelWidth?: number;
933
+ /** Height of the viewport in pixels. Defaults to 1080. */
934
+ pixelHeight?: number;
935
+ }
936
+ /**
937
+ * Camera bounds that limit how far the camera can pan.
938
+ */
939
+ interface Bounds {
940
+ minX: number;
941
+ maxX: number;
942
+ minY: number;
943
+ maxY: number;
944
+ }
945
+ /**
946
+ * CameraFrame represents the viewport window in world space.
947
+ * Extends Mobject (not VMobject - no visual representation).
948
+ * Its transform properties define what the camera shows:
949
+ * - scale(2) = zoom OUT (larger frame = see more)
950
+ * - scale(0.5) = zoom IN (smaller frame = see less)
951
+ *
952
+ * The CameraFrame is the primary way to control camera animations in Anima.
953
+ * Access it via `scene.frame` or `scene.camera.frame`.
954
+ *
955
+ * @example
956
+ * // Zoom in over 1 second
957
+ * this.play(this.frame.zoomIn(2).duration(1));
958
+ *
959
+ * @example
960
+ * // Pan to center on an object
961
+ * this.play(this.frame.centerOn(circle).duration(0.5));
962
+ *
963
+ * @example
964
+ * // Fit multiple objects in view
965
+ * this.play(this.frame.fitTo([obj1, obj2, obj3]).duration(1));
966
+ */
967
+ declare class CameraFrame extends Mobject {
968
+ private readonly baseWidth;
969
+ private readonly baseHeight;
970
+ private bounds?;
971
+ /**
972
+ * Creates a new CameraFrame with the specified viewport dimensions.
973
+ *
974
+ * @param config - Configuration options
975
+ * @param config.pixelWidth - Width of the viewport in pixels (default: 1920)
976
+ * @param config.pixelHeight - Height of the viewport in pixels (default: 1080)
977
+ *
978
+ * @example
979
+ * const frame = new CameraFrame({ pixelWidth: 1920, pixelHeight: 1080 });
1046
980
  */
1047
- getTotalDuration(): number;
981
+ constructor(config?: CameraFrameConfig);
1048
982
  /**
1049
- * Get the underlying Timeline for advanced control.
1050
- * Use this for direct manipulation of animation timing.
983
+ * The current width of the frame in world units, accounting for scale.
984
+ * @returns The frame width multiplied by the current scale.x
1051
985
  */
1052
- getTimeline(): Timeline;
986
+ get width(): number;
1053
987
  /**
1054
- * Get the Camera for view control and frame dimensions.
1055
- * Camera calculates Manim-compatible frame dimensions from pixel resolution.
988
+ * The current height of the frame in world units, accounting for scale.
989
+ * @returns The frame height multiplied by the current scale.y
1056
990
  */
1057
- getCamera(): Camera;
991
+ get height(): number;
1058
992
  /**
1059
- * Get the list of segments emitted by play() and wait() calls.
1060
- * Used by the Renderer for cache-aware segmented rendering.
993
+ * Sets the scale of the camera frame.
994
+ * Overrides Mobject.setScale to prevent zero or negative scales.
995
+ *
996
+ * @param sx - Scale factor for the x-axis (must be positive)
997
+ * @param sy - Scale factor for the y-axis (must be positive)
998
+ * @returns This CameraFrame for method chaining
999
+ * @throws Error if sx or sy is zero or negative
1000
+ *
1001
+ * @example
1002
+ * frame.setScale(2, 2); // Zoom out 2x
1003
+ * frame.setScale(0.5, 0.5); // Zoom in 2x
1061
1004
  */
1062
- getSegments(): readonly Segment[];
1005
+ setScale(sx: number, sy: number): this;
1063
1006
  /**
1064
- * Validates and registers animation targets based on lifecycle.
1065
- * Handles composition animations (Sequence, Parallel) by processing children.
1007
+ * Sets bounds that limit how far the camera can pan.
1008
+ * When bounds are set, the camera position is clamped to stay within them,
1009
+ * accounting for the frame size so edges don't go outside bounds.
1010
+ *
1011
+ * @param minX - Minimum x coordinate
1012
+ * @param minY - Minimum y coordinate
1013
+ * @param maxX - Maximum x coordinate
1014
+ * @param maxY - Maximum y coordinate
1015
+ * @returns This CameraFrame for method chaining
1016
+ *
1017
+ * @example
1018
+ * // Limit camera to a 100x100 world area
1019
+ * frame.setBounds(0, 0, 100, 100);
1066
1020
  */
1067
- private validateAndRegisterAnimation;
1021
+ setBounds(minX: number, minY: number, maxX: number, maxY: number): this;
1068
1022
  /**
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
1023
+ * Removes any bounds restrictions on camera movement.
1073
1024
  *
1074
- * This respects the scene graph hierarchy - children of registered
1075
- * VGroups are implicitly in scene via their parent.
1025
+ * @returns This CameraFrame for method chaining
1026
+ *
1027
+ * @example
1028
+ * frame.clearBounds(); // Camera can now pan freely
1076
1029
  */
1077
- isInScene(mobject: Mobject): boolean;
1030
+ clearBounds(): this;
1078
1031
  /**
1079
- * Gets children of composition animations (Sequence, Parallel).
1080
- * Returns empty array for non-composition animations.
1032
+ * Checks if the camera has bounds set.
1033
+ *
1034
+ * @returns True if bounds are set, false otherwise
1081
1035
  */
1082
- private getAnimationChildren;
1036
+ hasBounds(): boolean;
1083
1037
  /**
1084
- * Computes a holistic CRC32 hash for a segment.
1085
- * Includes camera state, all current mobjects, animations, and timing.
1038
+ * Gets the current bounds configuration.
1039
+ *
1040
+ * @returns The bounds object or undefined if no bounds are set
1086
1041
  */
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;
1133
- }
1134
-
1135
- /**
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).
1148
- */
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[]);
1042
+ getBounds(): Bounds | undefined;
1164
1043
  /**
1165
- * Gets the stroke color.
1044
+ * Sets the position of the camera frame.
1045
+ * Overrides Mobject.pos to clamp position within bounds if set.
1046
+ *
1047
+ * @param x - The x coordinate in world space
1048
+ * @param y - The y coordinate in world space
1049
+ * @returns This CameraFrame for method chaining
1050
+ *
1051
+ * @example
1052
+ * frame.pos(5, 3); // Move camera center to (5, 3)
1166
1053
  */
1167
- getStrokeColor(): Color;
1054
+ pos(x: number, y: number): this;
1168
1055
  /**
1169
- * Gets the stroke width.
1056
+ * Smoothly zoom the camera in by the given factor.
1057
+ * Internally scales the frame down, which makes objects appear larger.
1058
+ *
1059
+ * @param factor - Zoom multiplier. 2 = objects appear 2x larger (default: 2)
1060
+ * @returns FluentAnimation that can be chained with .duration() and .ease()
1061
+ * @throws Error if factor is zero or negative
1062
+ *
1063
+ * @example
1064
+ * // Zoom in 2x over 1 second
1065
+ * this.play(this.frame.zoomIn(2).duration(1));
1066
+ *
1067
+ * @example
1068
+ * // Zoom in 3x with easing
1069
+ * this.play(this.frame.zoomIn(3).duration(1.5).ease(easeInOutQuad));
1170
1070
  */
1171
- getStrokeWidth(): number;
1071
+ zoomIn(factor?: number): this & {
1072
+ toAnimation(): Animation<Mobject>;
1073
+ };
1172
1074
  /**
1173
- * Gets the fill color.
1075
+ * Smoothly zoom the camera out by the given factor.
1076
+ * Internally scales the frame up, which makes objects appear smaller.
1077
+ *
1078
+ * @param factor - Zoom multiplier. 2 = objects appear 2x smaller (default: 2)
1079
+ * @returns FluentAnimation that can be chained with .duration() and .ease()
1080
+ * @throws Error if factor is zero or negative
1081
+ *
1082
+ * @example
1083
+ * // Zoom out 2x over 1 second
1084
+ * this.play(this.frame.zoomOut(2).duration(1));
1085
+ *
1086
+ * @example
1087
+ * // Zoom out to show more of the scene
1088
+ * this.play(this.frame.zoomOut(4).duration(2).ease(easeOutCubic));
1174
1089
  */
1175
- getFillColor(): Color;
1090
+ zoomOut(factor?: number): this & {
1091
+ toAnimation(): Animation<Mobject>;
1092
+ };
1176
1093
  /**
1177
- * Gets the fill opacity.
1094
+ * Move the camera to center on a target Mobject.
1095
+ * The camera will smoothly pan so the target is at the center of the frame.
1096
+ *
1097
+ * @param target - The Mobject to center on
1098
+ * @returns FluentAnimation that can be chained with .duration() and .ease()
1099
+ * @throws Error if target is null or undefined
1100
+ *
1101
+ * @example
1102
+ * // Center on a circle over 0.5 seconds
1103
+ * this.play(this.frame.centerOn(circle).duration(0.5));
1104
+ *
1105
+ * @example
1106
+ * // Pan to focus on different objects in sequence
1107
+ * await this.play(this.frame.centerOn(obj1).duration(1));
1108
+ * await this.play(this.frame.centerOn(obj2).duration(1));
1178
1109
  */
1179
- getFillOpacity(): number;
1110
+ centerOn(target: Mobject): this & {
1111
+ toAnimation(): Animation<Mobject>;
1112
+ };
1180
1113
  /**
1181
- * Adds a new path to the VMobject.
1182
- * @param path - The BezierPath to add.
1183
- * @returns this for chaining.
1114
+ * Zoom in/out while keeping a specific world point fixed on screen.
1115
+ * Like pinch-to-zoom behavior where the pinch point stays stationary.
1116
+ *
1117
+ * Uses the formula: C' = P * (1 - factor) + C * factor
1118
+ * Where P = point, C = current center, factor = zoom factor.
1119
+ *
1120
+ * @param factor - Scale multiplier. Less than 1 for zoom in, greater than 1 for zoom out
1121
+ * @param point - World coordinates to keep fixed on screen
1122
+ * @returns Parallel animation combining move and scale
1123
+ * @throws Error if factor is zero or negative
1124
+ *
1125
+ * @example
1126
+ * // Zoom in 2x on a specific point
1127
+ * this.play(frame.zoomToPoint(0.5, { x: 5, y: 5 }).duration(1));
1128
+ *
1129
+ * @example
1130
+ * // Zoom out while keeping an object's position fixed
1131
+ * this.play(frame.zoomToPoint(2, circle.position).duration(1));
1184
1132
  */
1185
- addPath(path: BezierPath): this;
1133
+ zoomToPoint(factor: number, point: {
1134
+ x: number;
1135
+ y: number;
1136
+ }): Animation;
1186
1137
  /**
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.
1138
+ * Automatically frame one or more objects with optional margin.
1139
+ * Calculates the bounding box of all targets and animates the camera
1140
+ * to show them all with the specified margin around them.
1141
+ *
1142
+ * @param targets - Single Mobject or array of Mobjects to frame
1143
+ * @param margin - Padding around the objects in world units (default: 0.5)
1144
+ * @returns FluentAnimation that can be chained with .duration() and .ease()
1145
+ * @throws Error if targets array is empty
1146
+ *
1147
+ * @example
1148
+ * // Fit a single object with default margin
1149
+ * this.play(this.frame.fitTo(circle).duration(1));
1150
+ *
1151
+ * @example
1152
+ * // Fit multiple objects with custom margin
1153
+ * this.play(this.frame.fitTo([obj1, obj2, obj3], 1.0).duration(1.5));
1154
+ *
1155
+ * @example
1156
+ * // Show all objects in the scene
1157
+ * this.play(this.frame.fitTo(allObjects, 0).duration(2));
1191
1158
  */
1192
- stroke(color: Color, width?: number): this;
1159
+ fitTo(targets: Mobject | Mobject[], margin?: number): this & {
1160
+ toAnimation(): Animation<Mobject>;
1161
+ };
1162
+ private calculateBounds;
1163
+ private hasGetBoundingBox;
1164
+ }
1165
+
1166
+ /**
1167
+ * Configuration options for Camera.
1168
+ */
1169
+ interface CameraConfig {
1170
+ /** Pixel width for aspect ratio calculation. Default: 1920 */
1171
+ readonly pixelWidth?: number;
1172
+ /** Pixel height for aspect ratio calculation. Default: 1080 */
1173
+ readonly pixelHeight?: number;
1174
+ }
1175
+ /**
1176
+ * Resolved camera configuration with all defaults applied.
1177
+ */
1178
+ interface ResolvedCameraConfig {
1179
+ readonly pixelWidth: number;
1180
+ readonly pixelHeight: number;
1181
+ }
1182
+
1183
+ /**
1184
+ * Camera manages the view into the scene.
1185
+ * Uses CameraFrame (a Mobject) to store transform state, enabling camera animations.
1186
+ *
1187
+ * The Camera provides both instant manipulation methods (panTo, zoomTo) and
1188
+ * access to the CameraFrame for fluent animation APIs.
1189
+ *
1190
+ * @example
1191
+ * // Instant camera manipulation
1192
+ * camera.zoomTo(2);
1193
+ * camera.panTo(new Vector(5, 3));
1194
+ *
1195
+ * @example
1196
+ * // Animated camera movement via frame
1197
+ * this.play(this.frame.zoomIn(2).duration(1));
1198
+ * this.play(this.frame.centerOn(circle).duration(0.5));
1199
+ */
1200
+ declare class Camera {
1201
+ private readonly config;
1202
+ /** The CameraFrame that stores the camera's transform state. Use this for animations. */
1203
+ readonly frame: CameraFrame;
1193
1204
  /**
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.
1205
+ * Creates a new Camera with the specified viewport dimensions.
1206
+ *
1207
+ * @param config - Configuration options
1208
+ * @param config.pixelWidth - Width of the viewport in pixels (default: 1920)
1209
+ * @param config.pixelHeight - Height of the viewport in pixels (default: 1080)
1199
1210
  */
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
- };
1211
+ constructor(config?: CameraConfig);
1212
+ get frameHeight(): number;
1213
+ get frameWidth(): number;
1214
+ get frameYRadius(): number;
1215
+ get frameXRadius(): number;
1216
+ get pixelWidth(): number;
1217
+ get pixelHeight(): number;
1218
+ get position(): Vector;
1219
+ get zoom(): number;
1220
+ get rotation(): number;
1221
+ pan(delta: Vector): this;
1222
+ panTo(position: Vector): this;
1223
+ zoomTo(level: number): this;
1224
+ rotateTo(angle: number): this;
1225
+ getViewMatrix(): Matrix4x4;
1210
1226
  /**
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.
1227
+ * Transforms a world-space position to screen-space (pixel) coordinates.
1228
+ *
1229
+ * Screen coordinates have origin at top-left, with x increasing right
1230
+ * and y increasing downward.
1231
+ *
1232
+ * @param pos - Position in world coordinates
1233
+ * @returns Position in screen coordinates (pixels)
1234
+ *
1235
+ * @example
1236
+ * const screenPos = camera.worldToScreen(circle.position);
1237
+ * console.log(`Circle is at pixel (${screenPos.x}, ${screenPos.y})`);
1215
1238
  */
1216
- write(durationSeconds?: number): this & {
1217
- toAnimation(): Animation<Mobject>;
1218
- };
1239
+ worldToScreen(pos: Vector): Vector;
1219
1240
  /**
1220
- * Progressively removes the VMobject's paths (reverse of write).
1221
- * @param durationSeconds - Animation duration in seconds.
1222
- * @returns this for chaining.
1241
+ * Transforms a screen-space (pixel) position to world coordinates.
1242
+ * This is the inverse of worldToScreen.
1243
+ *
1244
+ * @param pos - Position in screen coordinates (pixels, origin at top-left)
1245
+ * @returns Position in world coordinates
1246
+ *
1247
+ * @example
1248
+ * // Convert a mouse click position to world coordinates
1249
+ * const worldPos = camera.screenToWorld(new Vector(mouseX, mouseY));
1223
1250
  */
1224
- unwrite(durationSeconds?: number): this & {
1225
- toAnimation(): Animation<Mobject>;
1226
- };
1251
+ screenToWorld(pos: Vector): Vector;
1227
1252
  /**
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.
1253
+ * Checks if a world-space position is currently visible within the camera frame.
1254
+ *
1255
+ * @param pos - Position in world coordinates to check
1256
+ * @returns True if the position is within the visible frame bounds
1257
+ *
1258
+ * @example
1259
+ * if (camera.isInView(object.position)) {
1260
+ * console.log('Object is visible');
1261
+ * }
1231
1262
  */
1232
- draw(durationSeconds?: number): this & {
1233
- toAnimation(): Animation<Mobject>;
1234
- };
1263
+ isInView(pos: Vector): boolean;
1264
+ reset(): this;
1235
1265
  /**
1236
- * Extends parent hash with VMobject-specific state:
1237
- * stroke/fill colors, widths, opacity, and path geometry.
1266
+ * Hashes camera config and the CameraFrame's full transform state.
1238
1267
  */
1239
1268
  computeHash(): number;
1240
1269
  }
@@ -1245,11 +1274,9 @@ type Edge = 'TOP' | 'BOTTOM' | 'LEFT' | 'RIGHT';
1245
1274
 
1246
1275
  /**
1247
1276
  * A collection of VMobjects that can be manipulated as a single unit.
1248
- * Uses Scene Graph hierarchy: transforms on parent are inherited by children
1249
- * via getWorldMatrix() calculation, not by mutating child matrices.
1277
+ * Uses Mobject's submobject hierarchy and recursive geometry transforms.
1250
1278
  */
1251
1279
  declare class VGroup extends VMobject {
1252
- protected children: VMobject[];
1253
1280
  constructor(...mobjects: VMobject[]);
1254
1281
  get length(): number;
1255
1282
  add(...mobjects: VMobject[]): this;
@@ -1257,7 +1284,6 @@ declare class VGroup extends VMobject {
1257
1284
  clear(): this;
1258
1285
  getChildren(): VMobject[];
1259
1286
  get(index: number): VMobject | undefined;
1260
- pos(x: number, y: number): this;
1261
1287
  show(): this;
1262
1288
  hide(): this;
1263
1289
  /**
@@ -1290,10 +1316,6 @@ declare class VGroup extends VMobject {
1290
1316
  toCorner(corner: CornerPosition, buff?: number): this;
1291
1317
  arrange(direction?: Direction, buff?: number, shouldCenter?: boolean): this;
1292
1318
  alignTo(target: VMobject, edge: Edge): this;
1293
- /**
1294
- * Recursively hashes this VGroup and all children.
1295
- * Any child state change invalidates segments containing this group.
1296
- */
1297
1319
  computeHash(): number;
1298
1320
  }
1299
1321
 
@@ -1310,14 +1332,14 @@ declare class Circle extends Arc {
1310
1332
  }
1311
1333
 
1312
1334
  declare class Line extends VMobject {
1313
- readonly start: Vector2;
1314
- readonly end: Vector2;
1335
+ readonly start: Vector;
1336
+ readonly end: Vector;
1315
1337
  constructor(x1?: number, y1?: number, x2?: number, y2?: number);
1316
1338
  private generatePath;
1317
1339
  }
1318
1340
 
1319
1341
  declare class Polygon extends VMobject {
1320
- readonly vertices: Vector2[];
1342
+ readonly vertices: Vector[];
1321
1343
  constructor(...points: Array<[number, number]>);
1322
1344
  private generatePath;
1323
1345
  }
@@ -1417,7 +1439,7 @@ declare class GraphNode extends VMobject {
1417
1439
  * Uses the standard 4-point circle approximation with control point factor ~0.5523.
1418
1440
  */
1419
1441
  private generateCirclePath;
1420
- getCenter(): Vector2;
1442
+ getCenter(): Vector;
1421
1443
  }
1422
1444
 
1423
1445
  /**
@@ -1455,167 +1477,62 @@ declare class Graph extends VGroup {
1455
1477
  /** Adds a node to the graph. */
1456
1478
  addNode(id: GraphNodeId, config?: NodeConfig): GraphNode;
1457
1479
  /** 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;
1469
- }
1470
-
1471
- /**
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
1480
- */
1481
- declare abstract class IntroductoryAnimation<T extends Mobject = Mobject> extends Animation<T> {
1482
- readonly lifecycle: AnimationLifecycle;
1483
- }
1484
-
1485
- /**
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
1495
- */
1496
- declare abstract class TransformativeAnimation<T extends Mobject = Mobject> extends Animation<T> {
1497
- readonly lifecycle: AnimationLifecycle;
1498
- protected initialized: boolean;
1499
- /**
1500
- * Captures the start state from the target.
1501
- * Called once when the animation first becomes active.
1502
- */
1503
- protected abstract captureStartState(): void;
1504
- ensureInitialized(): void;
1505
- reset(): void;
1506
- }
1507
-
1508
- /**
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
1518
- */
1519
- declare abstract class ExitAnimation<T extends Mobject = Mobject> extends Animation<T> {
1520
- readonly lifecycle: AnimationLifecycle;
1521
- }
1522
-
1523
- /**
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.
1528
- *
1529
- * @example
1530
- * const circle = new Circle(1);
1531
- * scene.play(new FadeIn(circle)); // Circle is auto-registered and faded in
1532
- */
1533
- declare class FadeIn<T extends Mobject = Mobject> extends IntroductoryAnimation<T> {
1534
- private readonly startOpacity;
1535
- constructor(target: T);
1536
- interpolate(progress: number): void;
1537
- }
1538
-
1539
- /**
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
1549
- */
1550
- declare class FadeOut<T extends Mobject = Mobject> extends ExitAnimation<T> {
1551
- private startOpacity;
1552
- interpolate(progress: number): void;
1553
- }
1554
-
1555
- /**
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.
1561
- *
1562
- * @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.
1580
- *
1581
- * This is a transformative animation - the target must already be in the scene.
1582
- * Start rotation is captured lazily when animation becomes active.
1583
- *
1584
- * @example
1585
- * scene.add(square);
1586
- * scene.play(new Rotate(square, Math.PI / 4)); // Rotate 45 degrees
1587
- */
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;
1594
- interpolate(progress: number): void;
1595
- /** Returns the total rotation angle in radians. */
1596
- getAngle(): number;
1480
+ removeNode(id: GraphNodeId): this;
1481
+ getNode(id: GraphNodeId): GraphNode | undefined;
1482
+ getNodes(): GraphNode[];
1483
+ addEdge(sourceId: GraphNodeId, targetId: GraphNodeId, config?: EdgeConfig): GraphEdge | undefined;
1484
+ removeEdge(sourceId: GraphNodeId, targetId: GraphNodeId): this;
1485
+ private removeEdgeInternal;
1486
+ getEdgePath(sourceId: GraphNodeId, targetId: GraphNodeId): ReturnType<GraphEdge['getPath']>;
1487
+ getEdges(): GraphEdge[];
1488
+ /** Applies a layout algorithm to reposition all nodes. */
1489
+ layout(type: LayoutType, config?: LayoutConfig): this;
1490
+ updateEdges(): this;
1597
1491
  }
1598
1492
 
1599
1493
  /**
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
1494
+ * Abstract base class for all animations.
1495
+ * Provides configuration for duration, easing, and delay.
1496
+ * Subclasses must specify their lifecycle category.
1609
1497
  */
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;
1498
+ declare abstract class Animation<T extends Mobject = Mobject> {
1499
+ protected readonly target: T;
1500
+ protected durationSeconds: number;
1501
+ protected easingFn: EasingFunction;
1502
+ protected delaySeconds: number;
1503
+ /**
1504
+ * The lifecycle category of this animation.
1505
+ * Determines how Scene.play() handles scene registration and validation.
1506
+ */
1507
+ abstract readonly lifecycle: AnimationLifecycle;
1508
+ constructor(target: T);
1509
+ duration(seconds: number): this;
1510
+ ease(easing: EasingFunction): this;
1511
+ delay(seconds: number): this;
1512
+ getDuration(): number;
1513
+ getDelay(): number;
1514
+ getEasing(): EasingFunction;
1515
+ getTarget(): T;
1516
+ getConfig(): AnimationConfig;
1517
+ abstract interpolate(progress: number): void;
1518
+ /**
1519
+ * Ensures the animation is initialized before interpolation.
1520
+ * Called before first update to capture start state.
1521
+ * Default: no-op. Override in subclasses that need lazy initialization.
1522
+ */
1523
+ ensureInitialized(): void;
1524
+ /**
1525
+ * Resets the animation to its uninitialized state.
1526
+ * Allows animations to be replayed or looped.
1527
+ */
1528
+ reset(): void;
1529
+ update(progress: number): void;
1530
+ /**
1531
+ * Hashes the animation type, config, and target state.
1532
+ * Subclass-specific behavior is captured through the target's hash,
1533
+ * since animations mutate the target.
1534
+ */
1535
+ computeHash(): number;
1619
1536
  }
1620
1537
 
1621
1538
  /**
@@ -1640,322 +1557,528 @@ declare class MorphTo<T extends VMobject = VMobject> extends TransformativeAnima
1640
1557
  }
1641
1558
 
1642
1559
  /**
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
1560
+ * Supported value types for keyframe interpolation.
1561
+ */
1562
+ type KeyframeValue = number;
1563
+ /**
1564
+ * A single keyframe with a normalized time position [0,1] and value.
1565
+ */
1566
+ interface Keyframe<T extends KeyframeValue = KeyframeValue> {
1567
+ /** Normalized time position in [0, 1]. */
1568
+ readonly time: number;
1569
+ /** The value at this keyframe. */
1570
+ readonly value: T;
1571
+ /** Optional easing function for interpolation TO this keyframe. */
1572
+ readonly easing?: EasingFunction;
1573
+ }
1574
+ /**
1575
+ * Interpolation function for a specific value type.
1576
+ * Takes start value, end value, and progress [0,1], returns interpolated value.
1577
+ */
1578
+ type InterpolatorFn<T> = (start: T, end: T, progress: number) => T;
1579
+
1580
+ /**
1581
+ * Manages a sequence of keyframes for animating a single property.
1582
+ * Keyframes are stored sorted by time and interpolated on demand.
1583
+ */
1584
+ declare class KeyframeTrack<T extends KeyframeValue = number> {
1585
+ private keyframes;
1586
+ private readonly interpolator;
1587
+ /**
1588
+ * Creates a new KeyframeTrack with the specified interpolator.
1589
+ * Defaults to linear number interpolation.
1590
+ */
1591
+ constructor(interpolator?: InterpolatorFn<T>);
1592
+ /**
1593
+ * Adds a keyframe at the specified normalized time.
1594
+ * Time must be in [0, 1]. Replaces existing keyframe at same time.
1595
+ */
1596
+ addKeyframe(time: number, value: T, easing?: EasingFunction): this;
1597
+ removeKeyframe(time: number): boolean;
1598
+ /**
1599
+ * Gets the keyframe at the specified time.
1600
+ * Returns undefined if no keyframe exists at that time.
1601
+ */
1602
+ getKeyframe(time: number): Keyframe<T> | undefined;
1603
+ /** All keyframes sorted by time. */
1604
+ getKeyframes(): ReadonlyArray<Keyframe<T>>;
1605
+ /** Interpolated value at normalized time (uses target keyframe easing). */
1606
+ getValueAt(time: number): T;
1607
+ getKeyframeCount(): number;
1608
+ }
1609
+
1610
+ /**
1611
+ * Property setter function type for applying values to a Mobject.
1612
+ */
1613
+ type PropertySetter<T extends Mobject, V> = (target: T, value: V) => void;
1614
+ /**
1615
+ * Animation that interpolates multiple property tracks via keyframes.
1616
+ * Each track controls a single property and is interpolated independently.
1650
1617
  *
1651
- * This is an introductory animation - it auto-registers the target with the scene.
1618
+ * This is a transformative animation - the target must already be in the scene.
1652
1619
  */
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;
1620
+ declare class KeyframeAnimation<T extends Mobject = Mobject> extends Animation<T> {
1621
+ private readonly tracks;
1622
+ readonly lifecycle: AnimationLifecycle;
1623
+ /**
1624
+ * Adds a named keyframe track with its property setter.
1625
+ * The setter is called during interpolation to apply values to the target.
1626
+ */
1627
+ addTrack<V extends KeyframeValue>(name: string, track: KeyframeTrack<V>, setter: PropertySetter<T, V>): this;
1628
+ /** Gets a track by name. */
1629
+ getTrack<V extends KeyframeValue>(name: string): KeyframeTrack<V> | undefined;
1630
+ /** All track names. */
1631
+ getTrackNames(): string[];
1632
+ /**
1633
+ * Interpolates all tracks at the given progress and applies values to target.
1634
+ */
1665
1635
  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;
1670
1636
  }
1671
1637
 
1638
+ type FollowOffsetInput = Vector | readonly [number, number] | readonly [number, number, number];
1672
1639
  /**
1673
- * Animation that progressively draws VMobject paths from start to end.
1640
+ * Configuration options for the Follow animation.
1641
+ */
1642
+ interface FollowConfig {
1643
+ /**
1644
+ * Offset from the target's position. The camera will track
1645
+ * (target.position + offset) instead of the exact target position.
1646
+ * Accepts:
1647
+ * - `Vector`
1648
+ * - `[x, y]`
1649
+ * - `[x, y, z]`
1650
+ *
1651
+ * Note: camera follow movement is planar, so only x/y affect the CameraFrame position.
1652
+ * If provided, z is accepted for API consistency but ignored by this animation.
1653
+ * @default Vector.ZERO
1654
+ */
1655
+ offset?: FollowOffsetInput;
1656
+ /**
1657
+ * Damping factor for smooth following (0 to 1).
1658
+ * - 0 = instant snap to target (no smoothing)
1659
+ * - 0.9 = very smooth, slow following
1660
+ * Higher values create a more "laggy" camera that takes longer to catch up.
1661
+ * @default 0
1662
+ */
1663
+ damping?: number;
1664
+ }
1665
+ /**
1666
+ * Animation that makes a CameraFrame track a target Mobject's position over time.
1667
+ * Unlike MoveTo which captures position once, Follow reads the target position
1668
+ * every frame, allowing the camera to track moving objects.
1674
1669
  *
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
1670
+ * @example
1671
+ * // Basic follow - camera snaps to target position
1672
+ * this.play(new Follow(this.frame, movingCircle).duration(5));
1678
1673
  *
1679
- * This is an introductory animation - it auto-registers the target with the scene.
1674
+ * @example
1675
+ * // Smooth follow with damping
1676
+ * this.play(new Follow(this.frame, player, { damping: 0.8 }).duration(10));
1677
+ *
1678
+ * @example
1679
+ * // Follow with offset (camera leads the target)
1680
+ * this.play(new Follow(this.frame, car, {
1681
+ * offset: [2, 0], // Camera 2 units ahead
1682
+ * damping: 0.5
1683
+ * }).duration(10));
1684
+ *
1685
+ * @example
1686
+ * // 3D tuple offset is accepted for consistency, but z is ignored by camera follow
1687
+ * this.play(new Follow(this.frame, car, {
1688
+ * offset: [2, 0, 1],
1689
+ * damping: 0.5
1690
+ * }).duration(10));
1680
1691
  */
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;
1692
+ declare class Follow extends Animation<CameraFrame> {
1693
+ readonly lifecycle: AnimationLifecycle;
1694
+ private readonly followTarget;
1695
+ private readonly offset;
1696
+ private readonly damping;
1697
+ /**
1698
+ * Creates a new Follow animation.
1699
+ *
1700
+ * @param frame - The CameraFrame to animate
1701
+ * @param target - The Mobject to follow
1702
+ * @param config - Configuration options
1703
+ * @throws Error if frame is null or undefined
1704
+ * @throws Error if target is null or undefined
1705
+ *
1706
+ * @example
1707
+ * const follow = new Follow(scene.frame, player, { damping: 0.7 });
1708
+ * this.play(follow.duration(10));
1709
+ */
1710
+ constructor(frame: CameraFrame, target: Mobject, config?: FollowConfig);
1711
+ /**
1712
+ * Updates the camera position each frame to track the target.
1713
+ * @param progress - Animation progress (0 to 1)
1714
+ */
1693
1715
  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;
1716
+ private static normalizeOffset;
1717
+ }
1718
+
1719
+ /**
1720
+ * Configuration options for the Shake animation.
1721
+ */
1722
+ interface ShakeConfig {
1723
+ /**
1724
+ * Maximum displacement distance in world units.
1725
+ * Higher values create more violent shaking.
1726
+ * @default 0.2
1727
+ */
1728
+ intensity?: number;
1729
+ /**
1730
+ * Number of oscillations per second.
1731
+ * Higher values create faster, more frantic shaking.
1732
+ * @default 10
1733
+ */
1734
+ frequency?: number;
1735
+ /**
1736
+ * Controls how quickly the shake diminishes over time.
1737
+ * - 0 = no decay (constant intensity throughout)
1738
+ * - 1 = linear decay
1739
+ * - Higher values = faster decay (shake fades quickly)
1740
+ * @default 1
1741
+ */
1742
+ decay?: number;
1698
1743
  }
1699
-
1700
1744
  /**
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.
1745
+ * Camera shake effect animation.
1746
+ * Creates procedural displacement using layered sine waves to simulate
1747
+ * impacts, explosions, or earthquakes.
1704
1748
  *
1705
- * Supports VGroup (including Text): animates each child's paths progressively.
1749
+ * The shake automatically returns to the original position when complete.
1706
1750
  *
1707
- * This is an exit animation - the target must already be in the scene.
1751
+ * @example
1752
+ * // Basic shake effect
1753
+ * this.play(new Shake(this.frame).duration(0.5));
1708
1754
  *
1709
1755
  * @example
1710
- * scene.play(new Write(text));
1711
- * scene.play(new Unwrite(text)); // Text is erased progressively
1756
+ * // Intense explosion shake with quick decay
1757
+ * this.play(new Shake(this.frame, {
1758
+ * intensity: 0.5,
1759
+ * frequency: 20,
1760
+ * decay: 2
1761
+ * }).duration(0.3));
1762
+ *
1763
+ * @example
1764
+ * // Subtle earthquake with slow decay
1765
+ * this.play(new Shake(this.frame, {
1766
+ * intensity: 0.1,
1767
+ * frequency: 5,
1768
+ * decay: 0.5
1769
+ * }).duration(3));
1712
1770
  */
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);
1771
+ declare class Shake extends TransformativeAnimation<CameraFrame> {
1772
+ private originalPosition;
1773
+ private readonly intensity;
1774
+ private readonly frequency;
1775
+ private readonly decay;
1776
+ private readonly seedX;
1777
+ private readonly seedY;
1778
+ /**
1779
+ * Creates a new Shake animation.
1780
+ *
1781
+ * @param frame - The CameraFrame to shake
1782
+ * @param config - Configuration options for intensity, frequency, and decay
1783
+ *
1784
+ * @example
1785
+ * const shake = new Shake(scene.frame, { intensity: 0.3 });
1786
+ * this.play(shake.duration(0.5));
1787
+ */
1788
+ constructor(frame: CameraFrame, config?: ShakeConfig);
1789
+ /**
1790
+ * Captures the original position before shake begins.
1791
+ */
1792
+ protected captureStartState(): void;
1793
+ /**
1794
+ * Applies procedural shake displacement each frame.
1795
+ * @param progress - Animation progress (0 to 1)
1796
+ */
1722
1797
  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;
1798
+ /**
1799
+ * Generates pseudo-random noise using layered sine waves.
1800
+ * @param t - Time value
1801
+ * @param seed - Random seed for variation
1802
+ * @returns Noise value between -1 and 1
1803
+ */
1804
+ private noise;
1727
1805
  }
1728
1806
 
1729
1807
  /**
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.
1808
+ * Represents an animation scheduled at a specific time on the Timeline.
1735
1809
  */
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;
1810
+ interface ScheduledAnimation {
1811
+ /** The animation to play */
1812
+ readonly animation: Animation;
1813
+ /** Start time in seconds from timeline beginning */
1814
+ readonly startTime: number;
1743
1815
  }
1744
1816
  /**
1745
- * Interpolation function for a specific value type.
1746
- * Takes start value, end value, and progress [0,1], returns interpolated value.
1817
+ * Configuration options for Timeline.
1747
1818
  */
1748
- type InterpolatorFn<T> = (start: T, end: T, progress: number) => T;
1819
+ interface TimelineConfig {
1820
+ /** Whether the timeline loops. Default: false */
1821
+ readonly loop?: boolean;
1822
+ }
1749
1823
 
1750
1824
  /**
1751
- * Manages a sequence of keyframes for animating a single property.
1752
- * Keyframes are stored sorted by time and interpolated on demand.
1825
+ * Timeline schedules and controls playback of animations.
1826
+ * Animations can be scheduled at specific times and the timeline
1827
+ * provides seek/state access for non-linear playback.
1753
1828
  */
1754
- declare class KeyframeTrack<T extends KeyframeValue = number> {
1755
- private keyframes;
1756
- private readonly interpolator;
1829
+ declare class Timeline {
1830
+ private readonly scheduled;
1831
+ private readonly config;
1832
+ private currentTime;
1833
+ constructor(config?: TimelineConfig);
1757
1834
  /**
1758
- * Creates a new KeyframeTrack with the specified interpolator.
1759
- * Defaults to linear number interpolation.
1835
+ * Schedule an animation to start at a specific time.
1836
+ * @param animation The animation to schedule
1837
+ * @param startTime Start time in seconds (default: 0)
1760
1838
  */
1761
- constructor(interpolator?: InterpolatorFn<T>);
1839
+ schedule(animation: Animation, startTime?: number): this;
1762
1840
  /**
1763
- * Adds a keyframe at the specified normalized time.
1764
- * Time must be in [0, 1]. Replaces existing keyframe at same time.
1841
+ * Schedule multiple animations to play in sequence.
1842
+ * First animation starts at the given startTime, subsequent
1843
+ * animations start after the previous one ends.
1844
+ * @param animations Animations to schedule sequentially
1845
+ * @param startTime Start time for the first animation (default: 0)
1765
1846
  */
1766
- addKeyframe(time: number, value: T, easing?: EasingFunction): this;
1767
- removeKeyframe(time: number): boolean;
1847
+ scheduleSequence(animations: Animation[], startTime?: number): this;
1768
1848
  /**
1769
- * Gets the keyframe at the specified time.
1770
- * Returns undefined if no keyframe exists at that time.
1849
+ * Schedule multiple animations to play in parallel.
1850
+ * All animations start at the same time.
1851
+ * @param animations Animations to schedule in parallel
1852
+ * @param startTime Start time for all animations (default: 0)
1771
1853
  */
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;
1854
+ scheduleParallel(animations: Animation[], startTime?: number): this;
1855
+ /**
1856
+ * Get all scheduled animations with resolved timing information.
1857
+ */
1858
+ private getResolved;
1859
+ /**
1860
+ * Get total duration of the timeline.
1861
+ * Returns the end time of the last animation to finish.
1862
+ */
1863
+ getTotalDuration(): number;
1864
+ /**
1865
+ * Seek to a specific time and update all animations.
1866
+ * @param time Time in seconds to seek to
1867
+ */
1868
+ seek(time: number): void;
1869
+ /**
1870
+ * Get the timeline state at a specific time without modifying the
1871
+ * current playhead position.
1872
+ * @param time Time in seconds
1873
+ */
1874
+ getStateAt(time: number): void;
1875
+ /**
1876
+ * Get the current time of the timeline.
1877
+ */
1878
+ getCurrentTime(): number;
1879
+ /**
1880
+ * Get all scheduled animations.
1881
+ */
1882
+ getScheduled(): readonly ScheduledAnimation[];
1883
+ /**
1884
+ * Check if timeline is configured to loop.
1885
+ */
1886
+ isLooping(): boolean;
1887
+ /**
1888
+ * Clear all scheduled animations.
1889
+ */
1890
+ clear(): void;
1778
1891
  }
1779
1892
 
1780
1893
  /**
1781
- * Property setter function type for applying values to a Mobject.
1894
+ * Configuration options for Scene.
1782
1895
  */
1783
- type PropertySetter<T extends Mobject, V> = (target: T, value: V) => void;
1896
+ interface SceneConfig {
1897
+ /** Pixel width of the scene. Default: 1920 */
1898
+ readonly width?: number;
1899
+ /** Pixel height of the scene. Default: 1080 */
1900
+ readonly height?: number;
1901
+ /** Background color. Default: BLACK */
1902
+ readonly backgroundColor?: Color;
1903
+ /** Frames per second. Default: 60 */
1904
+ readonly frameRate?: number;
1905
+ }
1906
+
1907
+ /** Protocol for objects that contribute to segment hashing. */
1908
+ interface Hashable {
1909
+ computeHash(): number;
1910
+ }
1911
+
1784
1912
  /**
1785
- * Animation that interpolates multiple property tracks via keyframes.
1786
- * Each track controls a single property and is interpolated independently.
1913
+ * A Segment represents one independent rendering unit,
1914
+ * corresponding to a single play() or wait() call.
1787
1915
  *
1788
- * This is a transformative animation - the target must already be in the scene.
1916
+ * Its hash is a holistic CRC32 composition of the camera state,
1917
+ * all current mobjects, and the animations for this segment.
1789
1918
  */
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[];
1919
+ interface Segment {
1920
+ /** Zero-based index in the scene's segment list. */
1921
+ readonly index: number;
1922
+ /** Start time in seconds. */
1923
+ readonly startTime: number;
1924
+ /** End time in seconds. */
1925
+ readonly endTime: number;
1926
+ /** Animations scheduled in this segment (empty for wait segments). */
1927
+ readonly animations: readonly Animation[];
1928
+ /** CRC32 hash of camera + mobjects + animations at this point. */
1929
+ readonly hash: number;
1930
+ }
1931
+
1932
+ /**
1933
+ * Manages a disk-based cache of rendered segment partial files.
1934
+ *
1935
+ * Each segment is stored as a video file keyed by its CRC32 hash.
1936
+ * On re-render, segments whose hashes match an existing file are skipped.
1937
+ */
1938
+ declare class SegmentCache {
1939
+ private readonly cacheDir;
1940
+ constructor(cacheDir: string);
1941
+ /** Ensure the cache directory exists. */
1942
+ init(): Promise<void>;
1943
+ /** Check if a rendered segment file exists for the given hash. */
1944
+ has(hash: number): boolean;
1945
+ /** Get the absolute file path for a segment hash. */
1946
+ getPath(hash: number): string;
1947
+ /** Get the cache directory path. */
1948
+ getDir(): string;
1802
1949
  /**
1803
- * Interpolates all tracks at the given progress and applies values to target.
1950
+ * Remove cached files that are not in the active set.
1951
+ * Call after a full render to clean up stale segments.
1804
1952
  */
1805
- interpolate(progress: number): void;
1953
+ prune(activeHashes: Set<number>): Promise<void>;
1806
1954
  }
1807
1955
 
1808
1956
  /**
1809
- * Configuration options for the Follow animation.
1957
+ * Scene is the core container that manages Mobjects and coordinates animations.
1958
+ * It provides both a simple API for playing animations and access to the
1959
+ * underlying Timeline and Camera for advanced control.
1810
1960
  */
1811
- interface FollowConfig {
1961
+ declare class Scene {
1962
+ private readonly config;
1963
+ private readonly mobjects;
1964
+ private readonly timeline;
1965
+ private readonly _camera;
1966
+ private readonly updaterEngine;
1967
+ private readonly segmentList;
1968
+ private playheadTime;
1969
+ constructor(config?: SceneConfig);
1970
+ get camera(): Camera;
1971
+ get frame(): CameraFrame;
1972
+ /** Get scene width in pixels. */
1973
+ getWidth(): number;
1974
+ /** Get scene height in pixels. */
1975
+ getHeight(): number;
1976
+ /** Get scene background color. */
1977
+ getBackgroundColor(): Color;
1978
+ /** Get scene frame rate. */
1979
+ getFrameRate(): number;
1812
1980
  /**
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
1981
+ * Add mobjects to the scene and make them immediately visible.
1982
+ * Use this for static elements or backgrounds that should be visible
1983
+ * before any animations begin.
1816
1984
  */
1817
- offset?: Vector2;
1985
+ add(...mobjects: Mobject[]): this;
1818
1986
  /**
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
1987
+ * Remove mobjects from the scene.
1824
1988
  */
1825
- damping?: number;
1826
- }
1827
- /**
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));
1846
- */
1847
- declare class Follow extends Animation<CameraFrame> {
1848
- readonly lifecycle: AnimationLifecycle;
1849
- private readonly followTarget;
1850
- private readonly offset;
1851
- private readonly damping;
1989
+ remove(...mobjects: Mobject[]): this;
1852
1990
  /**
1853
- * Creates a new Follow animation.
1991
+ * Check if a mobject is registered with this scene.
1992
+ */
1993
+ has(mobject: Mobject): boolean;
1994
+ /**
1995
+ * Get all mobjects in the scene.
1996
+ */
1997
+ getMobjects(): readonly Mobject[];
1998
+ /**
1999
+ * Schedule animations to play at the current playhead position.
1854
2000
  *
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
2001
+ * Accepts either Animation objects or Mobjects with queued fluent animations.
2002
+ * When a Mobject is passed, its queued animation chain is automatically extracted.
2003
+ *
2004
+ * - Introductory animations (FadeIn, Create, Draw, Write) auto-register
2005
+ * their targets with the scene if not already present.
2006
+ * - Transformative animations (MoveTo, Rotate, Scale) require the target
2007
+ * to already be in the scene, otherwise an error is thrown.
1860
2008
  *
1861
2009
  * @example
1862
- * const follow = new Follow(scene.frame, player, { damping: 0.7 });
1863
- * this.play(follow.duration(10));
2010
+ * // ProAPI style
2011
+ * this.play(new FadeIn(circle), new MoveTo(rect, 2, 0));
2012
+ *
2013
+ * // FluentAPI style
2014
+ * circle.fadeIn(1).moveTo(2, 0, 1);
2015
+ * this.play(circle);
2016
+ *
2017
+ * // Mixed
2018
+ * circle.fadeIn(1);
2019
+ * this.play(circle, new FadeIn(rect));
1864
2020
  */
1865
- constructor(frame: CameraFrame, target: Mobject, config?: FollowConfig);
2021
+ play(...items: Array<Animation | Mobject>): this;
1866
2022
  /**
1867
- * Updates the camera position each frame to track the target.
1868
- * @param progress - Animation progress (0 to 1)
2023
+ * Add a delay before the next play() call.
2024
+ * @param seconds Number of seconds to wait
1869
2025
  */
1870
- interpolate(progress: number): void;
1871
- }
1872
-
1873
- /**
1874
- * Configuration options for the Shake animation.
1875
- */
1876
- interface ShakeConfig {
2026
+ wait(seconds: number): this;
1877
2027
  /**
1878
- * Maximum displacement distance in world units.
1879
- * Higher values create more violent shaking.
1880
- * @default 0.2
2028
+ * Get the current playhead time.
1881
2029
  */
1882
- intensity?: number;
2030
+ getCurrentTime(): number;
1883
2031
  /**
1884
- * Number of oscillations per second.
1885
- * Higher values create faster, more frantic shaking.
1886
- * @default 10
2032
+ * Get the total duration of all scheduled animations.
1887
2033
  */
1888
- frequency?: number;
2034
+ getTotalDuration(): number;
1889
2035
  /**
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
2036
+ * Evaluates scene state at an absolute time.
2037
+ * Execution order is deterministic:
2038
+ * 1) timeline animations
2039
+ * 2) mobject updaters
1895
2040
  */
1896
- decay?: number;
1897
- }
1898
- /**
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));
1924
- */
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;
2041
+ evaluateFrame(time: number): void;
1932
2042
  /**
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));
2043
+ * Returns true if any scene mobject (or camera frame) has active updaters.
2044
+ * Used by renderer to disable unsafe segment caching.
1941
2045
  */
1942
- constructor(frame: CameraFrame, config?: ShakeConfig);
2046
+ hasActiveUpdaters(): boolean;
1943
2047
  /**
1944
- * Captures the original position before shake begins.
2048
+ * Get the underlying Timeline for advanced control.
2049
+ * Use this for direct manipulation of animation timing.
1945
2050
  */
1946
- protected captureStartState(): void;
2051
+ getTimeline(): Timeline;
1947
2052
  /**
1948
- * Applies procedural shake displacement each frame.
1949
- * @param progress - Animation progress (0 to 1)
2053
+ * Get the Camera for view control and frame dimensions.
2054
+ * Camera calculates Manim-compatible frame dimensions from pixel resolution.
1950
2055
  */
1951
- interpolate(progress: number): void;
2056
+ getCamera(): Camera;
1952
2057
  /**
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
2058
+ * Get the list of segments emitted by play() and wait() calls.
2059
+ * Used by the Renderer for cache-aware segmented rendering.
1957
2060
  */
1958
- private noise;
2061
+ getSegments(): readonly Segment[];
2062
+ /**
2063
+ * Validates and registers animation targets based on lifecycle.
2064
+ * Handles composition animations (Sequence, Parallel) by processing children.
2065
+ */
2066
+ private validateAndRegisterAnimation;
2067
+ /**
2068
+ * Checks if a Mobject is in the scene.
2069
+ * An object is "in scene" if:
2070
+ * - It's directly registered in this.mobjects, OR
2071
+ * - Any ancestor in its parent chain is registered
2072
+ *
2073
+ * This respects the scene graph hierarchy - children of registered
2074
+ * VGroups are implicitly in scene via their parent.
2075
+ */
2076
+ isInScene(mobject: Mobject): boolean;
2077
+ /**
2078
+ * Computes a holistic CRC32 hash for a segment.
2079
+ * Includes camera state, all current mobjects, animations, and timing.
2080
+ */
2081
+ private computeSegmentHash;
1959
2082
  }
1960
2083
 
1961
2084
  /**
@@ -2148,33 +2271,4 @@ declare class ProgressReporter {
2148
2271
  complete(): void;
2149
2272
  }
2150
2273
 
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 };
2274
+ 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, type UpdaterContext, type UpdaterFunction, type UpdaterHandle, type UpdaterOptions, VGroup, VMobject, Vector, 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 };