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<'t: 'r, 'r>(
64 self,
65 timeline: &'t RanimTimeline,
66 _camera: &'r mut Rabject<'t, CameraFrame>,
67 ) {
68 let frame_size = dvec2(8.0 * 16.0 / 9.0, 8.0);
69 let logo_width = frame_size.y * 0.618;
70
71 let mut logo = build_logo(logo_width)
72 .map(|item| timeline.insert(item))
73 .into_iter()
74 .collect::<Group<_>>();
75
76 timeline
77 .play(logo.lagged_anim(0.0, |item| {
78 item.write().with_duration(3.0).with_rate_func(smooth)
79 }))
80 .sync();
81
82 let gap_ratio = 1.0 / 60.0;
83 let gap = logo_width * gap_ratio;
84 let scale = (logo_width - gap * 2.0) / logo_width;
85 let scale = [
86 dvec3(scale, 1.0, 1.0),
87 dvec3(scale, scale, 1.0),
88 dvec3(scale, scale, 1.0),
89 ];
90 let anchor = [
91 Anchor::edge(-1, 0, 0),
92 Anchor::edge(1, 1, 0),
93 Anchor::edge(1, -1, 0),
94 ];
95 logo.chunks_mut(2)
96 .zip(scale.into_iter().zip(anchor))
97 .for_each(|(chunk, (scale, anchor))| {
98 timeline.play(
99 chunk
100 .transform(|data| {
101 data.scale_by_anchor(scale, anchor)
102 .scale_by_anchor(dvec3(0.9, 0.9, 1.0), Anchor::origin())
103 .shift(dvec3(0.0, 1.3, 0.0));
104 })
105 .with_rate_func(smooth)
106 .apply(),
107 );
108 });
109
110 let mut ranim_text = Group::<VItem>::from_svg(typst_svg!(
111 r#"
112#align(center)[
113 #text(10pt, font: "LXGW Bright")[Ranim]
114]"#
115 ));
116 ranim_text
117 .scale_to(ScaleHint::PorportionalHeight(1.0))
118 .put_center_on(DVec3::NEG_Y * 2.5);
119 let mut ranim_text = ranim_text
120 .into_iter()
121 .map(|item| timeline.insert(item))
122 .collect::<Group<_>>();
123 timeline.play(
124 ranim_text
125 .lagged_anim(0.2, |item| item.write())
126 .with_duration(2.0)
127 .with_rate_func(linear),
128 );
129 timeline.sync();
130
131 timeline.insert_time_mark(
132 timeline.duration_secs(),
133 TimeMark::Capture("preview.png".to_string()),
134 );
135 timeline.forward(1.0);
136
137 let mut all = logo.into_iter().chain(ranim_text).collect::<Group<_>>();
138 timeline.play(all.lagged_anim(0.0, |item| {
139 item.unwrite().with_duration(3.0).with_rate_func(smooth)
140 }));
141 }
142}
143
144fn main() {
145 render_scene(RanimLogoScene, &AppOptions::default());
146}
147