Skip to main content

gradient_demo/
gradient_demo.rs

1use motion_canvas_rs::prelude::*;
2use std::time::Duration;
3
4fn linear_grad(c1: Color, c2: Color, size: f64) -> Gradient {
5    Gradient {
6        kind: GradientKind::Linear {
7            start: Point::new(-size, 0.0),
8            end: Point::new(size, 0.0),
9        },
10        extend: Extend::Pad,
11        stops: ColorStops::from(vec![
12            ColorStop {
13                offset: 0.0,
14                color: c1,
15            },
16            ColorStop {
17                offset: 1.0,
18                color: c2,
19            },
20        ]),
21    }
22}
23
24fn tri_grad(c1: Color, c2: Color, c3: Color, size: f64) -> Gradient {
25    Gradient {
26        kind: GradientKind::Linear {
27            start: Point::new(-size, -size),
28            end: Point::new(size, size),
29        },
30        extend: Extend::Pad,
31        stops: ColorStops::from(vec![
32            ColorStop {
33                offset: 0.0,
34                color: c1,
35            },
36            ColorStop {
37                offset: 0.5,
38                color: c2,
39            },
40            ColorStop {
41                offset: 1.0,
42                color: c3,
43            },
44        ]),
45    }
46}
47
48fn radial_grad(inner: Color, outer: Color, radius: f64) -> Gradient {
49    Gradient {
50        kind: GradientKind::Radial {
51            start_center: Point::new(0.0, 0.0),
52            start_radius: 0.0,
53            end_center: Point::new(0.0, 0.0),
54            end_radius: radius as f32,
55        },
56        extend: Extend::Pad,
57        stops: ColorStops::from(vec![
58            ColorStop {
59                offset: 0.0,
60                color: inner,
61            },
62            ColorStop {
63                offset: 1.0,
64                color: outer,
65            },
66        ]),
67    }
68}
69
70/// Build a gradient with explicit direction points and arbitrary stops.
71fn directed_grad(start: Point, end: Point, stops: Vec<ColorStop>) -> Gradient {
72    Gradient {
73        kind: GradientKind::Linear { start, end },
74        extend: Extend::Pad,
75        stops: ColorStops::from(stops),
76    }
77}
78
79// Palette
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}