@redwilly/anima 0.1.2 → 0.1.22
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 +47 -51
- package/dist/index.js +194 -661
- package/package.json +9 -1
package/dist/index.d.ts
CHANGED
|
@@ -275,6 +275,7 @@ declare class AnimationQueue {
|
|
|
275
275
|
enqueueAnimation(animation: Animation<Mobject>): void;
|
|
276
276
|
setLastDuration(seconds: number): void;
|
|
277
277
|
setLastEasing(easing: EasingFunction): void;
|
|
278
|
+
setLastDelay(seconds: number): void;
|
|
278
279
|
isEmpty(): boolean;
|
|
279
280
|
popLastAnimation(): Animation<Mobject> | null;
|
|
280
281
|
toAnimation(): Animation<Mobject>;
|
|
@@ -343,6 +344,7 @@ declare class Mobject {
|
|
|
343
344
|
};
|
|
344
345
|
duration(seconds: number): this;
|
|
345
346
|
ease(easing: EasingFunction): this;
|
|
347
|
+
delay(seconds: number): this;
|
|
346
348
|
toAnimation(): Animation<Mobject>;
|
|
347
349
|
getQueuedDuration(): number;
|
|
348
350
|
hasQueuedAnimations(): boolean;
|
|
@@ -1022,6 +1024,16 @@ declare class Scene {
|
|
|
1022
1024
|
* Handles composition animations (Sequence, Parallel) by processing children.
|
|
1023
1025
|
*/
|
|
1024
1026
|
private validateAndRegisterAnimation;
|
|
1027
|
+
/**
|
|
1028
|
+
* Checks if a Mobject is in the scene.
|
|
1029
|
+
* An object is "in scene" if:
|
|
1030
|
+
* - It's directly registered in this.mobjects, OR
|
|
1031
|
+
* - Any ancestor in its parent chain is registered
|
|
1032
|
+
*
|
|
1033
|
+
* This respects the scene graph hierarchy - children of registered
|
|
1034
|
+
* VGroups are implicitly in scene via their parent.
|
|
1035
|
+
*/
|
|
1036
|
+
isInScene(mobject: Mobject): boolean;
|
|
1025
1037
|
/**
|
|
1026
1038
|
* Gets children of composition animations (Sequence, Parallel).
|
|
1027
1039
|
* Returns empty array for non-composition animations.
|
|
@@ -1297,12 +1309,16 @@ declare class Text extends VGroup {
|
|
|
1297
1309
|
readonly text: string;
|
|
1298
1310
|
private style;
|
|
1299
1311
|
private fontPath;
|
|
1300
|
-
constructor(text: string, fontPath
|
|
1312
|
+
constructor(text: string, fontPath?: string, options?: Partial<TextStyle>);
|
|
1301
1313
|
private buildGlyphs;
|
|
1302
1314
|
private getCharacterForGlyph;
|
|
1303
1315
|
private applyStyle;
|
|
1304
1316
|
setStyle(options: Partial<TextStyle>): this;
|
|
1305
1317
|
getStyle(): TextStyle;
|
|
1318
|
+
/** Override stroke to propagate to all Glyph children. */
|
|
1319
|
+
stroke(color: Color, width?: number): this;
|
|
1320
|
+
/** Override fill to propagate to all Glyph children. */
|
|
1321
|
+
fill(color: Color, opacity?: number): this;
|
|
1306
1322
|
getGlyph(index: number): Glyph | undefined;
|
|
1307
1323
|
}
|
|
1308
1324
|
|
|
@@ -1578,66 +1594,61 @@ declare class MorphTo<T extends VMobject = VMobject> extends TransformativeAnima
|
|
|
1578
1594
|
}
|
|
1579
1595
|
|
|
1580
1596
|
/**
|
|
1581
|
-
* Animation that first draws the
|
|
1582
|
-
*
|
|
1597
|
+
* Animation that first draws the stroke progressively, then fades in the fill.
|
|
1598
|
+
* - First 50%: stroke draws progressively
|
|
1599
|
+
* - Second 50%: fill fades in
|
|
1583
1600
|
*
|
|
1584
|
-
*
|
|
1601
|
+
* - Single VMobject: stroke then fill
|
|
1602
|
+
* - VGroup: all children animate together
|
|
1603
|
+
* - Text (VGroup of Glyphs): Glyphs animate sequentially for handwriting effect
|
|
1585
1604
|
*
|
|
1586
1605
|
* This is an introductory animation - it auto-registers the target with the scene.
|
|
1587
|
-
*
|
|
1588
|
-
* @example
|
|
1589
|
-
* const rect = new Rectangle(2, 1);
|
|
1590
|
-
* scene.play(new Draw(rect)); // Border draws, then fill fades in
|
|
1591
1606
|
*/
|
|
1592
1607
|
declare class Draw<T extends VMobject = VMobject> extends IntroductoryAnimation<T> {
|
|
1593
|
-
private readonly isVGroup;
|
|
1594
|
-
/** For non-VGroup targets: original paths on the target itself. */
|
|
1595
1608
|
private readonly originalPaths;
|
|
1596
|
-
private readonly originalFillOpacity;
|
|
1597
1609
|
private readonly originalOpacity;
|
|
1598
|
-
|
|
1610
|
+
private readonly originalStrokeColor;
|
|
1611
|
+
private readonly originalStrokeWidth;
|
|
1612
|
+
private readonly originalFillColor;
|
|
1613
|
+
private readonly originalFillOpacity;
|
|
1599
1614
|
private readonly childStates;
|
|
1615
|
+
/** Glyph states for Text children, keyed by the Text VMobject reference. */
|
|
1616
|
+
private readonly glyphStates;
|
|
1600
1617
|
constructor(target: T);
|
|
1601
|
-
|
|
1618
|
+
private createState;
|
|
1602
1619
|
interpolate(progress: number): void;
|
|
1603
|
-
/** Interpolates a single VMobject (non-VGroup). */
|
|
1604
|
-
private interpolateVMobject;
|
|
1605
|
-
/** Interpolates a VGroup by animating each child's paths. */
|
|
1606
1620
|
private interpolateVGroup;
|
|
1621
|
+
private interpolateGlyphs;
|
|
1622
|
+
/** Interpolates a single VMobject: stroke (0-0.5), then fill (0.5-1). */
|
|
1623
|
+
private interpolateVMobject;
|
|
1607
1624
|
}
|
|
1608
1625
|
|
|
1609
1626
|
/**
|
|
1610
|
-
* Animation that progressively draws
|
|
1611
|
-
* Preserves both stroke and fill properties - the complete object is visible at the end.
|
|
1627
|
+
* Animation that progressively draws VMobject paths from start to end.
|
|
1612
1628
|
*
|
|
1613
|
-
*
|
|
1614
|
-
*
|
|
1615
|
-
*
|
|
1616
|
-
* Supports VGroup (including Text): animates each child's paths progressively.
|
|
1629
|
+
* - Single VMobject: paths draw progressively
|
|
1630
|
+
* - VGroup: all children animate together with same progress
|
|
1631
|
+
* - Text (VGroup of Glyphs): Glyphs animate sequentially for handwriting effect
|
|
1617
1632
|
*
|
|
1618
1633
|
* This is an introductory animation - it auto-registers the target with the scene.
|
|
1619
|
-
*
|
|
1620
|
-
* @example
|
|
1621
|
-
* const circle = new Circle(1);
|
|
1622
|
-
* scene.play(new Write(circle)); // Circle is drawn progressively
|
|
1623
|
-
*
|
|
1624
|
-
* const text = new Text('Hello');
|
|
1625
|
-
* scene.play(new Write(text)); // Text is written progressively
|
|
1626
1634
|
*/
|
|
1627
1635
|
declare class Write<T extends VMobject = VMobject> extends IntroductoryAnimation<T> {
|
|
1628
|
-
private readonly isVGroup;
|
|
1629
|
-
/** For non-VGroup targets: original paths on the target itself. */
|
|
1630
1636
|
private readonly originalPaths;
|
|
1631
1637
|
private readonly originalOpacity;
|
|
1638
|
+
private readonly originalStrokeColor;
|
|
1639
|
+
private readonly originalStrokeWidth;
|
|
1640
|
+
private readonly originalFillColor;
|
|
1632
1641
|
private readonly originalFillOpacity;
|
|
1633
|
-
/** For VGroup targets: original state of each child. */
|
|
1634
1642
|
private readonly childStates;
|
|
1643
|
+
/** Glyph states for Text children, keyed by the Text VMobject reference. */
|
|
1644
|
+
private readonly glyphStates;
|
|
1635
1645
|
constructor(target: T);
|
|
1646
|
+
private createState;
|
|
1636
1647
|
interpolate(progress: number): void;
|
|
1637
|
-
/** Interpolates a single VMobject (non-VGroup). */
|
|
1638
|
-
private interpolateVMobject;
|
|
1639
|
-
/** Interpolates a VGroup by animating each child's paths. */
|
|
1640
1648
|
private interpolateVGroup;
|
|
1649
|
+
private interpolateGlyphs;
|
|
1650
|
+
/** Applies progress to a single VMobject, updating its paths and style. */
|
|
1651
|
+
private applyProgress;
|
|
1641
1652
|
}
|
|
1642
1653
|
|
|
1643
1654
|
/**
|
|
@@ -1901,21 +1912,6 @@ declare class Shake extends TransformativeAnimation<CameraFrame> {
|
|
|
1901
1912
|
private noise;
|
|
1902
1913
|
}
|
|
1903
1914
|
|
|
1904
|
-
/**
|
|
1905
|
-
* Scene serialization - the main entry point for serializing/deserializing Scenes.
|
|
1906
|
-
*/
|
|
1907
|
-
|
|
1908
|
-
/**
|
|
1909
|
-
* Serializes a Scene into a JSON-formatted string.
|
|
1910
|
-
*
|
|
1911
|
-
* Useful for saving scene state to a file or transmitting it over a network.
|
|
1912
|
-
*/
|
|
1913
|
-
declare function serialize(scene: Scene): string;
|
|
1914
|
-
/**
|
|
1915
|
-
* Restores a complete Scene from a JSON-formatted string.
|
|
1916
|
-
*/
|
|
1917
|
-
declare function deserialize(json: string): Scene;
|
|
1918
|
-
|
|
1919
1915
|
/**
|
|
1920
1916
|
* Supported render output formats.
|
|
1921
1917
|
* - sprite: PNG sequence (frame_0000.png, frame_0001.png, ...)
|
|
@@ -2083,4 +2079,4 @@ declare class ProgressReporter {
|
|
|
2083
2079
|
complete(): void;
|
|
2084
2080
|
}
|
|
2085
2081
|
|
|
2086
|
-
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 Keyframe, KeyframeAnimation, KeyframeTrack, type LayoutConfig, type LayoutType, Line, Mobject, MorphTo, MoveTo, type NodeConfig, Parallel, Point, Polygon, type ProgressCallback, ProgressReporter, Rectangle, type RenderConfig, type RenderFormat, type RenderProgress, type RenderQuality, Renderer, Resolution, type ResolvedCameraConfig, Rotate, Scale, Scene, type SceneConfig, type ScheduledAnimation, Sequence, Shake, Text, type TextStyle, Timeline, type TimelineConfig, Unwrite, VGroup, VMobject, Vector2, Write, clearRegistry, smooth as defaultEasing,
|
|
2082
|
+
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 Keyframe, KeyframeAnimation, KeyframeTrack, type LayoutConfig, type LayoutType, Line, Mobject, MorphTo, MoveTo, type NodeConfig, Parallel, Point, Polygon, type ProgressCallback, ProgressReporter, Rectangle, type RenderConfig, type RenderFormat, type RenderProgress, type RenderQuality, Renderer, Resolution, type ResolvedCameraConfig, Rotate, Scale, Scene, type SceneConfig, type ScheduledAnimation, Sequence, Shake, Text, type TextStyle, 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 };
|
package/dist/index.js
CHANGED
|
@@ -978,6 +978,18 @@ var AnimationQueue = class {
|
|
|
978
978
|
last.config.easing = easing;
|
|
979
979
|
}
|
|
980
980
|
}
|
|
981
|
+
setLastDelay(seconds) {
|
|
982
|
+
if (seconds < 0) {
|
|
983
|
+
throw new Error("Delay must be non-negative");
|
|
984
|
+
}
|
|
985
|
+
const last = this.queue[this.queue.length - 1];
|
|
986
|
+
if (!last) return;
|
|
987
|
+
if (isPrebuilt(last)) {
|
|
988
|
+
last.animation.delay(seconds);
|
|
989
|
+
} else {
|
|
990
|
+
last.config.delaySeconds = seconds;
|
|
991
|
+
}
|
|
992
|
+
}
|
|
981
993
|
isEmpty() {
|
|
982
994
|
return this.queue.length === 0;
|
|
983
995
|
}
|
|
@@ -1228,6 +1240,10 @@ var Mobject = class {
|
|
|
1228
1240
|
this.getQueue().setLastEasing(easing);
|
|
1229
1241
|
return this;
|
|
1230
1242
|
}
|
|
1243
|
+
delay(seconds) {
|
|
1244
|
+
this.getQueue().setLastDelay(seconds);
|
|
1245
|
+
return this;
|
|
1246
|
+
}
|
|
1231
1247
|
toAnimation() {
|
|
1232
1248
|
return this.getQueue().toAnimation();
|
|
1233
1249
|
}
|
|
@@ -1944,12 +1960,34 @@ var Scene = class {
|
|
|
1944
1960
|
if (target instanceof CameraFrame) {
|
|
1945
1961
|
break;
|
|
1946
1962
|
}
|
|
1947
|
-
if (!this.
|
|
1963
|
+
if (!this.isInScene(target)) {
|
|
1948
1964
|
throw new AnimationTargetNotInSceneError(anim, target);
|
|
1949
1965
|
}
|
|
1950
1966
|
break;
|
|
1951
1967
|
}
|
|
1952
1968
|
}
|
|
1969
|
+
/**
|
|
1970
|
+
* Checks if a Mobject is in the scene.
|
|
1971
|
+
* An object is "in scene" if:
|
|
1972
|
+
* - It's directly registered in this.mobjects, OR
|
|
1973
|
+
* - Any ancestor in its parent chain is registered
|
|
1974
|
+
*
|
|
1975
|
+
* This respects the scene graph hierarchy - children of registered
|
|
1976
|
+
* VGroups are implicitly in scene via their parent.
|
|
1977
|
+
*/
|
|
1978
|
+
isInScene(mobject) {
|
|
1979
|
+
if (this.mobjects.has(mobject)) {
|
|
1980
|
+
return true;
|
|
1981
|
+
}
|
|
1982
|
+
let current = mobject.parent;
|
|
1983
|
+
while (current !== null) {
|
|
1984
|
+
if (this.mobjects.has(current)) {
|
|
1985
|
+
return true;
|
|
1986
|
+
}
|
|
1987
|
+
current = current.parent;
|
|
1988
|
+
}
|
|
1989
|
+
return false;
|
|
1990
|
+
}
|
|
1953
1991
|
/**
|
|
1954
1992
|
* Gets children of composition animations (Sequence, Parallel).
|
|
1955
1993
|
* Returns empty array for non-composition animations.
|
|
@@ -2635,94 +2673,103 @@ function appendPartialCommand(result, cmd, cursor, subpathStart, localT) {
|
|
|
2635
2673
|
function isVGroup(target) {
|
|
2636
2674
|
return typeof target.getChildren === "function";
|
|
2637
2675
|
}
|
|
2676
|
+
function isGlyph(target) {
|
|
2677
|
+
return typeof target.character === "string";
|
|
2678
|
+
}
|
|
2679
|
+
function isText(target) {
|
|
2680
|
+
if (!isVGroup(target)) return false;
|
|
2681
|
+
const children = target.getChildren();
|
|
2682
|
+
return children.length > 0 && children.every(isGlyph);
|
|
2683
|
+
}
|
|
2638
2684
|
var Draw = class extends IntroductoryAnimation {
|
|
2639
|
-
isVGroup;
|
|
2640
|
-
/** For non-VGroup targets: original paths on the target itself. */
|
|
2641
2685
|
originalPaths;
|
|
2642
|
-
originalFillOpacity;
|
|
2643
2686
|
originalOpacity;
|
|
2644
|
-
|
|
2687
|
+
originalStrokeColor;
|
|
2688
|
+
originalStrokeWidth;
|
|
2689
|
+
originalFillColor;
|
|
2690
|
+
originalFillOpacity;
|
|
2645
2691
|
childStates;
|
|
2692
|
+
/** Glyph states for Text children, keyed by the Text VMobject reference. */
|
|
2693
|
+
glyphStates = /* @__PURE__ */ new Map();
|
|
2646
2694
|
constructor(target) {
|
|
2647
2695
|
super(target);
|
|
2648
|
-
this.isVGroup = isVGroup(target);
|
|
2649
2696
|
this.originalOpacity = target.opacity;
|
|
2697
|
+
this.originalStrokeColor = target.getStrokeColor();
|
|
2698
|
+
this.originalStrokeWidth = target.getStrokeWidth();
|
|
2699
|
+
this.originalFillColor = target.getFillColor();
|
|
2650
2700
|
this.originalFillOpacity = target.getFillOpacity();
|
|
2651
|
-
if (
|
|
2701
|
+
if (isVGroup(target)) {
|
|
2652
2702
|
this.originalPaths = [];
|
|
2653
|
-
this.childStates =
|
|
2654
|
-
for (const child of target.getChildren()) {
|
|
2655
|
-
this.childStates.push({
|
|
2656
|
-
child,
|
|
2657
|
-
originalPaths: child.paths.map((p) => p.clone()),
|
|
2658
|
-
originalOpacity: child.opacity,
|
|
2659
|
-
originalFillOpacity: child.getFillOpacity()
|
|
2660
|
-
});
|
|
2661
|
-
}
|
|
2703
|
+
this.childStates = target.getChildren().map((child) => this.createState(child));
|
|
2662
2704
|
} else {
|
|
2663
2705
|
this.originalPaths = target.paths.map((p) => p.clone());
|
|
2664
2706
|
this.childStates = [];
|
|
2665
2707
|
}
|
|
2666
2708
|
}
|
|
2667
|
-
|
|
2709
|
+
createState(child) {
|
|
2710
|
+
const state = {
|
|
2711
|
+
child,
|
|
2712
|
+
paths: child.paths.map((p) => p.clone()),
|
|
2713
|
+
opacity: child.opacity,
|
|
2714
|
+
strokeColor: child.getStrokeColor(),
|
|
2715
|
+
strokeWidth: child.getStrokeWidth(),
|
|
2716
|
+
fillColor: child.getFillColor(),
|
|
2717
|
+
fillOpacity: child.getFillOpacity()
|
|
2718
|
+
};
|
|
2719
|
+
if (isText(child)) {
|
|
2720
|
+
this.glyphStates.set(child, child.getChildren().map((g) => this.createState(g)));
|
|
2721
|
+
}
|
|
2722
|
+
return state;
|
|
2723
|
+
}
|
|
2668
2724
|
interpolate(progress) {
|
|
2669
|
-
if (this.
|
|
2670
|
-
this.
|
|
2725
|
+
if (this.childStates.length === 0) {
|
|
2726
|
+
this.interpolateVMobject(this.target, this.originalPaths, this.originalOpacity, this.originalStrokeColor, this.originalStrokeWidth, this.originalFillColor, this.originalFillOpacity, progress);
|
|
2671
2727
|
} else {
|
|
2672
|
-
this.
|
|
2728
|
+
this.interpolateVGroup(progress);
|
|
2673
2729
|
}
|
|
2674
2730
|
}
|
|
2675
|
-
|
|
2676
|
-
interpolateVMobject(progress) {
|
|
2731
|
+
interpolateVGroup(progress) {
|
|
2677
2732
|
const targetOpacity = this.originalOpacity === 0 ? 1 : this.originalOpacity;
|
|
2733
|
+
this.target.setOpacity(progress <= 0 ? 0 : targetOpacity);
|
|
2734
|
+
for (const state of this.childStates) {
|
|
2735
|
+
const glyphStates = this.glyphStates.get(state.child);
|
|
2736
|
+
if (glyphStates) {
|
|
2737
|
+
state.child.setOpacity(progress <= 0 ? 0 : state.opacity || 1);
|
|
2738
|
+
this.interpolateGlyphs(glyphStates, progress);
|
|
2739
|
+
} else {
|
|
2740
|
+
this.interpolateVMobject(state.child, state.paths, state.opacity, state.strokeColor, state.strokeWidth, state.fillColor, state.fillOpacity, progress);
|
|
2741
|
+
}
|
|
2742
|
+
}
|
|
2743
|
+
}
|
|
2744
|
+
interpolateGlyphs(glyphs, progress) {
|
|
2745
|
+
const lagRatio = 0.2;
|
|
2746
|
+
const totalSpan = 1 + (glyphs.length - 1) * lagRatio;
|
|
2747
|
+
glyphs.forEach((state, i) => {
|
|
2748
|
+
const start = i * lagRatio / totalSpan;
|
|
2749
|
+
const end = (i * lagRatio + 1) / totalSpan;
|
|
2750
|
+
const p = Math.max(0, Math.min(1, (progress - start) / (end - start)));
|
|
2751
|
+
this.interpolateVMobject(state.child, state.paths, state.opacity, state.strokeColor, state.strokeWidth, state.fillColor, state.fillOpacity, p);
|
|
2752
|
+
});
|
|
2753
|
+
}
|
|
2754
|
+
/** Interpolates a single VMobject: stroke (0-0.5), then fill (0.5-1). */
|
|
2755
|
+
interpolateVMobject(target, originalPaths, originalOpacity, originalStrokeColor, originalStrokeWidth, originalFillColor, originalFillOpacity, progress) {
|
|
2678
2756
|
if (progress <= 0) {
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
this.target.fill(this.target.getFillColor(), 0);
|
|
2757
|
+
target.paths = [];
|
|
2758
|
+
target.setOpacity(0);
|
|
2682
2759
|
return;
|
|
2683
2760
|
}
|
|
2684
|
-
|
|
2761
|
+
const opacity = originalOpacity === 0 ? 1 : originalOpacity;
|
|
2762
|
+
target.setOpacity(opacity);
|
|
2685
2763
|
if (progress < 0.5) {
|
|
2686
2764
|
const strokeProgress = progress * 2;
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
}
|
|
2691
|
-
this.target.paths = partialPaths;
|
|
2692
|
-
this.target.fill(this.target.getFillColor(), 0);
|
|
2765
|
+
target.paths = originalPaths.map((p) => getPartialPath(p, strokeProgress));
|
|
2766
|
+
target.stroke(originalStrokeColor, originalStrokeWidth);
|
|
2767
|
+
target.fill(originalFillColor, 0);
|
|
2693
2768
|
} else {
|
|
2694
|
-
this.target.paths = this.originalPaths.map((p) => p.clone());
|
|
2695
2769
|
const fillProgress = (progress - 0.5) * 2;
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
/** Interpolates a VGroup by animating each child's paths. */
|
|
2700
|
-
interpolateVGroup(progress) {
|
|
2701
|
-
const targetOpacity = this.originalOpacity === 0 ? 1 : this.originalOpacity;
|
|
2702
|
-
this.target.setOpacity(progress <= 0 ? 0 : targetOpacity);
|
|
2703
|
-
for (const state of this.childStates) {
|
|
2704
|
-
const { child, originalPaths, originalOpacity, originalFillOpacity } = state;
|
|
2705
|
-
const childOpacity = originalOpacity === 0 ? 1 : originalOpacity;
|
|
2706
|
-
if (progress <= 0) {
|
|
2707
|
-
child.paths = [];
|
|
2708
|
-
child.setOpacity(0);
|
|
2709
|
-
child.fill(child.getFillColor(), 0);
|
|
2710
|
-
continue;
|
|
2711
|
-
}
|
|
2712
|
-
child.setOpacity(childOpacity);
|
|
2713
|
-
if (progress < 0.5) {
|
|
2714
|
-
const strokeProgress = progress * 2;
|
|
2715
|
-
const partialPaths = [];
|
|
2716
|
-
for (const originalPath of originalPaths) {
|
|
2717
|
-
partialPaths.push(getPartialPath(originalPath, strokeProgress));
|
|
2718
|
-
}
|
|
2719
|
-
child.paths = partialPaths;
|
|
2720
|
-
child.fill(child.getFillColor(), 0);
|
|
2721
|
-
} else {
|
|
2722
|
-
child.paths = originalPaths.map((p) => p.clone());
|
|
2723
|
-
const fillProgress = (progress - 0.5) * 2;
|
|
2724
|
-
child.fill(child.getFillColor(), originalFillOpacity * fillProgress);
|
|
2725
|
-
}
|
|
2770
|
+
target.paths = originalPaths.map((p) => p.clone());
|
|
2771
|
+
target.stroke(originalStrokeColor, originalStrokeWidth);
|
|
2772
|
+
target.fill(originalFillColor, originalFillOpacity * fillProgress);
|
|
2726
2773
|
}
|
|
2727
2774
|
}
|
|
2728
2775
|
};
|
|
@@ -2731,87 +2778,97 @@ var Draw = class extends IntroductoryAnimation {
|
|
|
2731
2778
|
function isVGroup2(target) {
|
|
2732
2779
|
return typeof target.getChildren === "function";
|
|
2733
2780
|
}
|
|
2781
|
+
function isGlyph2(target) {
|
|
2782
|
+
return typeof target.character === "string";
|
|
2783
|
+
}
|
|
2784
|
+
function isText2(target) {
|
|
2785
|
+
if (!isVGroup2(target)) return false;
|
|
2786
|
+
const children = target.getChildren();
|
|
2787
|
+
return children.length > 0 && children.every(isGlyph2);
|
|
2788
|
+
}
|
|
2734
2789
|
var Write = class extends IntroductoryAnimation {
|
|
2735
|
-
isVGroup;
|
|
2736
|
-
/** For non-VGroup targets: original paths on the target itself. */
|
|
2737
2790
|
originalPaths;
|
|
2738
2791
|
originalOpacity;
|
|
2792
|
+
originalStrokeColor;
|
|
2793
|
+
originalStrokeWidth;
|
|
2794
|
+
originalFillColor;
|
|
2739
2795
|
originalFillOpacity;
|
|
2740
|
-
/** For VGroup targets: original state of each child. */
|
|
2741
2796
|
childStates;
|
|
2797
|
+
/** Glyph states for Text children, keyed by the Text VMobject reference. */
|
|
2798
|
+
glyphStates = /* @__PURE__ */ new Map();
|
|
2742
2799
|
constructor(target) {
|
|
2743
2800
|
super(target);
|
|
2744
|
-
this.isVGroup = isVGroup2(target);
|
|
2745
2801
|
this.originalOpacity = target.opacity;
|
|
2802
|
+
this.originalStrokeColor = target.getStrokeColor();
|
|
2803
|
+
this.originalStrokeWidth = target.getStrokeWidth();
|
|
2804
|
+
this.originalFillColor = target.getFillColor();
|
|
2746
2805
|
this.originalFillOpacity = target.getFillOpacity();
|
|
2747
|
-
if (
|
|
2806
|
+
if (isVGroup2(target)) {
|
|
2748
2807
|
this.originalPaths = [];
|
|
2749
|
-
this.childStates =
|
|
2750
|
-
for (const child of target.getChildren()) {
|
|
2751
|
-
this.childStates.push({
|
|
2752
|
-
child,
|
|
2753
|
-
originalPaths: child.paths.map((p) => p.clone()),
|
|
2754
|
-
originalOpacity: child.opacity,
|
|
2755
|
-
originalFillOpacity: child.getFillOpacity()
|
|
2756
|
-
});
|
|
2757
|
-
}
|
|
2808
|
+
this.childStates = target.getChildren().map((child) => this.createState(child));
|
|
2758
2809
|
} else {
|
|
2759
2810
|
this.originalPaths = target.paths.map((p) => p.clone());
|
|
2760
2811
|
this.childStates = [];
|
|
2761
2812
|
}
|
|
2762
2813
|
}
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2814
|
+
createState(child) {
|
|
2815
|
+
const state = {
|
|
2816
|
+
child,
|
|
2817
|
+
paths: child.paths.map((p) => p.clone()),
|
|
2818
|
+
opacity: child.opacity,
|
|
2819
|
+
strokeColor: child.getStrokeColor(),
|
|
2820
|
+
strokeWidth: child.getStrokeWidth(),
|
|
2821
|
+
fillColor: child.getFillColor(),
|
|
2822
|
+
fillOpacity: child.getFillOpacity()
|
|
2823
|
+
};
|
|
2824
|
+
if (isText2(child)) {
|
|
2825
|
+
this.glyphStates.set(child, child.getChildren().map((g) => this.createState(g)));
|
|
2768
2826
|
}
|
|
2827
|
+
return state;
|
|
2769
2828
|
}
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
this.
|
|
2775
|
-
return;
|
|
2776
|
-
}
|
|
2777
|
-
const targetOpacity = this.originalOpacity === 0 ? 1 : this.originalOpacity;
|
|
2778
|
-
this.target.setOpacity(targetOpacity);
|
|
2779
|
-
this.target.fill(this.target.getFillColor(), this.originalFillOpacity);
|
|
2780
|
-
if (progress >= 1) {
|
|
2781
|
-
this.target.paths = this.originalPaths.map((p) => p.clone());
|
|
2782
|
-
return;
|
|
2783
|
-
}
|
|
2784
|
-
const partialPaths = [];
|
|
2785
|
-
for (const originalPath of this.originalPaths) {
|
|
2786
|
-
partialPaths.push(getPartialPath(originalPath, progress));
|
|
2829
|
+
interpolate(progress) {
|
|
2830
|
+
if (this.childStates.length === 0) {
|
|
2831
|
+
this.applyProgress(this.target, this.originalPaths, this.originalOpacity, this.originalStrokeColor, this.originalStrokeWidth, this.originalFillColor, this.originalFillOpacity, progress);
|
|
2832
|
+
} else {
|
|
2833
|
+
this.interpolateVGroup(progress);
|
|
2787
2834
|
}
|
|
2788
|
-
this.target.paths = partialPaths;
|
|
2789
2835
|
}
|
|
2790
|
-
/** Interpolates a VGroup by animating each child's paths. */
|
|
2791
2836
|
interpolateVGroup(progress) {
|
|
2792
2837
|
const targetOpacity = this.originalOpacity === 0 ? 1 : this.originalOpacity;
|
|
2793
2838
|
this.target.setOpacity(progress <= 0 ? 0 : targetOpacity);
|
|
2794
2839
|
for (const state of this.childStates) {
|
|
2795
|
-
const
|
|
2796
|
-
if (
|
|
2797
|
-
child.
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
const childOpacity = originalOpacity === 0 ? 1 : originalOpacity;
|
|
2802
|
-
child.setOpacity(childOpacity);
|
|
2803
|
-
child.fill(child.getFillColor(), originalFillOpacity);
|
|
2804
|
-
if (progress >= 1) {
|
|
2805
|
-
child.paths = originalPaths.map((p) => p.clone());
|
|
2806
|
-
continue;
|
|
2807
|
-
}
|
|
2808
|
-
const partialPaths = [];
|
|
2809
|
-
for (const originalPath of originalPaths) {
|
|
2810
|
-
partialPaths.push(getPartialPath(originalPath, progress));
|
|
2840
|
+
const glyphStates = this.glyphStates.get(state.child);
|
|
2841
|
+
if (glyphStates) {
|
|
2842
|
+
state.child.setOpacity(progress <= 0 ? 0 : state.opacity || 1);
|
|
2843
|
+
this.interpolateGlyphs(glyphStates, progress);
|
|
2844
|
+
} else {
|
|
2845
|
+
this.applyProgress(state.child, state.paths, state.opacity, state.strokeColor, state.strokeWidth, state.fillColor, state.fillOpacity, progress);
|
|
2811
2846
|
}
|
|
2812
|
-
child.paths = partialPaths;
|
|
2813
2847
|
}
|
|
2814
2848
|
}
|
|
2849
|
+
interpolateGlyphs(glyphs, progress) {
|
|
2850
|
+
const lagRatio = 0.2;
|
|
2851
|
+
const totalSpan = 1 + (glyphs.length - 1) * lagRatio;
|
|
2852
|
+
glyphs.forEach((state, i) => {
|
|
2853
|
+
const start = i * lagRatio / totalSpan;
|
|
2854
|
+
const end = (i * lagRatio + 1) / totalSpan;
|
|
2855
|
+
const p = Math.max(0, Math.min(1, (progress - start) / (end - start)));
|
|
2856
|
+
this.applyProgress(state.child, state.paths, state.opacity, state.strokeColor, state.strokeWidth, state.fillColor, state.fillOpacity, p);
|
|
2857
|
+
});
|
|
2858
|
+
}
|
|
2859
|
+
/** Applies progress to a single VMobject, updating its paths and style. */
|
|
2860
|
+
applyProgress(target, originalPaths, originalOpacity, originalStrokeColor, originalStrokeWidth, originalFillColor, originalFillOpacity, progress) {
|
|
2861
|
+
if (progress <= 0) {
|
|
2862
|
+
target.paths = [];
|
|
2863
|
+
target.setOpacity(0);
|
|
2864
|
+
return;
|
|
2865
|
+
}
|
|
2866
|
+
const opacity = originalOpacity === 0 ? 1 : originalOpacity;
|
|
2867
|
+
target.setOpacity(opacity);
|
|
2868
|
+
target.stroke(originalStrokeColor, originalStrokeWidth);
|
|
2869
|
+
target.fill(originalFillColor, originalFillOpacity);
|
|
2870
|
+
target.paths = progress >= 1 ? originalPaths.map((p) => p.clone()) : originalPaths.map((p) => getPartialPath(p, progress));
|
|
2871
|
+
}
|
|
2815
2872
|
};
|
|
2816
2873
|
|
|
2817
2874
|
// src/core/animations/draw/Unwrite.ts
|
|
@@ -3564,6 +3621,7 @@ var Glyph = class extends VMobject {
|
|
|
3564
3621
|
|
|
3565
3622
|
// src/mobjects/text/Text.ts
|
|
3566
3623
|
import * as fontkit from "fontkit";
|
|
3624
|
+
import { join, resolve } from "path";
|
|
3567
3625
|
|
|
3568
3626
|
// src/mobjects/text/types.ts
|
|
3569
3627
|
var DEFAULT_TEXT_STYLE = {
|
|
@@ -3572,6 +3630,7 @@ var DEFAULT_TEXT_STYLE = {
|
|
|
3572
3630
|
};
|
|
3573
3631
|
|
|
3574
3632
|
// src/mobjects/text/Text.ts
|
|
3633
|
+
var DEFAULT_FONT_PATH = resolve(join(__dirname, "..", "..", "fonts", "ComicSansMS3.ttf"));
|
|
3575
3634
|
var Text = class extends VGroup {
|
|
3576
3635
|
text;
|
|
3577
3636
|
style;
|
|
@@ -3579,7 +3638,7 @@ var Text = class extends VGroup {
|
|
|
3579
3638
|
constructor(text, fontPath, options = {}) {
|
|
3580
3639
|
super();
|
|
3581
3640
|
this.text = text;
|
|
3582
|
-
this.fontPath = fontPath;
|
|
3641
|
+
this.fontPath = fontPath ?? DEFAULT_FONT_PATH;
|
|
3583
3642
|
this.style = { ...DEFAULT_TEXT_STYLE, ...options };
|
|
3584
3643
|
this.buildGlyphs();
|
|
3585
3644
|
centerGroup(this);
|
|
@@ -3614,8 +3673,8 @@ var Text = class extends VGroup {
|
|
|
3614
3673
|
applyStyle() {
|
|
3615
3674
|
for (const child of this.getChildren()) {
|
|
3616
3675
|
if (child instanceof Glyph) {
|
|
3617
|
-
child.stroke(this.
|
|
3618
|
-
child.fill(this.
|
|
3676
|
+
child.stroke(this.getStrokeColor(), this.getStrokeWidth());
|
|
3677
|
+
child.fill(this.getFillColor(), this.getFillOpacity());
|
|
3619
3678
|
}
|
|
3620
3679
|
}
|
|
3621
3680
|
}
|
|
@@ -3627,6 +3686,18 @@ var Text = class extends VGroup {
|
|
|
3627
3686
|
getStyle() {
|
|
3628
3687
|
return { ...this.style };
|
|
3629
3688
|
}
|
|
3689
|
+
/** Override stroke to propagate to all Glyph children. */
|
|
3690
|
+
stroke(color, width = 2) {
|
|
3691
|
+
super.stroke(color, width);
|
|
3692
|
+
this.applyStyle();
|
|
3693
|
+
return this;
|
|
3694
|
+
}
|
|
3695
|
+
/** Override fill to propagate to all Glyph children. */
|
|
3696
|
+
fill(color, opacity) {
|
|
3697
|
+
super.fill(color, opacity);
|
|
3698
|
+
this.applyStyle();
|
|
3699
|
+
return this;
|
|
3700
|
+
}
|
|
3630
3701
|
getGlyph(index) {
|
|
3631
3702
|
const child = this.get(index);
|
|
3632
3703
|
return child instanceof Glyph ? child : void 0;
|
|
@@ -4306,542 +4377,6 @@ var Shake = class extends TransformativeAnimation {
|
|
|
4306
4377
|
}
|
|
4307
4378
|
};
|
|
4308
4379
|
|
|
4309
|
-
// src/core/serialization/primitives.ts
|
|
4310
|
-
function serializeVector2(v) {
|
|
4311
|
-
return { x: v.x, y: v.y };
|
|
4312
|
-
}
|
|
4313
|
-
function deserializeVector2(data) {
|
|
4314
|
-
return new Vector2(data.x, data.y);
|
|
4315
|
-
}
|
|
4316
|
-
function serializeMatrix3x3(m) {
|
|
4317
|
-
return { values: Array.from(m.values) };
|
|
4318
|
-
}
|
|
4319
|
-
function deserializeMatrix3x3(data) {
|
|
4320
|
-
const values = new Float32Array(data.values);
|
|
4321
|
-
return new Matrix3x3(values);
|
|
4322
|
-
}
|
|
4323
|
-
function serializeColor(c) {
|
|
4324
|
-
return { r: c.r, g: c.g, b: c.b, a: c.a };
|
|
4325
|
-
}
|
|
4326
|
-
function deserializeColor(data) {
|
|
4327
|
-
return new Color(data.r, data.g, data.b, data.a);
|
|
4328
|
-
}
|
|
4329
|
-
function serializePathCommand(cmd) {
|
|
4330
|
-
const result = {
|
|
4331
|
-
type: cmd.type,
|
|
4332
|
-
end: serializeVector2(cmd.end)
|
|
4333
|
-
};
|
|
4334
|
-
const withControl1 = cmd.control1 ? { ...result, control1: serializeVector2(cmd.control1) } : result;
|
|
4335
|
-
const withControl2 = cmd.control2 ? { ...withControl1, control2: serializeVector2(cmd.control2) } : withControl1;
|
|
4336
|
-
return withControl2;
|
|
4337
|
-
}
|
|
4338
|
-
function serializeBezierPath(path) {
|
|
4339
|
-
const commands = path.getCommands().map(serializePathCommand);
|
|
4340
|
-
return { commands };
|
|
4341
|
-
}
|
|
4342
|
-
function deserializeBezierPath(data) {
|
|
4343
|
-
const path = new BezierPath();
|
|
4344
|
-
for (const cmd of data.commands) {
|
|
4345
|
-
const end = deserializeVector2(cmd.end);
|
|
4346
|
-
switch (cmd.type) {
|
|
4347
|
-
case "Move":
|
|
4348
|
-
path.moveTo(end);
|
|
4349
|
-
break;
|
|
4350
|
-
case "Line":
|
|
4351
|
-
path.lineTo(end);
|
|
4352
|
-
break;
|
|
4353
|
-
case "Quadratic":
|
|
4354
|
-
if (cmd.control1) {
|
|
4355
|
-
path.quadraticTo(deserializeVector2(cmd.control1), end);
|
|
4356
|
-
}
|
|
4357
|
-
break;
|
|
4358
|
-
case "Cubic":
|
|
4359
|
-
if (cmd.control1 && cmd.control2) {
|
|
4360
|
-
path.cubicTo(
|
|
4361
|
-
deserializeVector2(cmd.control1),
|
|
4362
|
-
deserializeVector2(cmd.control2),
|
|
4363
|
-
end
|
|
4364
|
-
);
|
|
4365
|
-
}
|
|
4366
|
-
break;
|
|
4367
|
-
case "Close":
|
|
4368
|
-
path.closePath();
|
|
4369
|
-
break;
|
|
4370
|
-
}
|
|
4371
|
-
}
|
|
4372
|
-
return path;
|
|
4373
|
-
}
|
|
4374
|
-
|
|
4375
|
-
// src/core/serialization/registry.ts
|
|
4376
|
-
var registry = /* @__PURE__ */ new Map();
|
|
4377
|
-
function getSerializer(typeName) {
|
|
4378
|
-
return registry.get(typeName);
|
|
4379
|
-
}
|
|
4380
|
-
|
|
4381
|
-
// src/core/serialization/mobject.ts
|
|
4382
|
-
var idCounter = 0;
|
|
4383
|
-
var mobjectIdMap = /* @__PURE__ */ new WeakMap();
|
|
4384
|
-
function getMobjectId(m) {
|
|
4385
|
-
let id = mobjectIdMap.get(m);
|
|
4386
|
-
if (!id) {
|
|
4387
|
-
id = `mob_${idCounter++}`;
|
|
4388
|
-
mobjectIdMap.set(m, id);
|
|
4389
|
-
}
|
|
4390
|
-
return id;
|
|
4391
|
-
}
|
|
4392
|
-
function resetIdCounter() {
|
|
4393
|
-
idCounter = 0;
|
|
4394
|
-
}
|
|
4395
|
-
function getMobjectType(m) {
|
|
4396
|
-
if (m instanceof Circle) return "Circle";
|
|
4397
|
-
if (m instanceof Rectangle) return "Rectangle";
|
|
4398
|
-
if (m instanceof Arrow) return "Arrow";
|
|
4399
|
-
if (m instanceof Line) return "Line";
|
|
4400
|
-
if (m instanceof Arc) return "Arc";
|
|
4401
|
-
if (m instanceof Polygon) return "Polygon";
|
|
4402
|
-
if (m instanceof Point) return "Point";
|
|
4403
|
-
if (m instanceof VGroup) return "VGroup";
|
|
4404
|
-
if (m instanceof VMobject) return "VMobject";
|
|
4405
|
-
return "Mobject";
|
|
4406
|
-
}
|
|
4407
|
-
function serializeMobjectBase(m) {
|
|
4408
|
-
return {
|
|
4409
|
-
type: getMobjectType(m),
|
|
4410
|
-
id: getMobjectId(m),
|
|
4411
|
-
matrix: serializeMatrix3x3(m.matrix),
|
|
4412
|
-
opacity: m.opacity
|
|
4413
|
-
};
|
|
4414
|
-
}
|
|
4415
|
-
function serializeVMobjectBase(v) {
|
|
4416
|
-
const base = serializeMobjectBase(v);
|
|
4417
|
-
return {
|
|
4418
|
-
...base,
|
|
4419
|
-
paths: v.paths.map(serializeBezierPath),
|
|
4420
|
-
strokeColor: serializeColor(v.getStrokeColor()),
|
|
4421
|
-
strokeWidth: v.getStrokeWidth(),
|
|
4422
|
-
fillColor: serializeColor(v.getFillColor()),
|
|
4423
|
-
fillOpacity: v.getFillOpacity()
|
|
4424
|
-
};
|
|
4425
|
-
}
|
|
4426
|
-
function serializeCircle(c) {
|
|
4427
|
-
const base = serializeVMobjectBase(c);
|
|
4428
|
-
const arc = c;
|
|
4429
|
-
return { ...base, type: "Circle", radius: arc.radius };
|
|
4430
|
-
}
|
|
4431
|
-
function serializeRectangle(r) {
|
|
4432
|
-
const base = serializeVMobjectBase(r);
|
|
4433
|
-
return { ...base, type: "Rectangle", width: r.width, height: r.height };
|
|
4434
|
-
}
|
|
4435
|
-
function serializeLine(l) {
|
|
4436
|
-
const base = serializeVMobjectBase(l);
|
|
4437
|
-
return {
|
|
4438
|
-
...base,
|
|
4439
|
-
type: "Line",
|
|
4440
|
-
start: serializeVector2(l.start),
|
|
4441
|
-
end: serializeVector2(l.end)
|
|
4442
|
-
};
|
|
4443
|
-
}
|
|
4444
|
-
function serializeArc(a) {
|
|
4445
|
-
const base = serializeVMobjectBase(a);
|
|
4446
|
-
return {
|
|
4447
|
-
...base,
|
|
4448
|
-
type: "Arc",
|
|
4449
|
-
radius: a.radius,
|
|
4450
|
-
startAngle: a.startAngle,
|
|
4451
|
-
endAngle: a.endAngle
|
|
4452
|
-
};
|
|
4453
|
-
}
|
|
4454
|
-
function serializePolygon(p) {
|
|
4455
|
-
const base = serializeVMobjectBase(p);
|
|
4456
|
-
return {
|
|
4457
|
-
...base,
|
|
4458
|
-
type: "Polygon",
|
|
4459
|
-
vertices: p.vertices.map(serializeVector2)
|
|
4460
|
-
};
|
|
4461
|
-
}
|
|
4462
|
-
function serializePoint(p) {
|
|
4463
|
-
const base = serializeVMobjectBase(p);
|
|
4464
|
-
return { ...base, type: "Point" };
|
|
4465
|
-
}
|
|
4466
|
-
function serializeVGroup(g) {
|
|
4467
|
-
const base = serializeMobjectBase(g);
|
|
4468
|
-
return {
|
|
4469
|
-
...base,
|
|
4470
|
-
type: "VGroup",
|
|
4471
|
-
children: g.getChildren().map(serializeMobject)
|
|
4472
|
-
};
|
|
4473
|
-
}
|
|
4474
|
-
function serializeMobject(m) {
|
|
4475
|
-
const typeName = m.constructor.name;
|
|
4476
|
-
const customSerializer = getSerializer(typeName);
|
|
4477
|
-
if (customSerializer) {
|
|
4478
|
-
return customSerializer.serialize(m);
|
|
4479
|
-
}
|
|
4480
|
-
if (m instanceof Circle) return serializeCircle(m);
|
|
4481
|
-
if (m instanceof Rectangle) return serializeRectangle(m);
|
|
4482
|
-
if (m instanceof Arrow) return serializeLine(m);
|
|
4483
|
-
if (m instanceof Line) return serializeLine(m);
|
|
4484
|
-
if (m instanceof Arc) return serializeArc(m);
|
|
4485
|
-
if (m instanceof Polygon) return serializePolygon(m);
|
|
4486
|
-
if (m instanceof Point) return serializePoint(m);
|
|
4487
|
-
if (m instanceof VGroup) return serializeVGroup(m);
|
|
4488
|
-
if (m instanceof VMobject) return serializeVMobjectBase(m);
|
|
4489
|
-
return serializeMobjectBase(m);
|
|
4490
|
-
}
|
|
4491
|
-
function applyMobjectBase(m, data) {
|
|
4492
|
-
const matrix = deserializeMatrix3x3(data.matrix);
|
|
4493
|
-
m.applyMatrix(matrix);
|
|
4494
|
-
m.setOpacity(data.opacity);
|
|
4495
|
-
}
|
|
4496
|
-
function applyVMobjectBase(v, data) {
|
|
4497
|
-
applyMobjectBase(v, data);
|
|
4498
|
-
v.paths = data.paths.map(deserializeBezierPath);
|
|
4499
|
-
v.stroke(deserializeColor(data.strokeColor), data.strokeWidth);
|
|
4500
|
-
v.fill(deserializeColor(data.fillColor), data.fillOpacity);
|
|
4501
|
-
}
|
|
4502
|
-
function deserializeMobject(data) {
|
|
4503
|
-
const customSerializer = getSerializer(data.type);
|
|
4504
|
-
if (customSerializer) {
|
|
4505
|
-
return customSerializer.deserialize(data);
|
|
4506
|
-
}
|
|
4507
|
-
switch (data.type) {
|
|
4508
|
-
case "Circle": {
|
|
4509
|
-
const d = data;
|
|
4510
|
-
const circle = new Circle(d.radius);
|
|
4511
|
-
applyVMobjectBase(circle, d);
|
|
4512
|
-
return circle;
|
|
4513
|
-
}
|
|
4514
|
-
case "Rectangle": {
|
|
4515
|
-
const d = data;
|
|
4516
|
-
const rect = new Rectangle(d.width, d.height);
|
|
4517
|
-
applyVMobjectBase(rect, d);
|
|
4518
|
-
return rect;
|
|
4519
|
-
}
|
|
4520
|
-
case "Line": {
|
|
4521
|
-
const d = data;
|
|
4522
|
-
const start = deserializeVector2(d.start);
|
|
4523
|
-
const end = deserializeVector2(d.end);
|
|
4524
|
-
const line = new Line(start.x, start.y, end.x, end.y);
|
|
4525
|
-
applyVMobjectBase(line, d);
|
|
4526
|
-
return line;
|
|
4527
|
-
}
|
|
4528
|
-
case "Arc": {
|
|
4529
|
-
const d = data;
|
|
4530
|
-
const arc = new Arc(d.radius, d.startAngle, d.endAngle);
|
|
4531
|
-
applyVMobjectBase(arc, d);
|
|
4532
|
-
return arc;
|
|
4533
|
-
}
|
|
4534
|
-
case "Polygon": {
|
|
4535
|
-
const d = data;
|
|
4536
|
-
const vertices = d.vertices.map(deserializeVector2);
|
|
4537
|
-
const polygon = new Polygon(vertices);
|
|
4538
|
-
applyVMobjectBase(polygon, d);
|
|
4539
|
-
return polygon;
|
|
4540
|
-
}
|
|
4541
|
-
case "Point": {
|
|
4542
|
-
const d = data;
|
|
4543
|
-
const point = new Point();
|
|
4544
|
-
applyVMobjectBase(point, d);
|
|
4545
|
-
return point;
|
|
4546
|
-
}
|
|
4547
|
-
case "VGroup": {
|
|
4548
|
-
const d = data;
|
|
4549
|
-
const children = d.children.map(deserializeMobject);
|
|
4550
|
-
const group = new VGroup(...children);
|
|
4551
|
-
applyMobjectBase(group, d);
|
|
4552
|
-
return group;
|
|
4553
|
-
}
|
|
4554
|
-
case "VMobject": {
|
|
4555
|
-
const d = data;
|
|
4556
|
-
const vmob = new VMobject();
|
|
4557
|
-
applyVMobjectBase(vmob, d);
|
|
4558
|
-
return vmob;
|
|
4559
|
-
}
|
|
4560
|
-
default: {
|
|
4561
|
-
const mob = new VMobject();
|
|
4562
|
-
if ("paths" in data) {
|
|
4563
|
-
applyVMobjectBase(mob, data);
|
|
4564
|
-
} else {
|
|
4565
|
-
applyMobjectBase(mob, data);
|
|
4566
|
-
}
|
|
4567
|
-
return mob;
|
|
4568
|
-
}
|
|
4569
|
-
}
|
|
4570
|
-
}
|
|
4571
|
-
|
|
4572
|
-
// src/core/serialization/easingLookup.ts
|
|
4573
|
-
var easingToName = /* @__PURE__ */ new Map();
|
|
4574
|
-
var nameToEasing = /* @__PURE__ */ new Map();
|
|
4575
|
-
function register(name, fn) {
|
|
4576
|
-
easingToName.set(fn, name);
|
|
4577
|
-
nameToEasing.set(name, fn);
|
|
4578
|
-
}
|
|
4579
|
-
register("linear", linear);
|
|
4580
|
-
register("easeInQuad", easeInQuad);
|
|
4581
|
-
register("easeOutQuad", easeOutQuad);
|
|
4582
|
-
register("easeInOutQuad", easeInOutQuad);
|
|
4583
|
-
register("easeInCubic", easeInCubic);
|
|
4584
|
-
register("easeOutCubic", easeOutCubic);
|
|
4585
|
-
register("easeInOutCubic", easeInOutCubic);
|
|
4586
|
-
register("easeInQuart", easeInQuart);
|
|
4587
|
-
register("easeOutQuart", easeOutQuart);
|
|
4588
|
-
register("easeInOutQuart", easeInOutQuart);
|
|
4589
|
-
register("easeInQuint", easeInQuint);
|
|
4590
|
-
register("easeOutQuint", easeOutQuint);
|
|
4591
|
-
register("easeInOutQuint", easeInOutQuint);
|
|
4592
|
-
register("easeInSine", easeInSine);
|
|
4593
|
-
register("easeOutSine", easeOutSine);
|
|
4594
|
-
register("easeInOutSine", easeInOutSine);
|
|
4595
|
-
register("easeInExpo", easeInExpo);
|
|
4596
|
-
register("easeOutExpo", easeOutExpo);
|
|
4597
|
-
register("easeInOutExpo", easeInOutExpo);
|
|
4598
|
-
register("easeInCirc", easeInCirc);
|
|
4599
|
-
register("easeOutCirc", easeOutCirc);
|
|
4600
|
-
register("easeInOutCirc", easeInOutCirc);
|
|
4601
|
-
register("easeInBack", easeInBack);
|
|
4602
|
-
register("easeOutBack", easeOutBack);
|
|
4603
|
-
register("easeInOutBack", easeInOutBack);
|
|
4604
|
-
register("easeInElastic", easeInElastic);
|
|
4605
|
-
register("easeOutElastic", easeOutElastic);
|
|
4606
|
-
register("easeInOutElastic", easeInOutElastic);
|
|
4607
|
-
register("easeInBounce", easeInBounce);
|
|
4608
|
-
register("easeOutBounce", easeOutBounce);
|
|
4609
|
-
register("easeInOutBounce", easeInOutBounce);
|
|
4610
|
-
register("smooth", smooth);
|
|
4611
|
-
register("doubleSmooth", doubleSmooth);
|
|
4612
|
-
register("rushInto", rushInto);
|
|
4613
|
-
register("rushFrom", rushFrom);
|
|
4614
|
-
register("slowInto", slowInto);
|
|
4615
|
-
register("thereAndBack", thereAndBack);
|
|
4616
|
-
register("wiggle", wiggle);
|
|
4617
|
-
register("lingering", lingering());
|
|
4618
|
-
register("runningStart", runningStart());
|
|
4619
|
-
function getEasingName(fn) {
|
|
4620
|
-
return easingToName.get(fn) ?? "smooth";
|
|
4621
|
-
}
|
|
4622
|
-
function getEasingByName(name) {
|
|
4623
|
-
return nameToEasing.get(name);
|
|
4624
|
-
}
|
|
4625
|
-
|
|
4626
|
-
// src/core/serialization/animation.ts
|
|
4627
|
-
function serializeAnimationConfig(anim) {
|
|
4628
|
-
return {
|
|
4629
|
-
durationSeconds: anim.getDuration(),
|
|
4630
|
-
delaySeconds: anim.getDelay(),
|
|
4631
|
-
easingName: getEasingName(anim.getEasing())
|
|
4632
|
-
};
|
|
4633
|
-
}
|
|
4634
|
-
function getAnimationType(anim) {
|
|
4635
|
-
if (anim instanceof FadeIn) return "FadeIn";
|
|
4636
|
-
if (anim instanceof FadeOut) return "FadeOut";
|
|
4637
|
-
if (anim instanceof MoveTo) return "MoveTo";
|
|
4638
|
-
if (anim instanceof Rotate) return "Rotate";
|
|
4639
|
-
if (anim instanceof Scale) return "Scale";
|
|
4640
|
-
if (anim instanceof MorphTo) return "MorphTo";
|
|
4641
|
-
if (anim instanceof Draw) return "Draw";
|
|
4642
|
-
if (anim instanceof Write) return "Write";
|
|
4643
|
-
if (anim instanceof Unwrite) return "Unwrite";
|
|
4644
|
-
if (anim instanceof Sequence) return "Sequence";
|
|
4645
|
-
if (anim instanceof Parallel) return "Parallel";
|
|
4646
|
-
return "Unknown";
|
|
4647
|
-
}
|
|
4648
|
-
function serializeAnimation(anim, getMobjectId2) {
|
|
4649
|
-
const baseData = {
|
|
4650
|
-
type: getAnimationType(anim),
|
|
4651
|
-
targetId: getMobjectId2(anim.getTarget()),
|
|
4652
|
-
config: serializeAnimationConfig(anim)
|
|
4653
|
-
};
|
|
4654
|
-
if (anim instanceof MoveTo) {
|
|
4655
|
-
const moveData = {
|
|
4656
|
-
...baseData,
|
|
4657
|
-
type: "MoveTo",
|
|
4658
|
-
destination: serializeVector2(anim.getDestination())
|
|
4659
|
-
};
|
|
4660
|
-
return moveData;
|
|
4661
|
-
}
|
|
4662
|
-
if (anim instanceof Rotate) {
|
|
4663
|
-
const rotateData = {
|
|
4664
|
-
...baseData,
|
|
4665
|
-
type: "Rotate",
|
|
4666
|
-
angle: anim.getAngle()
|
|
4667
|
-
};
|
|
4668
|
-
return rotateData;
|
|
4669
|
-
}
|
|
4670
|
-
if (anim instanceof Scale) {
|
|
4671
|
-
const scaleData = {
|
|
4672
|
-
...baseData,
|
|
4673
|
-
type: "Scale",
|
|
4674
|
-
factor: anim.getFactor()
|
|
4675
|
-
};
|
|
4676
|
-
return scaleData;
|
|
4677
|
-
}
|
|
4678
|
-
if (anim instanceof Sequence) {
|
|
4679
|
-
const seqData = {
|
|
4680
|
-
...baseData,
|
|
4681
|
-
type: "Sequence",
|
|
4682
|
-
animations: anim.getChildren().map((a) => serializeAnimation(a, getMobjectId2))
|
|
4683
|
-
};
|
|
4684
|
-
return seqData;
|
|
4685
|
-
}
|
|
4686
|
-
if (anim instanceof Parallel) {
|
|
4687
|
-
const parData = {
|
|
4688
|
-
...baseData,
|
|
4689
|
-
type: "Parallel",
|
|
4690
|
-
animations: anim.getChildren().map((a) => serializeAnimation(a, getMobjectId2))
|
|
4691
|
-
};
|
|
4692
|
-
return parData;
|
|
4693
|
-
}
|
|
4694
|
-
return baseData;
|
|
4695
|
-
}
|
|
4696
|
-
function applyConfig(anim, config) {
|
|
4697
|
-
anim.duration(config.durationSeconds);
|
|
4698
|
-
anim.delay(config.delaySeconds);
|
|
4699
|
-
const easing = getEasingByName(config.easingName);
|
|
4700
|
-
if (easing) {
|
|
4701
|
-
anim.ease(easing);
|
|
4702
|
-
}
|
|
4703
|
-
}
|
|
4704
|
-
function deserializeAnimation(data, registry2) {
|
|
4705
|
-
const target = registry2.get(data.targetId);
|
|
4706
|
-
if (!target) {
|
|
4707
|
-
throw new Error(`Mobject not found: ${data.targetId}`);
|
|
4708
|
-
}
|
|
4709
|
-
let anim;
|
|
4710
|
-
switch (data.type) {
|
|
4711
|
-
case "FadeIn":
|
|
4712
|
-
anim = new FadeIn(target);
|
|
4713
|
-
break;
|
|
4714
|
-
case "FadeOut":
|
|
4715
|
-
anim = new FadeOut(target);
|
|
4716
|
-
break;
|
|
4717
|
-
case "MoveTo": {
|
|
4718
|
-
const d = data;
|
|
4719
|
-
anim = new MoveTo(target, d.destination.x, d.destination.y);
|
|
4720
|
-
break;
|
|
4721
|
-
}
|
|
4722
|
-
case "Rotate": {
|
|
4723
|
-
const d = data;
|
|
4724
|
-
anim = new Rotate(target, d.angle);
|
|
4725
|
-
break;
|
|
4726
|
-
}
|
|
4727
|
-
case "Scale": {
|
|
4728
|
-
const d = data;
|
|
4729
|
-
anim = new Scale(target, d.factor);
|
|
4730
|
-
break;
|
|
4731
|
-
}
|
|
4732
|
-
case "Create":
|
|
4733
|
-
anim = new Write(target);
|
|
4734
|
-
break;
|
|
4735
|
-
case "Draw":
|
|
4736
|
-
anim = new Draw(target);
|
|
4737
|
-
break;
|
|
4738
|
-
case "Write":
|
|
4739
|
-
anim = new Write(target);
|
|
4740
|
-
break;
|
|
4741
|
-
case "Unwrite":
|
|
4742
|
-
anim = new Unwrite(target);
|
|
4743
|
-
break;
|
|
4744
|
-
case "Sequence": {
|
|
4745
|
-
const d = data;
|
|
4746
|
-
const children = d.animations.map((a) => deserializeAnimation(a, registry2));
|
|
4747
|
-
anim = new Sequence(children);
|
|
4748
|
-
break;
|
|
4749
|
-
}
|
|
4750
|
-
case "Parallel": {
|
|
4751
|
-
const d = data;
|
|
4752
|
-
const children = d.animations.map((a) => deserializeAnimation(a, registry2));
|
|
4753
|
-
anim = new Parallel(children);
|
|
4754
|
-
break;
|
|
4755
|
-
}
|
|
4756
|
-
default:
|
|
4757
|
-
throw new Error(`Unknown animation type: ${data.type}`);
|
|
4758
|
-
}
|
|
4759
|
-
applyConfig(anim, data.config);
|
|
4760
|
-
return anim;
|
|
4761
|
-
}
|
|
4762
|
-
|
|
4763
|
-
// src/core/serialization/scene.ts
|
|
4764
|
-
var SERIALIZATION_VERSION = "1.0.0";
|
|
4765
|
-
var serializationIdMap = /* @__PURE__ */ new Map();
|
|
4766
|
-
var serializationIdCounter = 0;
|
|
4767
|
-
function getSerializationId(m) {
|
|
4768
|
-
let id = serializationIdMap.get(m);
|
|
4769
|
-
if (!id) {
|
|
4770
|
-
id = `mob_${serializationIdCounter++}`;
|
|
4771
|
-
serializationIdMap.set(m, id);
|
|
4772
|
-
}
|
|
4773
|
-
return id;
|
|
4774
|
-
}
|
|
4775
|
-
function resetSerializationState() {
|
|
4776
|
-
serializationIdMap.clear();
|
|
4777
|
-
serializationIdCounter = 0;
|
|
4778
|
-
resetIdCounter();
|
|
4779
|
-
}
|
|
4780
|
-
function serializeSceneConfig(scene) {
|
|
4781
|
-
return {
|
|
4782
|
-
width: scene.getWidth(),
|
|
4783
|
-
height: scene.getHeight(),
|
|
4784
|
-
backgroundColor: serializeColor(scene.getBackgroundColor()),
|
|
4785
|
-
frameRate: scene.getFrameRate()
|
|
4786
|
-
};
|
|
4787
|
-
}
|
|
4788
|
-
function serializeTimeline(scene) {
|
|
4789
|
-
const timeline = scene.getTimeline();
|
|
4790
|
-
const scheduled = timeline.getScheduled();
|
|
4791
|
-
const serializedScheduled = scheduled.map((s) => ({
|
|
4792
|
-
animation: serializeAnimation(s.animation, getSerializationId),
|
|
4793
|
-
startTime: s.startTime
|
|
4794
|
-
}));
|
|
4795
|
-
return {
|
|
4796
|
-
loop: timeline.isLooping(),
|
|
4797
|
-
scheduled: serializedScheduled
|
|
4798
|
-
};
|
|
4799
|
-
}
|
|
4800
|
-
function serializeScene(scene) {
|
|
4801
|
-
resetSerializationState();
|
|
4802
|
-
const mobjects = scene.getMobjects();
|
|
4803
|
-
const serializedMobjects = mobjects.map((m) => serializeMobject(m));
|
|
4804
|
-
return {
|
|
4805
|
-
version: SERIALIZATION_VERSION,
|
|
4806
|
-
config: serializeSceneConfig(scene),
|
|
4807
|
-
mobjects: serializedMobjects,
|
|
4808
|
-
timeline: serializeTimeline(scene)
|
|
4809
|
-
};
|
|
4810
|
-
}
|
|
4811
|
-
function serialize(scene) {
|
|
4812
|
-
const data = serializeScene(scene);
|
|
4813
|
-
return JSON.stringify(data);
|
|
4814
|
-
}
|
|
4815
|
-
function deserializeScene(data) {
|
|
4816
|
-
if (!data.version) {
|
|
4817
|
-
throw new Error("Missing serialization version");
|
|
4818
|
-
}
|
|
4819
|
-
const scene = new Scene({
|
|
4820
|
-
width: data.config.width,
|
|
4821
|
-
height: data.config.height,
|
|
4822
|
-
backgroundColor: deserializeColor(data.config.backgroundColor),
|
|
4823
|
-
frameRate: data.config.frameRate
|
|
4824
|
-
});
|
|
4825
|
-
const mobjectRegistry = /* @__PURE__ */ new Map();
|
|
4826
|
-
const mobjects = [];
|
|
4827
|
-
for (const serializedMob of data.mobjects) {
|
|
4828
|
-
const mob = deserializeMobject(serializedMob);
|
|
4829
|
-
mobjectRegistry.set(serializedMob.id, mob);
|
|
4830
|
-
mobjects.push(mob);
|
|
4831
|
-
}
|
|
4832
|
-
scene.add(...mobjects);
|
|
4833
|
-
const timeline = scene.getTimeline();
|
|
4834
|
-
for (const scheduled of data.timeline.scheduled) {
|
|
4835
|
-
const animation = deserializeAnimation(scheduled.animation, mobjectRegistry);
|
|
4836
|
-
timeline.schedule(animation, scheduled.startTime);
|
|
4837
|
-
}
|
|
4838
|
-
return scene;
|
|
4839
|
-
}
|
|
4840
|
-
function deserialize(json) {
|
|
4841
|
-
const data = JSON.parse(json);
|
|
4842
|
-
return deserializeScene(data);
|
|
4843
|
-
}
|
|
4844
|
-
|
|
4845
4380
|
// src/core/renderer/FrameRenderer.ts
|
|
4846
4381
|
import { createCanvas } from "@napi-rs/canvas";
|
|
4847
4382
|
|
|
@@ -5048,7 +4583,7 @@ async function writePng(canvas, outputPath) {
|
|
|
5048
4583
|
}
|
|
5049
4584
|
|
|
5050
4585
|
// src/core/renderer/formats/sprite.ts
|
|
5051
|
-
import { join } from "path";
|
|
4586
|
+
import { join as join2 } from "path";
|
|
5052
4587
|
function padNumber(n, length) {
|
|
5053
4588
|
return n.toString().padStart(length, "0");
|
|
5054
4589
|
}
|
|
@@ -5059,7 +4594,7 @@ async function renderSpriteSequence(frameRenderer, outputDir, frameRate, totalDu
|
|
|
5059
4594
|
const time = frameIndex / frameRate;
|
|
5060
4595
|
const canvas = frameRenderer.renderFrame(time);
|
|
5061
4596
|
const filename = `frame_${padNumber(frameIndex, digitCount)}.png`;
|
|
5062
|
-
const outputPath =
|
|
4597
|
+
const outputPath = join2(outputDir, filename);
|
|
5063
4598
|
await writePng(canvas, outputPath);
|
|
5064
4599
|
progressReporter.reportFrame(frameIndex);
|
|
5065
4600
|
}
|
|
@@ -5291,7 +4826,6 @@ export {
|
|
|
5291
4826
|
Write,
|
|
5292
4827
|
clearRegistry,
|
|
5293
4828
|
smooth as defaultEasing,
|
|
5294
|
-
deserialize,
|
|
5295
4829
|
doubleSmooth,
|
|
5296
4830
|
easeInBack,
|
|
5297
4831
|
easeInBounce,
|
|
@@ -5333,7 +4867,6 @@ export {
|
|
|
5333
4867
|
runningStart,
|
|
5334
4868
|
rushFrom,
|
|
5335
4869
|
rushInto,
|
|
5336
|
-
serialize,
|
|
5337
4870
|
slowInto,
|
|
5338
4871
|
smooth,
|
|
5339
4872
|
thereAndBack,
|
package/package.json
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@redwilly/anima",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.22",
|
|
4
4
|
"description": "Animation library for mathematical visualizations",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/RedWilly/Anima.git"
|
|
8
|
+
},
|
|
9
|
+
"homepage": "https://github.com/RedWilly/Anima#readme",
|
|
10
|
+
"bugs": {
|
|
11
|
+
"url": "https://github.com/RedWilly/Anima/issues"
|
|
12
|
+
},
|
|
5
13
|
"type": "module",
|
|
6
14
|
"main": "./dist/index.js",
|
|
7
15
|
"types": "./dist/index.d.ts",
|