1use std::f64::consts::PI;
2
3use glam::{DVec3, dvec2, dvec3};
4use ranim::{
5 animation::{creation::WritingAnimSchedule, transform::GroupTransformAnimSchedule},
6 color::palettes::manim,
7 components::{Anchor, ScaleHint},
8 items::{
9 group::Group,
10 vitem::{Polygon, Rectangle, Square, VItem},
11 },
12 prelude::*,
13 timeline::TimeMark,
14 typst_svg,
15 utils::rate_functions::{linear, smooth},
16};
17
18fn build_logo(logo_width: f64) -> [VItem; 6] {
19 let mut red_bg_rect = Rectangle(logo_width / 2.0, logo_width).build();
20 red_bg_rect
21 .set_color(manim::RED_C.with_alpha(0.5))
22 .put_center_on(dvec3(-logo_width / 4.0, 0.0, 0.0));
23 let mut red_rect = Rectangle(logo_width / 4.0, logo_width).build();
24 red_rect
25 .set_color(manim::RED_C)
26 .put_anchor_on(Anchor::edge(1, 0, 0), dvec3(-logo_width / 4.0, 0.0, 0.0));
27
28 let mut green_bg_sq = Square(logo_width / 2.0).build();
29 green_bg_sq
30 .set_color(manim::GREEN_C.with_alpha(0.5))
31 .put_center_on(dvec3(logo_width / 4.0, logo_width / 4.0, 0.0));
32 let mut green_triangle = Polygon(vec![
33 dvec3(0.0, logo_width / 2.0, 0.0),
34 dvec3(logo_width / 2.0, logo_width / 2.0, 0.0),
35 dvec3(logo_width / 2.0, 0.0, 0.0),
36 ])
37 .build(); //
38 green_triangle.set_color(manim::GREEN_C);
39
40 let mut blue_bg_sq = Square(logo_width / 2.0).build();
41 blue_bg_sq
42 .set_color(manim::BLUE_C.with_alpha(0.5))
43 .put_center_on(dvec3(logo_width / 4.0, -logo_width / 4.0, 0.0));
44 let mut blue_triangle = green_triangle.clone();
45 blue_triangle
46 .set_color(manim::BLUE_C)
47 .rotate(PI, DVec3::Z)
48 .shift(DVec3::NEG_Y * logo_width / 2.0); //
49
50 [
51 red_bg_rect,
52 red_rect,
53 green_bg_sq,
54 green_triangle,
55 blue_bg_sq,
56 blue_triangle,
57 ]
58}
59#[scene]
60struct RanimLogoScene;
61
62impl TimelineConstructor for RanimLogoScene {
63 fn construct(self, timeline: &RanimTimeline, _camera: &mut Rabject<CameraFrame>) {
64 let frame_size = dvec2(8.0 * 16.0 / 9.0, 8.0);
65 let logo_width = frame_size.y * 0.618;
66
67 let mut logo = build_logo(logo_width)
68 .map(|item| timeline.insert(item))
69 .into_iter()
70 .collect::<Group<_>>();
71
72 timeline
73 .play(logo.lagged_anim(0.0, |item| {
74 item.write().with_duration(3.0).with_rate_func(smooth)
75 }))
76 .sync();
77
78 let gap_ratio = 1.0 / 60.0;
79 let gap = logo_width * gap_ratio;
80 let scale = (logo_width - gap * 2.0) / logo_width;
81 let scale = [
82 dvec3(scale, 1.0, 1.0),
83 dvec3(scale, scale, 1.0),
84 dvec3(scale, scale, 1.0),
85 ];
86 let anchor = [
87 Anchor::edge(-1, 0, 0),
88 Anchor::edge(1, 1, 0),
89 Anchor::edge(1, -1, 0),
90 ];
91 logo.chunks_mut(2)
92 .zip(scale.into_iter().zip(anchor))
93 .for_each(|(chunk, (scale, anchor))| {
94 timeline.play(
95 chunk
96 .transform(|data| {
97 data.scale_by_anchor(scale, anchor)
98 .scale_by_anchor(dvec3(0.9, 0.9, 1.0), Anchor::origin())
99 .shift(dvec3(0.0, 1.3, 0.0));
100 })
101 .with_rate_func(smooth)
102 .apply(),
103 );
104 });
105
106 let mut ranim_text = Group::<VItem>::from_svg(typst_svg!(
107 r#"
108#align(center)[
109 #text(10pt, font: "LXGW Bright")[Ranim]
110]"#
111 ));
112 ranim_text
113 .scale_to(ScaleHint::PorportionalHeight(1.0))
114 .put_center_on(DVec3::NEG_Y * 2.5);
115 let mut ranim_text = ranim_text
116 .into_iter()
117 .map(|item| timeline.insert(item))
118 .collect::<Group<_>>();
119 timeline.play(
120 ranim_text
121 .lagged_anim(0.2, |item| item.write())
122 .with_duration(2.0)
123 .with_rate_func(linear),
124 );
125 timeline.sync();
126
127 timeline.insert_time_mark(
128 timeline.duration_secs(),
129 TimeMark::Capture("preview.png".to_string()),
130 );
131 timeline.forward(1.0);
132
133 let mut all = logo.into_iter().chain(ranim_text).collect::<Group<_>>();
134 timeline.play(all.lagged_anim(0.0, |item| {
135 item.unwrite().with_duration(3.0).with_rate_func(smooth)
136 }));
137 }
138}
139
140fn main() {
141 render_scene(RanimLogoScene, &AppOptions::default());
142}
143