pub struct Color {
pub r: u8,
pub g: u8,
pub b: u8,
pub a: u8,
}Expand description
32-bit RGBA color.
Fields§
§r: u8Red component.
g: u8Green component.
b: u8Blue component.
a: u8Alpha component.
Implementations§
Source§impl Color
impl Color
Sourcepub const fn rgb8(r: u8, g: u8, b: u8) -> Color
pub const fn rgb8(r: u8, g: u8, b: u8) -> Color
Creates a new RGB color with 255 alpha.
Examples found in repository?
6const BG: Color = Color::rgb8(0x0e, 0x0e, 0x12);
7const WHITE: Color = Color::rgb8(0xf0, 0xf0, 0xf0);
8const DIM: Color = Color::rgb8(0x55, 0x55, 0x66);
9const ACCENT: Color = Color::rgb8(0x68, 0xab, 0xdf);
10const RED: Color = Color::rgb8(0xe1, 0x32, 0x38);
11const YELLOW: Color = Color::rgb8(0xe6, 0xa7, 0x00);
12const GREEN: Color = Color::rgb8(0x25, 0xc2, 0x81);
13const TEAL: Color = Color::rgb8(0x20, 0xb2, 0xaa);
14
15const CANVAS_W: u32 = 1280;
16const CANVAS_H: u32 = 720;
17const LEFT: f32 = 40.0;
18
19fn ms(n: u64) -> Duration {
20 Duration::from_millis(n)
21}
22fn secs(n: u64) -> Duration {
23 Duration::from_secs(n)
24}
25
26// ── Text Helpers ───────────────────────────────────────────────────────────
27fn title(text: &str, y: f32) -> TextNode {
28 TextNode::default()
29 .with_anchor(Vec2::new(-1.0, -1.0))
30 .with_position(Vec2::new(LEFT, y))
31 .with_text(text)
32 .with_font_size(36.0)
33 .with_fill(ACCENT)
34 .with_font(FONT)
35 .with_opacity(0.0)
36}
37fn h2(text: &str, y: f32) -> TextNode {
38 TextNode::default()
39 .with_anchor(Vec2::new(-1.0, -1.0))
40 .with_position(Vec2::new(LEFT, y))
41 .with_text(text)
42 .with_font_size(22.0)
43 .with_fill(WHITE)
44 .with_font(FONT)
45 .with_opacity(0.0)
46}
47fn body(text: &str, y: f32) -> TextNode {
48 TextNode::default()
49 .with_anchor(Vec2::new(-1.0, -1.0))
50 .with_position(Vec2::new(LEFT, y))
51 .with_text(text)
52 .with_font_size(17.0)
53 .with_fill(Color::rgb8(0xcc, 0xcc, 0xdd))
54 .with_font(FONT)
55 .with_opacity(0.0)
56}More examples
7const BG: Color = Color::rgb8(0x0e, 0x0e, 0x12);
8const WHITE: Color = Color::rgb8(0xf0, 0xf0, 0xf0);
9const DIM: Color = Color::rgb8(0x55, 0x55, 0x66);
10const ACCENT: Color = Color::rgb8(0x68, 0xab, 0xdf);
11const YELLOW: Color = Color::rgb8(0xe6, 0xa7, 0x00);
12const GREEN: Color = Color::rgb8(0x25, 0xc2, 0x81);
13const RED: Color = Color::rgb8(0xe1, 0x32, 0x38);
14
15trait HasOpacity {
16 fn opacity_signal(&self) -> Signal<f32>;
17}
18impl HasOpacity for TextNode {
19 fn opacity_signal(&self) -> Signal<f32> {
20 self.opacity.clone()
21 }
22}
23impl HasOpacity for Circle {
24 fn opacity_signal(&self) -> Signal<f32> {
25 self.opacity.clone()
26 }
27}
28impl HasOpacity for Rect {
29 fn opacity_signal(&self) -> Signal<f32> {
30 self.opacity.clone()
31 }
32}
33impl HasOpacity for Line {
34 fn opacity_signal(&self) -> Signal<f32> {
35 self.opacity.clone()
36 }
37}
38
39fn show(n: &impl HasOpacity, d: Duration) -> Box<dyn Animation> {
40 n.opacity_signal()
41 .to(1.0, d)
42 .ease(easings::cubic_out)
43 .into()
44}
45
46fn hide(n: &impl HasOpacity, d: Duration) -> Box<dyn Animation> {
47 n.opacity_signal().to(0.0, d).ease(easings::cubic_in).into()
48}
49
50// Helper for boxes to ensure they start completely hidden and slightly scaled down
51fn create_box(label: &str, center: Vec2, size: Vec2) -> (Rect, TextNode) {
52 let box_center = Vec2::new(center.x, center.y);
53
54 let text_pos = Vec2::new(center.x, center.y);
55
56 let r = Rect::default()
57 .with_position(box_center)
58 .with_size(size)
59 .with_scale(0.95)
60 .with_opacity(0.0)
61 .with_radius(8.0)
62 .with_stroke(ACCENT, 2.0)
63 .with_fill(Color::rgb8(0x26, 0x26, 0x2a));
64
65 let t = TextNode::default()
66 .with_position(text_pos)
67 .with_text(label)
68 .with_font_size(18.0)
69 .with_font("JetBrains Mono")
70 .with_fill(WHITE)
71 .with_scale(0.95)
72 .with_opacity(0.0);
73
74 (r, t)
75}4fn main() {
5 // 1. Initialize Project
6 let mut project = Project::default()
7 .with_fps(60)
8 .with_dimensions(500, 500)
9 .with_title("Math Animation")
10 .close_on_finish();
11
12 // 2. Create MathNode (Typst syntax)
13 let tex = MathNode::default()
14 .with_position(Vec2::new(250.0, 250.0))
15 .with_equation("y = a x^2")
16 .with_font_size(48.0)
17 .with_fill(Color::rgb8(0xf2, 0xf2, 0xf2));
18 project.scene.add(Box::new(tex.clone()));
19
20 // 3. Define Animation Sequence
21 project.scene.video_timeline.add(loop_anim(
22 move || {
23 chain![
24 tex.tex("y = a x^2 + b x", Duration::from_secs(1)),
25 tex.tex("e^(i pi) + 1 = 0", Duration::from_secs(1)),
26 tex.tex("y = a x^2", Duration::from_secs(1)),
27 ]
28 },
29 None,
30 ));
31
32 // 4. Run interactive preview
33 project.show().expect("Failed to render");
34}4fn main() {
5 // 1. Initialize the Project
6 let mut project = Project::default()
7 .with_fps(60)
8 .with_cache(true)
9 .with_title("Getting Started")
10 .close_on_finish();
11
12 // 2. Define Nodes
13 let circle = Circle::default()
14 .with_position(Vec2::new(400.0, 300.0))
15 .with_radius(50.0)
16 .with_fill(Color::rgb8(0xe1, 0x32, 0x38)); // Red
17
18 let text = TextNode::default()
19 .with_position(Vec2::new(400.0, 450.0))
20 .with_text("Hello Rust")
21 .with_font_size(40.0)
22 .with_fill(Color::rgb8(0xf2, 0xf2, 0xf2)); // White-ish
23
24 // 3. Add Nodes to the Scene
25 project.scene.add(Box::new(circle.clone()));
26 project.scene.add(Box::new(text.clone()));
27
28 // 4. Add Animations to the Timeline
29 project.scene.video_timeline.add(all![
30 circle.radius.to(100.0, Duration::from_secs(1)),
31 text.position
32 .to(Vec2::new(400.0, 500.0), Duration::from_secs(1)),
33 ]);
34
35 // 5. Show
36 project.show().expect("Failed to render");
37}4fn main() {
5 // 1. Initialize for Export
6 let mut project = Project::default()
7 .with_fps(30)
8 .with_ffmpeg(true)
9 .with_title("Export")
10 .with_output_path("output")
11 .close_on_finish();
12
13 // 2. Setup Nodes
14 let circle = Circle::default()
15 .with_position(Vec2::new(400.0, 300.0))
16 .with_radius(50.0)
17 .with_fill(Color::rgb8(0x68, 0xab, 0xdf)); // Blue
18
19 let text = TextNode::default()
20 .with_position(Vec2::new(400.0, 50.0))
21 .with_text("Export Demo")
22 .with_font_size(40.0)
23 .with_fill(Color::rgb8(0xf2, 0xf2, 0xf2)); // White
24
25 project.scene.add(Box::new(circle.clone()));
26 project.scene.add(Box::new(text.clone()));
27
28 // 3. Define Animations (Color and Font Size)
29 project.scene.video_timeline.add(all![
30 // Circle color and size
31 circle
32 .fill_color
33 .to(Color::rgb8(0xf2, 0xf2, 0xf2), Duration::from_secs(2))
34 .ease(easings::quad_in_out),
35 circle
36 .radius
37 .to(150.0, Duration::from_secs(2))
38 .ease(easings::elastic_out),
39 // Text font size
40 text.font_size
41 .to(50.0, Duration::from_secs(2))
42 .ease(easings::cubic_out),
43 ]);
44
45 // 4. Export (Renders frames and combines them into out.mkv)
46 println!("Starting export to {}...", project.output_path.display());
47 project.export().expect("Failed to export");
48}4fn main() {
5 let mut project = Project::default().with_title("Polygon").close_on_finish();
6
7 // Create a regular pentagon
8 let pentagon = Polygon::regular(5, 100.0)
9 .with_fill(Color::rgb8(0xe1, 0x32, 0x38)) // Red
10 .with_position(Vec2::new(200.0, 300.0))
11 .with_scale(0.0);
12
13 // Create a custom triangle
14 let triangle = Polygon::default()
15 .with_position(Vec2::new(500.0, 300.0))
16 .with_points(vec![
17 Vec2::new(0.0, -100.0),
18 Vec2::new(100.0, 100.0),
19 Vec2::new(-100.0, 100.0),
20 ])
21 .with_fill(Color::rgb8(0x68, 0xab, 0xdf)) // Blue
22 .with_stroke(Color::WHITE, 4.0);
23
24 project.scene.add(Box::new(pentagon.clone()));
25 project.scene.add(Box::new(triangle.clone()));
26
27 // Animate rotation and opacity
28 project.scene.video_timeline.add(all![
29 chain![
30 pentagon.scale.to(Vec2::ONE, Duration::from_secs(1)),
31 pentagon
32 .rotation
33 .to(std::f32::consts::PI, Duration::from_secs(2)),
34 pentagon.scale.to(-Vec2::ONE, Duration::from_secs(1)),
35 ],
36 chain![
37 triangle.opacity.to(1.0, Duration::from_secs(1)),
38 triangle
39 .position
40 .to(Vec2::new(500.0, 300.0), Duration::from_secs(1)),
41 triangle
42 .rotation
43 .to(360.0_f32.to_radians(), Duration::from_secs(1))
44 ],
45 ]);
46
47 project.show().expect("Failed to render");
48}Sourcepub const fn rgba8(r: u8, g: u8, b: u8, a: u8) -> Color
pub const fn rgba8(r: u8, g: u8, b: u8, a: u8) -> Color
Creates a new RGBA color.
Examples found in repository?
86fn hline(y: f32) -> Line {
87 Line::default()
88 .with_start(Vec2::new(LEFT, y))
89 .with_end(Vec2::new(LEFT, y))
90 .with_stroke(Color::rgba8(255, 255, 255, 25), 1.0)
91}
92// Shorthand for show/hide
93fn show(n: &impl HasOpacity, d: Duration) -> Box<dyn Animation> {
94 n.opacity_signal()
95 .to(1.0, d)
96 .ease(easings::cubic_out)
97 .into()
98}
99fn hide(n: &impl HasOpacity, d: Duration) -> Box<dyn Animation> {
100 n.opacity_signal().to(0.0, d).ease(easings::cubic_in).into()
101}
102
103// Trait to unify opacity access across different node types
104trait HasOpacity {
105 fn opacity_signal(&self) -> Signal<f32>;
106}
107impl HasOpacity for TextNode {
108 fn opacity_signal(&self) -> Signal<f32> {
109 self.opacity.clone()
110 }
111}
112impl HasOpacity for Circle {
113 fn opacity_signal(&self) -> Signal<f32> {
114 self.opacity.clone()
115 }
116}
117impl HasOpacity for Rect {
118 fn opacity_signal(&self) -> Signal<f32> {
119 self.opacity.clone()
120 }
121}
122impl HasOpacity for Line {
123 fn opacity_signal(&self) -> Signal<f32> {
124 self.opacity.clone()
125 }
126}
127impl HasOpacity for Polygon {
128 fn opacity_signal(&self) -> Signal<f32> {
129 self.opacity.clone()
130 }
131}
132impl HasOpacity for CodeNode {
133 fn opacity_signal(&self) -> Signal<f32> {
134 self.opacity.clone()
135 }
136}
137impl HasOpacity for GroupNode {
138 fn opacity_signal(&self) -> Signal<f32> {
139 self.opacity.clone()
140 }
141}
142impl HasOpacity for ImageNode {
143 fn opacity_signal(&self) -> Signal<f32> {
144 self.opacity.clone()
145 }
146}
147
148fn main() {
149 let mut project = Project::default()
150 .with_dimensions(CANVAS_W, CANVAS_H)
151 .with_fps(60)
152 .with_title("Explainer")
153 .with_background(BG)
154 .close_on_finish();
155
156 // =====================================================================
157 // S1: TITLE CARD
158 // =====================================================================
159 let s1_line = hline(100.0);
160 let s1_title = TextNode::default()
161 .with_anchor(Vec2::new(-1.0, -1.0))
162 .with_position(Vec2::new(LEFT, 120.0))
163 .with_text("motion-canvas-rs")
164 .with_font_size(52.0)
165 .with_fill(ACCENT)
166 .with_font(FONT)
167 .with_opacity(0.0);
168 let s1_sub = h2("A GPU-Accelerated Vector Animation Engine", 185.0);
169 let s1_built = body(
170 "Built on Vello + Typst — Inspired by Motion Canvas",
171 220.0,
172 );
173 let s1_desc = body(
174 "This animation will teach you how the library works,",
175 280.0,
176 );
177 let s1_desc2 = body(
178 "from struct definitions to the GPU rendering pipeline.",
179 305.0,
180 );
181
182 let s1_logo = ImageNode::default()
183 .with_position(Vec2::new(950.0, 420.0))
184 .with_path("examples/images/motion-canvas-rs.svg")
185 .with_scale(0.3)
186 .with_opacity(0.0);
187
188 for n in [&s1_title, &s1_sub, &s1_built, &s1_desc, &s1_desc2] {
189 project.scene.add(Box::new(n.clone()));
190 }
191 project.scene.add(Box::new(s1_line.clone()));
192 project.scene.add(Box::new(s1_logo.clone()));
193
194 // =====================================================================
195 // S2: THE 5 STEPS
196 // =====================================================================
197 let s2_h = title("Every program follows 5 steps", 50.0);
198 let steps = [
199 "1. Create a Project — your canvas settings",
200 "2. Create Nodes — shapes, text, images",
201 "3. Add Nodes to Scene — what gets drawn",
202 "4. Animate the Timeline — how things move",
203 "5. Show or Export — live window or video",
204 ];
205 let s2_texts: Vec<TextNode> = steps
206 .iter()
207 .enumerate()
208 .map(|(i, s)| body(s, 120.0 + i as f32 * 35.0))
209 .collect();
210
211 project.scene.add(Box::new(s2_h.clone()));
212 for t in &s2_texts {
213 project.scene.add(Box::new(t.clone()));
214 }
215
216 // =====================================================================
217 // S3: WHAT IS A STRUCT? + The Project struct
218 // =====================================================================
219 let s3_h = title("What is a 'struct'?", 50.0);
220 let s3_explain = h2(
221 "A struct is a container that groups related data together.",
222 95.0,
223 );
224 let s3_analogy = body(
225 "Think of it like a class in Python/JS, but it only holds data.",
226 130.0,
227 );
228
229 let s3_code = code_block(
230 "pub struct Project {
231 pub width: u32, // Canvas width in pixels
232 pub height: u32, // Canvas height in pixels
233 pub fps: u32, // Frames per second
234 pub title: String, // Window title
235 pub scene: BaseScene, // Holds nodes + timelines
236 pub background_color: Color,
237 pub close_on_finish: bool,
238}",
239 175.0,
240 );
241
242 let s3_note = note(
243 "^ This is the actual Project struct from the library.",
244 420.0,
245 );
246 let s3_note2 = body(
247 "'pub' means public — anyone can read/write these fields.",
248 455.0,
249 );
250 let s3_note3 = body(
251 "u32 = unsigned 32-bit integer, String = text, bool = true/false",
252 485.0,
253 );
254
255 for n in [
256 &s3_h,
257 &s3_explain,
258 &s3_analogy,
259 &s3_note,
260 &s3_note2,
261 &s3_note3,
262 ] {
263 project.scene.add(Box::new(n.clone()));
264 }
265 project.scene.add(Box::new(s3_code.clone()));
266
267 // =====================================================================
268 // S4: WHAT IS impl? + Builder pattern
269 // =====================================================================
270 let s4_h = title("What is 'impl'?", 50.0);
271 let s4_explain = h2("impl adds methods (functions) to a struct.", 95.0);
272 let s4_analogy = body(
273 "Like adding methods to a class. Separated from the data.",
274 130.0,
275 );
276
277 let s4_code = code_block(
278 "impl Project {
279 pub fn with_fps(mut self, fps: u32) -> Self {
280 self.fps = fps; // set the value
281 self // return yourself (builder pattern)
282 }
283 pub fn with_title(mut self, title: &str) -> Self {
284 self.title = title.to_string();
285 self
286 }
287}",
288 175.0,
289 );
290
291 let s4_usage = body("Usage — chain calls to configure:", 430.0);
292 let s4_usage_code = code_block(
293 "let project = Project::default()
294 .with_fps(60)
295 .with_title(\"My Animation\")
296 .with_dimensions(800, 600)
297 .close_on_finish();",
298 460.0,
299 );
300
301 let s4_note = note(
302 "Each .with_*() returns 'self', so you can chain them.",
303 590.0,
304 );
305
306 for n in [&s4_h, &s4_explain, &s4_analogy, &s4_usage, &s4_note] {
307 project.scene.add(Box::new(n.clone()));
308 }
309 project.scene.add(Box::new(s4_code.clone()));
310 project.scene.add(Box::new(s4_usage_code.clone()));
311
312 // =====================================================================
313 // S5: WHAT IS A TRAIT? + The Node trait
314 // =====================================================================
315 let s5_h = title("What is a 'trait'?", 50.0);
316 let s5_explain = h2(
317 "A trait is a contract — like an interface in Java/TypeScript.",
318 95.0,
319 );
320 let s5_analogy = body(
321 "Any type that implements a trait promises to provide those methods.",
322 130.0,
323 );
324
325 let s5_code = code_block(
326 "pub trait Node: Send + Sync + 'static {
327 fn render(&self, scene: &mut Scene,
328 parent_transform: Affine,
329 parent_opacity: f32);
330 fn update(&mut self, dt: Duration);
331 fn state_hash(&self) -> u64;
332 fn clone_node(&self) -> Box<dyn Node>;
333}",
334 175.0,
335 );
336
337 let s5_r = note(
338 "render() — draw yourself using current signal values",
339 410.0,
340 );
341 let s5_u = note(
342 "update(dt) — called every frame (for per-frame logic)",
343 435.0,
344 );
345 let s5_s = note(
346 "state_hash() — returns a number that changes when you change",
347 460.0,
348 );
349 let s5_c = note("clone_node() — make a deep copy of yourself", 485.0);
350 let s5_every = body(
351 "Circle, Rect, Line, TextNode, Polygon all implement Node.",
352 530.0,
353 );
354
355 for n in [
356 &s5_h,
357 &s5_explain,
358 &s5_analogy,
359 &s5_r,
360 &s5_u,
361 &s5_s,
362 &s5_c,
363 &s5_every,
364 ] {
365 project.scene.add(Box::new(n.clone()));
366 }
367 project.scene.add(Box::new(s5_code.clone()));
368
369 // =====================================================================
370 // S6: NODE GALLERY (visual demo)
371 // =====================================================================
372 let s6_h = title("The Built-in Nodes", 50.0);
373 let s6_sub = body(
374 "Each node uses the builder pattern and stores properties as Signals.",
375 90.0,
376 );
377
378 let demo_c = Circle::default()
379 .with_position(Vec2::new(120.0, 230.0))
380 .with_radius(40.0)
381 .with_fill(RED)
382 .with_opacity(0.0);
383 let demo_r = Rect::default()
384 .with_position(Vec2::new(293.0, 230.0))
385 .with_size(Vec2::new(80.0, 80.0))
386 .with_fill(ACCENT)
387 .with_radius(8.0)
388 .with_opacity(0.0);
389 let demo_l = Line::default()
390 .with_start(Vec2::new(420.0, 200.0))
391 .with_end(Vec2::new(510.0, 270.0))
392 .with_stroke(WHITE, 3.0)
393 .with_opacity(0.0);
394 let demo_p = Polygon::regular(5, 40.0)
395 .with_position(Vec2::new(606.0, 230.0))
396 .with_fill(YELLOW)
397 .with_opacity(0.0);
398 let demo_t = TextNode::default()
399 .with_position(Vec2::new(765.0, 230.0))
400 .with_text("Abc")
401 .with_font_size(36.0)
402 .with_fill(GREEN)
403 .with_font(FONT)
404 .with_opacity(0.0);
405
406 let lc = dim("Circle", 95.0, 285.0);
407 let lr = dim("Rect", 280.0, 285.0);
408 let ll = dim("Line", 445.0, 285.0);
409 let lp = dim("Polygon", 580.0, 285.0);
410 let lt = dim("TextNode", 735.0, 285.0);
411
412 let s6_box_h = h2("Why Box<dyn Node>?", 340.0);
413 let s6_box1 = body("The scene stores different node types in one list:", 375.0);
414 let s6_box_code = code_block(
415 "pub struct BaseScene {
416 pub nodes: Vec<Box<dyn Node>>, // a list of \"any Node\"
417}
418// 'Box' = heap-allocated, 'dyn Node' = any type implementing Node
419// Like List<INode> in Java or Array<Node> in TypeScript
420project.scene.add(Box::new(circle)); // wrap + add",
421 405.0,
422 );
423
424 for n in [&s6_h, &s6_sub, &lc, &lr, &ll, &lp, <, &s6_box_h, &s6_box1] {
425 project.scene.add(Box::new(n.clone()));
426 }
427 project.scene.add(Box::new(demo_c.clone()));
428 project.scene.add(Box::new(demo_r.clone()));
429 project.scene.add(Box::new(demo_l.clone()));
430 project.scene.add(Box::new(demo_p.clone()));
431 project.scene.add(Box::new(demo_t.clone()));
432 project.scene.add(Box::new(s6_box_code.clone()));
433
434 // =====================================================================
435 // S7: SIGNALS — The Reactive Core
436 // =====================================================================
437 let s7_h = title("Signals — The Reactive Core", 50.0);
438 let s7_sub = h2("Every animatable property is a Signal<T>.", 95.0);
439
440 let s7_code = code_block(
441 "pub struct Signal<T> {
442 pub data: Arc<Mutex<SignalData<T>>>,
443}
444pub struct SignalData<T> {
445 pub value: T, // the actual value (f32, Vec2, Color...)
446}",
447 140.0,
448 );
449
450 let s7_arc = note("Arc = shared pointer. Multiple owners, same data.", 310.0);
451 let s7_mutex = note(
452 "Mutex = lock. Only one thread reads/writes at a time.",
453 335.0,
454 );
455 let s7_why = body(
456 "Why? A node and its animation both need the same property:",
457 380.0,
458 );
459
460 let s7_diagram_code = code_block(
461 "let circle = Circle::default().with_radius(50.0);
462// circle.radius is a Signal<f32>
463
464circle.radius.to(100.0, Duration::from_secs(1));
465// Creates a SignalTween with a CLONE of circle.radius
466// Both point to the SAME underlying value (via Arc)
467
468// The animation WRITES new values each frame
469// The node READS them when rendering",
470 420.0,
471 );
472
473 // Live demo circle
474 let sig_demo = Circle::default()
475 .with_position(Vec2::new(1000.0, 400.0))
476 .with_radius(50.0)
477 .with_fill(RED)
478 .with_stroke(Color::rgba8(255, 255, 255, 50), 2.0)
479 .with_opacity(0.0);
480 let sig_lbl = dim("Live Signal demo", 900.0, 150.0);
481
482 for n in [&s7_h, &s7_sub, &s7_arc, &s7_mutex, &s7_why, &sig_lbl] {
483 project.scene.add(Box::new(n.clone()));
484 }
485 project.scene.add(Box::new(s7_code.clone()));
486 project.scene.add(Box::new(s7_diagram_code.clone()));
487 project.scene.add(Box::new(sig_demo.clone()));
488
489 // =====================================================================
490 // S8: SIGNAL TWEEN — How animations work per-frame
491 // =====================================================================
492 let s8_h = title("SignalTween — The Animation Engine", 50.0);
493 let s8_sub = body(
494 ".to() creates a SignalTween that interpolates over time:",
495 90.0,
496 );
497
498 let s8_code = code_block(
499 "pub struct SignalTween<T> {
500 data: Arc<Mutex<SignalData<T>>>, // shared ref to signal
501 start_value: Option<T>, // captured on FIRST update (lazy!)
502 target_value: Option<T>, // where we're going
503 duration: Duration, // how long
504 elapsed: Duration, // how much time passed
505 easing: fn(f32) -> f32, // curve function
506}",
507 125.0,
508 );
509
510 let s8_how = h2("Each frame update:", 340.0);
511 let s8_steps = [
512 "1. elapsed += dt",
513 "2. t_linear = elapsed / duration (0.0 to 1.0)",
514 "3. t_eased = easing(t_linear) (curved)",
515 "4. value = lerp(start, target, t) (interpolate)",
516 "5. Write value into Signal (node sees it)",
517 "6. If elapsed >= duration: finished! (return leftover dt)",
518 ];
519 let s8_step_texts: Vec<TextNode> = s8_steps
520 .iter()
521 .enumerate()
522 .map(|(i, s)| body(s, 370.0 + i as f32 * 28.0))
523 .collect();
524
525 let s8_lazy = note(
526 "start_value is captured lazily — so chained tweens read the",
527 570.0,
528 );
529 let s8_lazy2 = note(
530 "correct value at their actual start time, not creation time.",
531 590.0,
532 );
533
534 // Progress bar
535 let prog_bg = Rect::default()
536 .with_position(Vec2::new(895.0, 150.0))
537 .with_size(Vec2::new(400.0, 16.0))
538 .with_fill(Color::rgba8(255, 255, 255, 15))
539 .with_radius(8.0)
540 .with_opacity(0.0);
541 let prog_fill = Rect::default()
542 .with_position(Vec2::new(695.0, 154.0))
543 .with_anchor(Vec2::new(-1.0, 0.5))
544 .with_size(Vec2::new(0.0, 16.0))
545 .with_fill(ACCENT)
546 .with_radius(8.0)
547 .with_opacity(0.0);
548 let plbl0 = dim("t=0", 700.0, 172.0);
549 let plbl1 = dim("t=1", 1070.0, 172.0);
550 let tween_ball = Circle::default()
551 .with_position(Vec2::new(900.0, 430.0))
552 .with_radius(30.0)
553 .with_fill(RED)
554 .with_opacity(0.0);
555 let tween_lbl = dim("radius animating: 30 -> 80", 760.0, 220.0);
556
557 for n in [
558 &s8_h, &s8_sub, &s8_how, &s8_lazy, &s8_lazy2, &plbl0, &plbl1, &tween_lbl,
559 ] {
560 project.scene.add(Box::new(n.clone()));
561 }
562 project.scene.add(Box::new(s8_code.clone()));
563 for t in &s8_step_texts {
564 project.scene.add(Box::new(t.clone()));
565 }
566 project.scene.add(Box::new(prog_bg.clone()));
567 project.scene.add(Box::new(prog_fill.clone()));
568 project.scene.add(Box::new(tween_ball.clone()));
569
570 // =====================================================================
571 // S9: TWEENABLE + EASINGS
572 // =====================================================================
573 let s9_h = title("Tweenable — What Can Be Animated", 50.0);
574 let s9_code = code_block(
575 "pub trait Tweenable: Clone + Send + Sync {
576 fn interpolate(a: &Self, b: &Self, t: f32) -> Self;
577 fn state_hash(&self) -> u64;
578}
579// Implemented for: f32, Vec2, Color, String, Affine, Vec<Vec2>
580// f32: lerp(a, b, t) = a + (b-a)*t
581// Vec2: lerp x and y independently
582// Color: lerp R,G,B,A channels independently
583// String: snap — returns 'a' until t>=1, then 'b'",
584 95.0,
585 );
586
587 let s9_easing_h = h2("Easing functions curve the linear t:", 310.0);
588 let s9_easing_desc = body("Same distance, same duration — different feel.", 340.0);
589
590 let enames = [
591 "linear",
592 "cubic_in_out",
593 "elastic_out",
594 "bounce_out",
595 "back_out",
596 ];
597 let ecolors = [WHITE, ACCENT, RED, YELLOW, GREEN];
598 let mut eballs: Vec<Circle> = Vec::new();
599 let mut elabels: Vec<TextNode> = Vec::new();
600 for (i, name) in enames.iter().enumerate() {
601 let y = 390.0 + i as f32 * 55.0;
602 let b = Circle::default()
603 .with_position(Vec2::new(250.0, y))
604 .with_radius(12.0)
605 .with_fill(ecolors[i])
606 .with_opacity(0.0);
607 let l = dim(name, LEFT, y - 5.0);
608 project.scene.add(Box::new(b.clone()));
609 project.scene.add(Box::new(l.clone()));
610 eballs.push(b);
611 elabels.push(l);
612 }
613 project.scene.add(Box::new(s9_h.clone()));
614 project.scene.add(Box::new(s9_code.clone()));
615 project.scene.add(Box::new(s9_easing_h.clone()));
616 project.scene.add(Box::new(s9_easing_desc.clone()));
617
618 // =====================================================================
619 // S10: FLOW CONTROLS
620 // =====================================================================
621 let s10_h = title("Flow Controls — Composing Animations", 50.0);
622 let s10_sub = body(
623 "Individual tweens are simple. Power comes from composing them.",
624 90.0,
625 );
626
627 // chain
628 let s10_chain_h = h2("chain![ ] — one after another", 140.0);
629 let chain_d: Vec<Circle> = (0..3)
630 .map(|i| {
631 Circle::default()
632 .with_position(Vec2::new(LEFT + 30.0 + i as f32 * 60.0, 200.0))
633 .with_radius(18.0)
634 .with_fill([RED, ACCENT, YELLOW][i])
635 .with_opacity(0.0)
636 })
637 .collect();
638
639 // all
640 let s10_all_h = h2("all![ ] — all at the same time", 270.0);
641 let all_d: Vec<Circle> = (0..3)
642 .map(|i| {
643 Circle::default()
644 .with_position(Vec2::new(LEFT + 30.0 + i as f32 * 60.0, 330.0))
645 .with_radius(18.0)
646 .with_fill([RED, ACCENT, YELLOW][i])
647 .with_opacity(0.0)
648 })
649 .collect();
650
651 // sequence
652 let s10_seq_h = h2("sequence![ ] — staggered starts", 400.0);
653 let seq_d: Vec<Circle> = (0..3)
654 .map(|i| {
655 Circle::default()
656 .with_position(Vec2::new(LEFT + 30.0 + i as f32 * 60.0, 460.0))
657 .with_radius(18.0)
658 .with_fill([RED, ACCENT, YELLOW][i])
659 .with_opacity(0.0)
660 })
661 .collect();
662
663 let s10_code = code_block(
664 "chain![ a, b, c ] // a then b then c
665all![ a, b, c ] // a + b + c together
666sequence![ 200ms, a, b, c ] // staggered
667delay![ 500ms, a ] // wait then play
668wait(1s) // pause
669any![ a, b ] // race: first wins
670loop_anim![ a, 3 ] // repeat 3 times",
671 510.0,
672 );
673
674 project.scene.add(Box::new(s10_h.clone()));
675 project.scene.add(Box::new(s10_sub.clone()));
676 project.scene.add(Box::new(s10_chain_h.clone()));
677 project.scene.add(Box::new(s10_all_h.clone()));
678 project.scene.add(Box::new(s10_seq_h.clone()));
679 project.scene.add(Box::new(s10_code.clone()));
680 for d in &chain_d {
681 project.scene.add(Box::new(d.clone()));
682 }
683 for d in &all_d {
684 project.scene.add(Box::new(d.clone()));
685 }
686 for d in &seq_d {
687 project.scene.add(Box::new(d.clone()));
688 }
689
690 // =====================================================================
691 // S11: TIMELINE + RENDERING
692 // =====================================================================
693 let s11_h = title("The Timeline — Animation Queue", 50.0);
694 let s11_code = code_block(
695 "pub struct Timeline {
696 pub animations: Vec<Box<dyn Animation>>,
697}
698impl Timeline {
699 fn update(&mut self, mut dt: Duration) {
700 while !self.animations.is_empty() {
701 let (finished, leftover) = self.animations[0].update(dt);
702 if finished {
703 self.animations.remove(0); // pop front
704 dt = leftover; // pass leftover to next!
705 } else { break; }
706 }
707 }
708}",
709 95.0,
710 );
711
712 let s11_leftover = note(
713 "leftover propagation: if A finishes mid-frame, the remaining",
714 390.0,
715 );
716 let s11_leftover2 = note(
717 "dt is immediately given to B. No 'lost frames' at transitions.",
718 415.0,
719 );
720
721 let s11_render_h = h2("Rendering Pipeline (per frame):", 470.0);
722 let s11_steps = [
723 "1. Timeline.update(dt) => SignalTween writes to Signals",
724 "2. Node.render() => reads signals, draws shapes",
725 "3. Vello GPU => compiles scene => wgpu => pixels",
726 "4. state_hash() => seahash for hashing scene state, skip if unchanged",
727 ];
728 let s11_render_texts: Vec<TextNode> = s11_steps
729 .iter()
730 .enumerate()
731 .map(|(i, s)| body(s, 505.0 + i as f32 * 28.0))
732 .collect();
733
734 project.scene.add(Box::new(s11_h.clone()));
735 project.scene.add(Box::new(s11_code.clone()));
736 for n in [&s11_leftover, &s11_leftover2, &s11_render_h] {
737 project.scene.add(Box::new(n.clone()));
738 }
739 for t in &s11_render_texts {
740 project.scene.add(Box::new(t.clone()));
741 }
742
743 // =====================================================================
744 // S12: EVENT LOOP — Why an infinite loop?
745 // =====================================================================
746 let s12_h = title("Why an Infinite Loop? — The Event Loop", 50.0);
747 let s12_sub = body(
748 "GPU rendering requires a persistent event loop (winit + wgpu).",
749 90.0,
750 );
751 let s12_code = code_block(
752 "event_loop.run(|event, elwt| {
753 match event {
754 Resumed => { // GPU surface ready
755 renderer.resume(&window);
756 }
757 AboutToWait => { // run every frame
758 scene.update(dt); // advance animations
759 let hash = scene.state_hash();
760 if hash != last_hash { // dirty?
761 window.request_redraw();
762 }
763 }
764 RedrawRequested => { // GPU draw call
765 renderer.render(&scene, w, h);
766 }
767 }
768});",
769 130.0,
770 );
771 let s12_why = note(
772 "The window stays open because the GPU surface is tied to",
773 490.0,
774 );
775 let s12_why2 = note(
776 "the OS event loop. Without it, the surface is immediately dropped.",
777 510.0,
778 );
779 let s12_hash = body(
780 "state_hash() skips re-rendering unchanged frames (dirty-checking).",
781 550.0,
782 );
783
784 for n in [&s12_h, &s12_sub, &s12_why, &s12_why2, &s12_hash] {
785 project.scene.add(Box::new(n.clone()));
786 }
787 project.scene.add(Box::new(s12_code.clone()));
788
789 // =====================================================================
790 // S13: HEADLESS EXPORT — GPU without a window
791 // =====================================================================
792 let s13_h = title("Headless Export: GPU -> PNG -> FFmpeg", 50.0);
793 let s13_sub = body(
794 "Same GPU rendering, but without a window — output to files.",
795 90.0,
796 );
797 let s13_code = code_block(
798 "pub struct Exporter {
799 texture: wgpu::Texture, // GPU-side image
800 output_buffer: wgpu::Buffer, // CPU-readable copy
801 renderer: Renderer, // Vello
802}
803fn export_frame(&mut self, scene) -> Vec<u8> {
804 scene.render(&mut self.scene); // 1. build shapes
805 renderer.render_to_texture(..); // 2. GPU draws
806 encoder.copy_texture_to_buffer(..); // 3. GPU -> CPU
807 output_buffer.map_async(Read, ..); // 4. read pixels
808 return pixels; // 5. raw RGBA
809}",
810 130.0,
811 );
812 let s13_cache = note(
813 "Cache: state_hash per frame. If unchanged, skip GPU entirely.",
814 420.0,
815 );
816 let s13_ffmpeg = note(
817 "FFmpeg: raw pixels piped to stdin -> libx264 -> .mkv video.",
818 445.0,
819 );
820 let s13_parallel = body(
821 "PNG saving runs on a background thread. Export is pipelined.",
822 485.0,
823 );
824
825 for n in [&s13_h, &s13_sub, &s13_cache, &s13_ffmpeg, &s13_parallel] {
826 project.scene.add(Box::new(n.clone()));
827 }
828 project.scene.add(Box::new(s13_code.clone()));
829
830 // =====================================================================
831 // S14: ENGINE UTILITIES
832 // =====================================================================
833 let s14_h = title("Under the Hood: Utility Modules", 50.0);
834 let s14_sub = body(
835 "Helper systems that power the engine behind the scenes.",
836 90.0,
837 );
838 let s14_code = code_block(
839 "// src/engine/util/
840font_manager.rs // Lazy-loads system fonts via Typst
841 // Global HashMap cache with lazy_static
842
843image_manager.rs // Loads PNG + SVG (via resvg)
844 // Caches decoded images as Arc<Image>
845
846code_tokenizer.rs // Syntax highlighting via Syntect
847 // Parses code -> colored spans for CodeNode
848
849hash.rs // SeaHash: fast, deterministic fingerprints
850 // Position-aware combination
851 // Powers Rayon parallel state hashing
852
853export.rs // FFmpeg pipe: rawvideo -> libx264
854 // Audio merging with filter_complex
855 // Title sanitization for filenames",
856 130.0,
857 );
858 let s14_lazy = note(
859 "lazy_static + Mutex = global singleton, created once, cached forever.",
860 495.0,
861 );
862 let s14_arc = body(
863 "Arc<Image> lets multiple nodes share one decoded image without copies.",
864 530.0,
865 );
866 let s14_hash = note(
867 "Rayon + SeaHash = Deterministic fingerprints across runs & threads.",
868 565.0,
869 );
870
871 for n in [&s14_h, &s14_sub, &s14_lazy, &s14_arc, &s14_hash] {
872 project.scene.add(Box::new(n.clone()));
873 }
874 project.scene.add(Box::new(s14_code.clone()));
875
876 // =====================================================================
877 // S15: FINALE
878 // =====================================================================
879 let fin = TextNode::default()
880 .with_anchor(Vec2::new(-1.0, -1.0))
881 .with_position(Vec2::new(LEFT, 200.0))
882 .with_text("That's how it works!")
883 .with_font_size(48.0)
884 .with_fill(ACCENT)
885 .with_font(FONT)
886 .with_opacity(0.0);
887 let fin_steps = [
888 "1. struct — data container",
889 "2. impl — methods / builder pattern",
890 "3. trait Node — interface contract",
891 "4. Box<dyn Node> — type-erased heap allocation",
892 "5. Signal<T> — Arc<Mutex> shared reactive state",
893 "6. SignalTween — per-frame lerp interpolation",
894 "7. Timeline — sequential queue + leftover dt",
895 "8. Event Loop — winit + wgpu infinite loop",
896 "9. Exporter — headless GPU -> PNG/FFmpeg",
897 "10. Utilities — font/image cache, syntax highlight",
898 ];
899 let fin_texts: Vec<TextNode> = fin_steps
900 .iter()
901 .enumerate()
902 .map(|(i, s)| body(s, 270.0 + i as f32 * 28.0))
903 .collect();
904 let fin_hint = dim("cargo run --example getting_started", LEFT, 570.0);
905
906 project.scene.add(Box::new(fin.clone()));
907 for t in &fin_texts {
908 project.scene.add(Box::new(t.clone()));
909 }
910 project.scene.add(Box::new(fin_hint.clone()));
911
912 // =====================================================================
913 // ANIMATION TIMELINE
914 // =====================================================================
915 // Helper: hide_all takes a vec of opacity signals and fades them out
916 let hide_dur = ms(200);
917
918 project.scene.video_timeline.add(chain![
919 // ── S1: TITLE ──
920 s1_line
921 .end
922 .to(Vec2::new(500.0, 100.0), ms(500))
923 .ease(easings::cubic_out),
924 sequence![
925 ms(120),
926 show(&s1_title, ms(500)),
927 show(&s1_sub, ms(500)),
928 show(&s1_built, ms(500)),
929 show(&s1_logo, ms(600)),
930 show(&s1_desc, ms(500)),
931 show(&s1_desc2, ms(500)),
932 ],
933 wait(secs(5)),
934 all![
935 hide(&s1_title, hide_dur),
936 hide(&s1_sub, hide_dur),
937 hide(&s1_built, hide_dur),
938 hide(&s1_desc, hide_dur),
939 hide(&s1_desc2, hide_dur),
940 hide(&s1_logo, hide_dur),
941 s1_line.end.to(Vec2::new(LEFT, 100.0), hide_dur)
942 ],
943 wait(ms(150)),
944 // ── S2: FIVE STEPS ──
945 show(&s2_h, ms(500)),
946 wait(ms(400)),
947 sequence![
948 ms(250),
949 show(&s2_texts[0], ms(400)),
950 show(&s2_texts[1], ms(400)),
951 show(&s2_texts[2], ms(400)),
952 show(&s2_texts[3], ms(400)),
953 show(&s2_texts[4], ms(400)),
954 ],
955 wait(secs(8)),
956 all![
957 hide(&s2_h, hide_dur),
958 hide(&s2_texts[0], hide_dur),
959 hide(&s2_texts[1], hide_dur),
960 hide(&s2_texts[2], hide_dur),
961 hide(&s2_texts[3], hide_dur),
962 hide(&s2_texts[4], hide_dur)
963 ],
964 wait(ms(150)),
965 // ── S3: STRUCT ──
966 sequence![
967 ms(120),
968 show(&s3_h, ms(500)),
969 show(&s3_explain, ms(400)),
970 show(&s3_analogy, ms(400))
971 ],
972 wait(ms(500)),
973 show(&s3_code, ms(500)),
974 wait(secs(6)),
975 sequence![
976 ms(300),
977 show(&s3_note, ms(400)),
978 show(&s3_note2, ms(400)),
979 show(&s3_note3, ms(400))
980 ],
981 wait(secs(6)),
982 all![
983 hide(&s3_h, hide_dur),
984 hide(&s3_explain, hide_dur),
985 hide(&s3_analogy, hide_dur),
986 hide(&s3_code, hide_dur),
987 hide(&s3_note, hide_dur),
988 hide(&s3_note2, hide_dur),
989 hide(&s3_note3, hide_dur)
990 ],
991 wait(ms(150)),
992 // ── S4: IMPL / BUILDER ──
993 sequence![
994 ms(120),
995 show(&s4_h, ms(500)),
996 show(&s4_explain, ms(400)),
997 show(&s4_analogy, ms(400))
998 ],
999 wait(ms(500)),
1000 show(&s4_code, ms(500)),
1001 wait(secs(7)),
1002 show(&s4_usage, ms(400)),
1003 show(&s4_usage_code, ms(500)),
1004 wait(secs(2)),
1005 show(&s4_note, ms(400)),
1006 wait(secs(5)),
1007 all![
1008 hide(&s4_h, hide_dur),
1009 hide(&s4_explain, hide_dur),
1010 hide(&s4_analogy, hide_dur),
1011 hide(&s4_code, hide_dur),
1012 hide(&s4_usage, hide_dur),
1013 hide(&s4_usage_code, hide_dur),
1014 hide(&s4_note, hide_dur)
1015 ],
1016 wait(ms(150)),
1017 // ── S5: TRAIT / NODE ──
1018 sequence![
1019 ms(120),
1020 show(&s5_h, ms(500)),
1021 show(&s5_explain, ms(400)),
1022 show(&s5_analogy, ms(400))
1023 ],
1024 wait(ms(500)),
1025 show(&s5_code, ms(500)),
1026 wait(secs(6)),
1027 sequence![
1028 ms(300),
1029 show(&s5_r, ms(400)),
1030 show(&s5_u, ms(400)),
1031 show(&s5_s, ms(400)),
1032 show(&s5_c, ms(400))
1033 ],
1034 wait(secs(2)),
1035 show(&s5_every, ms(400)),
1036 wait(secs(4)),
1037 all![
1038 hide(&s5_h, hide_dur),
1039 hide(&s5_explain, hide_dur),
1040 hide(&s5_analogy, hide_dur),
1041 hide(&s5_code, hide_dur),
1042 hide(&s5_r, hide_dur),
1043 hide(&s5_u, hide_dur),
1044 hide(&s5_s, hide_dur),
1045 hide(&s5_c, hide_dur),
1046 hide(&s5_every, hide_dur)
1047 ],
1048 wait(ms(150)),
1049 // ── S6: NODE GALLERY ──
1050 sequence![ms(120), show(&s6_h, ms(500)), show(&s6_sub, ms(400))],
1051 wait(ms(400)),
1052 sequence![
1053 ms(200),
1054 all![show(&demo_c, ms(400)), show(&lc, ms(400))],
1055 all![show(&demo_r, ms(400)), show(&lr, ms(400))],
1056 all![show(&demo_l, ms(400)), show(&ll, ms(400))],
1057 all![show(&demo_p, ms(400)), show(&lp, ms(400))],
1058 all![show(&demo_t, ms(400)), show(<, ms(400))],
1059 ],
1060 wait(secs(2)),
1061 sequence![
1062 ms(200),
1063 show(&s6_box_h, ms(400)),
1064 show(&s6_box1, ms(400)),
1065 show(&s6_box_code, ms(500))
1066 ],
1067 wait(secs(7)),
1068 all![
1069 hide(&s6_h, hide_dur),
1070 hide(&s6_sub, hide_dur),
1071 hide(&demo_c, hide_dur),
1072 hide(&demo_r, hide_dur),
1073 hide(&demo_l, hide_dur),
1074 hide(&demo_p, hide_dur),
1075 hide(&demo_t, hide_dur),
1076 hide(&lc, hide_dur),
1077 hide(&lr, hide_dur),
1078 hide(&ll, hide_dur),
1079 hide(&lp, hide_dur),
1080 hide(<, hide_dur),
1081 hide(&s6_box_h, hide_dur),
1082 hide(&s6_box1, hide_dur),
1083 hide(&s6_box_code, hide_dur)
1084 ],
1085 wait(ms(150)),
1086 // ── S7: SIGNALS ──
1087 sequence![ms(120), show(&s7_h, ms(500)), show(&s7_sub, ms(400))],
1088 wait(ms(400)),
1089 show(&s7_code, ms(500)),
1090 wait(secs(5)),
1091 sequence![ms(300), show(&s7_arc, ms(400)), show(&s7_mutex, ms(400))],
1092 wait(secs(4)),
1093 show(&s7_why, ms(400)),
1094 show(&s7_diagram_code, ms(500)),
1095 wait(secs(6)),
1096 // Live demo
1097 all![show(&sig_demo, ms(300)), show(&sig_lbl, ms(300))],
1098 chain![
1099 sig_demo.radius.to(80.0, ms(700)).ease(easings::elastic_out),
1100 sig_demo.fill_color.to(TEAL, ms(500)),
1101 sig_demo
1102 .position
1103 .to(Vec2::new(950.0, 350.0), ms(500))
1104 .ease(easings::cubic_out),
1105 wait(ms(300)),
1106 all![
1107 sig_demo.radius.to(50.0, ms(400)),
1108 sig_demo.fill_color.to(RED, ms(400)),
1109 sig_demo.position.to(Vec2::new(900.0, 300.0), ms(400))
1110 ],
1111 ],
1112 wait(secs(3)),
1113 all![
1114 hide(&s7_h, hide_dur),
1115 hide(&s7_sub, hide_dur),
1116 hide(&s7_code, hide_dur),
1117 hide(&s7_arc, hide_dur),
1118 hide(&s7_mutex, hide_dur),
1119 hide(&s7_why, hide_dur),
1120 hide(&s7_diagram_code, hide_dur),
1121 hide(&sig_demo, hide_dur),
1122 hide(&sig_lbl, hide_dur)
1123 ],
1124 wait(ms(150)),
1125 // ── S8: SIGNAL TWEEN ──
1126 sequence![ms(120), show(&s8_h, ms(500)), show(&s8_sub, ms(400))],
1127 wait(ms(400)),
1128 show(&s8_code, ms(500)),
1129 wait(secs(6)),
1130 show(&s8_how, ms(300)),
1131 sequence![
1132 ms(100),
1133 show(&s8_step_texts[0], ms(250)),
1134 show(&s8_step_texts[1], ms(250)),
1135 show(&s8_step_texts[2], ms(250)),
1136 show(&s8_step_texts[3], ms(250)),
1137 show(&s8_step_texts[4], ms(250)),
1138 show(&s8_step_texts[5], ms(250)),
1139 ],
1140 wait(ms(500)),
1141 sequence![ms(100), show(&s8_lazy, ms(300)), show(&s8_lazy2, ms(300))],
1142 wait(ms(500)),
1143 // Progress bar demo
1144 all![
1145 show(&prog_bg, ms(200)),
1146 show(&prog_fill, ms(200)),
1147 show(&plbl0, ms(200)),
1148 show(&plbl1, ms(200)),
1149 show(&tween_ball, ms(200)),
1150 show(&tween_lbl, ms(200))
1151 ],
1152 all![
1153 prog_fill
1154 .size
1155 .to(Vec2::new(400.0, 16.0), secs(2))
1156 .ease(easings::cubic_in_out),
1157 tween_ball
1158 .radius
1159 .to(80.0, secs(2))
1160 .ease(easings::cubic_in_out),
1161 ],
1162 wait(secs(3)),
1163 all![
1164 hide(&s8_h, hide_dur),
1165 hide(&s8_sub, hide_dur),
1166 hide(&s8_code, hide_dur),
1167 hide(&s8_how, hide_dur),
1168 hide(&s8_lazy, hide_dur),
1169 hide(&s8_lazy2, hide_dur),
1170 hide(&prog_bg, hide_dur),
1171 hide(&prog_fill, hide_dur),
1172 hide(&plbl0, hide_dur),
1173 hide(&plbl1, hide_dur),
1174 hide(&tween_ball, hide_dur),
1175 hide(&tween_lbl, hide_dur),
1176 hide(&s8_step_texts[0], hide_dur),
1177 hide(&s8_step_texts[1], hide_dur),
1178 hide(&s8_step_texts[2], hide_dur),
1179 hide(&s8_step_texts[3], hide_dur),
1180 hide(&s8_step_texts[4], hide_dur),
1181 hide(&s8_step_texts[5], hide_dur)
1182 ],
1183 wait(ms(150)),
1184 // ── S9: TWEENABLE + EASINGS ──
1185 show(&s9_h, ms(500)),
1186 show(&s9_code, ms(500)),
1187 wait(secs(4)),
1188 sequence![
1189 ms(60),
1190 show(&s9_easing_h, ms(300)),
1191 show(&s9_easing_desc, ms(300))
1192 ],
1193 sequence![
1194 ms(50),
1195 all![show(&eballs[0], ms(200)), show(&elabels[0], ms(200))],
1196 all![show(&eballs[1], ms(200)), show(&elabels[1], ms(200))],
1197 all![show(&eballs[2], ms(200)), show(&elabels[2], ms(200))],
1198 all![show(&eballs[3], ms(200)), show(&elabels[3], ms(200))],
1199 all![show(&eballs[4], ms(200)), show(&elabels[4], ms(200))],
1200 ],
1201 wait(ms(300)),
1202 // Race!
1203 all![
1204 eballs[0]
1205 .position
1206 .to(Vec2::new(1050.0, 390.0), secs(2))
1207 .ease(easings::linear),
1208 eballs[1]
1209 .position
1210 .to(Vec2::new(1050.0, 445.0), secs(2))
1211 .ease(easings::cubic_in_out),
1212 eballs[2]
1213 .position
1214 .to(Vec2::new(1050.0, 500.0), secs(2))
1215 .ease(easings::elastic_out),
1216 eballs[3]
1217 .position
1218 .to(Vec2::new(1050.0, 555.0), secs(2))
1219 .ease(easings::bounce_out),
1220 eballs[4]
1221 .position
1222 .to(Vec2::new(1050.0, 610.0), secs(2))
1223 .ease(easings::back_out),
1224 ],
1225 wait(ms(500)),
1226 all![
1227 eballs[0]
1228 .position
1229 .to(Vec2::new(250.0, 390.0), secs(2))
1230 .ease(easings::linear),
1231 eballs[1]
1232 .position
1233 .to(Vec2::new(250.0, 445.0), secs(2))
1234 .ease(easings::cubic_in_out),
1235 eballs[2]
1236 .position
1237 .to(Vec2::new(250.0, 500.0), secs(2))
1238 .ease(easings::elastic_out),
1239 eballs[3]
1240 .position
1241 .to(Vec2::new(250.0, 555.0), secs(2))
1242 .ease(easings::bounce_out),
1243 eballs[4]
1244 .position
1245 .to(Vec2::new(250.0, 610.0), secs(2))
1246 .ease(easings::back_out),
1247 ],
1248 wait(ms(500)),
1249 all![
1250 hide(&s9_h, hide_dur),
1251 hide(&s9_code, hide_dur),
1252 hide(&s9_easing_h, hide_dur),
1253 hide(&s9_easing_desc, hide_dur),
1254 hide(&eballs[0], hide_dur),
1255 hide(&eballs[1], hide_dur),
1256 hide(&eballs[2], hide_dur),
1257 hide(&eballs[3], hide_dur),
1258 hide(&eballs[4], hide_dur),
1259 hide(&elabels[0], hide_dur),
1260 hide(&elabels[1], hide_dur),
1261 hide(&elabels[2], hide_dur),
1262 hide(&elabels[3], hide_dur),
1263 hide(&elabels[4], hide_dur)
1264 ],
1265 wait(ms(150)),
1266 // ── S10: FLOW CONTROLS ──
1267 sequence![ms(120), show(&s10_h, ms(500)), show(&s10_sub, ms(400))],
1268 wait(ms(400)),
1269 // chain demo
1270 show(&s10_chain_h, ms(400)),
1271 all![
1272 show(&chain_d[0], ms(300)),
1273 show(&chain_d[1], ms(300)),
1274 show(&chain_d[2], ms(300))
1275 ],
1276 wait(ms(300)),
1277 chain![
1278 chain_d[0]
1279 .position
1280 .to(Vec2::new(700.0, 200.0), ms(500))
1281 .ease(easings::cubic_out),
1282 chain_d[1]
1283 .position
1284 .to(Vec2::new(800.0, 200.0), ms(500))
1285 .ease(easings::cubic_out),
1286 chain_d[2]
1287 .position
1288 .to(Vec2::new(900.0, 200.0), ms(500))
1289 .ease(easings::cubic_out),
1290 ],
1291 wait(secs(1)),
1292 // all demo
1293 show(&s10_all_h, ms(400)),
1294 all![
1295 show(&all_d[0], ms(300)),
1296 show(&all_d[1], ms(300)),
1297 show(&all_d[2], ms(300))
1298 ],
1299 wait(ms(300)),
1300 all![
1301 all_d[0]
1302 .position
1303 .to(Vec2::new(700.0, 330.0), ms(500))
1304 .ease(easings::cubic_out),
1305 all_d[1]
1306 .position
1307 .to(Vec2::new(800.0, 330.0), ms(500))
1308 .ease(easings::cubic_out),
1309 all_d[2]
1310 .position
1311 .to(Vec2::new(900.0, 330.0), ms(500))
1312 .ease(easings::cubic_out),
1313 ],
1314 wait(secs(1)),
1315 // sequence demo
1316 show(&s10_seq_h, ms(400)),
1317 all![
1318 show(&seq_d[0], ms(300)),
1319 show(&seq_d[1], ms(300)),
1320 show(&seq_d[2], ms(300))
1321 ],
1322 wait(ms(300)),
1323 sequence![
1324 ms(250),
1325 seq_d[0]
1326 .position
1327 .to(Vec2::new(700.0, 460.0), ms(500))
1328 .ease(easings::cubic_out),
1329 seq_d[1]
1330 .position
1331 .to(Vec2::new(800.0, 460.0), ms(500))
1332 .ease(easings::cubic_out),
1333 seq_d[2]
1334 .position
1335 .to(Vec2::new(900.0, 460.0), ms(500))
1336 .ease(easings::cubic_out),
1337 ],
1338 wait(secs(1)),
1339 show(&s10_code, ms(500)),
1340 wait(secs(8)),
1341 all![
1342 hide(&s10_h, hide_dur),
1343 hide(&s10_sub, hide_dur),
1344 hide(&s10_chain_h, hide_dur),
1345 hide(&s10_all_h, hide_dur),
1346 hide(&s10_seq_h, hide_dur),
1347 hide(&s10_code, hide_dur),
1348 hide(&chain_d[0], hide_dur),
1349 hide(&chain_d[1], hide_dur),
1350 hide(&chain_d[2], hide_dur),
1351 hide(&all_d[0], hide_dur),
1352 hide(&all_d[1], hide_dur),
1353 hide(&all_d[2], hide_dur),
1354 hide(&seq_d[0], hide_dur),
1355 hide(&seq_d[1], hide_dur),
1356 hide(&seq_d[2], hide_dur)
1357 ],
1358 wait(ms(150)),
1359 // ── S11: TIMELINE + RENDERING ──
1360 show(&s11_h, ms(500)),
1361 wait(ms(400)),
1362 show(&s11_code, ms(500)),
1363 wait(secs(7)),
1364 sequence![
1365 ms(200),
1366 show(&s11_leftover, ms(400)),
1367 show(&s11_leftover2, ms(400))
1368 ],
1369 wait(secs(4)),
1370 show(&s11_render_h, ms(400)),
1371 sequence![
1372 ms(200),
1373 show(&s11_render_texts[0], ms(350)),
1374 show(&s11_render_texts[1], ms(350)),
1375 show(&s11_render_texts[2], ms(350)),
1376 show(&s11_render_texts[3], ms(350)),
1377 ],
1378 wait(secs(7)),
1379 all![
1380 hide(&s11_h, hide_dur),
1381 hide(&s11_code, hide_dur),
1382 hide(&s11_leftover, hide_dur),
1383 hide(&s11_leftover2, hide_dur),
1384 hide(&s11_render_h, hide_dur),
1385 hide(&s11_render_texts[0], hide_dur),
1386 hide(&s11_render_texts[1], hide_dur),
1387 hide(&s11_render_texts[2], hide_dur),
1388 hide(&s11_render_texts[3], hide_dur)
1389 ],
1390 wait(ms(300)),
1391 // ── S12: EVENT LOOP ──
1392 sequence![ms(120), show(&s12_h, ms(500)), show(&s12_sub, ms(400))],
1393 wait(ms(500)),
1394 show(&s12_code, ms(500)),
1395 wait(secs(8)),
1396 sequence![
1397 ms(200),
1398 show(&s12_why, ms(400)),
1399 show(&s12_why2, ms(400)),
1400 show(&s12_hash, ms(400))
1401 ],
1402 wait(secs(5)),
1403 all![
1404 hide(&s12_h, hide_dur),
1405 hide(&s12_sub, hide_dur),
1406 hide(&s12_code, hide_dur),
1407 hide(&s12_why, hide_dur),
1408 hide(&s12_why2, hide_dur),
1409 hide(&s12_hash, hide_dur)
1410 ],
1411 wait(ms(150)),
1412 // ── S13: HEADLESS EXPORT ──
1413 sequence![ms(120), show(&s13_h, ms(500)), show(&s13_sub, ms(400))],
1414 wait(ms(500)),
1415 show(&s13_code, ms(500)),
1416 wait(secs(8)),
1417 sequence![
1418 ms(200),
1419 show(&s13_cache, ms(400)),
1420 show(&s13_ffmpeg, ms(400)),
1421 show(&s13_parallel, ms(400))
1422 ],
1423 wait(secs(5)),
1424 all![
1425 hide(&s13_h, hide_dur),
1426 hide(&s13_sub, hide_dur),
1427 hide(&s13_code, hide_dur),
1428 hide(&s13_cache, hide_dur),
1429 hide(&s13_ffmpeg, hide_dur),
1430 hide(&s13_parallel, hide_dur)
1431 ],
1432 wait(ms(150)),
1433 // ── S14: UTILITIES ──
1434 sequence![ms(120), show(&s14_h, ms(500)), show(&s14_sub, ms(400))],
1435 wait(ms(500)),
1436 show(&s14_code, ms(500)),
1437 wait(secs(8)),
1438 sequence![ms(200), show(&s14_lazy, ms(400)), show(&s14_arc, ms(400))],
1439 wait(secs(5)),
1440 all![
1441 hide(&s14_h, hide_dur),
1442 hide(&s14_sub, hide_dur),
1443 hide(&s14_code, hide_dur),
1444 hide(&s14_lazy, hide_dur),
1445 hide(&s14_arc, hide_dur)
1446 ],
1447 wait(ms(300)),
1448 // ── S15: FINALE ──
1449 show(&fin, ms(700)),
1450 wait(ms(500)),
1451 sequence![
1452 ms(150),
1453 show(&fin_texts[0], ms(350)),
1454 show(&fin_texts[1], ms(350)),
1455 show(&fin_texts[2], ms(350)),
1456 show(&fin_texts[3], ms(350)),
1457 show(&fin_texts[4], ms(350)),
1458 show(&fin_texts[5], ms(350)),
1459 show(&fin_texts[6], ms(350)),
1460 show(&fin_texts[7], ms(350)),
1461 show(&fin_texts[8], ms(350)),
1462 show(&fin_texts[9], ms(350)),
1463 ],
1464 wait(secs(2)),
1465 show(&fin_hint, ms(400)),
1466 wait(secs(6)),
1467 ]);
1468
1469 #[cfg(feature = "audio")]
1470 project
1471 .scene
1472 .audio_timeline
1473 .add(play!(AudioNode::new("background.mp3").with_volume(0.3)));
1474
1475 project.show().expect("Failed to render");
1476}More examples
4fn main() {
5 let mut project = Project::default()
6 .with_title("Group Animation")
7 .close_on_finish();
8
9 // Create some child nodes
10 let rect = Rect::default()
11 .with_position(Vec2::new(0.0, 0.0))
12 .with_size(Vec2::new(100.0, 100.0))
13 .with_fill(Color::rgba8(100, 100, 255, 255))
14 .with_radius(10.0);
15
16 let circle1 = Circle::default()
17 .with_position(Vec2::new(-40.0, -40.0))
18 .with_radius(20.0)
19 .with_fill(Color::rgba8(255, 100, 100, 255));
20
21 let circle2 = Circle::default()
22 .with_position(Vec2::new(40.0, 40.0))
23 .with_radius(20.0)
24 .with_fill(Color::rgba8(100, 255, 100, 255));
25
26 // Create a GroupNode holding them
27 let group = GroupNode::default()
28 .with_nodes(vec![
29 Box::new(rect.clone()),
30 Box::new(circle1.clone()),
31 Box::new(circle2.clone()),
32 ])
33 .with_position(Vec2::new(400.0, 300.0));
34
35 // We must add the group to the scene's nodes to render it
36 project.scene.add(Box::new(group.clone()));
37
38 // Define animations and add them to the timeline
39 project.scene.video_timeline.add(chain![
40 // 1. Move the whole group
41 group
42 .position
43 .to(Vec2::new(200.0, 150.0), Duration::from_secs(2)),
44 // 2. Rotate the group
45 group
46 .rotation
47 .to(std::f32::consts::PI, Duration::from_secs(2)),
48 // 3. Complex transform (move + scale)
49 all![
50 group
51 .position
52 .to(Vec2::new(400.0, 450.0), Duration::from_secs(2)),
53 group.scale.to(Vec2::splat(2.0), Duration::from_secs(2)),
54 group.opacity.to(0.3, Duration::from_secs(2)),
55 ],
56 // 4. Reset (at the center)
57 all![
58 group
59 .position
60 .to(Vec2::new(400.0, 300.0), Duration::from_secs(1)),
61 group.scale.to(Vec2::ONE, Duration::from_secs(1)),
62 group.rotation.to(0.0, Duration::from_secs(1)),
63 group.opacity.to(1.0, Duration::from_secs(1)),
64 ],
65 ]);
66
67 project.show().expect("Failed to render");
68}4fn main() {
5 let mut project = Project::default()
6 .with_title("Signals")
7 .with_dimensions(800, 600)
8 .close_on_finish();
9
10 // 1. Create independent signals for our "Coordinate System"
11 // These are NOT tied to any node yet.
12 let x_var = Signal::new(0.0f32);
13 let y_var = Signal::new(0.0f32);
14
15 // 2. Create the Axis lines (Fixed)
16 let x_axis = Line::default()
17 .with_start(Vec2::new(-200.0, 0.0))
18 .with_end(Vec2::new(200.0, 0.0))
19 .with_stroke(Color::rgba8(255, 255, 255, 100), 2.0);
20
21 let y_axis = Line::default()
22 .with_start(Vec2::new(0.0, -200.0))
23 .with_end(Vec2::new(0.0, 200.0))
24 .with_stroke(Color::rgba8(255, 255, 255, 100), 2.0);
25
26 // Group the axes at the center
27 let axes = GroupNode::default()
28 .with_nodes(vec![Box::new(x_axis), Box::new(y_axis)])
29 .with_position(Vec2::new(400.0, 300.0));
30
31 // 3. Create a representation of the point (P)
32 let point = Circle::default()
33 .with_radius(8.0)
34 .with_fill(Color::rgb8(0xe1, 0x32, 0x38)); // Red
35
36 // 4. Create text labels that show the values
37 let x_label = TextNode::default()
38 .with_text("X: 0")
39 .with_font_size(24.0)
40 .with_fill(Color::WHITE);
41
42 let y_label = TextNode::default()
43 .with_text("Y: 0")
44 .with_font_size(24.0)
45 .with_fill(Color::WHITE);
46
47 // 5. Use .bind() to derive node properties from our variables
48 // This makes node properties react to x_var and y_var.
49
50 // Circle position follows both
51 let y_clone = y_var.clone();
52 let circle_pos_link = point.position.bind(x_var.clone(), move |x| {
53 Vec2::new(x + 400.0, y_clone.get() + 300.0)
54 });
55
56 // X Label follows X but stays at bottom
57 let x_label_pos_link = x_label
58 .position
59 .bind(x_var.clone(), |x| Vec2::new(x + 400.0, 550.0));
60
61 // Y Label stays at left but follows Y
62 let y_label_pos_link = y_label
63 .position
64 .bind(y_var.clone(), |y| Vec2::new(75.0, y + 300.0));
65
66 // Dynamic text update for labels
67 let x_text_link = x_label.text.bind(x_var.clone(), |x| format!("X: {:.1}", x));
68 let y_text_link = y_label.text.bind(y_var.clone(), |y| format!("Y: {:.1}", y));
69
70 // Add everything to the scene
71 project.scene.add(Box::new(axes));
72 project.scene.add(Box::new(point));
73 project.scene.add(Box::new(x_label));
74 project.scene.add(Box::new(y_label));
75
76 // Add the links as "invisible" nodes that just perform the sync
77 project.scene.add(Box::new(circle_pos_link));
78 project.scene.add(Box::new(x_label_pos_link));
79 project.scene.add(Box::new(y_label_pos_link));
80 project.scene.add(Box::new(x_text_link));
81 project.scene.add(Box::new(y_text_link));
82
83 // 6. Animate our independent variables!
84 project.scene.video_timeline.add(chain![
85 // Move X
86 x_var
87 .to(200.0, Duration::from_secs(1))
88 .ease(easings::cubic_out),
89 // Wait
90 wait(Duration::from_millis(500)),
91 // Move Y
92 y_var
93 .to(-150.0, Duration::from_secs(1))
94 .ease(easings::back_out),
95 // Move both together
96 all![
97 x_var
98 .to(-250.0, Duration::from_secs(2))
99 .ease(easings::expo_in_out),
100 y_var
101 .to(100.0, Duration::from_secs(2))
102 .ease(easings::sine_in_out),
103 ],
104 // Reset
105 all![
106 x_var.to(0.0, Duration::from_secs(1)),
107 y_var.to(0.0, Duration::from_secs(1)),
108 ],
109 // Final wait to see the result
110 wait(Duration::from_secs(1)),
111 ]);
112
113 project.show().expect("Failed to render");
114}4fn main() {
5 // 1. Initialize Project with full API coverage
6 let mut project = Project::default()
7 .with_fps(120)
8 .with_gpu(true)
9 .with_cache(true)
10 .with_ffmpeg(true)
11 .with_output_path("output")
12 .with_title("Advanced Flow")
13 .close_on_finish();
14
15 // 2. Setup Nodes
16 let mut path = BezPath::new();
17 path.move_to((100.0, 300.0));
18 path.curve_to((250.0, 100.0), (550.0, 500.0), (700.0, 300.0));
19 let path_node = PathNode::default()
20 .with_path(path)
21 .with_stroke(Color::rgb8(0x44, 0x44, 0x44), 2.0);
22 let follower = Circle::default()
23 .with_position(Vec2::new(100.0, 300.0))
24 .with_radius(20.0)
25 .with_fill(Color::rgb8(0xe1, 0x32, 0x38)); // Red
26
27 // Showcase: Rect and Line
28 let background_rect = Rect::default()
29 .with_position(Vec2::new(400.0, 300.0))
30 .with_size(Vec2::new(760.0, 560.0))
31 .with_fill(Color::rgba8(0x33, 0x33, 0x33, 150))
32 .with_radius(20.0);
33
34 let divider_line = Line::default()
35 .with_start(Vec2::new(0.0, 300.0))
36 .with_end(Vec2::new(0.0, 300.0))
37 .with_stroke(Color::rgb8(0x44, 0x44, 0x44), 1.0);
38 let title_text = TextNode::default()
39 .with_position(Vec2::new(50.0, 50.0))
40 .with_anchor(Vec2::new(-1.0, -1.0))
41 .with_text("Motion Canvas in Rust")
42 .with_font_size(40.0)
43 .with_fill(Color::rgb8(0x68, 0xab, 0xdf)) // Blue
44 .with_font("JetBrains Mono");
45
46 let code_block = CodeNode::default()
47 .with_anchor(Vec2::new(-1.0, -1.0))
48 .with_position(Vec2::new(50.0, 415.0))
49 .with_language("rust")
50 .with_opacity(0.0);
51
52 let math_eq = MathNode::default()
53 .with_position(Vec2::new(150.0, 150.0))
54 .with_equation("f(x) = sin(x)")
55 .with_font_size(30.0)
56 .with_fill(Color::rgb8(0xe6, 0xa7, 0x00)); // Yellow
57
58 let logo = ImageNode::default()
59 .with_position(Vec2::new(650.0, 150.0))
60 .with_path("./examples/images/motion-canvas-logo.png")
61 .with_size(Vec2::new(150.0, 150.0));
62
63 project.scene.video_timeline.add(all![
64 // Show code
65 chain![
66 code_block.opacity.to(1.0, Duration::from_secs(1)),
67 code_block.append("fn main() {\n", Duration::from_secs(1)),
68 code_block.append(
69 " let mut engine = MotionCanvas::new();\n",
70 Duration::from_secs(1)
71 ),
72 code_block.append(" engine.render();\n", Duration::from_secs(1)),
73 code_block.append("}", Duration::from_secs(1)),
74 // Staggered appearance of nodes
75 sequence![
76 Duration::from_millis(200),
77 divider_line
78 .end
79 .to(Vec2::new(800.0, 300.0), Duration::from_secs(1))
80 .ease(easings::cubic_out),
81 follower
82 .radius
83 .to(30.0, Duration::from_millis(500))
84 .ease(easings::elastic_out),
85 ],
86 // The path follow combined with a "race" logic
87 any![
88 follower
89 .position
90 .follow(&path_node, Duration::from_secs(3))
91 .ease(easings::cubic_in_out),
92 // Race: if this 'wait' finishes first, the follow is done
93 wait(Duration::from_secs(4)),
94 ],
95 // Final flourishes using different easings
96 all![
97 follower
98 .radius
99 .to(10.0, Duration::from_secs(1))
100 .ease(easings::quad_out),
101 divider_line
102 .start
103 .to(Vec2::new(400.0, 300.0), Duration::from_secs(1))
104 .ease(easings::cubic_in),
105 ]
106 ]
107 ]);
108
109 // 4. Build Scene
110 project.scene.add(Box::new(background_rect.clone()));
111 project.scene.add(Box::new(divider_line.clone()));
112 project.scene.add(Box::new(path_node.clone()));
113 project.scene.add(Box::new(follower.clone()));
114 project.scene.add(Box::new(title_text.clone()));
115 project.scene.add(Box::new(code_block.clone()));
116 project.scene.add(Box::new(math_eq.clone()));
117 project.scene.add(Box::new(logo.clone()));
118
119 // 5. Run (Choose show() for interactive or export() for PNGs)
120 project.show().expect("Failed to render");
121 // project.export().expect("Failed to export");
122}Sourcepub fn rgb(r: f64, g: f64, b: f64) -> Color
pub fn rgb(r: f64, g: f64, b: f64) -> Color
Create a color from three floating point values, each in the range 0.0 to 1.0.
The interpretation is the same as rgb8, and no greater precision is (currently) assumed.
Sourcepub fn rgba(r: f64, g: f64, b: f64, a: f64) -> Color
pub fn rgba(r: f64, g: f64, b: f64, a: f64) -> Color
Create a color from four floating point values, each in the range 0.0 to 1.0.
The interpretation is the same as rgba32, and no greater precision is (currently) assumed.
Sourcepub fn hlc(h: f64, l: f64, c: f64) -> Color
pub fn hlc(h: f64, l: f64, c: f64) -> Color
Create a color from a CIEL*a*b* polar (also known as CIE HCL) specification.
The h parameter is an angle in degrees, with 0 roughly magenta, 90
roughly yellow, 180 roughly cyan, and 270 roughly blue. The l
parameter is perceptual luminance, with 0 black and 100 white.
The c parameter is a chrominance concentration, with 0 grayscale
and a nominal maximum of 127 (in the future, higher values might
be useful, for high gamut contexts).
Currently this is just converted into sRGB, but in the future as we support high-gamut colorspaces, it can be used to specify more colors or existing colors with a higher accuracy.
Currently out-of-gamut values are clipped to the nearest sRGB color, which is perhaps not ideal (the clipping might change the hue). See https://github.com/d3/d3-color/issues/33 for discussion.
Sourcepub fn hlca(h: f64, l: f64, c: f64, a: f64) -> Color
pub fn hlca(h: f64, l: f64, c: f64, a: f64) -> Color
Create a color from a CIEL*a*b* polar specification and alpha.
The a value represents alpha in the range 0.0 to 1.0.
Sourcepub fn parse(s: &str) -> Option<Color>
pub fn parse(s: &str) -> Option<Color>
Parses a color from a string.
Currently accepts CSS style hexadecimal colors of the forms #RGB, #RGBA, #RRGGBB, #RRGGBBAA or the name of an SVG color such as “aliceblue”.
Sourcepub fn with_alpha_factor(self, alpha: f32) -> Color
pub fn with_alpha_factor(self, alpha: f32) -> Color
Returns the color with the alpha component multiplied by the specified factor.
Sourcepub fn to_premul_u32(self) -> u32
pub fn to_premul_u32(self) -> u32
Returns the color as a packed premultiplied value.
Source§impl Color
Named SVG colors.
impl Color
Named SVG colors.
Sourcepub const ALICE_BLUE: Color
pub const ALICE_BLUE: Color
Alice blue (240, 248, 255, 255)
Sourcepub const ANTIQUE_WHITE: Color
pub const ANTIQUE_WHITE: Color
Antique white (250, 235, 215, 255)
Sourcepub const AQUAMARINE: Color
pub const AQUAMARINE: Color
Aquamarine (127, 255, 212, 255)
Sourcepub const BLANCHED_ALMOND: Color
pub const BLANCHED_ALMOND: Color
Blanched almond (255, 235, 205, 255)
Sourcepub const BLUE_VIOLET: Color
pub const BLUE_VIOLET: Color
Blue violet (138, 43, 226, 255)
Sourcepub const CADET_BLUE: Color
pub const CADET_BLUE: Color
Cadet blue (95, 158, 160, 255)
Sourcepub const CHARTREUSE: Color
pub const CHARTREUSE: Color
Chartreuse (127, 255, 0, 255)
Sourcepub const CORNFLOWER_BLUE: Color
pub const CORNFLOWER_BLUE: Color
Cornflower blue (100, 149, 237, 255)
Sourcepub const DARK_GOLDENROD: Color
pub const DARK_GOLDENROD: Color
Dark goldenrod (184, 134, 11, 255)
Sourcepub const DARK_GREEN: Color
pub const DARK_GREEN: Color
Dark green (0, 100, 0, 255)
Sourcepub const DARK_KHAKI: Color
pub const DARK_KHAKI: Color
Dark khaki (189, 183, 107, 255)
Sourcepub const DARK_MAGENTA: Color
pub const DARK_MAGENTA: Color
Dark magenta (139, 0, 139, 255)
Sourcepub const DARK_OLIVE_GREEN: Color
pub const DARK_OLIVE_GREEN: Color
Dark olive green (85, 107, 47, 255)
Sourcepub const DARK_ORANGE: Color
pub const DARK_ORANGE: Color
Dark orange (255, 140, 0, 255)
Sourcepub const DARK_ORCHID: Color
pub const DARK_ORCHID: Color
Dark orchid (153, 50, 204, 255)
Sourcepub const DARK_SALMON: Color
pub const DARK_SALMON: Color
Dark salmon (233, 150, 122, 255)
Sourcepub const DARK_SEA_GREEN: Color
pub const DARK_SEA_GREEN: Color
Dark sea green (143, 188, 143, 255)
Sourcepub const DARK_SLATE_BLUE: Color
pub const DARK_SLATE_BLUE: Color
Dark slate blue (72, 61, 139, 255)
Sourcepub const DARK_SLATE_GRAY: Color
pub const DARK_SLATE_GRAY: Color
Dark slate gray (47, 79, 79, 255)
Sourcepub const DARK_TURQUOISE: Color
pub const DARK_TURQUOISE: Color
Dark turquoise (0, 206, 209, 255)
Sourcepub const DARK_VIOLET: Color
pub const DARK_VIOLET: Color
Dark violet (148, 0, 211, 255)
Sourcepub const DEEP_SKY_BLUE: Color
pub const DEEP_SKY_BLUE: Color
Deep sky blue (0, 191, 255, 255)
Sourcepub const DODGER_BLUE: Color
pub const DODGER_BLUE: Color
Dodger blue (30, 144, 255, 255)
Sourcepub const FLORAL_WHITE: Color
pub const FLORAL_WHITE: Color
Floral white (255, 250, 240, 255)
Sourcepub const FOREST_GREEN: Color
pub const FOREST_GREEN: Color
Forest green (34, 139, 34, 255)
Sourcepub const GHOST_WHITE: Color
pub const GHOST_WHITE: Color
Ghost white (248, 248, 255, 255)
Sourcepub const GREEN_YELLOW: Color
pub const GREEN_YELLOW: Color
Green yellow (173, 255, 47, 255)
Sourcepub const INDIAN_RED: Color
pub const INDIAN_RED: Color
Indian red (205, 92, 92, 255)
Sourcepub const LAVENDER_BLUSH: Color
pub const LAVENDER_BLUSH: Color
Lavender blush (255, 240, 245, 255)
Sourcepub const LAWN_GREEN: Color
pub const LAWN_GREEN: Color
Lawn green (124, 252, 0, 255)
Sourcepub const LEMON_CHIFFON: Color
pub const LEMON_CHIFFON: Color
Lemon chiffon (255, 250, 205, 255)
Sourcepub const LIGHT_BLUE: Color
pub const LIGHT_BLUE: Color
Light blue (173, 216, 230, 255)
Sourcepub const LIGHT_CORAL: Color
pub const LIGHT_CORAL: Color
Light coral (240, 128, 128, 255)
Sourcepub const LIGHT_CYAN: Color
pub const LIGHT_CYAN: Color
Light cyan (224, 255, 255, 255)
Sourcepub const LIGHT_GOLDENROD_YELLOW: Color
pub const LIGHT_GOLDENROD_YELLOW: Color
Light goldenrod yellow (250, 250, 210, 255)
Sourcepub const LIGHT_GRAY: Color
pub const LIGHT_GRAY: Color
Light gray (211, 211, 211, 255)
Sourcepub const LIGHT_GREEN: Color
pub const LIGHT_GREEN: Color
Light green (144, 238, 144, 255)
Sourcepub const LIGHT_PINK: Color
pub const LIGHT_PINK: Color
Light pink (255, 182, 193, 255)
Sourcepub const LIGHT_SALMON: Color
pub const LIGHT_SALMON: Color
Light salmon (255, 160, 122, 255)
Sourcepub const LIGHT_SEA_GREEN: Color
pub const LIGHT_SEA_GREEN: Color
Light sea green (32, 178, 170, 255)
Sourcepub const LIGHT_SKY_BLUE: Color
pub const LIGHT_SKY_BLUE: Color
Light sky blue (135, 206, 250, 255)
Sourcepub const LIGHT_SLATE_GRAY: Color
pub const LIGHT_SLATE_GRAY: Color
Light slate gray (119, 136, 153, 255)
Sourcepub const LIGHT_STEEL_BLUE: Color
pub const LIGHT_STEEL_BLUE: Color
Light steel blue (176, 196, 222, 255)
Sourcepub const LIGHT_YELLOW: Color
pub const LIGHT_YELLOW: Color
Light yellow (255, 255, 224, 255)
Sourcepub const LIME_GREEN: Color
pub const LIME_GREEN: Color
Lime green (50, 205, 50, 255)
Sourcepub const MEDIUM_AQUAMARINE: Color
pub const MEDIUM_AQUAMARINE: Color
Medium aquamarine (102, 205, 170, 255)
Sourcepub const MEDIUM_BLUE: Color
pub const MEDIUM_BLUE: Color
Medium blue (0, 0, 205, 255)
Sourcepub const MEDIUM_ORCHID: Color
pub const MEDIUM_ORCHID: Color
Medium orchid (186, 85, 211, 255)
Sourcepub const MEDIUM_PURPLE: Color
pub const MEDIUM_PURPLE: Color
Medium purple (147, 112, 219, 255)
Sourcepub const MEDIUM_SEA_GREEN: Color
pub const MEDIUM_SEA_GREEN: Color
Medium sea green (60, 179, 113, 255)
Sourcepub const MEDIUM_SLATE_BLUE: Color
pub const MEDIUM_SLATE_BLUE: Color
Medium slate blue (123, 104, 238, 255)
Sourcepub const MEDIUM_SPRING_GREEN: Color
pub const MEDIUM_SPRING_GREEN: Color
Medium spring green (0, 250, 154, 255)
Sourcepub const MEDIUM_TURQUOISE: Color
pub const MEDIUM_TURQUOISE: Color
Medium turquoise (72, 209, 204, 255)
Sourcepub const MEDIUM_VIOLET_RED: Color
pub const MEDIUM_VIOLET_RED: Color
Medium violet red (199, 21, 133, 255)
Sourcepub const MIDNIGHT_BLUE: Color
pub const MIDNIGHT_BLUE: Color
Midnight blue (25, 25, 112, 255)
Sourcepub const MINT_CREAM: Color
pub const MINT_CREAM: Color
Mint cream (245, 255, 250, 255)
Sourcepub const MISTY_ROSE: Color
pub const MISTY_ROSE: Color
Misty rose (255, 228, 225, 255)
Sourcepub const NAVAJO_WHITE: Color
pub const NAVAJO_WHITE: Color
Navajo white (255, 222, 173, 255)
Sourcepub const OLIVE_DRAB: Color
pub const OLIVE_DRAB: Color
Olive drab (107, 142, 35, 255)
Sourcepub const ORANGE_RED: Color
pub const ORANGE_RED: Color
Orange red (255, 69, 0, 255)
Sourcepub const PALE_GOLDENROD: Color
pub const PALE_GOLDENROD: Color
Pale goldenrod (238, 232, 170, 255)
Sourcepub const PALE_GREEN: Color
pub const PALE_GREEN: Color
Pale green (152, 251, 152, 255)
Sourcepub const PALE_TURQUOISE: Color
pub const PALE_TURQUOISE: Color
Pale turquoise (175, 238, 238, 255)
Sourcepub const PALE_VIOLET_RED: Color
pub const PALE_VIOLET_RED: Color
Pale violet red (219, 112, 147, 255)
Sourcepub const PAPAYA_WHIP: Color
pub const PAPAYA_WHIP: Color
Papaya whip (255, 239, 213, 255)
Sourcepub const PEACH_PUFF: Color
pub const PEACH_PUFF: Color
Peach puff (255, 218, 185, 255)
Sourcepub const POWDER_BLUE: Color
pub const POWDER_BLUE: Color
Powder blue (176, 224, 230, 255)
Sourcepub const REBECCA_PURPLE: Color
pub const REBECCA_PURPLE: Color
Rebecca purple (102, 51, 153, 255)
Sourcepub const ROSY_BROWN: Color
pub const ROSY_BROWN: Color
Rosy brown (188, 143, 143, 255)
Sourcepub const ROYAL_BLUE: Color
pub const ROYAL_BLUE: Color
Royal blue (65, 105, 225, 255)
Sourcepub const SADDLE_BROWN: Color
pub const SADDLE_BROWN: Color
Saddle brown (139, 69, 19, 255)
Sourcepub const SANDY_BROWN: Color
pub const SANDY_BROWN: Color
Sandy brown (244, 164, 96, 255)
Sourcepub const SLATE_BLUE: Color
pub const SLATE_BLUE: Color
Slate blue (106, 90, 205, 255)
Sourcepub const SLATE_GRAY: Color
pub const SLATE_GRAY: Color
Slate gray (112, 128, 144, 255)
Sourcepub const SPRING_GREEN: Color
pub const SPRING_GREEN: Color
Spring green (0, 255, 127, 255)
Sourcepub const STEEL_BLUE: Color
pub const STEEL_BLUE: Color
Steel blue (70, 130, 180, 255)
Sourcepub const TRANSPARENT: Color
pub const TRANSPARENT: Color
Transparent (0, 0, 0, 0)
Sourcepub const WHITE_SMOKE: Color
pub const WHITE_SMOKE: Color
White smoke (245, 245, 245, 255)
Sourcepub const YELLOW_GREEN: Color
pub const YELLOW_GREEN: Color
Yellow green (154, 205, 50, 255)
Trait Implementations§
Source§impl Ord for Color
impl Ord for Color
Source§impl PartialOrd for Color
impl PartialOrd for Color
Source§impl Tweenable for Color
impl Tweenable for Color
fn interpolate(a: &Self, b: &Self, t: f32) -> Self
fn state_hash(&self) -> u64
impl Copy for Color
impl Eq for Color
impl StructuralPartialEq for Color
Auto Trait Implementations§
impl Freeze for Color
impl RefUnwindSafe for Color
impl Send for Color
impl Sync for Color
impl Unpin for Color
impl UnsafeUnpin for Color
impl UnwindSafe for Color
Blanket Implementations§
Source§impl<S, D, Swp, Dwp, T> AdaptInto<D, Swp, Dwp, T> for Swhere
T: Real + Zero + Arithmetics + Clone,
Swp: WhitePoint<T>,
Dwp: WhitePoint<T>,
D: AdaptFrom<S, Swp, Dwp, T>,
impl<S, D, Swp, Dwp, T> AdaptInto<D, Swp, Dwp, T> for Swhere
T: Real + Zero + Arithmetics + Clone,
Swp: WhitePoint<T>,
Dwp: WhitePoint<T>,
D: AdaptFrom<S, Swp, Dwp, T>,
Source§fn adapt_into_using<M>(self, method: M) -> Dwhere
M: TransformMatrix<T>,
fn adapt_into_using<M>(self, method: M) -> Dwhere
M: TransformMatrix<T>,
Source§fn adapt_into(self) -> D
fn adapt_into(self) -> D
Source§impl<T, C> ArraysFrom<C> for Twhere
C: IntoArrays<T>,
impl<T, C> ArraysFrom<C> for Twhere
C: IntoArrays<T>,
Source§fn arrays_from(colors: C) -> T
fn arrays_from(colors: C) -> T
Source§impl<T, C> ArraysInto<C> for Twhere
C: FromArrays<T>,
impl<T, C> ArraysInto<C> for Twhere
C: FromArrays<T>,
Source§fn arrays_into(self) -> C
fn arrays_into(self) -> C
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<WpParam, T, U> Cam16IntoUnclamped<WpParam, T> for Uwhere
T: FromCam16Unclamped<WpParam, U>,
impl<WpParam, T, U> Cam16IntoUnclamped<WpParam, T> for Uwhere
T: FromCam16Unclamped<WpParam, U>,
Source§type Scalar = <T as FromCam16Unclamped<WpParam, U>>::Scalar
type Scalar = <T as FromCam16Unclamped<WpParam, U>>::Scalar
parameters when converting.Source§fn cam16_into_unclamped(
self,
parameters: BakedParameters<WpParam, <U as Cam16IntoUnclamped<WpParam, T>>::Scalar>,
) -> T
fn cam16_into_unclamped( self, parameters: BakedParameters<WpParam, <U as Cam16IntoUnclamped<WpParam, T>>::Scalar>, ) -> T
self into C, using the provided parameters.Source§impl<T> CheckedAs for T
impl<T> CheckedAs for T
Source§fn checked_as<Dst>(self) -> Option<Dst>where
T: CheckedCast<Dst>,
fn checked_as<Dst>(self) -> Option<Dst>where
T: CheckedCast<Dst>,
Source§impl<Src, Dst> CheckedCastFrom<Src> for Dstwhere
Src: CheckedCast<Dst>,
impl<Src, Dst> CheckedCastFrom<Src> for Dstwhere
Src: CheckedCast<Dst>,
Source§fn checked_cast_from(src: Src) -> Option<Dst>
fn checked_cast_from(src: Src) -> Option<Dst>
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<Q, K> Comparable<K> for Q
impl<Q, K> Comparable<K> for Q
Source§impl<T, C> ComponentsFrom<C> for Twhere
C: IntoComponents<T>,
impl<T, C> ComponentsFrom<C> for Twhere
C: IntoComponents<T>,
Source§fn components_from(colors: C) -> T
fn components_from(colors: C) -> T
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<T> Filterable for T
impl<T> Filterable for T
Source§fn filterable(
self,
filter_name: &'static str,
) -> RequestFilterDataProvider<T, fn(DataRequest<'_>) -> bool>
fn filterable( self, filter_name: &'static str, ) -> RequestFilterDataProvider<T, fn(DataRequest<'_>) -> bool>
Source§impl<T> FromAngle<T> for T
impl<T> FromAngle<T> for T
Source§fn from_angle(angle: T) -> T
fn from_angle(angle: T) -> T
angle.Source§impl<S> FromSample<S> for S
impl<S> FromSample<S> for S
fn from_sample_(s: S) -> S
Source§impl<T, U> FromStimulus<U> for Twhere
U: IntoStimulus<T>,
impl<T, U> FromStimulus<U> for Twhere
U: IntoStimulus<T>,
Source§fn from_stimulus(other: U) -> T
fn from_stimulus(other: U) -> T
other into Self, while performing the appropriate scaling,
rounding and clamping.Source§impl<T, U> IntoAngle<U> for Twhere
U: FromAngle<T>,
impl<T, U> IntoAngle<U> for Twhere
U: FromAngle<T>,
Source§fn into_angle(self) -> U
fn into_angle(self) -> U
T.Source§impl<WpParam, T, U> IntoCam16Unclamped<WpParam, T> for Uwhere
T: Cam16FromUnclamped<WpParam, U>,
impl<WpParam, T, U> IntoCam16Unclamped<WpParam, T> for Uwhere
T: Cam16FromUnclamped<WpParam, U>,
Source§type Scalar = <T as Cam16FromUnclamped<WpParam, U>>::Scalar
type Scalar = <T as Cam16FromUnclamped<WpParam, U>>::Scalar
parameters when converting.Source§fn into_cam16_unclamped(
self,
parameters: BakedParameters<WpParam, <U as IntoCam16Unclamped<WpParam, T>>::Scalar>,
) -> T
fn into_cam16_unclamped( self, parameters: BakedParameters<WpParam, <U as IntoCam16Unclamped<WpParam, T>>::Scalar>, ) -> T
self into C, using the provided parameters.Source§impl<T, U> IntoColor<U> for Twhere
U: FromColor<T>,
impl<T, U> IntoColor<U> for Twhere
U: FromColor<T>,
Source§fn into_color(self) -> U
fn into_color(self) -> U
Source§impl<T, U> IntoColorUnclamped<U> for Twhere
U: FromColorUnclamped<T>,
impl<T, U> IntoColorUnclamped<U> for Twhere
U: FromColorUnclamped<T>,
Source§fn into_color_unclamped(self) -> U
fn into_color_unclamped(self) -> U
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<F, T> IntoSample<T> for Fwhere
T: FromSample<F>,
impl<F, T> IntoSample<T> for Fwhere
T: FromSample<F>,
fn into_sample(self) -> T
Source§impl<T> IntoStimulus<T> for T
impl<T> IntoStimulus<T> for T
Source§fn into_stimulus(self) -> T
fn into_stimulus(self) -> T
self into T, while performing the appropriate scaling,
rounding and clamping.Source§impl<T> OverflowingAs for T
impl<T> OverflowingAs for T
Source§fn overflowing_as<Dst>(self) -> (Dst, bool)where
T: OverflowingCast<Dst>,
fn overflowing_as<Dst>(self) -> (Dst, bool)where
T: OverflowingCast<Dst>,
Source§impl<Src, Dst> OverflowingCastFrom<Src> for Dstwhere
Src: OverflowingCast<Dst>,
impl<Src, Dst> OverflowingCastFrom<Src> for Dstwhere
Src: OverflowingCast<Dst>,
Source§fn overflowing_cast_from(src: Src) -> (Dst, bool)
fn overflowing_cast_from(src: Src) -> (Dst, bool)
Source§impl<T> Pointable for T
impl<T> Pointable for T
Source§impl<R, P> ReadPrimitive<R> for P
impl<R, P> ReadPrimitive<R> for P
Source§fn read_from_little_endian(read: &mut R) -> Result<Self, Error>
fn read_from_little_endian(read: &mut R) -> Result<Self, Error>
ReadEndian::read_from_little_endian().Source§impl<T> SaturatingAs for T
impl<T> SaturatingAs for T
Source§fn saturating_as<Dst>(self) -> Dstwhere
T: SaturatingCast<Dst>,
fn saturating_as<Dst>(self) -> Dstwhere
T: SaturatingCast<Dst>,
Source§impl<Src, Dst> SaturatingCastFrom<Src> for Dstwhere
Src: SaturatingCast<Dst>,
impl<Src, Dst> SaturatingCastFrom<Src> for Dstwhere
Src: SaturatingCast<Dst>,
Source§fn saturating_cast_from(src: Src) -> Dst
fn saturating_cast_from(src: Src) -> Dst
Source§impl<T> StrictAs for T
impl<T> StrictAs for T
Source§fn strict_as<Dst>(self) -> Dstwhere
T: StrictCast<Dst>,
fn strict_as<Dst>(self) -> Dstwhere
T: StrictCast<Dst>,
Source§impl<Src, Dst> StrictCastFrom<Src> for Dstwhere
Src: StrictCast<Dst>,
impl<Src, Dst> StrictCastFrom<Src> for Dstwhere
Src: StrictCast<Dst>,
Source§fn strict_cast_from(src: Src) -> Dst
fn strict_cast_from(src: Src) -> Dst
Source§impl<T, U> ToSample<U> for Twhere
U: FromSample<T>,
impl<T, U> ToSample<U> for Twhere
U: FromSample<T>,
fn to_sample_(self) -> U
Source§impl<T, C> TryComponentsInto<C> for Twhere
C: TryFromComponents<T>,
impl<T, C> TryComponentsInto<C> for Twhere
C: TryFromComponents<T>,
Source§type Error = <C as TryFromComponents<T>>::Error
type Error = <C as TryFromComponents<T>>::Error
try_into_colors fails to cast.Source§fn try_components_into(self) -> Result<C, <T as TryComponentsInto<C>>::Error>
fn try_components_into(self) -> Result<C, <T as TryComponentsInto<C>>::Error>
Source§impl<T, U> TryIntoColor<U> for Twhere
U: TryFromColor<T>,
impl<T, U> TryIntoColor<U> for Twhere
U: TryFromColor<T>,
Source§fn try_into_color(self) -> Result<U, OutOfBounds<U>>
fn try_into_color(self) -> Result<U, OutOfBounds<U>>
OutOfBounds error is returned which contains
the unclamped color. Read more