API 演示¶
HelloJAnimExample ¶
from janim.imports import *
class HelloJAnimExample(Timeline):
def construct(self):
# 定义物件
circle = Circle(color=BLUE)
square = Square(color=GREEN, fill_alpha=0.5)
# 进行动画
self.forward()
self.play(Create(circle))
self.play(Transform(circle, square))
self.play(Uncreate(square))
self.forward()
BasicAnimationExample ¶
from janim.imports import *
class BasicAnimationExample(Timeline):
def construct(self):
circle = Circle()
star = Star()
self.forward()
self.play(Create(circle))
self.play(circle.anim.points.shift(LEFT * 3).scale(1.5))
self.play(circle.anim.set(color=RED, fill_alpha=0.5))
self.play(SpinInFromNothing(star))
self.play(star.anim.points.shift(RIGHT * 3).scale(1.5))
self.play(star.anim.set(color=YELLOW, fill_alpha=0.5))
self.forward()
TextExample ¶
from janim.imports import *
class TextExample(Timeline):
def construct(self):
txt = Text('Here is some text', font_size=64)
desc = Group(
Text('You can also apply <c BLUE>styles</c> to the text.', format=Text.Format.RichText),
Text('You can also apply <c GREEN><fs 1.4>styles</fs></c> to the text.', format=Text.Format.RichText),
)
group = Group(txt, desc)
group.points.arrange(DOWN, buff=MED_LARGE_BUFF)
self.forward()
self.play(Write(txt))
self.play(FadeIn(desc[0], UP))
self.play(Transform(desc[0], desc[1]))
self.forward()
TypstExample ¶
from janim.imports import *
typst_doc = t_(
R'''
JAnim provides `TypstText` and `TypstMath` classes to insert Typst content.
Math expressions are also supported.
$ A = pi r^2 $
$ "area" = pi dot "radius"^2 $
$ cal(A) :=
{ x in RR | x "is natural" } $
#let x = 5
$ #x < 17 $
You can also use `TypstDoc`, which automatically align to the top of the viewport,
instead of the center.
''')
class TypstExample(Timeline):
CONFIG = Config(
typst_shared_preamble=t_(
R'''
#import "@janim/colors:0.0.0": *
#show raw: set text(BLUE)
''')
)
def construct(self):
doc = TypstDoc(typst_doc)
group = Group(
Text('TypstText', color=BLUE),
TypstText('This is a sentence with a math expression $f(x)=x^2$'),
Text('TypstMath', color=BLUE),
TypstMath('sum_(i=1)^n x_i = x_1 + x_2 + dots.c + x_n')
)
group.points.arrange_in_grid()
# 作用于文本的动画的渲染速度较慢
self.play(Write(doc), duration=4)
self.forward()
self.play(FadeOut(doc))
self.play(Write(group))
self.forward()
self.play(FadeOut(group))
TypstColorizeExample ¶
from janim.imports import *
class TypstColorizeExample(Timeline):
def construct(self):
typ = TypstMath('cos^2 theta + sin^2 theta = 1', scale=3).show()
self.forward()
self.play(typ['cos'].anim.set(color=BLUE))
self.play(typ['sin'].anim.set(color=BLUE))
self.play(typ['theta', 0].anim.set(color=GOLD))
self.play(typ['theta', 1].anim.set(color=ORANGE))
self.forward()
self.play(typ['theta', ...].anim.set(color=GREEN))
self.play(typ['space^2', ...].anim.set(color=RED))
self.forward()
AnimatingPiExample ¶
from janim.imports import *
class AnimatingPiExample(Timeline):
def construct(self):
grid = TypstMath('pi') * 100
grid.points.scale(2).arrange_in_grid(10, 10, buff=0.2)
grid.show()
self.play(grid.anim.points.shift(LEFT))
self.play(grid(VItem).anim.color.set(YELLOW))
self.forward()
self.play(grid(VItem).anim.color.set(BLUE))
self.forward()
self.play(grid.anim.points.to_center().set_height(TAU - MED_SMALL_BUFF))
self.forward()
self.play(grid.anim.points.apply_complex_fn(np.exp), duration=5)
self.forward()
self.play(
grid.anim.points.apply_point_fn(
lambda p: [
p[0] + 0.5 * math.sin(p[1]),
p[1] + 0.5 * math.sin(p[0]),
p[2]
]
),
duration=5
)
self.forward()
NumberPlaneExample ¶
from janim.imports import *
class NumberPlaneExample(Timeline):
def construct(self):
plane = NumberPlane(faded_line_ratio=1)
sin_graph = plane.get_graph(lambda x: math.sin(x))
self.forward(0.2)
self.play(Write(plane, lag_ratio=0.05))
self.play(Write(sin_graph))
self.forward()
self.play(
plane.anim.points.apply_matrix([
[3, -1],
[1, 2]
]),
sin_graph.anim(),
duration=2
)
self.forward()
UpdaterExample ¶
from janim.imports import *
class UpdaterExample(Timeline):
def construct(self):
square = Square(fill_color=BLUE_E, fill_alpha=1).show()
brace = Brace(square, UP).show()
def text_updater(p: UpdaterParams):
cmpt = brace.current().points
return cmpt.create_text(f'Width = {cmpt.brace_length:.2f}')
self.prepare(
DataUpdater(
brace,
lambda data, p: data.points.match(square.current())
),
ItemUpdater(None, text_updater),
duration=10
)
self.forward()
self.play(square.anim.points.scale(2))
self.play(square.anim.points.scale(0.5))
self.play(square.anim.points.set_width(5, stretch=True))
w0 = square.points.box.width
self.play(
DataUpdater(
square,
lambda data, p: data.points.set_width(
w0 + 0.5 * w0 * math.sin(p.alpha * p.range.duration)
)
),
duration=5
)
self.forward()
ArrowPointingExample ¶
from janim.imports import *
class ArrowPointingExample(Timeline):
def construct(self):
dot1 = Dot(LEFT * 3)
dot2 = Dot()
arrow = Arrow(dot1, dot2, color=YELLOW)
self.show(dot1, dot2, arrow)
self.play(
dot2.update.points.rotate(TAU, about_point=RIGHT * 2),
GroupUpdater(
arrow,
lambda data, p:
data.set_start_and_end(
dot1.points.box.center,
dot2.current().points.box.center
)
),
duration=4
)
参考:
CombineUpdatersExample ¶
from janim.imports import *
class CombineUpdatersExample(Timeline):
def construct(self):
square = Square()
square.points.to_border(LEFT)
# 这里每次 play 都多一个 Updater,用于演示 动画复合 的效果
self.play(
square.anim.points.to_border(RIGHT),
duration=2
)
###############################
square.points.to_border(LEFT)
self.play(
square.anim.points.to_border(RIGHT),
DataUpdater(
square,
lambda data, p: data.points.shift(UP * math.sin(p.alpha * 4 * PI)),
become_at_end=False
),
duration=2
)
###############################
square.points.to_border(LEFT)
self.play(
square.anim.points.to_border(RIGHT),
DataUpdater(
square,
lambda data, p: data.points.shift(UP * math.sin(p.alpha * 4 * PI)),
become_at_end=False
),
square.update(become_at_end=False).color.set(BLUE).r.points.rotate(-TAU),
duration=2
)
RotatingPieExample ¶
from janim.imports import *
class RotatingPieExample(Timeline):
def construct(self):
pie = Group(*[
Sector(start_angle=i * TAU / 4, angle=TAU / 4, radius=1.5, color=color, fill_alpha=1, stroke_alpha=0)
.points.shift(rotate_vector(UR * 0.05, i * TAU / 4))
.r
for i, color in enumerate([RED, PURPLE, MAROON, GOLD])
])
self.play(
GroupUpdater(
pie,
lambda data, p: data.points.rotate(p.alpha * TAU, about_point=ORIGIN),
duration=5
),
DataUpdater(
pie[0],
lambda data, p: data.points.shift(normalize(data.mark.get()) * p.alpha),
rate_func=there_and_back,
become_at_end=False,
at=2,
duration=2
)
)
MarkedItemExample ¶
from janim.imports import *
class MarkedSquare(MarkedItem, Square):
def __init__(self, side_length: float = 2.0, **kwargs):
super().__init__(side_length, **kwargs)
self.mark.set_points([RIGHT * side_length / 4, DOWN * side_length / 4])
class MarkedItemExample(Timeline):
def construct(self):
square = MarkedSquare()
tri1 = Triangle(radius=0.2, color=GREEN)
tri2 = Triangle(radius=0.2, color=BLUE)
dots = DotCloud(color=RED)
self.play(
square.update.points.rotate(TAU),
DataUpdater(
square,
lambda data, p: data.points.shift(RIGHT * math.sin(4 * math.pi * p.alpha))
),
DataUpdater(
tri1,
lambda data, p: data.mark.set(square.current().mark.get())
),
DataUpdater(
tri2,
lambda data, p: data.mark.set(square.current().mark.get(index=1))
),
DataUpdater(
dots,
lambda data, p: data.points.set(square.current().mark.get_points()),
skip_null_items=False
),
duration=4
)
FrameEffectExample ¶
from janim.imports import *
class FrameEffectExample(Timeline):
def construct(self):
squares = Square(0.5, color=BLUE, fill_alpha=0.3) * 49
squares.points.arrange_in_grid()
effect1 = SimpleFrameEffect( # (2~8s) [::2] 的方块产生渐变色
squares[::2],
shader='''
f_color = frame_texture(v_texcoord);
f_color.gb *= v_texcoord;
'''
)
effect2 = SimpleFrameEffect( # (4~8s) [1::2] 的方块产生故障效果
squares[1::2],
shader='''
vec2 uv = v_texcoord;
float glitchStrength = sin(time) * 0.02;
vec2 offset = vec2(glitchStrength, 0.0);
float r = frame_texture(uv + offset).r;
float g = frame_texture(uv).g;
float b = frame_texture(uv - offset).b;
float a = max(frame_texture(uv + offset).a, max(frame_texture(uv).a, frame_texture(uv - offset).a));
float lineNoise = step(0.5, fract(uv.y * 10.0 + time));
r *= lineNoise;
b *= lineNoise;
f_color = vec4(r, g, b, a);
''',
uniforms=['float time']
)
self.schedule(2, effect1.show)
self.play(
Rotate(squares, TAU, duration=8),
DataUpdater(
effect2,
lambda data, p: data.apply_uniforms(time=p.elapsed),
at=4,
duration=4
)
)
ThreeDShapesExample ¶
from janim.imports import *
class _ThreeDShapesExampleSub(Timeline):
def __init__(self, shape_type: str, background_color: JAnimColor):
super().__init__()
self.shape_type = shape_type
self.background_color = background_color
def construct(self):
if self.shape_type == 'smooth':
axes = ThreeDAxes((-8, 8), (-8, 8), (-8, 8)).apply_depth_test()
self.prepare(FadeIn(axes, at=1))
background = FrameRect(fill_alpha=1, fill_color=self.background_color, stroke_alpha=0, depth=100)
background.fix_in_frame()
self.prepare(FadeIn(background, at=1.5, duration=3))
for shape in [Torus(2, 1), Cylinder(2, 4), Cone(2, 4)]:
item = shape.into(self.shape_type).show()
self.play(self.RotatingCamera(), duration=4)
item.hide()
def RotatingCamera(self):
return AnimGroup(
DataUpdater(
self.camera,
lambda data, p: data.points.rotate(TAU * p.alpha, axis=RIGHT),
rate_func=linear
),
DataUpdater(
self.camera,
lambda data, p: data.points.rotate(TAU * p.alpha, axis=OUT),
rate_func=linear
),
)
class ThreeDShapesExample(Timeline):
def construct(self):
subs = [
_ThreeDShapesExampleSub(type, color).build().to_item()
for type, color in zip(
['checker', 'wire', 'smooth', 'dots'],
['#000022', '#000033', '#000033', '#000022']
)
]
subs[0].show()
effects = [
RectClip(sub, anchor=ORIGIN)
for sub in subs
]
effects[0].show().depth.set(-1)
dirs = [UL, UR, DL, DR]
self.forward()
for sub, effect, dir in zip(subs, effects, dirs):
self.show(sub, effect)
self.prepare(
effect.anim
.points.scale(0.5).to_border(dir, buff=0)
.r.transform.set(scale=0.5)
)
self.forward_to(subs[0].duration)
MaskExample ¶
from janim.imports import *
class MaskExample(Timeline):
def construct(self):
## 第一部分:文本在矩形遮罩中上浮的动画
txt = Text("Mask Example!")
txt.points.scale(2).move_to(DOWN * 0.5)
# 创建一个位于文本上方的矩形遮罩
mask1_shape = Rect(txt.points.box.width, txt.points.box.height)
mask1_shape.points.next_to(txt, UP, buff=0.5)
mask1 = ShapeMask(txt, shape=mask1_shape).show()
# 文本逐个上浮
self.play(
*[
char.anim.points.shift(UP * (0.5 + txt.points.box.height))
for char in txt[0]
],
lag_ratio=0.1,
)
self.forward()
## 第二部分:遮罩与文字的变形
# 将遮罩变为圆形
mask2 = ShapeMask(txt, shape=Circle())
self.play(Transform(mask1, mask2))
self.forward()
# 遮罩的羽化
rect = Rect(3, 3, color=LIGHT_BROWN, fill_alpha=1, depth=10)
self.play(FadeIn(rect))
self.play(
mask2.anim.points.shift(UP * 0.5)
.r.feather.set(0.1),
)
self.play(
Succession(
txt.anim.points.shift(LEFT * 1),
txt.anim.points.shift(RIGHT * 1),
)
)
self.forward()
# 持有物件的变换
txt2 = Text("The mask should be hold")
txt2.points.scale(2)
mask2.apply(txt2)
self.play(TransformMatchingDiff(txt, txt2))
self.forward()
# 遮罩本体的淡出
self.play(
FadeOut(rect),
FadeOut(mask2),
)
self.forward()
self.play(FadeOut(txt2))
self.forward()
## 第三部分:遮罩与布尔运算
dot1 = Dot(LEFT, 1.5, color=YELLOW, fill_alpha=0.25).show()
dot2 = Dot(RIGHT, 1.5, color=YELLOW, fill_alpha=0.25).show()
txt3 = Text('Some Example Text Here', font_size=40).show()
# 使用 boolean_ops 创建遮罩的交并集
mask_union = ShapeMask(
txt3,
shape=boolean_ops.Union(dot1, dot2)
)
mask_intersection = ShapeMask(
txt3,
shape=boolean_ops.Intersection(dot1, dot2)
)
self.forward()
self.play(FadeIn(mask_union))
self.forward(0.5)
self.play(Transform(mask_union, mask_intersection), duration=0.5)
self.forward(0.5)
self.play(Transform(mask_intersection, mask_union), duration=0.5)
self.forward(0.5)
self.play(FadeOut(Group(dot1, dot2, txt3)))
self.forward()
## 第四部分:复杂形状遮罩与特殊效果
# 复杂形状遮罩
txt_fashion = Text('Fashion')
txt_fashion.points.scale(10)
dots = DotCloud(
*[
[i * 0.3 + 0.15, j * 0.3, 0]
for j in range(20, -40, -1)
for i in range(-23, 23)
],
radius=0.1,
color=PURPLE_E,
)
mask3 = ShapeMask(dots, shape=txt_fashion).show()
self.prepare(
dots.anim(rate_func=linear).points.shift(UP * 3),
duration=5.0,
)
self.play(FadeIn(dots))
self.forward(1.5)
self.play(mask3.anim.invert.set(1.0))
self.forward(1.5)