Skip to main content

Color

Struct Color 

Source
pub struct Color {
    pub r: u8,
    pub g: u8,
    pub b: u8,
    pub a: u8,
}
Expand description

32-bit RGBA color.

Fields§

§r: u8

Red component.

§g: u8

Green component.

§b: u8

Blue component.

§a: u8

Alpha component.

Implementations§

Source§

impl Color

Source

pub const fn rgb8(r: u8, g: u8, b: u8) -> Color

Creates a new RGB color with 255 alpha.

Examples found in repository?
examples/explainer.rs (line 6)
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
Hide additional examples
examples/news_feed.rs (line 7)
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
15fn show(opacity: &Signal<f32>, d: Duration) -> Box<dyn Animation> {
16    opacity.to(1.0, d).ease(easings::cubic_out).into()
17}
18
19fn hide(opacity: &Signal<f32>, d: Duration) -> Box<dyn Animation> {
20    opacity.to(0.0, d).ease(easings::cubic_in).into()
21}
22
23// Helper for boxes to ensure they start completely hidden and slightly scaled down
24fn create_box(label: &str, center: Vec2, size: Vec2) -> (Rect, TextNode) {
25    let box_center = Vec2::new(center.x, center.y);
26
27    let text_pos = Vec2::new(center.x, center.y);
28
29    let r = Rect::default()
30        .with_position(box_center)
31        .with_size(size)
32        .with_scale(0.95)
33        .with_opacity(0.0)
34        .with_radius(8.0)
35        .with_stroke(ACCENT, 2.0)
36        .with_fill(Color::rgb8(0x26, 0x26, 0x2a));
37
38    let t = TextNode::default()
39        .with_position(text_pos)
40        .with_text(label)
41        .with_font_size(18.0)
42        .with_font("JetBrains Mono")
43        .with_fill(WHITE)
44        .with_scale(0.95)
45        .with_opacity(0.0);
46
47    (r, t)
48}
examples/physics_demo.rs (line 5)
5const BG: Color = Color::rgb8(0x0f, 0x0f, 0x14);
6const FLOOR_COLOR: Color = Color::rgb8(0x2a, 0x2d, 0x3a);
7const ACCENT_RED: Color = Color::rgb8(0xe1, 0x32, 0x38);
8const ACCENT_BLUE: Color = Color::rgb8(0x68, 0xab, 0xdf);
9const ACCENT_YELLOW: Color = Color::rgb8(0xe6, 0xa7, 0x00);
10const ACCENT_TEAL: Color = Color::rgb8(0x20, 0xb2, 0xaa);
11const ACCENT_PURPLE: Color = Color::rgb8(0x9b, 0x59, 0xb6);
12const ACCENT_EMERALD: Color = Color::rgb8(0x25, 0xc2, 0x81);
13const TEXT_DIM: Color = Color::rgb8(0x88, 0x88, 0x99);
14const TEXT_BRIGHT: Color = Color::rgb8(0xe8, 0xe8, 0xf0);
15const WALL_COLOR: Color = Color::rgb8(0x3a, 0x3d, 0x4a);
examples/gradient_demo.rs (line 80)
80const CYAN: Color = Color::rgb8(0x00, 0xf2, 0xfe);
81const INDIGO: Color = Color::rgb8(0x4f, 0x46, 0xe5);
82const CORAL: Color = Color::rgb8(0xff, 0x5e, 0x3a);
83const PINK: Color = Color::rgb8(0xff, 0x2a, 0x68);
84const VIOLET: Color = Color::rgb8(0x92, 0x3c, 0xff);
85const FUCHSIA: Color = Color::rgb8(0xff, 0x00, 0x7f);
86const BG: Color = Color::rgb8(0x0a, 0x0a, 0x12);
87const GRID_COLOR: Color = Color::rgba8(0x20, 0x20, 0x38, 60);
88const LABEL: Color = Color::rgb8(0x99, 0x99, 0xbb);
89
90// Timing
91const FADE_IN: Duration = Duration::from_millis(500);
92const FADE_OUT: Duration = Duration::from_millis(300);
93const MORPH: Duration = Duration::from_millis(1800);
94
95fn main() {
96    let cx = 960.0_f32;
97    let cy = 480.0_f32;
98
99    let mut project = Project::default()
100        .with_dimensions(1920, 1080)
101        .with_cache(true)
102        .with_title("Gradient Demo")
103        .close_on_finish();
104
105    // Background
106    let bg_rect = Rect::default()
107        .with_position(Vec2::new(cx, 540.0))
108        .with_size(Vec2::new(1920.0, 1080.0))
109        .with_fill(BG);
110
111    let grid = GridNode::default()
112        .with_position(Vec2::new(cx, 540.0))
113        .with_columns(32.0)
114        .with_rows(18.0)
115        .with_spacing_all(60.0)
116        .with_stroke(GRID_COLOR, 1.0)
117        .with_opacity(0.0);
118
119    // Gradients
120    let sunset = tri_grad(CORAL, PINK, VIOLET, 120.0);
121    let ocean = linear_grad(CYAN, INDIGO, 120.0);
122    let glow = radial_grad(FUCHSIA, Color::rgba8(0x4f, 0x46, 0xe5, 0), 130.0);
123    let glow_alt = radial_grad(CYAN, Color::rgba8(0x00, 0xf2, 0xfe, 0), 180.0);
124
125    // Sunset in different directions (same colors, different orientation)
126    let sunset_stops = vec![
127        ColorStop {
128            offset: 0.0,
129            color: CORAL,
130        },
131        ColorStop {
132            offset: 0.5,
133            color: PINK,
134        },
135        ColorStop {
136            offset: 1.0,
137            color: VIOLET,
138        },
139    ];
140    let sunset_horiz = directed_grad(
141        Point::new(-120.0, 0.0),
142        Point::new(120.0, 0.0),
143        sunset_stops.clone(),
144    );
145    let sunset_vert = directed_grad(
146        Point::new(0.0, -120.0),
147        Point::new(0.0, 120.0),
148        sunset_stops.clone(),
149    );
150    let sunset_diag = directed_grad(
151        Point::new(-120.0, -120.0),
152        Point::new(120.0, 120.0),
153        sunset_stops.clone(),
154    );
155
156    // Ocean in different directions
157    let ocean_stops = vec![
158        ColorStop {
159            offset: 0.0,
160            color: CYAN,
161        },
162        ColorStop {
163            offset: 1.0,
164            color: INDIGO,
165        },
166    ];
167    let ocean_vert = directed_grad(
168        Point::new(0.0, -120.0),
169        Point::new(0.0, 120.0),
170        ocean_stops.clone(),
171    );
172
173    // Persistent title
174    let title = TextNode::default()
175        .with_position(Vec2::new(cx, 100.0))
176        .with_text("Gradient Paint Demo")
177        .with_font_size(48.0)
178        .with_fill(Color::rgb8(0xdd, 0xdd, 0xee))
179        .with_opacity(0.0);
180
181    // Per-scene label (reused position, swapped text via separate nodes)
182    let label_y = 200.0;
183
184    // ─── SCENE 1: Circle with linear gradient fill ───
185    let s1_lbl = TextNode::default()
186        .with_position(Vec2::new(cx, label_y))
187        .with_text("Linear Gradient Fill")
188        .with_font_size(28.0)
189        .with_fill(LABEL)
190        .with_opacity(0.0);
191
192    let s1 = Circle::default()
193        .with_position(Vec2::new(cx, cy))
194        .with_radius(130.0)
195        .with_fill(sunset.clone())
196        .with_stroke(Color::rgba8(0xff, 0xff, 0xff, 20), 2.0)
197        .with_scale(0.95)
198        .with_opacity(0.0);
199
200    // Guides
201    let s1_g_start = Circle::default()
202        .with_position(Vec2::new(cx - 120.0, cy - 120.0))
203        .with_radius(8.0)
204        .with_fill(Color::WHITE)
205        .with_stroke(CORAL, 2.5)
206        .with_opacity(0.0);
207
208    let s1_g_end = Circle::default()
209        .with_position(Vec2::new(cx + 120.0, cy + 120.0))
210        .with_radius(8.0)
211        .with_fill(Color::WHITE)
212        .with_stroke(VIOLET, 2.5)
213        .with_opacity(0.0);
214
215    let s1_g_line = Line::default()
216        .with_position(Vec2::new(cx, cy))
217        .with_start(Vec2::new(-120.0, -120.0))
218        .with_end(Vec2::new(120.0, 120.0))
219        .with_stroke(Color::rgba8(0xff, 0xff, 0xff, 80), 1.5)
220        .with_opacity(0.0);
221
222    // ─── SCENE 2: Rect with radial gradient fill ───
223    let s2_lbl = TextNode::default()
224        .with_position(Vec2::new(cx, label_y))
225        .with_text("Radial Gradient Fill")
226        .with_font_size(28.0)
227        .with_fill(LABEL)
228        .with_opacity(0.0);
229
230    let s2 = Rect::default()
231        .with_position(Vec2::new(cx, cy))
232        .with_size(Vec2::new(260.0, 260.0))
233        .with_radius(24.0)
234        .with_fill(glow.clone())
235        .with_stroke(Color::rgba8(0xff, 0xff, 0xff, 20), 2.0)
236        .with_scale(0.95)
237        .with_opacity(0.0);
238
239    // Guides
240    let s2_g_center = Circle::default()
241        .with_position(Vec2::new(cx, cy))
242        .with_radius(8.0)
243        .with_fill(Color::WHITE)
244        .with_stroke(FUCHSIA, 2.5)
245        .with_opacity(0.0);
246
247    let s2_g_radius = Circle::default()
248        .with_position(Vec2::new(cx, cy))
249        .with_radius(130.0)
250        .with_fill(Color::TRANSPARENT)
251        .with_stroke(Color::rgba8(0xff, 0x00, 0x7f, 80), 1.5)
252        .with_opacity(0.0);
253
254    // ─── SCENE 3: Hexagon with gradient stroke ───
255    let s3_lbl = TextNode::default()
256        .with_position(Vec2::new(cx, label_y))
257        .with_text("Gradient Stroke")
258        .with_font_size(28.0)
259        .with_fill(LABEL)
260        .with_opacity(0.0);
261
262    let s3 = Polygon::regular(6, 130.0)
263        .with_position(Vec2::new(cx, cy))
264        .with_fill(Color::rgba8(0x12, 0x12, 0x20, 255))
265        .with_stroke(ocean.clone(), 5.0)
266        .with_scale(0.95)
267        .with_opacity(0.0);
268
269    // Guides
270    let s3_g_start = Circle::default()
271        .with_position(Vec2::new(cx - 120.0, cy))
272        .with_radius(8.0)
273        .with_fill(Color::WHITE)
274        .with_stroke(CYAN, 2.5)
275        .with_opacity(0.0);
276
277    let s3_g_end = Circle::default()
278        .with_position(Vec2::new(cx + 120.0, cy))
279        .with_radius(8.0)
280        .with_fill(Color::WHITE)
281        .with_stroke(INDIGO, 2.5)
282        .with_opacity(0.0);
283
284    let s3_g_line = Line::default()
285        .with_position(Vec2::new(cx, cy))
286        .with_start(Vec2::new(-120.0, 0.0))
287        .with_end(Vec2::new(120.0, 0.0))
288        .with_stroke(Color::rgba8(0xff, 0xff, 0xff, 80), 1.5)
289        .with_opacity(0.0);
290
291    // ─── SCENE 4: Line with gradient stroke ───
292    let s4_lbl = TextNode::default()
293        .with_position(Vec2::new(cx, label_y))
294        .with_text("Gradient Line")
295        .with_font_size(28.0)
296        .with_fill(LABEL)
297        .with_opacity(0.0);
298
299    let s4 = Line::default()
300        .with_position(Vec2::new(cx, cy))
301        .with_start(Vec2::new(-160.0, 100.0))
302        .with_end(Vec2::new(160.0, -100.0))
303        .with_stroke(sunset.clone(), 8.0)
304        .with_opacity(0.0);
305
306    // Guides
307    let s4_g_start = Circle::default()
308        .with_position(Vec2::new(cx - 120.0, cy - 120.0))
309        .with_radius(8.0)
310        .with_fill(Color::WHITE)
311        .with_stroke(CORAL, 2.5)
312        .with_opacity(0.0);
313
314    let s4_g_end = Circle::default()
315        .with_position(Vec2::new(cx + 120.0, cy + 120.0))
316        .with_radius(8.0)
317        .with_fill(Color::WHITE)
318        .with_stroke(VIOLET, 2.5)
319        .with_opacity(0.0);
320
321    let s4_g_line = Line::default()
322        .with_position(Vec2::new(cx, cy))
323        .with_start(Vec2::new(-120.0, -120.0))
324        .with_end(Vec2::new(120.0, 120.0))
325        .with_stroke(Color::rgba8(0xff, 0xff, 0xff, 80), 1.5)
326        .with_opacity(0.0);
327
328    // ─── SCENE 5: Path with gradient stroke ───
329    let s5_lbl = TextNode::default()
330        .with_position(Vec2::new(cx, label_y))
331        .with_text("Gradient Path")
332        .with_font_size(28.0)
333        .with_fill(LABEL)
334        .with_opacity(0.0);
335
336    let mut tri_path = BezPath::new();
337    tri_path.move_to(kurbo::Point::new(0.0, -120.0));
338    tri_path.line_to(kurbo::Point::new(104.0, 60.0));
339    tri_path.line_to(kurbo::Point::new(-104.0, 60.0));
340    tri_path.close_path();
341
342    let s5 = PathNode::new(Vec2::new(cx, cy), tri_path, CYAN, 6.0)
343        .with_stroke(ocean.clone(), 6.0)
344        .with_opacity(0.0);
345
346    // Guides
347    let s5_g_start = Circle::default()
348        .with_position(Vec2::new(cx - 120.0, cy))
349        .with_radius(8.0)
350        .with_fill(Color::WHITE)
351        .with_stroke(CYAN, 2.5)
352        .with_opacity(0.0);
353
354    let s5_g_end = Circle::default()
355        .with_position(Vec2::new(cx + 120.0, cy))
356        .with_radius(8.0)
357        .with_fill(Color::WHITE)
358        .with_stroke(INDIGO, 2.5)
359        .with_opacity(0.0);
360
361    let s5_g_line = Line::default()
362        .with_position(Vec2::new(cx, cy))
363        .with_start(Vec2::new(-120.0, 0.0))
364        .with_end(Vec2::new(120.0, 0.0))
365        .with_stroke(Color::rgba8(0xff, 0xff, 0xff, 80), 1.5)
366        .with_opacity(0.0);
367
368    // ─── SCENE 6: Grid with gradient stroke ───
369    let s6_lbl = TextNode::default()
370        .with_position(Vec2::new(cx, label_y))
371        .with_text("Gradient Grid")
372        .with_font_size(28.0)
373        .with_fill(LABEL)
374        .with_opacity(0.0);
375
376    let s6_grid = GridNode::default()
377        .with_position(Vec2::new(cx, cy))
378        .with_columns(8.0)
379        .with_rows(6.0)
380        .with_spacing_all(50.0)
381        .with_stroke(ocean.clone(), 2.0)
382        .with_opacity(0.0);
383
384    // Guides
385    let s6_g_start = Circle::default()
386        .with_position(Vec2::new(cx - 120.0, cy))
387        .with_radius(8.0)
388        .with_fill(Color::WHITE)
389        .with_stroke(CYAN, 2.5)
390        .with_opacity(0.0);
391
392    let s6_g_end = Circle::default()
393        .with_position(Vec2::new(cx + 120.0, cy))
394        .with_radius(8.0)
395        .with_fill(Color::WHITE)
396        .with_stroke(INDIGO, 2.5)
397        .with_opacity(0.0);
398
399    let s6_g_line = Line::default()
400        .with_position(Vec2::new(cx, cy))
401        .with_start(Vec2::new(-120.0, 0.0))
402        .with_end(Vec2::new(120.0, 0.0))
403        .with_stroke(Color::rgba8(0xff, 0xff, 0xff, 80), 1.5)
404        .with_opacity(0.0);
405
406    // ─── SCENE 7: Text with gradient fill ───
407    let s7_lbl = TextNode::default()
408        .with_position(Vec2::new(cx, label_y))
409        .with_text("Gradient Text")
410        .with_font_size(28.0)
411        .with_fill(LABEL)
412        .with_opacity(0.0);
413
414    let s7 = TextNode::default()
415        .with_position(Vec2::new(cx, cy))
416        .with_text("HELLO GRADIENTS")
417        .with_font_size(80.0)
418        .with_fill(ocean.clone())
419        .with_scale(0.95)
420        .with_opacity(0.0);
421
422    // Guides
423    let s7_g_start = Circle::default()
424        .with_position(Vec2::new(cx - 120.0, cy))
425        .with_radius(8.0)
426        .with_fill(Color::WHITE)
427        .with_stroke(CYAN, 2.5)
428        .with_opacity(0.0);
429
430    let s7_g_end = Circle::default()
431        .with_position(Vec2::new(cx + 120.0, cy))
432        .with_radius(8.0)
433        .with_fill(Color::WHITE)
434        .with_stroke(INDIGO, 2.5)
435        .with_opacity(0.0);
436
437    let s7_g_line = Line::default()
438        .with_position(Vec2::new(cx, cy))
439        .with_start(Vec2::new(-120.0, 0.0))
440        .with_end(Vec2::new(120.0, 0.0))
441        .with_stroke(Color::rgba8(0xff, 0xff, 0xff, 80), 1.5)
442        .with_opacity(0.0);
443
444    // ─── SCENE 8: Math with gradient fill ───
445    let s8_lbl = TextNode::default()
446        .with_position(Vec2::new(cx, label_y))
447        .with_text("Gradient Math")
448        .with_font_size(28.0)
449        .with_fill(LABEL)
450        .with_opacity(0.0);
451
452    let s8 = MathNode::default()
453        .with_position(Vec2::new(cx, cy))
454        .with_equation("E = m c^2")
455        .with_font_size(72.0)
456        .with_fill(sunset.clone())
457        .with_scale(0.95)
458        .with_opacity(0.0);
459
460    // Guides
461    let s8_g_start = Circle::default()
462        .with_position(Vec2::new(cx - 120.0, cy - 120.0))
463        .with_radius(8.0)
464        .with_fill(Color::WHITE)
465        .with_stroke(CORAL, 2.5)
466        .with_opacity(0.0);
467
468    let s8_g_end = Circle::default()
469        .with_position(Vec2::new(cx + 120.0, cy + 120.0))
470        .with_radius(8.0)
471        .with_fill(Color::WHITE)
472        .with_stroke(VIOLET, 2.5)
473        .with_opacity(0.0);
474
475    let s8_g_line = Line::default()
476        .with_position(Vec2::new(cx, cy))
477        .with_start(Vec2::new(-120.0, -120.0))
478        .with_end(Vec2::new(120.0, 120.0))
479        .with_stroke(Color::rgba8(0xff, 0xff, 0xff, 80), 1.5)
480        .with_opacity(0.0);
481
482    // ─── SCENE 9: Solid ↔ Gradient ───
483    let s9_lbl = TextNode::default()
484        .with_position(Vec2::new(cx, label_y))
485        .with_text("Solid to Gradient")
486        .with_font_size(28.0)
487        .with_fill(LABEL)
488        .with_opacity(0.0);
489
490    let s9 = Circle::default()
491        .with_position(Vec2::new(cx, cy))
492        .with_radius(130.0)
493        .with_fill(Color::WHITE)
494        .with_stroke(Color::rgba8(0xff, 0xff, 0xff, 20), 2.0)
495        .with_scale(0.95)
496        .with_opacity(0.0);
497
498    // Guides (start with opacity 0, fade in when Sunset is active, fade out on Solid)
499    let s9_g_start = Circle::default()
500        .with_position(Vec2::new(cx - 120.0, cy - 120.0))
501        .with_radius(8.0)
502        .with_fill(Color::WHITE)
503        .with_stroke(CORAL, 2.5)
504        .with_opacity(0.0);
505
506    let s9_g_end = Circle::default()
507        .with_position(Vec2::new(cx + 120.0, cy + 120.0))
508        .with_radius(8.0)
509        .with_fill(Color::WHITE)
510        .with_stroke(VIOLET, 2.5)
511        .with_opacity(0.0);
512
513    let s9_g_line = Line::default()
514        .with_position(Vec2::new(cx, cy))
515        .with_start(Vec2::new(-120.0, -120.0))
516        .with_end(Vec2::new(120.0, 120.0))
517        .with_stroke(Color::rgba8(0xff, 0xff, 0xff, 80), 1.5)
518        .with_opacity(0.0);
519
520    // ─── SCENE 10: Radial ↔ Linear Interpolation ───
521    let s10_lbl = TextNode::default()
522        .with_position(Vec2::new(cx, label_y))
523        .with_text("Radial ↔ Linear Morph")
524        .with_font_size(28.0)
525        .with_fill(LABEL)
526        .with_opacity(0.0);
527
528    let s10 = Circle::default()
529        .with_position(Vec2::new(cx, cy))
530        .with_radius(130.0)
531        .with_fill(glow.clone()) // Start as Radial Gradient
532        .with_stroke(Color::rgba8(0xff, 0xff, 0xff, 20), 2.0)
533        .with_scale(0.95)
534        .with_opacity(0.0);
535
536    // Visual guides for Scene 10 (cross-fading between radial and linear handles)
537    let s10_g_rad_center = Circle::default()
538        .with_position(Vec2::new(cx, cy))
539        .with_radius(8.0)
540        .with_fill(Color::WHITE)
541        .with_stroke(FUCHSIA, 2.5)
542        .with_opacity(0.0);
543
544    let s10_g_rad_radius = Circle::default()
545        .with_position(Vec2::new(cx, cy))
546        .with_radius(130.0)
547        .with_fill(Color::TRANSPARENT)
548        .with_stroke(Color::rgba8(0xff, 0x00, 0x7f, 80), 1.5)
549        .with_opacity(0.0);
550
551    let s10_g_lin_start = Circle::default()
552        .with_position(Vec2::new(cx - 120.0, cy - 120.0))
553        .with_radius(8.0)
554        .with_fill(Color::WHITE)
555        .with_stroke(CORAL, 2.5)
556        .with_opacity(0.0);
557
558    let s10_g_lin_end = Circle::default()
559        .with_position(Vec2::new(cx + 120.0, cy + 120.0))
560        .with_radius(8.0)
561        .with_fill(Color::WHITE)
562        .with_stroke(VIOLET, 2.5)
563        .with_opacity(0.0);
564
565    let s10_g_lin_line = Line::default()
566        .with_position(Vec2::new(cx, cy))
567        .with_start(Vec2::new(-120.0, -120.0))
568        .with_end(Vec2::new(120.0, 120.0))
569        .with_stroke(Color::rgba8(0xff, 0xff, 0xff, 80), 1.5)
570        .with_opacity(0.0);
571
572    // Add all to scene
573    project.scene.add(&bg_rect);
574    project.scene.add(&grid);
575    project.scene.add(&title);
576
577    // Scene 1
578    project.scene.add(&s1_lbl);
579    project.scene.add(&s1);
580    project.scene.add(&s1_g_line);
581    project.scene.add(&s1_g_start);
582    project.scene.add(&s1_g_end);
583
584    // Scene 2
585    project.scene.add(&s2_lbl);
586    project.scene.add(&s2);
587    project.scene.add(&s2_g_radius);
588    project.scene.add(&s2_g_center);
589
590    // Scene 3
591    project.scene.add(&s3_lbl);
592    project.scene.add(&s3);
593    project.scene.add(&s3_g_line);
594    project.scene.add(&s3_g_start);
595    project.scene.add(&s3_g_end);
596
597    // Scene 4
598    project.scene.add(&s4_lbl);
599    project.scene.add(&s4);
600    project.scene.add(&s4_g_line);
601    project.scene.add(&s4_g_start);
602    project.scene.add(&s4_g_end);
603
604    // Scene 5
605    project.scene.add(&s5_lbl);
606    project.scene.add(&s5);
607    project.scene.add(&s5_g_line);
608    project.scene.add(&s5_g_start);
609    project.scene.add(&s5_g_end);
610
611    // Scene 6
612    project.scene.add(&s6_lbl);
613    project.scene.add(&s6_grid);
614    project.scene.add(&s6_g_line);
615    project.scene.add(&s6_g_start);
616    project.scene.add(&s6_g_end);
617
618    // Scene 7
619    project.scene.add(&s7_lbl);
620    project.scene.add(&s7);
621    project.scene.add(&s7_g_line);
622    project.scene.add(&s7_g_start);
623    project.scene.add(&s7_g_end);
624
625    // Scene 8
626    project.scene.add(&s8_lbl);
627    project.scene.add(&s8);
628    project.scene.add(&s8_g_line);
629    project.scene.add(&s8_g_start);
630    project.scene.add(&s8_g_end);
631
632    // Scene 9
633    project.scene.add(&s9_lbl);
634    project.scene.add(&s9);
635    project.scene.add(&s9_g_line);
636    project.scene.add(&s9_g_start);
637    project.scene.add(&s9_g_end);
638
639    // Scene 10
640    project.scene.add(&s10_lbl);
641    project.scene.add(&s10);
642    project.scene.add(&s10_g_rad_radius);
643    project.scene.add(&s10_g_rad_center);
644    project.scene.add(&s10_g_lin_line);
645    project.scene.add(&s10_g_lin_start);
646    project.scene.add(&s10_g_lin_end);
647
648    // Timeline — one scene at a time, each with its own gradient animation
649    project.scene.video_timeline.add(chain![
650        // Intro
651        all![
652            grid.opacity.to(1.0, Duration::from_millis(800)),
653            title.opacity.to(1.0, Duration::from_millis(800)),
654        ],
655        wait!(1),
656        // ─── 1: Circle linear fill — morph colors, then direction ───
657        all![
658            s1_lbl.opacity.to(1.0, FADE_IN),
659            s1.opacity.to(1.0, FADE_IN),
660            s1.scale.to(Vec2::ONE, FADE_IN),
661            s1_g_start.opacity.to(1.0, FADE_IN),
662            s1_g_end.opacity.to(1.0, FADE_IN),
663            s1_g_line.opacity.to(1.0, FADE_IN),
664        ],
665        wait!(1),
666        // Color morph: sunset → ocean
667        all![
668            s1.fill_paint.to(Paint::Gradient(ocean.clone()), MORPH),
669            s1_g_start.position.to(Vec2::new(cx - 120.0, cy), MORPH),
670            s1_g_end.position.to(Vec2::new(cx + 120.0, cy), MORPH),
671            s1_g_line.start.to(Vec2::new(-120.0, 0.0), MORPH),
672            s1_g_line.end.to(Vec2::new(120.0, 0.0), MORPH),
673            s1_g_start.stroke_paint.to(Paint::Solid(CYAN), MORPH),
674            s1_g_end.stroke_paint.to(Paint::Solid(INDIGO), MORPH),
675        ],
676        wait!(1),
677        // Color morph: ocean → sunset
678        all![
679            s1.fill_paint.to(Paint::Gradient(sunset.clone()), MORPH),
680            s1_g_start
681                .position
682                .to(Vec2::new(cx - 120.0, cy - 120.0), MORPH),
683            s1_g_end
684                .position
685                .to(Vec2::new(cx + 120.0, cy + 120.0), MORPH),
686            s1_g_line.start.to(Vec2::new(-120.0, -120.0), MORPH),
687            s1_g_line.end.to(Vec2::new(120.0, 120.0), MORPH),
688            s1_g_start.stroke_paint.to(Paint::Solid(CORAL), MORPH),
689            s1_g_end.stroke_paint.to(Paint::Solid(VIOLET), MORPH),
690        ],
691        wait!(1),
692        // Direction morph: diagonal → horizontal sunset
693        all![
694            s1.fill_paint
695                .to(Paint::Gradient(sunset_horiz.clone()), MORPH),
696            s1_g_start.position.to(Vec2::new(cx - 120.0, cy), MORPH),
697            s1_g_end.position.to(Vec2::new(cx + 120.0, cy), MORPH),
698            s1_g_line.start.to(Vec2::new(-120.0, 0.0), MORPH),
699            s1_g_line.end.to(Vec2::new(120.0, 0.0), MORPH),
700        ],
701        wait!(1),
702        // Direction morph: horizontal → vertical sunset
703        all![
704            s1.fill_paint
705                .to(Paint::Gradient(sunset_vert.clone()), MORPH),
706            s1_g_start.position.to(Vec2::new(cx, cy - 120.0), MORPH),
707            s1_g_end.position.to(Vec2::new(cx, cy + 120.0), MORPH),
708            s1_g_line.start.to(Vec2::new(0.0, -120.0), MORPH),
709            s1_g_line.end.to(Vec2::new(0.0, 120.0), MORPH),
710        ],
711        wait!(1),
712        // Direction morph: vertical → diagonal sunset
713        all![
714            s1.fill_paint
715                .to(Paint::Gradient(sunset_diag.clone()), MORPH),
716            s1_g_start
717                .position
718                .to(Vec2::new(cx - 120.0, cy - 120.0), MORPH),
719            s1_g_end
720                .position
721                .to(Vec2::new(cx + 120.0, cy + 120.0), MORPH),
722            s1_g_line.start.to(Vec2::new(-120.0, -120.0), MORPH),
723            s1_g_line.end.to(Vec2::new(120.0, 120.0), MORPH),
724        ],
725        wait!(1),
726        all![
727            s1_lbl.opacity.to(0.0, FADE_OUT),
728            s1.opacity.to(0.0, FADE_OUT),
729            s1.scale.to(Vec2::splat(0.95), FADE_OUT),
730            s1_g_start.opacity.to(0.0, FADE_OUT),
731            s1_g_end.opacity.to(0.0, FADE_OUT),
732            s1_g_line.opacity.to(0.0, FADE_OUT),
733        ],
734        // ─── 2: Rect radial fill — morph to another radial gradient and back ───
735        all![
736            s2_lbl.opacity.to(1.0, FADE_IN),
737            s2.opacity.to(1.0, FADE_IN),
738            s2.scale.to(Vec2::ONE, FADE_IN),
739            s2_g_center.opacity.to(1.0, FADE_IN),
740            s2_g_radius.opacity.to(1.0, FADE_IN),
741        ],
742        wait!(1),
743        // Radial color and radius morph: glow (Fuchsia 130px) -> glow_alt (Cyan 180px)
744        all![
745            s2.fill_paint.to(Paint::Gradient(glow_alt.clone()), MORPH),
746            s2_g_radius.radius.to(180.0, MORPH),
747            s2_g_center.stroke_paint.to(Paint::Solid(CYAN), MORPH),
748            s2_g_radius
749                .stroke_paint
750                .to(Paint::Solid(Color::rgba8(0x00, 0xf2, 0xfe, 80)), MORPH),
751        ],
752        wait!(1),
753        // Morph back to glow
754        all![
755            s2.fill_paint.to(Paint::Gradient(glow.clone()), MORPH),
756            s2_g_radius.radius.to(130.0, MORPH),
757            s2_g_center.stroke_paint.to(Paint::Solid(FUCHSIA), MORPH),
758            s2_g_radius
759                .stroke_paint
760                .to(Paint::Solid(Color::rgba8(0xff, 0x00, 0x7f, 80)), MORPH),
761        ],
762        wait!(1),
763        all![
764            s2_lbl.opacity.to(0.0, FADE_OUT),
765            s2.opacity.to(0.0, FADE_OUT),
766            s2.scale.to(Vec2::splat(0.95), FADE_OUT),
767            s2_g_center.opacity.to(0.0, FADE_OUT),
768            s2_g_radius.opacity.to(0.0, FADE_OUT),
769        ],
770        // ─── 3: Hex gradient stroke — morph colors, then direction ───
771        all![
772            s3_lbl.opacity.to(1.0, FADE_IN),
773            s3.opacity.to(1.0, FADE_IN),
774            s3.scale.to(Vec2::ONE, FADE_IN),
775            s3_g_start.opacity.to(1.0, FADE_IN),
776            s3_g_end.opacity.to(1.0, FADE_IN),
777            s3_g_line.opacity.to(1.0, FADE_IN),
778        ],
779        wait!(1),
780        // Morph: ocean (horizontal) -> sunset (diagonal)
781        all![
782            s3.stroke_paint.to(Paint::Gradient(sunset.clone()), MORPH),
783            s3_g_start
784                .position
785                .to(Vec2::new(cx - 120.0, cy - 120.0), MORPH),
786            s3_g_end
787                .position
788                .to(Vec2::new(cx + 120.0, cy + 120.0), MORPH),
789            s3_g_line.start.to(Vec2::new(-120.0, -120.0), MORPH),
790            s3_g_line.end.to(Vec2::new(120.0, 120.0), MORPH),
791            s3_g_start.stroke_paint.to(Paint::Solid(CORAL), MORPH),
792            s3_g_end.stroke_paint.to(Paint::Solid(VIOLET), MORPH),
793        ],
794        wait!(1),
795        // Morph: sunset (diagonal) -> ocean (horizontal)
796        all![
797            s3.stroke_paint.to(Paint::Gradient(ocean.clone()), MORPH),
798            s3_g_start.position.to(Vec2::new(cx - 120.0, cy), MORPH),
799            s3_g_end.position.to(Vec2::new(cx + 120.0, cy), MORPH),
800            s3_g_line.start.to(Vec2::new(-120.0, 0.0), MORPH),
801            s3_g_line.end.to(Vec2::new(120.0, 0.0), MORPH),
802            s3_g_start.stroke_paint.to(Paint::Solid(CYAN), MORPH),
803            s3_g_end.stroke_paint.to(Paint::Solid(INDIGO), MORPH),
804        ],
805        wait!(1),
806        // Direction morph: horizontal ocean -> vertical ocean
807        all![
808            s3.stroke_paint
809                .to(Paint::Gradient(ocean_vert.clone()), MORPH),
810            s3_g_start.position.to(Vec2::new(cx, cy - 120.0), MORPH),
811            s3_g_end.position.to(Vec2::new(cx, cy + 120.0), MORPH),
812            s3_g_line.start.to(Vec2::new(0.0, -120.0), MORPH),
813            s3_g_line.end.to(Vec2::new(0.0, 120.0), MORPH),
814        ],
815        wait!(1),
816        // Direction morph: vertical ocean -> horizontal ocean
817        all![
818            s3.stroke_paint.to(Paint::Gradient(ocean.clone()), MORPH),
819            s3_g_start.position.to(Vec2::new(cx - 120.0, cy), MORPH),
820            s3_g_end.position.to(Vec2::new(cx + 120.0, cy), MORPH),
821            s3_g_line.start.to(Vec2::new(-120.0, 0.0), MORPH),
822            s3_g_line.end.to(Vec2::new(120.0, 0.0), MORPH),
823        ],
824        wait!(1),
825        all![
826            s3_lbl.opacity.to(0.0, FADE_OUT),
827            s3.opacity.to(0.0, FADE_OUT),
828            s3.scale.to(Vec2::splat(0.95), FADE_OUT),
829            s3_g_start.opacity.to(0.0, FADE_OUT),
830            s3_g_end.opacity.to(0.0, FADE_OUT),
831            s3_g_line.opacity.to(0.0, FADE_OUT),
832        ],
833        // ─── 4: Line gradient stroke ───
834        all![
835            s4_lbl.opacity.to(1.0, FADE_IN),
836            s4.opacity.to(1.0, FADE_IN),
837            s4_g_start.opacity.to(1.0, FADE_IN),
838            s4_g_end.opacity.to(1.0, FADE_IN),
839            s4_g_line.opacity.to(1.0, FADE_IN),
840        ],
841        wait!(1),
842        // Morph: sunset (diagonal) -> ocean (horizontal)
843        all![
844            s4.stroke_paint.to(Paint::Gradient(ocean.clone()), MORPH),
845            s4_g_start.position.to(Vec2::new(cx - 120.0, cy), MORPH),
846            s4_g_end.position.to(Vec2::new(cx + 120.0, cy), MORPH),
847            s4_g_line.start.to(Vec2::new(-120.0, 0.0), MORPH),
848            s4_g_line.end.to(Vec2::new(120.0, 0.0), MORPH),
849            s4_g_start.stroke_paint.to(Paint::Solid(CYAN), MORPH),
850            s4_g_end.stroke_paint.to(Paint::Solid(INDIGO), MORPH),
851        ],
852        wait!(1),
853        // Morph: ocean (horizontal) -> sunset (diagonal)
854        all![
855            s4.stroke_paint.to(Paint::Gradient(sunset.clone()), MORPH),
856            s4_g_start
857                .position
858                .to(Vec2::new(cx - 120.0, cy - 120.0), MORPH),
859            s4_g_end
860                .position
861                .to(Vec2::new(cx + 120.0, cy + 120.0), MORPH),
862            s4_g_line.start.to(Vec2::new(-120.0, -120.0), MORPH),
863            s4_g_line.end.to(Vec2::new(120.0, 120.0), MORPH),
864            s4_g_start.stroke_paint.to(Paint::Solid(CORAL), MORPH),
865            s4_g_end.stroke_paint.to(Paint::Solid(VIOLET), MORPH),
866        ],
867        wait!(1),
868        all![
869            s4_lbl.opacity.to(0.0, FADE_OUT),
870            s4.opacity.to(0.0, FADE_OUT),
871            s4_g_start.opacity.to(0.0, FADE_OUT),
872            s4_g_end.opacity.to(0.0, FADE_OUT),
873            s4_g_line.opacity.to(0.0, FADE_OUT),
874        ],
875        // ─── 5: Path gradient stroke ───
876        all![
877            s5_lbl.opacity.to(1.0, FADE_IN),
878            s5.opacity.to(1.0, FADE_IN),
879            s5_g_start.opacity.to(1.0, FADE_IN),
880            s5_g_end.opacity.to(1.0, FADE_IN),
881            s5_g_line.opacity.to(1.0, FADE_IN),
882        ],
883        wait!(1),
884        // Morph: ocean (horizontal) -> sunset (diagonal)
885        all![
886            s5.stroke_paint.to(Paint::Gradient(sunset.clone()), MORPH),
887            s5_g_start
888                .position
889                .to(Vec2::new(cx - 120.0, cy - 120.0), MORPH),
890            s5_g_end
891                .position
892                .to(Vec2::new(cx + 120.0, cy + 120.0), MORPH),
893            s5_g_line.start.to(Vec2::new(-120.0, -120.0), MORPH),
894            s5_g_line.end.to(Vec2::new(120.0, 120.0), MORPH),
895            s5_g_start.stroke_paint.to(Paint::Solid(CORAL), MORPH),
896            s5_g_end.stroke_paint.to(Paint::Solid(VIOLET), MORPH),
897        ],
898        wait!(1),
899        // Morph: sunset (diagonal) -> ocean (horizontal)
900        all![
901            s5.stroke_paint.to(Paint::Gradient(ocean.clone()), MORPH),
902            s5_g_start.position.to(Vec2::new(cx - 120.0, cy), MORPH),
903            s5_g_end.position.to(Vec2::new(cx + 120.0, cy), MORPH),
904            s5_g_line.start.to(Vec2::new(-120.0, 0.0), MORPH),
905            s5_g_line.end.to(Vec2::new(120.0, 0.0), MORPH),
906            s5_g_start.stroke_paint.to(Paint::Solid(CYAN), MORPH),
907            s5_g_end.stroke_paint.to(Paint::Solid(INDIGO), MORPH),
908        ],
909        wait!(1),
910        all![
911            s5_lbl.opacity.to(0.0, FADE_OUT),
912            s5.opacity.to(0.0, FADE_OUT),
913            s5_g_start.opacity.to(0.0, FADE_OUT),
914            s5_g_end.opacity.to(0.0, FADE_OUT),
915            s5_g_line.opacity.to(0.0, FADE_OUT),
916        ],
917        // ─── 6: Grid gradient stroke ───
918        all![
919            s6_lbl.opacity.to(1.0, FADE_IN),
920            s6_grid.opacity.to(1.0, FADE_IN),
921            s6_g_start.opacity.to(1.0, FADE_IN),
922            s6_g_end.opacity.to(1.0, FADE_IN),
923            s6_g_line.opacity.to(1.0, FADE_IN),
924        ],
925        wait!(1),
926        // Morph: ocean (horizontal) -> sunset (diagonal)
927        all![
928            s6_grid
929                .stroke_paint
930                .to(Paint::Gradient(sunset.clone()), MORPH),
931            s6_g_start
932                .position
933                .to(Vec2::new(cx - 120.0, cy - 120.0), MORPH),
934            s6_g_end
935                .position
936                .to(Vec2::new(cx + 120.0, cy + 120.0), MORPH),
937            s6_g_line.start.to(Vec2::new(-120.0, -120.0), MORPH),
938            s6_g_line.end.to(Vec2::new(120.0, 120.0), MORPH),
939            s6_g_start.stroke_paint.to(Paint::Solid(CORAL), MORPH),
940            s6_g_end.stroke_paint.to(Paint::Solid(VIOLET), MORPH),
941        ],
942        wait!(1),
943        // Morph: sunset (diagonal) -> ocean (horizontal)
944        all![
945            s6_grid
946                .stroke_paint
947                .to(Paint::Gradient(ocean.clone()), MORPH),
948            s6_g_start.position.to(Vec2::new(cx - 120.0, cy), MORPH),
949            s6_g_end.position.to(Vec2::new(cx + 120.0, cy), MORPH),
950            s6_g_line.start.to(Vec2::new(-120.0, 0.0), MORPH),
951            s6_g_line.end.to(Vec2::new(120.0, 0.0), MORPH),
952            s6_g_start.stroke_paint.to(Paint::Solid(CYAN), MORPH),
953            s6_g_end.stroke_paint.to(Paint::Solid(INDIGO), MORPH),
954        ],
955        wait!(1),
956        all![
957            s6_lbl.opacity.to(0.0, FADE_OUT),
958            s6_grid.opacity.to(0.0, FADE_OUT),
959            s6_g_start.opacity.to(0.0, FADE_OUT),
960            s6_g_end.opacity.to(0.0, FADE_OUT),
961            s6_g_line.opacity.to(0.0, FADE_OUT),
962        ],
963        // ─── 7: Text — morph colors, then direction ───
964        all![
965            s7_lbl.opacity.to(1.0, FADE_IN),
966            s7.opacity.to(1.0, FADE_IN),
967            s7.scale.to(Vec2::ONE, FADE_IN),
968            s7_g_start.opacity.to(1.0, FADE_IN),
969            s7_g_end.opacity.to(1.0, FADE_IN),
970            s7_g_line.opacity.to(1.0, FADE_IN),
971        ],
972        wait!(1),
973        // Morph: ocean (horizontal) -> sunset (diagonal)
974        all![
975            s7.fill_paint.to(Paint::Gradient(sunset.clone()), MORPH),
976            s7_g_start
977                .position
978                .to(Vec2::new(cx - 120.0, cy - 120.0), MORPH),
979            s7_g_end
980                .position
981                .to(Vec2::new(cx + 120.0, cy + 120.0), MORPH),
982            s7_g_line.start.to(Vec2::new(-120.0, -120.0), MORPH),
983            s7_g_line.end.to(Vec2::new(120.0, 120.0), MORPH),
984            s7_g_start.stroke_paint.to(Paint::Solid(CORAL), MORPH),
985            s7_g_end.stroke_paint.to(Paint::Solid(VIOLET), MORPH),
986        ],
987        wait!(1),
988        // Morph: sunset (diagonal) -> ocean (horizontal)
989        all![
990            s7.fill_paint.to(Paint::Gradient(ocean.clone()), MORPH),
991            s7_g_start.position.to(Vec2::new(cx - 120.0, cy), MORPH),
992            s7_g_end.position.to(Vec2::new(cx + 120.0, cy), MORPH),
993            s7_g_line.start.to(Vec2::new(-120.0, 0.0), MORPH),
994            s7_g_line.end.to(Vec2::new(120.0, 0.0), MORPH),
995            s7_g_start.stroke_paint.to(Paint::Solid(CYAN), MORPH),
996            s7_g_end.stroke_paint.to(Paint::Solid(INDIGO), MORPH),
997        ],
998        wait!(1),
999        // Morph: horizontal ocean -> vertical ocean
1000        all![
1001            s7.fill_paint.to(Paint::Gradient(ocean_vert.clone()), MORPH),
1002            s7_g_start.position.to(Vec2::new(cx, cy - 120.0), MORPH),
1003            s7_g_end.position.to(Vec2::new(cx, cy + 120.0), MORPH),
1004            s7_g_line.start.to(Vec2::new(0.0, -120.0), MORPH),
1005            s7_g_line.end.to(Vec2::new(0.0, 120.0), MORPH),
1006        ],
1007        wait!(1),
1008        // Morph: vertical ocean -> horizontal ocean
1009        all![
1010            s7.fill_paint.to(Paint::Gradient(ocean.clone()), MORPH),
1011            s7_g_start.position.to(Vec2::new(cx - 120.0, cy), MORPH),
1012            s7_g_end.position.to(Vec2::new(cx + 120.0, cy), MORPH),
1013            s7_g_line.start.to(Vec2::new(-120.0, 0.0), MORPH),
1014            s7_g_line.end.to(Vec2::new(120.0, 0.0), MORPH),
1015        ],
1016        wait!(1),
1017        all![
1018            s7_lbl.opacity.to(0.0, FADE_OUT),
1019            s7.opacity.to(0.0, FADE_OUT),
1020            s7.scale.to(Vec2::splat(0.95), FADE_OUT),
1021            s7_g_start.opacity.to(0.0, FADE_OUT),
1022            s7_g_end.opacity.to(0.0, FADE_OUT),
1023            s7_g_line.opacity.to(0.0, FADE_OUT),
1024        ],
1025        // ─── 8: Math ───
1026        all![
1027            s8_lbl.opacity.to(1.0, FADE_IN),
1028            s8.opacity.to(1.0, FADE_IN),
1029            s8.scale.to(Vec2::ONE, FADE_IN),
1030            s8_g_start.opacity.to(1.0, FADE_IN),
1031            s8_g_end.opacity.to(1.0, FADE_IN),
1032            s8_g_line.opacity.to(1.0, FADE_IN),
1033        ],
1034        wait!(1),
1035        // Morph: sunset (diagonal) -> ocean (horizontal)
1036        all![
1037            s8.fill_paint.to(Paint::Gradient(ocean.clone()), MORPH),
1038            s8_g_start.position.to(Vec2::new(cx - 120.0, cy), MORPH),
1039            s8_g_end.position.to(Vec2::new(cx + 120.0, cy), MORPH),
1040            s8_g_line.start.to(Vec2::new(-120.0, 0.0), MORPH),
1041            s8_g_line.end.to(Vec2::new(120.0, 0.0), MORPH),
1042            s8_g_start.stroke_paint.to(Paint::Solid(CYAN), MORPH),
1043            s8_g_end.stroke_paint.to(Paint::Solid(INDIGO), MORPH),
1044        ],
1045        wait!(1),
1046        // Morph: ocean (horizontal) -> sunset (diagonal)
1047        all![
1048            s8.fill_paint.to(Paint::Gradient(sunset.clone()), MORPH),
1049            s8_g_start
1050                .position
1051                .to(Vec2::new(cx - 120.0, cy - 120.0), MORPH),
1052            s8_g_end
1053                .position
1054                .to(Vec2::new(cx + 120.0, cy + 120.0), MORPH),
1055            s8_g_line.start.to(Vec2::new(-120.0, -120.0), MORPH),
1056            s8_g_line.end.to(Vec2::new(120.0, 120.0), MORPH),
1057            s8_g_start.stroke_paint.to(Paint::Solid(CORAL), MORPH),
1058            s8_g_end.stroke_paint.to(Paint::Solid(VIOLET), MORPH),
1059        ],
1060        wait!(1),
1061        all![
1062            s8_lbl.opacity.to(0.0, FADE_OUT),
1063            s8.opacity.to(0.0, FADE_OUT),
1064            s8.scale.to(Vec2::splat(0.95), FADE_OUT),
1065            s8_g_start.opacity.to(0.0, FADE_OUT),
1066            s8_g_end.opacity.to(0.0, FADE_OUT),
1067            s8_g_line.opacity.to(0.0, FADE_OUT),
1068        ],
1069        // ─── 9: Solid ↔ Gradient ───
1070        all![
1071            s9_lbl.opacity.to(1.0, FADE_IN),
1072            s9.opacity.to(1.0, FADE_IN),
1073            s9.scale.to(Vec2::ONE, FADE_IN),
1074        ],
1075        wait!(1),
1076        // Morph: solid white -> sunset (diagonal gradient) + fade in guides
1077        all![
1078            s9.fill_paint.to(Paint::Gradient(sunset.clone()), MORPH),
1079            s9_g_start.opacity.to(1.0, MORPH),
1080            s9_g_end.opacity.to(1.0, MORPH),
1081            s9_g_line.opacity.to(1.0, MORPH),
1082        ],
1083        wait!(1),
1084        // Morph: sunset -> solid white + fade out guides
1085        all![
1086            s9.fill_paint.to(Paint::Solid(Color::WHITE), MORPH),
1087            s9_g_start.opacity.to(0.0, MORPH),
1088            s9_g_end.opacity.to(0.0, MORPH),
1089            s9_g_line.opacity.to(0.0, MORPH),
1090        ],
1091        wait!(1),
1092        all![
1093            s9_lbl.opacity.to(0.0, FADE_OUT),
1094            s9.opacity.to(0.0, FADE_OUT),
1095            s9.scale.to(Vec2::splat(0.95), FADE_OUT),
1096        ],
1097        // ─── 10: Radial ↔ Linear Morph ───
1098        all![
1099            s10_lbl.opacity.to(1.0, FADE_IN),
1100            s10.opacity.to(1.0, FADE_IN),
1101            s10.scale.to(Vec2::ONE, FADE_IN),
1102            s10_g_rad_center.opacity.to(1.0, FADE_IN),
1103            s10_g_rad_radius.opacity.to(1.0, FADE_IN),
1104        ],
1105        wait!(1),
1106        // Morph Radial (glow) to Linear (sunset) + cross-fade the visual guides
1107        all![
1108            s10.fill_paint.to(Paint::Gradient(sunset.clone()), MORPH),
1109            s10_g_rad_center.opacity.to(0.0, MORPH),
1110            s10_g_rad_radius.opacity.to(0.0, MORPH),
1111            s10_g_lin_start.opacity.to(1.0, MORPH),
1112            s10_g_lin_end.opacity.to(1.0, MORPH),
1113            s10_g_lin_line.opacity.to(1.0, MORPH),
1114        ],
1115        wait!(1),
1116        // Morph back from Linear (sunset) to Radial (glow)
1117        all![
1118            s10.fill_paint.to(Paint::Gradient(glow.clone()), MORPH),
1119            s10_g_rad_center.opacity.to(1.0, MORPH),
1120            s10_g_rad_radius.opacity.to(1.0, MORPH),
1121            s10_g_lin_start.opacity.to(0.0, MORPH),
1122            s10_g_lin_end.opacity.to(0.0, MORPH),
1123            s10_g_lin_line.opacity.to(0.0, MORPH),
1124        ],
1125        wait!(1),
1126        // Fade everything out
1127        all![
1128            s10_lbl.opacity.to(0.0, FADE_OUT),
1129            s10.opacity.to(0.0, FADE_OUT),
1130            s10_g_rad_center.opacity.to(0.0, FADE_OUT),
1131            s10_g_rad_radius.opacity.to(0.0, FADE_OUT),
1132            title.opacity.to(0.0, FADE_OUT),
1133            grid.opacity.to(0.0, FADE_OUT),
1134        ],
1135    ]);
1136
1137    project.show().expect("Failed to render animation");
1138}
examples/world_map.rs (line 138)
138const SKY_BG: Color = Color::rgb8(0xcf, 0xe5, 0xe8);
examples/math_animation.rs (line 17)
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(&tex);
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}
Source

pub const fn rgba8(r: u8, g: u8, b: u8, a: u8) -> Color

Creates a new RGBA color.

Examples found in repository?
examples/gradient_demo.rs (line 87)
87const GRID_COLOR: Color = Color::rgba8(0x20, 0x20, 0x38, 60);
88const LABEL: Color = Color::rgb8(0x99, 0x99, 0xbb);
89
90// Timing
91const FADE_IN: Duration = Duration::from_millis(500);
92const FADE_OUT: Duration = Duration::from_millis(300);
93const MORPH: Duration = Duration::from_millis(1800);
94
95fn main() {
96    let cx = 960.0_f32;
97    let cy = 480.0_f32;
98
99    let mut project = Project::default()
100        .with_dimensions(1920, 1080)
101        .with_cache(true)
102        .with_title("Gradient Demo")
103        .close_on_finish();
104
105    // Background
106    let bg_rect = Rect::default()
107        .with_position(Vec2::new(cx, 540.0))
108        .with_size(Vec2::new(1920.0, 1080.0))
109        .with_fill(BG);
110
111    let grid = GridNode::default()
112        .with_position(Vec2::new(cx, 540.0))
113        .with_columns(32.0)
114        .with_rows(18.0)
115        .with_spacing_all(60.0)
116        .with_stroke(GRID_COLOR, 1.0)
117        .with_opacity(0.0);
118
119    // Gradients
120    let sunset = tri_grad(CORAL, PINK, VIOLET, 120.0);
121    let ocean = linear_grad(CYAN, INDIGO, 120.0);
122    let glow = radial_grad(FUCHSIA, Color::rgba8(0x4f, 0x46, 0xe5, 0), 130.0);
123    let glow_alt = radial_grad(CYAN, Color::rgba8(0x00, 0xf2, 0xfe, 0), 180.0);
124
125    // Sunset in different directions (same colors, different orientation)
126    let sunset_stops = vec![
127        ColorStop {
128            offset: 0.0,
129            color: CORAL,
130        },
131        ColorStop {
132            offset: 0.5,
133            color: PINK,
134        },
135        ColorStop {
136            offset: 1.0,
137            color: VIOLET,
138        },
139    ];
140    let sunset_horiz = directed_grad(
141        Point::new(-120.0, 0.0),
142        Point::new(120.0, 0.0),
143        sunset_stops.clone(),
144    );
145    let sunset_vert = directed_grad(
146        Point::new(0.0, -120.0),
147        Point::new(0.0, 120.0),
148        sunset_stops.clone(),
149    );
150    let sunset_diag = directed_grad(
151        Point::new(-120.0, -120.0),
152        Point::new(120.0, 120.0),
153        sunset_stops.clone(),
154    );
155
156    // Ocean in different directions
157    let ocean_stops = vec![
158        ColorStop {
159            offset: 0.0,
160            color: CYAN,
161        },
162        ColorStop {
163            offset: 1.0,
164            color: INDIGO,
165        },
166    ];
167    let ocean_vert = directed_grad(
168        Point::new(0.0, -120.0),
169        Point::new(0.0, 120.0),
170        ocean_stops.clone(),
171    );
172
173    // Persistent title
174    let title = TextNode::default()
175        .with_position(Vec2::new(cx, 100.0))
176        .with_text("Gradient Paint Demo")
177        .with_font_size(48.0)
178        .with_fill(Color::rgb8(0xdd, 0xdd, 0xee))
179        .with_opacity(0.0);
180
181    // Per-scene label (reused position, swapped text via separate nodes)
182    let label_y = 200.0;
183
184    // ─── SCENE 1: Circle with linear gradient fill ───
185    let s1_lbl = TextNode::default()
186        .with_position(Vec2::new(cx, label_y))
187        .with_text("Linear Gradient Fill")
188        .with_font_size(28.0)
189        .with_fill(LABEL)
190        .with_opacity(0.0);
191
192    let s1 = Circle::default()
193        .with_position(Vec2::new(cx, cy))
194        .with_radius(130.0)
195        .with_fill(sunset.clone())
196        .with_stroke(Color::rgba8(0xff, 0xff, 0xff, 20), 2.0)
197        .with_scale(0.95)
198        .with_opacity(0.0);
199
200    // Guides
201    let s1_g_start = Circle::default()
202        .with_position(Vec2::new(cx - 120.0, cy - 120.0))
203        .with_radius(8.0)
204        .with_fill(Color::WHITE)
205        .with_stroke(CORAL, 2.5)
206        .with_opacity(0.0);
207
208    let s1_g_end = Circle::default()
209        .with_position(Vec2::new(cx + 120.0, cy + 120.0))
210        .with_radius(8.0)
211        .with_fill(Color::WHITE)
212        .with_stroke(VIOLET, 2.5)
213        .with_opacity(0.0);
214
215    let s1_g_line = Line::default()
216        .with_position(Vec2::new(cx, cy))
217        .with_start(Vec2::new(-120.0, -120.0))
218        .with_end(Vec2::new(120.0, 120.0))
219        .with_stroke(Color::rgba8(0xff, 0xff, 0xff, 80), 1.5)
220        .with_opacity(0.0);
221
222    // ─── SCENE 2: Rect with radial gradient fill ───
223    let s2_lbl = TextNode::default()
224        .with_position(Vec2::new(cx, label_y))
225        .with_text("Radial Gradient Fill")
226        .with_font_size(28.0)
227        .with_fill(LABEL)
228        .with_opacity(0.0);
229
230    let s2 = Rect::default()
231        .with_position(Vec2::new(cx, cy))
232        .with_size(Vec2::new(260.0, 260.0))
233        .with_radius(24.0)
234        .with_fill(glow.clone())
235        .with_stroke(Color::rgba8(0xff, 0xff, 0xff, 20), 2.0)
236        .with_scale(0.95)
237        .with_opacity(0.0);
238
239    // Guides
240    let s2_g_center = Circle::default()
241        .with_position(Vec2::new(cx, cy))
242        .with_radius(8.0)
243        .with_fill(Color::WHITE)
244        .with_stroke(FUCHSIA, 2.5)
245        .with_opacity(0.0);
246
247    let s2_g_radius = Circle::default()
248        .with_position(Vec2::new(cx, cy))
249        .with_radius(130.0)
250        .with_fill(Color::TRANSPARENT)
251        .with_stroke(Color::rgba8(0xff, 0x00, 0x7f, 80), 1.5)
252        .with_opacity(0.0);
253
254    // ─── SCENE 3: Hexagon with gradient stroke ───
255    let s3_lbl = TextNode::default()
256        .with_position(Vec2::new(cx, label_y))
257        .with_text("Gradient Stroke")
258        .with_font_size(28.0)
259        .with_fill(LABEL)
260        .with_opacity(0.0);
261
262    let s3 = Polygon::regular(6, 130.0)
263        .with_position(Vec2::new(cx, cy))
264        .with_fill(Color::rgba8(0x12, 0x12, 0x20, 255))
265        .with_stroke(ocean.clone(), 5.0)
266        .with_scale(0.95)
267        .with_opacity(0.0);
268
269    // Guides
270    let s3_g_start = Circle::default()
271        .with_position(Vec2::new(cx - 120.0, cy))
272        .with_radius(8.0)
273        .with_fill(Color::WHITE)
274        .with_stroke(CYAN, 2.5)
275        .with_opacity(0.0);
276
277    let s3_g_end = Circle::default()
278        .with_position(Vec2::new(cx + 120.0, cy))
279        .with_radius(8.0)
280        .with_fill(Color::WHITE)
281        .with_stroke(INDIGO, 2.5)
282        .with_opacity(0.0);
283
284    let s3_g_line = Line::default()
285        .with_position(Vec2::new(cx, cy))
286        .with_start(Vec2::new(-120.0, 0.0))
287        .with_end(Vec2::new(120.0, 0.0))
288        .with_stroke(Color::rgba8(0xff, 0xff, 0xff, 80), 1.5)
289        .with_opacity(0.0);
290
291    // ─── SCENE 4: Line with gradient stroke ───
292    let s4_lbl = TextNode::default()
293        .with_position(Vec2::new(cx, label_y))
294        .with_text("Gradient Line")
295        .with_font_size(28.0)
296        .with_fill(LABEL)
297        .with_opacity(0.0);
298
299    let s4 = Line::default()
300        .with_position(Vec2::new(cx, cy))
301        .with_start(Vec2::new(-160.0, 100.0))
302        .with_end(Vec2::new(160.0, -100.0))
303        .with_stroke(sunset.clone(), 8.0)
304        .with_opacity(0.0);
305
306    // Guides
307    let s4_g_start = Circle::default()
308        .with_position(Vec2::new(cx - 120.0, cy - 120.0))
309        .with_radius(8.0)
310        .with_fill(Color::WHITE)
311        .with_stroke(CORAL, 2.5)
312        .with_opacity(0.0);
313
314    let s4_g_end = Circle::default()
315        .with_position(Vec2::new(cx + 120.0, cy + 120.0))
316        .with_radius(8.0)
317        .with_fill(Color::WHITE)
318        .with_stroke(VIOLET, 2.5)
319        .with_opacity(0.0);
320
321    let s4_g_line = Line::default()
322        .with_position(Vec2::new(cx, cy))
323        .with_start(Vec2::new(-120.0, -120.0))
324        .with_end(Vec2::new(120.0, 120.0))
325        .with_stroke(Color::rgba8(0xff, 0xff, 0xff, 80), 1.5)
326        .with_opacity(0.0);
327
328    // ─── SCENE 5: Path with gradient stroke ───
329    let s5_lbl = TextNode::default()
330        .with_position(Vec2::new(cx, label_y))
331        .with_text("Gradient Path")
332        .with_font_size(28.0)
333        .with_fill(LABEL)
334        .with_opacity(0.0);
335
336    let mut tri_path = BezPath::new();
337    tri_path.move_to(kurbo::Point::new(0.0, -120.0));
338    tri_path.line_to(kurbo::Point::new(104.0, 60.0));
339    tri_path.line_to(kurbo::Point::new(-104.0, 60.0));
340    tri_path.close_path();
341
342    let s5 = PathNode::new(Vec2::new(cx, cy), tri_path, CYAN, 6.0)
343        .with_stroke(ocean.clone(), 6.0)
344        .with_opacity(0.0);
345
346    // Guides
347    let s5_g_start = Circle::default()
348        .with_position(Vec2::new(cx - 120.0, cy))
349        .with_radius(8.0)
350        .with_fill(Color::WHITE)
351        .with_stroke(CYAN, 2.5)
352        .with_opacity(0.0);
353
354    let s5_g_end = Circle::default()
355        .with_position(Vec2::new(cx + 120.0, cy))
356        .with_radius(8.0)
357        .with_fill(Color::WHITE)
358        .with_stroke(INDIGO, 2.5)
359        .with_opacity(0.0);
360
361    let s5_g_line = Line::default()
362        .with_position(Vec2::new(cx, cy))
363        .with_start(Vec2::new(-120.0, 0.0))
364        .with_end(Vec2::new(120.0, 0.0))
365        .with_stroke(Color::rgba8(0xff, 0xff, 0xff, 80), 1.5)
366        .with_opacity(0.0);
367
368    // ─── SCENE 6: Grid with gradient stroke ───
369    let s6_lbl = TextNode::default()
370        .with_position(Vec2::new(cx, label_y))
371        .with_text("Gradient Grid")
372        .with_font_size(28.0)
373        .with_fill(LABEL)
374        .with_opacity(0.0);
375
376    let s6_grid = GridNode::default()
377        .with_position(Vec2::new(cx, cy))
378        .with_columns(8.0)
379        .with_rows(6.0)
380        .with_spacing_all(50.0)
381        .with_stroke(ocean.clone(), 2.0)
382        .with_opacity(0.0);
383
384    // Guides
385    let s6_g_start = Circle::default()
386        .with_position(Vec2::new(cx - 120.0, cy))
387        .with_radius(8.0)
388        .with_fill(Color::WHITE)
389        .with_stroke(CYAN, 2.5)
390        .with_opacity(0.0);
391
392    let s6_g_end = Circle::default()
393        .with_position(Vec2::new(cx + 120.0, cy))
394        .with_radius(8.0)
395        .with_fill(Color::WHITE)
396        .with_stroke(INDIGO, 2.5)
397        .with_opacity(0.0);
398
399    let s6_g_line = Line::default()
400        .with_position(Vec2::new(cx, cy))
401        .with_start(Vec2::new(-120.0, 0.0))
402        .with_end(Vec2::new(120.0, 0.0))
403        .with_stroke(Color::rgba8(0xff, 0xff, 0xff, 80), 1.5)
404        .with_opacity(0.0);
405
406    // ─── SCENE 7: Text with gradient fill ───
407    let s7_lbl = TextNode::default()
408        .with_position(Vec2::new(cx, label_y))
409        .with_text("Gradient Text")
410        .with_font_size(28.0)
411        .with_fill(LABEL)
412        .with_opacity(0.0);
413
414    let s7 = TextNode::default()
415        .with_position(Vec2::new(cx, cy))
416        .with_text("HELLO GRADIENTS")
417        .with_font_size(80.0)
418        .with_fill(ocean.clone())
419        .with_scale(0.95)
420        .with_opacity(0.0);
421
422    // Guides
423    let s7_g_start = Circle::default()
424        .with_position(Vec2::new(cx - 120.0, cy))
425        .with_radius(8.0)
426        .with_fill(Color::WHITE)
427        .with_stroke(CYAN, 2.5)
428        .with_opacity(0.0);
429
430    let s7_g_end = Circle::default()
431        .with_position(Vec2::new(cx + 120.0, cy))
432        .with_radius(8.0)
433        .with_fill(Color::WHITE)
434        .with_stroke(INDIGO, 2.5)
435        .with_opacity(0.0);
436
437    let s7_g_line = Line::default()
438        .with_position(Vec2::new(cx, cy))
439        .with_start(Vec2::new(-120.0, 0.0))
440        .with_end(Vec2::new(120.0, 0.0))
441        .with_stroke(Color::rgba8(0xff, 0xff, 0xff, 80), 1.5)
442        .with_opacity(0.0);
443
444    // ─── SCENE 8: Math with gradient fill ───
445    let s8_lbl = TextNode::default()
446        .with_position(Vec2::new(cx, label_y))
447        .with_text("Gradient Math")
448        .with_font_size(28.0)
449        .with_fill(LABEL)
450        .with_opacity(0.0);
451
452    let s8 = MathNode::default()
453        .with_position(Vec2::new(cx, cy))
454        .with_equation("E = m c^2")
455        .with_font_size(72.0)
456        .with_fill(sunset.clone())
457        .with_scale(0.95)
458        .with_opacity(0.0);
459
460    // Guides
461    let s8_g_start = Circle::default()
462        .with_position(Vec2::new(cx - 120.0, cy - 120.0))
463        .with_radius(8.0)
464        .with_fill(Color::WHITE)
465        .with_stroke(CORAL, 2.5)
466        .with_opacity(0.0);
467
468    let s8_g_end = Circle::default()
469        .with_position(Vec2::new(cx + 120.0, cy + 120.0))
470        .with_radius(8.0)
471        .with_fill(Color::WHITE)
472        .with_stroke(VIOLET, 2.5)
473        .with_opacity(0.0);
474
475    let s8_g_line = Line::default()
476        .with_position(Vec2::new(cx, cy))
477        .with_start(Vec2::new(-120.0, -120.0))
478        .with_end(Vec2::new(120.0, 120.0))
479        .with_stroke(Color::rgba8(0xff, 0xff, 0xff, 80), 1.5)
480        .with_opacity(0.0);
481
482    // ─── SCENE 9: Solid ↔ Gradient ───
483    let s9_lbl = TextNode::default()
484        .with_position(Vec2::new(cx, label_y))
485        .with_text("Solid to Gradient")
486        .with_font_size(28.0)
487        .with_fill(LABEL)
488        .with_opacity(0.0);
489
490    let s9 = Circle::default()
491        .with_position(Vec2::new(cx, cy))
492        .with_radius(130.0)
493        .with_fill(Color::WHITE)
494        .with_stroke(Color::rgba8(0xff, 0xff, 0xff, 20), 2.0)
495        .with_scale(0.95)
496        .with_opacity(0.0);
497
498    // Guides (start with opacity 0, fade in when Sunset is active, fade out on Solid)
499    let s9_g_start = Circle::default()
500        .with_position(Vec2::new(cx - 120.0, cy - 120.0))
501        .with_radius(8.0)
502        .with_fill(Color::WHITE)
503        .with_stroke(CORAL, 2.5)
504        .with_opacity(0.0);
505
506    let s9_g_end = Circle::default()
507        .with_position(Vec2::new(cx + 120.0, cy + 120.0))
508        .with_radius(8.0)
509        .with_fill(Color::WHITE)
510        .with_stroke(VIOLET, 2.5)
511        .with_opacity(0.0);
512
513    let s9_g_line = Line::default()
514        .with_position(Vec2::new(cx, cy))
515        .with_start(Vec2::new(-120.0, -120.0))
516        .with_end(Vec2::new(120.0, 120.0))
517        .with_stroke(Color::rgba8(0xff, 0xff, 0xff, 80), 1.5)
518        .with_opacity(0.0);
519
520    // ─── SCENE 10: Radial ↔ Linear Interpolation ───
521    let s10_lbl = TextNode::default()
522        .with_position(Vec2::new(cx, label_y))
523        .with_text("Radial ↔ Linear Morph")
524        .with_font_size(28.0)
525        .with_fill(LABEL)
526        .with_opacity(0.0);
527
528    let s10 = Circle::default()
529        .with_position(Vec2::new(cx, cy))
530        .with_radius(130.0)
531        .with_fill(glow.clone()) // Start as Radial Gradient
532        .with_stroke(Color::rgba8(0xff, 0xff, 0xff, 20), 2.0)
533        .with_scale(0.95)
534        .with_opacity(0.0);
535
536    // Visual guides for Scene 10 (cross-fading between radial and linear handles)
537    let s10_g_rad_center = Circle::default()
538        .with_position(Vec2::new(cx, cy))
539        .with_radius(8.0)
540        .with_fill(Color::WHITE)
541        .with_stroke(FUCHSIA, 2.5)
542        .with_opacity(0.0);
543
544    let s10_g_rad_radius = Circle::default()
545        .with_position(Vec2::new(cx, cy))
546        .with_radius(130.0)
547        .with_fill(Color::TRANSPARENT)
548        .with_stroke(Color::rgba8(0xff, 0x00, 0x7f, 80), 1.5)
549        .with_opacity(0.0);
550
551    let s10_g_lin_start = Circle::default()
552        .with_position(Vec2::new(cx - 120.0, cy - 120.0))
553        .with_radius(8.0)
554        .with_fill(Color::WHITE)
555        .with_stroke(CORAL, 2.5)
556        .with_opacity(0.0);
557
558    let s10_g_lin_end = Circle::default()
559        .with_position(Vec2::new(cx + 120.0, cy + 120.0))
560        .with_radius(8.0)
561        .with_fill(Color::WHITE)
562        .with_stroke(VIOLET, 2.5)
563        .with_opacity(0.0);
564
565    let s10_g_lin_line = Line::default()
566        .with_position(Vec2::new(cx, cy))
567        .with_start(Vec2::new(-120.0, -120.0))
568        .with_end(Vec2::new(120.0, 120.0))
569        .with_stroke(Color::rgba8(0xff, 0xff, 0xff, 80), 1.5)
570        .with_opacity(0.0);
571
572    // Add all to scene
573    project.scene.add(&bg_rect);
574    project.scene.add(&grid);
575    project.scene.add(&title);
576
577    // Scene 1
578    project.scene.add(&s1_lbl);
579    project.scene.add(&s1);
580    project.scene.add(&s1_g_line);
581    project.scene.add(&s1_g_start);
582    project.scene.add(&s1_g_end);
583
584    // Scene 2
585    project.scene.add(&s2_lbl);
586    project.scene.add(&s2);
587    project.scene.add(&s2_g_radius);
588    project.scene.add(&s2_g_center);
589
590    // Scene 3
591    project.scene.add(&s3_lbl);
592    project.scene.add(&s3);
593    project.scene.add(&s3_g_line);
594    project.scene.add(&s3_g_start);
595    project.scene.add(&s3_g_end);
596
597    // Scene 4
598    project.scene.add(&s4_lbl);
599    project.scene.add(&s4);
600    project.scene.add(&s4_g_line);
601    project.scene.add(&s4_g_start);
602    project.scene.add(&s4_g_end);
603
604    // Scene 5
605    project.scene.add(&s5_lbl);
606    project.scene.add(&s5);
607    project.scene.add(&s5_g_line);
608    project.scene.add(&s5_g_start);
609    project.scene.add(&s5_g_end);
610
611    // Scene 6
612    project.scene.add(&s6_lbl);
613    project.scene.add(&s6_grid);
614    project.scene.add(&s6_g_line);
615    project.scene.add(&s6_g_start);
616    project.scene.add(&s6_g_end);
617
618    // Scene 7
619    project.scene.add(&s7_lbl);
620    project.scene.add(&s7);
621    project.scene.add(&s7_g_line);
622    project.scene.add(&s7_g_start);
623    project.scene.add(&s7_g_end);
624
625    // Scene 8
626    project.scene.add(&s8_lbl);
627    project.scene.add(&s8);
628    project.scene.add(&s8_g_line);
629    project.scene.add(&s8_g_start);
630    project.scene.add(&s8_g_end);
631
632    // Scene 9
633    project.scene.add(&s9_lbl);
634    project.scene.add(&s9);
635    project.scene.add(&s9_g_line);
636    project.scene.add(&s9_g_start);
637    project.scene.add(&s9_g_end);
638
639    // Scene 10
640    project.scene.add(&s10_lbl);
641    project.scene.add(&s10);
642    project.scene.add(&s10_g_rad_radius);
643    project.scene.add(&s10_g_rad_center);
644    project.scene.add(&s10_g_lin_line);
645    project.scene.add(&s10_g_lin_start);
646    project.scene.add(&s10_g_lin_end);
647
648    // Timeline — one scene at a time, each with its own gradient animation
649    project.scene.video_timeline.add(chain![
650        // Intro
651        all![
652            grid.opacity.to(1.0, Duration::from_millis(800)),
653            title.opacity.to(1.0, Duration::from_millis(800)),
654        ],
655        wait!(1),
656        // ─── 1: Circle linear fill — morph colors, then direction ───
657        all![
658            s1_lbl.opacity.to(1.0, FADE_IN),
659            s1.opacity.to(1.0, FADE_IN),
660            s1.scale.to(Vec2::ONE, FADE_IN),
661            s1_g_start.opacity.to(1.0, FADE_IN),
662            s1_g_end.opacity.to(1.0, FADE_IN),
663            s1_g_line.opacity.to(1.0, FADE_IN),
664        ],
665        wait!(1),
666        // Color morph: sunset → ocean
667        all![
668            s1.fill_paint.to(Paint::Gradient(ocean.clone()), MORPH),
669            s1_g_start.position.to(Vec2::new(cx - 120.0, cy), MORPH),
670            s1_g_end.position.to(Vec2::new(cx + 120.0, cy), MORPH),
671            s1_g_line.start.to(Vec2::new(-120.0, 0.0), MORPH),
672            s1_g_line.end.to(Vec2::new(120.0, 0.0), MORPH),
673            s1_g_start.stroke_paint.to(Paint::Solid(CYAN), MORPH),
674            s1_g_end.stroke_paint.to(Paint::Solid(INDIGO), MORPH),
675        ],
676        wait!(1),
677        // Color morph: ocean → sunset
678        all![
679            s1.fill_paint.to(Paint::Gradient(sunset.clone()), MORPH),
680            s1_g_start
681                .position
682                .to(Vec2::new(cx - 120.0, cy - 120.0), MORPH),
683            s1_g_end
684                .position
685                .to(Vec2::new(cx + 120.0, cy + 120.0), MORPH),
686            s1_g_line.start.to(Vec2::new(-120.0, -120.0), MORPH),
687            s1_g_line.end.to(Vec2::new(120.0, 120.0), MORPH),
688            s1_g_start.stroke_paint.to(Paint::Solid(CORAL), MORPH),
689            s1_g_end.stroke_paint.to(Paint::Solid(VIOLET), MORPH),
690        ],
691        wait!(1),
692        // Direction morph: diagonal → horizontal sunset
693        all![
694            s1.fill_paint
695                .to(Paint::Gradient(sunset_horiz.clone()), MORPH),
696            s1_g_start.position.to(Vec2::new(cx - 120.0, cy), MORPH),
697            s1_g_end.position.to(Vec2::new(cx + 120.0, cy), MORPH),
698            s1_g_line.start.to(Vec2::new(-120.0, 0.0), MORPH),
699            s1_g_line.end.to(Vec2::new(120.0, 0.0), MORPH),
700        ],
701        wait!(1),
702        // Direction morph: horizontal → vertical sunset
703        all![
704            s1.fill_paint
705                .to(Paint::Gradient(sunset_vert.clone()), MORPH),
706            s1_g_start.position.to(Vec2::new(cx, cy - 120.0), MORPH),
707            s1_g_end.position.to(Vec2::new(cx, cy + 120.0), MORPH),
708            s1_g_line.start.to(Vec2::new(0.0, -120.0), MORPH),
709            s1_g_line.end.to(Vec2::new(0.0, 120.0), MORPH),
710        ],
711        wait!(1),
712        // Direction morph: vertical → diagonal sunset
713        all![
714            s1.fill_paint
715                .to(Paint::Gradient(sunset_diag.clone()), MORPH),
716            s1_g_start
717                .position
718                .to(Vec2::new(cx - 120.0, cy - 120.0), MORPH),
719            s1_g_end
720                .position
721                .to(Vec2::new(cx + 120.0, cy + 120.0), MORPH),
722            s1_g_line.start.to(Vec2::new(-120.0, -120.0), MORPH),
723            s1_g_line.end.to(Vec2::new(120.0, 120.0), MORPH),
724        ],
725        wait!(1),
726        all![
727            s1_lbl.opacity.to(0.0, FADE_OUT),
728            s1.opacity.to(0.0, FADE_OUT),
729            s1.scale.to(Vec2::splat(0.95), FADE_OUT),
730            s1_g_start.opacity.to(0.0, FADE_OUT),
731            s1_g_end.opacity.to(0.0, FADE_OUT),
732            s1_g_line.opacity.to(0.0, FADE_OUT),
733        ],
734        // ─── 2: Rect radial fill — morph to another radial gradient and back ───
735        all![
736            s2_lbl.opacity.to(1.0, FADE_IN),
737            s2.opacity.to(1.0, FADE_IN),
738            s2.scale.to(Vec2::ONE, FADE_IN),
739            s2_g_center.opacity.to(1.0, FADE_IN),
740            s2_g_radius.opacity.to(1.0, FADE_IN),
741        ],
742        wait!(1),
743        // Radial color and radius morph: glow (Fuchsia 130px) -> glow_alt (Cyan 180px)
744        all![
745            s2.fill_paint.to(Paint::Gradient(glow_alt.clone()), MORPH),
746            s2_g_radius.radius.to(180.0, MORPH),
747            s2_g_center.stroke_paint.to(Paint::Solid(CYAN), MORPH),
748            s2_g_radius
749                .stroke_paint
750                .to(Paint::Solid(Color::rgba8(0x00, 0xf2, 0xfe, 80)), MORPH),
751        ],
752        wait!(1),
753        // Morph back to glow
754        all![
755            s2.fill_paint.to(Paint::Gradient(glow.clone()), MORPH),
756            s2_g_radius.radius.to(130.0, MORPH),
757            s2_g_center.stroke_paint.to(Paint::Solid(FUCHSIA), MORPH),
758            s2_g_radius
759                .stroke_paint
760                .to(Paint::Solid(Color::rgba8(0xff, 0x00, 0x7f, 80)), MORPH),
761        ],
762        wait!(1),
763        all![
764            s2_lbl.opacity.to(0.0, FADE_OUT),
765            s2.opacity.to(0.0, FADE_OUT),
766            s2.scale.to(Vec2::splat(0.95), FADE_OUT),
767            s2_g_center.opacity.to(0.0, FADE_OUT),
768            s2_g_radius.opacity.to(0.0, FADE_OUT),
769        ],
770        // ─── 3: Hex gradient stroke — morph colors, then direction ───
771        all![
772            s3_lbl.opacity.to(1.0, FADE_IN),
773            s3.opacity.to(1.0, FADE_IN),
774            s3.scale.to(Vec2::ONE, FADE_IN),
775            s3_g_start.opacity.to(1.0, FADE_IN),
776            s3_g_end.opacity.to(1.0, FADE_IN),
777            s3_g_line.opacity.to(1.0, FADE_IN),
778        ],
779        wait!(1),
780        // Morph: ocean (horizontal) -> sunset (diagonal)
781        all![
782            s3.stroke_paint.to(Paint::Gradient(sunset.clone()), MORPH),
783            s3_g_start
784                .position
785                .to(Vec2::new(cx - 120.0, cy - 120.0), MORPH),
786            s3_g_end
787                .position
788                .to(Vec2::new(cx + 120.0, cy + 120.0), MORPH),
789            s3_g_line.start.to(Vec2::new(-120.0, -120.0), MORPH),
790            s3_g_line.end.to(Vec2::new(120.0, 120.0), MORPH),
791            s3_g_start.stroke_paint.to(Paint::Solid(CORAL), MORPH),
792            s3_g_end.stroke_paint.to(Paint::Solid(VIOLET), MORPH),
793        ],
794        wait!(1),
795        // Morph: sunset (diagonal) -> ocean (horizontal)
796        all![
797            s3.stroke_paint.to(Paint::Gradient(ocean.clone()), MORPH),
798            s3_g_start.position.to(Vec2::new(cx - 120.0, cy), MORPH),
799            s3_g_end.position.to(Vec2::new(cx + 120.0, cy), MORPH),
800            s3_g_line.start.to(Vec2::new(-120.0, 0.0), MORPH),
801            s3_g_line.end.to(Vec2::new(120.0, 0.0), MORPH),
802            s3_g_start.stroke_paint.to(Paint::Solid(CYAN), MORPH),
803            s3_g_end.stroke_paint.to(Paint::Solid(INDIGO), MORPH),
804        ],
805        wait!(1),
806        // Direction morph: horizontal ocean -> vertical ocean
807        all![
808            s3.stroke_paint
809                .to(Paint::Gradient(ocean_vert.clone()), MORPH),
810            s3_g_start.position.to(Vec2::new(cx, cy - 120.0), MORPH),
811            s3_g_end.position.to(Vec2::new(cx, cy + 120.0), MORPH),
812            s3_g_line.start.to(Vec2::new(0.0, -120.0), MORPH),
813            s3_g_line.end.to(Vec2::new(0.0, 120.0), MORPH),
814        ],
815        wait!(1),
816        // Direction morph: vertical ocean -> horizontal ocean
817        all![
818            s3.stroke_paint.to(Paint::Gradient(ocean.clone()), MORPH),
819            s3_g_start.position.to(Vec2::new(cx - 120.0, cy), MORPH),
820            s3_g_end.position.to(Vec2::new(cx + 120.0, cy), MORPH),
821            s3_g_line.start.to(Vec2::new(-120.0, 0.0), MORPH),
822            s3_g_line.end.to(Vec2::new(120.0, 0.0), MORPH),
823        ],
824        wait!(1),
825        all![
826            s3_lbl.opacity.to(0.0, FADE_OUT),
827            s3.opacity.to(0.0, FADE_OUT),
828            s3.scale.to(Vec2::splat(0.95), FADE_OUT),
829            s3_g_start.opacity.to(0.0, FADE_OUT),
830            s3_g_end.opacity.to(0.0, FADE_OUT),
831            s3_g_line.opacity.to(0.0, FADE_OUT),
832        ],
833        // ─── 4: Line gradient stroke ───
834        all![
835            s4_lbl.opacity.to(1.0, FADE_IN),
836            s4.opacity.to(1.0, FADE_IN),
837            s4_g_start.opacity.to(1.0, FADE_IN),
838            s4_g_end.opacity.to(1.0, FADE_IN),
839            s4_g_line.opacity.to(1.0, FADE_IN),
840        ],
841        wait!(1),
842        // Morph: sunset (diagonal) -> ocean (horizontal)
843        all![
844            s4.stroke_paint.to(Paint::Gradient(ocean.clone()), MORPH),
845            s4_g_start.position.to(Vec2::new(cx - 120.0, cy), MORPH),
846            s4_g_end.position.to(Vec2::new(cx + 120.0, cy), MORPH),
847            s4_g_line.start.to(Vec2::new(-120.0, 0.0), MORPH),
848            s4_g_line.end.to(Vec2::new(120.0, 0.0), MORPH),
849            s4_g_start.stroke_paint.to(Paint::Solid(CYAN), MORPH),
850            s4_g_end.stroke_paint.to(Paint::Solid(INDIGO), MORPH),
851        ],
852        wait!(1),
853        // Morph: ocean (horizontal) -> sunset (diagonal)
854        all![
855            s4.stroke_paint.to(Paint::Gradient(sunset.clone()), MORPH),
856            s4_g_start
857                .position
858                .to(Vec2::new(cx - 120.0, cy - 120.0), MORPH),
859            s4_g_end
860                .position
861                .to(Vec2::new(cx + 120.0, cy + 120.0), MORPH),
862            s4_g_line.start.to(Vec2::new(-120.0, -120.0), MORPH),
863            s4_g_line.end.to(Vec2::new(120.0, 120.0), MORPH),
864            s4_g_start.stroke_paint.to(Paint::Solid(CORAL), MORPH),
865            s4_g_end.stroke_paint.to(Paint::Solid(VIOLET), MORPH),
866        ],
867        wait!(1),
868        all![
869            s4_lbl.opacity.to(0.0, FADE_OUT),
870            s4.opacity.to(0.0, FADE_OUT),
871            s4_g_start.opacity.to(0.0, FADE_OUT),
872            s4_g_end.opacity.to(0.0, FADE_OUT),
873            s4_g_line.opacity.to(0.0, FADE_OUT),
874        ],
875        // ─── 5: Path gradient stroke ───
876        all![
877            s5_lbl.opacity.to(1.0, FADE_IN),
878            s5.opacity.to(1.0, FADE_IN),
879            s5_g_start.opacity.to(1.0, FADE_IN),
880            s5_g_end.opacity.to(1.0, FADE_IN),
881            s5_g_line.opacity.to(1.0, FADE_IN),
882        ],
883        wait!(1),
884        // Morph: ocean (horizontal) -> sunset (diagonal)
885        all![
886            s5.stroke_paint.to(Paint::Gradient(sunset.clone()), MORPH),
887            s5_g_start
888                .position
889                .to(Vec2::new(cx - 120.0, cy - 120.0), MORPH),
890            s5_g_end
891                .position
892                .to(Vec2::new(cx + 120.0, cy + 120.0), MORPH),
893            s5_g_line.start.to(Vec2::new(-120.0, -120.0), MORPH),
894            s5_g_line.end.to(Vec2::new(120.0, 120.0), MORPH),
895            s5_g_start.stroke_paint.to(Paint::Solid(CORAL), MORPH),
896            s5_g_end.stroke_paint.to(Paint::Solid(VIOLET), MORPH),
897        ],
898        wait!(1),
899        // Morph: sunset (diagonal) -> ocean (horizontal)
900        all![
901            s5.stroke_paint.to(Paint::Gradient(ocean.clone()), MORPH),
902            s5_g_start.position.to(Vec2::new(cx - 120.0, cy), MORPH),
903            s5_g_end.position.to(Vec2::new(cx + 120.0, cy), MORPH),
904            s5_g_line.start.to(Vec2::new(-120.0, 0.0), MORPH),
905            s5_g_line.end.to(Vec2::new(120.0, 0.0), MORPH),
906            s5_g_start.stroke_paint.to(Paint::Solid(CYAN), MORPH),
907            s5_g_end.stroke_paint.to(Paint::Solid(INDIGO), MORPH),
908        ],
909        wait!(1),
910        all![
911            s5_lbl.opacity.to(0.0, FADE_OUT),
912            s5.opacity.to(0.0, FADE_OUT),
913            s5_g_start.opacity.to(0.0, FADE_OUT),
914            s5_g_end.opacity.to(0.0, FADE_OUT),
915            s5_g_line.opacity.to(0.0, FADE_OUT),
916        ],
917        // ─── 6: Grid gradient stroke ───
918        all![
919            s6_lbl.opacity.to(1.0, FADE_IN),
920            s6_grid.opacity.to(1.0, FADE_IN),
921            s6_g_start.opacity.to(1.0, FADE_IN),
922            s6_g_end.opacity.to(1.0, FADE_IN),
923            s6_g_line.opacity.to(1.0, FADE_IN),
924        ],
925        wait!(1),
926        // Morph: ocean (horizontal) -> sunset (diagonal)
927        all![
928            s6_grid
929                .stroke_paint
930                .to(Paint::Gradient(sunset.clone()), MORPH),
931            s6_g_start
932                .position
933                .to(Vec2::new(cx - 120.0, cy - 120.0), MORPH),
934            s6_g_end
935                .position
936                .to(Vec2::new(cx + 120.0, cy + 120.0), MORPH),
937            s6_g_line.start.to(Vec2::new(-120.0, -120.0), MORPH),
938            s6_g_line.end.to(Vec2::new(120.0, 120.0), MORPH),
939            s6_g_start.stroke_paint.to(Paint::Solid(CORAL), MORPH),
940            s6_g_end.stroke_paint.to(Paint::Solid(VIOLET), MORPH),
941        ],
942        wait!(1),
943        // Morph: sunset (diagonal) -> ocean (horizontal)
944        all![
945            s6_grid
946                .stroke_paint
947                .to(Paint::Gradient(ocean.clone()), MORPH),
948            s6_g_start.position.to(Vec2::new(cx - 120.0, cy), MORPH),
949            s6_g_end.position.to(Vec2::new(cx + 120.0, cy), MORPH),
950            s6_g_line.start.to(Vec2::new(-120.0, 0.0), MORPH),
951            s6_g_line.end.to(Vec2::new(120.0, 0.0), MORPH),
952            s6_g_start.stroke_paint.to(Paint::Solid(CYAN), MORPH),
953            s6_g_end.stroke_paint.to(Paint::Solid(INDIGO), MORPH),
954        ],
955        wait!(1),
956        all![
957            s6_lbl.opacity.to(0.0, FADE_OUT),
958            s6_grid.opacity.to(0.0, FADE_OUT),
959            s6_g_start.opacity.to(0.0, FADE_OUT),
960            s6_g_end.opacity.to(0.0, FADE_OUT),
961            s6_g_line.opacity.to(0.0, FADE_OUT),
962        ],
963        // ─── 7: Text — morph colors, then direction ───
964        all![
965            s7_lbl.opacity.to(1.0, FADE_IN),
966            s7.opacity.to(1.0, FADE_IN),
967            s7.scale.to(Vec2::ONE, FADE_IN),
968            s7_g_start.opacity.to(1.0, FADE_IN),
969            s7_g_end.opacity.to(1.0, FADE_IN),
970            s7_g_line.opacity.to(1.0, FADE_IN),
971        ],
972        wait!(1),
973        // Morph: ocean (horizontal) -> sunset (diagonal)
974        all![
975            s7.fill_paint.to(Paint::Gradient(sunset.clone()), MORPH),
976            s7_g_start
977                .position
978                .to(Vec2::new(cx - 120.0, cy - 120.0), MORPH),
979            s7_g_end
980                .position
981                .to(Vec2::new(cx + 120.0, cy + 120.0), MORPH),
982            s7_g_line.start.to(Vec2::new(-120.0, -120.0), MORPH),
983            s7_g_line.end.to(Vec2::new(120.0, 120.0), MORPH),
984            s7_g_start.stroke_paint.to(Paint::Solid(CORAL), MORPH),
985            s7_g_end.stroke_paint.to(Paint::Solid(VIOLET), MORPH),
986        ],
987        wait!(1),
988        // Morph: sunset (diagonal) -> ocean (horizontal)
989        all![
990            s7.fill_paint.to(Paint::Gradient(ocean.clone()), MORPH),
991            s7_g_start.position.to(Vec2::new(cx - 120.0, cy), MORPH),
992            s7_g_end.position.to(Vec2::new(cx + 120.0, cy), MORPH),
993            s7_g_line.start.to(Vec2::new(-120.0, 0.0), MORPH),
994            s7_g_line.end.to(Vec2::new(120.0, 0.0), MORPH),
995            s7_g_start.stroke_paint.to(Paint::Solid(CYAN), MORPH),
996            s7_g_end.stroke_paint.to(Paint::Solid(INDIGO), MORPH),
997        ],
998        wait!(1),
999        // Morph: horizontal ocean -> vertical ocean
1000        all![
1001            s7.fill_paint.to(Paint::Gradient(ocean_vert.clone()), MORPH),
1002            s7_g_start.position.to(Vec2::new(cx, cy - 120.0), MORPH),
1003            s7_g_end.position.to(Vec2::new(cx, cy + 120.0), MORPH),
1004            s7_g_line.start.to(Vec2::new(0.0, -120.0), MORPH),
1005            s7_g_line.end.to(Vec2::new(0.0, 120.0), MORPH),
1006        ],
1007        wait!(1),
1008        // Morph: vertical ocean -> horizontal ocean
1009        all![
1010            s7.fill_paint.to(Paint::Gradient(ocean.clone()), MORPH),
1011            s7_g_start.position.to(Vec2::new(cx - 120.0, cy), MORPH),
1012            s7_g_end.position.to(Vec2::new(cx + 120.0, cy), MORPH),
1013            s7_g_line.start.to(Vec2::new(-120.0, 0.0), MORPH),
1014            s7_g_line.end.to(Vec2::new(120.0, 0.0), MORPH),
1015        ],
1016        wait!(1),
1017        all![
1018            s7_lbl.opacity.to(0.0, FADE_OUT),
1019            s7.opacity.to(0.0, FADE_OUT),
1020            s7.scale.to(Vec2::splat(0.95), FADE_OUT),
1021            s7_g_start.opacity.to(0.0, FADE_OUT),
1022            s7_g_end.opacity.to(0.0, FADE_OUT),
1023            s7_g_line.opacity.to(0.0, FADE_OUT),
1024        ],
1025        // ─── 8: Math ───
1026        all![
1027            s8_lbl.opacity.to(1.0, FADE_IN),
1028            s8.opacity.to(1.0, FADE_IN),
1029            s8.scale.to(Vec2::ONE, FADE_IN),
1030            s8_g_start.opacity.to(1.0, FADE_IN),
1031            s8_g_end.opacity.to(1.0, FADE_IN),
1032            s8_g_line.opacity.to(1.0, FADE_IN),
1033        ],
1034        wait!(1),
1035        // Morph: sunset (diagonal) -> ocean (horizontal)
1036        all![
1037            s8.fill_paint.to(Paint::Gradient(ocean.clone()), MORPH),
1038            s8_g_start.position.to(Vec2::new(cx - 120.0, cy), MORPH),
1039            s8_g_end.position.to(Vec2::new(cx + 120.0, cy), MORPH),
1040            s8_g_line.start.to(Vec2::new(-120.0, 0.0), MORPH),
1041            s8_g_line.end.to(Vec2::new(120.0, 0.0), MORPH),
1042            s8_g_start.stroke_paint.to(Paint::Solid(CYAN), MORPH),
1043            s8_g_end.stroke_paint.to(Paint::Solid(INDIGO), MORPH),
1044        ],
1045        wait!(1),
1046        // Morph: ocean (horizontal) -> sunset (diagonal)
1047        all![
1048            s8.fill_paint.to(Paint::Gradient(sunset.clone()), MORPH),
1049            s8_g_start
1050                .position
1051                .to(Vec2::new(cx - 120.0, cy - 120.0), MORPH),
1052            s8_g_end
1053                .position
1054                .to(Vec2::new(cx + 120.0, cy + 120.0), MORPH),
1055            s8_g_line.start.to(Vec2::new(-120.0, -120.0), MORPH),
1056            s8_g_line.end.to(Vec2::new(120.0, 120.0), MORPH),
1057            s8_g_start.stroke_paint.to(Paint::Solid(CORAL), MORPH),
1058            s8_g_end.stroke_paint.to(Paint::Solid(VIOLET), MORPH),
1059        ],
1060        wait!(1),
1061        all![
1062            s8_lbl.opacity.to(0.0, FADE_OUT),
1063            s8.opacity.to(0.0, FADE_OUT),
1064            s8.scale.to(Vec2::splat(0.95), FADE_OUT),
1065            s8_g_start.opacity.to(0.0, FADE_OUT),
1066            s8_g_end.opacity.to(0.0, FADE_OUT),
1067            s8_g_line.opacity.to(0.0, FADE_OUT),
1068        ],
1069        // ─── 9: Solid ↔ Gradient ───
1070        all![
1071            s9_lbl.opacity.to(1.0, FADE_IN),
1072            s9.opacity.to(1.0, FADE_IN),
1073            s9.scale.to(Vec2::ONE, FADE_IN),
1074        ],
1075        wait!(1),
1076        // Morph: solid white -> sunset (diagonal gradient) + fade in guides
1077        all![
1078            s9.fill_paint.to(Paint::Gradient(sunset.clone()), MORPH),
1079            s9_g_start.opacity.to(1.0, MORPH),
1080            s9_g_end.opacity.to(1.0, MORPH),
1081            s9_g_line.opacity.to(1.0, MORPH),
1082        ],
1083        wait!(1),
1084        // Morph: sunset -> solid white + fade out guides
1085        all![
1086            s9.fill_paint.to(Paint::Solid(Color::WHITE), MORPH),
1087            s9_g_start.opacity.to(0.0, MORPH),
1088            s9_g_end.opacity.to(0.0, MORPH),
1089            s9_g_line.opacity.to(0.0, MORPH),
1090        ],
1091        wait!(1),
1092        all![
1093            s9_lbl.opacity.to(0.0, FADE_OUT),
1094            s9.opacity.to(0.0, FADE_OUT),
1095            s9.scale.to(Vec2::splat(0.95), FADE_OUT),
1096        ],
1097        // ─── 10: Radial ↔ Linear Morph ───
1098        all![
1099            s10_lbl.opacity.to(1.0, FADE_IN),
1100            s10.opacity.to(1.0, FADE_IN),
1101            s10.scale.to(Vec2::ONE, FADE_IN),
1102            s10_g_rad_center.opacity.to(1.0, FADE_IN),
1103            s10_g_rad_radius.opacity.to(1.0, FADE_IN),
1104        ],
1105        wait!(1),
1106        // Morph Radial (glow) to Linear (sunset) + cross-fade the visual guides
1107        all![
1108            s10.fill_paint.to(Paint::Gradient(sunset.clone()), MORPH),
1109            s10_g_rad_center.opacity.to(0.0, MORPH),
1110            s10_g_rad_radius.opacity.to(0.0, MORPH),
1111            s10_g_lin_start.opacity.to(1.0, MORPH),
1112            s10_g_lin_end.opacity.to(1.0, MORPH),
1113            s10_g_lin_line.opacity.to(1.0, MORPH),
1114        ],
1115        wait!(1),
1116        // Morph back from Linear (sunset) to Radial (glow)
1117        all![
1118            s10.fill_paint.to(Paint::Gradient(glow.clone()), MORPH),
1119            s10_g_rad_center.opacity.to(1.0, MORPH),
1120            s10_g_rad_radius.opacity.to(1.0, MORPH),
1121            s10_g_lin_start.opacity.to(0.0, MORPH),
1122            s10_g_lin_end.opacity.to(0.0, MORPH),
1123            s10_g_lin_line.opacity.to(0.0, MORPH),
1124        ],
1125        wait!(1),
1126        // Fade everything out
1127        all![
1128            s10_lbl.opacity.to(0.0, FADE_OUT),
1129            s10.opacity.to(0.0, FADE_OUT),
1130            s10_g_rad_center.opacity.to(0.0, FADE_OUT),
1131            s10_g_rad_radius.opacity.to(0.0, FADE_OUT),
1132            title.opacity.to(0.0, FADE_OUT),
1133            grid.opacity.to(0.0, FADE_OUT),
1134        ],
1135    ]);
1136
1137    project.show().expect("Failed to render animation");
1138}
More examples
Hide additional examples
examples/explainer.rs (line 90)
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(opacity: &Signal<f32>, d: Duration) -> Box<dyn Animation> {
94    opacity.to(1.0, d).ease(easings::cubic_out).into()
95}
96fn hide(opacity: &Signal<f32>, d: Duration) -> Box<dyn Animation> {
97    opacity.to(0.0, d).ease(easings::cubic_in).into()
98}
99
100fn main() {
101    let mut project = Project::default()
102        .with_dimensions(CANVAS_W, CANVAS_H)
103        .with_fps(60)
104        .with_title("Explainer")
105        .with_background(BG)
106        .close_on_finish();
107
108    // =====================================================================
109    //  S1: TITLE CARD
110    // =====================================================================
111    let s1_line = hline(100.0);
112    let s1_title = TextNode::default()
113        .with_anchor(Vec2::new(-1.0, -1.0))
114        .with_position(Vec2::new(LEFT, 120.0))
115        .with_text("motion-canvas-rs")
116        .with_font_size(52.0)
117        .with_fill(ACCENT)
118        .with_font(FONT)
119        .with_opacity(0.0);
120    let s1_sub = h2("A GPU-Accelerated Vector Animation Engine", 185.0);
121    let s1_built = body(
122        "Built on Vello + Typst  —  Inspired by Motion Canvas",
123        220.0,
124    );
125    let s1_desc = body(
126        "This animation will teach you how the library works,",
127        280.0,
128    );
129    let s1_desc2 = body(
130        "from struct definitions to the GPU rendering pipeline.",
131        305.0,
132    );
133
134    let s1_logo = SvgNode::default()
135        .with_position(Vec2::new(1142.0, 543.0))
136        .with_path("examples/images/motion-canvas-rs.svg")
137        .with_scale(0.3)
138        .with_size(Vec2::new(768.0, 768.0))
139        .with_opacity(0.0);
140
141    for n in [&s1_title, &s1_sub, &s1_built, &s1_desc, &s1_desc2] {
142        project.scene.add(n);
143    }
144    project.scene.add(&s1_line);
145    project.scene.add(&s1_logo);
146
147    // =====================================================================
148    //  S2: THE 5 STEPS
149    // =====================================================================
150    let s2_h = title("Every program follows 5 steps", 50.0);
151    let steps = [
152        "1. Create a Project       — your canvas settings",
153        "2. Create Nodes           — shapes, text, images",
154        "3. Add Nodes to Scene     — what gets drawn",
155        "4. Animate the Timeline   — how things move",
156        "5. Show or Export         — live window or video",
157    ];
158    let s2_texts: Vec<TextNode> = steps
159        .iter()
160        .enumerate()
161        .map(|(i, s)| body(s, 120.0 + i as f32 * 35.0))
162        .collect();
163
164    project.scene.add(&s2_h);
165    for t in &s2_texts {
166        project.scene.add(t);
167    }
168
169    // =====================================================================
170    //  S3: WHAT IS A STRUCT?  +  The Project struct
171    // =====================================================================
172    let s3_h = title("What is a 'struct'?", 50.0);
173    let s3_explain = h2(
174        "A struct is a container that groups related data together.",
175        95.0,
176    );
177    let s3_analogy = body(
178        "Think of it like a class in Python/JS, but it only holds data.",
179        130.0,
180    );
181
182    let s3_code = code_block(
183        "pub struct Project {
184    pub width: u32,          // Canvas width in pixels
185    pub height: u32,         // Canvas height in pixels
186    pub fps: u32,            // Frames per second
187    pub title: String,       // Window title
188    pub scene: BaseScene,    // Holds nodes + timelines
189    pub background_color: Color,
190    pub close_on_finish: bool,
191}",
192        175.0,
193    );
194
195    let s3_note = note(
196        "^ This is the actual Project struct from the library.",
197        420.0,
198    );
199    let s3_note2 = body(
200        "'pub' means public — anyone can read/write these fields.",
201        455.0,
202    );
203    let s3_note3 = body(
204        "u32 = unsigned 32-bit integer,  String = text,  bool = true/false",
205        485.0,
206    );
207
208    for n in [
209        &s3_h,
210        &s3_explain,
211        &s3_analogy,
212        &s3_note,
213        &s3_note2,
214        &s3_note3,
215    ] {
216        project.scene.add(n);
217    }
218    project.scene.add(&s3_code);
219
220    // =====================================================================
221    //  S4: WHAT IS impl?  +  Builder pattern
222    // =====================================================================
223    let s4_h = title("What is 'impl'?", 50.0);
224    let s4_explain = h2("impl adds methods (functions) to a struct.", 95.0);
225    let s4_analogy = body(
226        "Like adding methods to a class. Separated from the data.",
227        130.0,
228    );
229
230    let s4_code = code_block(
231        "impl Project {
232    pub fn with_fps(mut self, fps: u32) -> Self {
233        self.fps = fps;   // set the value
234        self              // return yourself (builder pattern)
235    }
236    pub fn with_title(mut self, title: &str) -> Self {
237        self.title = title.to_string();
238        self
239    }
240}",
241        175.0,
242    );
243
244    let s4_usage = body("Usage — chain calls to configure:", 430.0);
245    let s4_usage_code = code_block(
246        "let project = Project::default()
247    .with_fps(60)
248    .with_title(\"My Animation\")
249    .with_dimensions(800, 600)
250    .close_on_finish();",
251        460.0,
252    );
253
254    let s4_note = note(
255        "Each .with_*() returns 'self', so you can chain them.",
256        590.0,
257    );
258
259    for n in [&s4_h, &s4_explain, &s4_analogy, &s4_usage, &s4_note] {
260        project.scene.add(n);
261    }
262    project.scene.add(&s4_code);
263    project.scene.add(&s4_usage_code);
264
265    // =====================================================================
266    //  S5: WHAT IS A TRAIT?  +  The Node trait
267    // =====================================================================
268    let s5_h = title("What is a 'trait'?", 50.0);
269    let s5_explain = h2(
270        "A trait is a contract — like an interface in Java/TypeScript.",
271        95.0,
272    );
273    let s5_analogy = body(
274        "Any type that implements a trait promises to provide those methods.",
275        130.0,
276    );
277
278    let s5_code = code_block(
279        "pub trait Node: Send + Sync + 'static {
280    fn render(&self, scene: &mut Scene,
281              parent_transform: Affine,
282              parent_opacity: f32);
283    fn update(&mut self, dt: Duration);
284    fn state_hash(&self) -> u64;
285    fn clone_node(&self) -> Box<dyn Node>;
286}",
287        175.0,
288    );
289
290    let s5_r = note(
291        "render()     — draw yourself using current signal values",
292        410.0,
293    );
294    let s5_u = note(
295        "update(dt)   — called every frame (for per-frame logic)",
296        435.0,
297    );
298    let s5_s = note(
299        "state_hash() — returns a number that changes when you change",
300        460.0,
301    );
302    let s5_c = note("clone_node() — make a deep copy of yourself", 485.0);
303    let s5_every = body(
304        "Circle, Rect, Line, TextNode, Polygon all implement Node.",
305        530.0,
306    );
307
308    for n in [
309        &s5_h,
310        &s5_explain,
311        &s5_analogy,
312        &s5_r,
313        &s5_u,
314        &s5_s,
315        &s5_c,
316        &s5_every,
317    ] {
318        project.scene.add(n);
319    }
320    project.scene.add(&s5_code);
321
322    // =====================================================================
323    //  S6: NODE GALLERY  (visual demo)
324    // =====================================================================
325    let s6_h = title("The Built-in Nodes", 50.0);
326    let s6_sub = body(
327        "Each node uses the builder pattern and stores properties as Signals.",
328        90.0,
329    );
330
331    let demo_c = Circle::default()
332        .with_position(Vec2::new(120.0, 230.0))
333        .with_radius(40.0)
334        .with_fill(RED)
335        .with_opacity(0.0);
336    let demo_r = Rect::default()
337        .with_position(Vec2::new(293.0, 230.0))
338        .with_size(Vec2::new(80.0, 80.0))
339        .with_fill(ACCENT)
340        .with_radius(8.0)
341        .with_opacity(0.0);
342    let demo_l = Line::default()
343        .with_start(Vec2::new(420.0, 200.0))
344        .with_end(Vec2::new(510.0, 270.0))
345        .with_stroke(WHITE, 3.0)
346        .with_opacity(0.0);
347    let demo_p = Polygon::regular(5, 40.0)
348        .with_position(Vec2::new(606.0, 230.0))
349        .with_fill(YELLOW)
350        .with_opacity(0.0);
351    let demo_t = TextNode::default()
352        .with_position(Vec2::new(765.0, 230.0))
353        .with_text("Abc")
354        .with_font_size(36.0)
355        .with_fill(GREEN)
356        .with_font(FONT)
357        .with_opacity(0.0);
358
359    let lc = dim("Circle", 95.0, 285.0);
360    let lr = dim("Rect", 280.0, 285.0);
361    let ll = dim("Line", 445.0, 285.0);
362    let lp = dim("Polygon", 580.0, 285.0);
363    let lt = dim("TextNode", 735.0, 285.0);
364
365    let s6_box_h = h2("Why Box<dyn Node>?", 340.0);
366    let s6_box1 = body("The scene stores different node types in one list:", 375.0);
367    let s6_box_code = code_block(
368        "pub struct BaseScene {
369    pub nodes: Vec<Box<dyn Node>>,  // a list of \"any Node\"
370}
371// 'Box' = heap-allocated,  'dyn Node' = any type implementing Node
372// Like List<INode> in Java or Array<Node> in TypeScript
373project.scene.add(circle);  // wrap + add",
374        405.0,
375    );
376
377    for n in [&s6_h, &s6_sub, &lc, &lr, &ll, &lp, &lt, &s6_box_h, &s6_box1] {
378        project.scene.add(n);
379    }
380    project.scene.add(&demo_c);
381    project.scene.add(&demo_r);
382    project.scene.add(&demo_l);
383    project.scene.add(&demo_p);
384    project.scene.add(&demo_t);
385    project.scene.add(&s6_box_code);
386
387    // =====================================================================
388    //  S7: SIGNALS — The Reactive Core
389    // =====================================================================
390    let s7_h = title("Signals — The Reactive Core", 50.0);
391    let s7_sub = h2("Every animatable property is a Signal<T>.", 95.0);
392
393    let s7_code = code_block(
394        "pub struct Signal<T> {
395    pub data: Arc<Mutex<SignalData<T>>>,
396}
397pub struct SignalData<T> {
398    pub value: T,  // the actual value (f32, Vec2, Color...)
399}",
400        140.0,
401    );
402
403    let s7_arc = note("Arc = shared pointer. Multiple owners, same data.", 310.0);
404    let s7_mutex = note(
405        "Mutex = lock. Only one thread reads/writes at a time.",
406        335.0,
407    );
408    let s7_why = body(
409        "Why? A node and its animation both need the same property:",
410        380.0,
411    );
412
413    let s7_diagram_code = code_block(
414        "let circle = Circle::default().with_radius(50.0);
415// circle.radius is a Signal<f32>
416
417circle.radius.to(100.0, Duration::from_secs(1));
418// Creates a SignalTween with a CLONE of circle.radius
419// Both point to the SAME underlying value (via Arc)
420
421// The animation WRITES new values each frame
422// The node READS them when rendering",
423        420.0,
424    );
425
426    // Live demo circle
427    let sig_demo = Circle::default()
428        .with_position(Vec2::new(1000.0, 400.0))
429        .with_radius(50.0)
430        .with_fill(RED)
431        .with_stroke(Color::rgba8(255, 255, 255, 50), 2.0)
432        .with_opacity(0.0);
433    let sig_lbl = dim("Live Signal demo", 900.0, 150.0);
434
435    for n in [&s7_h, &s7_sub, &s7_arc, &s7_mutex, &s7_why, &sig_lbl] {
436        project.scene.add(n);
437    }
438    project.scene.add(&s7_code);
439    project.scene.add(&s7_diagram_code);
440    project.scene.add(&sig_demo);
441
442    // =====================================================================
443    //  S8: SIGNAL TWEEN — How animations work per-frame
444    // =====================================================================
445    let s8_h = title("SignalTween — The Animation Engine", 50.0);
446    let s8_sub = body(
447        ".to() creates a SignalTween that interpolates over time:",
448        90.0,
449    );
450
451    let s8_code = code_block(
452        "pub struct SignalTween<T> {
453    data: Arc<Mutex<SignalData<T>>>,  // shared ref to signal
454    start_value: Option<T>,           // captured on FIRST update (lazy!)
455    target_value: Option<T>,          // where we're going
456    duration: Duration,               // how long
457    elapsed: Duration,                // how much time passed
458    easing: fn(f32) -> f32,           // curve function
459}",
460        125.0,
461    );
462
463    let s8_how = h2("Each frame update:", 340.0);
464    let s8_steps = [
465        "1. elapsed += dt",
466        "2. t_linear = elapsed / duration          (0.0 to 1.0)",
467        "3. t_eased  = easing(t_linear)            (curved)",
468        "4. value    = lerp(start, target, t)      (interpolate)",
469        "5. Write value into Signal                (node sees it)",
470        "6. If elapsed >= duration: finished!      (return leftover dt)",
471    ];
472    let s8_step_texts: Vec<TextNode> = s8_steps
473        .iter()
474        .enumerate()
475        .map(|(i, s)| body(s, 370.0 + i as f32 * 28.0))
476        .collect();
477
478    let s8_lazy = note(
479        "start_value is captured lazily — so chained tweens read the",
480        570.0,
481    );
482    let s8_lazy2 = note(
483        "correct value at their actual start time, not creation time.",
484        590.0,
485    );
486
487    // Progress bar
488    let prog_bg = Rect::default()
489        .with_position(Vec2::new(895.0, 150.0))
490        .with_size(Vec2::new(400.0, 16.0))
491        .with_fill(Color::rgba8(255, 255, 255, 15))
492        .with_radius(8.0)
493        .with_opacity(0.0);
494    let prog_fill = Rect::default()
495        .with_position(Vec2::new(695.0, 154.0))
496        .with_anchor(Vec2::new(-1.0, 0.5))
497        .with_size(Vec2::new(0.0, 16.0))
498        .with_fill(ACCENT)
499        .with_radius(8.0)
500        .with_opacity(0.0);
501    let plbl0 = dim("t=0", 700.0, 172.0);
502    let plbl1 = dim("t=1", 1070.0, 172.0);
503    let tween_ball = Circle::default()
504        .with_position(Vec2::new(900.0, 430.0))
505        .with_radius(30.0)
506        .with_fill(RED)
507        .with_opacity(0.0);
508    let tween_lbl = dim("radius animating: 30 -> 80", 760.0, 220.0);
509
510    for n in [
511        &s8_h, &s8_sub, &s8_how, &s8_lazy, &s8_lazy2, &plbl0, &plbl1, &tween_lbl,
512    ] {
513        project.scene.add(n);
514    }
515    project.scene.add(&s8_code);
516    for t in &s8_step_texts {
517        project.scene.add(t);
518    }
519    project.scene.add(&prog_bg);
520    project.scene.add(&prog_fill);
521    project.scene.add(&tween_ball);
522
523    // =====================================================================
524    //  S9: TWEENABLE + EASINGS
525    // =====================================================================
526    let s9_h = title("Tweenable — What Can Be Animated", 50.0);
527    let s9_code = code_block(
528        "pub trait Tweenable: Clone + Send + Sync {
529    fn interpolate(a: &Self, b: &Self, t: f32) -> Self;
530    fn state_hash(&self) -> u64;
531}
532// Implemented for: f32, Vec2, Color, String, Affine, Vec<Vec2>
533//   f32:    lerp(a, b, t) = a + (b-a)*t
534//   Vec2:   lerp x and y independently
535//   Color:  lerp R,G,B,A channels independently
536//   String: snap — returns 'a' until t>=1, then 'b'",
537        95.0,
538    );
539
540    let s9_easing_h = h2("Easing functions curve the linear t:", 310.0);
541    let s9_easing_desc = body("Same distance, same duration — different feel.", 340.0);
542
543    let enames = [
544        "linear",
545        "cubic_in_out",
546        "elastic_out",
547        "bounce_out",
548        "back_out",
549    ];
550    let ecolors = [WHITE, ACCENT, RED, YELLOW, GREEN];
551    let mut eballs: Vec<Circle> = Vec::new();
552    let mut elabels: Vec<TextNode> = Vec::new();
553    for (i, name) in enames.iter().enumerate() {
554        let y = 390.0 + i as f32 * 55.0;
555        let b = Circle::default()
556            .with_position(Vec2::new(250.0, y))
557            .with_radius(12.0)
558            .with_fill(ecolors[i])
559            .with_opacity(0.0);
560        let l = dim(name, LEFT, y - 5.0);
561        project.scene.add(&b);
562        project.scene.add(&l);
563        eballs.push(b);
564        elabels.push(l);
565    }
566    project.scene.add(&s9_h);
567    project.scene.add(&s9_code);
568    project.scene.add(&s9_easing_h);
569    project.scene.add(&s9_easing_desc);
570
571    // =====================================================================
572    //  S10: FLOW CONTROLS
573    // =====================================================================
574    let s10_h = title("Flow Controls — Composing Animations", 50.0);
575    let s10_sub = body(
576        "Individual tweens are simple. Power comes from composing them.",
577        90.0,
578    );
579
580    // chain
581    let s10_chain_h = h2("chain![ ] — one after another", 140.0);
582    let chain_d: Vec<Circle> = (0..3)
583        .map(|i| {
584            Circle::default()
585                .with_position(Vec2::new(LEFT + 30.0 + i as f32 * 60.0, 200.0))
586                .with_radius(18.0)
587                .with_fill([RED, ACCENT, YELLOW][i])
588                .with_opacity(0.0)
589        })
590        .collect();
591
592    // all
593    let s10_all_h = h2("all![ ] — all at the same time", 270.0);
594    let all_d: Vec<Circle> = (0..3)
595        .map(|i| {
596            Circle::default()
597                .with_position(Vec2::new(LEFT + 30.0 + i as f32 * 60.0, 330.0))
598                .with_radius(18.0)
599                .with_fill([RED, ACCENT, YELLOW][i])
600                .with_opacity(0.0)
601        })
602        .collect();
603
604    // sequence
605    let s10_seq_h = h2("sequence![ ] — staggered starts", 400.0);
606    let seq_d: Vec<Circle> = (0..3)
607        .map(|i| {
608            Circle::default()
609                .with_position(Vec2::new(LEFT + 30.0 + i as f32 * 60.0, 460.0))
610                .with_radius(18.0)
611                .with_fill([RED, ACCENT, YELLOW][i])
612                .with_opacity(0.0)
613        })
614        .collect();
615
616    let s10_code = code_block(
617        "chain![ a, b, c ]           // a then b then c
618all![ a, b, c ]             // a + b + c together
619sequence![ 200ms, a, b, c ] // staggered
620delay![ 500ms, a ]          // wait then play
621wait(1s)                    // pause
622any![ a, b ]                // race: first wins
623loop_anim![ a, 3 ]          // repeat 3 times",
624        510.0,
625    );
626
627    project.scene.add(&s10_h);
628    project.scene.add(&s10_sub);
629    project.scene.add(&s10_chain_h);
630    project.scene.add(&s10_all_h);
631    project.scene.add(&s10_seq_h);
632    project.scene.add(&s10_code);
633    for d in &chain_d {
634        project.scene.add(d);
635    }
636    for d in &all_d {
637        project.scene.add(d);
638    }
639    for d in &seq_d {
640        project.scene.add(d);
641    }
642
643    // =====================================================================
644    //  S11: TIMELINE + RENDERING
645    // =====================================================================
646    let s11_h = title("The Timeline — Animation Queue", 50.0);
647    let s11_code = code_block(
648        "pub struct Timeline {
649    pub animations: Vec<Box<dyn Animation>>,
650}
651impl Timeline {
652    fn update(&mut self, mut dt: Duration) {
653        while !self.animations.is_empty() {
654            let (finished, leftover) = self.animations[0].update(dt);
655            if finished {
656                self.animations.remove(0); // pop front
657                dt = leftover;             // pass leftover to next!
658            } else { break; }
659        }
660    }
661}",
662        95.0,
663    );
664
665    let s11_leftover = note(
666        "leftover propagation: if A finishes mid-frame, the remaining",
667        390.0,
668    );
669    let s11_leftover2 = note(
670        "dt is immediately given to B. No 'lost frames' at transitions.",
671        415.0,
672    );
673
674    let s11_render_h = h2("Rendering Pipeline (per frame):", 470.0);
675    let s11_steps = [
676        "1. Timeline.update(dt)  =>  SignalTween writes to Signals",
677        "2. Node.render()        =>  reads signals, draws shapes",
678        "3. Vello GPU            =>  compiles scene => wgpu => pixels",
679        "4. state_hash()         =>  seahash for hashing scene state, skip if unchanged",
680    ];
681    let s11_render_texts: Vec<TextNode> = s11_steps
682        .iter()
683        .enumerate()
684        .map(|(i, s)| body(s, 505.0 + i as f32 * 28.0))
685        .collect();
686
687    project.scene.add(&s11_h);
688    project.scene.add(&s11_code);
689    for n in [&s11_leftover, &s11_leftover2, &s11_render_h] {
690        project.scene.add(n);
691    }
692    for t in &s11_render_texts {
693        project.scene.add(t);
694    }
695
696    // =====================================================================
697    //  S12: EVENT LOOP — Why an infinite loop?
698    // =====================================================================
699    let s12_h = title("Why an Infinite Loop? — The Event Loop", 50.0);
700    let s12_sub = body(
701        "GPU rendering requires a persistent event loop (winit + wgpu).",
702        90.0,
703    );
704    let s12_code = code_block(
705        "event_loop.run(|event, elwt| {
706    match event {
707        Resumed => {           // GPU surface ready
708            renderer.resume(&window);
709        }
710        AboutToWait => {       // run every frame
711            scene.update(dt);  // advance animations
712            let hash = scene.state_hash();
713            if hash != last_hash {    // dirty?
714                window.request_redraw();
715            }
716        }
717        RedrawRequested => {   // GPU draw call
718            renderer.render(&scene, w, h);
719        }
720    }
721});",
722        130.0,
723    );
724    let s12_why = note(
725        "The window stays open because the GPU surface is tied to",
726        490.0,
727    );
728    let s12_why2 = note(
729        "the OS event loop. Without it, the surface is immediately dropped.",
730        510.0,
731    );
732    let s12_hash = body(
733        "state_hash() skips re-rendering unchanged frames (dirty-checking).",
734        550.0,
735    );
736
737    for n in [&s12_h, &s12_sub, &s12_why, &s12_why2, &s12_hash] {
738        project.scene.add(n);
739    }
740    project.scene.add(&s12_code);
741
742    // =====================================================================
743    //  S13: HEADLESS EXPORT — GPU without a window
744    // =====================================================================
745    let s13_h = title("Headless Export: GPU -> PNG -> FFmpeg", 50.0);
746    let s13_sub = body(
747        "Same GPU rendering, but without a window — output to files.",
748        90.0,
749    );
750    let s13_code = code_block(
751        "pub struct Exporter {
752    texture: wgpu::Texture,       // GPU-side image
753    output_buffer: wgpu::Buffer,  // CPU-readable copy
754    renderer: Renderer,           // Vello
755}
756fn export_frame(&mut self, scene) -> Vec<u8> {
757    scene.render(&mut self.scene);           // 1. build shapes
758    renderer.render_to_texture(..);          // 2. GPU draws
759    encoder.copy_texture_to_buffer(..);      // 3. GPU -> CPU
760    output_buffer.map_async(Read, ..);       // 4. read pixels
761    return pixels;                           // 5. raw RGBA
762}",
763        130.0,
764    );
765    let s13_cache = note(
766        "Cache: state_hash per frame. If unchanged, skip GPU entirely.",
767        420.0,
768    );
769    let s13_ffmpeg = note(
770        "FFmpeg: raw pixels piped to stdin -> libx264 -> .mkv video.",
771        445.0,
772    );
773    let s13_parallel = body(
774        "PNG saving runs on a background thread. Export is pipelined.",
775        485.0,
776    );
777
778    for n in [&s13_h, &s13_sub, &s13_cache, &s13_ffmpeg, &s13_parallel] {
779        project.scene.add(n);
780    }
781    project.scene.add(&s13_code);
782
783    // =====================================================================
784    //  S14: ENGINE UTILITIES
785    // =====================================================================
786    let s14_h = title("Under the Hood: Utility Modules", 50.0);
787    let s14_sub = body(
788        "Helper systems that power the engine behind the scenes.",
789        90.0,
790    );
791    let s14_code = code_block(
792        "// src/engine/util/
793font_manager.rs    // Lazy-loads system fonts via Typst
794                   // Global HashMap cache with lazy_static
795
796image_manager.rs   // Loads PNG + SVG (via resvg)
797                   // Caches decoded images as Arc<Image>
798
799code_tokenizer.rs  // Syntax highlighting via Syntect
800                   // Parses code -> colored spans for CodeNode
801
802hash.rs            // SeaHash: fast, deterministic fingerprints
803                   // Position-aware combination
804                   // Powers Rayon parallel state hashing
805
806export.rs          // FFmpeg pipe: rawvideo -> libx264
807                   // Audio merging with filter_complex
808                   // Title sanitization for filenames",
809        130.0,
810    );
811    let s14_lazy = note(
812        "lazy_static + Mutex = global singleton, created once, cached forever.",
813        495.0,
814    );
815    let s14_arc = body(
816        "Arc<Image> lets multiple nodes share one decoded image without copies.",
817        530.0,
818    );
819    let s14_hash = note(
820        "Rayon + SeaHash = Deterministic fingerprints across runs & threads.",
821        565.0,
822    );
823
824    for n in [&s14_h, &s14_sub, &s14_lazy, &s14_arc, &s14_hash] {
825        project.scene.add(n);
826    }
827    project.scene.add(&s14_code);
828
829    // =====================================================================
830    //  S15: FINALE
831    // =====================================================================
832    let fin = TextNode::default()
833        .with_anchor(Vec2::new(-1.0, -1.0))
834        .with_position(Vec2::new(LEFT, 200.0))
835        .with_text("That's how it works!")
836        .with_font_size(48.0)
837        .with_fill(ACCENT)
838        .with_font(FONT)
839        .with_opacity(0.0);
840    let fin_steps = [
841        "1.  struct          — data container",
842        "2.  impl            — methods / builder pattern",
843        "3.  trait Node      — interface contract",
844        "4.  Box<dyn Node>   — type-erased heap allocation",
845        "5.  Signal<T>       — Arc<Mutex> shared reactive state",
846        "6.  SignalTween     — per-frame lerp interpolation",
847        "7.  Timeline        — sequential queue + leftover dt",
848        "8.  Event Loop      — winit + wgpu infinite loop",
849        "9.  Exporter        — headless GPU -> PNG/FFmpeg",
850        "10. Utilities       — font/image cache, syntax highlight",
851    ];
852    let fin_texts: Vec<TextNode> = fin_steps
853        .iter()
854        .enumerate()
855        .map(|(i, s)| body(s, 270.0 + i as f32 * 28.0))
856        .collect();
857    let fin_hint = dim("cargo run --example getting_started", LEFT, 570.0);
858
859    project.scene.add(&fin);
860    for t in &fin_texts {
861        project.scene.add(t);
862    }
863    project.scene.add(&fin_hint);
864
865    // =====================================================================
866    //  ANIMATION TIMELINE
867    // =====================================================================
868    // Helper: hide_all takes a vec of opacity signals and fades them out
869    let hide_dur = ms(200);
870
871    project.scene.video_timeline.add(chain![
872        // ── S1: TITLE ──
873        s1_line
874            .end
875            .to(Vec2::new(500.0, 100.0), ms(500))
876            .ease(easings::cubic_out),
877        sequence![
878            ms(120),
879            show(&s1_title.opacity, ms(500)),
880            show(&s1_sub.opacity, ms(500)),
881            show(&s1_built.opacity, ms(500)),
882            show(&s1_logo.opacity, ms(600)),
883            show(&s1_desc.opacity, ms(500)),
884            show(&s1_desc2.opacity, ms(500)),
885        ],
886        wait(secs(5)),
887        all![
888            hide(&s1_title.opacity, hide_dur),
889            hide(&s1_sub.opacity, hide_dur),
890            hide(&s1_built.opacity, hide_dur),
891            hide(&s1_desc.opacity, hide_dur),
892            hide(&s1_desc2.opacity, hide_dur),
893            hide(&s1_logo.opacity, hide_dur),
894            s1_line.end.to(Vec2::new(LEFT, 100.0), hide_dur)
895        ],
896        wait(ms(150)),
897        // ── S2: FIVE STEPS ──
898        show(&s2_h.opacity, ms(500)),
899        wait(ms(400)),
900        sequence![
901            ms(250),
902            show(&s2_texts[0].opacity, ms(400)),
903            show(&s2_texts[1].opacity, ms(400)),
904            show(&s2_texts[2].opacity, ms(400)),
905            show(&s2_texts[3].opacity, ms(400)),
906            show(&s2_texts[4].opacity, ms(400)),
907        ],
908        wait(secs(8)),
909        all![
910            hide(&s2_h.opacity, hide_dur),
911            hide(&s2_texts[0].opacity, hide_dur),
912            hide(&s2_texts[1].opacity, hide_dur),
913            hide(&s2_texts[2].opacity, hide_dur),
914            hide(&s2_texts[3].opacity, hide_dur),
915            hide(&s2_texts[4].opacity, hide_dur)
916        ],
917        wait(ms(150)),
918        // ── S3: STRUCT ──
919        sequence![
920            ms(120),
921            show(&s3_h.opacity, ms(500)),
922            show(&s3_explain.opacity, ms(400)),
923            show(&s3_analogy.opacity, ms(400))
924        ],
925        wait(ms(500)),
926        show(&s3_code.opacity, ms(500)),
927        wait(secs(6)),
928        sequence![
929            ms(300),
930            show(&s3_note.opacity, ms(400)),
931            show(&s3_note2.opacity, ms(400)),
932            show(&s3_note3.opacity, ms(400))
933        ],
934        wait(secs(6)),
935        all![
936            hide(&s3_h.opacity, hide_dur),
937            hide(&s3_explain.opacity, hide_dur),
938            hide(&s3_analogy.opacity, hide_dur),
939            hide(&s3_code.opacity, hide_dur),
940            hide(&s3_note.opacity, hide_dur),
941            hide(&s3_note2.opacity, hide_dur),
942            hide(&s3_note3.opacity, hide_dur)
943        ],
944        wait(ms(150)),
945        // ── S4: IMPL / BUILDER ──
946        sequence![
947            ms(120),
948            show(&s4_h.opacity, ms(500)),
949            show(&s4_explain.opacity, ms(400)),
950            show(&s4_analogy.opacity, ms(400))
951        ],
952        wait(ms(500)),
953        show(&s4_code.opacity, ms(500)),
954        wait(secs(7)),
955        show(&s4_usage.opacity, ms(400)),
956        show(&s4_usage_code.opacity, ms(500)),
957        wait(secs(2)),
958        show(&s4_note.opacity, ms(400)),
959        wait(secs(5)),
960        all![
961            hide(&s4_h.opacity, hide_dur),
962            hide(&s4_explain.opacity, hide_dur),
963            hide(&s4_analogy.opacity, hide_dur),
964            hide(&s4_code.opacity, hide_dur),
965            hide(&s4_usage.opacity, hide_dur),
966            hide(&s4_usage_code.opacity, hide_dur),
967            hide(&s4_note.opacity, hide_dur)
968        ],
969        wait(ms(150)),
970        // ── S5: TRAIT / NODE ──
971        sequence![
972            ms(120),
973            show(&s5_h.opacity, ms(500)),
974            show(&s5_explain.opacity, ms(400)),
975            show(&s5_analogy.opacity, ms(400))
976        ],
977        wait(ms(500)),
978        show(&s5_code.opacity, ms(500)),
979        wait(secs(6)),
980        sequence![
981            ms(300),
982            show(&s5_r.opacity, ms(400)),
983            show(&s5_u.opacity, ms(400)),
984            show(&s5_s.opacity, ms(400)),
985            show(&s5_c.opacity, ms(400))
986        ],
987        wait(secs(2)),
988        show(&s5_every.opacity, ms(400)),
989        wait(secs(4)),
990        all![
991            hide(&s5_h.opacity, hide_dur),
992            hide(&s5_explain.opacity, hide_dur),
993            hide(&s5_analogy.opacity, hide_dur),
994            hide(&s5_code.opacity, hide_dur),
995            hide(&s5_r.opacity, hide_dur),
996            hide(&s5_u.opacity, hide_dur),
997            hide(&s5_s.opacity, hide_dur),
998            hide(&s5_c.opacity, hide_dur),
999            hide(&s5_every.opacity, hide_dur)
1000        ],
1001        wait(ms(150)),
1002        // ── S6: NODE GALLERY ──
1003        sequence![
1004            ms(120),
1005            show(&s6_h.opacity, ms(500)),
1006            show(&s6_sub.opacity, ms(400))
1007        ],
1008        wait(ms(400)),
1009        sequence![
1010            ms(200),
1011            all![show(&demo_c.opacity, ms(400)), show(&lc.opacity, ms(400))],
1012            all![show(&demo_r.opacity, ms(400)), show(&lr.opacity, ms(400))],
1013            all![show(&demo_l.opacity, ms(400)), show(&ll.opacity, ms(400))],
1014            all![show(&demo_p.opacity, ms(400)), show(&lp.opacity, ms(400))],
1015            all![show(&demo_t.opacity, ms(400)), show(&lt.opacity, ms(400))],
1016        ],
1017        wait(secs(2)),
1018        sequence![
1019            ms(200),
1020            show(&s6_box_h.opacity, ms(400)),
1021            show(&s6_box1.opacity, ms(400)),
1022            show(&s6_box_code.opacity, ms(500))
1023        ],
1024        wait(secs(7)),
1025        all![
1026            hide(&s6_h.opacity, hide_dur),
1027            hide(&s6_sub.opacity, hide_dur),
1028            hide(&demo_c.opacity, hide_dur),
1029            hide(&demo_r.opacity, hide_dur),
1030            hide(&demo_l.opacity, hide_dur),
1031            hide(&demo_p.opacity, hide_dur),
1032            hide(&demo_t.opacity, hide_dur),
1033            hide(&lc.opacity, hide_dur),
1034            hide(&lr.opacity, hide_dur),
1035            hide(&ll.opacity, hide_dur),
1036            hide(&lp.opacity, hide_dur),
1037            hide(&lt.opacity, hide_dur),
1038            hide(&s6_box_h.opacity, hide_dur),
1039            hide(&s6_box1.opacity, hide_dur),
1040            hide(&s6_box_code.opacity, hide_dur)
1041        ],
1042        wait(ms(150)),
1043        // ── S7: SIGNALS ──
1044        sequence![
1045            ms(120),
1046            show(&s7_h.opacity, ms(500)),
1047            show(&s7_sub.opacity, ms(400))
1048        ],
1049        wait(ms(400)),
1050        show(&s7_code.opacity, ms(500)),
1051        wait(secs(5)),
1052        sequence![
1053            ms(300),
1054            show(&s7_arc.opacity, ms(400)),
1055            show(&s7_mutex.opacity, ms(400))
1056        ],
1057        wait(secs(4)),
1058        show(&s7_why.opacity, ms(400)),
1059        show(&s7_diagram_code.opacity, ms(500)),
1060        wait(secs(6)),
1061        // Live demo
1062        all![
1063            show(&sig_demo.opacity, ms(300)),
1064            show(&sig_lbl.opacity, ms(300))
1065        ],
1066        chain![
1067            sig_demo.radius.to(80.0, ms(700)).ease(easings::elastic_out),
1068            sig_demo.fill_paint.to(Paint::Solid(TEAL), ms(500)),
1069            sig_demo
1070                .position
1071                .to(Vec2::new(950.0, 350.0), ms(500))
1072                .ease(easings::cubic_out),
1073            wait(ms(300)),
1074            all![
1075                sig_demo.radius.to(50.0, ms(400)),
1076                sig_demo.fill_paint.to(Paint::Solid(RED), ms(400)),
1077                sig_demo.position.to(Vec2::new(900.0, 300.0), ms(400))
1078            ],
1079        ],
1080        wait(secs(3)),
1081        all![
1082            hide(&s7_h.opacity, hide_dur),
1083            hide(&s7_sub.opacity, hide_dur),
1084            hide(&s7_code.opacity, hide_dur),
1085            hide(&s7_arc.opacity, hide_dur),
1086            hide(&s7_mutex.opacity, hide_dur),
1087            hide(&s7_why.opacity, hide_dur),
1088            hide(&s7_diagram_code.opacity, hide_dur),
1089            hide(&sig_demo.opacity, hide_dur),
1090            hide(&sig_lbl.opacity, hide_dur)
1091        ],
1092        wait(ms(150)),
1093        // ── S8: SIGNAL TWEEN ──
1094        sequence![
1095            ms(120),
1096            show(&s8_h.opacity, ms(500)),
1097            show(&s8_sub.opacity, ms(400))
1098        ],
1099        wait(ms(400)),
1100        show(&s8_code.opacity, ms(500)),
1101        wait(secs(6)),
1102        show(&s8_how.opacity, ms(300)),
1103        sequence![
1104            ms(100),
1105            show(&s8_step_texts[0].opacity, ms(250)),
1106            show(&s8_step_texts[1].opacity, ms(250)),
1107            show(&s8_step_texts[2].opacity, ms(250)),
1108            show(&s8_step_texts[3].opacity, ms(250)),
1109            show(&s8_step_texts[4].opacity, ms(250)),
1110            show(&s8_step_texts[5].opacity, ms(250)),
1111        ],
1112        wait(ms(500)),
1113        sequence![
1114            ms(100),
1115            show(&s8_lazy.opacity, ms(300)),
1116            show(&s8_lazy2.opacity, ms(300))
1117        ],
1118        wait(ms(500)),
1119        // Progress bar demo
1120        all![
1121            show(&prog_bg.opacity, ms(200)),
1122            show(&prog_fill.opacity, ms(200)),
1123            show(&plbl0.opacity, ms(200)),
1124            show(&plbl1.opacity, ms(200)),
1125            show(&tween_ball.opacity, ms(200)),
1126            show(&tween_lbl.opacity, ms(200))
1127        ],
1128        all![
1129            prog_fill
1130                .size
1131                .to(Vec2::new(400.0, 16.0), secs(2))
1132                .ease(easings::cubic_in_out),
1133            tween_ball
1134                .radius
1135                .to(80.0, secs(2))
1136                .ease(easings::cubic_in_out),
1137        ],
1138        wait(secs(3)),
1139        all![
1140            hide(&s8_h.opacity, hide_dur),
1141            hide(&s8_sub.opacity, hide_dur),
1142            hide(&s8_code.opacity, hide_dur),
1143            hide(&s8_how.opacity, hide_dur),
1144            hide(&s8_lazy.opacity, hide_dur),
1145            hide(&s8_lazy2.opacity, hide_dur),
1146            hide(&prog_bg.opacity, hide_dur),
1147            hide(&prog_fill.opacity, hide_dur),
1148            hide(&plbl0.opacity, hide_dur),
1149            hide(&plbl1.opacity, hide_dur),
1150            hide(&tween_ball.opacity, hide_dur),
1151            hide(&tween_lbl.opacity, hide_dur),
1152            hide(&s8_step_texts[0].opacity, hide_dur),
1153            hide(&s8_step_texts[1].opacity, hide_dur),
1154            hide(&s8_step_texts[2].opacity, hide_dur),
1155            hide(&s8_step_texts[3].opacity, hide_dur),
1156            hide(&s8_step_texts[4].opacity, hide_dur),
1157            hide(&s8_step_texts[5].opacity, hide_dur)
1158        ],
1159        wait(ms(150)),
1160        // ── S9: TWEENABLE + EASINGS ──
1161        show(&s9_h.opacity, ms(500)),
1162        show(&s9_code.opacity, ms(500)),
1163        wait(secs(4)),
1164        sequence![
1165            ms(60),
1166            show(&s9_easing_h.opacity, ms(300)),
1167            show(&s9_easing_desc.opacity, ms(300))
1168        ],
1169        sequence![
1170            ms(50),
1171            all![
1172                show(&eballs[0].opacity, ms(200)),
1173                show(&elabels[0].opacity, ms(200))
1174            ],
1175            all![
1176                show(&eballs[1].opacity, ms(200)),
1177                show(&elabels[1].opacity, ms(200))
1178            ],
1179            all![
1180                show(&eballs[2].opacity, ms(200)),
1181                show(&elabels[2].opacity, ms(200))
1182            ],
1183            all![
1184                show(&eballs[3].opacity, ms(200)),
1185                show(&elabels[3].opacity, ms(200))
1186            ],
1187            all![
1188                show(&eballs[4].opacity, ms(200)),
1189                show(&elabels[4].opacity, ms(200))
1190            ],
1191        ],
1192        wait(ms(300)),
1193        // Race!
1194        all![
1195            eballs[0]
1196                .position
1197                .to(Vec2::new(1050.0, 390.0), secs(2))
1198                .ease(easings::linear),
1199            eballs[1]
1200                .position
1201                .to(Vec2::new(1050.0, 445.0), secs(2))
1202                .ease(easings::cubic_in_out),
1203            eballs[2]
1204                .position
1205                .to(Vec2::new(1050.0, 500.0), secs(2))
1206                .ease(easings::elastic_out),
1207            eballs[3]
1208                .position
1209                .to(Vec2::new(1050.0, 555.0), secs(2))
1210                .ease(easings::bounce_out),
1211            eballs[4]
1212                .position
1213                .to(Vec2::new(1050.0, 610.0), secs(2))
1214                .ease(easings::back_out),
1215        ],
1216        wait(ms(500)),
1217        all![
1218            eballs[0]
1219                .position
1220                .to(Vec2::new(250.0, 390.0), secs(2))
1221                .ease(easings::linear),
1222            eballs[1]
1223                .position
1224                .to(Vec2::new(250.0, 445.0), secs(2))
1225                .ease(easings::cubic_in_out),
1226            eballs[2]
1227                .position
1228                .to(Vec2::new(250.0, 500.0), secs(2))
1229                .ease(easings::elastic_out),
1230            eballs[3]
1231                .position
1232                .to(Vec2::new(250.0, 555.0), secs(2))
1233                .ease(easings::bounce_out),
1234            eballs[4]
1235                .position
1236                .to(Vec2::new(250.0, 610.0), secs(2))
1237                .ease(easings::back_out),
1238        ],
1239        wait(ms(500)),
1240        all![
1241            hide(&s9_h.opacity, hide_dur),
1242            hide(&s9_code.opacity, hide_dur),
1243            hide(&s9_easing_h.opacity, hide_dur),
1244            hide(&s9_easing_desc.opacity, hide_dur),
1245            hide(&eballs[0].opacity, hide_dur),
1246            hide(&eballs[1].opacity, hide_dur),
1247            hide(&eballs[2].opacity, hide_dur),
1248            hide(&eballs[3].opacity, hide_dur),
1249            hide(&eballs[4].opacity, hide_dur),
1250            hide(&elabels[0].opacity, hide_dur),
1251            hide(&elabels[1].opacity, hide_dur),
1252            hide(&elabels[2].opacity, hide_dur),
1253            hide(&elabels[3].opacity, hide_dur),
1254            hide(&elabels[4].opacity, hide_dur)
1255        ],
1256        wait(ms(150)),
1257        // ── S10: FLOW CONTROLS ──
1258        sequence![
1259            ms(120),
1260            show(&s10_h.opacity, ms(500)),
1261            show(&s10_sub.opacity, ms(400))
1262        ],
1263        wait(ms(400)),
1264        // chain demo
1265        show(&s10_chain_h.opacity, ms(400)),
1266        all![
1267            show(&chain_d[0].opacity, ms(300)),
1268            show(&chain_d[1].opacity, ms(300)),
1269            show(&chain_d[2].opacity, ms(300))
1270        ],
1271        wait(ms(300)),
1272        chain![
1273            chain_d[0]
1274                .position
1275                .to(Vec2::new(700.0, 200.0), ms(500))
1276                .ease(easings::cubic_out),
1277            chain_d[1]
1278                .position
1279                .to(Vec2::new(800.0, 200.0), ms(500))
1280                .ease(easings::cubic_out),
1281            chain_d[2]
1282                .position
1283                .to(Vec2::new(900.0, 200.0), ms(500))
1284                .ease(easings::cubic_out),
1285        ],
1286        wait(secs(1)),
1287        // all demo
1288        show(&s10_all_h.opacity, ms(400)),
1289        all![
1290            show(&all_d[0].opacity, ms(300)),
1291            show(&all_d[1].opacity, ms(300)),
1292            show(&all_d[2].opacity, ms(300))
1293        ],
1294        wait(ms(300)),
1295        all![
1296            all_d[0]
1297                .position
1298                .to(Vec2::new(700.0, 330.0), ms(500))
1299                .ease(easings::cubic_out),
1300            all_d[1]
1301                .position
1302                .to(Vec2::new(800.0, 330.0), ms(500))
1303                .ease(easings::cubic_out),
1304            all_d[2]
1305                .position
1306                .to(Vec2::new(900.0, 330.0), ms(500))
1307                .ease(easings::cubic_out),
1308        ],
1309        wait(secs(1)),
1310        // sequence demo
1311        show(&s10_seq_h.opacity, ms(400)),
1312        all![
1313            show(&seq_d[0].opacity, ms(300)),
1314            show(&seq_d[1].opacity, ms(300)),
1315            show(&seq_d[2].opacity, ms(300))
1316        ],
1317        wait(ms(300)),
1318        sequence![
1319            ms(250),
1320            seq_d[0]
1321                .position
1322                .to(Vec2::new(700.0, 460.0), ms(500))
1323                .ease(easings::cubic_out),
1324            seq_d[1]
1325                .position
1326                .to(Vec2::new(800.0, 460.0), ms(500))
1327                .ease(easings::cubic_out),
1328            seq_d[2]
1329                .position
1330                .to(Vec2::new(900.0, 460.0), ms(500))
1331                .ease(easings::cubic_out),
1332        ],
1333        wait(secs(1)),
1334        show(&s10_code.opacity, ms(500)),
1335        wait(secs(8)),
1336        all![
1337            hide(&s10_h.opacity, hide_dur),
1338            hide(&s10_sub.opacity, hide_dur),
1339            hide(&s10_chain_h.opacity, hide_dur),
1340            hide(&s10_all_h.opacity, hide_dur),
1341            hide(&s10_seq_h.opacity, hide_dur),
1342            hide(&s10_code.opacity, hide_dur),
1343            hide(&chain_d[0].opacity, hide_dur),
1344            hide(&chain_d[1].opacity, hide_dur),
1345            hide(&chain_d[2].opacity, hide_dur),
1346            hide(&all_d[0].opacity, hide_dur),
1347            hide(&all_d[1].opacity, hide_dur),
1348            hide(&all_d[2].opacity, hide_dur),
1349            hide(&seq_d[0].opacity, hide_dur),
1350            hide(&seq_d[1].opacity, hide_dur),
1351            hide(&seq_d[2].opacity, hide_dur)
1352        ],
1353        wait(ms(150)),
1354        // ── S11: TIMELINE + RENDERING ──
1355        show(&s11_h.opacity, ms(500)),
1356        wait(ms(400)),
1357        show(&s11_code.opacity, ms(500)),
1358        wait(secs(7)),
1359        sequence![
1360            ms(200),
1361            show(&s11_leftover.opacity, ms(400)),
1362            show(&s11_leftover2.opacity, ms(400))
1363        ],
1364        wait(secs(4)),
1365        show(&s11_render_h.opacity, ms(400)),
1366        sequence![
1367            ms(200),
1368            show(&s11_render_texts[0].opacity, ms(350)),
1369            show(&s11_render_texts[1].opacity, ms(350)),
1370            show(&s11_render_texts[2].opacity, ms(350)),
1371            show(&s11_render_texts[3].opacity, ms(350)),
1372        ],
1373        wait(secs(7)),
1374        all![
1375            hide(&s11_h.opacity, hide_dur),
1376            hide(&s11_code.opacity, hide_dur),
1377            hide(&s11_leftover.opacity, hide_dur),
1378            hide(&s11_leftover2.opacity, hide_dur),
1379            hide(&s11_render_h.opacity, hide_dur),
1380            hide(&s11_render_texts[0].opacity, hide_dur),
1381            hide(&s11_render_texts[1].opacity, hide_dur),
1382            hide(&s11_render_texts[2].opacity, hide_dur),
1383            hide(&s11_render_texts[3].opacity, hide_dur)
1384        ],
1385        wait(ms(300)),
1386        // ── S12: EVENT LOOP ──
1387        sequence![
1388            ms(120),
1389            show(&s12_h.opacity, ms(500)),
1390            show(&s12_sub.opacity, ms(400))
1391        ],
1392        wait(ms(500)),
1393        show(&s12_code.opacity, ms(500)),
1394        wait(secs(8)),
1395        sequence![
1396            ms(200),
1397            show(&s12_why.opacity, ms(400)),
1398            show(&s12_why2.opacity, ms(400)),
1399            show(&s12_hash.opacity, ms(400))
1400        ],
1401        wait(secs(5)),
1402        all![
1403            hide(&s12_h.opacity, hide_dur),
1404            hide(&s12_sub.opacity, hide_dur),
1405            hide(&s12_code.opacity, hide_dur),
1406            hide(&s12_why.opacity, hide_dur),
1407            hide(&s12_why2.opacity, hide_dur),
1408            hide(&s12_hash.opacity, hide_dur)
1409        ],
1410        wait(ms(150)),
1411        // ── S13: HEADLESS EXPORT ──
1412        sequence![
1413            ms(120),
1414            show(&s13_h.opacity, ms(500)),
1415            show(&s13_sub.opacity, ms(400))
1416        ],
1417        wait(ms(500)),
1418        show(&s13_code.opacity, ms(500)),
1419        wait(secs(8)),
1420        sequence![
1421            ms(200),
1422            show(&s13_cache.opacity, ms(400)),
1423            show(&s13_ffmpeg.opacity, ms(400)),
1424            show(&s13_parallel.opacity, ms(400))
1425        ],
1426        wait(secs(5)),
1427        all![
1428            hide(&s13_h.opacity, hide_dur),
1429            hide(&s13_sub.opacity, hide_dur),
1430            hide(&s13_code.opacity, hide_dur),
1431            hide(&s13_cache.opacity, hide_dur),
1432            hide(&s13_ffmpeg.opacity, hide_dur),
1433            hide(&s13_parallel.opacity, hide_dur)
1434        ],
1435        wait(ms(150)),
1436        // ── S14: UTILITIES ──
1437        sequence![
1438            ms(120),
1439            show(&s14_h.opacity, ms(500)),
1440            show(&s14_sub.opacity, ms(400))
1441        ],
1442        wait(ms(500)),
1443        show(&s14_code.opacity, ms(500)),
1444        wait(secs(8)),
1445        sequence![
1446            ms(200),
1447            show(&s14_lazy.opacity, ms(400)),
1448            show(&s14_arc.opacity, ms(400))
1449        ],
1450        wait(secs(5)),
1451        all![
1452            hide(&s14_h.opacity, hide_dur),
1453            hide(&s14_sub.opacity, hide_dur),
1454            hide(&s14_code.opacity, hide_dur),
1455            hide(&s14_lazy.opacity, hide_dur),
1456            hide(&s14_arc.opacity, hide_dur)
1457        ],
1458        wait(ms(300)),
1459        // ── S15: FINALE ──
1460        show(&fin.opacity, ms(700)),
1461        wait(ms(500)),
1462        sequence![
1463            ms(150),
1464            show(&fin_texts[0].opacity, ms(350)),
1465            show(&fin_texts[1].opacity, ms(350)),
1466            show(&fin_texts[2].opacity, ms(350)),
1467            show(&fin_texts[3].opacity, ms(350)),
1468            show(&fin_texts[4].opacity, ms(350)),
1469            show(&fin_texts[5].opacity, ms(350)),
1470            show(&fin_texts[6].opacity, ms(350)),
1471            show(&fin_texts[7].opacity, ms(350)),
1472            show(&fin_texts[8].opacity, ms(350)),
1473            show(&fin_texts[9].opacity, ms(350)),
1474        ],
1475        wait(secs(2)),
1476        show(&fin_hint.opacity, ms(400)),
1477        wait(secs(6)),
1478    ]);
1479
1480    #[cfg(feature = "audio")]
1481    project
1482        .scene
1483        .audio_timeline
1484        .add(play!(AudioNode::new("background.mp3").with_volume(0.3)));
1485
1486    project.show().expect("Failed to render");
1487}
examples/mask_demo.rs (line 24)
8fn make_source(w: f32, h: f32, font: f32) -> GroupNode {
9    GroupNode::new(vec![
10        Box::new(
11            Rect::default()
12                .with_size(Vec2::new(w, h))
13                .with_radius(w * 0.04)
14                .with_fill(linear_gradient!(
15                    Color::rgb8(0xf4, 0x3f, 0x5e),
16                    Color::rgb8(0x8b, 0x5c, 0xf6),
17                    Color::rgb8(0x06, 0xb6, 0xd4)
18                )),
19        ),
20        Box::new(
21            Circle::default()
22                .with_position(Vec2::new(-w * 0.3, 0.0))
23                .with_radius(w * 0.12)
24                .with_stroke(Color::rgba8(0xff, 0xff, 0xff, 0x88), 3.0),
25        ),
26        Box::new(
27            Circle::default()
28                .with_position(Vec2::new(w * 0.3, 0.0))
29                .with_radius(w * 0.12)
30                .with_stroke(Color::rgba8(0xff, 0xff, 0xff, 0x88), 3.0),
31        ),
32        Box::new(
33            TextNode::default()
34                .with_text("MASKED")
35                .with_font_size(font)
36                .with_fill(Color::WHITE),
37        ),
38    ])
39}
examples/group_animation.rs (line 13)
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(&group);
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. Combined 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}
examples/signals.rs (line 19)
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(axes);
72    project.scene.add(point);
73    project.scene.add(x_label);
74    project.scene.add(y_label);
75
76    // Add the links as "invisible" nodes that just perform the sync
77    project.scene.add(circle_pos_link);
78    project.scene.add(x_label_pos_link);
79    project.scene.add(y_label_pos_link);
80    project.scene.add(x_text_link);
81    project.scene.add(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}
examples/blur_demo.rs (line 76)
8fn main() {
9    let mut project = Project::default()
10        .with_title("Blur Demo")
11        .with_background(Color::rgb8(0x08, 0x08, 0x10))
12        .close_on_finish();
13
14    // Dot Grid Backdrop
15    for x in 1..8 {
16        for y in 1..6 {
17            project.scene.add(
18                Circle::default()
19                    .with_position(Vec2::new(x as f32 * 100.0, y as f32 * 100.0))
20                    .with_radius(1.5)
21                    .with_fill(Color::rgb8(0x1a, 0x1a, 0x2e)),
22            );
23        }
24    }
25
26    // Title
27    let title = TextNode::default()
28        .with_position(Vec2::new(400.0, 60.0))
29        .with_text("Universal Blur")
30        .with_font_size(42.0)
31        .with_fill(Color::rgb8(0xe2, 0xe8, 0xf0))
32        .with_blur(0.0);
33    project.scene.add(&title);
34
35    // Shape
36    let orb = Circle::default()
37        .with_position(Vec2::new(180.0, 220.0))
38        .with_radius(55.0)
39        .with_fill(Color::rgb8(0xa7, 0x6b, 0xf1))
40        .with_opacity(0.9)
41        .with_blur(20.0);
42    project.scene.add(&orb);
43
44    // SVG
45    let logo = SvgNode::default()
46        .with_position(Vec2::new(620.0, 220.0))
47        .with_path("./examples/images/motion-canvas-rs.svg")
48        .with_size(Vec2::new(100.0, 100.0))
49        .with_blur(0.0);
50    project.scene.add(&logo);
51
52    // Math
53    let eq = MathNode::default()
54        .with_position(Vec2::new(200.0, 400.0))
55        .with_equation(r#"E = m c^2"#)
56        .with_font_size(38.0)
57        .with_fill(Color::rgb8(0xfb, 0xd3, 0x8d))
58        .with_blur(0.0);
59    project.scene.add(&eq);
60
61    // Code
62    let snippet = CodeNode::default()
63        .with_position(Vec2::new(400.0, 400.0))
64        .with_language("rs")
65        .with_code("let blur = 20.0;\ncircle.with_blur(blur);")
66        .with_font_size(18.0)
67        .with_blur(0.0);
68    project.scene.add(&snippet);
69
70    // Group
71    let card = GroupNode::new(vec![
72        Box::new(
73            Rect::default()
74                .with_size(Vec2::new(200.0, 90.0))
75                .with_radius(12.0)
76                .with_fill(Color::rgba8(0x38, 0xa1, 0xdb, 0xbb)),
77        ),
78        Box::new(
79            TextNode::default()
80                .with_text("Group Blur")
81                .with_font_size(22.0)
82                .with_fill(Color::WHITE),
83        ),
84    ])
85    .with_position(Vec2::new(400.0, 300.0))
86    .with_blur(0.0);
87    project.scene.add(&card);
88
89    // Subtitle
90    let sub = TextNode::default()
91        .with_position(Vec2::new(400.0, 550.0))
92        .with_text("Shape · SVG · Math · Code · Group")
93        .with_font_size(16.0)
94        .with_fill(Color::rgb8(0x64, 0x6e, 0x7a))
95        .with_blur(0.0);
96    project.scene.add(&sub);
97
98    // Animation: staggered blur waves
99    // Phase 1 — blur everything except the orb (which sharpens)
100    // Phase 2 — restore, then blur the card and equation
101    // Phase 3 — return to initial state
102    project.scene.video_timeline.add(loop_anim!(
103        chain![
104            wait(BEAT),
105            // Phase 1: orb sharpens, everything else softens
106            all![
107                orb.blur.to(0.0, FAST),
108                logo.blur.to(18.0, FAST),
109                eq.blur.to(14.0, FAST),
110                snippet.blur.to(14.0, FAST),
111                card.blur.to(12.0, FAST),
112                title.blur.to(6.0, FAST),
113                sub.blur.to(4.0, FAST),
114            ],
115            wait(BEAT),
116            // Phase 2: card + equation sharp, rest blurred
117            all![
118                orb.blur.to(24.0, SLOW),
119                logo.blur.to(0.0, SLOW),
120                eq.blur.to(0.0, SLOW),
121                snippet.blur.to(18.0, SLOW),
122                card.blur.to(0.0, SLOW),
123                title.blur.to(0.0, SLOW),
124                sub.blur.to(0.0, SLOW),
125            ],
126            wait(BEAT),
127            // Phase 3: return to opening state
128            all![
129                orb.blur.to(20.0, FAST),
130                logo.blur.to(0.0, FAST),
131                eq.blur.to(0.0, FAST),
132                snippet.blur.to(0.0, FAST),
133                card.blur.to(0.0, FAST),
134                title.blur.to(0.0, FAST),
135                sub.blur.to(0.0, FAST),
136            ],
137        ],
138        None,
139    ));
140
141    project.show().expect("Failed to show window");
142}
Source

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.

Source

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.

Source

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.

Source

pub fn hlca(h: f64, l: f64, c: f64, alpha: 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.

Source

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”.

Source

pub fn with_alpha_factor(self, alpha: f32) -> Color

👎Deprecated since 0.2.0:

This method has been renamed to multiply_alpha.

Returns the color with the alpha component multiplied by the specified factor.

Source

pub fn multiply_alpha(self, alpha: f32) -> Color

Returns the color with the alpha component multiplied by alpha. The behaviour of this transformation is undefined if alpha is negative.

If the resulting alpha would overflow, this currently saturates (to opaque).

Source

pub fn to_premul_u32(self) -> u32

Returns the color as a packed premultiplied value.

Source§

impl Color

Named SVG colors.

Source

pub const ALICE_BLUE: Color

Alice blue (240, 248, 255, 255)

Source

pub const ANTIQUE_WHITE: Color

Antique white (250, 235, 215, 255)

Source

pub const AQUA: Color

Aqua (0, 255, 255, 255)

Source

pub const AQUAMARINE: Color

Aquamarine (127, 255, 212, 255)

Source

pub const AZURE: Color

Azure (240, 255, 255, 255)

Source

pub const BEIGE: Color

Beige (245, 245, 220, 255)

Source

pub const BISQUE: Color

Bisque (255, 228, 196, 255)

Source

pub const BLACK: Color

Black (0, 0, 0, 255)

Source

pub const BLANCHED_ALMOND: Color

Blanched almond (255, 235, 205, 255)

Source

pub const BLUE: Color

Blue (0, 0, 255, 255)

Source

pub const BLUE_VIOLET: Color

Blue violet (138, 43, 226, 255)

Source

pub const BROWN: Color

Brown (165, 42, 42, 255)

Source

pub const BURLYWOOD: Color

Burlywood (222, 184, 135, 255)

Source

pub const CADET_BLUE: Color

Cadet blue (95, 158, 160, 255)

Source

pub const CHARTREUSE: Color

Chartreuse (127, 255, 0, 255)

Source

pub const CHOCOLATE: Color

Chocolate (210, 105, 30, 255)

Source

pub const CORAL: Color

Coral (255, 127, 80, 255)

Source

pub const CORNFLOWER_BLUE: Color

Cornflower blue (100, 149, 237, 255)

Source

pub const CORNSILK: Color

Cornsilk (255, 248, 220, 255)

Source

pub const CRIMSON: Color

Crimson (220, 20, 60, 255)

Source

pub const CYAN: Color

Cyan (0, 255, 255, 255)

Source

pub const DARK_BLUE: Color

Dark blue (0, 0, 139, 255)

Source

pub const DARK_CYAN: Color

Dark cyan (0, 139, 139, 255)

Source

pub const DARK_GOLDENROD: Color

Dark goldenrod (184, 134, 11, 255)

Source

pub const DARK_GRAY: Color

Dark gray (169, 169, 169, 255)

Source

pub const DARK_GREEN: Color

Dark green (0, 100, 0, 255)

Source

pub const DARK_KHAKI: Color

Dark khaki (189, 183, 107, 255)

Source

pub const DARK_MAGENTA: Color

Dark magenta (139, 0, 139, 255)

Source

pub const DARK_OLIVE_GREEN: Color

Dark olive green (85, 107, 47, 255)

Source

pub const DARK_ORANGE: Color

Dark orange (255, 140, 0, 255)

Source

pub const DARK_ORCHID: Color

Dark orchid (153, 50, 204, 255)

Source

pub const DARK_RED: Color

Dark red (139, 0, 0, 255)

Source

pub const DARK_SALMON: Color

Dark salmon (233, 150, 122, 255)

Source

pub const DARK_SEA_GREEN: Color

Dark sea green (143, 188, 143, 255)

Source

pub const DARK_SLATE_BLUE: Color

Dark slate blue (72, 61, 139, 255)

Source

pub const DARK_SLATE_GRAY: Color

Dark slate gray (47, 79, 79, 255)

Source

pub const DARK_TURQUOISE: Color

Dark turquoise (0, 206, 209, 255)

Source

pub const DARK_VIOLET: Color

Dark violet (148, 0, 211, 255)

Source

pub const DEEP_PINK: Color

Deep pink (255, 20, 147, 255)

Source

pub const DEEP_SKY_BLUE: Color

Deep sky blue (0, 191, 255, 255)

Source

pub const DIM_GRAY: Color

Dim gray (105, 105, 105, 255)

Source

pub const DODGER_BLUE: Color

Dodger blue (30, 144, 255, 255)

Source

pub const FIREBRICK: Color

Firebrick (178, 34, 34, 255)

Source

pub const FLORAL_WHITE: Color

Floral white (255, 250, 240, 255)

Source

pub const FOREST_GREEN: Color

Forest green (34, 139, 34, 255)

Source

pub const FUCHSIA: Color

Fuchsia (255, 0, 255, 255)

Source

pub const GAINSBORO: Color

Gainsboro (220, 220, 220, 255)

Source

pub const GHOST_WHITE: Color

Ghost white (248, 248, 255, 255)

Source

pub const GOLD: Color

Gold (255, 215, 0, 255)

Source

pub const GOLDENROD: Color

Goldenrod (218, 165, 32, 255)

Source

pub const GRAY: Color

Gray (128, 128, 128, 255)

Source

pub const GREEN: Color

Green (0, 128, 0, 255)

Source

pub const GREEN_YELLOW: Color

Green yellow (173, 255, 47, 255)

Source

pub const HONEYDEW: Color

Honeydew (240, 255, 240, 255)

Source

pub const HOT_PINK: Color

Hot pink (255, 105, 180, 255)

Source

pub const INDIAN_RED: Color

Indian red (205, 92, 92, 255)

Source

pub const INDIGO: Color

Indigo (75, 0, 130, 255)

Source

pub const IVORY: Color

Ivory (255, 255, 240, 255)

Source

pub const KHAKI: Color

Khaki (240, 230, 140, 255)

Source

pub const LAVENDER: Color

Lavender (230, 230, 250, 255)

Source

pub const LAVENDER_BLUSH: Color

Lavender blush (255, 240, 245, 255)

Source

pub const LAWN_GREEN: Color

Lawn green (124, 252, 0, 255)

Source

pub const LEMON_CHIFFON: Color

Lemon chiffon (255, 250, 205, 255)

Source

pub const LIGHT_BLUE: Color

Light blue (173, 216, 230, 255)

Source

pub const LIGHT_CORAL: Color

Light coral (240, 128, 128, 255)

Source

pub const LIGHT_CYAN: Color

Light cyan (224, 255, 255, 255)

Source

pub const LIGHT_GOLDENROD_YELLOW: Color

Light goldenrod yellow (250, 250, 210, 255)

Source

pub const LIGHT_GRAY: Color

Light gray (211, 211, 211, 255)

Source

pub const LIGHT_GREEN: Color

Light green (144, 238, 144, 255)

Source

pub const LIGHT_PINK: Color

Light pink (255, 182, 193, 255)

Source

pub const LIGHT_SALMON: Color

Light salmon (255, 160, 122, 255)

Source

pub const LIGHT_SEA_GREEN: Color

Light sea green (32, 178, 170, 255)

Source

pub const LIGHT_SKY_BLUE: Color

Light sky blue (135, 206, 250, 255)

Source

pub const LIGHT_SLATE_GRAY: Color

Light slate gray (119, 136, 153, 255)

Source

pub const LIGHT_STEEL_BLUE: Color

Light steel blue (176, 196, 222, 255)

Source

pub const LIGHT_YELLOW: Color

Light yellow (255, 255, 224, 255)

Source

pub const LIME: Color

Lime (0, 255, 0, 255)

Source

pub const LIME_GREEN: Color

Lime green (50, 205, 50, 255)

Source

pub const LINEN: Color

Linen (250, 240, 230, 255)

Source

pub const MAGENTA: Color

Magenta (255, 0, 255, 255)

Source

pub const MAROON: Color

Maroon (128, 0, 0, 255)

Source

pub const MEDIUM_AQUAMARINE: Color

Medium aquamarine (102, 205, 170, 255)

Source

pub const MEDIUM_BLUE: Color

Medium blue (0, 0, 205, 255)

Source

pub const MEDIUM_ORCHID: Color

Medium orchid (186, 85, 211, 255)

Source

pub const MEDIUM_PURPLE: Color

Medium purple (147, 112, 219, 255)

Source

pub const MEDIUM_SEA_GREEN: Color

Medium sea green (60, 179, 113, 255)

Source

pub const MEDIUM_SLATE_BLUE: Color

Medium slate blue (123, 104, 238, 255)

Source

pub const MEDIUM_SPRING_GREEN: Color

Medium spring green (0, 250, 154, 255)

Source

pub const MEDIUM_TURQUOISE: Color

Medium turquoise (72, 209, 204, 255)

Source

pub const MEDIUM_VIOLET_RED: Color

Medium violet red (199, 21, 133, 255)

Source

pub const MIDNIGHT_BLUE: Color

Midnight blue (25, 25, 112, 255)

Source

pub const MINT_CREAM: Color

Mint cream (245, 255, 250, 255)

Source

pub const MISTY_ROSE: Color

Misty rose (255, 228, 225, 255)

Source

pub const MOCCASIN: Color

Moccasin (255, 228, 181, 255)

Source

pub const NAVAJO_WHITE: Color

Navajo white (255, 222, 173, 255)

Source

pub const NAVY: Color

Navy (0, 0, 128, 255)

Source

pub const OLD_LACE: Color

Old lace (253, 245, 230, 255)

Source

pub const OLIVE: Color

Olive (128, 128, 0, 255)

Source

pub const OLIVE_DRAB: Color

Olive drab (107, 142, 35, 255)

Source

pub const ORANGE: Color

Orange (255, 165, 0, 255)

Source

pub const ORANGE_RED: Color

Orange red (255, 69, 0, 255)

Source

pub const ORCHID: Color

Orchid (218, 112, 214, 255)

Source

pub const PALE_GOLDENROD: Color

Pale goldenrod (238, 232, 170, 255)

Source

pub const PALE_GREEN: Color

Pale green (152, 251, 152, 255)

Source

pub const PALE_TURQUOISE: Color

Pale turquoise (175, 238, 238, 255)

Source

pub const PALE_VIOLET_RED: Color

Pale violet red (219, 112, 147, 255)

Source

pub const PAPAYA_WHIP: Color

Papaya whip (255, 239, 213, 255)

Source

pub const PEACH_PUFF: Color

Peach puff (255, 218, 185, 255)

Source

pub const PERU: Color

Peru (205, 133, 63, 255)

Source

pub const PINK: Color

Pink (255, 192, 203, 255)

Source

pub const PLUM: Color

Plum (221, 160, 221, 255)

Source

pub const POWDER_BLUE: Color

Powder blue (176, 224, 230, 255)

Source

pub const PURPLE: Color

Purple (128, 0, 128, 255)

Source

pub const REBECCA_PURPLE: Color

Rebecca purple (102, 51, 153, 255)

Source

pub const RED: Color

Red (255, 0, 0, 255)

Source

pub const ROSY_BROWN: Color

Rosy brown (188, 143, 143, 255)

Source

pub const ROYAL_BLUE: Color

Royal blue (65, 105, 225, 255)

Source

pub const SADDLE_BROWN: Color

Saddle brown (139, 69, 19, 255)

Source

pub const SALMON: Color

Salmon (250, 128, 114, 255)

Source

pub const SANDY_BROWN: Color

Sandy brown (244, 164, 96, 255)

Source

pub const SEA_GREEN: Color

Sea green (46, 139, 87, 255)

Source

pub const SEASHELL: Color

Seashell (255, 245, 238, 255)

Source

pub const SIENNA: Color

Sienna (160, 82, 45, 255)

Source

pub const SILVER: Color

Silver (192, 192, 192, 255)

Source

pub const SKY_BLUE: Color

Sky blue (135, 206, 235, 255)

Source

pub const SLATE_BLUE: Color

Slate blue (106, 90, 205, 255)

Source

pub const SLATE_GRAY: Color

Slate gray (112, 128, 144, 255)

Source

pub const SNOW: Color

Snow (255, 250, 250, 255)

Source

pub const SPRING_GREEN: Color

Spring green (0, 255, 127, 255)

Source

pub const STEEL_BLUE: Color

Steel blue (70, 130, 180, 255)

Source

pub const TAN: Color

Tan (210, 180, 140, 255)

Source

pub const TEAL: Color

Teal (0, 128, 128, 255)

Source

pub const THISTLE: Color

Thistle (216, 191, 216, 255)

Source

pub const TOMATO: Color

Tomato (255, 99, 71, 255)

Source

pub const TRANSPARENT: Color

Transparent (0, 0, 0, 0)

Source

pub const TURQUOISE: Color

Turquoise (64, 224, 208, 255)

Source

pub const VIOLET: Color

Violet (238, 130, 238, 255)

Source

pub const WHEAT: Color

Wheat (245, 222, 179, 255)

Source

pub const WHITE: Color

White (255, 255, 255, 255)

Source

pub const WHITE_SMOKE: Color

White smoke (245, 245, 245, 255)

Source

pub const YELLOW: Color

Yellow (255, 255, 0, 255)

Source

pub const YELLOW_GREEN: Color

Yellow green (154, 205, 50, 255)

Trait Implementations§

Source§

impl Clone for Color

Source§

fn clone(&self) -> Color

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Color

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl Default for Color

Source§

fn default() -> Color

Returns the “default value” for a type. Read more
Source§

impl From<[u8; 3]> for Color

Source§

fn from(rgb: [u8; 3]) -> Color

Converts to this type from the input type.
Source§

impl From<[u8; 4]> for Color

Source§

fn from(rgba: [u8; 4]) -> Color

Converts to this type from the input type.
Source§

impl From<Color> for Paint

Source§

fn from(c: Color) -> Self

Converts to this type from the input type.
Source§

impl Hash for Color

Source§

fn hash<__H>(&self, state: &mut __H)
where __H: Hasher,

Feeds this value into the given Hasher. Read more
1.3.0 · Source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where H: Hasher, Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
Source§

impl Ord for Color

Source§

fn cmp(&self, other: &Color) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 (const: unstable) · Source§

fn max(self, other: Self) -> Self
where Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 (const: unstable) · Source§

fn min(self, other: Self) -> Self
where Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 (const: unstable) · Source§

fn clamp(self, min: Self, max: Self) -> Self
where Self: Sized,

Restrict a value to a certain interval. Read more
Source§

impl PartialEq for Color

Source§

fn eq(&self, other: &Color) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl PartialOrd for Color

Source§

fn partial_cmp(&self, other: &Color) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 (const: unstable) · Source§

fn lt(&self, other: &Rhs) -> bool

Tests less than (for self and other) and is used by the < operator. Read more
1.0.0 (const: unstable) · Source§

fn le(&self, other: &Rhs) -> bool

Tests less than or equal to (for self and other) and is used by the <= operator. Read more
1.0.0 (const: unstable) · Source§

fn gt(&self, other: &Rhs) -> bool

Tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 (const: unstable) · Source§

fn ge(&self, other: &Rhs) -> bool

Tests greater than or equal to (for self and other) and is used by the >= operator. Read more
Source§

impl Tweenable for Color

Source§

fn interpolate(a: &Self, b: &Self, t: f32) -> Self

Interpolates between a and b by factor t (0.0 to 1.0).
Source§

fn state_hash(&self) -> u64

Returns a hash of the current value for change detection.
Source§

impl Copy for Color

Source§

impl Eq for Color

Source§

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 S
where 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) -> D
where M: TransformMatrix<T>,

Convert the source color to the destination color using the specified method.
Source§

fn adapt_into(self) -> D

Convert the source color to the destination color using the bradford method by default.
Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T, C> ArraysFrom<C> for T
where C: IntoArrays<T>,

Source§

fn arrays_from(colors: C) -> T

Cast a collection of colors into a collection of arrays.
Source§

impl<T, C> ArraysInto<C> for T
where C: FromArrays<T>,

Source§

fn arrays_into(self) -> C

Cast this collection of arrays into a collection of colors.
Source§

impl<T> Az for T

Source§

fn az<Dst>(self) -> Dst
where T: Cast<Dst>,

Casts the value.
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<WpParam, T, U> Cam16IntoUnclamped<WpParam, T> for U
where T: FromCam16Unclamped<WpParam, U>,

Source§

type Scalar = <T as FromCam16Unclamped<WpParam, U>>::Scalar

The number type that’s used in parameters when converting.
Source§

fn cam16_into_unclamped( self, parameters: BakedParameters<WpParam, <U as Cam16IntoUnclamped<WpParam, T>>::Scalar>, ) -> T

Converts self into C, using the provided parameters.
Source§

impl<Src, Dst> CastFrom<Src> for Dst
where Src: Cast<Dst>,

Source§

fn cast_from(src: Src) -> Dst

Casts the value.
Source§

impl<T> CheckedAs for T

Source§

fn checked_as<Dst>(self) -> Option<Dst>
where T: CheckedCast<Dst>,

Casts the value.
Source§

impl<Src, Dst> CheckedCastFrom<Src> for Dst
where Src: CheckedCast<Dst>,

Source§

fn checked_cast_from(src: Src) -> Option<Dst>

Casts the value.
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<Q, K> Comparable<K> for Q
where Q: Ord + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn compare(&self, key: &K) -> Ordering

Compare self to key and return their ordering.
Source§

impl<T, C> ComponentsFrom<C> for T
where C: IntoComponents<T>,

Source§

fn components_from(colors: C) -> T

Cast a collection of colors into a collection of color components.
Source§

impl<T> Downcast<T> for T

Source§

fn downcast(&self) -> &T

Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert 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>

Convert 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)

Convert &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)

Convert &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
where T: Any + Send + Sync,

Source§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Convert Arc<Trait> (where Trait: Downcast) to Arc<Any>. Arc<Any> can then be further downcast into Arc<ConcreteType> where ConcreteType implements Trait.
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
Source§

impl<T> Filterable for T

Source§

fn filterable( self, filter_name: &'static str, ) -> RequestFilterDataProvider<T, fn(DataRequest<'_>) -> bool>

Creates a filterable data provider with the given name for debugging. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> FromAngle<T> for T

Source§

fn from_angle(angle: T) -> T

Performs a conversion from angle.
Source§

impl<S> FromSample<S> for S

Source§

fn from_sample_(s: S) -> S

Source§

impl<T, U> FromStimulus<U> for T
where U: IntoStimulus<T>,

Source§

fn from_stimulus(other: U) -> T

Converts other into Self, while performing the appropriate scaling, rounding and clamping.
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> IntoAngle<U> for T
where U: FromAngle<T>,

Source§

fn into_angle(self) -> U

Performs a conversion into T.
Source§

impl<WpParam, T, U> IntoCam16Unclamped<WpParam, T> for U
where T: Cam16FromUnclamped<WpParam, U>,

Source§

type Scalar = <T as Cam16FromUnclamped<WpParam, U>>::Scalar

The number type that’s used in parameters when converting.
Source§

fn into_cam16_unclamped( self, parameters: BakedParameters<WpParam, <U as IntoCam16Unclamped<WpParam, T>>::Scalar>, ) -> T

Converts self into C, using the provided parameters.
Source§

impl<T, U> IntoColor<U> for T
where U: FromColor<T>,

Source§

fn into_color(self) -> U

Convert into T with values clamped to the color defined bounds Read more
Source§

impl<T, U> IntoColorUnclamped<U> for T
where U: FromColorUnclamped<T>,

Source§

fn into_color_unclamped(self) -> U

Convert into T. The resulting color might be invalid in its color space Read more
Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts 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 more
Source§

impl<F, T> IntoSample<T> for F
where T: FromSample<F>,

Source§

fn into_sample(self) -> T

Source§

impl<T> IntoStimulus<T> for T

Source§

fn into_stimulus(self) -> T

Converts self into T, while performing the appropriate scaling, rounding and clamping.
Source§

impl<T> OverflowingAs for T

Source§

fn overflowing_as<Dst>(self) -> (Dst, bool)
where T: OverflowingCast<Dst>,

Casts the value.
Source§

impl<Src, Dst> OverflowingCastFrom<Src> for Dst
where Src: OverflowingCast<Dst>,

Source§

fn overflowing_cast_from(src: Src) -> (Dst, bool)

Casts the value.
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> SaturatingAs for T

Source§

fn saturating_as<Dst>(self) -> Dst
where T: SaturatingCast<Dst>,

Casts the value.
Source§

impl<Src, Dst> SaturatingCastFrom<Src> for Dst
where Src: SaturatingCast<Dst>,

Source§

fn saturating_cast_from(src: Src) -> Dst

Casts the value.
Source§

impl<T> StrictAs for T

Source§

fn strict_as<Dst>(self) -> Dst
where T: StrictCast<Dst>,

Casts the value.
Source§

impl<Src, Dst> StrictCastFrom<Src> for Dst
where Src: StrictCast<Dst>,

Source§

fn strict_cast_from(src: Src) -> Dst

Casts the value.
Source§

impl<SS, SP> SupersetOf<SS> for SP
where SS: SubsetOf<SP>,

Source§

fn to_subset(&self) -> Option<SS>

The inverse inclusion map: attempts to construct self from the equivalent element of its superset. Read more
Source§

fn is_in_subset(&self) -> bool

Checks if self is actually part of its subset T (and can be converted to it).
Source§

fn to_subset_unchecked(&self) -> SS

Use with care! Same as self.to_subset but without any property checks. Always succeeds.
Source§

fn from_subset(element: &SS) -> SP

The inclusion map: converts self to the equivalent element of its superset.
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> ToSample<U> for T
where U: FromSample<T>,

Source§

fn to_sample_(self) -> U

Source§

impl<T, C> TryComponentsInto<C> for T
where C: TryFromComponents<T>,

Source§

type Error = <C as TryFromComponents<T>>::Error

The error for when try_into_colors fails to cast.
Source§

fn try_components_into(self) -> Result<C, <T as TryComponentsInto<C>>::Error>

Try to cast this collection of color components into a collection of colors. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T, U> TryIntoColor<U> for T
where U: TryFromColor<T>,

Source§

fn try_into_color(self) -> Result<U, OutOfBounds<U>>

Convert into T, returning ok if the color is inside of its defined range, otherwise an OutOfBounds error is returned which contains the unclamped color. Read more
Source§

impl<C, U> UintsFrom<C> for U
where C: IntoUints<U>,

Source§

fn uints_from(colors: C) -> U

Cast a collection of colors into a collection of unsigned integers.
Source§

impl<C, U> UintsInto<C> for U
where C: FromUints<U>,

Source§

fn uints_into(self) -> C

Cast this collection of unsigned integers into a collection of colors.
Source§

impl<T> UnwrappedAs for T

Source§

fn unwrapped_as<Dst>(self) -> Dst
where T: UnwrappedCast<Dst>,

Casts the value.
Source§

impl<Src, Dst> UnwrappedCastFrom<Src> for Dst
where Src: UnwrappedCast<Dst>,

Source§

fn unwrapped_cast_from(src: Src) -> Dst

Casts the value.
Source§

impl<T> Upcast<T> for T

Source§

fn upcast(&self) -> Option<&T>

Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WrappingAs for T

Source§

fn wrapping_as<Dst>(self) -> Dst
where T: WrappingCast<Dst>,

Casts the value.
Source§

impl<Src, Dst> WrappingCastFrom<Src> for Dst
where Src: WrappingCast<Dst>,

Source§

fn wrapping_cast_from(src: Src) -> Dst

Casts the value.
Source§

impl<S, T> Duplex<S> for T
where T: FromSample<S> + ToSample<S>,

Source§

impl<T> ErasedDestructor for T
where T: 'static,

Source§

impl<T> ErasedDestructor for T
where T: 'static,

Source§

impl<T> MaybeSendSync for T
where T: Send + Sync,

Source§

impl<T> Scalar for T
where T: 'static + Clone + PartialEq + Debug,

Source§

impl<T> WasmNotSend for T
where T: Send,

Source§

impl<T> WasmNotSendSync for T

Source§

impl<T> WasmNotSync for T
where T: Sync,